From f629e602fb5c1e2fbe08b7d8b0b3e4be37ac8a99 Mon Sep 17 00:00:00 2001 From: Packit Service Date: Dec 09 2020 13:45:15 +0000 Subject: gawk-4.2.1 base --- diff --git a/ABOUT-NLS b/ABOUT-NLS new file mode 100644 index 0000000..1551426 --- /dev/null +++ b/ABOUT-NLS @@ -0,0 +1,1379 @@ +1 Notes on the Free Translation Project +*************************************** + +Free software is going international! The Free Translation Project is a +way to get maintainers of free software, translators, and users all +together, so that free software will gradually become able to speak many +languages. A few packages already provide translations for their +messages. + + If you found this 'ABOUT-NLS' file inside a distribution, you may +assume that the distributed package does use GNU 'gettext' internally, +itself available at your nearest GNU archive site. But you do _not_ +need to install GNU 'gettext' prior to configuring, installing or using +this package with messages translated. + + Installers will find here some useful hints. These notes also +explain how users should proceed for getting the programs to use the +available translations. They tell how people wanting to contribute and +work on translations can contact the appropriate team. + +1.1 INSTALL Matters +=================== + +Some packages are "localizable" when properly installed; the programs +they contain can be made to speak your own native language. Most such +packages use GNU 'gettext'. Other packages have their own ways to +internationalization, predating GNU 'gettext'. + + By default, this package will be installed to allow translation of +messages. It will automatically detect whether the system already +provides the GNU 'gettext' functions. Installers may use special +options at configuration time for changing the default behaviour. The +command: + + ./configure --disable-nls + +will _totally_ disable translation of messages. + + When you already have GNU 'gettext' installed on your system and run +configure without an option for your new package, 'configure' will +probably detect the previously built and installed 'libintl' library and +will decide to use it. If not, you may have to to use the +'--with-libintl-prefix' option to tell 'configure' where to look for it. + + Internationalized packages usually have many 'po/LL.po' files, where +LL gives an ISO 639 two-letter code identifying the language. Unless +translations have been forbidden at 'configure' time by using the +'--disable-nls' switch, all available translations are installed +together with the package. However, the environment variable 'LINGUAS' +may be set, prior to configuration, to limit the installed set. +'LINGUAS' should then contain a space separated list of two-letter +codes, stating which languages are allowed. + +1.2 Using This Package +====================== + +As a user, if your language has been installed for this package, you +only have to set the 'LANG' environment variable to the appropriate +'LL_CC' combination. If you happen to have the 'LC_ALL' or some other +'LC_xxx' environment variables set, you should unset them before setting +'LANG', otherwise the setting of 'LANG' will not have the desired +effect. Here 'LL' is an ISO 639 two-letter language code, and 'CC' is +an ISO 3166 two-letter country code. For example, let's suppose that +you speak German and live in Germany. At the shell prompt, merely +execute 'setenv LANG de_DE' (in 'csh'), 'export LANG; LANG=de_DE' (in +'sh') or 'export LANG=de_DE' (in 'bash'). This can be done from your +'.login' or '.profile' file, once and for all. + + You might think that the country code specification is redundant. +But in fact, some languages have dialects in different countries. For +example, 'de_AT' is used for Austria, and 'pt_BR' for Brazil. The +country code serves to distinguish the dialects. + + The locale naming convention of 'LL_CC', with 'LL' denoting the +language and 'CC' denoting the country, is the one use on systems based +on GNU libc. On other systems, some variations of this scheme are used, +such as 'LL' or 'LL_CC.ENCODING'. You can get the list of locales +supported by your system for your language by running the command +'locale -a | grep '^LL''. + + Not all programs have translations for all languages. By default, an +English message is shown in place of a nonexistent translation. If you +understand other languages, you can set up a priority list of languages. +This is done through a different environment variable, called +'LANGUAGE'. GNU 'gettext' gives preference to 'LANGUAGE' over 'LANG' +for the purpose of message handling, but you still need to have 'LANG' +set to the primary language; this is required by other parts of the +system libraries. For example, some Swedish users who would rather read +translations in German than English for when Swedish is not available, +set 'LANGUAGE' to 'sv:de' while leaving 'LANG' to 'sv_SE'. + + Special advice for Norwegian users: The language code for Norwegian +bokma*l changed from 'no' to 'nb' recently (in 2003). During the +transition period, while some message catalogs for this language are +installed under 'nb' and some older ones under 'no', it's recommended +for Norwegian users to set 'LANGUAGE' to 'nb:no' so that both newer and +older translations are used. + + In the 'LANGUAGE' environment variable, but not in the 'LANG' +environment variable, 'LL_CC' combinations can be abbreviated as 'LL' to +denote the language's main dialect. For example, 'de' is equivalent to +'de_DE' (German as spoken in Germany), and 'pt' to 'pt_PT' (Portuguese +as spoken in Portugal) in this context. + +1.3 Translating Teams +===================== + +For the Free Translation Project to be a success, we need interested +people who like their own language and write it well, and who are also +able to synergize with other translators speaking the same language. +Each translation team has its own mailing list. The up-to-date list of +teams can be found at the Free Translation Project's homepage, +'http://translationproject.org/', in the "Teams" area. + + If you'd like to volunteer to _work_ at translating messages, you +should become a member of the translating team for your own language. +The subscribing address is _not_ the same as the list itself, it has +'-request' appended. For example, speakers of Swedish can send a +message to 'sv-request@li.org', having this message body: + + subscribe + + Keep in mind that team members are expected to participate _actively_ +in translations, or at solving translational difficulties, rather than +merely lurking around. If your team does not exist yet and you want to +start one, or if you are unsure about what to do or how to get started, +please write to 'coordinator@translationproject.org' to reach the +coordinator for all translator teams. + + The English team is special. It works at improving and uniformizing +the terminology in use. Proven linguistic skills are praised more than +programming skills, here. + +1.4 Available Packages +====================== + +Languages are not equally supported in all packages. The following +matrix shows the current state of internationalization, as of Jun 2014. +The matrix shows, in regard of each package, for which languages PO +files have been submitted to translation coordination, with a +translation percentage of at least 50%. + + Ready PO files af am an ar as ast az be bg bn bn_IN bs ca crh cs + +---------------------------------------------------+ + a2ps | [] [] [] | + aegis | | + anubis | | + aspell | [] [] [] | + bash | [] [] [] | + bfd | | + binutils | [] | + bison | | + bison-runtime | [] | + buzztrax | [] | + ccd2cue | | + ccide | | + cflow | | + clisp | | + coreutils | [] [] | + cpio | | + cppi | | + cpplib | [] | + cryptsetup | [] | + datamash | | + denemo | [] [] | + dfarc | [] | + dialog | [] [] [] | + dico | | + diffutils | [] | + dink | [] | + direvent | | + doodle | [] | + dos2unix | | + dos2unix-man | | + e2fsprogs | [] [] | + enscript | [] | + exif | [] | + fetchmail | [] [] | + findutils | [] | + flex | [] | + freedink | [] [] | + fusionforge | | + gas | | + gawk | [] | + gcal | [] | + gcc | | + gdbm | | + gettext-examples | [] [] [] [] [] | + gettext-runtime | [] [] [] | + gettext-tools | [] [] | + gjay | | + glunarclock | [] [] [] | + gnubiff | [] | + gnubik | [] | + gnucash | () () [] | + gnuchess | | + gnulib | [] | + gnunet | | + gnunet-gtk | | + gold | | + gphoto2 | [] | + gprof | [] | + gramadoir | | + grep | [] [] [] | + grub | [] | + gsasl | | + gss | | + gst-plugins-bad | [] | + gst-plugins-base | [] [] [] | + gst-plugins-good | [] [] [] | + gst-plugins-ugly | [] [] [] | + gstreamer | [] [] [] [] | + gtick | [] | + gtkam | [] [] | + gtkspell | [] [] [] [] [] | + guix | | + guix-packages | | + gutenprint | [] | + hello | [] | + help2man | | + help2man-texi | | + hylafax | | + idutils | | + iso_15924 | [] | + iso_3166 | [] [] [] [] [] [] [] [] [] [] | + iso_3166_2 | | + iso_4217 | [] | + iso_639 | [] [] [] [] [] [] [] [] [] | + iso_639_3 | [] [] | + iso_639_5 | | + jwhois | | + kbd | [] | + klavaro | [] [] [] [] [] | + latrine | | + ld | [] | + leafpad | [] [] [] [] | + libc | [] [] [] | + libexif | () | + libextractor | | + libgnutls | [] | + libgphoto2 | [] | + libgphoto2_port | [] | + libgsasl | | + libiconv | [] [] | + libidn | [] | + liferea | [] [] [] [] | + lilypond | [] [] | + lordsawar | [] | + lprng | | + lynx | [] [] | + m4 | [] | + mailfromd | | + mailutils | | + make | [] | + man-db | [] [] | + man-db-manpages | | + midi-instruments | [] [] [] | + minicom | [] | + mkisofs | [] | + myserver | [] | + nano | [] [] [] | + opcodes | | + parted | [] | + pies | | + popt | [] | + procps-ng | | + procps-ng-man | | + psmisc | [] | + pspp | [] | + pushover | [] | + pwdutils | | + pyspread | | + radius | [] | + recode | [] [] [] | + recutils | | + rpm | | + rush | | + sarg | | + sed | [] [] [] | + sharutils | [] | + shishi | | + skribilo | | + solfege | [] | + solfege-manual | | + spotmachine | | + sudo | [] [] | + sudoers | [] [] | + sysstat | [] | + tar | [] [] [] | + texinfo | [] [] | + texinfo_document | [] | + tigervnc | [] | + tin | | + tin-man | | + tracgoogleappsa... | | + trader | | + util-linux | [] | + ve | | + vice | | + vmm | | + vorbis-tools | [] | + wastesedge | | + wcd | | + wcd-man | | + wdiff | [] [] | + wget | [] | + wyslij-po | | + xboard | | + xdg-user-dirs | [] [] [] [] [] [] [] [] [] [] | + xkeyboard-config | [] [] [] | + +---------------------------------------------------+ + af am an ar as ast az be bg bn bn_IN bs ca crh cs + 4 0 2 5 3 11 0 8 23 3 3 1 54 4 73 + + da de el en en_GB en_ZA eo es et eu fa fi fr + +--------------------------------------------------+ + a2ps | [] [] [] [] [] [] [] [] [] | + aegis | [] [] [] [] | + anubis | [] [] [] [] [] | + aspell | [] [] [] [] [] [] [] | + bash | [] [] [] | + bfd | [] [] [] [] | + binutils | [] [] [] | + bison | [] [] [] [] [] [] [] [] | + bison-runtime | [] [] [] [] [] [] [] [] | + buzztrax | [] [] [] [] | + ccd2cue | [] [] [] | + ccide | [] [] [] [] [] [] | + cflow | [] [] [] [] [] | + clisp | [] [] [] [] [] | + coreutils | [] [] [] [] [] | + cpio | [] [] [] [] [] | + cppi | [] [] [] [] [] | + cpplib | [] [] [] [] [] [] | + cryptsetup | [] [] [] [] [] | + datamash | [] [] [] [] | + denemo | [] | + dfarc | [] [] [] [] [] [] | + dialog | [] [] [] [] [] [] [] [] [] | + dico | [] [] [] [] | + diffutils | [] [] [] [] [] [] | + dink | [] [] [] [] [] [] | + direvent | [] [] [] [] | + doodle | [] [] [] [] | + dos2unix | [] [] [] [] [] | + dos2unix-man | [] [] [] | + e2fsprogs | [] [] [] [] [] | + enscript | [] [] [] [] [] [] | + exif | [] [] [] [] [] [] | + fetchmail | [] () [] [] [] [] [] | + findutils | [] [] [] [] [] [] [] [] | + flex | [] [] [] [] [] [] | + freedink | [] [] [] [] [] [] [] [] | + fusionforge | [] [] [] | + gas | [] [] [] | + gawk | [] [] [] [] [] | + gcal | [] [] [] [] | + gcc | [] [] | + gdbm | [] [] [] [] [] | + gettext-examples | [] [] [] [] [] [] [] | + gettext-runtime | [] [] [] [] [] [] | + gettext-tools | [] [] [] [] [] | + gjay | [] [] [] [] | + glunarclock | [] [] [] [] [] | + gnubiff | () [] [] () | + gnubik | [] [] [] [] [] | + gnucash | [] () () () () () () | + gnuchess | [] [] [] [] | + gnulib | [] [] [] [] [] [] [] | + gnunet | [] | + gnunet-gtk | [] | + gold | [] [] [] | + gphoto2 | [] () [] [] | + gprof | [] [] [] [] [] [] | + gramadoir | [] [] [] [] [] | + grep | [] [] [] [] [] [] [] | + grub | [] [] [] [] [] | + gsasl | [] [] [] [] [] | + gss | [] [] [] [] [] | + gst-plugins-bad | [] [] | + gst-plugins-base | [] [] [] [] [] [] | + gst-plugins-good | [] [] [] [] [] [] [] | + gst-plugins-ugly | [] [] [] [] [] [] [] [] | + gstreamer | [] [] [] [] [] [] [] | + gtick | [] () [] [] [] | + gtkam | [] () [] [] [] [] | + gtkspell | [] [] [] [] [] [] [] [] | + guix | [] [] | + guix-packages | | + gutenprint | [] [] [] [] | + hello | [] [] [] [] [] [] [] [] | + help2man | [] [] [] [] [] [] [] | + help2man-texi | [] [] [] | + hylafax | [] [] | + idutils | [] [] [] [] [] | + iso_15924 | [] () [] [] () [] () | + iso_3166 | [] () [] [] [] [] () [] () | + iso_3166_2 | [] () () () | + iso_4217 | [] () [] [] [] () [] () | + iso_639 | [] () [] [] () [] () | + iso_639_3 | () () () | + iso_639_5 | () () () | + jwhois | [] [] [] [] [] | + kbd | [] [] [] [] [] [] | + klavaro | [] [] [] [] [] [] [] | + latrine | [] () [] [] | + ld | [] [] [] [] | + leafpad | [] [] [] [] [] [] [] [] | + libc | [] [] [] [] [] | + libexif | [] [] () [] [] | + libextractor | [] | + libgnutls | [] [] [] [] | + libgphoto2 | [] () [] | + libgphoto2_port | [] () [] [] [] [] | + libgsasl | [] [] [] [] [] | + libiconv | [] [] [] [] [] [] [] | + libidn | [] [] [] [] [] | + liferea | [] () [] [] [] [] [] | + lilypond | [] [] [] [] [] [] | + lordsawar | [] [] | + lprng | | + lynx | [] [] [] [] [] [] | + m4 | [] [] [] [] [] [] | + mailfromd | [] | + mailutils | [] [] [] [] | + make | [] [] [] [] [] | + man-db | [] [] [] [] | + man-db-manpages | [] [] | + midi-instruments | [] [] [] [] [] [] [] [] [] | + minicom | [] [] [] [] [] | + mkisofs | [] [] [] | + myserver | [] [] [] [] | + nano | [] [] [] [] [] [] [] | + opcodes | [] [] [] [] [] | + parted | [] [] [] | + pies | [] | + popt | [] [] [] [] [] [] | + procps-ng | [] [] | + procps-ng-man | [] [] | + psmisc | [] [] [] [] [] [] [] | + pspp | [] [] [] | + pushover | () [] [] [] | + pwdutils | [] [] [] | + pyspread | [] [] [] | + radius | [] [] | + recode | [] [] [] [] [] [] [] | + recutils | [] [] [] [] | + rpm | [] [] [] [] [] | + rush | [] [] [] | + sarg | [] [] | + sed | [] [] [] [] [] [] [] [] | + sharutils | [] [] [] [] | + shishi | [] [] [] | + skribilo | [] [] | + solfege | [] [] [] [] [] [] [] [] | + solfege-manual | [] [] [] [] [] | + spotmachine | [] [] [] [] | + sudo | [] [] [] [] [] [] | + sudoers | [] [] [] [] [] [] | + sysstat | [] [] [] [] [] [] | + tar | [] [] [] [] [] [] [] | + texinfo | [] [] [] [] [] | + texinfo_document | [] [] [] [] | + tigervnc | [] [] [] [] [] [] | + tin | [] [] [] [] | + tin-man | [] | + tracgoogleappsa... | [] [] [] [] [] | + trader | [] [] [] [] [] [] | + util-linux | [] [] [] [] | + ve | [] [] [] [] [] | + vice | () () () | + vmm | [] [] | + vorbis-tools | [] [] [] [] | + wastesedge | [] () | + wcd | [] [] [] [] | + wcd-man | [] | + wdiff | [] [] [] [] [] [] [] | + wget | [] [] [] [] [] [] | + wyslij-po | [] [] [] [] | + xboard | [] [] [] [] | + xdg-user-dirs | [] [] [] [] [] [] [] [] [] [] | + xkeyboard-config | [] [] [] [] [] [] [] | + +--------------------------------------------------+ + da de el en en_GB en_ZA eo es et eu fa fi fr + 120 130 32 1 6 0 94 95 22 13 4 103 136 + + ga gd gl gu he hi hr hu hy ia id is it ja ka kk + +-------------------------------------------------+ + a2ps | [] [] [] [] | + aegis | [] | + anubis | [] [] [] [] | + aspell | [] [] [] [] [] | + bash | [] [] [] | + bfd | [] [] | + binutils | [] [] [] | + bison | [] | + bison-runtime | [] [] [] [] [] [] [] [] | + buzztrax | | + ccd2cue | [] | + ccide | [] [] | + cflow | [] [] [] | + clisp | | + coreutils | [] [] [] | + cpio | [] [] [] [] [] [] | + cppi | [] [] [] [] [] | + cpplib | [] [] | + cryptsetup | [] | + datamash | | + denemo | [] | + dfarc | [] [] [] | + dialog | [] [] [] [] [] [] [] [] [] [] | + dico | | + diffutils | [] [] [] [] | + dink | [] | + direvent | [] | + doodle | [] [] | + dos2unix | [] [] | + dos2unix-man | | + e2fsprogs | [] | + enscript | [] [] [] | + exif | [] [] [] [] [] [] | + fetchmail | [] [] [] | + findutils | [] [] [] [] [] [] [] | + flex | [] | + freedink | [] [] [] [] | + fusionforge | | + gas | [] | + gawk | [] () [] | + gcal | | + gcc | | + gdbm | | + gettext-examples | [] [] [] [] [] [] [] | + gettext-runtime | [] [] [] [] [] [] [] | + gettext-tools | [] [] [] | + gjay | [] | + glunarclock | [] [] [] [] [] [] | + gnubiff | [] [] () | + gnubik | [] [] [] | + gnucash | () () () () () [] | + gnuchess | | + gnulib | [] [] [] [] [] | + gnunet | | + gnunet-gtk | | + gold | [] [] | + gphoto2 | [] [] [] [] | + gprof | [] [] [] [] | + gramadoir | [] [] [] | + grep | [] [] [] [] [] [] [] | + grub | [] [] [] | + gsasl | [] [] [] [] [] | + gss | [] [] [] [] [] | + gst-plugins-bad | [] | + gst-plugins-base | [] [] [] [] | + gst-plugins-good | [] [] [] [] [] [] | + gst-plugins-ugly | [] [] [] [] [] [] | + gstreamer | [] [] [] [] [] | + gtick | [] [] [] [] [] | + gtkam | [] [] [] [] [] | + gtkspell | [] [] [] [] [] [] [] [] [] [] | + guix | | + guix-packages | | + gutenprint | [] [] [] | + hello | [] [] [] [] [] | + help2man | [] [] [] | + help2man-texi | | + hylafax | [] | + idutils | [] [] | + iso_15924 | [] [] [] [] [] [] | + iso_3166 | [] [] [] [] [] [] [] [] [] [] [] [] [] | + iso_3166_2 | [] [] | + iso_4217 | [] [] [] [] [] [] | + iso_639 | [] [] [] [] [] [] [] [] [] | + iso_639_3 | [] [] | + iso_639_5 | | + jwhois | [] [] [] [] | + kbd | [] [] [] | + klavaro | [] [] [] [] [] | + latrine | [] | + ld | [] [] [] [] | + leafpad | [] [] [] [] [] [] [] () | + libc | [] [] [] [] [] | + libexif | [] | + libextractor | | + libgnutls | [] | + libgphoto2 | [] [] | + libgphoto2_port | [] [] | + libgsasl | [] [] [] [] | + libiconv | [] [] [] [] [] [] [] | + libidn | [] [] [] [] | + liferea | [] [] [] [] [] | + lilypond | [] | + lordsawar | | + lprng | [] | + lynx | [] [] [] [] | + m4 | [] [] [] [] [] | + mailfromd | | + mailutils | | + make | [] [] [] [] | + man-db | [] [] | + man-db-manpages | [] [] | + midi-instruments | [] [] [] [] [] [] [] [] [] | + minicom | [] [] [] | + mkisofs | [] [] | + myserver | [] | + nano | [] [] [] [] [] | + opcodes | [] [] [] | + parted | [] [] [] [] | + pies | | + popt | [] [] [] [] [] [] [] [] [] [] | + procps-ng | | + procps-ng-man | | + psmisc | [] [] [] [] | + pspp | [] [] | + pushover | [] | + pwdutils | [] | + pyspread | | + radius | [] | + recode | [] [] [] [] [] [] [] | + recutils | | + rpm | [] | + rush | [] | + sarg | | + sed | [] [] [] [] [] [] [] | + sharutils | | + shishi | | + skribilo | [] | + solfege | [] [] | + solfege-manual | | + spotmachine | | + sudo | [] [] [] [] | + sudoers | [] [] [] | + sysstat | [] [] [] | + tar | [] [] [] [] [] [] | + texinfo | [] [] [] | + texinfo_document | [] [] | + tigervnc | | + tin | | + tin-man | | + tracgoogleappsa... | [] [] [] [] | + trader | [] [] | + util-linux | [] | + ve | [] | + vice | () () | + vmm | | + vorbis-tools | [] [] | + wastesedge | () | + wcd | | + wcd-man | | + wdiff | [] [] [] | + wget | [] [] [] | + wyslij-po | [] [] [] | + xboard | | + xdg-user-dirs | [] [] [] [] [] [] [] [] [] [] [] [] [] [] | + xkeyboard-config | [] [] [] [] [] | + +-------------------------------------------------+ + ga gd gl gu he hi hr hu hy ia id is it ja ka kk + 35 2 47 4 8 2 53 69 2 6 80 11 86 58 0 3 + + kn ko ku ky lg lt lv mk ml mn mr ms mt nb ne nl + +--------------------------------------------------+ + a2ps | [] [] | + aegis | [] | + anubis | [] [] [] | + aspell | [] [] | + bash | [] [] | + bfd | | + binutils | | + bison | [] | + bison-runtime | [] [] [] [] [] [] | + buzztrax | | + ccd2cue | | + ccide | [] [] | + cflow | [] | + clisp | [] | + coreutils | [] [] | + cpio | [] | + cppi | | + cpplib | [] | + cryptsetup | [] | + datamash | [] [] | + denemo | | + dfarc | [] [] | + dialog | [] [] [] [] [] [] | + dico | | + diffutils | [] [] [] | + dink | [] | + direvent | [] | + doodle | [] | + dos2unix | [] [] | + dos2unix-man | [] | + e2fsprogs | [] | + enscript | [] | + exif | [] [] | + fetchmail | [] | + findutils | [] [] | + flex | [] | + freedink | [] [] | + fusionforge | | + gas | | + gawk | [] | + gcal | | + gcc | | + gdbm | | + gettext-examples | [] [] [] [] [] [] | + gettext-runtime | [] [] | + gettext-tools | [] | + gjay | | + glunarclock | [] [] | + gnubiff | [] | + gnubik | [] [] | + gnucash | () () () () () () () [] | + gnuchess | [] [] | + gnulib | [] | + gnunet | | + gnunet-gtk | | + gold | | + gphoto2 | [] | + gprof | [] [] | + gramadoir | [] | + grep | [] [] | + grub | [] [] [] | + gsasl | [] | + gss | | + gst-plugins-bad | [] [] | + gst-plugins-base | [] [] [] | + gst-plugins-good | [] [] [] [] | + gst-plugins-ugly | [] [] [] [] [] | + gstreamer | [] [] | + gtick | [] | + gtkam | [] [] | + gtkspell | [] [] [] [] [] [] [] | + guix | | + guix-packages | | + gutenprint | [] | + hello | [] [] [] | + help2man | [] | + help2man-texi | | + hylafax | [] | + idutils | [] | + iso_15924 | () [] [] | + iso_3166 | [] [] [] () [] [] [] [] [] [] | + iso_3166_2 | () [] | + iso_4217 | () [] [] [] | + iso_639 | [] [] () [] [] [] [] | + iso_639_3 | [] () [] | + iso_639_5 | () | + jwhois | [] [] | + kbd | [] | + klavaro | [] [] | + latrine | | + ld | | + leafpad | [] [] [] [] [] | + libc | [] [] | + libexif | [] | + libextractor | [] | + libgnutls | [] [] | + libgphoto2 | [] | + libgphoto2_port | [] | + libgsasl | [] | + libiconv | [] [] | + libidn | [] | + liferea | [] [] [] | + lilypond | [] | + lordsawar | | + lprng | | + lynx | [] | + m4 | [] | + mailfromd | | + mailutils | | + make | [] [] | + man-db | [] | + man-db-manpages | [] | + midi-instruments | [] [] [] [] [] [] [] | + minicom | [] | + mkisofs | [] | + myserver | | + nano | [] [] [] | + opcodes | [] | + parted | [] | + pies | | + popt | [] [] [] [] [] | + procps-ng | | + procps-ng-man | | + psmisc | [] | + pspp | [] [] | + pushover | | + pwdutils | [] | + pyspread | | + radius | [] | + recode | [] [] | + recutils | [] | + rpm | [] | + rush | [] | + sarg | | + sed | [] [] | + sharutils | [] | + shishi | | + skribilo | | + solfege | [] [] | + solfege-manual | [] | + spotmachine | [] | + sudo | [] [] | + sudoers | [] [] | + sysstat | [] [] | + tar | [] [] [] | + texinfo | [] | + texinfo_document | [] | + tigervnc | [] | + tin | | + tin-man | | + tracgoogleappsa... | [] [] [] | + trader | [] | + util-linux | [] | + ve | [] | + vice | [] | + vmm | [] | + vorbis-tools | [] | + wastesedge | [] | + wcd | [] | + wcd-man | [] | + wdiff | [] | + wget | [] [] | + wyslij-po | [] | + xboard | [] | + xdg-user-dirs | [] [] [] [] [] [] [] [] [] [] [] | + xkeyboard-config | [] [] [] | + +--------------------------------------------------+ + kn ko ku ky lg lt lv mk ml mn mr ms mt nb ne nl + 5 11 4 6 0 13 22 3 3 3 4 11 2 40 1 124 + + nn or os pa pl ps pt pt_BR ro ru rw sk sl sq sr + +--------------------------------------------------+ + a2ps | [] [] [] [] [] [] [] | + aegis | [] [] | + anubis | [] [] [] | + aspell | [] [] [] [] [] [] [] | + bash | [] [] [] [] [] | + bfd | [] | + binutils | [] [] | + bison | [] [] [] | + bison-runtime | [] [] [] [] [] [] [] [] | + buzztrax | | + ccd2cue | [] | + ccide | [] [] [] | + cflow | [] [] | + clisp | [] | + coreutils | [] [] [] [] | + cpio | [] [] [] | + cppi | [] [] [] | + cpplib | [] [] [] | + cryptsetup | [] [] | + datamash | [] [] | + denemo | | + dfarc | [] [] [] | + dialog | [] [] [] [] [] [] [] | + dico | [] | + diffutils | [] [] | + dink | | + direvent | [] [] | + doodle | [] [] | + dos2unix | [] [] [] [] | + dos2unix-man | [] [] | + e2fsprogs | [] | + enscript | [] [] [] [] [] [] | + exif | [] [] [] [] [] [] | + fetchmail | [] [] [] | + findutils | [] [] [] [] [] | + flex | [] [] [] [] [] | + freedink | [] [] [] [] [] | + fusionforge | | + gas | | + gawk | [] | + gcal | | + gcc | | + gdbm | [] [] [] | + gettext-examples | [] [] [] [] [] [] [] [] | + gettext-runtime | [] [] [] [] [] [] [] [] [] | + gettext-tools | [] [] [] [] [] [] [] | + gjay | [] | + glunarclock | [] [] [] [] [] [] | + gnubiff | [] | + gnubik | [] [] [] [] | + gnucash | () () () () [] | + gnuchess | [] [] | + gnulib | [] [] [] [] [] | + gnunet | | + gnunet-gtk | | + gold | | + gphoto2 | [] [] [] [] [] | + gprof | [] [] [] [] | + gramadoir | [] [] | + grep | [] [] [] [] [] [] | + grub | [] [] [] [] [] | + gsasl | [] [] [] | + gss | [] [] [] [] | + gst-plugins-bad | [] [] [] [] | + gst-plugins-base | [] [] [] [] [] [] | + gst-plugins-good | [] [] [] [] [] [] [] | + gst-plugins-ugly | [] [] [] [] [] [] [] | + gstreamer | [] [] [] [] [] [] [] | + gtick | [] [] [] [] [] | + gtkam | [] [] [] [] [] [] | + gtkspell | [] [] [] [] [] [] [] [] [] | + guix | | + guix-packages | | + gutenprint | [] [] | + hello | [] [] [] [] [] [] | + help2man | [] [] [] [] | + help2man-texi | [] | + hylafax | | + idutils | [] [] [] | + iso_15924 | [] () [] [] [] [] | + iso_3166 | [] [] [] [] () [] [] [] [] [] [] [] [] | + iso_3166_2 | [] () [] | + iso_4217 | [] [] () [] [] [] [] [] | + iso_639 | [] [] [] () [] [] [] [] [] [] | + iso_639_3 | [] () | + iso_639_5 | () [] | + jwhois | [] [] [] [] | + kbd | [] [] | + klavaro | [] [] [] [] [] | + latrine | [] | + ld | | + leafpad | [] [] [] [] [] [] [] [] [] | + libc | [] [] [] | + libexif | [] () [] | + libextractor | [] | + libgnutls | [] | + libgphoto2 | [] | + libgphoto2_port | [] [] [] [] [] | + libgsasl | [] [] [] [] | + libiconv | [] [] [] [] [] | + libidn | [] [] [] | + liferea | [] [] [] [] () [] [] | + lilypond | | + lordsawar | | + lprng | [] | + lynx | [] [] | + m4 | [] [] [] [] [] | + mailfromd | [] | + mailutils | [] | + make | [] [] [] | + man-db | [] [] [] | + man-db-manpages | [] [] [] | + midi-instruments | [] [] [] [] [] [] [] [] | + minicom | [] [] [] [] | + mkisofs | [] [] [] | + myserver | [] [] | + nano | [] [] [] [] [] [] | + opcodes | | + parted | [] [] [] [] [] [] | + pies | [] | + popt | [] [] [] [] [] [] | + procps-ng | [] | + procps-ng-man | [] | + psmisc | [] [] [] [] | + pspp | [] [] | + pushover | | + pwdutils | [] | + pyspread | [] [] | + radius | [] [] | + recode | [] [] [] [] [] [] [] [] | + recutils | [] | + rpm | [] | + rush | [] [] [] | + sarg | [] [] | + sed | [] [] [] [] [] [] [] [] | + sharutils | [] [] [] | + shishi | [] [] | + skribilo | | + solfege | [] [] [] | + solfege-manual | [] [] | + spotmachine | [] [] | + sudo | [] [] [] [] [] [] | + sudoers | [] [] [] [] | + sysstat | [] [] [] [] [] | + tar | [] [] [] [] [] | + texinfo | [] [] [] | + texinfo_document | [] [] | + tigervnc | [] | + tin | [] | + tin-man | | + tracgoogleappsa... | [] [] [] [] | + trader | [] | + util-linux | [] [] | + ve | [] [] [] | + vice | | + vmm | | + vorbis-tools | [] [] [] | + wastesedge | | + wcd | | + wcd-man | | + wdiff | [] [] [] [] [] | + wget | [] [] [] [] | + wyslij-po | [] [] [] [] | + xboard | [] [] [] | + xdg-user-dirs | [] [] [] [] [] [] [] [] [] [] [] [] [] | + xkeyboard-config | [] [] [] [] | + +--------------------------------------------------+ + nn or os pa pl ps pt pt_BR ro ru rw sk sl sq sr + 7 3 1 6 114 1 12 83 32 80 3 38 45 7 94 + + sv sw ta te tg th tr uk ur vi wa wo zh_CN zh_HK + +---------------------------------------------------+ + a2ps | [] [] [] [] [] | + aegis | [] | + anubis | [] [] [] [] | + aspell | [] [] [] [] | + bash | [] [] [] [] | + bfd | [] [] | + binutils | [] [] [] | + bison | [] [] [] [] | + bison-runtime | [] [] [] [] [] [] | + buzztrax | [] [] [] | + ccd2cue | [] [] [] | + ccide | [] [] [] [] | + cflow | [] [] [] [] | + clisp | | + coreutils | [] [] [] [] | + cpio | [] [] [] [] [] | + cppi | [] [] [] [] | + cpplib | [] [] [] [] [] | + cryptsetup | [] [] [] | + datamash | [] [] [] | + denemo | | + dfarc | [] | + dialog | [] [] [] [] [] [] | + dico | [] | + diffutils | [] [] [] [] [] | + dink | | + direvent | [] [] | + doodle | [] [] | + dos2unix | [] [] [] [] | + dos2unix-man | [] [] [] | + e2fsprogs | [] [] [] [] | + enscript | [] [] [] [] | + exif | [] [] [] [] [] | + fetchmail | [] [] [] [] | + findutils | [] [] [] [] [] | + flex | [] [] [] [] | + freedink | [] [] | + fusionforge | | + gas | [] | + gawk | [] [] | + gcal | [] [] | + gcc | [] [] | + gdbm | [] [] | + gettext-examples | [] [] [] [] [] [] | + gettext-runtime | [] [] [] [] [] [] | + gettext-tools | [] [] [] [] [] | + gjay | [] [] | + glunarclock | [] [] [] [] | + gnubiff | [] [] | + gnubik | [] [] [] [] | + gnucash | () () () () [] | + gnuchess | [] [] | + gnulib | [] [] [] [] | + gnunet | | + gnunet-gtk | | + gold | [] [] | + gphoto2 | [] [] [] [] | + gprof | [] [] [] [] | + gramadoir | [] [] [] | + grep | [] [] [] [] [] | + grub | [] [] [] [] | + gsasl | [] [] [] [] | + gss | [] [] [] | + gst-plugins-bad | [] [] [] [] | + gst-plugins-base | [] [] [] [] [] | + gst-plugins-good | [] [] [] [] [] | + gst-plugins-ugly | [] [] [] [] [] | + gstreamer | [] [] [] [] [] | + gtick | [] [] [] | + gtkam | [] [] [] [] | + gtkspell | [] [] [] [] [] [] [] [] | + guix | [] | + guix-packages | | + gutenprint | [] [] [] [] | + hello | [] [] [] [] [] [] | + help2man | [] [] [] | + help2man-texi | [] | + hylafax | [] | + idutils | [] [] [] | + iso_15924 | [] () [] [] () [] | + iso_3166 | [] [] () [] [] () [] [] [] | + iso_3166_2 | () [] [] () [] | + iso_4217 | [] () [] [] () [] [] | + iso_639 | [] [] [] () [] [] () [] [] [] | + iso_639_3 | [] () [] [] () | + iso_639_5 | () [] () | + jwhois | [] [] [] [] | + kbd | [] [] [] | + klavaro | [] [] [] [] [] [] | + latrine | [] [] | + ld | [] [] [] [] [] | + leafpad | [] [] [] [] [] [] | + libc | [] [] [] [] [] | + libexif | [] () | + libextractor | [] [] | + libgnutls | [] [] [] [] | + libgphoto2 | [] [] | + libgphoto2_port | [] [] [] [] | + libgsasl | [] [] [] [] | + libiconv | [] [] [] [] [] | + libidn | () [] [] [] | + liferea | [] [] [] [] [] | + lilypond | [] | + lordsawar | | + lprng | [] | + lynx | [] [] [] [] | + m4 | [] [] [] | + mailfromd | [] [] | + mailutils | [] | + make | [] [] [] [] | + man-db | [] [] | + man-db-manpages | [] | + midi-instruments | [] [] [] [] [] [] | + minicom | [] [] | + mkisofs | [] [] [] | + myserver | [] | + nano | [] [] [] [] | + opcodes | [] [] [] | + parted | [] [] [] [] [] | + pies | [] [] | + popt | [] [] [] [] [] [] [] | + procps-ng | [] [] | + procps-ng-man | [] | + psmisc | [] [] [] [] | + pspp | [] [] [] | + pushover | [] | + pwdutils | [] [] | + pyspread | [] | + radius | [] [] | + recode | [] [] [] [] | + recutils | [] [] [] | + rpm | [] [] [] [] | + rush | [] [] | + sarg | | + sed | [] [] [] [] [] | + sharutils | [] [] [] | + shishi | [] [] | + skribilo | [] | + solfege | [] [] [] | + solfege-manual | [] | + spotmachine | [] [] [] | + sudo | [] [] [] [] | + sudoers | [] [] [] | + sysstat | [] [] [] [] [] | + tar | [] [] [] [] [] | + texinfo | [] [] [] | + texinfo_document | [] | + tigervnc | [] [] | + tin | [] | + tin-man | | + tracgoogleappsa... | [] [] [] [] [] | + trader | [] | + util-linux | [] [] [] | + ve | [] [] [] [] | + vice | () () | + vmm | | + vorbis-tools | [] [] | + wastesedge | | + wcd | [] [] [] | + wcd-man | [] | + wdiff | [] [] [] [] | + wget | [] [] [] | + wyslij-po | [] [] | + xboard | [] | + xdg-user-dirs | [] [] [] [] [] [] [] [] [] | + xkeyboard-config | [] [] [] [] | + +---------------------------------------------------+ + sv sw ta te tg th tr uk ur vi wa wo zh_CN zh_HK + 91 1 4 3 0 13 50 113 1 126 7 1 95 7 + + zh_TW + +-------+ + a2ps | | 30 + aegis | | 9 + anubis | | 19 + aspell | | 28 + bash | [] | 21 + bfd | | 9 + binutils | | 12 + bison | [] | 18 + bison-runtime | [] | 38 + buzztrax | | 8 + ccd2cue | | 8 + ccide | | 17 + cflow | | 15 + clisp | | 10 + coreutils | | 20 + cpio | | 20 + cppi | | 17 + cpplib | [] | 19 + cryptsetup | | 13 + datamash | | 11 + denemo | | 4 + dfarc | | 16 + dialog | [] | 42 + dico | | 6 + diffutils | | 21 + dink | | 9 + direvent | | 10 + doodle | | 12 + dos2unix | [] | 18 + dos2unix-man | | 9 + e2fsprogs | | 14 + enscript | | 21 + exif | | 26 + fetchmail | | 19 + findutils | | 28 + flex | [] | 19 + freedink | | 23 + fusionforge | | 3 + gas | | 5 + gawk | | 12 + gcal | | 7 + gcc | | 4 + gdbm | | 10 + gettext-examples | [] | 40 + gettext-runtime | [] | 34 + gettext-tools | [] | 24 + gjay | | 8 + glunarclock | [] | 27 + gnubiff | | 9 + gnubik | | 19 + gnucash | () | 7 + gnuchess | | 10 + gnulib | | 23 + gnunet | | 1 + gnunet-gtk | | 1 + gold | | 7 + gphoto2 | [] | 19 + gprof | | 21 + gramadoir | | 14 + grep | [] | 31 + grub | | 21 + gsasl | [] | 19 + gss | | 17 + gst-plugins-bad | | 14 + gst-plugins-base | | 27 + gst-plugins-good | | 32 + gst-plugins-ugly | | 34 + gstreamer | [] | 31 + gtick | | 19 + gtkam | | 24 + gtkspell | [] | 48 + guix | | 3 + guix-packages | | 0 + gutenprint | | 15 + hello | [] | 30 + help2man | | 18 + help2man-texi | | 5 + hylafax | | 5 + idutils | | 14 + iso_15924 | [] | 23 + iso_3166 | [] | 58 + iso_3166_2 | | 9 + iso_4217 | [] | 28 + iso_639 | [] | 46 + iso_639_3 | | 10 + iso_639_5 | | 2 + jwhois | [] | 20 + kbd | | 16 + klavaro | | 30 + latrine | | 7 + ld | [] | 15 + leafpad | [] | 40 + libc | [] | 24 + libexif | | 9 + libextractor | | 5 + libgnutls | | 13 + libgphoto2 | | 9 + libgphoto2_port | [] | 19 + libgsasl | | 18 + libiconv | [] | 29 + libidn | | 17 + liferea | | 29 + lilypond | | 11 + lordsawar | | 3 + lprng | | 3 + lynx | | 19 + m4 | [] | 22 + mailfromd | | 4 + mailutils | | 6 + make | | 19 + man-db | | 14 + man-db-manpages | | 9 + midi-instruments | [] | 43 + minicom | [] | 17 + mkisofs | | 13 + myserver | | 9 + nano | [] | 29 + opcodes | | 12 + parted | [] | 21 + pies | | 4 + popt | [] | 36 + procps-ng | | 5 + procps-ng-man | | 4 + psmisc | [] | 22 + pspp | | 13 + pushover | | 6 + pwdutils | | 8 + pyspread | | 6 + radius | | 9 + recode | | 31 + recutils | | 9 + rpm | [] | 13 + rush | | 10 + sarg | | 4 + sed | [] | 34 + sharutils | | 12 + shishi | | 7 + skribilo | | 4 + solfege | | 19 + solfege-manual | | 9 + spotmachine | | 10 + sudo | | 24 + sudoers | | 20 + sysstat | | 22 + tar | [] | 30 + texinfo | | 17 + texinfo_document | | 11 + tigervnc | | 11 + tin | [] | 7 + tin-man | | 1 + tracgoogleappsa... | [] | 22 + trader | | 11 + util-linux | | 12 + ve | | 14 + vice | | 1 + vmm | | 3 + vorbis-tools | | 13 + wastesedge | | 2 + wcd | | 8 + wcd-man | | 3 + wdiff | [] | 23 + wget | | 19 + wyslij-po | | 14 + xboard | | 9 + xdg-user-dirs | [] | 68 + xkeyboard-config | [] | 27 + +-------+ + 90 teams zh_TW + 166 domains 42 2748 + + Some counters in the preceding matrix are higher than the number of +visible blocks let us expect. This is because a few extra PO files are +used for implementing regional variants of languages, or language +dialects. + + For a PO file in the matrix above to be effective, the package to +which it applies should also have been internationalized and distributed +as such by its maintainer. There might be an observable lag between the +mere existence a PO file and its wide availability in a distribution. + + If Jun 2014 seems to be old, you may fetch a more recent copy of this +'ABOUT-NLS' file on most GNU archive sites. The most up-to-date matrix +with full percentage details can be found at +'http://translationproject.org/extra/matrix.html'. + +1.5 Using 'gettext' in new packages +=================================== + +If you are writing a freely available program and want to +internationalize it you are welcome to use GNU 'gettext' in your +package. Of course you have to respect the GNU Lesser General Public +License which covers the use of the GNU 'gettext' library. This means +in particular that even non-free programs can use 'libintl' as a shared +library, whereas only free software can use 'libintl' as a static +library or use modified versions of 'libintl'. + + Once the sources are changed appropriately and the setup can handle +the use of 'gettext' the only thing missing are the translations. The +Free Translation Project is also available for packages which are not +developed inside the GNU project. Therefore the information given above +applies also for every other Free Software Project. Contact +'coordinator@translationproject.org' to make the '.pot' files available +to the translation teams. diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..fa9e7fe --- /dev/null +++ b/AUTHORS @@ -0,0 +1,13 @@ + Copyright (C) 2006, 2007 Free Software Foundation, Inc. + + Copying and distribution of this file, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. + +Gawk was written by Paul Rubin, and finished by Paul Finlason and +Richard Stallman. + +David Trueman and Arnold Robbins took it over, with David doing most +of the work to make it compatible with new awk. + +Circa 1994, Arnold Robbins took over maintenance. diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..b31740b --- /dev/null +++ b/ChangeLog @@ -0,0 +1,7655 @@ +2018-02-25 Arnold D. Robbins + + * 4.2.1: Release tar ball made. + +2018-02-25 Arnold D. Robbins + + * config.guess, config.sub: Updated. + +2018-02-23 Arnold D. Robbins + + * configure.ac: Restore checking for PPC Macintosh before + checking for MPFR. See README_d/README.macosx for info. + +2018-02-21 Arnold D. Robbins + + * configure.ac: Remove checking for PPC Macintosh before + checking for MPFR. Installing a newer compiler on that + system allows things to work. + +2018-02-19 Arnold D. Robbins + + * gawkapi.h, io.c, msg.c: Update copyright year. + +2018-02-10 Arnold D. Robbins + + * main.c, msg.c: Add a call to fflush(NULL) before each call + to abort(), since GLIBC 2.27 doesn't necessarily flush before + aborting. Thanks to Nelson H.F. Beebe for the report. + +2018-02-09 Arnold D. Robbins + + * io.c (socketopen): Rearrange assigning the flags to use + AI_ADDRCONFIG only if family is AF_UNSPEC. Thanks to + Houder for the report and initial + code suggestion. + +2018-02-07 Andrew J. Schorr + + Print +"01" should print "1", not "01". + * interpret.h (Op_unary_plus): Need to make a new number node that does + not contain the original string representation. The logic is copied + from Op_unary_minus. + * mpfr.c (mpg_interpret): Add new case for Op_unary_plus based on + the Op_unary_minus logic. We need a fresh number node that does not + contain the string. + +2018-01-28 Arnold D. Robbins + + * config.guess, config.sub: Updated. + +2018-01-25 Arnold D. Robbins + + * main.c (main): Add explanatory comment about O_APPEND stuff. + * NEWS: Updated. + +2018-01-22 Arnold D. Robbins + + Fix the inplace tests on *BSD systems. + + * main.c (main): Add O_APPEND flag to fileno(stderr). + +2018-01-17 Arnold D. Robbins + + * builtin.c (do_isarray): Check that tmp is Node_var + before calling DEREF. Thanks to Denis Shirokov + for the report. + +2018-01-15 Arnold D. Robbins + + * NEWS: Small typo fix. + * config.sub: Updated. + * io.c (fork_and_open_slave_pty): Rationalize down to one + function with two bodies. + (set_slave_pty_attributes, push_pty_line_disciplines): Move + into #ifdef for TERMIOS_H. Helps out with VMS compiling. + +2018-01-12 Arnold D. Robbins + + * gawkapi.h: Remove extraneous '*' on parameters of + type awk_ext_id. Thanks to Andrew Schorr for the report. + +2018-01-11 Arnold D. Robbins + + * compile, config.guess, config.rpath, config.sub, + depcomp: Updated from GNULIB. + +2018-01-08 John E. Malmberg + + * io.c (set_slave_pty_attributes): Currently no termios on VMS. + (set_slave_pty_attributes): No fork on VMS. + +2018-01-04 Arnold D. Robbins + + Refactor handling of slave pty. On AIX and HP-UX open + slave in the child. Otherwise open slave in the parent + before forking (restoring code mostly from 4.1.3). Thanks + to Andrew Schorr for the bug report. + + * io.c (fork_and_open_slave_pty): New routine. Two versions. + (set_slave_pty_attributes): New routine. Common code used by + both versions of fork_and_open_slave_pty. + (push_pty_line_disciplines): New routine. Common code used by + both versions of fork_and_open_slave_pty. + (two_way_open): Call fork_and_open_slave_pty instead of + doing it inline. + +2018-01-03 Arnold D. Robbins + + * main.c (UPDATE_YEAR): Move to 2018. Revise copyright year. + * NEWS: Bring up to date. + +2018-01-02 Arnold D. Robbins + + If ROUNDMODE changes, cause cached string conversions + to become invalid. Thanks to Nethox + for the report. Day 1 bug from 4.1.0 release. + + In all the below files, bump copyright year, too. + + * array.c (value_info): Include strndmode in the output. + * awk.h (NODE): New member, strndmode. + (MPFR_round_mode): Add extern declaration. + (force_string_fmt): Check s->strnmode against MPFR_round_mode. + * awkgram.y (set_profile_text): Set n->strndmode to MPFR_round_mode. + * builtin.c (do_print): Remove tests and just call force_string_fmt. + * field.c (set_record): Set n->strndmode to MPFR_round_mode. + * gawkapi.c (api_sym_update_scalar): Set r->strndmode to + MPFR_round_mode. + * interpret.h (r_interpret): For Op_assign_concat, set t1->strndmode + to MPFR_round_mode. + * mpfr.c (MPFR_round_mode): Define and initialize. + (mpfr_format_val): Set s->strndmode to MPFR_round_mode. + (set_ROUNDMODE): Update MPFR_round_mode when ROUNDMODE changes + successfully. + * node.c (r_format_val): Set s->strndmode to MPFR_round_mode. + (make_str_node): Set r->strndmode to MPFR_round_mode. + * str_array.c (str_kilobytes): Update a comment. + * symbol.c (check_param_names): Set n.strndmode to MPFR_round_mode. + +2017-12-24 Arnold D. Robbins + + Avoid some compiler warnings. Thanks to Michal Jaegermann + for the report. + + * builtin.c (do_strftime): Initialize save. + (do_dcgetttext): Initialize save and save2. + (do_dcngettext): Ditto. + (do_bindtextdomain): Initialize save and save1. + + Unrelated: + + * main.c (optlist): Make 'L' option's argument optional, to + match --lint. Thanks to Manuel Collado + for the report. + +2017-12-22 Arnold D. Robbins + + * config.guess, config.sub, depcomp, install-sh: Updated + from GNULIB. + +2017-12-20 Arnold D. Robbins + + * configure.ac: Add --enable-versioned-dir option for a + directory with API version in it to hold extensions. + +2017-12-19 Arnold D. Robbins + + * configure.ac: Remove x's from `test "x$something" = "xyes" + kinds of things. With correct quoting, the x isn't needed. + (DYNAMIC): Remove use of -Wl,-export-dynamic on Linux + and FreeBSD. It was needed for old-style extensions, which are + no longer supported. + +2017-12-10 Arnold D. Robbins + + * awkgram.y: For '!' optimization on a string constant, don't + apply the optimization if it's a translatable string. Thanks + to Jeremy Feusi for the report. + +2017-11-25 Andrew J. Schorr + + * debug.c (do_set_var): As in interpret.h (Op_store_field), we should + call the assign function before unref to give it a chance to copy + any non-malloced $n string values before freeing $0. + +2017-11-14 Andrew J. Schorr + + * mpfr.c (get_rnd_mode): Fix MPFR_RNDA comment. + +2017-11-14 Andrew J. Schorr + + Fix corruption when $0 is reassigned while other NODEs have open + references to $n. Thanks to Eric Pruitt for + the bug report. + + * field.c (purge_record): For each $n field variable, if valref > 1 + and it has not already been malloced, make a copy of the string, since + $0 is about to be reset. + * interpret.h (Op_store_field): We must call the assign function + before unref, since we must copy any non-malloced $n string values + before freeing $0. + +2017-11-09 Arnold D. Robbins + + * main.c (usage): Add a note to not post bugs in comp.lang.awk. + So there. + +2017-11-08 Arnold D. Robbins + + * gawkapi.h (AWK_NUMBER_TYPE): Move this enum out to the + top level so that it works correctly with C++. + +2017-10-24 Arnold D. Robbins + + * NEWS: Updated with info about OS/2. + +2017-10-21 Arnold D. Robbins + + * awkgram.y: For string concatenation, don't fold constants + if one or the other is translatable. Thanks to Harald van Dijk + for the report. + +2017-10-21 KO Myung-Hun + + * nonposix.h [__KLIBC__]: Include dlfcn.h, declare os2_dlsym, and + redirect dlsym to os2_dlsym. Declare os2_fixdllname. Declare + os2_dlopen and redirect dlopen to os2_dlopen. + * io.h (find_source) [__EMX__]: Truncate extension file basename + to 8 characters. + +2017-10-19 Arnold D. Robbins + + * 4.2.0: Release tar ball made. + +2017-10-17 Andrew J. Schorr + + * NEWS: Actually, isarray is not deprecated in this release. + * builtin.c (do_isarray): Remove lint warning deprecating isarray. + +2017-10-14 Arnold D. Robbins + + * field.c (do_split): Simplify the lint warnings. + Based on suggested code by Eric Pruitt . + +2017-10-08 Arnold D. Robbins + + * command.y: Fix the FSF's address. + +2017-10-08 Arnold D. Robbins + + * NEWS: Rationalized with respect to stuff on the API. + Also rationalized with respect to the pretty printer changes. + +2017-10-04 Andrew J. Schorr + + * README: Fix grammar by removing a stray word. + +2017-10-04 Arnold D. Robbins + + * NEWS: Add a note about OS/2 not working. + +2017-10-02 Arnold D. Robbins + + * config.guess, config.sub: Updated. + +2017-09-28 Arnold D. Robbins + + * io.c (devopen): Move declaration of `cp' to where it's first used. + +2017-09-18 Arnold D. Robbins + + * README: Update required version of texinfo.tex. + * compile, config.guess, config.sub, depcomp: Updated. + +2017-09-17 Arnold D. Robbins + + * gawkapi.h: Small changes to make it usable with C++. + +2017-09-13 Arnold D. Robbins + + * Makefile.am (command.c): Don't need the dependency on awkgram.c + anymore. + * bisonfix.awk: Removed. + * README: Revised to describe use of Bison exclusively. + +2017-09-13 Andrew J. Schorr + + * Makefile.am (awkgram.c): Use -o option to bison. Get rid of + messing with y.tab.h, that was obsolete. + (EXTRA_DIST): Don't need bisonfix.awk anymore. + +2017-09-12 Petr Ovtchenkov + Andrew J. Schorr + + * Makefile.am (command.c): Make dependant on awkgram.c so + that bison is run serially with make -j. Use -o option so + that we no longer need bisonfix.awk in this rule. + +2017-08-28 Arnold D. Robbins + + * interpret.h (r_interpret): Add some casts to avoid warning + messages in printf statements. + + Unrelated: + + * configure.ac: Add check for gai_strerror. + * io.c (socketopen): Use gai_strerror to add more information + if getaddrinfo fails. + +2017-08-25 Pat Rankin + + * builtin.c (TYPE_MINIMUM): Use type uintmax_t for the calculation, + deferring the cast to the target type until the final result. + +2017-08-27 Juan Manuel Guerrero + + * mbsupport.h [__DJGPP_]: Provide multi-byte specific declarations + and definitions for DJGPP. + +2017-08-23 Arnold D. Robbins + + * README.git: Minor edits to make build steps clearer. + +2017-08-21 Daniel Richard G. + + * awk.h (c_func): Renamed to c_function to avoid conflict. + with z/OS headers. + * ext.c, interpret.h: Ditto. + * configure: Regenerated after update to m4/arch.m4. + +2017-08-18 Arnold D. Robbins + + * debug.c (do_set_var): Fix typos in error messages. + Thanks to Jean-Philippe Guerard + for the report. + +2017-08-17 Arnold D. Robbins + + * field.c (rebuild_record): Set new fields valref to 1 if + original field's valref was > 1. Update the comment. Found + by running chem. + * mpfr.c (do_mpfr_compl): Fix typo in warning message. + Thanks to Jean-Philippe Guerard + for the report. + * NEWS: Mention the Italian translation of the manual. + +2017-08-16 Arnold D. Robbins + + * gawkapi.c (assign_number): Clean up the code a bit. + (api_get_mpfr, api_get_mpz): Add return NULL in non-MPFR case + to avoid compiler warnings. + +2017-08-16 Arnold D. Robbins + + * config.guess: Update from GNULIB. + * NEWS, README: Updated in preparation for release. + +2017-08-16 Andrew J. Schorr + + * gawkapi.c (assign_number): Add 'ifdef HAVE_MPFR' tests to get this + to build in the absence of MPFR. + +2017-08-13 Arnold D. Robbins + + * gawkapi.h (gawk_api_major_version): Reset to 2 after merging + in feature/api-mpfr branch. + * NEWS: `intdiv' is not built-in; remove the entry for up and update + numbering. Add note about API supporting GMP and MPFR values. + +2017-08-09 Arnold D. Robbins + + * gawkapi.h (check_mpfr_versions): Define differently based on if + MPFR version macro is defined. Enhance body to use do/while(0). + (dl_load): Call check_mpfr_versions unconditionally. + +2017-08-09 Arnold D. Robbins + + * main.c (usage): Add URL for Bug reporting info to the help message. + + Unrelated: + + * str_array.c (str_lookup): Make a copy of the string if it + came from Nnull_string or a null field. Thanks to + Daniel Pettet for the report. + +2017-08-04 Arnold D. Robbins + + * array.c, awk.h, awkgram.y, builtin.c, cint_array.c, + cmd.h, debug.c, eval.c, ext.c, field.c, gawkapi.c, gawkmisc.c, + gettext.h, int_array.c, main.c, mpfr.c, msg.c, node.c, profile.c, + re.c, str_array.c, symbol.c: Update copyright years. + +2017-08-04 Arnold D. Robbins + + * config.guess, mkinstalldirs: Updated from GNULIB. + +2017-08-01 Juan Manuel Guerrero + + Bring DJGPP support up to speed. + + * awk.h: Add DJGPP in #if for include of nonposix.h + * nonposix.h (btowc, putwc): Add declarations for DJGPP. + +2017-07-17 Arnold D. Robbins + + * awkgram.y [non_post_simp_exp]: Merge LEX_BUILTIN and + LEX_LENGTH expansions. + (lookup_builtin): Move MPFR test to after test for sub builtin. + + * awkgram.y [non_post_simp_exp]: Unmerge LEX_BUILTIN and + LEX_LENGTH expansions. This introduced a reduce/reduce + conflict, and those are bad. I don't know why I didn't + notice this earlier. Sigh. + +2017-07-15 Arnold D. Robbins + + Revert change of 2016-07-24 that always runs the dfa + matcher. Based on a bug report from Alexandre Oliva + , DFA can cause gawk to hang, even + in the C locale. + + * re.c (research): Don't use dfa if need_start is true. + +2017-07-11 Arnold D. Robbins + + * awk.h (is_letter): Add declaration. + * ext.c (is_valid_identifier): New function. + (make_builtin): Use is_valid_identifier instead of inline code. + (is_letter): Moved from here ... + * awkgram.y (is_letter): ... to here. + (yylex): Use is_letter instead of a test. + * command.y (yylex): Ditto. + * main.c (arg_assign): Ditto. + +2017-07-07 Arnold D. Robbins + + Remove warnings from GCC 7.1 compilation. + + * awk.h (fatal_tag_valid): Change type to int. + * awkgram.y (yylex): Set did_newline to true instead of using ++. + * builtin.c (format_tree): Set lj to true instead of using ++. + * cmd.h (pager_quit_tag_valid): Change type to int. + * debug.c (pager_quit_tag_valid): Change type to int. + (do_clear): Make bp_found an int, change uses. + (do_run): Treat fatal_tag_valid as an int. + * msg.c (fatal_tag_valid): Change type to int. + +2017-07-07 Arnold D. Robbins + + * 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 + + * gawkapi.h, gawkapi.c: Typo fixes in comments. + +2017-06-26 Arnold D. Robbins + + * configure.ac: Turn a tab into a space in AC_DEFINE(SUPPLY_INTDIV). + +2017-06-25 Andrew J. Schorr + + * gawkmisc.c (xmalloc): Remove function now in support/xalloc.h. + +2017-06-22 Arnold D. Robbins + + 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 + + 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 + + * 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 + + * 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 + + * NEWS: Mention PROCINFO["argv"]. + +2017-05-24 Andrew J. Schorr + + * 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 + + * 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 + + * 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 + + * awkgram.y (add_lint): Make ``no effect'' check smarter about + reporting line numbers. + +2017-05-01 Arnold D. Robbins + + * 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 + + * 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 + + * 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 + + * awkgram.y (nextc): Adjust so that 3.1.x behavior is restored + whereby --source arguments are concatenated. Thanks to + "Neil R. Ormos" for the report. + +2017-04-21 Arnold D. Robbins + + * 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 + + * 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 + + Rename intdiv it intdiv0 and require enabling at configure time. + + * awkgram.y (tokentab): Bracket intdiv0 in #ifdef SUPPLY_INTDIV. + (snode): Similar. + * builtin.c (do_intdiv): Bracket in #ifdef SUPPLY_INTDIV. + * mpfr.c (do_mpfr_intdiv): Bracket in #ifdef SUPPLY_INTDIV. + * configure.ac: Add --enable-builtin-intdiv0 option. If enabled, + also revise doc/gawktexi.in. + +2017-04-16 Arnold D. Robbins + + * 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-13 Arnold D. Robbins + + * awk.h (make_number_node): Simplify. + * mpfr.c (mpg_node): Change parameter name to `flags'. + +2017-04-12 Arnold D. Robbins + + * 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. + + * gawkapi.c (awk_value_to_node): Initialize ext_ret_val to NULL + to avoid compiler warnings. + +2017-04-12 Manuel Collado + + 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 + + * 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 + + * symbol.c (free_bc_mempool): Change `first' from int to bool. + +2017-04-09 Andrew J. Schorr + + * 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 + + * 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 + + * 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 + + * 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 always 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 + + * 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 + + 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 + + * io.c (flush_io): Use r_fatal and r_warning for messagefunc + in the loop. + +2017-03-24 Arnold D. Robbins + + * 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 + + * config.sub: Updated again. + +2017-03-22 Andrew J. Schorr + + * NEWS: Document new PROCINFO["FS"] value of "API". + +2017-03-22 Andrew J. Schorr + + * NEWS: Document new FIELDWIDTHS skip capability and API input parser + field parsing enhancement. + +2017-03-22 Andrew J. Schorr + + * gawkapi.h (awk_input_buf_t): Update get_record comment regarding the + new field_width argument. + +2017-03-21 Andrew J. Schorr + + * 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 + + Improve handling of EPIPE. Problems reported by + Alexandre Ferrieux + and David Kerns . + + * 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 + + * configure.ac: Some cleanups. + +2017-03-09 Andrew J. Schorr + + * 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 + + * field.c: Minor style edits. + +2017-03-06 Andrew J. Schorr + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * builtin.c (do_typeof): Handle arguments that have + the NULL_FIELD flag set. + +2017-02-03 Andrew J. Schorr + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * interpret.h [UNFIELD]: Fix condition for assignment from + value with valref == 1. Fixes problems introduced at gawk 4.1.2. + +2017-01-27 Arnold D. Robbins + + * interpret.h: Update copyright year. + * debug.c (do_run): Rework error message to ease translation. + Thanks to Rafael Fontenelle and to + Eli Zaretskii . + +2017-01-26 Andrew J. Schorr + + * 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 + + * 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 + + * str_array.c (env_remove): Terminate string before calling unsetenv. + +2017-01-26 Andrew J. Schorr + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + 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 + + * 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 + + * interpret.h (r_interpret): Fix bug in Op_assign_concat reported + on Cygwin mailing list. The string concatenation optimization was + not updating the node correctly by setting STRING and STRCUR flags + and setting stfmt. + +2017-01-06 Andrew J. Schorr + + Enhance API to support extended-precision arithmetic. + * awk.h (enum block_id): Add new values BLOCK_MPFR and BLOCK_MPZ. + (make_number_node): New inline function to reduce code duplication + for creating numeric nodes. + * gawkapi.h (gawk_api_major_version): Bump to 3. + (awk_number_t): New typedef to represent numbers with varying internal + representations. + (awk_value_t): For numbers, replace double with awk_number_t. + (num_value): Redefine. + (num_type, num_ptr): New defines for awk_number_t union members. + (gawk_api_t): Add constants for version checking: gmp_major_version, + gmp_minor_version, mpfr_major_version, and mpfr_minor_version. + Add functions api_get_mpfr and api_get_mpz to allocate memory for + extended-precision numbers to hand to gawk. + (get_mpfr_ptr, get_mpz_ptr): Helper macros to wrap api_get_mpfr and + api_get_mpz. + (make_number): Modify to populate awk_number_t correctly. + (make_number_mpz, make_number_mpfr): New helper functions to create + extended-precision numeric nodes. + (check_mpfr_version): New macro to check GMP/MPFR version compatibility + in extensions that want to support extended-precision math. + * gawkapi.c (getmpfr, freempfr, getmpz, freempz): New macros to + allocate and free memory blocks for extended-precision math. + (awk_value_to_node): For AWK_NUMBER values, support three different + kinds of internal numbers: double, mpz_t, and mpfr_t. + (assign_number): New helper function to convert a numeric node to + an awk_value_t. + (node_to_awk_value): Use assign_number to pass numbers properly. + (api_get_mpfr): Implement new api_get_mpfr hook. + (api_get_mpfz): Implement new api_get_mpz hook. + (api_impl): Add GMP & MPFR versions, api_get_mpfr, and api_get_mpz. + * node.c (r_make_number): Use new make_number_node inline function + to reduce code duplication. + (nextfree): Add block allocators for mpfr_t and mpz_t. + (more_blocks): Add an assert to protect against cases where the block + size is too small to hold our structure. + * mpfr.c (mpg_node): Use new make_number_node inline function + to reduce code duplication. + +2017-01-04 Arnold Robbins + + * config.guess, config.sub, compile, depcomp: Sync from latest + in GNULIB. + +2016-12-27 Juergen Kahrs + + * CMakeLists.txt: Updated after adding support library. + +2016-12-23 Arnold D. Robbins + + * 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 + + * 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 : + + * 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 + + * 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 + + * 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 + + 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 + + * 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 + + * dfa.c: Sync with GNULIB. + +2016-12-05 Andrew J. Schorr + + 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 + + * 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 + + * 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 + + * 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 + + 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 + + * 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 + + * dfa.c: Sync with fixes in GNULIB. + + Unrelated: + + * gawkapi.h (make_regex): New function. + +2016-11-29 Arnold D. Robbins + + 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 + + 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 + + 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 + + * dfa.c: Sync with GNULIB. + +2016-11-17 Arnold D. Robbins + + 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 computation 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 + + * 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 + + 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 + + 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 (grammar): 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 + + * builtin.c (efwrite) [__MINGW32__]: Call w32_maybe_set_errno if + errno is not set or set to EINVAL. + + * nonposix.h (w32_maybe_set_errno) [__MINGW32__]: Add prototype. + +2016-11-01 Arnold D. Robbins + + * eval.c (flags2str): Add NO_EXT_SET and NUMCONSTSTR. + +2016-10-31 Arnold D. Robbins + + 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 + + * io.c (init_awkpath): Set max path len for leading separator. + +2016-10-25 Arnold D. Robbins + + * io.c (init_awkpath): Restore documented behavior whereby + null elements represent the current directory. Sheesh. + Bug reported by "Jun T." . + + 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 + + * 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 + + * awkgram.y: Typo fix in call to add_sign_to_num. + +2016-10-16 Arnold D. Robbins + + * 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 + + * dfa.c: Sync with GNULIB. + +2016-10-12 Arnold D. Robbins + + * 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 + + * 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 + + * debug.c (restart) [__MINGW32__]: Cast 2nd argument of execvp to + avoid compiler warnings about prototype mismatch. Reported by + Marc de Bourget . + +2016-09-09 Norihiro Tanaka + + * 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 + + * dfa.c: Sync with grep. + +2016-09-08 Paul Eggert + + * dfa.c, dfa.h: Sync with grep. + * re.c (make_regexp): Adjust to DFA API changes. + +2016-09-08 Arnold D. Robbins + + * command.y: Update license text to version 3. Oops. + +2016-09-07 Arnold D. Robbins + + * cmd.h, debug.c: Update license text to version citing + GPLv3+ and with correct FSF address. Thanks to + David Kaspar for pointing out the need. + +2016-09-02 Arnold D. Robbins + + * dfa.c: Sync with grep. + +2016-09-01 Arnold D. Robbins + + 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 + + * 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 + + 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 + + * 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 + + * dfa.c: Sync with grep. + +2016-08-25 Arnold D. Robbins + + * 4.1.4: Release tar ball made. + +2016-08-23 Arnold D. Robbins + + * dfa.h: Sync with grep. API changes. + * dfa.c: Sync with grep. + * re.c (make_regexp): Adjust for API changes, move call to dfasyntax + into stanza that compiles the regex. + (resetup): Call dfa_init. + * node.c (str2wstr): using_utf8 is now called dfa_using_utf8. + + Unrelated: + + * Makefile.am: Quote all uses of $(srcdir) and $(distdir). + (spell): New target. + +2016-08-18 Arnold D. Robbins + + * dfa.c: Sync with grep. + +2016-08-15 Andrew J. Schorr + + * 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 + + * re.c (make_regexp): Only call dfasyntax if actually using + dfa. Gives a 14% speedup on this test: https://raw.githubusercontent.com/chadbrewbaker/awka/master/benchmark/regexp.awk. + From blathering in comp.lang.awk. + +2016-08-12 Arnold D. Robbins + + * dfa.c: Sync with GNU grep. + + Unrelated: + + * int_array.c: Minor text and formatting edits. + +2016-08-09 Andrew J. Schorr + + * awk.h: Add a comment explaining the NUMINT flag in more detail. + * int_array.c (standard_integer_string): New function to test whether + a string matches what would be produced by sprintf("%ld", ). + (is_integer): Fix bug -- if NUMBER was set, then the function was + accepting strnum values with nonstandard string representations. We + now call standard_integer_string to check that the string looks OK. + Also added ifdef'ed code to simplify the function by relying upon + force_number to parse the string, but this is disabled due to possible + negative performance impact. + +2016-08-03 Arnold D. Robbins + + 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 + + * README, NEWS: Mark DJGPP port as unsupported. + +2016-08-01 Andrew J. Schorr + + * mpfr.c (mpg_tofloat): Always set precision to avoid hysteresis effects + from previous calculations using the same temporary mpfr variables. + +2016-08-01 Andrew J. Schorr + + * mpfr.c (default_prec): Add new static variable to show current PREC + setting in effect. + (init_mpfr, set_PREC): Save mpfr_set_default_prec argument in + default_prec. + (do_mpfr_func): If the argument's precision exceeds the default + precision, boost the result's precision to match it. This fixes a + bug where we used to copy the argument's precision, regardless of + whether it was higher or lower than the PREC setting. + +2016-07-24 Norihiro Tanaka + + * re.c (research): Now that the dfa matcher correctly runs even + in multibyte locales, try it if even if need_start is true. + However, if start > 0, avoid dfa matcher, since it can't handle + the case where the search starts in the middle of a string. + + Unrelated: + + * eval.c (load_casetable): Reset casetable[i] to `i' if i + 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 + + 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 + + * builtin.c (do_print): Improve logic for formatting + numeric values. + +2016-07-19 Andrew J. Schorr + + * eval.c (set_LINT): Simplify the code considerably. + +2016-07-19 Arnold D. Robbins + + * awkgram.y (shadow_funcs): Change test at end to be + `lintfunc == r_fatal' instead of `lintfunc != warning'. + Thank to Andrew Schorr for the suggestion. + +2016-07-18 Arnold D. Robbins + + * main.c (locale_dir): New variable, init to LOCALEDIR (set by + configure). + (set_locale_stuff): Move calls to bindtextdomain and + textdomain to here; they must be done after calling setlocale. + Use locale_dir instead of LOCALEDIR. + (main): Move call to set_locale_stuff() to before parsing arguments. + Check for GAWK_LOCALE_DIR env var and use it if there. If doing + locale debugging, call set_locale_stuff again if arg parsing changed + the locale. + + Unrelated: + + * dfa.c: Sync with GNU grep. + + Unrelated: + + * config.sub: Updated from GNULIB. + +2016-07-17 Arnold D. Robbins + + * eval.c (set_LINT): Reset lintfunc to `warning' for LINT="invalid". + Thanks to Andy Schorr for the report. + +2016-07-08 Andrew J. Schorr + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + 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 + + * awk.h: Renumber flags to remove gap created when FIELD was removed. + +2016-07-05 Andrew J. Schorr + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * array.c (value_info): Print something reasonable when stfmt + is -1. + * mpfr.c (mpg_format_val): Don't cast index to char. + * node.c (r_format_val): Ditto. + Thanks to Andrew Schorr for pointing these out. + + Unrelated: + + * gawkapi.c (api_warning): Fix the comment header. + (api_lintwarn): Factor out the call to va_end to after the if. + + Unrelated: + + * symbol.c (get_symbols): Add FUNCTAB and SYMTAB to the list + for the -d option. + * awkgram.y (dump_vars): Allow "-" to mean print to stdout. + Thanks to Hermann Peifer for the reports. + +2016-06-30 Arnold D. Robbins + + * node.c (r_force_number): Coding style change. + +2016-06-30 Andrew J. Schorr + + * 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 + + * 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 + + * gawkapi.h (awk_string): Add comment about the potential lack of + NUL-termination. + +2016-06-27 Andrew J. Schorr + + * awk.h: Add a comment regarding the potential lack of NUL-termination + for Node_val strings. + +2016-06-27 Andrew J. Schorr + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + Repair change of 2015-08-25 to handling of MAYBE_NUM. + * mpfr.c (mpg_force_number): Just clear MAYBE_NUM. + * node.c (r_force_number): Clear STRING separately after + setting NUMBER. + + 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 + + * 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 + + * node.c (r_force_number): Fix typo in comment. + +2016-06-16 Arnold D. Robbins + + * awk.h: Add comment headers for several functions. + * builtin.c (nondec2awknum): Actually set a '\0' before + calling to strtod() so that the save and restore do something. + +2016-06-15 Arnold D. Robbins + + * config.sub: Update from GNULIB. + +2016-06-14 Andrew J. Schorr + + * 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 + + * 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 + + * 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 + + * awkgram.y: Eliminate STRCUR tests. Must use STRING to test whether + a scalar is a string. + +2016-06-12 Andrew J. Schorr + + * 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 + + * 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 + + * config.guess, config.sub: Get latest from Gnulib master. + * main.c (UPDATE_YEAR): Bump to 2016. + +2016-06-09 Arnold D. Robbins + + * dfa.c: Sync with GNU grep. + + Unrelated: + + * configure.ac: Move AM_CONDITIONAL[ENABLE_EXTENSIONS] outside + the enclosing if. Thanks to Assaf Gordon + for the report. + +2016-06-08 Arnold D. Robbins + + * symbol.c (lookup): If got Node_val, it's a non-variable + in SYMTAB, return NULL. Can affect watchpoints in the debugger, + maybe other places. Thanks to Hermann Peifer for the + test case and report. + +2016-06-05 Arnold D. Robbins + + * dfa.c: Sync with GNU grep. + +2016-06-01 Arnold D. Robbins + + * nonposix.h (getpgrp): Wrap declaration in ifdef so it doesn't + mess things up on POSIX systems (like Solaris). Thanks to + Nelson Beebe for the report. + * node.c (is_hex): New function to check for 0x preceded by + optional sign. + (r_force_number): Use it. Thanks to Mike Brennan for the report. + +2016-05-30 Andrew J. Schorr + + * 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 + + * main.c (arg_assign): Fully bracket ifdefs around call + to force_number. Thanks to Andrew Schorr for pointing out + that force_number was called only if LC_NUMERIC was defined. + + Lots of files: Update copyright date. + + * field.c (set_FS): Handle FS = "\0" if RS = "". Thanks to + Janis Papanagnou for the report. + + * getopt.c, getopt.h, getopt1.c, getopt_int.h: Sync with GLIBC. + +2016-05-26 Andrew J. Schorr + + * awk.h (get_actual_argument): Remove unused "optional" argument. + (get_scalar_argument, get_array_argument): Change macro definition to + remove 3rd "optional" argument. + * ext.c (get_actual_argument): Remove unused "optional" argument. + * gawkapi.c (api_get_argument, api_set_argument): Remove unused final + argument to get_array_argument and get_scalar_argument. + +2016-05-26 Arnold D. Robbins + + * awk.h [fatal]: Make parentheses and use of indirection + consistent with warning and lintwarn. Thanks to Andrew Schorr + for pointing this out. + * str_array.c (str_lookup): Move test for MAYBE_NUM to where + we duplicate the subscript. Removing it across the board is + wrong if there are multiple references to the value. Thanks + to Andrew Schorr for discussion and test case. + +2016-05-26 Andrew J. Schorr + + * awk.h (get_actual_argument): Add an initial argument containing + the (NODE *) previously returned by get_argument. This allows us to + eliminate a call to get_argument from inside get_actual_argument. + (get_scalar_argument, get_array_argument): Change macro definition to + add an initial node argument to pass through to get_actual_argument. + * ext.c (get_actual_argument): Add initial (NODE *) argument to contain + the value previously returned by get_argument. This allows us to + avoid repeating the call to get_argument. We can also eliminate the + check for a NULL value, since the caller did that already. + * gawkapi.c (api_get_argument): Pass (NODE *) returned by get_argument + to get_array_argument and get_scalar_argument. + (api_set_argument): Pass (NODE *) returned by get_argument to + get_array_argument. + +2016-05-25 Manuel Collado . + + * 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 + + * str_array.c (str_lookup): Remove MAYBE_NUM from subscript flags. + Bug reported by Andres Legarra . + + Unrelated: Fix issues with SIGPIPE. Reported by + Ian Jackson . + + * builtin.c (do_system): Reset/restore SIGPIPE to/from default around + call to system. + * io.c (redirect, gawk_popen [PIPES_SIMULATED]): Same. + +2016-05-12 Eli Zaretskii + + * nonposix.h: Add prototypes for POSIX functions emulated in pc/* + files. + +2016-05-09 Andrew J. Schorr + + * 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 + + * builtin.c (format_tree): Do not waste a byte at the end of a string. + +2016-05-03 Andrew J. Schorr + + * builtin.c (format_tree): After the string has been rendered, use + realloc to shrink the buffer to the needed size. Otherwise, the minimum + buffer size of 512 bytes can result in lots of wasted memory if many + sprintf results are stored in an array. + +2016-05-02 Andrew J. Schorr + + * gawkapi.h (gawk_api_major_version, gawk_api_minor_version): Add + CPP #define values to support conditional compilation. + +2016-05-02 Arnold D. Robbins + + * dfa.h, dfa.c: Sync with grep. + * re.c (research): Adjust type of try_backref. + +2016-05-02 Arnold D. Robbins + + * awk.h (success_node): Declare. + * array.c (success_node): Define. + * cint_array.c, int_array.c, str_array.c: Use `& success_node' + instead of `(NODE **) ! NULL' to indicate success throughout. + Thanks to Pat Rankin for the cleanup suggestion. + +2016-04-27 Arnold D. Robbins + + * io.c (set_RS): Use rs1scan if do_traditional, even if length + of RS is > 1. Bug reported by Glauco Ciullini + . + +2016-04-24 Arnold D. Robbins + + * dfa.c: Sync with GNU grep. + +2016-04-11 Arnold D. Robbins + + * regex_internal.c: Replace _GL_ATTRIBUTE_PURE with + __attribute__. + +2016-04-11 Arnold D. Robbins + + * regexec.c: Stamp out last remaining use of __attribute. + * regcomp.c: Undo change of 2016-01-24 when parsing single-byte + ranges. Go back to treating them as bytes and not as characters. + The change broke things on Windows in non-UTF-8 character sets. + * mbsupport.h (mbstate_t): Define to int. + Update copyright. + +2016-04-10 John E. Malmberg + + * regex_internal.c: Use _GL_ATTRIBUTE_PURE macro + +2016-04-07 Arnold D. Robbins + + * awk.h (two_way_close_type): Move here from io.c. + (close_rp): Add declaration. + * builtin.c (do_printf): Call close_rp before fatal message when + attempting to write the closed write end of a two way pipe. + (do_print): Ditto. + (do_print_rec): Ditto. + * io.c (do_getline_redir): Same, for reading closed read end. + (close_rp): Make not static. + +2016-04-07 Eli Zaretskii + + * nonposix.h (WEXITSTATUS, WIFEXITED, WIFSIGNALED, WTERMSIG) + (WIFSTOPPED, WSTOPSIG) [__MINGW32__]: New macros to replace the + missing header sys/wait.h. + (w32_status_to_termsig): Add prototype. + + * builtin.c (do_system) [__MINGW32__]: Compute the exit status of + 'system' differently under --traditional, as the low 8 bits are + the most interesting. + +2016-04-06 Arnold D. Robbins + + * 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 + + * builtin.c (do_fflush): Add warning for flush to two-way + pipe where write end was closed. + * io.c (flush_io): Add some braces for the for loop. + +2016-04-02 Arnold D. Robbins + + * builtin.c (do_printf): If the redirection is two way but the + fp is NULL, it means we're writing to the closed write-end of + a two-way pipe. Issue a fatal error message. + (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. + * NEWS: Updated. + +2016-03-27 Stephen Davies + + * awkgram.y (get_comment): Strip CRs from comment. Strip + off trailing newlines. + +2016-03-21 Arnold D. Robbins + + * profile.c (pprint): Improve handling of comment after + and if statement without an else. + +2016-03-19 Arnold D. Robbins + + 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 existence. 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 + + * 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 + + * 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 + + * debug.c (print_instruction): Normalize printing of comment dump. + +2016-03-10 Arnold D. Robbins + + * builtin.c (do_system): Further improvements. Catch core dump + flag. + +2016-03-11 Arnold D. Robbins + + * builtin.c (do_system): Improve return values of system(). + +2016-03-08 Arnold D. Robbins + + * profile.c (print_instruction): Fix duplicate case not caught + by TinyCC. Grrr. + +2016-03-07 Arnold D. Robbins + + * profile.c (print_instruction): Further improvements in + instruction dump, especially for when pretty-printing. + * builtin.c (do_system): Augment the logic for the return + value so that death-by-signal info is available too. + +2016-03-03 Arnold D. Robbins + + * profile.c (pp_list): Unconditionally compute delimlen. Avoids + compiler warning. + +2016-03-02 Arnold D. Robbins + + * debug.c (print_instruction): Improvements in instruction dump + for if and else. + +2016-03-01 Arnold D. Robbins + + * 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 + + * profile.c (pp_list): Handle the case of nargs equal to zero. + Thanks to Hermann Peifer for the report. + +2016-02-28 Arnold D. Robbins + + * profile.c (pprint): Fix copy-paste error in else handling. + Thanks to Michal Jaegermann for the report. + +2016-02-23 Arnold D. Robbins + + * config.guess, config.rpath, config.sub: Update to latest + from GNULIB. + +2016-02-23 Arnold D. Robbins + + * NEWS: Update full list of infrastructure tools. + +2016-02-22 gettextize + + * configure.ac (AM_GNU_GETTEXT_VERSION): Bump to 0.19.7. + +2016-02-21 Nelson H.F. Beebe + + * 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 + + * regexec.c (prune_impossible_nodes): Remove attribute that + keeps it from compiling with 32 bit GCC. Who the heck knows + why or how. Sigh. Double sigh. + +2016-02-20 Arnold D. Robbins + + * regcomp.c, regex.c, regex.h, regex_internal.c, regex_internal.h, + regexec.c: Sync with GLIBC, mostly prototype changes. + +2016-02-18 Arnold D. Robbins + + Fix profile / pretty-printing to chain else-ifs. + + * profile.c (pprint): Change third argument into a set of flags + for in the for header or in an else if. Adjust case Op_K_else to + make the right checks and format the code properly. In Op_K_if + clear the flag so that any following else gets indented properly. + Adjust all calls. + +2016-02-14 Arnold D. Robbins + + * 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 + + 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 + + * Makefile.am (SUBDIRS): Include extras. Otherwise dist does + doesn't work. + +2016-01-27 Arnold D. Robbins + + * 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 + + * io.c (redirect): Need to call close_one more than once after + running out of file handles. + +2016-01-25 Arnold D. Robbins + + * NEWS: Document VMS support updated. + +2016-01-24 Arnold D. Robbins + + Regex: treat [x] as x if x is a unibyte encoding error. + This change removes an ifdef GAWK. + + * regcomp.c (parse_byte) [ !_LIBC && RE_ENABLE_I18N]: New function. + (build_range_exp) [ !_LIBC && RE_ENABLE_I18N]: Use it. + From Paul Eggert . + +2016-01-22 Arnold D. Robbins + + * regexec.c (prune_impossible_nodes): Remove all attributes, on + both declaration and definition. Fixes a Linux Mint 17 compilation + braino reported by Antonio Colombo. + * regex_internal.h (test_malloc): Add cast to silence a warning + on the same system. + (test_realloc): Ditto. + +2016-01-20 Arnold D. Robbins + + * regex_internal.h [attribute_hidden]: Remove definition. + * regcomp.c [attribute_hidden]: Remove uses. Not needed since + the variables are static. Thanks to Paul Eggert for pointing + this out. + +2016-01-18 Paul Eggert + + Diagnose ERE '()|\1' + Problem reported by Hanno Boeck in: http://bugs.gnu.org/21513 + + * lib/regcomp.c (parse_reg_exp): While parsing alternatives, keep + track of the set of previously-completed subexpressions available + before the first alternative, and restore this set just before + parsing each subsequent alternative. This lets us diagnose the + invalid back-reference in the ERE '()|\1'. + + Unrelated: General minor cleanups (spelling, code) from Gnulib: + + * regex.h, regex_internal.c, regex_internal.h, regexec.c: Minor + cleanups. + +2016-01-14 Arnold D. Robbins + + * eval.c (r_get_lhs): If original array was Node_var_new, + assign value that is dupnode of Nnull_string and not + Nnull_string directly. Fixes core dump reported by + ruyk . + + Unrelated: + + * ChangeLog: Cleanup spurious extra whitespace. + +2016-01-03 Arnold D. Robbins + + * 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 + + * dfa.c (add_utf8_anychar): Minor change in declaration of + utf8_classes to keep Tiny CC happy. Also syncs with grep. + * dfa.h: Sync with grep (update copyright year). + +2015-12-27 Arnold D. Robbins + + * awkgram.y (mk_condition): Revise to correctly handle + empty else part for pretty printing. Bug report by + ziyunfei <446240525@qq.com>. + +2015-12-20 Arnold D. Robbins + + * io.c (nonfatal): New static constant string. + * is_non_fatal, is_non_fatal_redirect: Use it. + +2015-12-16 Arnold D. Robbins + + * io.c (two_way_open): Remove unneeded close of slave in the + parent. + +2015-12-16 Arnold D. Robbins + + * profile.c (pp_number): Move count into ifdef for MPFR. Avoids + an unused variable warning if not compiling for MPFR. + + Unrelated: + + * io.c (two_way_open): If using a pty instead of pipes, open the + slave in the child. Fixes AIX and doesn't seem to break GNU/Linux. + +2015-11-26 Arnold D. Robbins + + * command.y (cmdtab): Add "exit" as synonym for "quit". + Suggested by Joep van Delft . + * NEWS: Document this. + +2015-11-24 Arnold D. Robbins + + * debug.c (debug_pre_execute): Fix to check watchpoints before + checking breakpoints. Gives more natural behavior for the user. + * NEWS: Document this. + Issue reported by Joep van Delft . + +2015-10-28 Arnold D. Robbins + + * awkgram.y (nextc): Don't allow '\0' even if check_for_bad + is false. Fixes a problem reported by Hanno Boeck . + + Unrelated: + + * dfa.c: Sync with GNU grep. + +2015-10-25 Arnold D. Robbins + + * awkgram.y (yylex): Fix invalid write problems. + Reported by Hanno Boeck . + Only appeared in master. Harumph. + +2015-10-16 Arnold D. Robbins + + * Makefile.am (SUBDIRS): Fix ordering so that + make check directly after configure works properly. + Thanks to Michal Jaegermann + for the report. + + Unrelated: + + * dfa.c: Sync with GNU grep. + +2015-10-11 Arnold D. Robbins + + * awkgram.y (yylex): Fix invalid read problems. + Reported by Hanno Boeck . + +2015-10-04 Arnold D. Robbins + + * configure.ac: Bump version to 4.1.3a. + +2015-09-26 Arnold D. Robbins + + * awkgram.y (yylex): Diagnose multidimensional arrays for + traditional/posix (fatal) or lint. Thanks to Ed Morton + for the bug report. + +2015-09-25 Arnold D. Robbins + + * config.guess, config.sub, config.rpath: Updated. + +2015-09-18 Arnold D. Robbins + + * field.c (fpat_parse_field): Always use rp->non_empty instead + of only if in_middle. The latter can be true even if we've + already parsed part of the record. Thanks to Ed Morton + for the bug report. + +2015-09-11 Daniel Richard G. + + * regcomp.c: Include strings.h, wrapped in ifdef. Revise + defines for BTOWC. + * regex_internal.h: Remove ZOS_USS bracketing ifdefs. + +2015-09-04 Arnold D. Robbins + + * profile.c (pp_num): Use format_val to print integral values + as integers. Thanks to Hermann Peifer for the report. + +2015-08-28 Daniel Richard G. + + * Makefile.am, configure.ac: Use an Automake conditional to + enable/disable the "extensions" subdirectory instead of + producing a stub Makefile therein from the configure script. + * awk.h, custom.h, regex_internal.h: Removed z/OS-specific code + that is no longer needed due to improvements in Gawk's general + Autotools support. + * awk.h: Allow to be #included together with + as this is required on some systems (z/OS). + * io.c, configure.ac: is needed for select() + and related bits on z/OS. + * awk.h: Handle the redefinition of EXIT_FAILURE on z/OS in a + more elegant/general way. + * awkgram.y, command.y, configure.ac, eval.c, + helpers/testdfa.c: Define and use the USE_EBCDIC cpp symbol + instead of checking the value of 'a' whenever we want to know + if we're on an EBCDIC system. Also, don't assume that z/OS + necessarily means EBCDIC, as the compiler does have an ASCII + mode (-qascii). + * awkgram.y, command.y, configure.ac: On EBCDIC systems, + convert singleton EBCDIC characters in the input stream to + ASCII on the fly so that the generated awkgram.c/command.c in + the distributed sources can be used, i.e. we don't have to + require the user to build Bison and re-generate those files + themselves. This implementation uses a z/OS-specific function + (__etoa_l()) to do the conversion, but support for other + systems can be added in the future as necessary. + * io.c: No need to protect this block of "#if + defined(HAVE_TERMIOS_H)" code from z/OS; it works just fine + there. + * configure.ac: Check for the "struct passwd.pw_passwd" and + "struct group.gr_passwd" fields and conditionalize their use, + as they don't exist on z/OS. Needed for doc/gawktexi.in. + +2015-08-25 Arnold D. Robbins + + * node.c (str2wstr): Upon finding an invalid character, if + using UTF-8, use the replacement character instead of skipping + it. Helps match() and other functions work better in the face + of unexpected data. Make the lint warning an unconditional + warning. + + Unrelated: + + * awk.h: Add explanatory comment on the flags related to + types and values. + * mpfr.c (mpg_force_number): If setting NUMBER, clear STRING also + when clearing MAYBE_NUM. + (set_PREC): Check STRCUR instead of STRING. + * node.c (r_force_number): If setting NUMBER, clear STRING also + when clearing MAYBE_NUM. + +2015-08-15 Arnold D. Robbins + + * dfa.c (dfamust): Restore c90 compat by moving some + variable declarations to the top of the routine. + +2015-08-12 Arnold D. Robbins + + * dfa.c: Sync with GNU grep. Yet again, again. + +2015-08-02 Arnold D. Robbins + + * dfa.c: Sync with GNU grep. Yet again. + +2015-07-21 Arnold D. Robbins + + * dfa.c: Sync with GNU grep. + +2015-07-18 Arnold D. Robbins + + * dfa.c: Sync with GNU grep. + +2015-07-08 Arnold D. Robbins + + * dfa.h, dfa.c: Sync with GNU grep. + +2015-06-29 Arnold D. Robbins + + * 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 + + 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 + + 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 + + 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 + + * 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_triggered): 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 + + 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 + + * builtin.c (do_isarray): Minor edit to lint warning. + * TODO: Updated. + +2015-06-14 Arnold D. Robbins + + * regcomp.c, regex_internal.h, regexec.c: Sync with GLIBC. + + Unrelated: + + * regex_internal.c, regexec.c: __attribute --> __attribute__. + + Related: + + * regex_internal.h: Clean up defines for non-GCC for attribute; + essentially sync it with GLIBC. + +2015-06-12 Arnold D. Robbins + + * awkgram.y: Finish converting "hard" regex to "typed" regex. + +2015-05-31 Arnold D. Robbins + + * field.c (posix_def_parse_field): Removed. It's no longer + needed after updates to the POSIX standard. Thanks to + Michael Klement for pointing this out. + +2015-05-26 Paul Eggert + + * floatcomp.c (count_trailing_zeros): New function. + This compiles to a single TZCNT instruction on the x86-64. + (adjust_uint): Use it to keep more high-order bits when + some of the lowest-order bits are zero. This implements + the documented behavior: "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." + +2015-05-26 Arnold D. Robbins + + * regcomp.c: Fix offsets so error messages come out correct + once again. + +2015-05-19 Arnold D. Robbins + + * 4.1.3: Release tar ball made. + +2015-05-15 Andrew J. Schorr + + * 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 + + * 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 + + * 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 + + * awkgram.y (yylex): Yet Another Fix for parsing bracket + expressions. Thanks yet again to Andrew Schorr. Maybe it's + even finally nailed down now. + + Unrelated: + + * 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 + + * awkgram.y: Make sure values are not null in param list. + Avoids core dump for `function f(func, a) {}'. Thanks to + Tibor Palinkas . + +2015-04-30 Arnold D. Robbins + + * Makefile.am: Take --program-prefix into account when + installing/uninstalling the symlinks, especially 'awk'. + Thanks to Steffen Nurpmeso for + the report. + + Unrelated: + + * awkgram.y (yylex): Yet Another Fix for parsing bracket + expressions. Thanks again to Andrew Schorr. + +2015-04-29 Arnold D. Robbins + + * 4.1.2: Release tar ball made. + +2015-04-28 Arnold D. Robbins + + * builtin.c (isarray): Add lint warning that isarray() + is deprecated. + +2015-04-28 Arnold D. Robbins + + * awkgram.y (yylex): Rework the bracket handling from zero. + Thanks to Michal Jaegermann for yet another test case. + + Unrelated: + + * eval.c (setup_frame): Restore call-by-value for $0. This was + necessitated by the changes on 2014-11-11 for conserving + memory use. Thanks to Andrew Schorr for the report and isolating + the cause of the problem. + +2015-04-27 Arnold D. Robbins + + * awkgram.y (yylex): Make change of Jan 7 for parsing regexps + work better. Thanks to Nelson Beebe. + +2015-04-26 Arnold D. Robbins + + * dfa.c: Sync with grep. + +2015-04-16 Arnold D. Robbins + + * builtin.c (do_strftime): For bad time_t values, return "". + +2015-04-16 Andrew J. Schorr + + * node.c (r_force_number): If strtod sets errno, then force the + numeric value in node->numbr to zero. For subnormal values, strtod + sets errno but does not return zero, and we don't want to retain + those subnormal values. + +2015-04-16 Arnold D. Robbins + + 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 + + * 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 + + * builtin.c (do_strftime): Use a double for the timestamp and + check that the value is within range for a time_t. + + Unrelated: + + * regex_internal.h (test_malloc, test_realloc): Use %lu in printf + format for error messages. Thanks to Michal Jaegermann for + pointing this out. + + Unrelated: + + * NEWS: Updated. + +2015-04-15 Arnold D. Robbins + + 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 + + * builtin.c (do_strftime): Restore checking for negative result and + add check that time_t is > 0 --- means we're assigning a negative value + to an unsigned time_t. Thanks again to Glaudiston Gomes da Silva + . + + If localtime() or gmtime() return NULL, return a null string. + Thanks to Andrew Schorr. + + 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 + Arnold D. Robbins + + * 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 + + * regcomp.c (analyze): Prevent malloc(0). + * regex_internal.h (test_malloc, test_realloc): New functions + that check for zero count. + (re_malloc, re_realloc): Adjust to call the new functions for gawk. + * regexec.c (build_trtable, match_ctx_clean): Replace malloc/free + with re_malloc/re_free. + + Unrelated: + + * builtin.c (do_strftime): Disable checking timestamp value for less + than zero. Allows times before the epoch to work with strftime. + Thanks to Glaudiston Gomes da Silva + for raising the issue. + +2015-04-12 Arnold D. Robbins + + * Makefile.am (efence): Make this link again. + Thanks to Michal Jaegermann for pointing out the problem. + +2015-04-09 Andrew J. Schorr + + * 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 + + * custom.h: VMS shares some code paths with ZOS_USS in + building gawkfts extension. + +2015-04-08 Arnold D. Robbins + + Factor out opening of /dev/XXX files from /inet. + Enable interpretation of special filenames for profiling output. + + * awk.h (devopen_simple): Add declaration. + * io.c (devopen_simple): New routine. + (devopen): Call devopen_simple as appropriate. + * profile.c (set_prof_file): Call devopen_simple as appropriate, + some additional logic to handle fd to fp conversion. + + Unrelated: + + * main.c (usage): Add a comment for translators. + +2015-04-08 Eli Zaretskii + + * profile.c (set_prof_file): Interpret a file name of "-" to mean + standard output. + +2015-04-06 Arnold D. Robbins + + * awk.h (force_number): Add `!= 0' check to bitwise operation. + * awkgram.y: Same, many places. + (check_special): Simplify code for checking extension flags. + +2015-04-05 Arnold D. Robbins + + * awkgram.y (install_builtins): If do_traditional is true, do not + install gawk extensions flagged with GAWKX. Similarly, if do_posix + is true, do not install functions flagged with NOT_POSIX. + This fixes a problem with spurious lint complaints about shadowing + a global variable that is not valid in traditional or posix mode. + Thanks to Andrew Schorr for finding the problem and supplying + initial code; I did it slightly differently. + +2015-04-03 Arnold D. Robbins + + * 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 + + * NEWS: Rename div to intdiv. + +2015-04-02 Arnold D. Robbins + + 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 + + * awk.h (call_sub): Renamed from call_sub_func. + (call_match, call_split_func): Declare. + * builtin.c (call_sub): Renamed from call_sub_func. + (call_match, call_split_func): New functions. + * interpret.h (r_interpret): Call new functions as appropriate. + * node.c (r_unref): Revert change to handle Node_regex, not needed. + +2015-03-31 Arnold D. Robbins + + * awk.h (r_get_field): Declare. + * builtin.c (call_sub_func): Rearrange the stack to be what + the buitin function expects. + * eval.c (r_get_field): Make extern. + +2015-03-27 Arnold D. Robbins + + * 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 + + * awkgram.y (make_regnode): Make extern. + * awk.h (make_regnode): Declare. + * builtin.c (call_sub_func): Start on reworking the stack to + be what do_sub() expects. Still needs work. + * interpret.h (r_interpret): Add a cast in comparison with do_sub(). + * node.c (r_unref): Handle Node_regex nodes. + +2015-03-24 Andrew J. Schorr + + * 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 + + * awk.h, gawkapi.c, io.c: Minor code reformatting. + +2015-03-20 Arnold D. Robbins + + Start on fixing indirect calls of builtins. + + * awk.h (call_sub_func): Add declaration. + * awkgram.y (lookup_builtin): Handle length, sub functions. + (install_builtin): Handle length function. + * builtin.c (call_sub_func): New function. + * interpret.h (r_interpret): If calling do_sub, do it through + call_sub_func(). + +2015-03-19 Arnold D. Robbins + + * 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 + + * 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 + + * config.guess, config.sub: Updated, from libtool 2.4.6. + +2015-03-17 Arnold D. Robbins + + * profile.c (pp_number): Allocate enough room to print the number + in all cases. Was a problem mixing -M with profiling with a really + big number. Thanks to Hermann Peifer for the bug report. + +2015-03-08 Arnold D. Robbins + + * 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 + + * 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 + + * 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 + + * symbol.c (check_param_names): Fix argument order in memset() call. + * configure.ac: Use AC_SEARCH_LIBS instead of AC_CHECK_LIB. This fixes + a long-standing problem where `-lm' was used twice in the final + compilation line. + +2015-02-27 Arnold D. Robbins + + 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 + + * POSIX.STD: Update copyright year. + * awkgram.y (yylex): Allow \r after \\ line continuation everywhere. + Thanks to Scott Rush for the report. + +2015-02-13 Arnold D. Robbins + + * awkgram.y (yylex): Be more careful about passing true to + nextc() when collecting a regexp. Some systems' iscntrl() + are not as forgiving as GLIBC's. E.g., Solaris. + Thanks to Dagobert Michelsen for + the bug report and access to systems to check the fix. + +2015-02-12 Arnold D. Robbins + + * POSIX.STD: Update with info about function parameters. + * configure.ac: Remove test for / use of dbug library. + +2015-02-11 Arnold D. Robbins + + * gawkapi.h: Fix spelling error in comment. + +2015-02-10 Arnold D. Robbins + + * profile.c (pprint): Restore printing of count for rules. + Bug report by Hermann Peifer. + +2015-02-08 Arnold D. Robbins + + * io.c: Make it "NONFATAL" everywhere. + +2015-02-08 Andrew J. Schorr + + * 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 + + * 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 + + * regcomp.c, regex.c, regex.h, regex_internal.c, regex_internal.h, + regexec.c: Sync with GLIBC. Mostly copyright date updates. + +2015-02-05 Andrew J. Schorr + + * eval.c (set_IGNORECASE): If IGNORECASE has a numeric value, try + using that before treating it as a string. This fixes a problem + where setting -v IGNORECASE=0 on the command line was not working + properly. + +2015-02-01 Arnold D. Robbins + + Move POSIX requirement for disallowing parameter names with the + same name as a function into --posix. + + * NEWS: Document it. + * awkgram.y (parse_program): Check do_posix before calling + check_param_names(). + * symbol.c (check_param_names): Set up a fake node and call + in_array() for function parameter names instead of linear + searching the function list a second time. Thanks to Andrew + Schorr for the motivation. + +2015-01-30 Arnold D. Robbins + + Don't allow function parameter names to be the same as function + names - required by POSIX. Bug first reported in comp.lang.awk. + + In addition, don't allow use of a parameter as a function name + in a call (but it's ok in indirect calls). + + * NEWS: Updated. + * awk.h (check_param_names): Add declaration. + * awkgram.y (at_seen): New variable. Communicates between + yylex() and the parser. + (FUNC_CALL production): Check at_seen and check that the identifier + is a function name. + (parse_program): Call check_param_names() and set errcount. + (yylex): Set at_seen after seeing an at-sign. + * symbol.c (check_param_names): New function. + +2015-01-24 Arnold D. Robbins + + Infrastructure updates. + + Bison 3.0.4. Automake 1.15. Gettext 0.19.4. + +2015-01-20 Arnold D. Robbins + + * gawkapi.c (api_set_array_element): Remove useless call to + make_aname. + * symbol.c (load_symbols): Ditto. + Thanks to Andrew Schorr for pointing out the problem. + +2015-01-19 Arnold D. Robbins + + * awkgram.c: Update to bison 3.0.3. + * command.c: Ditto. + * NEWS: Note same. + +2015-01-16 Stephen Davies + + * 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 + + * dfa.h, dfa.c: Sync with grep. Mainly copyright updates. + * getopt.c, getopt.h, getopt1.c getopt_int.h: Sync with GLIBC. + Mainly copyright updates, one minor code fix. + +2015-01-14 Arnold D. Robbins + + Remove deferred variables. + + * awk.h (register_deferred_variable): Remove declaration. + * awkgram.y (is_deferred_variable, process_deferred, + symtab_used, extensions_used, deferred_variables, + process_deferred): Remove declarations, bodies, and uses. + * builtin.c (do_length): Update comment. + * main.c (init_vars): Just call load_procinfo() and `load_environ()'. + +2015-01-08 Andrew J. Schorr + + 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 + + * 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 + + * configure.ac: Update debug flags if developing. + * awkgram.y (yylex): Regex parsing bug fix for bracket expressions. + Thanks to Mike Brennan for the report. + * builtin.c (format_tree): Catch non-use of count$ for dynamic + field width or precision. + + Unrelated: + + Load deferred variables if extensions are used; they might + want to access PROCINFO and/or ENVIRON. Thanks to Andrew Schorr + for pointing out the issue. + + * awkgram.y (extensions_used): New variable. Set it on @load. + (do_add_scrfile): Set it on -l. + (process_deferred): Check it also. + +2015-01-06 Andrew J. Schorr + + * 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 + + * 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 deferred + array, not the other way around. The ENVIRON array has special funcs + to call setenv and unsetenv. + +2015-01-06 Andrew J. Schorr + + * 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 + + * 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 + + * gawkapi.h: Fix another comment typo. + +2015-01-04 Andrew J. Schorr + + * gawkapi.h: Fix typo in comment. + +2015-01-02 Andrew J. Schorr + + * 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 + + * 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 + + * builtin.c (do_sub): Do not waste a byte at the end of a string. + +2014-12-14 Arnold D. Robbins + + * 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 + + * 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 + + 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 + + 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 + + * dfa.c: Sync with GNU grep. + +2014-11-26 Arnold D. Robbins + + * builtin.c (do_sub): Improve wording of gensub warnings. + +2014-11-25 Arnold D. Robbins + + * builtin.c (do_sub): For gensub, add more warnings for invalid + third argument. + +2014-11-23 Arnold D. Robbins + + * awk.h: Move all inline functions to the bottom of the file. + Keeps modern GCC happier. + +2014-11-22 Arnold D. Robbins + + * awk.h (emalloc, realloc): Redefine in terms of ... + (emalloc_real, erealloc_real): New static inline functions. + (fatal): Move definition up. + * gawkmisc.c (xmalloc): If count is zero, make it one for older + mallocs that require size > 0 (such as z/OS). + +2014-11-21 Arnold D. Robbins + + * main.c: Remove a debugging // comment. + * NOTES: Removed. + + Unrelated: + + Revert changes of 2014-11-20 from Paul Eggert. Causes failures + on z/OS. + + Unrelated: Avoid unnecessary copying of $0. + + * interpret.h (UNFIELD): New macro. + (r_interpret): Use it where *lhs is assigned to. + +2014-11-20 Paul Eggert + + Port to systems where malloc (0) and/or realloc(P, 0) returns NULL. + * gawkmisc.c (xmalloc): + * xalloc.h (realloc): + Do not fail if malloc(0) or realloc(P, 0) returns NULL. + Fail only when the allocator returns null when attempting to + allocate a nonzero number of bytes. + +2014-11-19 Arnold D. Robbins + + Infrastructure upgrades: + + * Automake 1.14.1, Gettext 0.19.3, Libtool 2.4.3. + * compile, extension/build-aux/compile: New files. + +2014-11-19 gettextize + + * configure.ac (AM_GNU_GETTEXT_VERSION): Bump to 0.19.3. + +2014-11-16 Arnold D. Robbins + + * interpret.h: Revert change of 2014-11-11 since it breaks + certain uses. + + Unrelated: + + * dfa.c: Sync with GNU grep. + +2014-11-15 Arnold D. Robbins + + * array.c, awk.h, awkgram.y, builtin.c, dfa.c, eval.c, field.c, + interpret.h, io.c, main.c, mpfr.c, node.c, re.c, regex_internal.h, + replace.c: Remove all uses of MBS_SUPPORT. + * regex_internal.h: Disable wide characters on DJGPP. + * mbsupport.h: Rework to be needed only for DJGPP. + +2014-11-11 Arnold D. Robbins + + Don't let memory used increase linearly in the size of + the input. Problem reported by dragan legic + . + + * field.c (set_record): NUL-terminate the buffer. + * interpret.h (r_interpret): Op_field_spec: if it's $0, increment + the valref. Op_store_var: if we got $0, handle it appropriately. + +2014-11-10 Arnold D. Robbins + + Reorder main.c activities so that we can set a locale on the + command line with the new, for now undocumented, -Z option. + + * main.c (parse_args, set_locale_stuff): New functions. + (stopped_early): Made file level static. + (optlist, optab): Add new argument. + (main): Adjust ordering and move inline code into new functions. + +2014-11-09 Andrew J. Schorr + + * gawkapi.c (node_to_awk_value): When the type wanted is AWK_UNDEFINED + 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 + + * 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 + + * 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 + + * re.c (research): Use dfa superset to improve matching speed. + +2014-11-02 Arnold D. Robbins + + * profile.c (div_on_left_mul_on_right): New function. + (parenthesize): Call it. + +2014-10-30 Arnold D. Robbins + + * configure: Regenerated after fix to m4/readline.m4. + + Unrelated; fixes to profiling. Thanks to Hermann Peifer and + Manuel Collado for pointing out problems: + + * profile.c (pprint): For Op_unary_minus, parenthesize -(-x) + correctly. + (prec_level): Get the levels right (checked the grammar). + (is_unary_minus): New function. + (pp_concat): Add checks for unary minus; needs to be parenthesized. + +2014-10-30 Andrew J. Schorr + + * NEWS: Mention installation of /etc/profile.d/gawk.{csh,sh}. + +2014-10-29 Andrew J. Schorr + + * configure.ac (AC_CONFIG_FILES): Add extras/Makefile. + * Makefile.am (SUBDIRS): Add extras. + * extras: Add new subdirectory. + +2014-10-29 Arnold D. Robbins + + * dfa.c: Sync with GNU grep. Again, again. + +2014-10-28 Arnold D. Robbins + + * dfa.c: Sync with GNU grep. Again. + +2014-10-25 Arnold D. Robbins + + * dfa.c: Sync with GNU grep. + +2014-10-17 John E. Malmberg + + * ext.c (close_extensions): Test for null pointer since + since this can be called by signal handler before the + pointers are initialized. + +2014-10-15 Arnold D. Robbins + + Make sane the handling of AWKPATH and AWKLIBPATH: + + 1. Don't explicitly search "."; it must be in the path either + physically or as null element a la the shell's $PATH + 2. If environment's value was empty, use built-in default value. + 3. Set ENVIRON["AWK*PATH"] to the path used. + + * io.c (path_info): Remove try_cwd member. + (get_cwd): Removed, not needed anymore. + (do_find_source): Don't do explicit check in current directory. + It must come from the AWKPATH or AWKLIBPATH variable. + * main.c (path_environ): If value from environment was empty, + set it to the default. This is how gawk has behaved since 2.10. + +2014-10-13 Arnold D. Robbins + + * regcomp.c (__re_error_msgid): Make error message for REG_EBRACK + more helpful - also used for unmatched [:, [., [=. + Thanks to Davide Brini for raising the issue. + +2014-10-12 KO Myung-Hun + + Fixes for OS/2: + + * Makefile.am (install-exec-hook, uninstall-links): Use $(EXEEXT). + * getopt.h: Redefinitions if using KLIBC. + * io.c (_S_IFDIR, _S_IRWXU): Define if the more standard versions + are available. + +2014-10-12 Arnold D. Robbins + + * README: Remove Pat Rankin from VMS duties, per his request. + +2014-10-08 Arnold D. Robbins + + * dfa.c: Sync with GNU grep. + +2014-10-05 Arnold D. Robbins + + * 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 + + * 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 + + * awkgram.y (program_comment): Renamed from comment0. + (function_comment): Renamed from commentf. + +2014-10-02 Arnold D. Robbins + + * awkgram.y, profile.c: Minor white space cleanups. + +2014-10-01 Arnold D. Robbins + + 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 + + * main.c (main): In optlist, it should say "h", not "h:", since there + is no argument for the help option. Thanks to Joep van Delft for + the bug report. + +2014-09-29 Arnold D. Robbins + + * gawkapi.h: Minor edits to sync with documentation. Does not + influence the behavior of the API. + +2014-09-28 Arnold D. Robbins + + * command.y (cmdtab): Add "where" as an alias for "backtrace". + Finally! + + Unrelated: + + * dfa.c: Sync with GNU grep. + +2014-09-27 Arnold D. Robbins + + * awkgram.y (check_for_bad): Bitwise-and the bad character with 0xFF + to avoid sign extension into a large integer. + + Unrelated: + + * configure.ac: Add an option to enable locale letters in identifiers. + Undocumented and subject to being rescinded at any time in the future. + * NEWS: Mention to look at configure --help. + + Unrelated: + + * profile.c (pprint): Use "rule(s)" instead of "block(s)" in the + header. + +2014-09-23 Arnold D. Robbins + + * awkgram.y (yylex): Don't check for junk characters inside + quoted strings. Caused issues on DJGPP and Solaris. + + Unrelated: + + * io.c (devopen): Straighten things out with respect to + compatibility with BWK awk. + +2014-09-19 Arnold D. Robbins + + * awkgram.y: Further commentary as to the treacherousness + of isalnum and isalpha. + +2014-09-15 Arnold D. Robbins + + Finish removing use of isalpha and isalnum. + + * awk.h (is_alpha, is_alnum, is_identchar): Add declarations. + * awkgram.y (yylex): Use is_alpha. + (is_alpha, is_alnum): New functions. + (is_identchar): Use is_alnum. + * builtin.c (r_format_tree): Use is_alpha, is_alnum. + * command.y (yylex): Use is_alpha, is_identchar. + * ext.c (is_letter): Use is_alpha. + (is_identifier_char): Removed; replaced uses with is_identchar. + * main.c (arg_assign): Use is_alpha, is_alnum. + * node.c (r_force_number): Use is_alpha. + +2014-09-14 Arnold D. Robbins + + * awkgram.y (is_identchar): Change from simple macro to function + since use of isalnum() let non-ASCII letters slip through into + identifiers. + +2014-09-13 Stephen Davies + + 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 variables 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 preceded by comments, take the last non-blank + line as function comment and any preceding 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 + + * awk.h: Move libsigsegv stuff to ... + * main.c: here. Thanks to Yehezkel Bernat for motivating + the cleanup. + * symbol.c (make_symbol, install, install_symbol): Add const to + first parameter. Adjust decls and fix up uses. + +2014-09-05 Arnold D. Robbins + + Add builtin functions to FUNCTAB for consistency. + + * awk.h (Node_builtin_func): New node type. + (install_builtins): Declare new function. + * awkgram.y [DEBUG_USE]: New flag value for debug functions; they + don't go into FUNCTAB. + (install_builtins): New function. + * eval.c (nodetypes): Add Node_builtin_func. + * interpret.h (r_interpret): Rework indirect calls of built-ins + since they're now in the symbol table. + * main.c (main): Call `install_builtins'. + * symbol.c (install): Adjust for Node_builtin_func. + (load_symbols): Ditto. + +2014-09-04 Arnold D. Robbins + + * profile.c (pprint): Case Op_K_for: Improve printing of + empty for loop header. + + Unrelated: Make indirect function calls work for built-in and + extension functions. + + * awkgram.y (lookup_builtin): New function. + * awk.h (builtin_func_t): New typedef. + (lookup_builtin): Declare it. + * interpret.h (r_interpret): For indirect calls, add code to + find and call builtin functions, and call extension functions. + +2014-09-01 Arnold D. Robbins + + * builtin.c (do_substr): Return "" instead of null string in case + result is passed to length() with --lint. Based on discussions in + comp.lang.awk. + + Unrelated: + + * interpret.h (r_interpret): For indirect function call, separate + error message if lookup returned NULL. Otherwise got a core dump. + Thanks to "Kenny McKormack" for the report in comp.lang.awk. + +2014-08-27 Arnold D. Robbins + + * configure.ac: Add test for strcasecmp. + * regcomp.c: Remove special case code around use of strcasecmp(). + * replace.c: Include missing/strncasecmp.c if either strcasecmp() + or strncasecmp() aren't available. + +2014-08-26 Arnold D. Robbins + + * regcomp.c, regex_internal.c: Sync with GBLIC. Why not. + + Unrelated: + + Remove support for MirBSD. It uglified the code too much + for no discernible 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 + + * regex.h: Remove underscores in names of parameters in function + declarations. Tweak names as needed. + +2014-08-20 Arnold D. Robbins + + * node.c (parse_escape): Max of 2 digits after \x. + +2014-08-18 Arnold D. Robbins + + * symbol.c: General formatting cleanup. + +2014-08-15 Arnold D. Robbins + + * main.c (usage): Adjust whitespace for -L and add "invalid" + as a possible value for it. Report from Robert P. J. Day + . + +2014-08-14 Arnold D. Robbins + + * Makefile.am (SUBDIRS): Put awklib after doc so that examples + get extracted when the doc changes. + +2014-08-13 Arnold D. Robbins + + * builtin.c (do_sub): Move initial allocation of the replacement + string down towards code to do the replacement, with a (we hope) + better guesstimate of how much to initially allocate. The idea + is to avoid unnecessary realloc() calls by making a better guess + at how much to allocate. This came up in an email discussion + with Tom Dickey about mawk's gsub(). + +2014-08-12 Juergen Kahrs + + * cmake/configure.cmake: + * cmake/package.cmake: Copyright update. + * README.cmake: + * README_d/README.cmake: Moved file. + +2014-08-12 Arnold D. Robbins + + OFS being set should rebuild $0 using previous OFS if $0 + needs to be rebuilt. Thanks to Mike Brennan for pointing this out. + + * awk.h (rebuild_record): Declare. + * eval.c (set_OFS): If not being called from var_init(), check + if $0 needs rebuilding. If so, parse the record fully and rebuild it. + Make OFS point to a separate copy of the new OFS for next time, since + OFS_node->var_value->stptr was already updated at this point. + * field.c (rebuild_record): Is now extern instead of static. + Use OFS and OFSlen instead of the value of OFS_node. + + Unrelated: + + * Makefile.am (RM): Define for makes that don't have it, + such as on OpenBSD. Thanks to Jeremie Courreges-Anglas + for the report. + +2014-08-05 Arnold D. Robbins + + Bug fix: For MPFR sqrt(), need to set precision of result to be + the same as that of the argument. Doesn't hurt other functions. + See test/mpfrsqrt.awk. Thank to Katie Wasserman + for the bug report. + + * mpfr.c (do_mpfr_func): New function. Runs code for MPFR functions + while still enabling debugging. Add call here to mpfr_set_prec(). + Original code from SPEC_MATH macro. + (SPEC_MATH): Change macro to call do_mpfr_func(). + + Next MPFR bug fix: The % operator gave strange results for negative + numerator. Thanks again to Katie Wasserman for the bug report. + + * mpfr.c (mpg_mod): Use mpz_tdiv_qr() instead of mpz_mod(). From + the GMP doc, mpz_mod() should have worked; it's not clear why + it doesn't. + +2014-08-03 Arnold D. Robbins + + * builtin.c (format_tree): Don't need to check return value of + wctombr for -2. Thanks to Eli Zaretskii for pointing this out. + + Unrelated: + + * gawkapi.h: Fix doc for API get_record - errcode needs to + be greater than zero. + * interpret.h (r_interpret): Move setting of ERRNO to here, from ... + * io.c (inrec): ... here. Makes the code cleaner. + +2014-08-03 Andrew J. Schorr + + * awkgram.y (getfname): Match on either ptr or ptr2 so --profile + will work in -M (MPFR bignum) mode. + +2014-07-31 Arnold D. Robbins + + * builtin.c (format_tree): Make %c handling more sane on Windows. + Rework the lint messages. + + Unrelated: + + * dfa.c: Sync with GNU grep. Mainly white space differences. + + Unrelated: + + * mpfr.c (cleanup_mpfr): New function to deallocate _mpf_t1 + and _mpf_t2; removes some valgrind warnings. + * 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 + for isolating the problem to that routine. + +2014-07-25 Arnold D. Robbins + + * main.c (main): Add a warning message if -M is used and gawk was + compiled without MPFR/GMP. + +2014-07-24 Arnold D. Robbins + + * main.c (usage): Put text for `-n' *after* text for `-m'. + Report from Robert P. J. Day . + + Fix problems with I/O errors reported by Assaf Gordon + : + + * io.c (inrec): Change type to bool to make calling easier. Add + check in non-EOF case for error, and if so, return false. + Update ERRNO in case there is an ENDFILE block. + * awk.h (inrec): Change type in declaration. + * interpret.h (r_interpret): Change call of inrec() to boolean + notation. + +2014-07-10 Arnold D. Robbins + + New `div()' function to do integer division and remainder; + mainly useful for use with GMP integers. Thanks to + Katie Wasserman 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 + + * awkgram.y (check_for_bad): New routine to do the fatal message, + with smarter checking. + (nextc): Call it as appropriate. + + * builtin.c (format_tree): Add check for bad returns from mbrlen + to avoid trying to malloc (size_t) -1 bytes. Thanks to + mail.green.fox@gmail.com for the bug report. + +2014-07-03 Arnold D. Robbins + + * awkgram.y (nextc): Add bool check_for_bad parameter to check + for bad characters in the source program. + (yylex): Adjust calls. + +2014-06-24 Arnold D. Robbins + + * 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 + + Bring in from GNULIB: + + regex: fix memory leak in compiler + Fix by Andreas Schwab in: + https://sourceware.org/ml/libc-alpha/2014-06/msg00462.html + * lib/regcomp.c (parse_expression): Deallocate partially + constructed tree before returning error. + +2014-06-19 Arnold D. Robbins + + * builtin.c (do_sub): Add more info to leading comment. + Add some whitespace in the code. + +2014-06-08 Arnold D. Robbins + + * dfa.c: Sync with GNU grep. + +2014-06-03 Arnold D. Robbins + + * dfa.c (mbs_to_wchar): Define a macro if not MBS. + +2014-05-29 Arnold D. Robbins + + * dfa.c: Sync with GNU grep. + +2014-05-26 Arnold D. Robbins + + * io.c (inetfile): Change return type to bool. Wrap code + with ifdef HAVE_SOCKETS so that it'll compile on DJGPP. + +2014-05-22 Andrew J. Schorr + + Allow any redirected getline inside BEGINFILE/ENDFILE. + + * awkgram.y (LEX_GETLINE): Only require a redirection and not also + a variable if getline is in a BEGINFILE or ENDFILE rule. + * interpret.h (Op_K_getline_redir): Remove check and fatal error. + +2014-05-20 Arnold D. Robbins + + * dfa.c (dfaexec): Minor sync with GNU grep. + +2014-05-14 Arnold D. Robbins + + * custom.h (_GL_PURE): Move definition to here. Sigh. + * dfa.h, dfa.c: Sync with GNU grep. Sigh. + + Unrelated: + + * custom.h: Remove stuff for Ultrix 4.3. No one has such + systems anymore; this just got missed earlier. + +2014-05-11 Arnold D. Robbins + + * debug.c (do_eval): Repair fix of 2014-05-09 and use + assoc_remove to take @eval out of the function table. + * symbol.c: Fix a comment. This file needs some work. + +2014-05-10 Arnold D. Robbins + + * io.c (get_a_record): Finish TERMNEAREND handling in case + we don't have a regular file but aren't going to get more data. + Added some additional comments. + +2014-05-09 Arnold D. Robbins + + * debug.c (do_eval): Don't free `f' which points into the context + that was previously freed. Bug reported by Jan Chaloupka + . Apparently introduced with move to + SYMTAB and FUNCTAB, but only showed up on Fedora 20 and Ubuntu 14.04, + which have a newer glibc. + (do_eval): Fix a memory leak seen by valgrind on Fedora 20 and + Ubuntu 14.04: the new SRCFILE that is added wasn't released. + + Unrelated: + + * io.c (get_a_record): Handle return of TERMNEAREND when the + entire file has been read into the buffer and we're using a + regex for RS. Bug report by Grail Dane . + +2014-05-04 Arnold D. Robbins + + * debug.c (debug_prog): Change check for GAWK_RESTART so that it + actually works. Bug fix: run command in debugger would start + over again but not actually start running the program. + +2014-04-25 Andrew J. Schorr + + * io.c (two_way_open): In forked child, reset SIGPIPE to SIG_DFL. + Fixes problems with "broken pipe" errors from child processes, + restoring 4.1.0 and earlier behavior. Thanks to Daryl F + for the report. + (gawk_popen): Ditto. + +2014-04-25 Arnold D. Robbins + + * dfa.h, dfa.c: Merge with GNU grep; lots of forward motion. + +2014-04-24 Arnold D. Robbins + + Update xalloc.h for pending merge with dfa. + + * xalloc.h (xstrdup): Implement this. + (x2nrealloc): Incorporate changed logic from GNULIB. + +2014-04-20 Andrew J. Schorr + + * io.c (struct inet_socket_info): Define new structure + for use in parsing special socket filenames. + (inetfile): Parse all components of the special socket filename + into the struct inet_socket_info. Returns true only if it is a + valid socket fliename, unlike the previous version which checked + for the '/inet[46]?/' prefix only. + (redirect): Patch to use updated inetfile() function. + (devopen): Remove logic to parse socket filenames, since this has + been moved into the inetfile() function. + (two_way_open): Update args to inetfile(). + +2014-04-20 Arnold D. Robbins + + * builtin.c (do_rand): Make calls to random() in predictable + order to avoid order of evaluation differences amongst compilers. + Thanks to Anders Magnusson (of the PCC team) + for the suggestion. + +2014-04-18 Arnold D. Robbins + + * configure.ac: Change adding of -export-dynamic for GCC to be + -Wl,-export-dynamic, which then works for PCC also. + +2014-04-11 Arnold D. Robbins + + * io.c (closemaybesocket): Define if not defined, e.g. building + without socket code. Thanks to dave.gma@googlemail.com (Dave Sines) + for the report. + +2014-04-08 Arnold D. Robbins + + * 4.1.1: Release tar ball made. + +2014-04-08 Arnold D. Robbins + + * README: Update. + * configure.ac: Bump version. + +2014-04-03 Arnold D. Robbins + + * regcomp.c (parse_bracket_exp): Move a call to `re_free' inside + an ifdef. Makes the code marginally cleaner. + +2014-03-30 Arnold D. Robbins + + * dfa.c: Sync with GNU grep. + +2014-03-28 Arnold D. Robbins + + * configure.ac: Remove duplicate AC_HEADER_TIME and rearrange + order of macros some. May help on older systems. + +2014-03-23 Arnold D. Robbins + + * dfa.c: Move include of dfa.h around for correct building + on Irix. Thanks to Nelson H.F. Beebe for the report. + + Unrelated: + + * .gitignore: Simplify .dSYM pattern for Mac OS X. + +2014-03-21 Arnold D. Robbins + + * dfa.c (using_simple_locale): Add ifdefs in case there is no + locale support at all. Thanks to Scott Deifik for the report. + + Unrelated: + + * main.c (UPDATE_YEAR): Set to 2014. + +2014-03-17 Arnold D. Robbins + + * .gitignore: Add .dSYM directories for Mac OS X. + Thanks to Hermann Peifer for the suggestion. + +2014-03-10 Arnold D. Robbins + + * dfa.h, dfa.c: Sync with grep. Yet again. + * regex_internal.c (built_wcs_upper_buffer, build_upper_buffer): + Fixes from GNULIB for mixed case matching on Mac OS X. + + Unrelated: + + * builtin.c (format_tree): Smarten handling of %' flag. Always + pass it in for floating point formats. Then only add the + thousands_sep if there is one. Also, allow for thousands_sep + to be a string, not just one character. Thanks to Michal Jaegermann + for the report. + +2014-03-08 Andrew J. Schorr + + * gawkapi.c (api_impl): Add memory allocation function pointers. + * gawkapi.h (GAWK_API_MINOR_VERSION): Bump. + (gawk_api_t): Add memory allocation function pointers api_malloc, + api_calloc, api_realloc, and api_free. + (gawk_malloc, gawk_calloc, gawk_realloc, gawk_free): New macros. + (emalloc): Replace malloc with gawk_malloc. + (erealloc): Replace erealloc with gawk_erealloc. + +2014-03-05 Arnold D. Robbins + + Straighten out enumerated types some more. + + * awk.h (add_srcfile): Fix type of first parameter. + * awkgram.y (add_srcfile, do_add_srcfile): Ditto. + * cmd.h (A_NONE): New enum nametypeval. + * command.y (argtab): Use it in final value. + * ext.c (make_builtin): Use awk_false, awk_true. + * io.c (init_output_wrapper): Use awk_false. + + Unrelated: + + * debug.c (do_commands): Initialize num to silence warnings. + Thanks to Michal Jaegermann. + + Unrelated: + + * builtin.c (do_mktime): Change lint warning for minutes to + check against 59, not 60. Thanks to Hermann Peifer for the report. + +2014-03-03 Arnold D. Robbins + + * dfa.c: Sync with grep. Yet again. + +2014-02-28 Arnold D. Robbins + + * dfa.c: Sync with grep. Looks like good improvement with + respect to bracket expressions. + +2014-02-27 Arnold D. Robbins + + Fixes for enum/int mismatches as warned by some compilers. + + * awk.h (ANONE): New enum for array sorting. + * array.c (assoc_list): Use it. + * builtin.c (format_tree): New MP_NONE value. + * gawkapi.c: Use awk_false and awk_true everywhere instead of + false and true. + +2014-02-26 Arnold D. Robbins + + * configure.ac: Set up do-nothing extension/Makefile on + MirBSD also. + +2014-02-21 Arnold D. Robbins + + * dfa.h, dfa.c (parse_bracket_exp): Sync with grep. + +2014-02-20 Arnold D. Robbins + + * regex.h, regex.c, regex_internal.c, regex_internal.h: Sync + with GLIBC. Mainly copyright updates. + * getopt.c, getopt.h, getopt1.c, getopt_int.h: Ditto. + * dfa.c (parse_bracket_exp): Sync with grep, where they restored + the buggy code. Sigh. + + Unrelated: + + * NEWS: Typo fix. + * interpret.h (r_interpret): Init a variable for BEGINFILE to avoid + compiler warnings. Thanks to Michal Jaegermann. + +2014-02-15 Arnold D. Robbins + + * awkgram.c, command.c: Regenerated - Bison 3.0.2. + +2014-02-04 Arnold D. Robbins + + * dfa.c (to_uchar): Make use of this. Syncs with GNU grep. + +2014-02-03 Arnold D. Robbins + + * awkgram.y (negate_num): Bracket `tval' in #ifdef MPFR since it's + only used in that code. + +2014-01-31 Arnold D. Robbins + + * Makefile.am (dist-hook): Improve creation of pc/config.h. We + have to jump through a lot of hoops for 'make distcheck' to + actually work. + +2014-01-30 Arnold D. Robbins + + * Makefile.am (dist-hook): Improve creation of pc/config.h to copy + the new file into the distribution directory being created. + Also, put the temporary files into /tmp. + +2014-01-28 Arnold D. Robbins + + * awkgram.y (negate_num): If just a double, return. Fixes a bug + that showed up on 32-bit systems with MPFR. Thanks to Eli Zaretskii + and Corinna Vinschen for the report. Also, free the MPZ integer. + Thanks to valgrind for the report. + + Unrelated: + + * dfa.c: Sync with GNU grep - removed some special cased code + for grep. + +2014-01-24 Arnold D. Robbins + + * configure.ac, field.c: Update copyright year. + +2014-01-19 Arnold D. Robbins + + * awkgram.y (negate_num): Handle the case of -0 for MPFR; the sign + was getting lost. Thanks to Hermann Peifer for the report. + +2014-01-18 Arnold D. Robbins + + * dfa.c (parse_bracket_exp): Sync with GNU grep, which now uses + gawk's code for RRI in single-byte locales! Hurray. + +2014-01-16 Arnold D. Robbins + + * configure.ac: For z/OS, restore creation of do-nothing + Makefile in extension directory. + +2014-01-14 Arnold D. Robbins + + * field.c (do_split): Make sure split() gets FS value if no + third arg even after FPAT was set. Thanks to Janis Papanagnou + for the report. + +2014-01-13 Arnold D. Robbins + + * README: Fix John Malmberg's email address. + +2014-01-12 Arnold D. Robbins + + * awkgram.y: Update copyright year. + (func_use): Simplify code. + * command.y: Update copyright year. + * ext.c: Update copyright year. + (make_builtin): Small simplification. + (make_old_builtin): Make code consistent with make_builtin(), add + call to track_ext_func(). + * bootstrap.sh: Update copyright year. Remove touch of version.c + since that file is no longer autogenerated. + +2014-01-07 Arnold D. Robbins + + * command.y (next_word): Move into ifdef for HAVE_LIBREADLINE, + since it's only used by that code. + * ext.c (load_old_ext): Minor improvements. + +2014-01-03 Arnold D. Robbins + + * config.guess, config.rpath, config.sub, depcomp, + install-sh: Updated. + * dfa.h, dfa.c: Sync with GNU grep; comment fix and copyright year. + * NEWS: Updated some, including copyright year. + +2013-12-26 Arnold D. Robbins + + * README: Add John Malmberg for VMS. + +2013-12-24 Arnold D. Robbins + + * getopt.h: Add `defined(__sun)' to list of system that do get to + include stdlib.h. Needed for Illumos. Thanks to + Richard Palo for the report. + +2013-12-21 Mike Frysinger + + * configure.ac: Add --disable-extensions flag to control + compiling extensions. Better for cross-compiling. + (AC_CANONICAL_HOST): Added. Changed case statements appropriately. + * Makefile.am (check-for-shared-lib-support): Removed. + (check-recursive, all-recursive): Removed. + +2013-12-21 Arnold D. Robbins + + * config.guess: Updated. + * configure, aclocal.m4: Updated based on automake 1.13.4. + +2013-12-19 Arnold D. Robbins + + * regexec.c (re_search_internal): Make sure `dfa' pointer is + not NULL before trying to dereference it. + +2013-12-16 Arnold D. Robbins + + * configure.ac (AC_FUNC_VPRINTF): Remove. Not needed on current + systems. + * awk.h (HAVE_VPRINTF): Remove check. + +2013-12-12 John E. Malmberg + + * io.c (redirect): Add additional VMS error codes. + (nextfile): Retry open after closing some files. + +2013-12-10 Scott Deifik + + * io.c (closemaybesocket): Add definition for DJGPP. + +2013-12-10 Arnold D. Robbins + + * awk.h (Floor, Ceil): Remove declarations and VMS redefinitions. + * floatcomp.c (Floor, Ceil): Removed, not needed. Move bracketing + ifdef to the top of the file. + * builtin.c (double_to_int): Use floor() and ceil(). + +2013-12-07 Arnold D. Robbins + + * regex_internal.h (__attribute__): Define to empty if not GCC. + * custom.h (__attribute__): Remove the definition from here; the + right place was regex_internal.h. + +2013-12-06 Arnold D. Robbins + + No need to generate version.c from version.in. + Thanks to John E. Malmberg for the suggestion. + + * version.in: Removed. + * version.c: Use PACKAGE_STRING directly. + * Makefile.am (EXTRA_DIST): Remove version.in. + (distcleancheck_listfiles): Remove this rule. + (MAINTAINERCLEANFILES): Remove this definition. + (version.c): Remove the rule to create it. + +2013-12-05 Arnold D. Robbins + + Fixes for Z/OS. + + * custom.h (__attribute__): Define to empty. + * dfa.c (parse_bracket_exp): Add a cast to quiet a warning. + * regex.c: Correctly bracket include of . + + Unrelated: + + * debug.c (find_rule): Add a FIXME comment. + +2013-12-03 John E. Malmberg + + * io.c (redirect): Add additional VMS error code to check. + (do_find_source): Append "/" if not a VMS filename. + +2013-12-01 Andrew J. Schorr + + * main.c (optab): Sort by long option name. + +2013-11-27 Andrew J. Schorr + + * main.c (optab): Add entry for --include. + +2013-11-23 Arnold D. Robbins + + * dfa.c: Merge from grep; minor fixes in how bit twiddling + is done. + +2013-11-01 Arnold D. Robbins + + * dfa.c (lex): Reset laststart so that stuff like \s* works. + Fix from grep. + +2013-10-31 Arnold D. Robbins + + * builtin.c (efwrite): If write error to stdout is EPIPE, + die silently. Thanks to Hermann Peifer for helping find this. + +2013-10-22 Arnold D. Robbins + + Revise error messages when writing to standard output or standard + error to ignore EPIPE. Add the ability based on an environment + variable to get the source file and line number. + + * awk.h (r_warning): Renamed from warning. + (warning): New macro to set location and call warning. + * io.c (flush_io): Print errors only if not EPIPE. + (close_io): Ditto. + * main.c (lintfunc): Init to r_warning. + (main): Enhance explanatory comment. + (usage): Print errors only if not EPIPE. + (copyleft): Ditto. + * msg.c (err): Make printing srcfile and srcline depend upon + GAWK_MSG_SRC environment variable. + (r_warning): Renamed from warning. + +2013-10-17 Arnold D. Robbins + + * 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 + + Make -O work again. Turns out that C99 bool variables + are clamped to zero or one. + + * main.c (do_optimize): Init to false. + (main): Set do_optimize to true on -O. + * eval.c (setup_frame): Change all uses of do_optimize to be + a boolean check instead of a test > 1. + * awkgram.y: Ditto. + (optimize_assignment): Remove check against do_optimize since + it was inited to true anyway. + + Unrelated: + + * 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 + + * dfa.c (lex): Sync with GNU grep. Handle multibyte \s and \S. + + Unrelated: + + * awk.h [ARRAY_MAXED]: Fix value of this and subsequent flags + after addition of NULL_FIELD. + * eval.c (flags2str): Add NULL_FIELD. Duh. + +2013-10-09 Arnold D. Robbins + + * awkgram.y (mk_assignment): Rework switch to handle Op_assign, + and to provide a better error message upon unknown opcode. + +2013-09-28 Arnold D. Robbins + + * dfa.c: Sync with GNU grep. + +2013-09-25 Arnold D. Robbins + + * builtin.c (do_rand): Make the result more random by calling + random() twice. See the comment in the code. Thanks to + Bob Jewett for the report and + the fix. + +2013-09-24 Arnold D. Robbins + + * debug.c (find_rule): Handle case where lineno is zero. Can happen + if break is given without a line number on a current line. Thanks + to Ray Song for the report. + +2013-09-19 Arnold D. Robbins + + * dfa.c (parse_bracket_exp): Use code from grep to keep things within + range (updates change of 2013-09-08). Fix whitespace in one of the + gawk-only additions. + +2013-09-13 Arnold D. Robbins + + Fix use of NF after it's extended, e.g. see test/nfloop.awk. + + * awk.h (NULL_FIELD): New flag + * builtin.c (do_print_rec): Check f0->flags instead of if + equal to Nnull_string. + * eval.c (r_get_field): Check (*lhs)->flags instead of if + equal to Nnull_string or Null_field. + * field.c (init_fields): Init field zero and Null_field with + NULL_FIELD flag. + (set_NF): Set parse_high_water = NF in case NF extended past the + end. This is the actual bug fix. + +2013-09-08 Arnold D. Robbins + + Fixes based on reports from a static code checker. Thanks to + Anders Wallin for sending in the list. + + * array.c (asort_actual): Free list if it's not NULL. + * builtin.c (do_sub): Set buf to NULL and assert on it before using + it. + * cint_array.c (cint_array_init): Clamp any value of NHAT from the + environment such that it won't overflow power_two_table when used as + an index. + * dfa.c (parse_bracket_exp): Check that len is in range before using it + to index buf. + * getopt.c (_getopt_internal_r): Change call to alloca to use malloc. + * io.c (socket_open): Init read_len to zero. + (two_way_open): Upon failure to fork, close the slave fd also. + * re.c (research): Init try_backref to false. + * regcomp.c (build_range_exp): Free any items that were allocated in + the case where not all items were. + (build_charclass_op): Same. Init br_token to zero with memset. + (create_tree): Init token t to zero with memset. + * regex_internal.c (re_dfa_add_node): Free any items that were + allocated in the case where not all items were. + * symbol.c (destroy_symbol): On default, break, to fall into releasing + of resources. + +2013-08-29 Arnold D. Robbins + + * debug.c (HAVE_HISTORY_LIST): Move checks and defines to the top. + (do_save, serialize): Adjust #if checks to depend on having both + readline and the history functions. Needed for Mac OS X whose + native readline is a very old version. Sigh. + * configh.in, configure: Regenerated due to change in m4/readline.m4. + Issue reported by Hermann Peifer and Larry Baker. + + Unrelated: + + * getopt.c: Sync with GLIBC, changes are minor. + + Unrelated: + + * dfa.c: Sync with version in grep. Primarily whitespace / comment + wording changes. + +2013-08-26 Arnold D. Robbins + + * regcomp.c (parse_dup_op): Remove RE_TOKEN_INIT_BUG code (change of + Feb 19 2005) since it's no longer needed. + + * regcomp.c (re_fastmap_iter): Undo addition of volatile from + Jan 18 2007; no longer needed and is one less change to have to + maintain against the upstream. + + * regcomp.c, regex.h, regex_internal.h: Sync with GLIBC. + +2013-08-22 Arnold D. Robbins + + * 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 + + * nonposix.h: New file. Contains FAKE_FD_VALUE. + * awk.h: Include it if MinGW or EMX. + * Makefile.am (base_sources): Add nonposix.h. + +2013-08-18 Arnold D. Robbins + + 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 + + * 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. + +2013-08-15 Arnold D. Robbins + + * debug.c (print_memory): Fix whitespace / indentation. + +2013-08-02 Arnold D. Robbins + + * awkgram.y (append_rule): Add attempt to insert any comment + before a rule. Commented out at the moment. + +2013-07-30 Arnold D. Robbins + + * 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 + + * io.c (FAKE_FD_VALUE): Move definition from here ... + * awk.h (FAKE_FD_VALUE): ... to here. Fixes compilation on MinGW. + +2013-07-08 Arnold D. Robbins + + * io.c (get_a_record): Change `min' to `MIN' for consistency with + other files and general practice. + +2013-07-07 Andrew J. Schorr + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * gawkapi.h (awk_element_t): Add comment indicating that the array + element index will always be a string! + * gawkapi.c (api_flatten_array): When converting the index to an awk + value, request a string conversion, since we want the indices to + appear as strings to the extensions. This makes the call to + force_string redundant, since node_to_awk_value does that internally + when we request a string. + +2013-07-02 Andrew J. Schorr + + * 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 + + * eval.c (update_ERRNO_int, unset_ERRNO): Update PROCINFO["errno"]. + +2013-06-30 Andrew J. Schorr + + * 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 + + * builtin.c (format_tree): Fixes for %c with multibyte characters + and field width > 1. Bugs reported by Nethox . + +2013-07-02 Arnold D. Robbins + + * profile.c (pp_string): Add a call to chksize and fix another. + Avoids valgrind errors on profile5 test. Thanks to Andrew + Schorr for the report. + +2013-06-27 Arnold D. Robbins + + * awkgram.y: Minor whitespace cleanup, remove redundant ifdef. + +2013-06-24 Arnold D. Robbins + + * dfa.c (copytoks): Rewrite to call addtok_mb() directly. Avoids + problems with multibyte characters inside character sets. + Thanks to Steven Daniels for reporting + the problem. Much thanks to Mike Haertel for the + analysis and fix. + +2013-06-24 Eli Zaretskii + + * io.c: Move #include "popen.h" out of the HAVE_SOCKETS condition, + as this is needed for non-sockets builds as well. See + http://lists.gnu.org/archive/html/bug-gawk/2013-06/msg00014.html + for the details of the problem this caused. + +2013-06-15 Arnold D. Robbins + + * io.c: Add ifdefs for VMS so that it will compile again. + Thanks to Anders Wallin. + +2013-06-11 Arnold D. Robbins + + * debug.c (print_lines): Move setting of binary mode to after all + the messing with the fd. Simplifies code some. + * io.c (srcopen): Rearrange so that can add call to setbinmode + here too. This fixes the debugger and makes reading source + files a little faster. Thanks again to Corinna Vinschen. + +2013-06-10 Arnold D. Robbins + + * debug.c (print_lines): Set binary mode so that calculation of the + byte offsets will be right. Thanks to Corinna Vinschen for the + direction. + +2013-06-10 Arnold D. Robbins + + * re.c (check_bracket_exp): Remove warning about ranges being + locale dependent, since they aren't anymore. + +2013-06-09 Arnold D. Robbins + + * io.c (iop_finish): Change fstat call to fcntl/F_GETFL per + Eli Z., for Windows. + +2013-06-03 Arnold D. Robbins + + * eval.c (unwind_stack): If exiting, don't worry about strange stuff + on the stack. + + Unrelated: + + * awk.h (init_sockets): Declare. + * io.c (init_io): Remove ifdef around call. + +2013-06-01 Eli Zaretskii + + * io.c (SHUT_RD) [SD_RECEIVE]: Define to SD_RECEIVE. + (SHUT_WR) [SD_SEND]: Define to SD_SEND. + (SHUT_RDWR) [SD_BOTH]: Define to SD_BOTH. + (FD_TO_SOCKET, closemaybesocket) [!FD_TO_SOCKET]: New macros. + (SOCKET_TO_FD, SOCKET) [!SOCKET_TO_FD]: New macros. + (PIPES_SIMULATED): Define only for DJGPP. + (pipe) [__MINGW32__]: Define to call _pipe, unless PIPES_SIMULATED + is defined. + (init_io) [HAVE_SOCKETS]: Call init_sockets. + (iop_close, socketopen): Call closemaybesocket instead of close. + (redirect) [__MINGW32__]: Call wait_any with a non-zero argument. + (devopen) [__EMX__ || __MINGW32__]: Don't call stat on network + pseudo-filenames. + (two_way_open) [HAVE_SOCKETS]: Switch input and output to binary + mode if appropriate. + (two_way_open) [!PIPES_SIMULATED]: Use the __EMX__ code for MinGW + as well. + [__MINGW32__] Call spawnl to invoke $ComSpec and pass it a + suitably quoted command line. + (two_way_open) [__MINGW32__]: Wait only for a specified process + ID. If successful, update the exit status of the exited process. + Don't use signals that are undefined on MinGW. + (two_way_open) [!PIPES_SIMULATED]: Use the __EMX__ code for MinGW + as well. + (min): Define only if not already defined. + (read_with_timeout) [__MINGW32__]: Allow reading from sockets with + timeout. + (gawk_fclose) [__MINGW32__]: Close the underlying socket as well. + + * getopt.c: Include stdlib.h for MinGW as well. + +2013-05-30 Arnold D. Robbins + + More profiling fixes: + + * profile.c (pprint): For Op_in_array, parenthesize subscript if + the precedence is lower. E.g.: (c = tolower(foo)) in ARRAY. + (prec_level): Merge cases for precedence of 5. + (parenthesize): Simplify, as in 3.1.8. Avoids stuff like + `(x == 1 && (z ==2 && (q == 4 && w == 7)))'. + + Unrelated: + + * io.c (iop_finish): fstat the fd before closing it to avoid + errors on some operating systems. Thanks to Eli Zaretskii + for the report. + +2013-05-29 Arnold D. Robbins + + * profile.c (pp_group3): Renamed from pp_concat. Change all calls. + (is_binary): Change return type to bool. + (is_scalar): New function. + (pp_concat): New function to handle concatenation operator better. + (pprint): Call it at case Op_concat. Fix Op_K_delete if multiple + indexes to separate with "][". + General: Add leading comments as needed. + +2013-05-28 Arnold D. Robbins + + * main.c (main): Add minor hack to not run code if pretty printing + and undocumented env var GAWK_NO_PP_RUN exists. + * profile.c (pp_string): Explicitly print NUL chars as \000. + +2013-05-27 Arnold D. Robbins + + * configure.ac (AM_INIT_AUTOMAKE): Add dist-lzip to quiet + outside maintainer warnings. + + Unrelated: + + * configure.ac (AC_STRUCT_ST_BLKSIZE): Replaced with call to + AC_CHECK_MEMBERS. + + Unrelated: + + * array.c (null_array): Remove the assert and just clear + symbol->xarray. + +2013-05-26 Arnold D. Robbins + + * getopt.c: For Mac OS X, also include to avoid + some compiler warnings. + +2013-05-20 Arnold D. Robbins + + * gawkapi.h [FAKE_FD_VALUE]: Moved from here to ... + * io.c [FAKE_FD_VALUE]: here. + +2013-05-14 Eli Zaretskii + + * io.c (devopen) [__EMX__ || __MINGW32__]: Produce EISDIR on MinGW + when an attempt to open() a directory fails. + (two_way_open) [__EMX__ || __MINGW32__]: When trying to open() a + directory fails with EISDIR, assign FAKE_FD_VALUE to the file + descriptor and attributes of a directory to its mode bits. This + is needed to support the readdir extension. + + * gawkapi.h (FAKE_FD_VALUE): New macro, used in io.h and in + extension/gawkdirfd.h. + +2013-05-09 Arnold D. Robbins + + * 4.1.0: Release tar ball made. + +2013-05-09 Arnold D. Robbins + + * awkgram.y (snode): Make it a fatal error to use a regexp constant + as the second argument of index(). Thanks to Christopher Durant + and Brian Kernighan for the report + and the advice. + +2013-04-28 Eli Zaretskii + + * io.c (redirect): Remove the HACK that called close_one when + errno was zero in the MinGW build. This prevents failure in + several tests in the test suite, e.g., closebad. + +2013-04-28 Arnold D. Robbins + + * bootstrap.sh: Fix a comment. + +2013-04-24 Arnold D. Robbins + + * io.c (do_getline_redir): Fix the leading comment. + +2013-04-23 Arnold D. Robbins + + * main.c (load_procinfo): Add PROCINFO entries for API major + and minor versions. + +2013-04-21 Arnold D. Robbins + + * missing: Update from Automake 1.13.1. + +2013-04-18 Arnold D. Robbins + + * configure.ac: Fix a typo. + +2013-04-17 Corinna Vinschen + + * configure.ac: Remove special casing for cygwin for libiconv + and libintl. + +2013-04-16 Arnold D. Robbins + + * bootstrap.sh: Touch gawk.texi too. Update copyright. + +2013-04-16 Arnold D. Robbins + + * awkgram.c: Regenerated from bison 2.7.1. + * command.c: Ditto. + * dfa.h, dfa.c: Minor edits to sync with GNU grep. + * gettext.h: Sync with gettext 0.18.2.1. + * random.h: Remove obsolete __P macro and use. Update copyright year. + * Makefile.am, array.c, builtin.c, cint_array.c, cmd.h, debug.c, + eval.c, ext.c, field.c, gawkapi.c, gawkapi.h, gettext.h, int_array.c, + interpret.h, msg.c, node.c, profile.c, re.c, replace.c, str_array.c, + symbol.c: Update copyright year. + + Update to automake 1.13.1: + + * configure.ac (AM_INIT_AUTOMAKE): Update version. + * configure, Makefile.in, aclocal.m4, awklib/Makefile.in, + doc/Makefile.in, test/Makefile.in: Regenerated. + + * getopt.c, getopt.h, getopt1.c, getopt_int.h: Sync with GLIBC. + +2013-04-14 Arnold D. Robbins + + * awkgram.y (check_funcs): Fix logic of test for called but + not defined warning. Thanks to Scott Deifik for the bug report. + +2013-04-02 Arnold D. Robbins + + * profile.c (print_lib_list): Send final newline to prof_fp + instead of stdout. Thanks to Hermann Peifer for the bug report. + +2013-03-27 Arnold D. Robbins + + * Makefile.am (SUBDIRS): Move extension back into the middle of + the list so that `make check' without a prior `make' works. + + Unrelated: + + * main.c (main): Move env_lc into ifdef for LIBC_IS_BORKED. + +2013-03-20 Arnold D. Robbins + + For systems where libc is borked (MirBSD, maybe others). + + * dfa.c: Force use of gawk_mb_cur_max instead of MB_CUR_MAX and make + mbrtowc a macro that always fails. + (using_utf8): Force utf8 to be 0 if libc borked and gawk_mb_cur_max + is one. + * main.c (main): If libc is borked and LC_ALL or LANG exist in the + environment and are set to "C" or "c", force gawk_mb_cur_max to one. + +2013-03-11 Arnold D. Robbins + + * re.c (check_bracket_exp): Make handling of embedded ] in + regexp smarter. Thanks to Ed Morton + for reporting the bug. + +2013-03-01 Arnold D. Robbins + + Don't build extensions if API isn't supported: + + * Makefile.am (SUBDIRS): Move extension directory to last in case + building the extensions is not supported. + * configure.ac: Add check for MirBSD and don't even try to run the + checks for DYNAMIC if so. + + Check for systems (MirBSD) where libc doesn't understand not + to use UTF-8 for LC_ALL=C. + + * configure.ac (LIBC_IS_BORKED): AC_DEFINE if needed. + * regcomp.c (init_dfa): Change logic as needed if LIBC_IS_BORKED. + +2013-02-28 Arnold D. Robbins + + Cause profiling / pretty printing to include a list of + loaded extensions. Thanks to Hermann Peifer for the bug report. + + * awk.h (srcfiles): Add declaration. + * profile.c (print_lib_list): New function. + (dump_prog): Call it. + +2013-02-26 Arnold D. Robbins + + * awkgram.y (expression_list): In case of error return the list + instead of NULL so that snode gets something it can count. + +2013-02-12 Arnold D. Robbins + + * bisonfix.awk: Comment out code for fixing continued #if + statements. It is likely not needed anymore. Leave it there in + case I'm wrong. + +2013-02-06 Arnold D. Robbins + + * builtin.c (printf_common): Move nargs > 0 check into assert. + (do_sprintf): Add nargs check and fatal message to here. + +2013-02-04 Arnold D. Robbins + + * main.c (main): Remove undocumented -m option which was for + compatibility with BWK awk. His awk dropped it back in 2007. + +2013-02-03 Arnold D. Robbins + + * configure.ac: Add Automake test for cross compiling. + +2013-01-31 Arnold D. Robbins + + * regcomp.c, regex.c, regex_internal.c, regexec.c: Update + copyright years to sync with GLIBC. + + From: http://www.sourceware.org/ml/libc-alpha/2013-01/msg00967.html, + by Andreas Schwab : + + * regexec.c (extend_buffers): Add parameter min_len. + (check_matching): Pass minimum needed length. + (clean_state_log_if_needed): Likewise. + (get_subexp): Likewise.` + +2013-01-31 Arnold D. Robbins + + * dfa.c: Include "dfa.h" which includes regex.h after limits.h + so that RE_DUP_MAX gets the correct value. Especially needed on + OpenVMS. Thanks to Anders Wallin. + + * main.c (version): Print out API version numbers if DYNAMIC. + Helpful also for knowing if to run the shlib tests. + + * configure: Regenerated after change in m4/readline.m4. + +2013-01-31 Arnold D. Robbins + + * PROBLEMS: Removed. It is no longer needed. + * Makefile.am (EXTRA_DIST): Remove PROBLEMS from list. + +2013-01-31 Andrew J. Schorr + + * configure.ac: Remove TEST_MPFR conditional added in last patch. + We will instead test for MPFR capability by looking at the output + from gawk --version. + +2013-01-27 Andrew J. Schorr + + * configure.ac: Add MPFR test for use in test/Makefile.am. + +2013-01-25 Arnold D. Robbins + + * awkgram.y (parms_shadow): Change int param to bool. + * cmd.h (output_is_tty): Sync type with rest of code (is bool). + * dfa.c (MALLOC): Undef first, for Irix. + * Makefile.am (LDADD): Use LIBREADLINE and LIBMPFR instead of + automake substitutions. + * configure.ac (AC_INIT): Version bump. + (GAWK_CHECK_READLINE): Renamed from GNUPG_CHECK_READLINE. + +2013-01-23 Arnold D. Robbins + + * awk.h (list_functions): Change parameter to bool. + * symbol.c (list_functions): Ditto. + (get_symbols): Change sort parameter to bool. Additional + code cleanup. + +2013-01-22 Arnold D. Robbins + + * symbol.c (get_symbols): Reset count after each loop to only + sort the actual items retrieved. Thanks to Hermann Peifer (by + way of Andrew Schorr) for reporting the bug. Also add some + commentary and fix function name in emalloc calls. + +2013-01-20 Arnold D. Robbins + + * re.c (regexflags2str): New routine. + (resetup): If do_intervals, also turn on RE_NO_BK_BRACES. + Thanks to Yan Lei for the + bug report. + +2013-01-18 Arnold D. Robbins + + Fix a problem with include ordering to get ptrdiff_t definition, + showed up on Debian Lenny. Reported by Manuel Collado. + Fix brought over from grep. + + * dfa.h: Include regex.h and stddef.h directly. + * dfa.c: Adjust includes. + +2013-01-11 John Haque + + * awk.h (do_mpfr_rshift): Renamed from do_mpfr_rhift. + * awkgram.y (do_mpfr_rshift): Renamed from do_mpfr_rhift. + * mpfr.c (_tz1, _tz2, _mpz1, _mpz2, mpz1, mpz2, get_bit_ops, + free_bit_ops): Removed. + (init_mpfr): Remove calls to mpz_init. + (get_intval, free_intval): New functions. + (do_mpfr_rshift, do_mpfr_lshift): Rework code. + (do_mpfr_and, do_mpfr_or, do_mpfr_xor): Accept two or more arguments + to match regular functions. + +2013-01-11 Arnold D. Robbins + + * bisonfix.awk: Adjust ARGV / ARGC to force reading of standard + input; apparently needed for Mac OS X. Thanks to Akim Demaille + for the report. + +2013-01-06 Arnold D. Robbins + + * io.c (redirect, two_way_open): Set the name field in the + awk_input_buf_t and awk_output_buf_t structures, as needed. + Thanks to Manuel Collado for the report. + +2013-01-05 Arnold D. Robbins + + * regex_internal.h (struct re_dfa_t): Restore ifdefs around + __libc_lock_define, they really were needed. Bleah. + +2013-01-01 Arnold D. Robbins + + Sync with GLIBC regex files. + + * regex_internal.h (struct re_dfa_t): Remove ifdefs around + __libc_lock_define since it's already defined to empty in non-LIBC + case. + * regexec.c (check_node_accept_bytes): Restore decl with use from + GLIBC code since this is LIBC case. + +2012-12-27 Arnold D. Robbins + + * builtin.c (do_print, do_printf): Use output_fp as default + output for print/printf only if running under the debugger. + Otherwise use stdout as Brian, Peter, and Al intended. + +2012-12-25 Arnold D. Robbins + + Remove sym-constant from API after discussions with John + Haque and Andrew Schorr. + + * gawkapi.h (api_sym_constant): Removed field in API struct. + (sym_constant): Remove macro. + * gawkapi.c (set_constant, api_sym_update, api_sym_constant): Removed. + (sym_update_real): Renamed to api_sym_update(). is_const parameter + removed and code adjusted. + +2012-12-24 Arnold D. Robbins + + * 4.0.2: Release tar ball made. + +2012-12-23 John Haque + + * eval.c (r_get_lhs): Node_array_ref. If original is Node_var, + don't assign null-string as value. + * ext.c (get_argument): Node_array_ref. Check if already a scalar. + +2011-12-23 John Haque + + * awkgram.y (is_deferred_variable): New function. + (func_install): Call it. + * eval.c (r_interpret): Op_push_arg. Check for uninitialized scalar. + +2012-12-23 Arnold D. Robbins + + * awkgram.y (tokentab): Whitespace fix for "include". + * builtin.c (printf_common): Do a fatal error if no args to printf() + or sprintf(). + +2012-12-19 Arnold D. Robbins + + * bootstrap.sh: Touch extension/aclocal.m4 also. + + Unrelated: Extend input parser API: + + * awk.h (IOBUF): Remove read_func pointer. + * gawkapi.h (awk_input_buf_t): Move it to here. + * io.c (iop_alloc, get_a_record, get_read_timeout): Adjust code. + + Unrelated: Make sure that variables like NF, NR, FNR are + accessable correctly both through SYMTAB and through API. + + * gawkapi.c (api_sym_lookup): Call update_global_values(). + (api_sym_lookup_scalar): Ditto. + * interpret.h (Op_subscript, Op_subscript_lhs): Ditto. + * main.c (update_global_values): Adjust comment. + + Unrelated: Fix --disable-lint so that everything compiles. + + * main.c (main): Move case label inside ifdef. + * awkgram.y (isnoeffect): Add ifdefs around declaration, use, + and function body. + + Unrelated: Restore building with tcc. + + * awk.h (AFUNC): Move to array.c which is the only place its used. + (ainit_ind, atypeof_ind, etc.): New macros for use in array.c + * array.c (AFUNC): Change to use F##_ind. Works with tcc and other + compilers. + * configure.ac: Only add -export-dynamic flag if compiling with gcc. + +2012-12-18 Andrew J. Schorr + + * gawkapi.c (sym_update_real): If setting a scalar variable that exists + already in an undefined state with type set to Node_var_new, we must + update the type to Node_var if the new value is not undefined. + +2012-12-18 Arnold D. Robbins + + * awkgram.y (tokentab): "extension" needs to be inside ifdef DYNAMIC. + Thanks to Anders Wallin for finding this. + +2012-12-16 Arnold D. Robbins + + * debug.c (do_set_var): Fix last remaining `*assoc_lookup() = x'. + +2012-12-15 Arnold D. Robbins + + Infrastructure Updates: + + * awkgram.c, command.c: Regenerated with bison 2.7. + * config.guess, config.sub, depcomp: Updated from automake 1.12.6. + +2012-12-09 Arnold D. Robbins + + Clean up BINMODE to use symbolic values. + + * awk.h (enum binmode_values): New enum. + * eval.c (set_BINMODE): Use them. + * io.c (binmode, close_rp, gawk_popen): Ditto. + * main.c (main): Ditto. + * builtin.c (do_system): Ditto. + + Unrelated: + + * configure.ac: Look for posix_openpt + * io.c (two_way_open): Use posix_openpt if it's available. + Thanks to Christian Weisgerber for + the changes. + + Also unrelated: + + * regex.c: Don't include on VMS. Thanks to + Anders Wallin. + + Also unrelated: + + * ext.c (is_letter, is_identifier_char): New functions. Don't use + functions since those could rely on the locale. + (make_builtin): Adjust test for valid name to call the new + functions and return false instead of throwing a fatal error. + (make_old_builtin): Adjust test for valid name to call the new + function. + * awk.h (is_identchar): Move from here, ... + * awkgram.y (is_identchar): ... to here. This is safe, since + the locale is C during parsing the program. + + Also unrelated: Make all checks for bitflags being set consistent + in case we should wish to switch them to macro calls: + + * awkgram.y, builtin.c, cint_array.c, debug.c, eval.c, gawkapi.c, + int_array.c, io.c, mpfr.c, node.c, profile.c, str_array.c: Fix + as needed. + +2012-12-07 Arnold D. Robbins + + * awkgram.y (tokentab): `fflush()' is now in POSIX, remove the + RESX flag. This was the last use, so delete the flag. + (yylex): Don't check RESX. + + Thanks to Nathan Weeks for helping make this + happen. + +2012-12-01 Arnold D. Robbins + + * interpret.h: For op_assign_concat, if both strings + have WSTRCUR, then do the realloc() and append for the + wide string too. Thanks to Janis Papanagnou + for the discussion in + comp.lang.awk. + +2012-11-30 Arnold D. Robbins + + * regcomp.c, regex.c, regex_internal.h, regexec.c: Sync + with GLIBC. Why not. + + * gawkapi.c (awk_bool_t): Change into an enum with awk_false and + awk_true values. + +2012-01-30 Andrew J. Schorr + + Further cleanups of macros in awk.h + + * awk.h (_r, _t): Remove declarations. + (unref, m_force_string): Remove macros. + (r_unref): Move declaration. + (r_force_string): Remove declaration. + (DEREF, force_string, force_number, unref): Now inline functions. + (POP_STRING, TOP_STRING): Back to macros. + * eval.c (_t): Remove definition. + * main.c (_r): Remove definition. + * node.c (r_force_string): Remove. + +2012-11-27 Arnold D. Robbins + + * builtin.c (do_fflush): Make fflush() and fflush("") both + flush everything. See the comment in the code. + +2012-11-26 Arnold D. Robbins + + * awk.h (Node_old_ext_func, Op_old_ext_func): New enum values. + * configure.ac: Use -export-dynamic if supported for old extension + mechanism. + * eval.c (nodeytpes): Add Node_old_ext_func. + (optypetab): Add Op_old_ext_func. + * ext.c (make_old_ext_builtin): "New" function. + * interpret.h: Special case Op_old_ext_builtin. Add checks for + Node_old_ext_func. + * msg.c: Adjust placement of a comment. + +2012-05-02 John Haque + + * str_array.c (str_copy): Initialize next pointer in the linked list + to avoid memory corruption. + * int_array.c (int_copy): Ditto. + +2012-04-21 John Haque + + Shutdown routine for a dynamic extension. + + * awk.h (SRCFILE): New field fini_func. + * ext.c (load_ext): Takes an additional argument to look up and + save the clean up routine in SRCFILE struct. + (INIT_FUNC, FINI_FUNC): Defines for default init and fini routine + names. + (do_ext): Use default for the name of the init or fini routine if + one is not supplied. Adjust call to load_ext(). + (close_extensions): Execute fini routines. + * interpret.h (Op_at_exit): Call close_extensions(). + * msg.c (gawk_exit): Ditto. + * debug.c (close_all): Ditto. + * main.c (main): Adjust call to load_ext(). + * awkgram.y (tokentab): Specify 2nd and 3rd optional arguments + for the extension() built-in. + + Unrelated: + + * interpret.h (Op_arrayfor_init): Use assoc_length for array size. + +2012-04-19 John Haque + + Enhanced array interface to support transparent implementation + using external storage and ... + + * awk.h (astore): Optional post-assignment store routine for + array subscripts. + (Op_subscript_assign): New opcode to support the store routine. + (alength): New array interface routine for array length. + (assoc_length): New macro. + (assoc_empty): Renamed from array_empty. + * awkgram.y (snode): Append Op_subscript_assign opcode if + (g)sub variable is an array element. + (mk_getline): Same for getline variable. + (mk_assignment): Same if assigning to an array element. + * field.c (set_element): Call store routine if needed. + * builtin.c (do_match): Ditto. + (do_length): Use length routine for array size. + * symbol.c (print_vars): Ditto. + * array.c (null_length): Default function for array length interface. + (asort_actual): Call store routine if defined. + (asort_actual, assoc_list): Use length routine for array size. + (null_array_func): Add length and store routine entries. + * str_array.c (str_array_func): Same. + * cint_array.c (cint_array_func): Same. + * int_array.c (int_array_func): Same. + * eval.c (optypetab): Add Op_subscript_assign. + * profile.c (pprint): Add case Op_subscript_assign. + * interpret.h (set_array, set_idx): New variables to keep track + of an array element with store routine. + (Op_sub_array, Op_subscript_lhs, Op_store_sub, Op_subscript_assign): + Add code to handle array store routine. + * debug.c (print_symbol, print_array, cmp_val, watchpoint_triggered, + initialize_watch_item): Use length routine for array size. + + * awk.h (assoc_kind_t): New typedef for enum assoc_list_flags. + (sort_context_t): Renamed from SORT_CONTEXT. + * array.c (asort_actual, assoc_sort): Adjust. + * cint_array.c (cint_list, tree_list, leaf_list): Adjust. + * int_array.c (int_list): Adjust. + * str_array.c (str_list): Adjust. + +2012-04-18 John Haque + + * awk.h (atypeof, AFUNC): New macros. + (afunc_t): Renamed typedef from array_ptr. + * array.c (register_array_func, null_lookup): Use AFUNC macro + instead of hard-coded index for array functions. + (asort_actual): Unref null array elements before overwriting. + (force_array): Renamed from get_array. + (null_array): Renamed from init_array. Also initialize flags to 0. + (array_types): Renamed from atypes. + (num_array_types): Renamed from num_atypes. + * interpret.h (r_interpret): In case Op_sub_array, unref null array element. + * str_array.c (str_array_init): Reworked for (re)initialization of array. + * int_array.c (int_array_init): Ditto. + * cint_array.c (cint_array_init): Ditto. + +2012-11-24 Arnold D. Robbins + + Directory cleanup. + + * TODO.xgawk, FUTURES: Merged into TODO. + * TODO: More stuff added. + * Makefile.am (EXTRA_DIST): Updated. + +2012-11-22 Arnold D. Robbins + + Cleanup of awk.h. + + * array.c (r_in_array): Removed. + * awk.h (MALLOC_ARG_T): Replaced with size_t everywhere. + (S_ISREG, setsid): Moved to io.c. + (__extension__): Removed. + (INT32_BIT): Moved to cint_array.c. + (_t): Always declare. + (DO_LINT_INVALID, et al): Moved into an enum. + (POP_ARRAY, POP_PARAM, POP_SCALAR, TOP_SCALAR, dupnode, in_array): + Moved into inline functions. + (force_number, force_string): Simplified. + (ZOS_USS): Remove undef of DYNAMIC, it's handled in configure.ac. + * io.c (S_ISREG, setsid): Moved to here. + * cint_array.c (INT32_BIT): Moved to here. + * eval.c (_t): Always define. + * protos.h: Use size_t directly instead of MALLOC_ARG_T. + + Unrelated: + + * gawkapi.h: Add `awk_' prefix to structure tags where they + were missing. Document the full list of include files needed. + +2012-11-14 Arnold D. Robbins + + * io.c (do_find_source): On VMS, don't add the `/' separator. + Thanks to Anders Wallin. + + MPFR minor cleanup: + + * awk.h (mpfr_unset): Declare new function. + * mpfr.c (mpfr_unset): New function. + * node.c (r_unref): Call it instead of inline code. + * gawk_api.c (api_sym_update_scalar): Call it instead of inline code. + +2012-11-13 Arnold D. Robbins + + * symbol.c (get_symbols): Check type, not vname. Keeps + valgrind happy. Thanks to Andrew Schorr for noticing the problem. + +2012-11-10 Arnold D. Robbins + + * Update to bison 2.6.5. Various files regenerated. + * io.c (find_source): Add a default value for SHLIBEXT. + (read_with_timeout): For VMS also, just use read(). + +2012-11-10 John Haque + + * int_array.c (int_copy): Initialize next pointer of newchain to null. + * eval.c (eval_condition): Force string context for an integer used + as array index. + +2012-11-10 Arnold D. Robbins + + * gawkapi.c (api_add_ext_func, api_awk_atexit, api_clear_array, + api_create_array, api_create_value, api_register_ext_version, + api_release_value, api_update_ERRNO_string, node_to_awk_value, + remove_element, run_ext_exit_handlers): Add null pointer checks. + Everywhere: Add / fixup leading comments. + + * interpret.h (Op_store_sub): If assigning to an uninitialized variable + through SYMTAB, change it to Node_var. Add explanatory comments. + * symbol.c (get_symbol): Rationalized. Skip non-variables in SYMTAB. + +2012-11-04 Arnold D. Robbins + + * gawkapi.h: Minor documentation edit. + +2012-10-31 Arnold D. Robbins + + * awkgram.y (want_regexp): Use as a bool, not as an int. + * field.c: Fix a comment. + * gawkapi.h: Add comment to include . + * symbol.c (load_symbols): ``No automatic aggregate initialization.'' + Here too. Sigh again. + + * gawkapi.h: Minor documentation edits. + +2012-11-27 Arnold D. Robbins + + * builtin.c (do_fflush): Make fflush() and fflush("") both + flush everything. See the comment in the code. + +2012-10-28 Arnold D. Robbins + + * Update to bison 2.6.4. Various files regenerated. + +2012-10-27 Arnold D. Robbins + + * gawkapi.h: Continuing the minor formatting / doc cleanups. + +2012-10-26 Arnold D. Robbins + + * gawkapi.h: Continuing the minor formatting / doc cleanups. + +2012-10-24 Arnold D. Robbins + + * gawkapi.h: Still more minor formatting / doc cleanups. + +2012-10-23 Arnold D. Robbins + + * gawkapi.h: More minor formatting / doc cleanups. + +2012-10-21 Arnold D. Robbins + + Fixes for z/OS from Dave Pitts. + + * awk.h (assoc_list_flags): No trailing comma on last enum value. + * gawkapi.h (awk_valtype_t): Ditto. + * symbol.c (lookup): ``No automatic aggregate initialization.'' Sigh. + + Unrelated: + + * gawkapi.h: Minor formatting / doc cleanups. + +2012-10-19 Arnold D. Robbins + + If SYMTAB is used, make sure ENVIRON and PROCINFO get loaded too. + + * awkgram.y (process_deferred): New function. Call it when program + is completely parsed. + (symtab_used): New variable. + (variable): Set it to true if SYMTAB is looked up. + * main.c (load_environ, load_procinfo): Make sure the routines are + only called once. + + Unrelated fixes: + + * awkgram.y (yylex): Check continue_allowed and break_allowed as + soon as they are seen in the scanner; the rules that check them + can not be reduced until after a token that allows them is seen, + leading to errors at execution time. + * interpret.h (Op_K_break, Op_K_continue, Op_jmp): Add assertion + that pc->target_jmp is not NULL. + + * symbol.c (lookup): Correct a comment. + +2012-10-14 Arnold D. Robbins + + * gawkapi.h (IOBUF_PUBLIC): Renamed awk_input_buf_t. + (struct iobuf_public): Renamed struct awk_input. + * awk.h: Adjust. + +2012-10-13 Arnold D. Robbins + + * Update to Automake 1.12.4. Various files regenerated. + +2012-10-11 Arnold D. Robbins + + * awk.h (dup_ent): New member for Node_param_list. + * symbol.c (install): For parameters, if this is a duplicate, chain + it off the original using the dup_ent pointer. + (remove_params): If there's a duplicate, remove it from the list. + + * awk.h: Fix flags to have unique numeric values. Oops. + +2012-10-10 Arnold D. Robbins + + * gawkapi.h: Add considerably more documentation. Rearrange order + of functions in the struct to make more sense, grouping related + functions together in a more logical order. + * gawkapi.c: Adjust as needed. + * ext.c (make_builtin): Adjust for name change in struct member. + +2012-10-05 Arnold D. Robbins + + * mbsupport.h: Add a bunch of undefs for z/OS. + +2012-10-04 Arnold D. Robbins + + * TODO.xgawk: Update. + * awk.h (make_str_node): Removed macro. + (make_string): Modified to call make_str_node. + (r_make_str_node): Renamed to make_str_node. + * gawkapi.c: Changed r_make_str_node to make_str_node everywhere. + * node.c (make_str_node): Renamed from make_str_node. + + Update to automake 1.12.4. + + * Makefile.in, aclocal.m4, awklib/Makefile.in, doc/Makefile.in, + extension/Makefile.in, extension/aclocal.m4, test/Makefile.in: + Regenerated. + + * interpret.h (Op_Subscript): Added lint warnings for FUNCTAB + and SYMTAB. + +2012-10-02 Arnold D. Robbins + + * awk.h (func_table): Declare. + * awkgram.y: If do_posix or do_traditional, then check for + delete on SYMTAB. Add check for delete on FUNCTAB, also. + * interpret.h (Op_Subscript): For FUNCTAB, return the element name + as its value too. Avoids lots of weirdness and allows indirect calls + after assignment from FUNCTAB["foo"] to work. + (Op_store_sub): Disallow assignment to elements of FUNCTAB. + (Op_indirect_func_all): Turn assert into check and fatal error. + * symbol.c (func_table): No longer static. + (lookup): If do_posix or do_traditional, skip the global table. + (release_all_vars): Clear func_table too. + +2012-09-25 Arnold D. Robbins + + First cut at SYMTAB and FUNCTAB. This does the following: + - Change symbol table handling to use gawk arrays. + - Store symbols in SYMTAB array and allow indirect access + through SYMTAB to variables, both getting and setting. + - List function names in FUNCTAB indexes; Values cannot be + used at the moment. + - No documentation yet. + + * awk.h (Node_hashnode, hnext, hname, hlength, hcode, hvalue): + Removed, not needed any more. + (init_symbol_table, symbol_table): Add declarations. + * awkgram.y: Disallow delete on SYMTAB, fix warning for tawk + extension if traditional. + * eval.c (nodetypes): Remove Node_hashnode element. + * interpret.h (Op_subscript, Op_store_sub): Handle SYMTAB and go + through to the actual value. + * main.c (main): Init Nnull_string earlier. Add call to + init_symbol_table(). + * profile.c (pp_str, pp_len): Change definitions. + (pp_next): New macro. + (pp_push, pp_pop): Adjust uses. + * symbol.c (variables): Removed. + (global_table, param_table, func_table, symbol_table, + installing_specials): New variables. + (lookup, make_params, install_params, remove_params, remove_symbol, + make_symbol, install, get_symbols, release_all_vars, append_symbol, + release_symbols, load_symbols): Rework logic considerably. + (init_symbol_table): New function. + +2012-09-23 Arnold D. Robbins + + `delete array' and `nextfile' are now in POSIX. + Thanks to Nathan Weeks for the + initiative and letting us know about it. + + * awkgram.y: Make the right code changes for `delete array' + and `nextfile'. + (tokentab): Set flags to zero for nextfile. + +2012-09-19 Arnold D. Robbins + + * symbol.c (load_symbols): Zero out the new node. Prevents assertion + failure on PPC Mac OS X. + +2012-09-14 Arnold D. Robbins + + Allow read-only access to built-in variables from extensions. + + * awk.h (NO_EXT_SET): New flag. + * gawkapi.c (api_sym_lookup, api_sym_update_real): Set flag if off + limits variable instead of failing. Adjust logic. + (api_sym_update_scalar, api_set_array_element, api_del_array_element, + api_release_flattened_array): Adjust logic. + * gawkapi.h: Adjust documentation. + + Provide PROCINFO["identifiers"]. Undocumented for now. + + * awk.h (load_symbols): Add declaration. + * awkgram.y (variable): Adjust comment formatting. + * main.c (main): Call load_symbols(). + * symbol.c (load_symbols): New function. + +2012-09-13 Arnold D. Robbins + + * configure.ac: Determination of DYNAMIC adjusted. Hopefully is + smarter for z/OS. + +2012-09-13 Dave Pitts + + * awk.h: Add defines for z/OS for newer types. + +2012-08-31 Arnold D. Robbins + + * gawkapi.c: Wrap various bits in #ifdef DYNAMIC so that + gawk will compile on systems without dynamic loading. + +2012-08-24 Arnold D. Robbins + + Add version facility to API. Thanks to Manuel Collado + for the idea. + + * awk.h (print_ext_versions): Declare. + Rearrange includes and decls to make more sense. + * gawkapi.h (register_ext_version): New API. + (dl_load_func): Add code for ext_version. + * gawkapi.c (api_register_ext_version, print_ext_versions): + New functions. + * main.c (do_version): New variable. + (optab): Set it for -v / --version. + (main): Set it in arg parsing switch. Call version() after the + extensions have been loaded. + +2012-08-22 Arnold D. Robbins + + Add output wrapper and two-way processor to extension API. + + * awk.h (struct redirect): Replace output FILE * with awk_output_buf_t. + (register_output_wrapper, register_two_way_processor): Declare. + * builtin.c (efwrite): Adjust logic to use rp->output data and + functions if rp is not NULL. Remove redundant declaration of function. + (do_fflush, do_printf, do_print, do_print_rec): Same adjustment. + * ext.c (make_builtin): Adjust error messages. + * gawkapi.c (api_register_output_wrapper, + api_register_two_way_processor): New functions. + (sym_update_real): Adjust code formatting. + * gawkapi.h (awk_input_parser_t): Make next pointer awk_const. + (awk_output_buf_t, awk_two_way_processor_t): New structs. + (api_register_output_wrapper, api_register_two_way_processor): New APIs. + (dl_load_func): Allow for empty function table (NULL elements). + * io.c (find_output_wrapper, init_output_wrapper, find_two_processor, + gawk_fwrite, gawk_ferror, gawk_fflush, gawk_fclose): New functions. + (redirect): Call init_output_wrapper, find_output_wrapper as needed. + Adjust use of rp->fp to rp->output.fp and also function calls. + (close_rp, close_redir, flush_io): Same adjustment. + (two_way_open): Same adjustment. Call find_two_way_processor, and + find_output_wrapper, as needed. + +2012-08-17 Arnold D. Robbins + + * Update infrastructure: Automake 1.12.3 and bison 2.6.2. + +2012-08-15 Arnold D. Robbins + + * dfa.c: Sync w/GNU grep. + +2012-08-12 Arnold D. Robbins + + * gawkapi.h: Make the versions enum constants instead of defines. + +2012-08-11 Andrew J. Schorr + + * awkgram.y (add_srcfile): It is now a fatal error to load the + same file with -f and -i (or @include). + * TODO.xgawk: Update to reflect this change. + +2012-08-10 Arnold D. Robbins + + * FUTURES, TODO.xgawk: Updates. + +2012-08-08 Arnold D. Robbins + + * configure.ac: Add -DNDEBUG to remove asserts if not developing. + + * gawkapi.h: Document how to build up arrays. + * gawkapi.c (api_sym_update): For an array, pass the new cookie + back out to the extension. + + * awk.h (IOBUF): Move struct stat into IOBUF_PUBLIC. + (os_isreadable): Change to take an IOBUF_PUBLIC. + * gawkapi.h (IOBUF_PUBLIC): Received struct stat. + (INVALID_HANDLE): Moves to here. + * io.c (iop_alloc): Stat the fd and fill in stat buf. + (iop_finish): Use passed in stat info. + +2012-08-05 Arnold D. Robbins + + * README.git: More stuff added. + +2012-08-01 Arnold D. Robbins + + * io.c (iop_finish): New function. + (iop_alloc): Add errno_val parameter. Move code into iop_finish. + Add large explanatory leading comment. + (after_beginfile): Rework logic. Check for input parser first, then + check for invalid iop. + (nextfile): Organize code better. Call iop_alloc then iop_finish. + (redirect): Call iop_alloc, find_input_parser, iop_finish. + (two_way_open): Call iop_alloc, find_input_parser, iop_finish. + (gawk_popen): Call iop_alloc, find_input_parser, iop_finish. + (find_input_parser): Set iop->valid if input parser takes control. + (get_a_record): Rework setting RT to use macros. + +2012-07-29 Andrew J. Schorr + + * awk.h (set_RT_to_null, set_RT): Removed. + * gawkapi.h (api_set_RT): Removed. + (get_record): Signature changed in input parser struct. + * gawkapi.c (api_set_RT): Removed. + * io.c (set_RT_to_null, set_RT): Removed. + (get_a_record): Adjustments for new API for input parser. + +2012-07-29 Arnold D. Robbins + + * awk.h (os_isreadable): Adjust declaration. + (struct iobuf): Add new member `valid'. + * io.c (iop_alloc): Remove do_input_parsers parameter, it's + always true. Adjust logic to set things to invalid if could not + find an input parser. + (after_beginfile): Use valid member to check if iobuf is valid. + Don't clear iop->errcode. + (nextfile): Adjust logic to clear errcode if valid is true and + also to update ERRNO. + (redirect): Check iop->valid and cleanup as necessary, including + setting ERRNO. + (two_way_open): Ditto. + (gawk_popen): Ditto. + (devopen): Remove check for directory. + +2012-07-27 Andrew J. Schorr + + * io.c (find_input_parser): Issue a warning if take_control_of fails. + +2012-07-27 Arnold D. Robbins + + * awk.h (set_RT): Change to take a NODE * parameter. + * io.c (set_RT): Change to take a NODE * parameter. + * gawkapi.h: Change open hook to input parser in comment. + * gawkapi.c (api_set_RT): Adjust call to set_RT. + +2012-07-26 Arnold D. Robbins + + * awk.h (set_RT_to_null, set_RT): Declare functions. + (os_isreadable): Declare function. + * io.c (set_RT_to_null, set_RT): New functions. + (iop_close): Init ret to zero. + * gawkapi.c (api_register_input_parser): Check for null pointer. + (api_set_RT): New function. + * gawkapi.h (api_set_RT): New function. + +2012-07-26 Andrew J. Schorr + + * gawkapi.h (IOBUF_PUBLIC): Document the get_record and close_func + API. + (awk_input_parser_t) Change can_take_file argument to const, and + document the API. + * io.c (get_a_record): Document that the caller initializes *errcode + to 0, and remote the test for non-NULL errcode. + +2012-07-26 Andrew J. Schorr + + * gawkapi.c (api_sym_update_scalar): Fix some minor bugs. Was + not updating AWK_NUMBER when valref != 1. And strings were not + freeing MPFR values. + +2012-07-25 Arnold D. Robbins + + Start refactoring of IOBUF handling and turn "open hooks" + into "input parsers". + + * awk.h (IOP_NOFREE_OBJ): Flag removed. + (register_input_parser): Renamed from register_open_hook. + * ext.c (load_ext): Make sure lib_name is not NULL. + * gawk_api.c (api_register_input_parser): Renamed from + api_register_open_hook. + * gawk_api.h (api_register_input_parser): Renamed from + api_register_open_hook. Rework structure to have "do you want it" + and "take control of it" functions. + * io.c (iop_alloc): Remove third argument which is IOBUF pointer. + Always malloc it. Remove use of IOP_NOFREE_OBJ everywhere. + (find_input_parser): Renamed from find_open_hook. + (nextfile): Don't use static IOBUF. + (iop_close): Call close_func first. Then close fd or remap it + if it's still not INVALID_HANDLE. + (register_input_parser): Renamed from register_open_hook. + Use a FIFO list and check if more than one parser will accept the + file. If so, fatal error. + +2012-07-25 Andrew J. Schorr + + * configure.ac: Instead of using acl_shlibext for the shared library + extension, define our own variable GAWKLIBEXT with a hack to work + correctly on Mac OS X. + * Makefile.am (SHLIBEXT): Use the value of GAWKLIBEXT instead of + acl_shlibext. + +2012-07-24 Arnold D. Robbins + + * configure.ac: Add crude but small hack to make plug-ins work + on Mac OS X. + +2012-07-20 Arnold D. Robbins + + * gawkapi.h: Rework table to not take up so much space. + * gawkapi.c (api_sym_update_scalar): Rework optimization code + to clean up the function. + +2012-07-17 Andrew J. Schorr + + * gawkapi.h: Add comments explaining new api_create_value and + api_release_value functions. + * gawkapi.c (sym_update_real): Allow updates with AWK_SCALAR and + AWK_VALUE_COOKIE types. After creating a regular variable, + remove the call to unref(node->var_value), since this is not + done elsewhere in the code (see, for example, main.c:init_vars). + If the update is for an existing variable, allow any val_type + except AWK_ARRAY (was previously disallowing AWK_SCALAR and + AWK_VALUE_COOKIE for no apparent reason). + (api_sym_update_scalar): The switch should return false for an + invalid val_type value, so change the AWK_ARRAY case to default. + (valid_subscript_type): Any scalar value is good, so accept any valid + type except AWK_ARRAY. + (api_create_value): Accept only AWK_NUMBER and AWK_STRING values. + Anything else should fail. + +2012-07-17 Arnold D. Robbins + + Speedup: + + * awk.h (r_free_wstr): Renamed from free_wstr. + (free_wstr): Macro to test the WSTRCUR flag first. + * node.c (r_free_wstr): Renamed from free_wstr. + + Support value cookies: + + * gawkapi.h (awk_val_type_t): Add AWK_VALUE_COOKIE. + (awk_value_cookie_t): New type. + (awk_value_t): Support AWK_VALUE_COOKIE. + (api_create_value, api_release_value): New function pointers. + * gawkapi.c (awk_value_to_node, api_sym_update_scalar, + valid_subscript_type): Handle AWK_VALUE_COOKIE. + (api_create_value, api_release_value): New functions. + +2012-07-16 Arnold D. Robbins + + * gawkapi.c (awk_value_to_node): Support AWK_SCALAR. + (api_sym_update_scalar): Performance improvements. + +2012-07-12 Arnold D. Robbins + + Allow creation of constants. Thanks to John Haque for the + implementation concept. + + * gawk_api.h (api_sym_constant): Create a constant. + * gawk_api.h (api_sym_update_real): Renamed from api_sym_update. + Add is_const parameter and do the right thing if true. + (api_sym_update, api_sym_constant): Call api_sym_update_real + in the correct way. + (set_constant): New function. + +2012-07-11 Andrew J. Schorr + + * gawkapi.h: Fix typo in comment. + (awk_value_t): Type for scalar_cookie should be awk_scalar_t, + not awk_array_t. + (gawk_api): Add new api_sym_lookup_scalar function. + (sym_lookup_scalar): New wrapper macro for api_sym_lookup_scalar hook. + * gawkapi.c (api_sym_lookup_scalar): New function for faster scalar + lookup. + (api_impl): Add entry for api_sym_lookup_scalar. + +2012-07-11 Andrew J. Schorr + + * gawkapi.c (awk_value_to_node): Change to a switch statement + so AWK_SCALAR or other invalid type is handled properly. + (valid_subscript_type): Test whether a value type is acceptable + for use as an array subscript (any scalar value will do). + (api_get_array_element, api_set_array_element, api_del_array_element): + Use new valid_subscript_type instead of restricting to string values. + +2012-07-11 Arnold D. Robbins + + Lots of API work. + + * gawkapi.h: Function pointer members renamed api_XXX and + macros adjusted. More documentation. + (awk_valtype_t): New AWK_SCALAR enum for scalar cookies. + (awk_scalar_t): New type. + (awk_value_t): New member scalar_cookie. + (api_sym_update_scalar): New API function. + (erealloc): New macro. + (make_const_string): New macro, renamed from dup_string. + (make_malloced_string): New macro, renamed from make_string. + (make_null_string): New inline function. + (dl_load_func): Add call to init routine through pointer if + not NULL. + + * gawkapi.c (awk_value_to_node): Assume that string values came + from malloc. + (node_to_awk_value): Handle AWK_SCALAR. + (api_sym_update): Ditto. + (api_sym_update_scalar): New routine. + (api_get_array_element): Return false if the element doesn't exist. + Always unref the subscript. + (remove_element): New helper routine. + (api_del_array_element): Use it. + (api_release_flattened_array): Ditto. + (api_impl): Add the new routine. + +2012-07-11 Andrew J. Schorr + + * gawkapi.c (api_sym_update): Allow val_type to be AWK_UNDEFINED + for setting a variable to "", i.e. dupnode(Nnull_string). + +2012-07-10 Andrew J. Schorr + + * awkgram.y (add_srcfile): Lint warning message for a previously loaded + shared library should say "already loaded shared library" instead + of "already included source file". + +2012-07-08 Arnold D. Robbins + + * gawkapi.h (set_array_element): Use index + value instead + of element structure. Matches get_array_element. + (set_array_element_by_elem): New macro to use an element. + * gawkapi.c (api_set_array_element): Make the necessary adjustments. + +2012-07-04 Arnold D. Robbins + + * awkgram.y (tokentab): Remove limit on number of arguments + for "and", "or", and "xor". + * builtin.c (do_and, do_or, do_xor): Modify code to perform the + respective operation on any number of arguments. There must be + at least two. + +2012-06-29 Arnold D. Robbins + + * gawkapi.h: Improve the documentation of the return values + per Andrew Schorr. + +2012-06-25 Arnold D. Robbins + + * TODO.xgawk: Updated. + * awk.h (track_ext_func): Declared. + * awkgram.y (enum defref): Add option for extension function. + (struct fdesc): Add member for extension function. + (func_use): Handle extension function, mark as extension and defined. + (track_ext_func): New function. + (check_funcs): Update logic for extension functions. + * ext.c (make_builtin): Call track_ext_func. + +2012-06-24 Andrew J. Schorr + + * TODO.xgawk: Most of IOBUF has been hidden. + * gawkapi.h (IOBUF): Remove declaration (now back in awk.h). + (IOBUF_PUBLIC): Declare new structure defining subset of IOBUF fields + that should be exposed to extensions. + (gawk_api): Update register_open_hook argument from IOBUF to + IOBUF_PUBLIC. + * awk.h (IOBUF): Restore declaration with 5 fields moved to new + IOBUF_PUBLIC structure. + (register_open_hook): Update open_func argument from IOBUF to + IOBUF_PUBLIC. + * gawkapi.c (api_register_open_hook): Ditto. + * io.c (after_beginfile, nextfile, iop_close, gawk_pclose): Some fields + such as fd and name are now inside the IOBUF public structure. + (struct open_hook): Update open_func argument from IOBUF to + (register_open_hook): Ditto. + (find_open_hook): opaque now inside IOBUF_PUBLIC. + (iop_alloc): fd and name now in IOBUF_PUBLIC. + (get_a_record): If the get_record hook returns EOF, set the IOP_AT_EOF + flag. Access fd inside IOBUF_PUBLIC. + (get_read_timeout): File name now inside IOBUF_PUBLIC. + * interpret.h (r_interpret): File name now inside IOBUF_PUBLIC. + * ext.c (load_ext): No need to call return at the end of a void + function. + +2012-06-24 Arnold D. Robbins + + * ext.c (load_ext): Don't return a value from a void function. + * gawkapi.c (api_set_array_element): Set up vname and parent_array. + +2012-06-21 Arnold D. Robbins + + More API and cleanup: + + * awk.h (stopme): Make signature match other built-ins. + * awkgram.y (stopme): Make signature match other built-ins. + (regexp): Minor edit. + * gawkapi.c (api_set_argument): Remove unused variable. + Set parent_array field of array value. + * TODO.xgawk: Update some. + + Remove extension() builtin. + + * awk.h (do_ext): Removed. + (load_ext): Signature changed. + * awkgram.y (tokentab): Remove do_ext. + Change calls to do_ext. + * ext.c (load_ext): Make init function a constant. + * main.c (main): Change calls to do_ext. + +2012-06-20 Arnold D. Robbins + + Restore lost debugging function: + + * awkgram.y (stopme): Restore long lost debugging function. + * awk.h (stopme): Add declaration. + + API work: + + * ext.c (get_argument): Make extern. + * awk.h (get_argument): Declare it. + * gawkapi.c (api_set_argument): Call it. Finish off the logic. + (api_get_argument): Refine logic to use get_argument. + * gawkapi.h (set_argument): New API. + +2012-06-19 Arnold D. Robbins + + Remove code duplication in gawkapi.c from msg.c: + + * awk.h (err): Add `isfatal' first parameter. + * awkgram.y (err): Adjust all calls. + * msg.c (err): Adjust all calls. Move fatal code to here ... + (r_fatal): From here. + * gawkapi.c: Remove code duplication and adjust calls to `err'. + + Handle deleting elements of flattened array: + + * awk.h (get_argument): Remove declaration. + * ext.c (get_argument): Make static. + * gawkapi.h (awk_flat_array_t): Make opaque fields const. Add + more descriptive comments. + * gawkapi.c (release_flattened_array): Delete elements flagged + for deletion. Free the flattened array also. + + Add additional debugging when developing: + + * configure.ac: Add additional debugging flags. + * configure: Regenerated. + +2012-06-18 Arnold D. Robbins + + * gawkapi.h (get_array_element): Restore `wanted' parameter. + (awk_element_t): Use awk_value_t for index. Add awk_flat_array_t. + (flatten_array): Change signature to use awk_flat_array_t; + (release_flattened_array): Change signature to use awk_flat_array_t; + * gawkapi.c (api_sym_update): Handle case where variable exists already. + (api_get_array_element): Restore `wanted' parameter and pass it + on to node_to_awk_value. + (api_set_array_element): Revisse to match changed element type. + (api_flatten_array): Revise signature, implement. + (api_release_flattened_array): Revise signature, implement. + +2012-06-17 Arnold D. Robbins + + API Work: + + * gawkapi.h (get_array_element): Remove `wanted' parameter. + (r_make_string): Comment the need for `api' and `ext_id' parameters. + * gawkapi.c (api_sym_update): Move checks to front. + Initial code for handling arrays. Still needs work. + (api_get_array_element): Implemented. + (api_set_array_element): Additional checking code. + (api_del_array_element): Implemented. + (api_create_array): Implemented. + (init_ext_api): Force do_xxx values to be 1 or 0. + (update_ext_api): Ditto. + +2012-06-12 Arnold D. Robbins + + API Work: + + * gawkapi.h (awk_value_t): Restore union. + (get_curfunc_param): Renamed to get_argument. Return type changed + to awk_bool_t. Semantics better thought out and documented. + (awk_atexit, get_array_element): Return type now void. + (sym_lookup): Return type now void. Argument order rationalized. + * gawkapi.c (node_to_awk_value): Return type is now awk_bool_t. + Semantics now match table in gawkawpi.h. + (api_awk_atexit): Return type now void. + (api_sym_lookup): Return type is now awk_bool_t. Change parameter + order. + (api_get_array_element): Return type is now awk_bool_t. + + Further API implementations and fixes for extension/testext.c: + + * awk.h (final_exit): Add declaration. + * ext.c (load_ext): Change `func' to install_func. + * gawkapi.c: Add casts to void for id param in all functions. + (api_sym_update): Finish implementation. + (api_get_array_element): Start implementation. + (api_set_array_element): Add error checking. + (api_get_element_count): Add error checking, return the right value. + * main.c (main): Call final_exit instead of exit. + (arg_assign): Ditto. + * msg.c (final_exit): New routine to run the exit handlers and exit. + (gawk_exit): Call it. + * profile.c (dump_and_exit): Ditto. + +2012-06-10 Andrew J. Schorr + + * TODO.xgawk: Addition of time extension moved to "done" section. + +2012-06-10 Andrew J. Schorr + + * gawkapi.c (api_update_ERRNO_string): Treat boolean true as a request + for TRANSLATE, and false as DONT_TRANSLATE. + +2012-06-06 Arnold D. Robbins + + * cint_array.c (tree_print, leaf_print): Add additional casts + for printf warnings. + + * awk.h (update_ext_api): Add declaration. + * gawkapi.c (update_ext_api): New function. + * eval.c (set_LINT): Call update_ext_api() at the end. + * gawkapi.h: Document that do_XXX could change on the fly. + + * awk.h (run_ext_exit_handlers): Add declaration. + * msg.c (gawk_exit): Call it. + +2012-06-05 Arnold D. Robbins + + * ext.c (load_ext): Remove use of RTLD_GLOBAL. Not needed in new + scheme. Clean up error messages. + +2012-06-04 Arnold D. Robbins + + * configure.ac: Remove use of -export-dynamic for GCC. + * configure: Regenerated. + +2012-05-30 Arnold D. Robbins + + * main.c (is_off_limits_var): Minor coding style edit. + * gawkapi.c (awk_value_to_node): More cleanup. + (node_to_awk_value): Use `wanted' for decision making. + (api_sym_update): Start implementation. Needs more work. + General: More cleanup, comments. + * gawkapi.h (api_sym_update): Add additional comments. + +2012-05-29 Arnold D. Robbins + + * gawkapi.c (node_to_awk_value): Add third parameter indicating type + of value desired. Based on that, do force_string or force_number + to get the "other" type. + (awk_value_to_node): Clean up the code a bit. + (get_curfunc_param): Move forcing of values into node_to_awk_value. + (api_sym_lookup): Add third parameter indicating type of value wanted. + (api_get_array_element): Ditto. + * gawk_api.h: Additional comments and clarifications. Revise APIs + to take third 'wanted' argument as above. + (awk_value_t): No longer a union so that both values may be accessed. + All macros: Parenthesized the bodies. + * bootstrap.sh: Rationalize a bit. + +2012-05-26 Andrew J. Schorr + + * Makefile.am (include_HEADERS): Add so gawkapi.h will be installed. + (base_sources): Add gawkapi.h so that it is in dist tarball. + * TODO.xgawk: Update. + * main.c (is_off_limits_var): Stop returning true for everything + except PROCINFO. + +2012-05-25 Arnold D. Robbins + + * main.c (is_off_limits_var): New function to check if a variable + is one that an extension function may not change. + * awk.h (is_off_limits_var): Declare it. + * gawkapi.c (api_sym_lookup): Use it. + + * bootstrap.sh: Touch various files in the extension directory also. + +2012-05-24 Andrew J. Schorr + + * gawkapi.h (awk_param_type_t): Remove (use awk_valtype_t instead). + (awk_ext_func_t): Pass a result argument, and return an awk_value_t *. + (gawk_api.get_curfunc_param): Add a result argument. + (gawk_api.set_return_value): Remove obsolete function. + (gawk_api.sym_lookup, gawk_api.get_array_element): Add a result + argument. + (gawk_api.api_make_string, gawk_api.api_make_number): Remove hooks, + since access to gawk internal state is not required to do this. + (set_return_value): Remove obsolete macro. + (get_curfunc_param, sym_lookup, get_array_element): Add result argument. + (r_make_string, make_number): New static inline functions. + (make_string, dup_string): Revise macro definitions. + (dl_load_func): Remove global_api_p and global_ext_id args, + and fix SEGV by setting api prior to checking its version members. + (GAWK): Expand ifdef to include more stuff. + * gawkapi.c (node_to_awk_value): Add result argument. + (api_get_curfunc_param): Add result argument, and use awk_valtype_t. + (api_set_return_value): Remove obsolete function. + (awk_value_to_node): New global function to convert back into internal + format. + (api_add_ext_func): Simply call make_builtin. + (node_to_awk_value): Add result argument, and handle Node_val case. + (api_sym_lookup, api_get_array_element): Add result argument. + (api_set_array_element): Implement. + (api_make_string, api_make_number): Remove functions that belong on + client side. + (api_impl): Remove 3 obsolete entries. + * TODO.xgawk: Update to reflect progress. + * Makefile.am (base_sources): Add gawkapi.c. + * awk.h: Include gawkapi.h earlier. + (api_impl, init_ext_api, awk_value_to_node): Add declarations + so we can hook in new API. + (INSTRUCTION): Add new union type efptr for external functions. + (extfunc): New define for d.efptr. + (load_ext): Remove 3rd obj argument that was never used for anything. + (make_builtin): Change signature for new API. + * awkgram.y (load_library): Change 2nd argument to load_ext + from dlload to dl_load, and remove pointless 3rd argument. + * main.c (main): Call init_ext_api() before loading shared libraries. + Change 2nd argument to load_ext from dlload to dl_load, and remove + pointless 3rd argument. + * ext.c (do_ext): Remove pointless 3rd argument to load_ext. + (load_ext): Remove 3rd argument. Port to new API (change initialization + function signature). If initialization function fails, issue a warning + and return -1, else return 0. + (make_builtin): Port to new API. + * interpret.h (r_interpret): For Op_ext_builtin, call external functions + with an awk_value_t result buffer, and convert the returned value + to a NODE *. For Node_ext_func, code now in extfunc instead of builtin. + +2012-05-21 Andrew J. Schorr + + * configure.ac: Remove libtool, and call configure in the + extension subdirectory. Change pkgextensiondir to remove the + version number, since the new API has builtin version checks. + * TODO.xgawk: Update. + * ltmain.sh: Removed, since libtool no longer used here. + +2012-05-19 Andrew J. Schorr + + * TODO.xgawk: Update to reflect progress and new issues. + * main.c (main): Add -i (--include) option. + (usage): Ditto. + * awkgram.y (add_srcfile): Eliminate duplicates only for SRC_INC + and SRC_EXTLIB sources (i.e. -f duplicates should not be removed). + * io.c (find_source): Set DEFAULT_FILETYPE to ".awk" if not defined + elsewhere. + +2012-05-15 Arnold D. Robbins + + * awk.h: Include "gawkapi.h" to get IOBUF. + * gawkapi.h: Considerable updates. + * gawkapi.c: New file. Start at implementing the APIs. + +2012-05-13 Andrew J. Schorr + + * TODO.xgawk: Update to reflect recent discussions and deletion of + extension/xreadlink.[ch]. + +2012-05-11 Arnold D. Robbins + + Sweeping change: Use `bool', `true', and `false' everywhere. + +2012-04-09 Andrew J. Schorr + + * eval.c (unset_ERRNO): Fix memory management bug -- need to use + dupnode with Nnull_string. + +2012-04-08 Andrew J. Schorr + + * Makefile.am (valgrind): Define VALGRIND instead of redefining AWK. + This allows test/Makefile.am to set up the command environment as + desired. + (valgrind-noleak): Ditto, plus set --leak-check=no instead of the + default summary setting. + +2012-04-07 Andrew J. Schorr + + * TODO.xgawk: Update to reflect progress. + +2012-04-01 Andrew J. Schorr + + * TODO.xgawk: Move valgrind-noleak item into "done" section. + * Makefile.am (valgrind-noleak): Add new valgrind rule that omits + the "--leak-check=full" option to help spot more serious problems. + +2012-04-01 Andrew J. Schorr + + * TODO.xgawk: Move ERRNO item into "done" section. + * awk.h (update_ERRNO, update_ERRNO_saved): Remove declarations. + (update_ERRNO_int, enum errno_translate, update_ERRNO_string, + unset_ERRNO): Add new declarations. + * eval.c (update_ERRNO_saved): Renamed to update_ERRNO_int. + (update_ERRNO_string, unset_ERRNO): New functions. + * ext.c (do_ext): Use new update_ERRNO_string function. + * io.c (ERRNO_node): Remove redundant extern declaration (in awk.h). + (after_beginfile, nextfile): Replace update_ERRNO() with + update_ERRNO_int(errno). + (inrec): Replace update_ERRNO_saved with update_ERRNO_int. + (do_close): Use new function update_ERRNO_string. + (close_redir, do_getline_redir, do_getline): Replace update_ERRNO_saved + with update_ERRNO_int. + +2012-03-27 Andrew J. Schorr + + * TODO.xgawk: Update to reflect debate about how to support Cygwin + and other platforms that cannot link shared libraries with unresolved + references. + * awkgram.y (add_srcfile): Minor bug fix: reverse sense of test + added by Arnold in last patch. + * configure.ac: AC_DISABLE_STATIC must come before AC_PROG_LIBTOOL. + +2012-03-26 Arnold D. Robbins + + Some cleanups. + + * awkgram.y (add_srcfile): Use whole messages, better for + translations. + * io.c (init_awkpath): Small style tweak. + * main.c (path_environ): Straighten out initial comment, fix + compiler warning by making `val' const char *. + +2012-03-25 Andrew J. Schorr + + * configure.ac (AC_DISABLE_STATIC): Add this to avoid building useless + static extension libraries. + +2012-03-25 Andrew J. Schorr + + * TODO.xgawk: New file listing completed and pending xgawk enhancements. + +2012-03-24 Andrew J. Schorr + + * io.c (path_info): Fix white space. + (pi_awkpath, pi_awklibpath): Avoid structure initializers. + (do_find_source): Eliminate pointless parentheses. + (find_source): Leave a space after "&". + * main.c (load_environ): Fix typo in comment. + +2012-03-21 Andrew J. Schorr + + * awkgram.y (LEX_LOAD): New token to support @load. + (grammar): Add rules to support @load. + (tokentab): Add "load". + (add_srcfile): Improve error message to distinguish between source files + and shared libraries. + (load_library): New function to load libraries specified with @load. + (yylex): Add support for LEX_LOAD (treated the same way as LEX_INCLUDE). + +2012-03-20 Andrew J. Schorr + + * Makefile.am (EXTRA_DIST): Remove extension. + (SUBDIRS): Add extension so libraries will be built. + (DEFS): Define DEFLIBPATH and SHLIBEXT so we can find shared libraries. + * awk.h (deflibpath): New extern declaration. + * configure.ac: Add support for building shared libraries by adding + AC_PROG_LIBTOOL and AC_SUBST for acl_shlibext and pkgextensiondir. + (AC_CONFIG_FILES): Add extension/Makefile. + * io.c (pi_awkpath, pi_awklibpath): New static structures to contain + path information. + (awkpath, max_pathlen): Remove static variables now inside pi_awkpath. + (init_awkpath): Operate on path_info structure to support both + AWKPATH and AWKLIBPATH. No need for max_path to be static, since + this should be called only once for each environment variable. + (do_find_source): Add a path_info arg to specify which path to search. + Check the try_cwd parameter to decide whether to search the current + directory (not desirable for AWKLIBPATH). + (find_source): Choose appropriate path_info structure based on value + of the is_extlib argument. Set EXTLIB_SUFFIX using SHLIBEXT define + instead of hardcoding ".so". + * main.c (path_environ): New function to add AWKPATH or AWKLIBPATH + to the ENVIRON array. + (load_environ): Call path_environ for AWKPATH and AWKLIBPATH. + +2012-06-19 Arnold D. Robbins + + * main.c (main): Do setlocale to "C" if --characters-as-bytes. + Thanks to "SP" for the bug report. + +2012-05-09 Arnold D. Robbins + + * configure.ac: Added AC_HEADER_STDBOOL + * awk.h, dfa.c, regex.c: Reworked to use results + of test and include missing_d/gawkbool.h. + +2012-05-07 Arnold D. Robbins + + * array.c (prnode): Add casts to void* for %p format. + * debug.c (print_instruction): Ditto. + * builtin.c: Fix %lf format to be %f everywhere. + + Unrelated: + + * replace.c: Don't include "config.h", awk.h gets it for us. + +2012-05-04 Arnold D. Robbins + + * getopt.c [DJGPP]: Change to __DJGPP__. + * mbsupport.h [DJGPP]: Change to __DJGPP__. + + Unrelated: + + * awk.h: Workarounds for _TANDEM_SOURCE. + +2012-05-01 Arnold D. Robbins + + * dfa.c: Sync with GNU grep. RRI code now there, needed additional + change for gawk. + * configure.ac: Add check for stdbool.h. + * regex.c: Add check for if not have stdbool.h, then define the + bool stuff. + +2012-04-27 Arnold D. Robbins + + * dfa.c: Sync with GNU grep. + * xalloc.h (xmemdup): Added, from grep, for dfa.c. Sigh. + +2012-04-27 Arnold D. Robbins + + Update to autoconf 2.69, automake 1.12. + + * INSTALL, aclocal.m4, configh.in, depcomp, install-sh, missing, + mkinstalldirs, ylwrap: Updated. + * configure.ac (AC_TYPE_LONG_LONG_INT, AC_TYPE_UNSIGNED_LONG_LONG_INT, + AC_TYPE_INTMAX_T, AC_TYPE_UINTMAX_T): Renamed from gl_* versions. + * configure: Regenerated. + +2012-04-24 Arnold D. Robbins + + * cmd.h (dPrompt, commands_Prompt, eval_Prompt, dgawk_Prompt): Changed + to dbg_prompt, commands_prompt, eval_prompt, dgawk_prompt. + * debug.c: Ditto. + * command.y: Ditto. Some minor whitespace and comments cleanup. + +2012-04-24 Arnold D. Robbins + + io.c cleanup and some speedup for RS as regexp parsing. + + * awk.h (Regexp): New members has_meta and maybe_long. + (enum redirval): Add redirect_none as value 0. + (remaybelong): Remove function declaration. + * awkgram.y: Use redirect_none instead of 0 for no redirect cases. + * io.c (go_getline_redir): Second arg now of type enum redirval. + Changed intovar into into_variable. + (comments and whitespace): Lots of general cleanup. + (socket_open): readle changed to read_len. + (two_way_open): Add additional calls to os_close_on_exec. + (rsrescan): Simplify code a bit and use RS->maybe_long. + * re.c (make_regexp): Set up new members in Regexp struct. + (remaybelong): Remove function. + (reisstring): Simplified code. + +2012-04-16 Eli Zaretskii + + * io.c (read_with_timeout) [__MINGW32__]: Just call the blocking + 'read', as 'select' is only available for sockets. + * mpfr.c (set_ROUNDMODE) [!HAVE_MPFR]: Renamed from set_RNDMODE. + * main.c (load_procinfo): Declare name[] also when HAVE_MPFR is + defined even though HAVE_GETGROUPS etc. are not. + +2012-04-12 John Haque + + * array.c, awk.h, awkgram.y, builtin.c, command.y, debug.c, + field.c, mpfr.c, profile.c: Change RND_MODE to ROUND_MODE. + +2012-04-11 John Haque + + * main.c (varinit): Change RNDMODE to ROUNDMODE. + +2012-04-11 Arnold D. Robbins + + * main.c: Change --arbitrary-precision to --bignum. + +2012-04-02 John Haque + + Add support for arbitrary-precision arithmetic. + + * mpfr.c: New file. + * awk.h (struct exp_node): Add union to handle different number types. + (MPFN, MPZN): New flag values. + (DO_MPFR, do_mpfr): New defines. + (PREC_node, RNDMODE_node): Add declarations. + (PRECISION, RND_MODE, MNR, MFNR, mpzval, do_ieee_fmt): Add declarations. + (make_number, str2number, format_val, cmp_numbers): Ditto. + (force_number): Change definition. + (Func_pre_exec, Func_post_exec): New typedefs. + (POP_NUMBER, TOP_NUMBER): Change definitions. + (get_number_ui, get_number_si, get_number_d, get_number_uj, + iszero, IEEE_FMT, mpg_float, mpg_integer, mpg_float, + mpg_integer): New defines. + * awkgram.y (tokentab): Add alternate function entries for MPFR/GMP. + (snode): Choose the appropriate function. + (negate_num): New function to negate a number. + (grammar): Use it. + (yylex): Adjust number handling code. + * array.c (value_info, asort_actual, sort_user_func): Adjust for + MPFR/GMP numbers. + (do_adump, indent): Minor changes. + (sort_up_index_number, sort_up_value_number, sort_up_value_type): Use + cmp_numbers() for numeric comparisons. + * builtin.c (mpz2mpfr): New function. + (format_tree): Adjust to handle MPFR and GMP numbers. + * eval.c (register_exec_hook): New function to manage interpreter hooks. + (num_exec_hook, pre_execute, post_execute): New and adjusted definitions. + (h_interpret): Renamed from debug_interpret. + (init_interpret): Changed to use the new name. + (flags2str): New entries for MPFN and MPZN. + (cmp_nodes): Reworked to use separate routine for numeric comparisons. + (set_IGNORECASE, set_BINMODE, set_LINT, update_NR, update_FNR, + update_NF): Adjust code and some cleanup. + * field.c (rebuild_record): Field copying code reworked to handle + MPFR/GMP numbers. + (set_NF): Minor adjustment. + * io.c (INCREMENT_REC): New macro. + (inrec, do_getline): Use the new macro. + (nextfile, set_NR, set_FNR, get_read_timeout, pty_vs_pipe): Adjust code + to handle MPFR/GMP numbers. + * interpret.h (r_interpret): Adjust TOP_NUMBER/POP_NUMBER usage. + (EXEC_HOOK): New macro and definition. + (DEBUGGING): Removed. + * main.c (DEFAULT_PREC, DEFAULT_RNDMODE): New defines. + (opttab): New entry for option arbitrary-precision. + (main): Handle the new option. + (usage): Add to usage message. + (varinit): Add PREC and RNDMODE. + (load_procinfo): Install MPFR and GMP related items. + (version): Append MPFR and GMP versions to message. + * msg.c (err) : Adjust FNR handling with MPFR/GMP. + * node.c (r_format_val): Renamed from format_val. + (r_force_number): Return NODE * instead of AWKNUM. + (make_number, str2number, format_val, cmp_numpers: Defined and initialized. + (r_unref): Free MPFR/MPZ numbers. + (get_numbase): Renamed from isnondecimal and return the base. + (cmp_awknums): New function to compare two AWKNUMs. + * command.y (yylex): Adjust number handling code. + (grammar): Minor adjustments to handle negative numbers. + * debug.c (init_debug): New function. + (do_info, do_set_var, watchpoint_triggered, serialize, + initialize_watch_item, do_watch, print_watch_item): Minor adjustments. + (debug_pre_execute): Adjusted to handle MPFR and GMP numbers. + +2012-04-09 Arnold D. Robbins + + * INSTALL, config.guess, config.sub, depcomp, install-sh, + missing, mkinstalldirs, ylwrap: Update to latest from automake 1.11.4. + +2012-04-08 Arnold D. Robbins + + * Update various files to automake 1.11.4. + +2012-03-30 Arnold D. Robbins + + * configure.ac (GAWK_AC_NORETURN): Do as macro instead of inline. + +2012-03-29 Arnold D. Robbins + + * dfa.h, dfa.c: Sync with grep. Major cleanups and some changes + there. + * re.c (research): Pass size_t* to dfaexec to match type change. + * configure.ac (AH_VERBATIM[_Noreturn]): Added from Paul Eggert to + ease compiling. + (AC_INIT): Bump version. + * configure, configh.in, version.c: Regenerated. + +2012-03-28 Arnold D. Robbins + + * 4.0.1: Release tar ball made. + +2012-03-28 Arnold D. Robbins + + * getopt.c: Add DJGPP to list of platforms where it's ok + to include . + * awkgram.y, builtin.c, ext.c, mbsupport.h, re.c: Update + copyright year. + +2012-03-21 Corinna Vinschen + + * getopt.c: Add Cygwin to list of platforms where it's ok + to include . + +2012-03-20 Arnold D. Robbins + + Get new getopt to work on Linux and C90 compilers: + + * getopt.c: Undef ELIDE_CODE for gawk. + (_getopt_internal_r): Init first.needs_free to 0. In test for -W + move executable code to after declarations for C90 compilers. + * getopt1.c: Undef ELIDE_CODE for gawk. + + Minor bug fix with printf, thanks to John Haque: + + * builtin.c (format_tree): Initialize base to zero at the top + of the while loop. + + Getting next tar ball ready: + + * configure.ac: Remove duplicate check for wcscoll. Thanks + to Stepan Kasal. + +2012-03-16 Arnold D. Robbins + + * getopt.c, getopt.h, getopt1.c, getopt_int.h, regcomp.c, + regex.c, regex.h, regex_internal.c, regex_internal.h, + regexec.c: Sync with GLIBC, what the heck. + +2012-03-14 Eli Zaretskii + + * mbsupport.h (btowc): Change for non-DJGPP. + * re.c (dfaerror): Add call to exit for DJGPP. + +2012-03-14 Arnold D. Robbins + + * regex_internal.c (re_string_skip_chars): Fix calculation of + remain_len with m.b. chars. Thanks to Stanislav Brabec + . + +2012-02-28 Arnold D. Robbins + + * main.c (init_groupset): Make `getgroups' failing a non-fatal + error. After all, what's the big deal? Should help on Plan 9. + +2012-02-27 Arnold D. Robbins + + * dfa.c (parse_bracket_exp): Revert changes 2012-02-15 to stay + in sync with grep. + * dfa.h (dfarerror): Add __attribute__ from grep. + +2012-02-15 Arnold D. Robbins + + Fix warnings from GCC 4.6.2 -Wall option. + + * awkgram.y (newline_eof): New function to replace body of + NEWLINE_EOF macro. + (yylex): Replace body of NEWLINE_EOF macro. + * dfa.c (parse_bracket_exp): Init variables to zero. + * ext.c (dummy, junk): Remove. + * regex_internal.c (re_string_reconstruct): Remove buf array. It was + set but not used. + +2012-02-10 Arnold D. Robbins + + * dfa.c: Sync with GNU grep. + +2012-02-07 Arnold D. Robbins + + * main.c (main): Move init of `output_fp' to before parsing of + program so that error messages from msg.c don't dump core. + Thanks to Michael Haardt . + +2012-01-13 Arnold D. Robbins + + * dfa.c [is_valid_unibtye_character]: Fix from GNU grep to + bug reported by me from Scott Deifik for DJGPP. + +2012-01-03 Arnold D. Robbins + + * dfa.c: Sync with GNU grep. + +2012-01-02 Arnold D. Robbins + + * io.c (Read_can_timeout, Read_timeout, Read_default_timeout): + Renamed to use lower case. + Other minor stylistic edits. + +2012-01-01 John Haque + + * awk.h (struct iobuf): New entry read_func. + * io.c (Read_can_timeout, Read_timeout, Read_default_timeout): + New variables. + (init_io): New routine to initialize the variables. + (in_PROCINFO): New "clever" routine to parse elements with indices + separated by a SUPSEP. + (get_read_timeout): New routine to read timeout value for an IOBUF. + (read_with_timeout): New routine to read from a fd with a timeout. + (pty_vs_pipe): Use in_PROCINFO(). + (get_a_record): Set the timeout value and the read routine as necessary. + * main.c (main): Call init_io(). + +2011-12-31 Arnold D. Robbins + + * profile_p.c: Remove the file. + * msg.c (err): Remove check for name being dgawk. + +2011-12-31 Arnold D. Robbins + + * awk.h [STREQ, STREQN]: Remove macros. + * awkgram.y, builtin.c, command.y, debug.c, eval.c, + io.c, msg.c: Change all uses to call strcmp, strncmp. + +2011-12-28 Arnold D. Robbins + + * int_array.c, str_array.c: Fix some compiler warnings 32/64 + bit system differences. + +2011-12-26 John Haque + + Merge gawk, pgawk and dgawk into a single executable gawk. + + * awk.h (DO_PRETTY_PRINT, DO_PROFILE, DO_DEBUG, + do_pretty_print, do_debug): New defines. + (interpret): New variable, a pointer to an interpreter routine. + (enum exe_mode): Nuked. + * main.c (opttab): New options --pretty-print and --debug; + Remove option --command. + (usage): Update usage messages. + * interpret.h: New file. + * eval.c (r_interpret): Move to the new file. + (debug_interpret): New interpreter routine when debugging. + (init_interpret): New routine to initialize interpreter related + variables. + * eval_d.c, eval_p.c: Delete files. + * debug.c (interpret): Renamed to debug_prog. + (DEFAULT_PROMPT, DEFAULT_HISTFILE, DEFAULT_OPTFILE): Remove prefix 'd'. + * profile.c (init_profiling): Nuked. + * Makefile.am: Adjusted. + + Add command line option --load for loading extensions. + + * awk.h (srctype): Add new source type SRC_EXTLIB. + * ext.c(load_ext): New routine to load extension. + (do_ext): Adjust to use load_ext(). + * main.c (opttab): Add new option --load. + (main): Call load_ext() to load extensions. + (usage): Add usage message for the new option. + * io.c (get_cwd): New routine. + (do_find_source): Use the new routine. + (find_source): Handle new type SRC_EXTLIB. + * awkgram.y (parse_program, next_sourcefile): Skip type SRC_EXTLIB. + (add_srcfile): Adjust call to find_source. + * debug.c (source_find): Same. + + Unrelated: + + * ext.c (get_argument): Fixed argument parsing. + * array.c (null_array_func): Reworked array routines for an empty array. + * str_array.c, int_array.c: Make GCC happy, use %u instead of %lu + printf formats. + * eval.c (node_Boolean): New array for TRUE and FALSE nodes. + (init_interpret): Create the new nodes. + (eval_condition): Add test for the new nodes. + (setup_frame): Disable tail-recursion optimization when profiling. + * interpret.h (r_interpret): Use the boolean nodes instead of making + new ones when needed. + +2011-12-26 Arnold D. Robbins + + Finish Rational Range Interpretation (!) + + * dfa.c (match_mb_charset): Compare wide characters directly + instead of using wcscoll(). + * regexec.c (check_node_accept_byte): Ditto. + + Thanks to Paolo Bonzini for pointing these out. + +2011-12-06 John Haque + + * debug.c (source_find): Fix misplaced call to efree. + * profile.c (redir2str): Add a missing comma in the redirtab array. + * eval.c (r_interpret): Disallow call to exit if currule is undefined. + This avoids the possibility of running END blocks more than once when + used in a user-defined sorted-in comparison function. + * array.c (sort_user_func): Adjust appropriately. + +2011-12-06 Arnold D. Robbins + + * awk.h, mbsupport.h: Changes for MBS support on DJGPP + and z/OS. + * io.c: Disable pty support on z/OS. + +2011-11-27 Arnold D. Robbins + + * dfa.c: Sync with GNU grep. + * dfa.h: Add _GL_ATTRIBUTE_PURE macro. Bleah. + +2011-11-14 John Haque + + * debug.c (set_breakpoint_at): Fix problem with setting + breakpoints in a switch statement. Thanks to Giorgio Palandri + for the bug report. + +2011-11-14 Arnold D. Robbins + + * mbsupport.h: Add check for HAVE_BTOWC, per Pat Rankin. + +2011-11-12 Eli Zaretskii + + * mbsupport.h: Additional glop for dfa.c in Windows environment. + +2011-11-01 Arnold D. Robbins + + * dfa.c: Move glop for ! MBS_SUPPORT to ... + * mbsupport.h: ... here. + * replace.c: Include missing_d/wcmisc.c if ! MBS_SUPPORT. + * regex_internal.h: Move include of mbsupport.h up and add + additional checks to avoid inclusion of wctype.h and wchar.h. + +2011-10-27 Arnold D. Robbins + + * builtin.c (do_strftime): Per Pat Rankin, instead of casting + fclock, use a long variable and check for negative or overflow. + +2011-10-25 Arnold D. Robbins + + Merge with gawk_performance branch done. Additionally: + + * cint_array.c, int_array.c, str_array.c: Fix compiler complaints + about printf formats (signed / unsigned vs. %d / %u). + * eval.c (setup_frame): Add a missing return value. + +2011-10-25 Arnold D. Robbins + + * Makefile.am (dist-hook): Use `cd $(srcdir)/pc' so that + `make distcheck' works completely. + * builtin.c (do_strftime): Add cast to long int in check + for fclock < 0 for systems where time_t is unsigned (e.g., VMS). + +2011-10-25 Stefano Lattarini + + dist: generated file `version.c' is not removed by "make distclean" + + * Makefile.am (distcleancheck_listfiles): Define to ignore the + generated `version.c' file. + +2011-10-24 Arnold D. Robbins + + * dfa.c (wcscoll): Create for VMS. + * Makefile.am (dist-hook): Run sed scripts to make pc/config.h. + +2011-10-24 Eli Zaretskii + + * builtin.c [HAVE_POPEN_H]: Include "popen.h". + * README.git: Update for pc/ systems. + +2011-10-21 Arnold D. Robbins + + * Makefile.am (distcleancheck_listfiles): Added, per advice from + Stefano Lattarini . + * dfa.c: Additional faking of mbsupport for systems without it; + mainly VMS. + +2011-10-21 Stefano Lattarini + + * configure.ac (AM_C_PROTOTYPES): Remove call to this macro. + The comments in configure.ac said that the call to AM_C_PROTOTYPES + was needed for dfa.h, synced from GNU grep; but this statement is + not true anymore in grep since commit v2.5.4-24-g9b5e7d4 "replace + AC_CHECK_* with gnulib modules", dating back to 2009-11-26. Also, + the support for automatic de-ANSI-fication has been deprecated in + automake 1.11.2, and will be removed altogether in automake 1.12. + * vms/vms-conf.h (PROTOTYPES, __PROTOTYPES): Remove these #define, + they are not used anymore. + * pc/config.h (PROTOTYPES): Likewise. + +2011-10-18 Dave Pitts + + * dfa.c: Move some decls to the top of their functions for + C90 compilers. + +2011-10-18 Arnold D. Robbins + + * builtin.c (do_strftime): Add check for negative / overflowed + time_t value with fatal error. Thanks to Hermann Peifer + for the bug report. + * dfa.c (setbit_wc): Non-MBS version. Add a return false + since VMS compiler doesn't understand that abort doesn't return. + +2011-10-10 Arnold D. Robbins + + * builtin.c (do_sub): Init textlen to zero to avoid "may be + used uninitialized" warning. Thanks to Corinna Vinschen for + pointing this out. + * eval.c (unwind_stack): Add parentheses around condition in while + to avoid overzealous warning from GCC. + +2011-09-30 Eli Zaretskii + + * io.c (remap_std_file): Fix non-portable code that caused + redirected "print" to fail if a previous read from standard input + returned EOF. Reported by David Millis . + (remap_std_file): Per Eli's suggestion, removed the leading close + of oldfd and will let dup2 do the close for us. + +2011-10-11 John Haque + + * symbol.c: Add licence notice. + * array.c (PREC_NUM, PREC_STR): Define as macros. + +2011-10-09 Arnold D. Robbins + + * dfa.c: Sync with GNU grep. + +2011-10-07 John Haque + + Tail recursion optimization. + * awkgram.y (grammar, mk_function): Recognize tail-recursive + calls. + * awk.h (tail_call, num_tail_calls): New defines. + * eval.c (setup_frame): Reuse function call stack for + tail-recursive calls. + (dump_fcall_stack): Reworked. + +2011-10-04 Arnold D. Robbins + + * awk.h, main.c (gawk_mb_cur_max): Make it a constant 1 when + MBS_SUPPORT isn't available to allow GCC dead code constant + expression computation and dead code elimination to help out. + +2011-10-02 Arnold D. Robbins + + * io.c (rsnullscan, get_a_record): Fix the cases where terminators + are incomplete when RS == "". Also fix the case where the new value + is shorter than the old one. Based on patch from Rogier + as submitted by Jeroen Schot + . + +2011-09-24 Arnold D. Robbins + + * eval.c, io.c, re.c: Fix some spelling errors. Thanks to + Jeroen Schot . + +2011-09-21 Arnold D. Robbins + + * dfa.c, mbsupport.h: Sync with GNU grep. Large amount of changes + that remove many ifdefs, moving many conditions for multibyte + support into regular C code and relying GCC's dead code optimization + to eliminate code that won't be needed. + * dfa.c: For gawk, add a number of additional defines so that things + will compile if MBS_SUPPORT is 0. + * array.c, awk.h, awkgram.y, builtin.c, eval.c, field.c, main.c, + node.c, re.c: Change `#ifdef MBS_SUPPORT' to `#if MBS_SUPPORT'. + * awk.h, regex_internal.h: Move NO_MBSUPPORT handling to ... + * mbsupport.h: ...here. + +2011-09-16 Arnold D. Robbins + + * dfa.c: Sync with GNU grep. + +2011-09-08 John Haque + + Optimization for compound assignment, increment and + decrement operators; Avoid unref and make_number calls + when there is no extra references to the value NODE. + +2011-09-03 Arnold D. Robbins + + * dfa.c: Sync with GNU grep. + +2011-08-31 John Haque + + Grammar related changes: Simplify grammar for user-defined + functions and general cleanups. + + * symbol.c: New file. + * awkgram.y: Move symbol table related routines to the + new file. + (rule, func_name, function_prologue, param_list): Reworked. + (install_function, check_params): Do all error checks + for the function name and parameters before installing in + the symbol table. + (mk_function): Finalize function definition. + (func_install, append_param, dup_params): Nuked. + * symbol.c (make_params): allocate function parameter nodes + for the symbol table. Use the hash node as Node_param_list; + Saves a NODE for each parameter. + (install_params): Install function parameters into the symbol + table. + (remove_params): Remove parameters out of the symbol table. + * awk.h (parmlist, FUNC): Nuked. + (fparms): New define. + + Dynamically loaded function parameters are now handled like + those for a builtin. + + * awk.h (Node_ext_func, Op_ext_builtin): New types. + (Op_ext_func): Nuked. + * ext.c (make_builtin): Simplified. + (get_curfunc_arg_count): Nuked; Use the argument 'nargs' of + the extension function instead. + (get_argument, get_actual_argument): Adjust. + * eval.c (r_interpret): Update case Op_func_call for a dynamic + extension function. Handle the new opcode Op_ext_builtin. + * pprint (profile.c): Adjust. + + Use a single variable to process gawk options. + + * awk.h (do_flags): New variable. + (DO_LINT_INVALID, DO_LINT_ALL, DO_LINT_OLD, DO_TRADITIONAL, + DO_POSIX, DO_INTL, DO_NON_DEC_DATA, DO_INTERVALS, + DO_PROFILING, DO_DUMP_VARS, DO_TIDY_MEM, + DO_SANDBOX): New defines. + (do_traditional, do_posix, do_intervals, do_intl, + do_non_decimal_data, do_profiling, do_dump_vars, + do_tidy_mem, do_sandbox, do_lint, + do_lint_old): Defined as macros. + * main.c: Remove definitions of the do_XX variables. Add + do_flags definition. + * debug.c (execute_code, do_eval, parse_condition): Save + do_flags before executing/parsing and restore afterwards. + + Nuke PERM flag. Always increment/decrement the reference + count for a Node_val. Simplifies macros and avoids + occasional memory leaks, specially in the debugger. + + * awk.h (UPREF, DEREF, dupnode, unref): Simplified. + (mk_number): Nuked. + * (*.c): Increment the reference count of Nnull_string before + assigning as a value. + + Revamped array handling mechanism for more speed and + less memory consumption. + + * awk.h (union bucket_item, BUCKET): New definitions. Used as + bucket elements for the hash table implementations of arrays; + 40% space saving in 32 bit x86. + (buckets, nodes, array_funcs, array_base, array_capacity, + xarray, alookup, aexists, aclear, aremove, alist, + acopy, adump, NUM_AFUNCS): New defines. + (array_empty): New macro to test for an empty array. + (assoc_lookup, in_array): Defined as macros. + (enum assoc_list_flags): New declaration. + (Node_ahash, NUMIND): Nuked. + * eval.c (r_interpret): Adjust cases Op_subscript, + Op_subscript_lhs, Op_store_var and Op_arrayfor_incr. + * node.c (dupnode, unref): Removed code related to Node_ahash. + * str_array.c: New file to handle array with string indices. + * int_array.c: New file to handle array with integer indices. + * cint_array.c: New file. Special handling of arrays with + (mostly) consecutive integer indices. + + Memory pool management reworked to handle NODE and BUCKET. + + * awk.h (struct block_item, BLOCK, block_id): New definitions. + (getblock, freeblock): New macros. + (getbucket, freebucket): New macros to allocate and deallocate + a BUCKET. + (getnode, freenode): Adjusted. + * node.c (more_nodes): Nuked. + (more_blocks): New routine to allocate blocks of memory. + +2011-08-24 Arnold D. Robbins + + Fix pty co-process communication on Ubuntu GNU/Linux. + + * io.c: Add include of to get definition of TIOCSCTTY. + (two_way_open): Move call for this ioctl to after setsid() call. + +2011-08-23 Arnold D. Robbins + + * regex_internal.c (re_string_fetch_byte_case): Remove + __attribute((pure)) since it causes failures with gcc -O2 + -fno-inline. Thanks to Neil Cahill + for reporting the bug. + +2011-08-10 John Haque + + BEGINFILE/ENDFILE related code redone. + + * awk.h (prev_frame_size, has_endfile, target_get_record, + target_newfile): New defines. + * awkgram.y (mk_program): Initialize has_endfile appropriately for + Op_get_record. + (parse_program): Initialize new jump targets for + Op_get_record and Op_newfile. + * eval.c (unwind_stack): Change argument to number of + items to be left in the stack. Adjust code. + (pop_fcall, pop_stack): New defines. + (setup_frame): Initialize prev_frame_size. + (exec_state, EXEC_STATE): New structure and typedef. + (exec_state_stack): New variable. + (push_exec_state, pop_exec_state): New functions to save and + later retrieve an execution state. + (r_interpret): Use the new functions and the defines in + cases Op_K_getline, Op_after_beginfile, Op_after_endfile, + Op_newfile and Op_K_exit. + * io.c (after_beginfile): When skipping a file using nextfile, + return zero in case there was an error opening the file. + (has_endfile): Nuke global variable. + (inrec): Add a second argument to pass errno to the calling + routine. + * debug.c (print_instruction): Update cases. + +2011-08-10 Arnold D. Robbins + + Fix (apparently long-standing) problem with FIELDWIDTHS. + Thanks to Johannes Meixner . + + * field.c (set_FIELDWIDTHS): Adjust calculations. + + Fix problem with FPAT, reported by "T. X. G." + + * awk.h (Regexp): Add new member 'non_empty'. + * field.c (fpat_parse_field): Save/restore local variable non_empty + from member in Regexp struct. + +2011-08-09 Arnold D. Robbins + + Fix pty issue reported by "T. X. G." + + * configure.ac: Check for setsid. + * awk.h: If not HAVE_SETSID define it as an empty macro. + * io.c (two_way_open): Call setsid if using pty's. + +2011-07-29 Eli Zaretskii + + * builtin.c (format_tree): Rename small -> small_flag, + big -> big_flag, bigbig -> bigbig_flag. Solves compilation errors + when building Gawk with libsigsegv on MS-Windows, see + https://lists.gnu.org/archive/html/bug-gawk/2011-07/msg00029.html. + +2011-07-28 Arnold D. Robbins + + * builtin.c (do_sub): Revert to gawk 3.1 behavior for backslash + handling. It was stupid to think I could break compatibility. + Thanks to John Ellson for raising + the issue. + +2011-07-26 John Haque + + * eval.c (r_interpret): In cases Op_var_assign and Op_field_assign, + include Op_K_getline_redir in the test for skipping the routine. + +2011-07-26 John Haque + + Fix handling of assign routines for 'getline var'. + Rework the previous fix for (g)sub. + + * awk.h: New define assign_ctxt for use in Op_var_assign + and Op_field_assign opcodes. Remove define AFTER_ASSIGN. + * awkgram.y (snode, mk_getline): Initialize assign_ctxt. + * builtin.c (do_sub): Adjust to take only the first two + arguments. + * eval.c (r_interpret): In cases Op_var_assign and Op_field_assign, + skip the routine as appropriate. Adjust case Op_sub_builtin. + * main.c (get_spec_varname): New function. + * debug.c (print_instruction): Use the new function to get + special variable name. + +2011-07-17 Arnold D. Robbins + + * main.c (varinit): Mark FPAT as NON_STANDARD. Thanks to + Wolfgang Seeberg for the report. + * Makefile.am (EXTRA_DIST): Add po/README, per advice from + Bruno Haible. + * dfa.c: Sync with GNU grep. + * xalloc.h (xzalloc): New function, from GNU grep, for dfa.c. + * README: Note that bug list is really a real mailing list. + +2011-07-16 Arnold D. Robbins + + * Makefile.am (AUTOMAKE_OPTIONS): Removed. + * configure.ac (AM_INIT_AUTOMAKE): Removed dist-bzip2 option, on + advice from Karl Berry. + +2011-07-15 John Haque + + * awk.h (Op_sub_builtin): New opcode. + (GSUB, GENSUB, AFTER_ASSIGN, LITERAL): New flags for + Op_sub_builtin. + * awkgram.y (struct tokentab): Change opcode to Op_sub_builtin + for sub, gsub and gensub. + (snode): Update processing of sub, gsub and gensub. + * builtin.c (do_sub, do_gsub, do_gensub): Nuke. + (sub_common): Renamed to do_sub. Relocate gensub argument + handling code from do_gensub to here; Simplify the code a + little bit. + * eval.c (r_interpret): Handle Op_sub_builtin. Avoid field + re-splitting or $0 rebuilding if (g)sub target string is + a field and no substitutions were done. + * pprint (profile.c): Add case for the new opcode. + * print_instruction (debug.c): Ditto. + + Take out translation for errno strings; extensions will + need to use their own domain. + + * awk.h (enum errno_translate): Removed. + (update_ERRNO_string): Remove second translate parameter. + * eval.c (update_ERRNO_string): Remove second translate parameter + and code that used it. + * gawkapi.h (api_update_ERRNO_string): Remove third translate + parameter. + * gawkapi.c (api_update_ERRNO_string): Remove third translate + parameter and change call to update_ERRNO_string. + * io.c (do_close): Fix call to update_ERRNO_string. + +2011-07-15 Arnold D. Robbins + + * awk.h: Typo fix: "loner" --> longer. Thanks to Nelson Beebe. + * builtin.c (efwrite): Fix flushing test back to what it was + in 3.1.8. Thanks to Strefil for the problem + report. + * configure.ac: Bump version to 4.0.0a for stable branch. + +2011-06-24 Arnold D. Robbins + + * Makefile.am (EXTRA_DIST): Add ChangeLog.0. + * 4.0.0: Remake the tar ball. + +2011-06-23 Arnold D. Robbins + + * configure.ac: Update version to 4.0.0. + * configure: Regenerated. + * ChangeLog.0: Rotated ChangeLog into this file. + * ChangeLog: Created anew for gawk 4.0.0 and on. + * README: Bump version to 4.0.0. + * 4.0.0: Release tar ball made. diff --git a/ChangeLog.0 b/ChangeLog.0 new file mode 100644 index 0000000..af6bd99 --- /dev/null +++ b/ChangeLog.0 @@ -0,0 +1,9885 @@ +Mon Jun 20 20:33:26 2011 Arnold D. Robbins + + * dfa.c (dfaanalyze): Allocate the right number of leaves to + avoid crashes. Thanks to Jim Meyering. + +Mon Jun 20 20:22:35 2011 Arnold D. Robbins + + * dfa.c (setbit_c, setbit_case_fold_c): Compare btowc result against + WEOF. Thanks to Eli Zaretskii for pointing out the problem. + +Mon Jun 20 20:22:26 2011 Pat Rankin + + * dfa.c (addtok_wc): enclose prototype within #if MBS_SUPPORT. + +Fri Jun 17 11:09:22 2011 Arnold D. Robbins + + * Release 3.1.86: Final beta test tar ball for 4.0. + +Fri Jun 17 10:55:27 2011 Arnold D. Robbins + + Implement Rational Range Interpretation (RRI) directly in code. + + * regex.h [RE_RANGES_IGNORE_LOCALES]: Remove macro and its use. + * dfa.c (parse_bracket_exp): Remove use of RE_RANGES_IGNORE_LOCALES + and just do it in code. + (hard-locale.h): Remove include. + (hard_LC_COLLATE): Remove variable and its uses. + * re.c (resetup): Remove use of RE_RANGES_IGNORE_LOCALES. + * regcomp.c (build_range_exp): Remove use of RE_RANGES_IGNORE_LOCALES + and just do it in code. Remove cmp_buf array; it's no longer needed. + * Makefile.am (base_sources): Remove hard_locale.h and hard_locale.c. + * hard_locale.h, hard_locale.c: Removed from dist. + +Sun Jun 12 23:43:06 2011 Arnold D. Robbins + + * re.c (resetup): Always turn on RE_RANGES_IGNORE_LOCALES. + Add justifying comment with URLs for the relevant portions of + POSIX. Thanks to Paul Eggert for pointing out the happy change + to the rules and supplying the URLs. + +Wed Jun 8 22:41:30 2011 Arnold D. Robbins + + * regcomp.c (build_range_exp): Add check for RE_NO_EMPTY_RANGES + from GNULIB regcomp.c, courtesy of GNU grep. + +Wed Jun 8 22:10:03 2011 Arnold D. Robbins + + * dfa.c: Sync with GNU grep. + +Sun Jun 5 21:49:30 2011 Arnold D. Robbins + + * Release 3.1.85: Fourth beta test tar ball for 4.0. + +Sun Jun 5 21:39:17 2011 Arnold D. Robbins + + * field.c (fpat_parse_field): Bug fix. Thanks to + "Radoulov, Dimitre" for pointing + out the problem. + +Fri Jun 3 10:39:17 2011 Arnold D. Robbins + + * regcomp.c (build_range_exp): Make syntax the first argument, + for compatibility with gnulib version of the file. + +Wed Jun 1 06:29:27 2011 Pat Rankin + + * re.c (check_bracket_exp): Fix typo. + +Tue May 31 23:01:00 2011 John Haque + + * re.c (check_bracket_exp): Use mem* routines instead of str* + for searching. + * main.c (arg_assign): Disallow builtin or user-defined function + as the name of a variable. + * awkgram.y (check_special): Rework so can be called from + arg_assign. + +Tue May 31 22:23:41 2011 Arnold D. Robbins + + In order to attain the goal of having ranges act like they are + always in the C locale, bit the bullet and did the work in + the regex and dfa engines. The pre-processing routine was not + handling too many cases that a full regexp parser would catch. + + * regex.h [RE_RANGES_IGNORE_LOCALES]: New syntax bit. + (RE_SYNTAX_GNU_AWK): Use it. + * dfa.c (parse_bracket_exp): If the RE_RANGES_IGNORE_LOCALES + is set, ignore locales when building a range. + * re.c (expand_range): Remove function and declaration. + (add_char): Remove function and declaration. + (make_regexp): Remove use of expand_range. + (resetup): Add RE_RANGES_IGNORE_LOCALES if --traditional. + * regcomp.c (build_range_exp): Add syntax variable as last argument. + Add code to check for RE_RANGES_IGNORE_LOCALES and do the right thing. + Adjust all calls. + +Sun May 29 22:48:41 2011 Arnold D. Robbins + + * re.c (expand_range): Handle cases where expanded range + includes '\\' (and ']'). Thanks to Juergen Daubert . + Fatal error if end point is below start point ([z-a]), + thanks to John Haque. Don't repeat the last character in + the expansion. Thanks to Arnold Robbins. + +Fri May 27 10:01:17 2011 Arnold D. Robbins + + * Release 3.1.84: Third beta test tar ball for 4.0. + +Thu May 26 22:10:08 2011 Arnold D. Robbins + + * field.c (get_field): Enhance logic for setting NF if we're + using FPAT to parse fields. Can end up with weird cases. Thanks + to Pat Rankin for pointing them out. + +Mon May 23 22:06:13 2011 Arnold D. Robbins + + * awkgram.y: Allow newline after comma in range patterns, + per POSIX. Thanks to discussion in comp.lang.awk. (!!!) + +Mon May 23 22:02:46 2011 John Haque + + * ext.c (get_actual_argument): Change argument type from + Node_var_new to Node_var when used as a scalar. + +Sun May 22 11:56:40 2011 Arnold D. Robbins + + * main.c (varinit): Give FPAT a reasonable default value. + * field (get_field): Adjust test for at end of record to >=; + fpat_parse_field can go beyond when matching null regexps. + Thanks to Pat Rankin. + +Fri May 20 11:00:17 2011 Arnold D. Robbins + + * regex_internal.h (__attribute_warn_unused_result__): Always + ifdef out. Bleah. + +Thu May 19 17:13:18 2011 Arnold D. Robbins + + * Release 3.1.83: Second beta test tar ball for 4.0. + +Thu May 19 16:47:19 2011 Arnold D. Robbins + + * awkgram.y (dump_vars): Fix warning message. Thanks to Pat Rankin. + * main.c (usage): No space allowed after -d and -p. Also thanks + to Pat Rankin. + +Thu May 19 16:34:04 2011 Pat Rankin + + * regex_internal.h (__attribute_warn_unused_result__): Define with + empty expansion for !__GNUC__ configuration. + +Wed May 18 22:13:18 2011 Arnold D. Robbins + + * Release 3.1.82: Beta test tar ball for 4.0, we hope! + +Wed May 18 21:47:54 2011 Arnold D. Robbins + + * io.c (PIPES_SIMULATED): Simplify the case where PIPES_SIMULATED + is true but using temporary files - that code not needed anymore. + * regcomp.c, regex.h, regex_internal.c, regex_internal.h, + regexec.c: Sync with GLIBC. Why not. + +Mon May 16 17:55:25 2011 Arnold D. Robbins + + * awkgram.c: Regenerated using bison 2.5. + +Sat May 14 22:25:50 2011 Arnold D. Robbins + + * io.c (nextfile): Use `in_array' in main loop to see if element + of ARGV exists, instead of using `assoc_lookup'. The latter creates + the element! A day one bug! + * dfa.c (parse_bracket_exp): For z/OS init pattern manually. + +Mon May 9 16:30:49 2011 Arnold D. Robbins + + * array.c (sort_up_value_type): Remove unused variable ret. + (do_delete): Initialize local variables to silence warnings. + Thanks to Michal Jaegermann. + +Mon May 9 15:07:29 2011 Corinna Vinschen + + * awk.h: Remove cygwin code for libsigsegv. + +Sun May 8 20:38:03 2011 John Haque + + * eval.c (r_interpret): In case Op_sub_array, store only the + subarray index as 'vname'. + * array.c (make_aname): Redone for dynamic computation of + a subarray actual 'vname'. + (array_vname): Use make_aname() for (sub)array name. + (asort_actual): Performance optimization for asort(a). + +Sun May 8 20:29:17 2011 Arnold D. Robbins + + * debug.c (print_array): Sort in order of string indices, per + request from John Haque. + * array.c (sort_up_value_number): Use string value to provide + ordering when numeric values are equal. Ensures that tests come + out OK on different systems. + +Sun May 8 20:27:27 2011 Arnold D. Robbins + + * dfa.c: Sync with GNU grep. + * regex.h: Sync with GLIBC in preparation for submitting updates + back. + +Thu May 5 21:22:44 2011 Arnold D. Robbins + + * eval.c (r_interpret): PROCINFO sorting only takes effect + if not do_posix. + +Wed May 4 23:31:14 2011 Arnold D. Robbins + + Move array sorting to using predefined strings, add value sorting + by type of assignment. + + * array.c (sort_up_value_type, sort_down_value_type): New routines. + (asort_actual): Pass string value to assoc_list, not NODE *. + Make sure indices of new arrays have numeric value set also. + (sort_up_value_number): Don't break the tie based on string value. + (sort_selection): Removed. + (assoc_list): Third arg is string constant. Add name to table of + functions. Linear search it. + * awk.h (assoc_list): Fix declaration. + * debug.c (print_array): And use of assoc_list. + * eval.c (r_interpret): Ditto. + +Wed May 4 23:06:17 2011 John Haque + + * eval.c (setup_frame): Handle a Node_var in stack. Fixes + a problem when a Node_var_new as param becomes Node_var during + expresssion evaluation for a subsequent param. + +Wed May 4 23:04:06 2011 John Haque + + Fix the problem (crash) with disappearing array argument when + it is a subarray of another deleted array argument. + + * awk.h (struct exp_node): Nuke unused field sub.nodep.number. + New field sub.nodep.rn. + (parent_array): New definition for sub.nodep.rn to keep track + of the parent of a subarray. + * awkgram.y (mk_symbol): Initialize parent_array to NULL. + * eval.c (r_interpret): In the case Op_sub_array, assign + parent_array. + * array.c (get_array): Initialize parent_array to NULL when + a Node_var_new becomes a Node_var_array. + (assoc_find): Add a fourth argument for the previous node + of the returned bucket. + (in_array, assoc_lookup): Adjust calls to assoc_find(). + (adjust_fcall_stack): New routine to change a soon-to-be deleted + subarray parameter in the function call stack to a local array. + (do_delete): Simplify code, remove recursive usage. Call + adjust_fcall_stack() where appropriate. + (do_delete_loop): Call adjust_fcall_stack() before clearing the + array. + (asort_actual): Don't accept an array and its subarray as + arguments for asort() or asorti(). + (asort_actual, dup_table): For asort(), appropriately assign + parent_array when creating the result array. + * field.c (do_split, do_patsplit): An array and its subarray not + accepted for the second and the fourth arguments. Remove + unnecessary dupnode of the field seperator node. + + Unrelated: + * awkgram.y (LEX_DELETE, simple_variable): Change type argument + from Node_var_array to Node_var_new for calls to variable(). + * io.c (devopen): Fix parsing GAWK_MSEC_SLEEP env variable. + +Mon May 2 23:44:34 2011 Arnold D. Robbins + + * dfa.c (parse_bracket_exp): Sync with GNU grep, since we + now require C 90, go ahead and put non-constant values into + the array initializers. + +Mon May 2 23:37:09 2011 Corinna Vinschen + + * awk.h (small): Undef after include of to compile + builtin.c on Cygwin. + +Fri Apr 29 12:29:56 2011 Arnold D. Robbins + + * dfa.c: Sync with GNU grep, mainly typos in comments. + +Fri Apr 29 12:13:32 2011 Arnold D. Robbins + + * io.c (inetfile): Change ifdef to ifndef for have getaddrinfo. + Ooops. + +Fri Apr 29 11:49:38 2011 Arnold D. Robbins + + Per Pat Rankin, remove code related to GFMT_WORKAROUND and VAXCRTL. + + * builtin.c (sgfmt): Nuked. + (format_tree): Removed code related to GFMT_WORKAROUND and VAXCRTL. + * node.c (format_val): Revise comment. + +Fri Apr 29 11:33:08 2011 Arnold D. Robbins + + * awk.h (NUMIND): New flag, indicates numeric value of an + array index is current. + * array.c (awk_hash): Remove code for VAXC, it's no longer + needed. Per Pat Rankin. + (assoc_lookup): Only assign the numeric value if it's available. + (do_delete): Add comment about free_subs calling force_string. + (sort_force_index): Use NUMIND. + +Fri Apr 29 10:15:24 2011 John Haque + + * builtin.c: Relocate all codes from awkprintf.h. Restore + format_tree. + * debug.c (do_print_f): Adjust appropriately. Install fatal trap + for format_tree. + * Makefile.am (base_sources): Remove awkprintf.h. + + * array.c (assoc_list): Avoid possible crash; Remove unneeded + initialization of pre_func. + +Wed Apr 27 22:31:23 2011 Arnold D. Robbins + + * awk.h (ahash_dupnode): Merged into dupnode in node.c, change uses. + * array.c (ahash_unref): Merged into unref in node.c, change all uses. + * node.c (dupnode): Revised to support Node_ahash. + (unref): Ditto. + + Lots of code clean up in array.c: + + * array.c (AVG_CHAIN_MAX): Made unsigned. + (array_init): Use strtoul to convert value instead of doing it + manually. + (array_vname): Nuke code that could limit length of name. It + was never used. + (concat_exp): Make len unsigned, clean up the calculation. + (assoc_lookup): Set ahname_num in the index at time of element + creation. + (dup_table): Copy ahname_num also. + Other minor cleanups after code review. + +Sun Apr 24 15:39:19 2011 Arnold D. Robbins + + * NEWS.0: Moved all pre-4.0 news to here. + * NEWS: Shortened. + * Makefile.am (EXTRA_DIST): Add NEWS.0. + +Sun Apr 24 12:43:49 2011 John Haque + + * array.c (sort_user_func): Fix return value to match the + documentaion. + (sort_selection): Make user-specified comparison function with + the same name override default "unsorted" specification. + +Fri Apr 22 16:05:27 2011 John Haque + + * array.c (sort_user_func): New routine to handle user-defined + quicksort comparison function. + (assoc_list): Adjust for user-defined comparison function. + +Fri Apr 22 09:18:16 2011 Arnold D. Robbins + + * array.c (awk_hash): Force results into 32 bits for consistency + across platforms. Keeps the test suite happy. This may turn out + to be a bad idea in the long run. + +Mon Apr 18 10:18:26 2011 John Haque + + * array.c (assoc_list): New function to construct, and optionally + sort, a list of array elements. + (asort_actual): Use the new function to sort array elements. + (assoc_sort_inplace, assoc_from_list, merge_sort, merge): Nuked. + (sort_selection): Simplify handling of error and warning messages. + (sorted_in, sort_match): Nuked, related code in sort_selection() and + assoc_list(). + (sort_ignorecase, sort_up_index_ignrcase, sort_down_index_ignrcase, + sort_maybe_numeric_index, sort_cmp_nodes, cmp_func, sort_up_value, + sort_down_value): Nuked. Ignorecase handling done in the corresponding + non-ignorecase versions. + (cmp_string): New routine for string comparisons. + (sort_up_value_string, sort_down_value_string, sort_up_value_number, + sort_down_value_number, sort_force_index_number, + sort_force_value_number, sort_force_value_string): New routines. + * awk.h (struct exp_node): New field sub.hash.num to store the + numeric value of an array index. + (ahname_num): New define. + (SORT_CTXT): New typedef. + * awkgram.y (tokentab): Accept three args for asort() and asorti(). + (snode): Adjust for the extra args. + * eval.c (r_interpret): In case Op_arrayfor_init, call assoc_list() + for a list of array elements. + * debug.c (print_array): Call assoc_list() for a sorted list of array + elements. + +Wed Apr 13 10:17:37 2011 John Haque + + * builtin.c (do_strftime): Make the third argument to strftime + really work. + * io.c (redirect): Do not free `rp' after failure to open socket + in redirect_twoway. Fixes a double-free memory error. + +Thu Apr 7 21:38:08 2011 Arnold D. Robbins + + * array.c (merge): Use sort_cmp_nodes for asort/asorti. + See test/arraysort.awk test 1. + +Thu Apr 7 10:48:21 2011 Pat Rankin + + * array.c (sort_cmp_nodes): New routine. Unlike cmp_nodes, numbers + are less than strings instead of being formatted and then compared. + (sort_up_value): Use it. + +Sun Apr 3 22:18:26 2011 Arnold D. Robbins + + * README, FUTURE: Minor edits. + +Fri Apr 1 11:53:54 2011 Pat Rankin + + * array.c (sort_up_index_number): Fix the NODE arguments passed to + sort_up_index_string() when a tie breaker is needed. + +Fri Apr 1 11:49:17 2011 Arnold D. Robbins + + Change ISATTY macro to os_isatty function. + + * awk.h (ISATTY): Remove definition. + (os_isatty): Add declaration. + * debug.c, io.c, main.c: Change all calls. + +Thu Mar 31 22:57:36 2011 Arnold D. Robbins + + * Checklist: Updated. This is a git-only file. + * POSIX.STD: Revised some. + +Tue Mar 29 20:52:38 2011 John Haque + + * awkgram.y (LEXT_NEXT): Don't issue an error message if the next + statement is in a function (rule = 0). + + Always resolve the jump target for an exit statement at run-time. + This fixes a bug when the statement occurs in a function. + + * awk.h: New defines target_atexit and target_end. + * awkgram.y (LEX_EXIT): Initilize the jump targets. + * eval.c (r_interpret): Use current rule to choose the jump target + for Op_K_exit. + * debug.c (print_instruction): Adjust case Op_K_exit. + +Tue Mar 29 20:45:49 2011 Pat Rankin + + Move the code to support sorting `for (index in array)' from + eval.c to array.c, and implement several additional orderings. + + * array.c (comp_func, sorted_in, sort_ignorecase, + sort_up_index_ignrcase, sort_down_index_ignrcase): Move from eval.c. + (sort_up_index_string, sort_down_index_string): Move from eval.c + and rename from *_str to *_string. + (sort_selection, sort_match, sort_maybe_numeric_index, + sort_up_index_number, sort_down_index_number, + sort_up_value, sort_down_value): New routines. + * eval.c (sort_&c): Move to array.c. + (r_interpret: case Op_arrayfor_init): Call sort_maybe_numeric_index + before and after qsort. + * awk.h (qsort_compfunc): New typedef. + (sorted_in, sort_maybe_numeric_index): Declare. + +Fri Mar 25 13:15:36 2011 Arnold D. Robbins + + * awk.h: Move libsigsegv portability checks to here from main.c. + * eval.c (fcall_list, fcall_count): Move definitions to here + from main.c. + * io.c (do_find_source): Check against NULL in for loop. + * main.c: Lots of cleanup. Move some things out to other files, + add comments to some variable definitions. + (enum asgntype): To assign_type + (main): Remove decls of getopt variables, clean up comments. + Use emalloc and efree for libsigsegv stack. Remove check for SCCS + leading magic characters. + (add_preassign): Change allocassigns to alloc_assigns. + (init_locale): Change strdup calls to estrdup. + (save_argv): Make the routine static. + * version.in (version_string): Remove leading 4 SCCS magic characters. + +Wed Mar 2 08:15:02 2011 John Haque + + * array.c (asort_actual): Handle the case when the same array + is used as the source and destination. + * field.c (do_split): Make it fatal if attempting to use the same + array for both second and fourth arguments. + (do_patsplit): Ditto. + +Sun Feb 27 08:01:04 2011 Arnold D. Robbins + + Update copryright in all relevant files. + +Sat Feb 26 21:54:07 2011 Arnold D. Robbins + + * eval.c (sorted_in): Revise text of lint warning. + +Fri Feb 25 17:34:14 2011 Pat Rankin + + * eval.c (sorted_in): Remove incorrect unref() call. + +Wed Feb 23 21:48:20 2011 Arnold D. Robbins + + * main.c (main): Free extra_stack, to make valgrind happier. + +Tue Feb 22 12:04:09 2011 Arnold D. Robbins + + * main.c (UPDATE_YEAR): Move to 2011. Fix copyright. + +Tue Feb 15 17:11:26 2011 Pat Rankin + + * eval.c (sorted_in, sort_up_index_str, sort_down_index_str, + sort_up_index_ignrcase, sort_down_index_ignrcase, sort_ignorecase): + New functions to sort arrays for `for (index in array)' statements. + (r_interpret: case Op_arrayfor_init): Call sorted_in(). + +Wed Feb 16 07:12:50 2011 John Haque + + Fix line numbers in the lint, warning and error messages issued + by the parser. + + * awkgram.y (lintwarn_ln, warning_ln, error_ln): New local versions, + each accepts an additional line number argument. + (print_included_from): New function to seperate 'Included from ..' + message from yyerror. Use it in yyerror, and in the new functions. + (grammar): Use the local versions for messages. + (add_srcfile, include_source, dup_parms, func_install, param_sanity, + mk_binary, add_lint): Ditto. + (dup_params, include_source): Adjust arguments to pass line number. + * awk.h: New definition ATTRIBUTE_PRINTF_2. + + * awkgram.y (yylex): New variable warntab. Use it to issue only one + warning for the same non-standard special token in source. + (parse_program): Avoid spurious warnings. Don't call check_funcs if + yyparse aborts prematurely. + +Mon Feb 14 08:03:41 2011 John Haque + + * awkgram.y (regexp): Don't use tokstart in lint warning, it isn't + `\0' terminated. + (grammar): Copy update and assign routines from relevant variables into + instructions to avoid extra pointer dereferencing at run-time. + * awk.h (update_var, assign_var): new definitions. + * eval.c (r_interpret): Adjust cases Op_var_assign and Op_var_update. + +Sun Feb 13 20:22:47 2011 Eli Zaretskii + + * awkgram.y (add_srcfile): + * debug.c (source_find): Pass `path' and `src' to files_are_same. + * gawkmisc.c [__DJGPP__ || __MINGW32__]: Include pc/gawkmisc.pc, + for consistency with __EMX__ and pc/Makefile. + * debug.c (interpret, initialize_pager, prompt_continue) + (set_gawk_output): Use ISATTY instead of isatty. + * io.c (redirect, iop_alloc): Same. + * main.c (main): Same. + * awk.h (ISATTY): Trivial definition, if not defined elsewhere. + +Sun Feb 13 20:16:04 2011 Arnold D. Robbins + + * awkgram.y (check_funcs): Update warning about never called to say + "never called directly" since it could be called indirectly. + +Sun Feb 13 07:12:50 2011 John Haque + + * profile.c (pprint): In case Op_indirect_func_call, pop off + indirect var after function parameters. + Thanks to Hermann Peifer for the bug report. + * array.c (do_delete): Always free an empty sub-array name and node. + * ChangeLog: Fix typos. + +Fri Feb 11 10:26:25 2011 Arnold D. Robbins + + * io.c (remad_std_file): Close oldfd first, in case we've + run out of fd and do dup2 if the newfd isn't what we were + looking for. Thanks to Hermann Peifer for + the bug report. + +Thu Feb 10 21:31:36 2011 Andreas Buening + + * main.c (load_procinfo): Fix warning about unsed variables if we + don't have multiple groups. + * protos.h: Move decls for many standard functions here if + they aren't in the header files (OS/2) and bracket inside + #ifndef STDC_HEADERS. + * io.c (devopen): Remove decl of strtoul. + * field.c (set_FIELDWIDTHS): Same. + * awk.h: Always include protos.h. + +Tue Feb 8 22:46:22 2011 Arnold D. Robbins + + * array.c, builtin.c, eval.c: Equalize message strings and + fix a typo. Thanks to Benno Schulenberg . + +Mon Feb 7 11:23:33 2011 Arnold D. Robbins + + * awkgram.y (next_sourcefile): Comment out assertion that + lexeof is true; causes core dump on user typos of bad + characters which previous versions did not do. Thanks to + Pat Rankin for the report. + + * re.c (expand_range): Allow for ^ as first character + inside range. Thanks for Nelson Beebe for the bug report. + +Fri Feb 4 10:28:19 2011 Arnold D. Robbins + + * README.cvs: Udpated. + * Checklist: New file for storage in the git repository. + +Wed Feb 2 20:34:41 2011 Corinna Vinschen + + * awkgram.y (free_bc_internal): Remove unused variable. + +Tue Feb 1 23:13:10 2011 Arnold D. Robbins + + * bootstrap.sh: No need to find aclocal.m4, just touch it. + +Tue Feb 1 23:05:51 2011 Corinna Vinschen + + Make values of ctype macros into unsigned char to fix + warnings found on Cygwin / Newlib. + + * array.c (array_init): Add cast. + * awkgram.y: Ditto. + * awkprintf.h: Ditto. + * builtin.c (sub_common, nondec2awknum): Ditto. + * command.y: Ditto. + * eval.c (fmt_ok): Ditto. + * ext.c (make_builtin): Ditto. + * main.c (main, arg_assign): Ditto. + * re.c (check_bracket_exp): Ditto. + * node.c (r_force_number, parse_escape): Ditto. + (dump_wstr): Add unused attribute (unrelated). + +Tue Feb 1 23:01:40 2011 John Haque + + Fix switch debugging. + + * awkgram.y (LEX_SWITCH, case_statements, case_statement, + case_value): Linearize instructions to facilitate debugging. + (switch_body): Removed. + (yylex): Add LEX_CASE in special token processing. + (free_bc_internal): Remove case Op_K_switch. + * awk.h (OPCODE): Remove opcode Op_case_list. + * eval.c (r_interpret): Remove Op_K_switch. Add case + Op_K_case to handle switch. + Add cases Op_K_do, Op_K_while, Op_K_for, Op_K_arrayfor, Op_K_switch + and Op_K_default as no-ops, needed for pgawk. + * debug.c (print_instruction): Remove case Op_K_switch, + add case Op_K_case instead. + + Unrelated: + * awkgram.y (case_statements): As case values, "abc" and /abc/ + no longer considered as duplicates. + + Cleanup grammar and run-time code for switch and loops. + Jump targets for break and continue are now fixed, and known + at parse time. See ChangeLog entry dated Oct 21, 2010. + + * awk.h (OPCODE): Remove Op_push_loop and Op_pop_loop. + (loop_count): Remove definition. + * awkgram.y (fix_break_continue): Change calling parameters to + instruction list, break and continue targets. Adjust code. + (LEX_DO, LEX_WHILE, LEX_SWITCH, LEX_FOR): Simplify grammar. Use + Op_no_op as target for break. Adjust call to fix_break_continue. + (mk_for_loop): Ditto. + * eval.c (r_interpret): Nuke cases Op_push_loop and Op_pop_loop. + Simplify Op_K_break and Op_K_continue. Remove declaration of in_loop + and all loop detection code thereof. + * debug.c (pre_execute, post_execute): Adjust declarations and code. + (print_instruction): Nuke cases Op_push_loop and Op_pop_loop. + * eval.c (r_interpret): Adjust calls to pre_execute and post_execute. + * profile.c (pprint): Adjust cases Op_K_for, Op_K_do, Op_K_while, + Op_K_switch and Op_K_arrayfor. Add cases Op_K_case and Op_K_default. + Remove Op_push_loop and Op_pop_loop. + + Unrelated cleanup: + * awkgram.y (mk_condition): Don't include Op_K_if, Op_K_else and + Op_cond_exp if not profiling. + +Tue Feb 1 10:20:02 2011 Arnold D. Robbins + + * eval.c (r_interpret): Change magic string for array sorting. + +Sun Jan 30 21:49:53 2011 John Haque + + Add `isarray' built-in function. + + * awk.h (enum opcodeval): Op_push_arg: new opcode. + (do_isarray): Add declaration. + * awkgram.y (tokentab): Add new entry for `isarray' function. + (snode): Add handling for it. + * builtin.c (do_isarray): New function. + (do_length): Die if posix and get an array argument. + * debug.c (print_instruction): Handle Op_push_arg. + * profile.c (pprint): Likewise. + * eval.c (optypes, r_interpret): Likewise. + +Sun Jan 30 21:13:01 2011 Arnold D. Robbins + + * hard-locale.h: Synced to GNU grep. + * hard-locale.c: New file, brought in from GNU grep. + * Makefile.am (base_sources): Add hard-locale.c. + * dfa.h: Sync as much as possible to GNU grep. + * dfa.c: Sync as much as possible to GNU grep. + * builtin.c (do_strftime): Remove unneeded variable. + +Thu Jan 27 22:52:54 2011 Arnold D. Robbins + + * awk.h (comp_func): Add declaration. + * debug.c (comp_func): Make not static, and move to ... + * eval.c (comp_func): ... here. + (r_interpret): Add array sorting if magic index is + set in PROCINFO. + +Thu Jan 27 22:12:00 2011 Corinna Vinschen + + * Makefile.am: Remove $(EXEEXT) from 'awk' symlink. + +Thu Jan 27 21:21:13 2011 John Haque + + * eval.c (r_interpret): When in BEGINFILE or ENDFILE, add check for + `getline var < file' in cases Op_K_getline_redir and Op_K_getline. + + * awkgram.y (constant_fold): Code cleanups. Fix bug in the code for + string concatenation. + + * configure.ac: Remove unneeded extra call to AC_LANG. + +Thu Jan 27 15:00:42 2011 Arnold D. Robbins + + * eval.c: Fix up some comments. + * io.c (remap_std_file): New function. + (iop_close): Use it. + +Mon Jan 24 22:14:21 2011 Andreas Buening + + * debug.c: Bracket variables used with readline in #ifdef. + * dfa.c (add_utf8_anychar): Move inside ifdef. + +Mon Jan 24 22:05:26 2011 Arnold D. Robbins + + * re.c (make_regexp): Add separate variable for dfa syntax. + General formatting cleanup. + (research): General formatting cleanup. + (refree): Remove out of date comment. + (re_update): Comment the routine. + (check_bracket_exp): Improve check for range to not get [^-/] + kinds of things. Thanks to Nelson Beebe for pointing out the bug. + +Wed Jan 19 20:31:17 2011 Arnold D. Robbins + + * awk.h (is_valid_character): Add `& 0XFF' and remove casts to + unsigned chars in other files. Remove definition of this macro + in not MBS_SUPPORT case, since it wasn't being used. + (btowc_cache): New macro to index into the array and use the + same trick. Relies on ANSI C preprocessor semantics. + Fix all uses. + * builtin.c, node.c, io.c: Fix uses of these macros. + +Wed Jan 19 20:19:29 2011 Arnold D. Robbins + + * node.c (wstr2str): New function. + * awk.h: Declare it. + * builtin.c (is_wupper, is_wlower, to_wupper, to_wlower, + wide_change_case, wide_tolower, wide_toupper): New functions to + simplify wide character case conversions. + (do_tolower, do_toupper): Use wide_tolower, wide_toupper in multibyte + case. + (do_substr): Simplify code a little bit. + +Mon Jan 17 22:48:48 2011 Arnold D. Robbins + + * builtin.c (do_bindtextdomain): Change type of `the_result' + to const char* to kill compiler warnings. + * debug.c (source_find): Improve error message when file not + found. + * awkgram.y (get_src_buf): Add cast to value of `read' to + turn off compiler warnings on different systems. + +Mon Jan 10 21:40:05 2011 Andreas Buening + + * io.c (devopen): Handle opening of directories for OS/2. + +Mon Jan 10 21:37:49 2011 Arnold D. Robbins + + * awk.h: Rearrange includes of so it won't be + included for VMS, move definition of O_BINARY down. + +Sat Jan 8 23:00:37 2011 Arnold D. Robbins + + * awk.h: Include here. + * main.c, io.c: Remove includes of . + +2011-01-08 Eli Zaretskii + + * io.c (PIPES_SIMULATED) [__DJGPP__ || __MINGW32__]: Define. + (binmode): Define for __DJGPP__ and __MINGW32__ as well. + (gawk_popen) [!PIPES_SIMULATED]: Define for __DJGPP__ and + __MINGW32__ as well. + +Wed Jan 5 20:35:30 2011 Arnold D. Robbins + + * configure.ac: Move call to AC_LANG([C]) into here from + m4/readline.m4. + +Tue Jan 4 11:21:18 2011 Arnold D. Robbins + + Clean up some compiler warnings: + + * array.c (do_delete): Cast for printf. + * builtin.c (do_bindtextdomain): Casts for const char *. + * io.c (rs1scan): Cast for indexing of array. + * re.c (add_char): Remove unused variables. + +Fri Dec 31 11:05:11 2010 Michal Jaegermann + + * awk.h (strncasecmpmbs): Change parameters to const char *. + * builtin.c (strncasecmpmbs): Change parameters to const char *. + Add casts as appropriate in calls to other functions. + * eval.c (cmp_nodes): Add casts in calls to strncasecmpmbs. + * node.c (str2wstr): Ditto. + +Tue Dec 28 21:13:31 2010 Eli Zaretskii + + * gawkmisc.c: Restore inclusion of pc/gawkmisc.pc. + +Tue Dec 28 21:00:36 2010 Arnold D. Robbins + + * ext.c (make_builtin): Make first parameter const char *. + Adjust code inside to fit. + * awk.h (make_builtin): Adjust declaration. + +Mon Dec 27 19:55:10 2010 Arnold D. Robbins + + * io.c [AF_UNSPEC, AF_INET, AF_INET6]: Add definitions for systems + that don't define them. + (inetfile): Make IPv6 a fatal error if using the fake getaddrinfo, + since chances are good that IPv6 really isn't available. + +Sat Dec 25 19:36:27 2010 Arnold D. Robbins + + Fixes for z/OS. + + * awkgram.y (tokcompare): Change argument types to const void *. + (check_special): Add cast to void * in call to qsort. + * builtin.c (do_bindtextdomain): Change `directory' and `domain' + to const char *. + * custom.h (ZOS_USS): Undef HAVE_SYS_PARAM_H and HAVE_MCHECK_H. + Beats me why configure thinks it has those things. + +Fri Dec 24 12:56:46 2010 Arnold D. Robbins + + * custom.h: Remove defs for MIPS RiscOS. + * configure.ac, aclocal.m4: Updated to Autoconf 2.68. + +Wed Dec 22 21:21:28 2010 Arnold D. Robbins + + * gettext.h: Synchronized with gettext 0.18.1. + +2010-12-22 gettextize + + * configure.ac (AM_GNU_GETTEXT_VERSION): Bump to 0.18.1. + * ABOUT-NLS, config.rpath: Updated from gettext 0.18.1. + +Sun Dec 19 16:43:14 2010 Arnold D. Robbins + + * awk.h (update_PROCINFO_str, update_PROCINFO_num, make_str_node): + Change `char *' parameters to `const char *' to avoid some + compiler warnings. + * ext.c (do_ext): Remove cast in call to make_string. + * field.c (update_PROCINFO_str, update_PROCINFO_num): Adjust. + * main.c (init_args): Remove casts in calls to make_string. + * node.c (r_make_str_node): Add cast in assignment if ALREADY_MALLOCED. + +Sat Dec 18 20:12:59 2010 Eli Zaretskii + + * array.c, gawkmisc.c, io.c, main.c, regex_internal.h, + awkgram.y, awk.h, array.c: Remove OS2 and _MSC_VER defines. + +Sat Dec 18 19:56:17 2010 Arnold D. Robbins + + * builtin.c, eval.c, floatcomp.c, io.c: Remove all the crufty + old code for #ifdef CRAY. + +Thu Dec 16 11:06:50 2010 Arnold D. Robbins + + Put strftime() default format into PROCINFO["strftime"]. + + * awk.h (def_strftime_format): Declare const char[] array. + * main.c (def_strftime_format): Define it. + (load_procinfo): Load it into PROCINFO. + * builtin.c (do_strftime): Use value in PROCINFO for format + string if it's there. Remove old def_format static array. + +Mon Dec 13 17:12:44 2010 Arnold D. Robbins + + If not POSIX, turn [d-h] into [defgh]. + + * re.c (check_bracket_exp): Make warning about ranges under + lint control. + (expand_range): New routine to expand ranges. + (make_regexp): Check if might have range and call expand_range. + (add_char): New helper function for expand_range. + +Thu Dec 9 22:12:48 2010 Arnold D. Robbins + + * io.c: Restored changes of 1 July 2010 to allow /inet4 and /inet6; + they got lost amongst the merges. Fixed checking of do_sandbox. + Also, removed the option for raw IP sockets since it was never + implemented and wasn't going to be. + +Tue Dec 7 11:59:00 2010 Arnold D. Robbins + + * configure.ac: Remove test for return type of sprintf. Another + renegade from the late 1980's bites the dust! + * protos.h (sprintf): Remove declaration. + +Sun Dec 5 15:01:35 2010 Arnold D. Robbins + + * eval.c (grow_stack): Change env var to GAWK_STACKSIZE. + * awk.h, main.c, eval.c, profile.c: Removed features added + for those who are Strong In The Ways of the Source. + * debug.c (comp_func): Moved to here from eval.c, where it's + no longer needed. + +Sat Dec 4 21:44:38 2010 Arnold D. Robbins + + * node.c (init_btowc_cache): New function. + (btowc_cache): New array. + (str2wstr): Use is_valid_character in test instead of several isXXX + calls. + * awk.h [is_valid_character]: Macro to use btowc_cache. + * main.c (main): Call init_btowc_cache(). + * io.c (rs1scan): Add call to is_valid_character when processing + characters byte by byte. + +Wed Dec 1 08:10:21 2010 Arnold D. Robbins + + * awk.h, awkgram.y, debug.c: Change CONTEXT to AWK_CONTEXT + everywhere to avoid problems with libsigsegv on cygwin. + +Tue Nov 30 13:48:34 2010 Arnold D. Robbins + + * main.c (MRL): Removed variable, not used since Tandem code nuked. + (main): Fix argument parsing for -m. + (usage): Make -m undocumented (already is the doc/* files). + * io.c (MRL): Remove declaration. + +Mon Nov 29 21:59:21 2010 Arnold D. Robbins + + * re.c (check_bracket_exp): Add check and warning for ranges. + I may live to regret this. + +Mon Nov 29 20:09:18 2010 Eli Zaretskii + + * replace.c [!HAVE_STRFTIME]: For __MINGW32__, define + HAVE_STRFTIME while compiling missing_d/strftime.c. + +Thu Nov 25 20:12:28 2010 John Haque + + * awkgram.y (grammar): Bug fix in delete for loop efficiency hack. + * debug.c (do_info): Don't sort functions to avoid potential memory leak + in case A_FUNCTIONS. + + Plug more potential leaks in the debugger eval/condition commands: + * builtin.c (POP_TWO_SCALARS): New macro to free first scalar in case + of a fatal error in the next. + (do_index, do_atan2, do_lshift, do_rshift, do_and, do_or, do_xor): Use it + instead of two consecutive POP_SCALARs. + + Execution context related code cleanups. Also, added descriptive + comments for functions. + * awkgram.y (get_context): Nuked. + (push_context, pop_context, in_main_context): New functions. + (mk_program, parse_program, yylex): Updated. + * debug.c (condition_triggered, do_eval, parse_condition): Updated. + * eval.c (unwind_stack): Updated. + * main.c (main): Updated. + * awk.h (struct context): Removed member level, not needed. + + * eval.c (op_assign): Initialize r to NULL, and declare x only + if HAVE_FMOD not defined to remove GCC warnings. + +Thu Nov 25 08:32:31 2010 Arnold D. Robbins + + * eval.c (posix_compare): Do string comparison with strcoll() / + wcscoll(). + (cmp_nodes): Call it if do_posix. This may be a bad idea, + but what the heck. Standards compatibility uber alles! + +Wed Nov 24 20:09:23 2010 Arnold D. Robbins + + * ext.c (do_ext): Require definition of `plugin_is_GPL_compatible' + per GNU Coding standards. + +Sun Nov 21 14:23:58 2010 John Haque + + Debugger: Fix memory leak when quitting pager. + * awk.h (PUSH_BINDING, POP_BINDING): Generalize macro definitions. + * debug.c (print_array): save and restore bindings for pager. + free list in case of an early exit in the pager. + (do_dump_instructions): Don't sort functions to avoid potential + memory leak. + (execute_code): Adjust PUSH_BINDING and POP_BINDING macro invocations. + + * awkgram.y (func_call): Avoid reading freed memory for indirect var + name; do the special variable check before the call to 'variable'. + + * eval.c (r_interpret): Fixes and cleanups. Change TOP to TOP_SCALAR + in the case Op_store_field. + (assign_common, assign, compare): Nuked macros. + (cmp_scalar, op_assign): New functions as replacements for the macros. + +Fri Nov 19 11:57:28 2010 Arnold D. Robbins + + * bootstrap.sh, Makefile.am: Remove treatment of CVS. + * README.cvs: Updated further. + +Thu Nov 18 23:28:23 2010 Arnold D. Robbins + + * configure.ac: Remove `--enable-portals' option. I don't think + anyone ever used it. + * io.c (two_way_open): Remove the code for portals. + * README.cvs, README.git, bootstrap.sh: New files for storage + in the Git repository. + +Tue Nov 16 11:56:31 2010 Arnold D. Robbins + + * version.in: Removed descriptive comments. New features and + so on are documented in the documentation and in NEWS. + +Mon Nov 15 19:19:25 2010 Arnold D. Robbins + + * awkgram.y (LEX_LENGTH): Removed warning about length with + no argument being deprecated. + * awkprintf.h: Remove code for sun386. Fix %c to print multibyte + character instead of first byte. + * builtin.c (sub_common): Update commentary about POSIX. + * io.c (nextfile): Add MAYBE_NUM to FILENAME. + +Fri Nov 12 11:53:15 2010 Arnold D. Robbins + + * main.c (update_global_values): New routine, needed for correct + operation of --dump-variables. + * awk.h: Declared it. + * awkgram.y (get_varlist): Call it. + Thanks to Hermann Peifer for the bug report. + + * debug.c (find_subscript): Initialize `r' to NULL, per + Michal Jaegermann. + +Thu Nov 11 16:31:49 2010 Arnold D. Robbins + + * awk.h: Restore decls of strcasecmp, strncasecmp. + * builtin.c: Lots of general cleanups. + (sub_common): Actually enable POSIX rules! (Wasn't done right + earlier.) + +Thu Nov 4 14:08:29 2010 Arnold D. Robbins + + * array.c, awkgram.y, awkprintf.h, builtin.c, debug.c, eval.c, + field.c, io.c, main.c, node.c, profile.c, re.c: Remove register + keyword everywhere. + * node.c: Minor code cleanups. + +Wed Nov 3 08:29:15 2010 Arnold D. Robbins + + * node.c (free_wstr): If argument is null string or null field, + return. Thanks to Vojtech Vitek + +Tue Nov 2 16:45:06 2010 Arnold D. Robbins + + Straighten out options more. --lint --> -L, --lint-old --> -t + + * main.c (optlist, optab, main, usage): Adjusted approrpiately. + + Other: + * awk.h: Lots more general cleanup. + * builtin.c (strncasecmpmbs): Move mbstate vars into the routine. + * awk.h (strncasecmpmbs): Adjust declaration. + * eval.c (cmp_nodes): Adjust call. + * awkgram.y, command.y: Remove unused variables. + +Mon Nov 1 21:55:26 2010 Arnold D. Robbins + + * main.c (optlist, optab, main): Renamed -l option to -t + so can eventually merge in xgawk's -l option. + (usage): Adjusted approrpiately. + +Mon Nov 1 16:23:52 2010 Arnold D. Robbins + + * array.c, awk.h, custom.h, eval.c, gawkmisc.c, io.c, main.c, + protos.h, replace.c: Remove code related to: __amigaos__, + atarist, BeOS, _MSC_VER, MSDOS, TANDOM, WIN32, and anything + not for __STDC__. + +Sun Oct 31 21:49:22 2010 Arnold D. Robbins + + * awk.h: Start on cleaning up. Remove stuff for DOS, WIN32, + TANDEM, atarist, NeXT even! + +Sun Oct 31 05:56:23 2010 John Haque + + Add array of arrays. + + * awk.h (Op_sub_array): New opcode. + (POP_SCALAR, TOP_SCALAR): New macros. If the item is not a scalar, + make it a fatal error. + (POP_STRING, TOP_STRING): Use POP_SCALAR and TOP_SCALAR instead + of POP and TOP. + (force_string, force_number): Unrelated: simplify (remove) macros + for older gcc and non-gcc compilers. + * awkgram.y (grammar): New non-terminals for array subscripts. + delete array subscripts are handled differently than array subscripts + used as a variable. + (SUBSCRIPT): New terminal symbol to indicate end of subscripts. + (yylex): Return SUBSCRIPT after all the subscripts has been read. + (rules variable, LEX_DELETE and LEX_FOR): Adapt to these changes. + (sub_counter): New global to count the number of subscripts in a + delete statement. + (optimize_assignment): Adjust code for assignment to an array element. + * array.c (make_aname): New function to construct a sub-array name. + (get_array): Handle Node_val in the default case. + (concat_exp): Issue fatal error message if each expression is not a + scalar. + (assoc_clear): Recursively clear sub-arrays. + (do_delete, assoc_dump, assoc_sort_inplace, dup_table): + Handle array of arrays. + * builtin.c: Replace POP with POP_SCALAR as appropriate. + * eval.c (optypes): Add entry for Op_sub_array. + (r_interpret): Handle Op_sub_array. For case Op_subscript, increment + reference count only if the result is a scalar. If type is not a + scalar in Op_subscript_lhs, make it fatal. Adjust stack pointer + after a call to do_delete in Op_K_delete. Change POP(TOP) + to POP_SCALAR(TOP_SCALAR) as needed. + * profile.c (pprint): Add case for Op_sub_array. + * command.y (grammar): New non-terminals and rules to handle + array of arrays. + * debug.c (struct list_item): Redesigned. Field subs is NODE ** now, + new fields num_subs and sname. New flags OLD_IS_ARRAY and CUR_IS_ARRAY; + removed flag ARRAY_WATCH. Renamed macro IS_ARRAY() to WATCHING_ARRAY. + (do_info): Adapt to the structural changes in cases A_WATCH and + A_DISPLAY. + (print_array): New function to print contents of an array. + (print_subscript): New function to print an element of an array. + (do_print_var): Use the new functions to print an array element + and contents. + (do_set_var): Adapt to the structural changes in list_item for + an array element. + (delete_item, do_add_item, display): Ditto. + (add_item): Ditto. Use field symbol, not subs to store field number and + adjust accordingly everywhere. + Unrelated: handle function parameter correctly, watch and display now + prints the param name instead of the actual array name. + (find_subscript): New function. + (initialize_watch_item): Use the new function find_subscript + to locate an array element NODE. + (watchpoint_triggered): Redone. + (cmp_val): Redone. + (print_watch_code): Adjust code for printing subscript. + (print_instruction): Add case for Op_sub_array. + (serialize_subscript): New function. + (serialize): Use the new function to serialize watch and display + subscripts. + (unserialize_list_item): Adapt to the structural changes. Also, + simplify code. + (do_print_f): Redo code for printting array element. + (pre_execute_code, execute_code): Change POP to POP_SCALAR. + + Unrelated: + + * debug.c (unserialize_commands): New function for common code in + unserialize_breakpoint and unserialize_list_item. + (unserialize_breakpoint and unserialize_list_item): Use the new + function. + + * awkgram.y (grammar): Do not terminate parser if seen an empty(NULL) + subscript. Install null string as subscript and continue parsing. + (variable): Do not terminate parser if type is Node_func, change it + to Node_var_new temporarily. Simplifies grammar and allows parser to + continue. + + * command.y (yylex): Add history entry when blank line repeats + previous command. + + * debug.c (pp_args): Removed. Pretty-printing SUBSEP + seperated indexes can not be made to work reasonably in all cases. + (struct list_item): Removed field pp_subs. + (concat_args): Move to file command.y. + * command.y (grammar): Concatenate SUPSEP seperated indexes. + +Thu Oct 28 16:25:08 2010 Arnold D. Robbins + + Remove use of varargs.h everywhere: + + * awkgram.y (yyerror): Fixed. + * awk.h [CAN_USE_STADARG_H]: Removed, #error added if not available. + (snprintf, Func_print, msg, error, warning): Fix declarations. + * cmd.h (gprintf, d_error): Fix declaration. + * command.y (yyerror): Fixed. + * debug.c (d_error, gprintf): Fixed code. + * main.c (lintfunc): Fix declaration. + * msg.c (msg, warnning, error, r_fatal): Fixed code. + +Wed Oct 27 16:45:29 2010 Arnold D. Robbins + + * awk.h [P]: Finally, nuked the `P' macro. Removed definitions + and uses. + [HAVE_DOPRNT]: Removed check for this, now require vfprintf. + [BELL]: Nuked; require a compiler that supports '\a'. + * array.c, awkgram.y, awkprintf.h, builtin.c, cmd.h, command.y, + debug.c, eval.c, ext.c, field.c, io.c, main.c, protos.h [P]: + Remove all uses. + * node.c (r_force_number): Change check with strtod to `ptr == cpend', + SunOS 3.5 compatibility no longer concerns us. Removed the comment. + [P]: Removed all uses. + (parse_escape): Change from BELL to '\a'. + * profile.c (pp_string): Change from BELL to '\a'. + [P]: Removed all uses. + +Tue Oct 26 20:11:37 2010 Arnold D. Robbins + + * awkgram.y (fix_break_continue): New routine to make break and + continue instructions point to where they should jump to. Adjusted + grammar to call it for switch and loops. + * eval.c (r_interpret): For Op_K_break and Op_K_continue, jump + to pc->target_jmp. + * command.y (cmdtab, do_help): Translate the help messages. + * debug.c (option_list, option_help): Translate the help messages. + Elsewhere, clean up / add calls to gettext. + +Fri Oct 22 11:18:29 2010 Arnold D. Robbins + + * ChangeLog: Merged with ChangeLog.BYTECODE. + * Makefile.am (EXTRA_DIST): Removed ChangeLog.BYTECODE. + * ChangeLog.BYTECODE: Removed the file. + +Thu Oct 21 12:16:35 2010 Arnold D. Robbins + + Make break and continue outside a loop not allowed at all, + even with --traditional, as BWK awk no longer allows this. + + * eval.c (r_interpret): For Op_K_break and Op_K_continue, make + them fatal errors if not in a loop. + * awkgram.y (break_allowed, continue_allowed): New variables. + [BREAK, CONTINUE]: New flags for tokentab. + (yylex): If set, increment the corresponding variable. + (Grammar): Test variables when break/continue seen, decrement them + at the end of productions for loops and switch. + +Tue Oct 19 20:03:29 2010 Arnold D. Robbins + + * main.c (optab, usage): Remove --compat, --copyleft, and --usage extra + option aliases. + +Tue Oct 19 08:25:02 2010 Arnold D. Robbins + + * awkprintf.h (r_format_arg): Undouble "%" characters in + error messages. Thanks to Scott Deifik for catching the problem. + +Sat Oct 16 22:08:54 2010 Arnold Robbins + + Apply changes from John Haque: + + * awk.h [ASSIGNED]: Remove unused flag. + (Op_cond_pair_left): Remove. + * debug.c (print_instruction): Remove Op_cond_pair_left. + (do_trace_instruction): Fix print for Op_newfile. + (parse_condition): Improve code. + * eval.c (optypes): Add space to string for "!". + (r_interpret): Remove Op_cond_pair_left and Node_instruction cases. + Revise Op_cond_pair to handle left and right sides correctly. + Simple code fixes in some other cases. + * profile.c (pprint): Remove Op_cond_pair_left. Simplify Op_not. + +Fri Oct 15 14:17:09 2010 Arnold Robbins + + * awk.h (Op_cond_pair_left): New op for left side of condition pair. + * debug.c (print_instruction): Support it. + * profile.c (pprint): Ditto. + * eval.c (r_interpret): Split Op_cond_pair into two cases; they have + to be handled differently. + +Wed Oct 13 19:17:03 2010 Arnold D. Robbins + + * regex.h [RE_SYNTAX_AWK]: Add RE_CHAR_CLASSES, for compatibility + with modern Unix awk. + +Sun Oct 10 15:31:01 2010 Arnold D. Robbins + + * re.c (dfawarn): Do nothing in body, since gawk does it's + own checking. + +Sun Oct 10 15:30:34 2010 Arnold D. Robbins + + MERGE with bytecode version! Many many files changed / added. + +Sun Oct 3 08:41:25 2010 John Haque + + * Lots of files: Indirect function call, FPAT, BEGINFILE/ENDFILE + from gawk-devel. + + * awk.h (defrule): New enum for rule types. + (ruletab): Converts rule types to string constants. + * awkgram.y: Use rule types to simplify code in grammar. + * eval.c, debug.c, profile.c, awkgram.y routines: Update to use ruletab. + + * Lots of files: New debugger command eval for evaluation of + arbitrary (g)awk expression(s). + eval "awk statement(s)" + OR + eval p1, p2 + > awk statement + > more awk statement(s) + > end + p1, p2 are eval locals. + Conditional break/watch point: + break 1 "condition expression" + OR + break 1 + condition "condition expression" + + * command.y: grammar clean-ups. + (find_command): Redo to fix bugs in abbreviation/partial-string + search. + + * debug.c (command_source): New structure. Used to manage + sources for debugger commands. 'source file' command can now + include additional source commands. + + * awk.h: new enum type redirval for I/O redirection types; + remove redirection types from OPCODE. + * awkgram.y: Adjust grammar for redirection type changes. + (yylex, mk_getline): Update for redirection type changes. + * io.c (redirect, do_getline): Ditto. + * profile.c (redir2str): New function to convert redirection types + to string constants. + (pprint): Use new function redir2str. + * debug.c (print_instruction): Ditto. + * eval.c (optypes): Remove redirection types from table. + + * main.c (main): initialize do_optimize to 1, default optimizations. + do_optimize > 1 for -O (--optimize) command line option. + do_optimize = 0 turns off all optimizations, and is for debugging + purposes. + * awkgram.y: Updated. + + Lots of other cleanups and improvements. + +Thu Sep 16 09:44:47 2010 John Haque + + Lots of bug fixes & improvements, including work on + profiling. + +Wed Aug 18 22:15:06 2010 Arnold Robbins + + Lots of files: Sync fully with gawk-stable version, in particular + documentation edits and all ChangeLog files. + +Mon Aug 9 07:17:54 2010 John Haque + + Fix the case when runtime stack can have a INSTRUCTION pointer + while popping stack items (a next/nextfile statement inside a loop). + + * awk.h: new NODETYPE Node_instruction. Remove instruction pointer + from STACK_ITEM union, and all related macros. + * eval.c (r_interpret): wrap code (INSTRUCTION) pointer inside + a NODE for Op_push_loop. Change Op_pop_loop, Op_K_break + and Op_K_continue accordingly. + (unwind_stack): free Node_instruction. + (nodetypes): add new entry for Node_instruction. + +Thu Aug 5 15:05:22 2010 Arnold Robbins + + * awk.h: Remove redundant declaration of struct lconv loc; + * awkprintf.h: Move ifdef for HAVE_LOCALE_H inside case '\''. + * custom.h: Add macros for setenv and unsetenv for Z/OS. + * main.c (main): Remove three argument version for Tiny CC after + applying patches to local copy that fix the issue with environ. + +Mon Jul 26 07:23:01 2010 John Haque + + Started Byte Code version ChangeLog. + + * awk.h, eval.c, debug.c, profile.c: Renamed opcode Op_exit to + Op_atexit. Simplify exit value handling; use existing global + exit_val from main.c. + New opcode Op_stop. + + * msg.c: New variables fatal_tag_valid, fatal_tag. + (r_fatal): Use these new variables. + (err): Change myname from dgawk to gawk when debugging; + reflects the correct source of error messages. + + * builtin.c, msg.c: Change stdout to output_fp. + (do_fflush): Also flush output_fp if not stdout. + + * command.y (yylex, yyparse): (Much) improved error recovery. + + * awkgram.y (yylex): Add 'goto out' in 'check_special' + for do_traditional or do_posix check, lost somewhere + between 3.1.3 to 3.1.8. + (pop_var): New name remove_symbol to go with mk_symbol. + (install): New name install_symbol. + + * debug.c:(set_gawk_output): Improved handling of /dev files + including /dev/ttyN, /dev/pts/N. + (pre_execute): Renamed execute, a pre_hook in r_interpret. + (post_execute): New function, a post_hook in r_interpret; + used to detect non-local jumps (next, nextfile, exit) + with commands 'until' and 'finish', and to print the + returned value for finish. + (print_instruction): Redo function params initialization + when trace is on. Hopefully, correct this time around. + (close_all): New function to close all known files + during quit and restart. + + * eval.c(r_interpret): Redefine macro JUMPTO to include + post_hook from above, and use it exclusively to move to + the next instruction for execution. + + * debug.c (do_run): Trap gawk fatal errors. +Sun Sep 5 12:44:24 2010 Arnold D. Robbins + + * re.c (check_bracket_exp): Add `warned' flag to table and adjust + code to only warn once about each candidate. + (make_regexp): Always call check_bracket_exp, per discussion + on comp.lang.awk. + +Fri Aug 6 16:29:55 2010 Arnold D. Robbins + + * re.c (check_bracket_exp): Improved the code, again. + +Thu Aug 5 18:41:27 2010 Arnold D. Robbins + + * re.c (check_bracket_exp): Improved the code. + +Tue Aug 3 11:35:11 2010 Arnold D. Robbins + + * re.c (check_bracket_exp): New function. + (make_regexp): Call it if do_lint. + +Thu Jul 1 19:22:33 2010 Arnold D. Robbins + + Add support for /inet4/... and /inet6/... files. + + * io.c (socketopen): New parameter `family' for address family. + (inetfile): New function. Changed everywhere to use it and + the values it sets. + +Fri Jun 25 01:01:39 2010 Arnold D. Robbins + + * main.c (main): Added short option letters for all long options + that didn't have them so that they can be used in #!. This + reinstates -r, FWIW. + (usage): Revised message to list standard options first, then + options for extensions, sorted by short letter. + +Mon Jun 21 23:05:20 2010 Arnold D. Robbins + + New FPAT variable and patsplit built-in function. + + * awk.h (NODETYPE): Add Node_FPAT. + (FPAT_node, do_patsplit, set_FPAT): Declare. + (set_FPAT, update_PROCINFO_str, update_PROCINFO_num, + current_field_sep): New functions. + * awkgram.y (tokentab): Add patsplit. + (snode): Add code for do_patsplit to default third arg to FPAT. + (isnoeffect, isassignable): Add cases for Node_FPAT. + * eval.c (nodetypes): Add FPAT. + (r_tree_eval, r_get_lhs): Add cases for Node_FPAT. + * field.c (fpat_parse_field, update_PROCINFO_num, set_FPAT, + do_patsplit): New functions. + (update_PROCINFO): Renamed to update_PROCINFO_str. + (FPAT_re_yes_case, FPAT_re_no_case, FPAT_regexp): New variables. + (using_FIELDWIDTHS): Replaced with current_field_sep and all calls. + * io.c (set_RS): Call current_field_sep insead of using_fieldwidths. + * main.c (main): Use update_PROCINFO_str and update_PROCINFO_num + instead of manually updating the array. + (varinit): Add FPAT. + * profile.c (tree_eval, pp_lhs, is_scalar, pp_var): Add case for + Node_FPAT. + +Fri Jun 12 13:25:32 2009 Arnold D. Robbins + + Make command line arguments that are directories a warning. + They remain a fatal error if --posix or --traditional. + + * configure.ac: Remove the --disable-directories-fatal option. + * io.c (nextfile): Rationalize the code that handles directories, + including setting ERRNO correctly. + +Thu Feb 26 20:57:52 2009 Arnold D. Robbins + + Changes from August 2008 through February 2009 to add + BEGINFILE and ENDFILE, originally against 3.1.6, merged into + development version. + + * awk.h (in_beginfile_rule, in_endfile_rule): Add declarations. + * awkgram.y (beginfile_block, endfile_block): Add declarations. + (beginfile_or_endfile_rule, parsing_endfile_rule): New variables. + (LEX_BEGINFILE, LEX_ENDFILE): New tokens, new rules for those tokens. + (tokentab): Add new entries for BEGINFILE, ENDFILE. + (LEX_NEXTFILE): Allow nextfile in BEGINFILE rule. + (LEX_GETLINE): Allow only `getline var < file' inside BEGINFILE or + ENDFILE. + * eval.c (interpret): Check in_beginfile_rule and in_endfile_rule for + errors for next and nextfile. + (update_ERRNO_saved): When errno == 0, set to ERRNO to + null string. + (interpret): Allow nextfile in BEGINFILE rule. + (update_ERRNO_saved): Check errcode paramater, not global errno. + * io.c (beginfile_block, endfile_block, in_beginfile_rule, + in_endfile_rule): New variables. + (do_input): Set them. Update ERRNO only if not do_traditional. + Propogate error code down to fatal message. + (run_beginfile_rule, run_endfile_rule): New functions. + (iop_alloc): Use it instead of inline code. Add fourth argument + indicating that the open hooks should run. Adjust calls. Point is + to not call open hooks twice inside `nextfile'. + (do_nextfile): Check it and also in_beginfile_rule and only longjump + when both filebuf valid and not in a BEGINFILE rule. + (nextfile): Call run_beginfile_rule and run_endfile_rule as + appropriate. Reorder the logic to set ERRNO and allow BEGINFILE + to call nextfile to skip a bad data file. Adjust calls to + iop_open and find_open_hook. + (nextfile): Call iop_alloc if there's a BEGINFILE block in case + the hooks changed. + (find_open_hook): New function. + (get_a_record): On read error, just set *errcode and return. Let + higher level logic decide if it's fatal. + (inrec): Have error be fatal if traditional or if there isn't + an ENDFILE rule. + * profile.c (dump_prog): Add code for BEGINFILE / ENDFILE. + * awk.h (dump_prog): Adjust declaration. + * main.c (main): Adjust call to `dump_prog'. Check beginfile_block and + endfile_block also to be not NULL in order to call do_input. Thanks to + Steffen Schuler for pointing out the bug. + +Thu Feb 26 07:54:51 2009 Arnold D. Robbins + + Per advice from BWK and my own feelings, nuke additions from 2001 + of seek and tell functions. They were never documented anyway. + + * awk.h (do_seek, do_tell): Remove declarations. + (IOBUF): Remove save_start and rec_size members. + * awkgram.y (tokentab): Remove "seek" and "tell" entries. + * io.c (do_getline): Remove code setting save_start and rec_size. + (iop_alloc): Remove code initializing save_start and rec_size. + (do_seek, do_tell): Removed. + * configure.ac: Remove --enable-seektell option. + +Mon Feb 16 21:54:13 2009 Arnold D. Robbins + + * awkgram.y (tokentab): Enable switch / case by default. + * configure.ac: Remove test for --enable-switch. + +Thu Feb 12 22:06:17 2009 Arnold D. Robbins + + * main.c (optab): --gen-po becomes --gen-pot. -r goes away since it's + now on by default. + (usage): Similar changes. + * regex.h [RE_SYNTAX_GNU_AWK, RE_SYNTAX_POSIX_AWK]: Adjust to support + interval expressions. + [RE_DEBUG]: Nuke: it is no longer used. + * re.c (resetup): Adjust comment for do_intervals. + (reflags2str): Remove RE_DEBUG. + +Sat Jan 17 20:41:54 2009 Arnold D. Robbins + + * awk.h (WSTRCUR): Always define, no real need for ifdef. + * eval.c (flags2str): Similar. + * field.c (rebuild_record): Similar. + +Sat Jan 17 19:59:39 2009 Arnold D. Robbins + + Add indirect function calls. They require a special + syntax, which is an `@' in front of a function call. + + * awk.h (NODETYPE): New Node_indirect_function_call value. + (ASSIGNED): New flag value. + * eval.c (nodetype2str): Add new node type. + (flags2str): Add ASSIGNED. + (func_call): Test the node type to determine + what kind of call. Cache the function body if a real function + is called indirectly. Also get scoping right if called from a function. + LOTS of work here to get this code right! + (op_assign): Add ASSIGNED to flags. + * awkgram.y (function_call, direct_function_call): New productions for + creating indirect function calls. Only call func_use for direct call. + (yylex): Add case for '@'. Only return it if not posix or traditional. + * profile.c (tree_eval): Add case for Node_indirect_func_call. + (pp_func_call): Check type and print '@' for indirect call. + +Tue Dec 30 22:25:04 2008 Assaf Gordon + + * awk.h (do_sandbox): New variable declaration. + * main.c (do_sandbox): Variable definition. + (opttab): Add new option --sandbox. + (usage): Add to usage message. + * builtin.c (do_system): Disallow if sandboxed. + * io.c (redirect): Disallow redirections if sandboxed. + +Tue Dec 30 22:22:04 2008 Arnold D. Robbins + + * builtin.c (usage): Change --binary to --characters-as-bytes, + per Karl Berry. + +Thu Dec 18 05:29:46 2008 Steffen Schuler + + * field.c (*_parse_field): Add `sep_arr' argument and fill it. + * field.c (do_split): Add handling of fourth argument of awk + builtin `split'. + * field.c (get_field): Extend parse_field by default argument. + * awkgram.y (tokentab): Extend `split' entry with fourth argument. + +Wed Dec 17 09:54:00 2008 Arnold D. Robbins + + * main.c (do_binary): New variable for new option -b which + makes gawk not mess with multibyte strings. + (opttab): Add option entry for -b / --binary. + (main): If do_binary, set gawk_mb_cur_max to 1. + +Sat Oct 27 22:43:50 2007 Arnold D. Robbins + + * re.c (resetup): Add RE_INVALID_INTERVAL_ORD to syntax bits if + doing interval expressions. + +Thu Oct 25 23:11:10 2007 Arnold D. Robbins + + * awk.h (devopen): Add `isdir' pointer argument. + * io.c (devopen): Ditto. Adjust logic that checks for directory. + Adjust all calls. + * main.c (main): Adjust call to devopen. + +Sun Oct 3 23:18:44 2004 Arnold D. Robbins + + * dfa.c (lex): Enabled \s and \S escape sequences. + * regcomp.c (peek_token): Ditto. + +Tue Aug 3 13:29:53 2004 Arnold D. Robbins + + * builtin.c (sub_common): Make POSIX 2001 behavior the + default for `sub' and `gsub'. + +Wed Aug 21 13:39:08 2002 Dean Wakerly + + * main.c (main): Add short option letter 'r' for --re-interval. + Mainly for use in #! scripts. + +Wed Dec 26 22:03:48 2001 Arnold D. Robbins + + Nuke /dev/pid etc. special files! + + * awk.h (IOP_IS_INTERNAL, IOP_NO_FREE): Removed. Other defines + renumbered. + * io.c (iop_open, spec_setup, specfdopen, pidopen, useropen): Removed. + (do_input, redirect): Change uses of iop_open() to devopen() + + iop_alloc(). + (iop_close, get_a_record): Remove special handling for IOP_INTERNAL, + IOP_NO_FREE. + (devopen): Remove comment relating to iop_open. + Add fstat check for valid fd for /dev/fd/N. + +Sun Nov 4 10:27:58 2001 Arnold D. Robbins + + * awk.h, builtin.c, awkgram.y: Renamed mark/reset to tell/seek. + * acconfig.h: Add `#undef SEEK_TELL'. + * configure.in: Add `--enable-seektell' configure-time option. + * io.c (do_seek, do_tell): renamed from do_reset, do_mark. + +Thu Aug 16 12:21:28 2001 Arnold D. Robbins + + New feature, undocumented for now, use #define MARK_RESET to + to turn it on. New function val = mark("/some/file") to + save start position of current record. Use + reset("/some/file", pos) to go back to it. ONLY works + with getline. + + * awk.h (IOBUF): New members save_start and rec_size. + (do_mark, do_reset): Add declarations. + * awkgram.y (tokentab): Add entries for mark and reset. + * io.c (specsetup): Initialize save_start and rec_size. + (iop_alloc): Ditto. + (do_getline): Update them as appropriate. + (do_mark, do_reset): New functions. + +Fri Sep 17 12:42:42 2010 Arnold D. Robbins + + * regcomp.c (btowc): Changed to use mbrtowc. + +Wed Sep 15 08:26:55 2010 Arnold D. Robbins + + * dfa.c: Further sync with GNU grep. + +Tue Sep 14 09:53:55 2010 Arnold D. Robbins + + * node.c (str2wstr): Per advice from Ulrich Drepper, when converting, + if the current byte is isprint, isgraph, iscntrl or zero, then it + can't start a multibyte character. This can save many calls to + `mbrtowcs', and speed up the conversion considerably. + +Mon Sep 13 11:19:21 2010 Arnold D. Robbins + + * dfa.h, dfa.c: Sync with GNU grep. + * re.c (dfawarn): New routine for use by dfa. + +Sun Sep 12 22:17:02 2010 Arnold D. Robbins + + * profile.c (tree_eval): Fix comment on for ... delete array loop. + (pp_string_fp): Get escapes right on regex constant. + +Sun Sep 5 20:38:42 2010 John E. Haque + + * re.c (str2wstr): Decrement src_count when skipping bad bytes. + +Fri Aug 27 13:51:13 2010 Arnold D. Robbins + + * dfa.c: Sync with current GNU grep - minor edits only. + +Fri Aug 20 16:26:14 2010 Arnold D. Robbins + + * profile.c (tree_eval): Always parenthesize Node_cond_exp. + May add a few extra parens but guarantees the right semantics. + Thanks to Hermann Peifer for the bug report. + +Thu Aug 19 21:35:13 2010 Arnold D. Robbins + + * regex_internal.c (re_string_reconstruct): Move ifdef out to cover + variable declarations, to avoid "unused variable" warnings. + * regexec.c (check_arrival_add_next_nodes): Bracket declaration of + `err' with ifdef for the same reason. + + Thanks to avarab@gmail.com for the suggestions. + +Wed Aug 18 22:13:30 2010 Arnold D. Robbins + + * Makefile.am (AUTOMAKE_OPTIONS): Added. Other minor cleanups. + +Tue Aug 17 23:27:43 2010 Arnold D. Robbins + + * profile.c (pp_string_fp): Use different sets of escape characters + if printing a string or a regex, based on delimiter. Thanks to + Hermann Peifer for the bug report. + +Sun Aug 8 23:05:09 2010 Arnold D. Robbins + + * re.c (make_regexp): Don't allocate rp->dfareg unless + we're using dfa; causes a memory leak otherwise. Thanks to + Antonio Columbo for reporting the bug. + +Wed Jul 14 23:04:30 2010 Eli Zaretskii + + * dfa.c: Include langinfo.h only if HAVE_LANGINFO_CODESET is + defined. + +Wed Jul 14 23:00:19 2010 Arnold D. Robbins + + * awkgram.y (yylex): Allow a backslash before CR-LF to also + work for line continuation, for MS-DOS style source files. + Thanks to (Vincent Belaiche) for pointing this out. + +Wed Jul 14 22:31:53 2010 Arnold D. Robbins + + * node.c (str2wstr): Keep going if get a bad multibyte sequence. + Allows match to give correct answers for RSTART, RLENGTH. + Add a lint warning. Correctly set the length of the string + based on pointer subtraction. + +Wed Jun 16 21:52:09 2010 Arnold D. Robbins + + * awk.h (exec_count): Moved into NODE structure as standalone + element since count on `/pat/ { ... }' was wrong. Thanks to + Hermann Peifer for the bug report. + + Note to self: DO NOT propogate this to the byte-code version. + + Unrelated: + + * awkgram.y (matchop): Made left associative to match behavior + of other awks. + (print_expression_list): Simplified so that something like + `print ("a", "b") in B in A' will work. Again, to match what + other awks do. + +Fri Jun 4 15:56:59 2010 Arnold D. Robbins + + * dfa.c: Further merges with GNU grep. + +Thu May 20 22:20:32 2010 Stepan Kasal + + * Makefile.am [AUTOMAKE_OPTIONS]: Removed, contents now in ... + * configure.ac [AM_INIT_AUTOMAKE]: ... here. + Added dist-xz while I'm at it, per Karl Berry. + +Tue May 18 14:52:04 2010 Marcin Szewczyk + + * builtin.c (format_tree): Simplify code in pr_tail when multibyte + and %s or %d. + +Thu May 6 20:55:14 2010 Arnold D. Robbins + + * Release 3.1.8: Release tar file made. + +Fri Apr 30 11:37:54 2010 Arnold D. Robbins + + * configure.ac: Remove check for libsnprintf. + +Tue Apr 27 22:23:26 2010 Andreas Schwab + + * builtin.c (do_mktime): Make lint check more sane. + Fix overflow check. Removes GCC warning that Arnold + incorrectly didn't like. + +Mon Apr 26 20:16:07 2010 Arnold D. Robbins + + * ltmain.sh: Removed. + * builtin.c (do_mktime): Restored old code to match the + documentation. We now have a warning that we just have to + live with. Sigh. Stupid GCC. Added a lint warning though. + (format_tree): More code so that %'d acts like %d on systems + without . + * main.c (main): Add `&& #if defined(HAVE_LOCALE_H)' for + call to setlocale. + +Wed Apr 21 23:35:43 2010 Arnold D. Robbins + + * Makefile.am: Change quoting of -Dargs so that even tcsh + users will be happy. + * regex_internal.c (MAX): Add `#undef MAX', just in case. + * configure.ac: Don't look for libsigsegv on OSF/1, gives + us severe headaches. + +Tue Apr 20 12:01:01 2010 Arnold D. Robbins + + * dfa.h, dfa.c: Sync with GNU grep. The long-standing x{0} bug + is now gone. Matching UTF-8 with "." is now much faster. + * re.c (avoid_dfa): Remove call to dfabroken() which is now gone. + * builtin.c (do_mktime): Simplify check of values passed in to be + more readable and to avoid a weird compiler warning from GCC. + +Fri Apr 16 15:02:26 2010 Arnold D. Robbins + + * array.c (assoc_lookup): Add cast in error message to turn + off compiler warning. + * dfa.c (is_blank): New function. Use it everywhere instead of + ctype.h `isblank' macro which isn't available universally. + +Tue Apr 13 22:36:31 2010 Arnold D. Robbins + + * array.c, awkgram.y, builtin.c, dfa.c, eval.c, ext.c, main.c, + node.c, re.c: Remove old ISxxx and TOxxx macros in favor of + standard versions. ``We're two wild and crazy guys!'' + +Tue Apr 13 22:07:18 2010 Arnold D. Robbins + + * getopt.c, getopt.h, getopt1.c, getopt_int.h, regcomp.c, regex.c, + regex.h, regex_internal.c, regex_internal.h, regexec.c: Sync with + glibc. What the heck. + +Thu Apr 8 21:33:09 2010 Arnold D. Robbins + + * dfa.h, dfa.c: All leading indentation is now spaces only. Yet + another sync with grep. + +Thu Apr 8 20:45:25 2010 Arnold D. Robbins + + Move dfa internals into dfa.c and sync with grep. Avoids VMS and + z/OS compile problems in order to avoid cygwin issue when used + with ligsigsegv. ("Portability? We don't need no stinkin' + portability!") + + * dfa.h: Move all the internals into dfa.c. + (dfaalloc, dfamusts, dfabroken): Add declarations. + * dfa.c: Accept all the internals. + (dfaalloc, dfamusts, dfabroken): New functions. + * awk.h (Regexp): Use a `struct dfa *'. + * re.c (make_regexp): Call dfaalloc. Adjust uses of dfareg + in other routines. + (refree): Free the dfa struct too. + +Tue Apr 6 23:06:55 2010 Arnold D. Robbins + + * dfa.h, dfa.c: Further sync with GNU grep for enum change + and other misc changes. + +Tue Apr 6 20:13:45 2010 Michal Jaegermann + + * main.c: Wrap declarations and bodies of `catchsegv' and + `catchstackoverflow' in #ifdef HAVE_LIBSIGSEGV to avoid + "not used" warnings. + +Tue Apr 6 20:11:47 2010 Arnold D. Robbins + + * dfa.h: Move definition of token enum to dfa.c to avoid conflict + with Windows WCHAR introduced by libsigsegv. Thanks to Corinna + Vinschen. + * dfa.c: Enum body here. + (in_coll_range): z/OS fix: Initialize array to all zeros and assign + values instead of putting them into the initializer. Thanks to Dave + Pitts for reporting the problem. + +Fri Apr 2 12:32:40 2010 Arnold D. Robbins + + * dfa.c: Sync with grep 2.6.3. + +Wed Mar 31 15:50:34 2010 Arnold D. Robbins + + * dfa.c (dfaexec): Move decl of `saved_end' up to top of function. + Fixes compilation on C89 compilers. + +Mon Mar 29 08:40:29 2010 Arnold D. Robbins + + Remove local copy of libsigsegv. Use an external copy if available. + + * Makefile.am: Remove SEGVSUBDIR and SEGVINCLUDE. + * configure.ac: Remove previous code that handled the library and use + gl_LIBSIGSEGV library. + * custom.h: Remove code for HAVE_SIGSEGV_H. + * main.c: Move to HAVE_LIBSIGSEGV. + * libsigegv/ : Removed. + +Mon Mar 29 05:41:35 2010 Corinna Vinschen + + * dfa.c: Include hard-locale.h after xalloc.h because it needs + xmalloc. + * hard-locale.h (xmalloc): Remove declaration. + (hard_locale): Cast xmalloc to correct target type. + +Mon Mar 29 05:38:47 2010 Arnold D. Robbins + + * io.c: (two_way_open): In counting down retries, test for > 0 + instead of >= 0 since retries is unsigned. Thanks to Pat Rankin + for noticing. + * configure.ac: Remove use of -export-dynamic on cygwin. + +Thu Mar 25 21:48:13 2010 Arnold D. Robbins + + * dfa.c: Sync to grep 2.6.1. That's probably enough for now. + +Wed Mar 24 19:48:01 2010 Arnold D. Robbins + + * dfa.c: More sync with grep. + +Tue Mar 23 19:42:48 2010 Jeff Chua + + * io.c (two_way_open): Bug fix in management of timeout value. + +Tue Mar 23 19:40:04 2010 Arnold D. Robbins + + * dfa.h, dfa.c: Synced with released grep 2.6. Oh Frabjous Day! + Callou! Callay! + +Mon Mar 22 22:49:44 2010 Arnold D. Robbins + + * awkgram.c: Regenerated using bison 2.4.2. + +Fri Mar 19 10:19:20 2010 Arnold D. Robbins + + * dfa.c: Minor edits for compat with grep. + +Fri Mar 19 09:19:56 2010 Arnold D. Robbins + + * io.c (two_way_open): Cleanup new code for socket opens. + * replace.c: Include missing_d/usleep.c based HAVE_USLEEP. + * configure.ac: Add usleep to list of functions to look for. + +Thu Mar 18 23:30:33 2010 Arnold D. Robbins + + * dfa.h, dfa.c: Imported from GNU grep and merged. Passes "make test". + * xalloc.h: New file, needed by dfa.c. + * Makefile.am (base_sources ): Added xalloc.h. + +Thu Mar 18 07:29:45 2010 Jeff Chua + + * io.c (two_way_open): Make failure to open a socket a non-fatal error. + Allow the amount of time to sleep during socket retries to come from an + undocumented env variable giving time in milliseconds. + +Mon Mar 8 20:58:05 2010 Paolo Bonzini + + More fixes from GNU grep. + + * dfa.c (dfaexec): Remove register keywords. + (FETCH): Use do..while(0) idiom. + (parse_bracket_exp_mb): Return MBCSET. + (in_coll_range): New. + (lex): Assign return value of parse_bracket_exp_mb to lasttok, + return it. Use in_coll_range instead of regcomp/regexec. + +Mon Mar 8 20:36:35 2010 Jim Meyering + + Fixes from GNU grep development version: + + build: avoid shadowing warnings + * dfa.c (match_mb_charset): Rename parameter: s/index/idx/. + (check_matching_with_multibyte_ops, match_anychar): Likewise. + + build: avoid shadowing warning for unused "rs" + * dfa.c (transit_state): Remove dead stores; + Ignore transit_state_consume_1char return value. + + syntax: remove trailing blanks + * dfa.c: Remove trailing blanks, to ease synchronization with grep. + + clean-up: limit visibility of an internal function + * dfa.c (match_mb_charset): Declare static. + + build: rename local to avoid shadowing global, dfa + * dfa.c (dfamust): Rename parameter: s/dfa/d/. + +Thu Feb 18 22:44:01 2010 Arnold D. Robbins 0 + + * eval.c (push_args): Clear the stack to NULL pointers after mallocing + it. Fixes yesterday's problem when called from a rule. + See test/fcall_exit2.awk. Thanks to Seb . + +Wed Feb 17 23:19:32 2010 Arnold D. Robbins + + * eval.c (pop_fcall): Check that argument on stack is not NULL before + attempting to clear it; add comment explaining it. + (push_args): Set nodes to zero for argument to make sure that values + are NULL for testing later in pop_fcall. See test/fcall_exit.awk. + Thanks to Seb . + +Sun Jan 31 22:46:49 2010 Arnold D. Robbins + + * profile.c (prec_level): Add Node_regex to the switch so that + `! /xxx/' works. Thanks to Hermann Peifer for + reporting the bug. + +Thu Jan 28 17:40:14 2010 Arnold D. Robbins + + * configure, Makefile.am: Updated to Autoconf 2.65 and Automake 1.11.1, + libsigsegv 2.8. + +Thu Jan 21 23:24:56 2010 Arnold D. Robbins + + * profile.c (pprint): Separate out code for Node_switch_body and only + print the lnode; avoids printing the default case twice. Thanks to + Hermann Peifer for reporting the bug. + +Sun Jan 3 21:03:01 2010 Arnold D. Robbins + + * dfa.c: Added casts as needed to silence warnings about + signedness of pointers from GCC 4.x. + +Fri Jan 1 11:41:50 2010 Arnold D. Robbins + + * builtin.c (format_tree): At pr_tail, remember to take the precision + into account when determining how many characters to copy out. + Thanks to tczy for the bug report. + +Tue Dec 8 12:29:30 2009 Arnold D. Robbins + + * configure.ac, awk.h: Remove use of header file. + +Mon Dec 7 15:25:02 2009 Arnold D. Robbins + + * node.c (format_val): Use <= and >= in the comparisons with + LONG_xxx instead of < and > so that things work correctly on systems + with 64 bit integers. Thanks to Stephen Davies for pointing out + the problem. + +Sat Nov 21 23:14:59 2009 Arnold D. Robbins + + * builtin.c (format_tree): If there is not an actual thousands + separator character, don't let `quote_flag' have an effect. Fixes + test failure on Solaris 10, which bizarrely says to use the + thousands separator character every three digits, but then doesn't + actually supply one. Thanks to Nelson Beebe for the initial + report. + +Mon Nov 16 22:27:44 2009 Arnold D. Robbins + + * awk.h (getnode): If MPROF wrap body in parentheses; remove + incorrect trailing semicolon. + * bisonfix.awk: Convert "y.tab.c" to "awkgram.c" for those rare + instances where we need to use a debugger on the parser so + that gdb will find the right source file. + +2009-10-26 Andreas Schwab + + * io.c (iop_open): Set errno when rejecting a directory. + +Tue Oct 20 22:48:14 2009 Arnold D. Robbins + + * awkgram.y (constant_fold): Fix check for two strings to look + at `right->flags'. Fix division code to check for division by + zero first. Thanks to Stephen Davies + for both. + +Fri Oct 16 08:41:29 2009 Arnold D. Robbins + + * io.c (redirect): Do the close-on-exec setting before + attempt to get a FILE *. Thanks to Andreas Schwab. + +Wed Oct 14 23:25:47 2009 Arnold D. Robbins + + * io.c (redirect): When opening a file, set the close-on-exec flag. + Thanks to Chris Pearson for the bug report. + +Tue Oct 6 21:07:23 2009 Arnold D. Robbins + + * main.c (main): When an option requires an argument and we print a + message, call `usage' and exit. + + Fix all calls to `usage' to use EXIT_FAILURE and EXIT_SUCCESS + instead of 1 and 0. + +Sun Oct 4 21:46:11 2009 Arnold D. Robbins + + * main.c (main): Don't reset argv[0] to myname. In call + to `init_args', pass argv[0] if do_posix. Based on + Fedora bug report. + +Sun Oct 4 18:45:06 2009 Arnold D. Robbins + + * array.c (assoc_lookup): In lint warning, don't clobber + the character at the end of the subscript; instead use the + length to limit the number of characters printed. Thanks to + Nick Hobson . + +Sun Aug 30 22:40:12 2009 Arnold D. Robbins + + * builtin.c (do_length): Handle the case where Node_var_new + was passed in as a parameter via a function call parameter. + Thanks to Greg Johnson for reporting + the bug. + +Tue Aug 11 19:23:51 2009 Arnold D. Robbins + + * profile.c (parenthesize_expr): New function. + (tree_eval): Use it for Node_and and Node_or. Thanks to + Hermann Peifer for reporting the bug. + +Tue Aug 4 06:04:23 2009 Arnold D. Robbins + + * builtin.c (format_tree): zero_flag does not apply to + %c and %s conversions. Thanks to Mike Brennan and Thomas Dickey + for the bug report. + +Tue Jul 21 22:28:56 2009 Arnold D. Robbins + + * Release 3.1.7: Release tar file made. + +Fri Jul 17 08:35:10 2009 Arnold D. Robbins + + * awkgram.c: Rebuilt with current Bison (2.4.1). + +Thu Jul 9 22:55:17 2009 Arnold D. Robbins + + * (NEWS README array.c awk.h awkgram.y builtin.c configure + configure.ac custom.h dfa.c ext.c field.c floatcomp.c io.c + main.c node.c profile.c re.c replace.c): Update copyrights + and other prep for a release. + +Thu Jul 9 22:20:04 2009 Arnold D. Robbins + + * main.c (init_locale): New function to make a deep copy of the + struct lconv. Thanks to KIMURA Koichi + for the info. + * eval.c (r_tree_eval): Further improve Node_assign_concat code to + temporarily to keep reference counts correct and to get the + desired behavior. + +Mon Jul 6 20:29:12 2009 Arnold D. Robbins + + * floatmagic.h: Remove @ signs copied from Texinfo. + It would help if I were more awake. + +Sat Jul 4 21:55:18 2009 Arnold D. Robbins + + * Makefile.am (base_sources): Add floatmagic.h so it'll + go into the tar ball. + +Fri Jul 3 13:47:36 2009 Arnold D. Robbins + + * profile.c (is_scalar): Add Node_func_call to list. + (pp_concat): Make logic smarter for tree created by Node_assign_concat. + +Fri Jul 3 13:01:49 2009 Arnold D. Robbins + + * awkgram.y (optimize_concat): New function that applies + Node_assign_concat more generally. + * eval.c (r_tree_eval): Improve Node_assign_concat code to temporarily + increase the stref on `l' to avoid side effects during evaluation of + `r'. This makes test/nasty.awk work. Ouch. + +Tue Jun 30 22:10:37 2009 Arnold D. Robbins + + * floatmagic.h: New file. + * builtin.c (format_tree): Use functions defined in floatmagic.h. + +Tue Jun 30 21:57:47 2009 Arnold D. Robbins + + * configure.ac, Makefile.am: Add new --disable-libsigsegv command line + option to configure. + (LIBSIGSEGV, SEGVINCLUDE, SEGVSUBDIR): New variables that will be empty + if libsigsegv is disabled so nothing will happen, and that will have the + right values otherwise. They are then substituted into the Makefile. + +Wed Jun 24 23:00:10 2009 Arnold D. Robbins + + * bootstrap.sh: Revised. Now works again. We think. (CVS-only file) + +Wed Jun 24 21:57:30 2009 Arnold D. Robbins + + * custom.h: Move z/OS EXIT_FAILURE definition from here to ... + * awk.h: Here. Define at end after regular definition. + +Thu Jun 18 06:17:38 2009 Scott Deifik + + * awk.h: Don't define HAVE_SIGSEGV_H for DJGPP. + +Thu Jun 18 05:38:42 2009 Dave Pitts + + * custom.h: Changes needed for z/OS. + +Wed Jun 10 08:22:53 2009 Arnold D. Robbins + + * node.c (parse_escape): Add a lint warning if \x.. has more than two + hex digits. + +2009-06-08 gettextize + + * configure.ac (AM_GNU_GETTEXT_VERSION): Bump to 0.17. + +Mon Jun 8 22:13:49 2009 Arnold D. Robbins + + Update to Autoconf 2.63, Automake 1.11, Libtool 2.2.6a + + * ltmain.sh: New file. + * configure.ac: Changes to keep infrastructure tools happy. + * alocal.m4, configure: Regenerated. + * Makefile.in, */Makefile.in: Regenerated. + +Mon Jun 8 07:43:25 2009 John DuBois + + * builtin.c (mbc_byte_count, mbc_char_count): Make sure all declarations + come before executable code, for older compilers. + * dfa.c (insert): Ditto. + * io.c (devoopen): Ditto. + +Thu May 21 21:11:44 2009 Arnold D. Robbins + + Add simple constant folding. + + * awk.h (do_optimize): New declaration. + (calc_exp): Add declaration. + * eval.c (calc_exp): Make non-static. + * main.c (do_optimize): New variable. + (opttab): Add new entry for --optimize. + (main): Add 'O' to optlist and code for argument parsing. + (usage): Update for new option. + * awkgram.y (Node_concat, Node_exp, Node_times, Node_quotient, Node_mod, + Node_plus, Node_minus): Call `constant_fold' to create the node in + the tree. + (constant_fold): New function. + +Fri May 15 16:02:01 2009 Arnold D. Robbins + + * awk.h (getnode): For MPROF: Fix a typo. + +Fri May 15 14:10:44 2009 Arnold D. Robbins + + Function arguments cannot be reserved variable names, per POSIX. + + * main.c (struct varinit): Add flags member. + (varinit): Add values for flags member (one or both of NON_STANDARD + or NO_INSTALL). Add entries for the rest of the gawk variables and + sort them, so that the table can be searched by ... + (is_std_var): New routine to see if a name is a standard variable. + * awk.h (is_std_var): Add declaration. + * awkgram.y (func_install): Use new routine and issue error. + +Wed Apr 22 07:42:05 2009 Arnold D. Robbins + + * builtin.c (sub_common): In code for handling \ replacements, + first make sure that is within the range of parentheses sets + given, and then make sure that the subpattern start is not -1, meaning + that something actually matched. Thanks to Martin Olsson + for the bug report. + (do_length): Add a lint warning if `length' is passed an untyped + argument. + +Thu Apr 16 22:59:32 2009 Arnold D. Robbins + + * eval.c (func_call): Save nloops_active; if after function returns + the actual nloops_active is greater than the saved value, it means + there was a return inside the loop body, so pop off the necessary + number of loops. Bug reported by Aleksey Cheusov . + Gawk was not leaking memory - that is, things were still pointed + to, but memory use could keep on growing. + +Fri Mar 27 10:59:11 2009 Arnold D. Robbins + + * builtin.c (format_tree): Add lint warnings for fieldwidth and/or + precision in %%, and add lint warning for unknown format specifier + (e.g. %b). Thanks to "joanes.polus" for + the report. + +Wed Mar 18 18:15:41 2009 Pat Rankin + + * awk.h (EXIT_SUCCESS, EXIT_FAILURE): Move VMS-specific values + to vms/vms-conf.h. + (EXIT_FATAL): Define here instead of in msg.c. + * msg.c (EXIT_FATAL): Move definition to awk.h. + +Mon Mar 16 18:58:09 2009 Pat Rankin + + * main.c [#if HAVE_SIGSEGV_H]: For the #else case (VMS), + (stackoverflow_context_t): Dummy typedef for use in prototypes; + (stackoverflow_install_handler): Make macro expand to 0 rather + than nothing so that (void) cast on invocation of it works. + + * main.c (catchstackoverflow): Don't return 0 from void function. + +Wed Feb 25 21:34:14 2009 Arnold D. Robbins + + * awkgram.y (tokentab): Have only one copy of BEGIN / END. + (tokcompare): New function. + (check_special): Sort tokentab for EBCDIC systems. + +Sun Feb 15 22:39:30 2009 Arnold D. Robbins + + * profile.c (pp_delete): Print tree->exec_count to actually get + the value printed. Thanks to Hermann Peifer + for reporting the bug. + +Thu Feb 12 21:54:34 2009 Arnold D. Robbins + + * awkgram.y: Change to use EXIT_FAILURE. + * msg.c [EXIT_FATAL]: New macro. + * msg.c (r_fatal): Change to use EXIT_FATAL. + Thanks to Pat Rankin for pointing these out. + * re.c (reflags2str): Account for RE_SYNTAX_EMACS. + * awk.h: If not VMS, define HAVE_SIGSEGV_H. + * main.c: Check HAVE_SIGSEGV_H before including . If not + there, define dummy macros. + (catchsegv, catchstackoverflow): Remove unneeded comment. Add return 0 + for compilers that care. + +Mon Feb 9 05:24:52 2009 Arnold D. Robbins + + * awk.h [CONST]: Renamed CONSTANT to avoid conflict with libsigsegv + on Windows. + * awkgram.y, field.c, re.c: Update all uses. + +Tue Feb 3 22:46:59 2009 Arnold D. Robbins + + * io.c (do_close): Wrap updating of ERRNO in check for not + do_traditional. + +Sat Jan 31 23:14:00 2009 Arnold D. Robbins + + * builtin.c (format_tree): For '%s', don't count the multibyte + characters if we are just copying all the characters. Gives + big speedup. Thanks to Hirofumi Saito + for reporting the problem. + +Thu Jan 29 21:14:30 2009 Arnold D. Robbins + + * field.c (parse_field, re_parse_field, def_parse_field, + posix_def_parse_field, null_parse_field, sc_parse_field, + fw_parse_field): Add new last arg `in_middle'. Ignored by all + except re_parse_field. + (re_parse_field): Enhance logic to only allow ^ in a regex to match + if indeed at the beginning of a record. + (getfield): Adjust call to parse_field. + +Tue Jan 27 21:42:47 2009 Arnold D. Robbins + + Changes suggested by Toni Schilling , + as modified by feedback from Pat Rankin, and some help + from me. + + * awk.h [WEXITSTATUS]: Improve definition for MSC and VMS. + [EXIT_SUCCESS, EXIT_FAILURE]: Define if they aren't. + * io.c, main.c, profile.c: Switch to using EXIT_xxx instead of + 0 and 1. + (main): Use constants instead of 0/1 for exit_val variable. + * eval.c (interpret): Map exit value from `exit' statement into + success / fail constants for VMS for exit_val variable. + +Tue Jan 20 07:35:34 2009 Arnold D. Robbins + + * regex.h: Define __USE_GNU if not _LIBC; needed for non-GLIBC + systems such as, oh say, Mac OS X. + +Tue Jan 13 09:23:40 2009 Arnold D. Robbins + + * regex.c, regex_internal.h: Remove some changes that are no + longer needed after sync with GLIBC. + +Mon Jan 12 22:27:10 2009 Arnold D. Robbins + + Bi-annual sync with GLIBC. + + * regexec.c, regex.h, regex_internal.c, regcomp.c, regex_internal.h, + regex.c: Reapply any portability patches specific to gawk. + * getopt.c: Sync with GLIBC. + + Base versions: + getopt.c 1.57 Thu Jan 8 20:02:05 2009 + getopt.h 1.21 Fri Mar 19 00:19:32 2004 + getopt1.c 1.10 Tue Mar 9 10:35:37 2004 + getopt_int.h 1.1 Tue Mar 9 10:31:19 2004 + regex.c 1.129 Tue Sep 6 20:49:44 2005 + regexec.c 1.99 Thu Jan 8 20:02:06 2009 + regexec.c 1.99 Thu Jan 8 20:02:06 2009 + regex.h 1.43 Wed Jan 16 10:09:47 2008 + regex_internal.c 1.69 Thu Jan 8 20:02:06 2009 + regex_internal.h 1.76 Thu Jan 8 20:02:06 2009 + regcomp.c 1.120 Thu Jan 8 20:02:06 2009 + +Mon Jan 5 23:07:58 2009 Arnold D. Robbins + + * io.c (devopen): Add a retry to calls to socketopen. Tunable + via undocumented GAWK_SOCK_RETRIES environment variable. Based + on code from Juergen Kahrs after a + suggestion from Hermann Peifer . + +Mon Jan 5 22:48:39 2009 Arnold D. Robbins + + * io.c (redirect): A getline from a directory is no longer + fatal; instead it returns -1. Thanks to Paolo + for the report. + +Mon Dec 29 22:04:57 2008 Arnold D. Robbins + + * builtin.c (format_tree): Case for 's', improve logic for setting + the number of characters to copy, also at pr_tail. Based on + bug report by Hermann Peifer . + +Thu Dec 11 21:23:50 2008 Arnold D. Robbins + + * builtin.c (do_length): If the wide string has zero length + but the bytes are more than zero, use the number of bytes. + (do_index): Similar also: fall back to byte count if the + bytes don't make a wide-character string. + Bug reported by "Carlos G." + + (do_substr): If defaulting to length of rest of the string, + do it based on the wide char string if it's valid. + +Fri Dec 5 11:12:11 2008 Arnold D. Robbins + + * io.c (free_rp): New function. + (redirect): Improved logic for yesterday's change, including + use of free_rp. + (close_redir): Use free_rp. + +Thu Dec 4 22:35:05 2008 Arnold D. Robbins + + * io.c (redirect): Only put the new struct redirect into + the list if the file or pipe could actually be opened. Fixes + a bug with the wrong return value of close, noticed by + Seb . + * dfa.c (parse_bracket_exp_mb): Don't zero out work_mbc->chars + after we malloc'ed it. Fixes a leak found by valgrind when + using UTF-8. (Hmmm. This got fixed in January 2007; It seems + to have crept back into the code in the August 2007 merge with + GNU grep. Sigh.) + +Mon Oct 20 11:47:59 2008 Arnold D. Robbins + + * configure.ac: Add -g3 and -gdwarf-2 to CFLAGS if compiling with + GCC and doing development. Should have done this ages ago. + +Sun Aug 31 22:03:55 2008 Arnold D. Robbins + + * eval.c (set_BINMODE): Tighten up the code even more so + that it matches the documentation. + +Mon Aug 25 22:41:47 2008 Arnold D. Robbins + + * eval.c (set_BINMODE): Tighten up the code to only allow + certain reasonable values when setting BINMODE. + +Fri Aug 22 14:43:49 2008 Arnold D. Robbins + + * io.c (nextfile): Users Strong In The Ways Of The Source can use + non-existant files on the command line without it being a fatal error. + +Wed Jul 30 23:10:51 2008 Arnold D. Robbins + + * re.c (research): Don't ever use DFA if need_start. It can + break on some weird cases. Reported by + "T. X. G." . + +Wed Jul 30 22:27:20 2008 Arnold D. Robbins + + * builtin.c (do_match): Add MAYBE_NUM flag to elements of array + created by `match' since data could come from user. Similar + semantics to `split'. Thanks to Dr. Dirk Zimoch + for reporting the bug. + +Tue Jun 24 07:44:06 2008 Arnold D. Robbins + + * dfa.c (insert): Reworked for significant speed improvement + by Johan Walles . Imported from grep + bug list. + * profile.c (tree_eval): Do a return after all the built-in + variables instead of a break. Thanks again to Hermann Peifer + for finding the problem. + +Sun Jun 22 23:08:14 2008 Arnold D. Robbins + + * node.c (format_val): Restore old code to use %ld when the value + is within the range of a long; improves performance noticably for + applications that convert integers to strings. Use %.0f only for + integral values that are outside the range of a long. Thanks to + Hermann Peifer for pointing out the existence + of a problem. + +Fri May 23 12:08:24 2008 Arnold D. Robbins + + * dfa.c (epsclosure): Change type of `visited' from int to char for + potential speedup. Based on bug report to bug-grep list from + Johan Walles . + +Wed May 14 05:55:48 2008 Arnold D. Robbins + + * builtin.c (format_tree): For `%c' case, add a lint warning + if the value is greater than 255. + (mbc_byte_count, mbc_char_count): Remove unused variable `i'. + +Thu Apr 24 20:31:03 2008 Bruno Haible + + * main.c (main): Move call to catch SIGBUS to before installation of + libsigsegv handler, since on some systems libsigsegv installs its + own handler for SIGBUS. + [STACK_SIZE]: Add a constant instead of inline. ADR. + +Wed Apr 23 22:30:27 2008 Duncan Moore + + * builtin.c (state): Do as an integer array for systems that need it. + (do_rand, init_rand): Modify call to `initstate' as needed. + +Wed Apr 23 22:22:06 2008 Arnold D. Robbins + + * dfa.c (prednames): Add an extra zero to final initializer to + silence a compiler warning. Reported by Duncan Moore + . + +Wed Apr 23 21:36:06 2008 Steffen Schuler + + * field.c (fw_parse_field): Add code for multibyte case. + +Sat Mar 15 22:17:21 2008 Arnold D. Robbins + + * builtin.c (do_length): Handle the case of the parameter being + an array that was a function parameter. + +Tue Mar 11 22:49:11 2008 Kimura Koichi + + * builtin.c (format_tree): Fix call to mbc_byte_count to pass the + right number of characters based on the format type. + +Tue Mar 11 22:31:58 2008 Arnold D. Robbins + + * libsigsegv: Incorporated into the dist. + * Makefile.am (SUBDIRS): Added. Make it first so that the library + is built before gawk is. + (LDADD): Add the library. + (AM_CPPFLAGS): Add -I option to find header. + * configure.ac: Add call to AC_CONFIG_SUBDIRS for libsigsegv. + * main.c (catchsegv, catchstackoverflow): New functions. + (main): Call into sigsegv library with them. + +Tue Mar 4 21:02:25 2008 Arnold D. Robbins + + * builtin.c (mbc_char_count, mbc_byte_count): New functions to return + the number of m.b. chars there are and the number of bytes needed to + copy them. + (format_tree): Use them for %s and %c cases to adjust precision and + for copying characters at pr_tail label. + +Thu Feb 14 14:05:01 2008 Arnold D. Robbins + + * main.c (init_args): Adjust type of third arg to remove warning from + GCC 4.2, add cast in call to make_string. Bleah. + +Fri Jan 25 12:13:39 2008 Dave Pitts + + * README_d/README.zos: New file. + * Makefile.am: Add sed on y.tab.c to convert older Bison "parse error" + messages to "syntax error" messages. + * configure.ac: Added ZOS_USS changes. + * m4/arch.m4: Added ZOS_USS changes. + * m4/inttypes_h.m4: Added ZOS_USS changes. + * m4/inttypes.m4: Added ZOS_USS changes. + * m4/stdint_h.m4: Added ZOS_USS changes. + * awkgram.y: Added USE_EBCDIC changes for EBCDIC collating sequence. + * awk.h: Added ZOS_USS compile changes. + * eval.c: Added EBCDIC casetable and ZOS_USS changes. + * regcomp.c: Added btowc function for ZOS_USS. + * regex.h: Changed __string to __cstring to avoid ZOS_USS header usage. + * regex_internal.h: Added ZOS_USS changes and type defines. + +Sun Jan 13 08:16:38 2008 Arnold D. Robbins + + * dfa.c (epsclosure): Replace MALLOC + zero-out-loop with CALLOC for + large potential speedup, based on bug report to bug-grep list from + Johan Walles . + (dfaanalyze): Made a similar change. + +Fri Dec 21 11:22:16 2007 Arnold D. Robbins + + * profile.c (pprint): Add a missing `#ifdef PROFILING'. + +Thu Dec 13 22:19:19 2007 Arnold D. Robbins + + * profile.c (parenthesize): Remove "!" from output string. + (tree_eval): Fix quotes for delete array case. + (pp_var): New function, call it as appropriate everywhere else. + +Fri Nov 30 11:11:52 2007 Arnold D. Robbins + + * io.c (socketopen): Use NULL as first argument to `getaddrinfo' + if any_remote_host is true. Should help on Non-GLIBC systems. + +Thu Nov 15 22:01:36 2007 Arnold D. Robbins + + * io.c (two_way_open): Case for ptys. Change search for letters + to avoid ASCII / EBCDIC problems. + +Mon Oct 22 08:49:05 2007 Arnold D. Robbins + + * Release 3.1.6: Release tar file made. + +Sun Oct 14 23:19:12 2007 Ralf Wildenhues + + * Makefile.am: Avoid GNU make-specific `make -C'. + +Sun Oct 14 19:37:01 2007 Arnold D. Robbins + + * configure.ac: Add check for `atexit', needed by replacement + version of `snprintf'. + +Sun Sep 30 21:50:59 2007 Arnold D. Robbins + + Rationalize locale's influence on %'g, strtonum, and input. + + * awk.h (use_lc_numeric): Add declaration. + * builtin.c (format_tree): Add check for quote_flag and set + LC_NUMERIC so that The Right Thing gets done, then reset it. + (do_strtonum): Pass use_lc_numeric as second arg to isnondecimal. + * main.c (main): Have do_posix set use_lc_numeric also. + +Thu Sep 27 21:36:23 2007 Stepan Kasal + + * configure.ac: Do not instantiate version.c; remove the hack + to keep version.c from being removed upon `make distclean'. + * Makefile.am (version.c): New rule. + (.c.i, SUFFIXES): Remove, `.i' is unused. + (MAINTAINERCLEANFILES): Remove awkgram.c; Automake takes care of that. + +Wed Sep 26 14:40:13 2007 Eli Zaretskii + + * builtin.c (format_tree): Handle non-standard snprintf that + returns a negative value when the buffer is too small. + +Tue Sep 25 23:27:41 2007 Arnold D. Robbins + + * ChangeLog: Removed all leading spaces. Fixed up formatting of + entries to have capital letter after the colon. Fixed a number of + entries to have the '*' in the right place. ASCII instead of ascii. + Capitalize Linux. (Is this anal-retentive or what? Sheesh.) + +Tue Sep 25 08:24:11 2007 KIMURA Koichi + + * awk.h: Add include of for Visual Studio. + * regex_internal.h: Do the right thing for replacing alloca. + +Sat Sep 22 23:26:27 2007 Arnold D. Robbins + + * field.c (set_FIELDWIDTHS): Restore behavior of 3.1.4 that allowed + FIELDWIDTHS to be "" without crashing, and such a value has NF = 0. + Yet Another Dark Corner. Thanks to Glenn Zazulia + for pointing out the problem. + + Unrelated: + + * builtin.c (format_free): Make `quote_flag' not sticky. Thanks to + Ulrich Drepper for pointing this out. + * main.c (main): Adjust calls to `setlocale' and `localeconv' so that + the %'d flag will work even if not using the locale's decimal point. + +Thu Sep 20 21:02:41 2007 Arnold D. Robbins + + * array.c (hash, awk_hash, gst_hash_string): Add fourth argument + pointer to retrieve code. Only assign a value if not NULL. + Fix most places to pass NULL for fourth argument. + (assoc_lookup): Save the code in the node for use in growing the + array later. + (grow_table): Use the saved code instead of recomputing each time. + * awk.h (NODE hash): Add `code' member and `ahcode' macro. + (hash): Revise declaration. + * awkgram.y: Revise calls to `hash'. + +Tue Aug 21 17:47:07 2007 Arnold D. Robbins + + * main.c (copyleft): Cite version 3 of the license. + * dfa.c: Minor edits to sync with grep 2.5.3. + +Sat Aug 11 22:48:11 2007 Arnold D. Robbins + + * COPYING: Replaced with GPL 3. + * All other relevent files: Upgraded to GPL 3. + +Fri Aug 3 15:01:38 2007 Andrew J. Schorr + + * builtin.c (format_tree): Free `obuf' before call to `fatal' + to keep valgrind happy. + +Mon Jun 4 01:12:21 2007 Arnold D. Robbins + + * All relevant files: Updated copyright year to 2007. + +Mon May 28 08:06:15 2007 Arnold D. Robbins + + * main.c (use_lc_numeric): New variable, true for new + option `--use-lc-numeric'. + (optab): Add option "use-lc-numeric". + (usage): Add to usage message. + (main): Allow the --use-lc-numeric option to also use the + local decimal point. + +Fri May 18 16:26:00 2007 Arnold D. Robbins + + * awk.h (_TANDME_SOURCE): Add test for ! _SCO_DS for + SCO systems. Thanks to John DuBois + +Tue May 15 13:14:04 2007 Arnold D. Robbins + + General capability suggested by Michael May . + + * configure.ac: New option --disable-directories-fatal. Makes gawk + silently skip directories on the command line. + * io.c (iop_open): Add fourth parameter, pointer to flag which is set + to true if the file is a directory. In this case, close the fd and + return NULL. + (nextfile): Modify call to iop_open. Add logic to check for directory + and skip if --disable-directories-fatal was used. If the configure flag + was not used, then if do_traditional also skip. + (redirect): Modify call to iop_open and call fatal if isdir is true. + +Mon May 7 14:51:54 2007 Arnold D. Robbins + + * POSIX.STD: Updated. + +Wed May 2 19:29:56 2007 Stepan Kasal + + Revert precedence of concatenation and | getline. + From mail dated 2005-10-31. + + * awkgram.y (common_exp): Move the two rules for naked regexp and + the rule for "(...) in arr" to ... + (non_post_simp_exp): ... here ... + (simp_exp): ... and here, respectively. Fixes test/parsefld.awk/. + (simp_exp_nc): New nonterminal, needed to fix the + precedence of concatenation over "|getline". + (common_exp): Can also start with simp_exp_nc. + +Tue May 1 19:53:11 2007 Arnold D. Robbins + + Work around problem with /ab{0}c/. + * dfa.h (struct dfa): Add member `broken'. + * dfa.c (dfainit): Initialize it to false. + (lex): Set it if `minrep == maxrep && minrep == 0'. + * re.c (avoid_dfa): Check flag and return TRUE if set. + +Tue May 1 05:34:53 2007 Arnold D. Robbins + + * configure.ac: Add calls to AM_LANGINFO_CODESET, and gt_LC_MESSAGES. + Thanks to Matthew Burgess . + +Sun Apr 29 22:55:12 2007 Arnold D. Robbins + + * regcomp.c (utf8_sb_map): Remove const if not __GNUC__ >= 3. + * regex_internal.h (re_dfa_t): Bracket bizarre macro call with + check for _LIBC. + Thanks to Nelson Beebe for finding both problems. + +Sun Apr 29 13:10:31 2007 Arnold D. Robbins + + * builtin.c (do_strftime): Add optional third argument to strftime() + which if non-zero or non-null means to use UTC. + * awkgram.y (tokentab): Allow three arguments to strftime. + +Fri Apr 27 11:44:27 2007 Arnold D. Robbins + + * README.cvs, bootstrap.sh: Added to CVS archive, not for + inclusion in tarballs. + +Fri Apr 20 16:48:30 2007 Pat Rankin + + * awk.h: Move inclusion of redirect.h before HAVE_func blocks. + +Tue Apr 24 21:55:36 2007 Arnold D. Robbins + + * re.c (research): In the multibyte case, fall back to the full + matcher if need_start, since there are bugs in the dfa matcher + in some obscure cases. Sigh. + * builtin.c (format_tree): When using %.0f instead of %d, assert + that we're not malloc-ing zero. + +Tue Apr 17 21:51:40 2007 Arnold D. Robbins + + Portability fixes for lsbcc from Nelson Beebe. + + * configure.ac: Check for stddef.h header. + * regex.h: Use check and include header to get size_t definition. + * main.c: Update UPDATE_YEAR, add #ifdef for HAVE_MTRACE. + +Tue Apr 17 13:49:13 2007 Arnold D. Robbins + + * configure.ac: Add test for struct sockaddr_storage. + * io.c: Add macro to redefine sockaddr_storage as sockaddr. + +Tue Apr 17 05:45:19 2007 Arnold D. Robbins + + * io.c (get_a_record): Make it static, to match declaration at the + top of the file. (Thank you GCC for not reporting this. Grr.) + +Fri Apr 13 00:29:24 2007 Arnold D. Robbins + + * replace.c: Only include missing/getaddrinfo.c if HAVE_SOCKETS + is defined. Avoids problems on VMS. Thanks to Pat Rankin. + +Tue Apr 10 18:53:04 2007 Arnold D. Robbins + + * awkgram.y, builtin.c, eval.c, ext.c, field.c, io.c, + node.c: Added some sanity to the lint warnings, to only + print them once if they are syntactic or of the type where + they don't need to be repeated. Switch to `short' instead + of `int', and in general use a variable named `warned', for + consistency. + +Sun Apr 8 16:49:28 2007 Arnold D. Robbins + + * awkgram.y: Add guard code to ifdef out "signed" for VMS. Thanks for + the heads-up to Pat Rankin. + * regcomp.c (utf8_sb_map, init_dfa): Move non-GCC code to initialize + this array into code, to preserve word-size independance. + * configure.ac: Add check for . + * io.c: Include if we have it, instead of keyed off + Tandem, needed on some Unix systems. + * awk.h, main.c, msg.c, awkgram.y: Move to use of CAN_USE_STDARG_H + instead of continuously repeating check for header and defined STDC + and STDC. Thanks to Pat Rankin. + +Fri Apr 6 15:28:09 2007 Arnold D. Robbins + + * builtin.c (do_length): Only print `length(array)' lint warning once. + * node.c (dump_wstr): Restore from being ifdef'ed out. Useful in case + it needs to be called from a debugger. + * regcomp.c (utf8_sb_map): Fix gcc-specific code. + * awk.h (snprintf): Add declaration in case not available on the system. + (Ceil, Floor): Add macros changing the name for VMS, in an attempt to + fix linkage problems. + * io.c: Simplify includes for internet headers and for getaddrinfo + defines. + +Wed Apr 4 23:38:24 2007 Arnold D. Robbins + + * io.c [AI_ADDRCONFIG]: Add a definition in case it's not available. + * main.c (usage): Add comment for translators to add translation + bug report address. + +Wed Apr 4 18:26:45 2007 Pat Rankin + + * regexec.c (build_trtrable): Add missing #if HAVE_ALLOCA. + +Thu Mar 29 19:30:20 2007 Pat Rankin + + * re.c (make_regexp): Cast casetable to RE_TRANSLATE_TYPE. + +Mon Mar 19 12:35:00 2007 Arnold D. Robbins + + Finish removing references to STRTOD_NOT_C89. + + * awk.h (gawk_strtod): Use now if there is no strtod. + * replace.c (strtod.c): Include if there is no strtod. + * configure.ac [GAWK_AC_FUNC_STRTOD_C89]: Removed. + +Mon Mar 19 12:17:16 2007 Kimura Koichi + + * dfa.c (dfaexec): Add check for half-width katakana characters in + character classes in ShiftJIS locale. + From mail originally sent Mon, 01 Aug 2005 09:07:55 +0900 + +Fri Mar 9 11:53:25 2007 Arnold D. Robbins + + * field.c (rebuild_record): Assert that wide string is off when + creating new fields. Inspired by Karel Zak. + +Fri Mar 9 11:26:01 2007 Matthew Woehlke + + * io.c (get_a_record): Limit the max amount read to SSIZE_MAX. Needed + on Tandem systems where this amount is incredibly small. + +Tue Mar 6 08:17:49 2007 Paul Eggert + + * node.c (is_ieee_magic_val): Don't rely on strncasecmp; it mishandles + ASCII bytes in some locales. + (get_ieee_magic_val): Use strtod if it works, relying on our handbuilt + code only if it doesn't work. This is more likely to do the right + thing with strings like "-nan". + +Tue Feb 27 20:51:29 2007 Arnold D. Robbins + + * configure.ac (AM_PROG_CC_STDC): Removed, per email suggestion + from Stepan Kasal some time ago. + +Tue Feb 27 20:44:07 2007 Aleksey Cheusov + + * awk.h: Revise checks for MEMCPY_ULONG and MEMSET_ULONG + for MS Interix using MSVC. + * configure.ac (AC_CHECK_FUNCS): Add checks for memcopy_ulong + and memset_ulong. + From mail dated Tue Aug 30 12:38:39 2005. + +Mon Feb 26 12:47:10 2007 Tony Leneis + + * dfa.c (dfacomp): Check that regexp is non-zero in length + also. Avoids problems with empty regex and IGNORECASE on + systems where `malloc(0)' returns a non-NULL pointer. + From mail dated Wed, 26 Oct 2005 15:42:07 -0700. + +Wed Feb 21 10:23:12 2007 Arnold D. Robbins + + * floatcomp.c (Floor, Ceil): Restore correct expression for Cray. + Then ifdef out the whole business, since it's likely to be obsolete. + Thanks to Paul Eggert. + +Mon Feb 19 12:28:47 2007 Arnold D. Robbins + + * node.c (format_val): Simplify code: always format the value + ourselves. Use %.0f if the value is integral. + * floatcomp.c (dval_out_of_range): Remove function, not needed. + (awknum_fraction_bits): Removed. + (adjust_uint): New function, defined IFF have uintmax_t. + * builtin.c (tmp_integer): Use adjust_uint. + Move include of and ... + * awk.h: to here. + (awknum_fraction_bits): Removed. + (adjust_uint): Declare, or define as do-nothing macro. + +Sun Feb 18 17:43:33 2007 Arnold D. Robbins + + * node.c, floatcomp.c: Add include of to get + correct declarations of math functions. + * configure.ac: If doing development, add -DYYDEBUG and also + -fno-builtin for GCC. + +Wed Feb 14 19:42:08 2007 Arnold D. Robbins + + Add support for special infinity and NaN values in non-POSIX + mode, and in POSIX mode, just call system `strtod'. + + * configure.ac [GAWK_AC_FUNC_STRTOD_C89]: Comment out. + * node.c (is_ieee_magic_val, get_ieee_magic_val): New functions. + (r_force_number): Adapt logic and use new functions. + +Tue Feb 13 13:02:32 2007 Arnold D. Robbins + + Move Paul's numeric stuff to a separate file to make code cleaner. + + * floatcomp.c (awknum_fraction_bits): New variable. + (Floor, Ceil): Functions, moved here from macros in builtin.c. + (dval_out_of_range): New function for checking if double is in range + of long. + (FLT_RADIX, FLT_MANT_DIG, DBL_MANT_DIG, AWKSMALL_MANT_DIG, + AWKNUM_MANT_DIG, AWKNUM_FRACTION_BITS): Moved here from awk.h. + * awk.h: Add decls of stuff now in floatcomp.c. + * Makefile.am[base_sources]: Add floatcomp.c. + * builtin.c (tmp_integer): Refer to `awknum_fraction_bits' + instead of AWKNUM_FRACTION_BITS. + * node.c (format_val): Call `dval_out_of_range' instead of + inline coding the test. + +2007-02-06 Paul Eggert + + * node.c (format_val): Fix bug when handling numbers close to + LONG_MIN and LONG_MAX. + * awk.h (FLT_RADIX, FLT_MANT_DIG, DBL_MANT_DIG, AWKSMALL_MANT_DIG, + AWKNUM_MANT_DIG, AWKNUM_FRACTION_BITS): Moved here from builtin.c. + * builtin.c: Move those macros to awk.h. + * awk.h (DBL_FRACTION_BITS): New macro. + +Fri Feb 9 13:40:10 2007 Matthew Woehlke + + More Tandem fixes. + + * configure.ac: Check in Tandem's zrldsrl library for dlopen. + * regex_internal.h: Move include into ifdef. + * regexec.c: Bracket alloca uses. Fix GCC use of `?:'. + +Fri Feb 9 13:30:15 2007 Arnold D. Robbins + + * replace.c: Add include of snprintf.c. Ooops! + * configure.ac: Add check for mkstemp and tmpfile for replacement + snprintf.c. + +Tue Feb 6 14:33:51 2007 Arnold D. Robbins + + * node.c (format_val): Restructure a bit to remove need for and + use of goto. + +Sun Feb 4 16:35:21 2007 Arnold D. Robbins + + * awkgram.y (field_spec, opt_incdec): New terminals. + (variable): Change definition of field reference to use field_spec. + See test/parse1.awk. + +Thu Feb 1 17:38:38 2007 Arnold D. Robbins + + * main.c: Allow YYDEBUG to enable the `-D' option, not just + GAWKDEBUG. + +Wed Jan 31 19:30:26 2007 Arnold D. Robbins + + * node.c (format_val): Restore my test for numeric values + being representable, as it includes more conditions than + Andrew's, pending a thorough review of undealt-with emails on + the topic. + * regexec.c (proceed_next_node): Move check for NULL to after + variable declarations inside initial `if'. + +Wed Jan 31 19:25:21 2007 Andrew J. Schorr + + * configure.ac (getaddrinfo): Improve test, since this function + can be in libsocket on some systems. + +Mon Jan 29 15:33:10 2007 Andrew J. Schorr + + * Makefile.am (valgrind): Also call new valgrind-scan target. + +Mon Jan 29 12:44:54 2007 Andreas Schwab + + * dfa.c (copytoks): Adjust index into multibyte csets when + copying an MBCSET token. + +Fri Jan 26 20:01:38 2007 Andrew J. Schorr + + * node.c (format_val): Test whether a numeric value is integral + simply by converting it to long and then back again, and checking + if the value matches. That's more robust than trying to test + whether the floating-point value is representable as a long. + * builtin.c (format_tree): Fix buffer overflow bug, off-by-one errors + in checking snprintf return codes, and use "%.0f" to implement "%d" + formatting. For octal or hex formatting, test whether the value + is integral by trying to convert back to floating point and seeing + if the value matches. This is more robust than trying to test + whether the floating-point value is representable as an integer. + +Tue Jan 23 17:49:28 2007 Arnold D. Robbins + + * io.c (socketopen): Initialize socketfd to avoid "may be used + uninitialized" warning. + * regexec.c (regexec, re_search_stub): Removed unused variable `dfa'. + * builtin.c (wide_tolower_toupper): Fix signedness of pointer in + allocation calls and in call to make_str_node. + +Mon Jan 22 12:57:19 2007 Kimura Koichi + + Deal with halfwidth katakana in SJIS locale inside character ranges. + Based on http://sources.redhat.com/bugzilla/show_bug.cgi?id=1149. + Changes affect non-__LIBC code only. + + * regcomp.c (re_compile_fastmap_iter): Handle half-size characters. + * regexec.c (check_node_accept_bytes): Same. + +Thu Jan 18 22:19:01 2007 Karel Zak + + * node.c (free_wstr): Assert that type is Node_val. + +Thu Jan 18 12:18:47 2007 Arnold D. Robbins + + * regcomp.c (re_compile_fastmap_iter): Declare `dfa' to be + be volatile. Fixes valgrind problem with the ignrcase test. + Sheesh. Gawk should now be valgrind-clean. We hope. + +Mon Jan 15 14:28:04 2007 Arnold D. Robbins + + Use getaddrinfo instead of gethostbyname, to handle IPV6 + format addresses. Based on patch submitted by + Jan Pazdziora . + + * configure.ac: Add getaddrinfo to list of checked functions. + * configh.in, configure: Regenerated. + * io.c: Rework includes based on HAVE_GETADDRINFO. + (socketopen): Reworked for getaddrinfo. + (devopen): Modified for new socketopen. + * replace.c: Include getaddrinfo.c if necessary. + +Sun Jan 14 12:19:53 2007 Arnold D. Robbins + + * awkgram.y: For bad name in array subscripting, build a + valid node anyway to avoid invalid reads reported by valgrind. + * dfa.c (parse_bracket_exp_mb): Remove assignment of NULL + to work_mbc->chars, was losing data malloc'ed earlier. Thanks + to valgrind. + (state_index): Alway initialize d->states[i].mbps elements to zero. + (dfafree): Free allocated d->states[i].mbps.elems if needed. + * regex.c: Try harder to undef alloca. + * regex_internal.h (__mempcpy): Undef before redefinining for + more recent versions of GLIBC. + +Sat Jan 13 22:10:43 2007 Arnold D. Robbins + + * node.c (str2wstr): For count of zero from mbrtowc, set count to 1 + and fall through to code that copies. Originally from Paul Eggert. + + Unrelated: + * configure.ac: Add call to AC_USE_SYSTEM_EXTENSIONS, should help + on Tandem. This lets us remove AC_AIX and AC_MINIX. + + From Matthew Woehlke for Tandem: + + * awk.h (_TANDEM_SOURCE): Also define _XOPEN_SOURCE_EXTENDED. + * io.c (_TANDEM_SOURCE): Include more headers. + +Sat Jan 13 21:53:48 2007 Ralf Wildenhues + + * field.c (set_FIELDWIDTHS): Avoid writing one past the end of + the array. + * node.c (r_force_number): Avoid reading uninitialized variable. + +Sat Jan 13 21:37:15 2007 Arnold D. Robbins + + * Makefile.am (valgrind): New target based on idea from + Ralf Wildenhues for running valgrind on test suite. + +Sat Jan 13 21:24:54 2007 Ralf Wildenhues + + Enable more `--lint-old' warnings. + * awkgram.y: Warning about multiple BEGIN or END rules, + `index in array' outside of for loops, multidimensional arrays. + * field.c (set_FS): Warn about regex FS. + * node.c (parse_escape): Warn about `\b', `\f', `\r'. + +Sat Jan 13 20:56:56 2007 Arnold D. Robbins + + * node.c (wcasestrstr): Revert use of continue, reinstate goto. + Thanks to Andrew Schorr. + (free_wstr): Move zeroing of wsptr and wslen and clearing of flag + back outside the if. + * field.c (rebuild_record): In loop that copies fields to new record, + add call to `free_wstr'. This ensures that flag values are correct + and avoids double free later. Thanks to Karel Zak for pointing out + the problem. + +Fri Jan 12 14:01:51 2007 Dmitry V. Levin + + * builtin.c (do_match): In addition to "gawk_mb_cur_max > 1" check, + check for positive string length. + +Fri Jan 12 13:57:20 2007 Arnold D. Robbins + + Sync with GLIBC. Bi-annual this time. + + * regexec.c, regex.h, regex_internal.c, regcomp.c: + Reapply any portability patches specific to gawk. + * regex_internal.h (build_wcs_upper_buffer): Fix return type + in declaration. Reapply any portability patches specific to gawk. + * regex.c: Add definitions for `bool', `true' and `false'. + Define `alloca' to something invalid to keep it from linking + in case a usage of `alloca' slipped through. Reapply any portability + patches specific to gawk. + + Base versions: + getopt1.c 1.10 Tue Mar 9 10:35:37 2004 + getopt.c 1.55 Fri Mar 24 10:59:56 2006 + getopt.h 1.21 Fri Mar 19 00:19:32 2004 + getopt_int.h 1.1 Tue Mar 9 10:31:19 2004 + regex.c 1.129 Fri Mar 24 10:59:57 2006 + regexec.c 1.97 Fri Mar 24 10:59:57 2006 + regex.h 1.40 Mon Sep 25 20:03:05 2006 + regex_internal.c 1.67 Mon Sep 25 20:03:05 2006 + regex_internal.h 1.73 Fri Mar 24 10:59:57 2006 + regcomp.c 1.112 Fri Mar 24 10:59:57 2006 + +Fri Jan 12 12:28:51 2007 Arnold D. Robbins + + * ABOUT-NLS, INSTALL, Makefile.in, aclocal.m4, config.guess, + config.rpath, config.sub, configh.in, configure, configure.ac, + depcomp, gettext.h, install-sh, missing, mkinstalldirs, ylwrap: + Updated to current autotools, Autoconf 2.61, Automake 1.10, + gettext 0.16.1. + +Thu Jan 4 18:23:50 2007 Dmitry V. Levin + + * node.c (free_wstr): Zero wstptr and wstlen only if WSTRCUR + flag is set. + (str2wstr): Replace invalid `free' call with `free_wstr' call. + +Thu Jan 4 16:49:21 2007 Arnold D. Robbins + + * builtin.c (do_match): Move freeing of wc_indices to outside if. + Thanks to Sven Wegener for the report. + +Thu Dec 21 14:32:13 2006 Arnold D. Robbins + + * main.c (arg_assign): Reassign the '=' only if not initing. + * profile.c (varname): Deleted. + (pp_concat): New function to print concatenations. + (tree_eval): Don't use `varname' anymore. Use `pp_concat'. + +Mon Dec 11 12:43:04 2006 Arnold D. Robbins + + * builtin.c (sub_common): Clear numeric flags on result + unconditionally. + * node.c (wcasestr): Replace `goto' with `continue'. + +Thu Nov 30 15:54:07 2006 Bruno Haible . + + * builtin.c: Change use of HAVE_LC_MESSAGES to defined(LC_MESSAGES). + Bruno suggested only for dcngettext, I did it everywhere (ADR). + +Wed Sep 6 02:04:32 2006 Andrew J. Schorr + + * awkgram.y (get_src_buf): Adjust `source' and `sourceline' to + correctly handle mixed -f and --source options. + +Mon Aug 28 21:17:20 2006 Arnold D. Robbins + + * AUTHORS, FUTURES, LIMITATIONS, NEWS, POSIX.STD, PROBLEMS, README: + Added FSF copyright for no other reason than to satisfy the flunkies + running Savannah. + * Makefile.am: Removed `ansi2knr' from AUTOMAKE_OPTIONS also. + +Fri Aug 11 15:07:45 2006 Arnold D. Robbins + + * field.c (set_field, rebuild_record, set_record): Remove calls to + `free_wstr' since they're not needed. + +Sat Aug 5 22:04:24 2006 Arnold D. Robbins + + * node.c (unref): Call `free_wstr' for fields also. Thanks to + Andrew Schorr. + +Tue Jul 4 22:43:05 2006 Arnold D. Robbins + + * eval.c (interpret): Node_assign_concat case: Turn off NUMBER and + NUMCUR flags in result. Sheesh. Thanks to + for finding the problem. + +Mon Jul 3 22:49:44 2006 Pat Rankin + + * main.c (load_environ): When AWKPATH is missing from ENVIRON[], + try to find it with getenv("AWKPATH") before resorting to DEFPATH. + Suggested by Galen Tackett. + +Mon Jul 3 00:27:59 2006 Arnold D. Robbins + + * io.c (INTERNAL_HANDLE): New constant for use by `iop_alloc' + when allocating an internal IOBUF. + (pidopen, useropen): Use it. + (iop_alloc): Add check for it and just return iop. + +Fri Jun 23 15:48:34 2006 Arnold D. Robbins + + * awkgram.y (subn): At end for `do_sprintf' check, verify + that lnode is not NULL before using it to assign through. + +Sun Jun 18 22:27:25 2006 Arnold D. Robbins + + Repair internal names like /dev/user, /dev/pid, as well as /dev/fd/N, + which have been broken for a long time but noone noticed. + + * io.c (is_internal): New macro to check for internal file like + `/dev/user'. + (spec_setup): Reduce to two parameters, allocate logic is always true. + Add IOP_NO_FREE to flag. + (pidopen, useropen): Return `IOBUF *' instead of int. Fix + logic to test if `iop' parameter is NULL and if so to allocate it. + (specfdopen,): Return `IOBUF *' instead of int. Fix + logic to test if `iop' parameter is NULL and if so to allocate it. + Don't set IOP_NO_FREE in flag. + (iop_open): Remove `IOBUF iob' field from `struct internal' and its use + and the use of `spec_setup' from the code here. Change the check in the + call to the open function to look for NULL. + (get_a_record): Use `is_internal' in initial check for filling the + buffer to not try to call `read' on internal files. If true, set + the IOP_AT_EOF in the flag and return EOF. + +Fri Mar 24 13:05:56 2006 Arnold D. Robbins + + * awkgram.y (get_src_buf): Remove function argument types from + declaration of `readfunc' to avoid bugaboos with VMS declaration + of `read' system call. + +Fri Mar 10 06:28:23 2006 Arnold D. Robbins + + * awk.h (free_wstr): New declaration if MBS_SUPPORT, empty macro + otherwise. + * node.c (free_wstr): New function, inside MBS_SUPPORT. Frees the wide + string part of a node. Provided so that it can be used consistently + everywhere. + (format_val, r_dupnode, mk_number, make_str_node, unref): Use it. + * builtin.c (sub_common): Call `free_wstr' instead of doing it manually. + * eval.c (r_tree_eval): Same in Node_assign_concat case. + * field.c (set_field, rebuild_record, set_record): Add calls to + `free_wstr'. + +Mon Feb 13 22:45:34 2006 Arnold D. Robbins + + * eval.c (r_tree_eval): Node_assign_concat. Release any + wide string value and reset the WSTRCUR flag. Based on + bug report by Karel Zak. + +2006-01-03 Paul Eggert + + * Makefile.am (awkgram.c): Use $(AWK), not awk, so that the rule + works on Solaris too (e.g., Solaris 10). Problem reported by + Andrew J. Schorr. + +Mon Dec 19 05:39:46 2005 Arnold D. Robbins + + * node.c (format_val): Account for overlow of conversion + from double to long. Shows up worse on 64-bit systems. + +Wed Dec 14 18:57:34 2005 Arnold D. Robbins + + * eval.c (set_BINMODE): Fix logic of test for no numeric value. + Makes `gawk -v BINMODE=1 ...' work again. Thanks to Eli Zaretskii + for pointing out the problem. + +Wed Oct 19 10:58:27 2005 Arnold D. Robbins + + * main.c (main, arg_init): Only use the locale's decimal + point if do_posix is set. Too many people the world over + have complained about this. + +Fri Oct 7 13:54:09 2005 Arnold D. Robbins + + Enhancement to fix from 23 Sept 2005, suggested by Pat Rankin. + + * awkgram.y (one_line_close): New function, closes open FILE * used + by `read_one_line'. + (fp): Static FILE * used by `read_one_line' and `one_line_close'. + * awkgram.y (read_one_line): Simplify check for call to `fdopen'. + (get_src_buf): New variable `closefunc' which is a pointer to a + function implementing the `close' system call interface. + +Fri Oct 7 13:23:29 2005 Arnold D. Robbins + + * field.c (set_FIELDWIDTHS): Fix off-by-one error in assignment + of sentinel value at end of FIELDWIDTHS array. + +Fri Sep 23 16:05:13 2005 Arnold D. Robbins + + * awkgram.y (read_one_line): New function, mainly for debugging, + that reads one line of data at a time to pass back as a buffer. + Emulates the variable-length record filesystem of VMS, where + we first saw the problem fixed here. + (get_src_buf): New variable `readfunc' which is a pointer to a + function implementing the `read' system call interface. Based on + an environment variable, use `read_one_line' instead of `read' + for testing. Make the test for expanding the buffer smarter, + so that it doesn't grow unnecessarily. + + Thanks to Galen Tackett (tackett_galen@bah.com) for reporting + the problem and to Anders Wallin and Pat Rankin for help + tracing and reproducing the problem and testing the fix. + +Fri Sep 9 15:06:07 2005 Arnold D. Robbins + + * hard-locale.h (xmalloc): Move declaration to file scope + for non-glibc systems and gcc 4. Thanks to Kito Danya Dietrich + . + +Thu Aug 25 22:40:40 2005 Arnold D. Robbins + + * regcomp.c (build_range_exp): Avoid `btowc' for single-byte + characters. Fedora Core 2, maybe others, have a broken version + that can't handle values > 127. + +Fri Aug 19 16:13:28 2005 Arnold D. Robbins + + * regexec.c (proceed_next_node): Added a band-aid check at the + top of the first `if' to make sure that `mctx->state_log[*pidx]' + isn't NULL. + +Fri Aug 12 13:10:33 2005 Arnold D. Robbins + + * io.c (iop_alloc): Only free `iop' if it was malloc'ed in + the first place. + +Tue Jul 26 21:46:16 2005 Arnold D. Robbins + + * Release 3.1.5: Release tar file made. + +Tue Jul 26 21:44:54 2005 Arnold D. Robbins + + Copyright dates on all relevant files updated to 2005. + +Wed Jul 6 17:09:02 2005 Arnold D. Robbins + + Minor cleanups: + + * io.c (do_index): Remove unused variables `mbclen', `mbs1' and `mbs2'. + * node.c (wstrstr): Remove unsed variable `j'. + (dump_wstr): `#ifdef' out, not currently needed. + * eval.c (op_assign): Move decl of `t1' and `t2' into a separate block + for the `! HAVE_FMOD' case. Keeps the compiler quiet. Similar for + `ltemp'. + +Wed Jul 6 16:51:31 2005 Arnold D. Robbins + + * io.c (close_io): Now takes pointer to boolean parameter indicating + if there was a problem closing standard output or standard error. + Update it in the right places. + * awk.h (close_io): Update the declaration. + * main.c (main): New variable `stdio_problem'. Pass it to `close_io'. + Check the result and exit non-zero if there was a problem. + (usage, version): Print warning message if problems with stdout. + + Unrelated: + + * main.c (main): For call to `setlocale' for LC_MESSAGES, just use + `#ifdef LC_MESSAGES'. Per Bruno Haible . + +Wed Jul 6 16:44:58 2005 Jim Meyering + + * main.c (init_fds): If any of the STDIN_FILENO, STDOUT_FILENO, + STDERR_FILENO are initially closed, reopen them with permissions + contrary to common usage so that any reasonable attempt to use + them will evoke the same sort of error as reading or writing to + a closed file descriptor would. + +Mon Jul 4 09:38:29 2005 Arnold D. Robbins + + More multibyte fixes from Kimura Koichi, . + + * node.c (format_val, r_dupnode): Spell `wstptr' correctly. + * regex_internal.c (build_wcs_upper_buffer): Label `offsets_needed' + should not be inside `#ifdef _LIBC'. + * regcomp.c (build_charclass): Fix declaration of `class_name' in + prototype to not be unsigned. + +Thu Jun 30 11:52:34 2005 Arnold D. Robbins + + * profile.c (tree_eval): Node_not: Remember to print the exclamation + point! Thanks to Dan Nielsen + for the bug report. + * mbsupport.h: Fix spelling of HAVE_ISWUPPER. Thanks to + Kimura Koichi, . + +Sun Jun 26 16:37:59 2005 Arnold D. Robbins + + Unrelated changes: + + * builtin.c (do_length): Allow array argument to length(). + Returns number of elements in array. + + * awkgram.y (yylex): Ignore carriage returns in source code. Sigh. + +Wed Jun 15 22:12:15 2005 Arnold D. Robbins + + * node.c (isnondecimal): Check loc.decimal_point before using it. + Avoids problems with command line assignment when locale info may + not be set up all the way yet. + +Wed Jun 15 21:59:54 2005 Arnold D. Robbins + + * node.c (make_str_node): If working with multibyte characters, while + parsing string constants, keep multibyte characters together. This + avoids problems in cases where one of the bytes is backslash. Initial + patch supplied by Kimura Koichi, . + +Tue Jun 14 21:50:37 2005 Andrew J. Schorr + + Use Exponentiation By Squaring for integer powers for ^ and ^=. + + * eval.c (calc_exp, cal_exp_posint): New functions. + (r_tree_eval): Use them. + +Fri Jun 3 12:15:54 2005 Arnold D. Robbins + + * configure.ac: Further change the hack at the end so that + it works on Mac OS X `sed'. Sigh. + +Thu Jun 2 22:44:01 2005 Arnold D. Robbins + + * configure.ac (TYPE_SOCKLEN_T): Use `int' as default type if can't + figure one out. + * awkgram.y: Warn that `//' is not a C++ comment. (:-) + +Thu Jun 2 20:55:27 2005 Arnold D. Robbins + + From: Benno Schulenberg + + * eval.c (func_call): Take message out of gettext call since it's for + debugging. + * ext.c (get_actual_argument): Fix formatting of message. + +Wed May 25 09:19:37 2005 Arnold D. Robbins + + * configure.ac: Change hack at end that fixes Makefile to keep + version.c to use `sed' and not `ed'. More portable to OS/2, probably + other systems. + +Mon May 23 09:01:26 2005 Arnold D. Robbins + + Portability help from Jim Meyering. + + * io.c: Rework ifdefs for and . Test them + individually. + * configure.ac: Add AC_C_RESTRICT and code for socklen_t from rsync. + Check for isascii and btowc for regex. + +Sat May 14 22:49:54 2005 Arnold D. Robbins + + * wait_any (errno): Remove decl. + * gawk_popen: The pipe-simulated but not VMS or DOS version. Remove + decl/use of `strdup' in favor of `emalloc' and `strcpy'. + +Wed May 11 18:33:30 2005 Arnold D. Robbins + + All files: Updated address of FSF to: + + 51 Franklin Street, Fifth Floor + Cambridge, MA 02110-1301 + +Wed May 11 18:19:03 2005 Jim Meyering + + * configure.ac: Use AM_GNU_GETTEXT([external]). + Reflect upgrade to gettext-0.14.4. + Reflect renaming of `jm_'-prefixed macros. + (AC_CONFIG_FILES): Remove intl/Makefile. + + * Makefile.am (SUBDIRS): Remove intl. + (AM_CPPFLAGS): Remove -Iintl. + +Wed May 11 11:42:06 2005 Arnold D. Robbins + + Straighten out mess with `isblank' which is C99 function. + + * configure.ac: Remove check for `isblank' in call to AC_CHECK_FUNCS. + * regex_internal.h: #ifdef out definition of `isblank' and provide + `is_blank' function a la dfa.c. + * field.c: Ditto. + * regcomp.c: #ifdef use of `isblank' and add `is_blank' use instead. + +Mon May 9 08:29:37 2005 Arnold D. Robbins + + * configure.ac: Add type check for `socklen_t', fixes compile + warning on AMD/64 Linux. + * io.c (socketopen): Change type of socket length variables + to `socklen_t' from `size_t'. + +Thu May 5 22:00:03 2005 John E. Haque + + * io.c (iop_alloc): Let an input processor hook installed via + `register_open_hooks' open its own fd in case gawk does not know + how to open it. + (iop_open): Call `os_close_on_exec' after `iop_alloc'. + ADR: If `iop_alloc' returns NULL but the fd is valid, close + the fd to avoid an fd leak. + +Mon May 2 08:05:59 2005 Arnold D. Robbins + + * eval.c (update_ERRNO): Don't use `return' in a `void' function. + * awk.h (AWKNUM): Back out use of `long double' based on LDBL_MANT_DIG. + * builtin.c (tmp_integer): Back out extra ifdefs. + +Fri Apr 29 13:01:05 2005 Arnold D. Robbins + + * configure.ac: Look for `isblank' function. + * field.c: Add define for `isblank' if we don't have it. + +Fri Apr 29 12:01:33 2005 Julian Foad + + From grep. Doesn't seem to affect awk. + + * dfa.c (lex): Fix bug #9519: "echo do^re | grep do^re" was + failing to find a match. [Towards end, set `lasttok' before + returning `c'.] + +Fri Apr 29 00:28:46 2005 Arnold D. Robbins + + * configure.ac: Jump through an amazingly convoluted hoop to get + config.status to keep version.c upon `make distclean'. Seems to + work though. + +Thu Apr 28 23:40:02 2005 Stepan Kasal + + * configure.ac (PRINTF_HAS_F_FORMAT): Some cosmetic changes. + (custom.h): Don't cat custom.h at the end of config.h; instead, use + AH_BOTTOM([#include "custom.h"]) + * awklib/Makefile.am (AM_CPPFLAGS): Add $(top_srcdir) so that + custom.h can be found. + +Thu Apr 28 23:21:22 2005 Jim Meyering + + * field.c (set_FIELDWIDTHS): Tighten up the code to accept FIELDWIDTHS + values in [1..INT_MAX], e.g., detect overflow and invalid strings, + and reject strings starting with `-'. + +Thu Apr 28 23:05:33 2005 Stepan Kasal + + * dfa.c (parse_bracket_exp_mb): Shorten one part of the code, to get + closer to grep's copy. + +Thu Apr 28 23:00:58 2005 Pat Rankin + + * builtin.c (format_tree) [#if VAXCRTL]: For floating point + formatting, reject zero_flag if using old VAXCRTL run-time + library to avoid getting erroneous results which appear as if + numerically incorrect (due to an embedded space in some cases, + extra trailing zeroes in others) rather than just misformatted. + `hsprint' test still fails, but not as badly. + +Thu Apr 28 19:12:03 2005 Arnold D. Robbins + + * re.c (reflags2str): Add three new RE_ flags from current regex.h + to bring the table up to date. + + * builtin.c (format_tree): Save 2 spare bytes instead of one. Suggested + by Stepan Kasal. + +Thu Apr 28 18:16:09 2005 Andrew J. Schorr + + * awk.h (IOBUF): Add new fields `opaque', `get_record', and + *close_func', to support insertion of an alternate input processor. + This is used by the XML extension. + (register_deferred_variable, register_open_hook, update_ERRNO_saved): + Declare new functions. + (load_environ, load_procinfo): Remove declarations -- these functions + are no longer global, since we use register_deferred_variable instead. + * awkgram.y (register_deferred_variable): New function to allow + calling code to register special variable names that trigger a callback + upon the first reference. This is now used to implement ENVIRON + and PROCINFO. + (variable): Search the list of deferred variables instead of hardcoded + tests for ENVIRON and PROCINFO. + * eval.c (set_BINMODE): Fix spelling of "arbitrary" in warning message. + (update_ERRNO_saved): New function that allows the caller to specify + the errno value instead of using the current value. + (update_ERRNO): Implement by calling update_ERRNO_saved(errno). + * io.c (iop_close): Call `iop->close_func' if non-NULL. + (close_redir): Should save `errno' value, otherwise `lintwarn' messages + might update it. Then use `update_ERRNO_saved' to set ERRNO. + (do_getline): Call `update_ERRNO_saved' to set ERRNO based on the + error code returned by the redirect function (instead of the current + value of errno). Similarly, use `update_ERRNO_saved' to set ERRNO + based on the value returned by `get_a_record'. But add a special + check to avoid updating ERRNO if `get_a_record' returns an error + code value of -1 (this is used by the XML extension which already + sets ERRNO before returning). + (register_open_hook): New function to register a function to be + called whenever a new data file is opened. This can be used to + install a special input processor (as in the XML extension). + (iop_alloc): Call registered open hook. + (get_a_record): If a `get_record' method has been set, call that instead. + * main.c (init_vars): Use `register_deferred_variable' to implement + ENVIRON and PROCINFO. + (load_environ, load_procinfo): Now static instead of global. + * doc/gawk.texi: Document new internal functions `update_ERRNO_saved', + `register_deferred_variable', and `register_open_hook'. + +Thu Apr 28 10:50:10 2005 Arnold D. Robbins + + * array.c (assoc_find, do_delete): Change incorrect uses of STREQN + to memcmp. + * builtin.c (do_index): Same. + * field.c (set_FS): Same. + * io.c (redirect, getredirect, do_close, set_RS): Same. + * re.c (reisstring): Same. + +Wed Apr 27 21:35:57 2005 Arnold D. Robbins + + Allow for long double. Initial changes from Jean-Marc Saffroy + . + + * awk.h (AWKNUM): If have long doubles (LDBL_MANT_DIG), define AWKNUM + as long double, otherwise just use double. + * builtin.c (format_tree): Change type of tmpval to double. + (do_strtonum): Same for `d' and types used in casts. + (tmp_integer): Don't do bit shifting if have long doubles. + + Unrelated, from Andrew J. Schorr: + + * io.c (close_one): Check for RED_FILE|RED_WRITE, not just RED_FILE. + +Mon Apr 25 12:23:18 2005 Andrew J. Schorr + + * eval.c (r_tree_eval): In Node_assign_concat case, when copying string + constants, include the terminating zero byte. + +Fri Apr 1 06:26:31 2005 Arnold D. Robbins + + Update to Automake 1.9.5. + + * INSTALL, aclocal.m4, depcomp, install-sh, missing, + mkinstalldirs, ylwrap: Updated. + + Unrelated: + + * builtin.c (do_tolower, do_toupper): Remove old code + based on 8-bit character table. + +Wed Feb 23 08:23:22 2005 Arnold D. Robbins + + * bisonfix.awk: New file, fixes continued #ifdef for dumb compilers. + * Makefile.am (awkgram.c): Fix rule to use it. + (EXTRA_DIST): Include bisonfix.awk. + +Tue Feb 22 21:18:50 2005 Arnold D. Robbins + + * random.h: Remove include of config.h and move it to ... + * random.c: Here. Move include of random.h back to where it was. + + * regcomp.c, regex.c, regexec.c: NUKED all use of alloca not inside + `_LIBC' ifdef. Hooray! + +Sat Feb 19 20:13:28 2005 Pat Rankin + + Workarounds for bugs and missing C89 features in old VAX C compiler. + + * regex_internal.h "mbsupport.h": Suppress inclusion if NO_MBSUPPORT + is defined. + [MB_CUR_MAX]: Define as 1 if mbsupport.h hasn't defined it. + [ER_ERRMSG, ERRMSG_TYPE, ERRMSG_OFFSET, ERRMSG_SEPARATOR]: New macros + conditionalized upon gawk's NO_TOKEN_PASTING macro. + * regcomp.c: Use them. + (parse_dup_op): Use alternate initialization of start_token if + RE_TOKEN_INIT_BUG is defined. + * regexec.c (proceed_next_node): Compare push_fail_stack() result + explicitly against REG_NOERROR rather than implicitly against 0. + +Sat Feb 19 20:05:50 2005 Pat Rankin + + * dfa.c "mbsupport.h": Suppress inclusion if NO_MBSUPPORT is defined. + +Wed Feb 16 20:43:07 2005 Pat Rankin + + * awk.h "mbsupport.h": Suppress inclusion if NO_MBSUPPORT is defined. + * regex.h : Guard inclusion with HAVE_SYS_TYPES_H. + * regex.c : Likewise. + * random.c "random.h": Include this first to get config.h setup. + : Guard inclusion with HAVE_FCNTL_H. + : Guard inclusion with HAVE_UNISTD_H. + * io.c [#if defined(MSDOS) ||... defined(__CYGWIN__)]: Splice the + backslash continuation back into one long line. + +Wed Feb 16 10:11:21 2005 Arnold D. Robbins + + * node.c (unref, format_val): Add assertions checking that both + `tmp->wstptr != NULL' and `(tmp->flags & WSTRCUR) != 0' before + freeing `tmp->wstptr'. Thanks to kimura.koichi@canon.co.jp. + + * random.c (HAVE_UNISTD_H): Conditionalize include of . + Thanks to Scott Deifik . + +Sun Feb 13 18:24:50 2005 Arnold D. Robbins + + * io.c (socketopen): Move `#ifdef MSG_PEEK' up to above + declarations too. Thanks to Michal Jaegermann. + + * config.guess, config.sub: Updated from Savannah. + +Thu Feb 10 15:48:48 2005 Arnold D. Robbins + + * regex_internal.c (re_dfa_add_node): Remove variable `type' + and just use `token.type' directly in RE_ENABLE_I18N code below. + Saves a compiler warning, and a good compiler will handle it anyway. + * regexec.c (check_arrival_add_next_nodes): Move decl of `err' + inside #ifdef RE_ENABLE_I18N code where it's used. + * awkgram.y (yylex): Add casts to int before use of `strlen' results + for printf-style precision. Avoid a compiler warning. + * io.c (redirect, do_close): Same for use of tmp->stlen. + + Thanks to Michal Jaegermann . + +Wed Feb 9 10:19:15 2005 Stepan Kasal + + * Makefile.am (datadir, libexecdir): Removed. + (awkdatadir): Renamed to pkgdatadir. + (pkgdatadir, LDADD): Use the make syntax to refer to other variables, + not @...@. + +Wed Feb 9 10:05:46 2005 Arnold D. Robbins + + * node.c (r_dupnode): Assign NULL to r->wstr after `getnode'. + Fix count of bytes to copy in call to `memcpy'. + Thanks to Kimura Koichi, . + +Tue Feb 8 19:26:22 2005 Pat Rankin + + * regcomp.c (init_dfa): Avoid strcasecmp() since regex.c doesn't + use awk.h and none of the assorted other included header files + are guaranteed to declare it. + (parse_expression): Modify casts for the string arguments passed to + build_charclass_op() to fix char * vs unsigned char * mismatch. + (parse_bracket_exp): Likewise add cast for the string argument + passed to build_charclass(). + +Mon Feb 7 15:04:09 2005 Arnold D. Robbins + + * eval.c (make_scalar): Don't use P() macro in definition. + Thanks to Juergen Kahrs . + +Wed Feb 2 16:36:19 2005 Arnold D. Robbins + + * main.c (main): Call `close_io', without its result affecting + the exit status. Super small, super dark corner. + + See test/exitval2.awk. + +Tue Feb 1 11:58:29 2005 Arnold D. Robbins + + * regex.h (__APPLE_CC__): Removed test and definition of __restrict. + Not needed for current MacOS X compiler. + +Sun Jan 30 13:56:37 2005 Arnold D. Robbins + + Fresh merge with CVS regex routines. Fixes handling of \B. + See tests/gnureop3.awk and also + http://sources.redhat.com/bugzilla/show_bug.cgi?id=693. + + CVS base versions: + + * regcomp.c: Version 1.92, Thu Jan 27 19:05:20 2005. + * regexec.c: Version 1.77, Thu Jan 27 19:06:34 2005. + * regex_internal.c: Version 1.49, Thu Jan 27 19:07:15 2005. + * regex_internal.h: Version 1.60, Wed Jan 26 22:40:50 2005. + * regexec.c: Version 1.77, Thu Jan 27 19:06:34 2005. + +Sat Jan 22 22:30:40 2005 Arnold D. Robbins + + Reinstate patch of 18 Nov 2001, for VMS, at least: + + * random.c (srandomdev): ifdef-out. Lots of compile time + problems on multiple platforms, and gawk doesn't even + use the routine. The heck with fine-grained solutions. + +Thu Jan 20 14:15:32 2005 Arnold D. Robbins + + * awkgram.y (LEX_FOR): Free NAME tokens in transformation of + `for (iggy in foo) delete foo[iggy]' into `delete foo'. + Thanks and a tip of the hatlo to Valgrind. + + * dfa.c (_): Clean up stuff here by just including "gettext.h". + Per Bruno Haible. + +Wed Jan 19 18:29:23 2005 Arnold D. Robbins + + * awkgram.y (yylex): Improve parsing of numeric constants + and hex values, via a push from Paul Eggert. See test/hex.awk. + + * regex_internal.c (re_node_set_alloc): If `size' is 0, just + zero out the structure. From valgrind. + +Tue Jan 18 17:23:25 2005 Arnold D. Robbins + + Make gawk multibyte aware. This means that index(), length(), + substr() and match() all work in terms of characters, not bytes. + + * awk.h (NODE): Add `wsp' and `wslen' elements to value for wide + string. + (WSTRCUR, wstptr, wstlen, force_wstring): New macros. + (str2wstr, wstrstr, wcasestrstr): New declarations. + * builtin.c (do_index, do_length, do_substr, do_match): Handle wide + strings. + * eval.c (flags2str): Add WSTRCUR. + * node.c (format_val, r_dupnode, mk_number, make_str_node, unref): + Add code to deal with wide strings. + (str2wstr, dump_wstr, wstrstr, wcasestrstr): New functions. + +Sun Jan 16 15:10:35 2005 Arnold D. Robbins + + * random.h (int32_t): Define this type. + +Thu Jan 13 14:38:13 2005 Arnold D. Robbins + + Cause `configure --disable-nls' to still allow locale-correct + formating of numeric values. + + * builtin.c (format_tree): Change #ifdefs to only test HAVE_LOCALE_H. + Improve code for ' flag so that extraneous separator is not included if + number of digits is multiple of locale separater count (3, 6, 9, etc.) + * dfa.c (dfaparse): Change ifdef to only test #ifdef LC_COLLATE. + * eval.c (fmt_ok): Remove ENABLE_NLS from #ifdef test. + * gettext.h: Include on both sides of test. Should really + be factored out. + * main.c (loc): Remove ENABLE_NLS from #ifdef test. + (main): Same in call to localeconv(). + * node.c (isnondecimal): Remove ENABLE_NLS from #ifdef test. + + Unrelated: + + * regcomp.c (init_dfa): Change `codeset' to `codeset_name' in two + places. + +Mon Jan 10 11:49:56 2005 Arnold D. Robbins + + Annual sync with glibc. + + * getopt_int.h: New file. + * Makefile.am (base_sources): Add it. + * getopt.h, getopt.c, getopt1.c: Updated. + * regcomp.c, regex.c, regex.h, regex_internal.c, regex_internal.h, + regexec.c: Updated. + + Original versions: + + getopt_int.h, 1.1, Tue Mar 9 10:31:19 2004 + getopt1.c, 1.10, Tue Mar 9 10:35:37 2004 + getopt.h, 1.21, Fri Mar 19 00:19:32 2004 + getopt.c, 1.53, Wed Mar 10 23:13:26 2004 + regcomp.c, 1.87, Mon Dec 6 02:56:42 2004 + regex.c, 1.126, Fri Jan 30 05:19:58 2004 + regex.h, 1.33, Thu Nov 18 23:50:57 2004 + regex_internal.c, 1.46, Thu Jan 6 20:59:49 2005 + regex_internal.h, 1.57, Mon Dec 27 16:29:05 2004 + regexec.c, 1.75, Mon Dec 27 16:29:52 2004 + + * regex.h: Add check for __APPLE_CC__ and definition of __restrict. + * regex.c: Add check for _MSC_VER and include . + * regex_internal.h (_RE_ENABLE_I18N): Change test. + (re_realloc): Add check/fix for SunOS 4.1.x. + * regex_internal.c (build_wcs_upper_buffer): ifdef label + `offsets_needed', add cast in call to `wcrtomb'. + * regcomp.c (build_charclass, build_charclass_op): Remove `unsigned' + from declarations of `char *' params. + (regerror): Remove use of mempcpy. + (peek_token): Disallow \s and \S for gawk. + (build_charclass): Change decl of `class_name' and use it directly. + Nuke variable `name'. + (build_charclass_op): Change decl of `class_name' and `extra'. + +Thu Jan 6 16:44:32 2005 Arnold D. Robbins + + Improve autoconfiscation stuff for wide character use. + + * builtin.c (do_tolower, do_toupper): Conditionally compile + call to `wide_tolower_toupper'. + (wide_tolower_toupper): Conditionally compile typedefs and function. + * mbsupport.h: Add check for having `wint_t', and `iswlower', + `iswupper', `towlower' and `towupper'. + * configure.ac (HAVE_WINT_T): Add test. + (AC_CHECK_FUNCS): Add `wint_t', `iswlower', `iswupper', `towlower' + and `towupper'. + + Unrelated change: + + * hard-locale.h (hard_locale): Add decl of `xmalloc' to prevent + redeclaration problems on some compilers. + +Wed Jan 5 10:20:17 2005 Arnold D. Robbins + + Update to Bison 2.0. + + * bisonfix.sed: Removed, no longer needed. + * Makefile.am (EXTRA_DIST): Removed bisonfix.sed. + (awkgram.c): Fix build rule. + * awkgram.c: Regenerated. + +Tue Jan 4 18:47:56 2005 Arnold D. Robbins + + Update to Automake 1.9.4. + + * alocal.m4, config.guess, config.sub, install-sh: Updated. + +Mon Jan 3 14:08:27 2005 Arnold D. Robbins + + Update to Automake 1.9.3. + + * INSTALL, alocal.m4, config.guess, config.sub, depcomp, + install-sh, missing, ylwrap: Updated. + +Mon Jan 3 11:23:36 2005 Arnold D. Robbins + + Fix obscure issue. ^ in RS should only match at the very + beginning of the input. Essentially, the file is one long + string. To do this, use the `not_bol' flag in the `struct + pattern_buffer'. Thanks to Stepan Kasal for pointing out the + problem and to Andreas Schwab for pointing out the mechanism + for a solution. + + * awk.h (RE_NEED_START, RE_NO_BOL): New flags for `research'. + (IOP_AT_START): New flag for IOBUF. + (research): Last parameter is now `flags'. + * builtin.c (do_match, sub_common): Change calls to `research'. + * eval.c (interpret, match_op): Same. + * field.c (re_parse_field): Same. + * io.c (spec_setup): Add IOP_AT_START flag. + (iop_alloc): Same. + (rsrescan): Modify logic to check IOP_AT_START and if not on to + add RE_NO_BOL to flags value in call to `research'. + (get_a_record): Clear IOP_AT_START upon return from `*matchrec'. + (iopflags2str): Add IOP_AT_START to table. Also IOP_CLOSED, + which was missing. (Ooops.) + * re.c (research): Last paramater is now flags. Modify logic to + handle RE_NO_BOL case by setting the right bit initially. Clean + up control flow so that it's cleared before returning. If RE_NO_BOL, + don't bother with the dfa matcher, as it doesn't have an analogous + capability. + +Wed Dec 22 12:33:48 2004 Arnold D. Robbins + + For --exec, don't allow x=y assignments where filenames would be. + Do allow -v. This is because we assume --exec is used mainly for + CGI stuff and we don't want var assigns to affect the code. + + Suggested by Stepan Kasal; motivated by reading about web security. + + * main.c (disallow_var_assigns): New variable. + (main): Set the var for --exec. + (arg_assign): Check it appropriately. + +Sun Dec 19 17:27:09 2004 Arnold D. Robbins + + * builtin.c (do_gensub): Make `global' flag smarter, such that + a string numeric constant (e.g., "3") acts like a numeric + constant. + * node.c (r_force_number): Not really related: Only set NUMCUR + if we actually convert some digits. + +Sun Dec 19 16:08:50 2004 Arnold D. Robbins + + * dfa.h, dfa.c: Synchronize with what's happening in GNU grep + development. Effectively only minor whitespace changes and some + slight code motion of ifdefs and includes. + * hard-locale.h: New file, extracted from old dfa.c. + * Makefile.am (base_sources): Add hard-locale.h. + +Sun Dec 19 11:13:45 2004 Arnold D. Robbins + + * io.c (socketopen): Change type of `readle' and `namelen' + variables to size_t. For QNX, but a good idea anyway. Thanks + to `Anthony' (rz1a@mail.ru). + +Mon Dec 6 11:11:22 2004 Arnold D. Robbins + + Undid change of Mar 9 2004, to add gofast patch. It gets things + wrong for gawk. This removes the bandaid of ifdef-ing out the + main check. Eventually this'll all get straightened out in the + GNU grep code. + + * dfa.c (buf_offset): Removed. + (SKIP_REMAINS_MB_IF_INITIAL_STATE): Removed use of buf_offset, do + free `mblen_buf', `inputwcs'. + (match_anychar, match_mb_charset, transit_state_consume_1char, + transit_state): Remove use of buf_offset in mblen_buf. + (dfaexec): Use `free' and `malloc', not `realloc'. + +Mon Dec 6 10:55:37 2004 Fumitoshi UKAI + + Forwarded from james@nocrew.org, the Debian contact. + + * dfa.c (parse_bracket_exp_mb): + 1. Build range correctly when IGNORECASE for [a-a] to also get 'A'. + 2. For [:lower:] and [:upper:], if ignoring case, set type string + to "alpha". This parallels code in the regex routines. + 3. Reset wc1 to EOF when parsing bracket expressions. + +Mon Nov 29 18:36:25 2004 Arnold D. Robbins + + * io.c (redirect): When allocating a new struct redirect, set + rp->pid to -1, not 0, so that code checking for EOF on an + input pipe works correctly. + +Thu Nov 25 14:22:41 2004 Stepan Kasal + + * Makefile.am (MAINTAINERCLEANFILES): Add. + * version.in (version_string): Use PACKAGE_STRING. + +Tue Nov 23 17:27:38 2004 Stepan Kasal + + * re.c: Fix a typo in a comment. + +Mon Nov 22 16:47:00 2004 Arnold D. Robbins + + * awkgram.y (yylex): Add lint check for tawk style modifiers on + regexes, /.../i and /.../s. Not that it'll help anyone. + +Wed Oct 27 14:25:18 2004 Stepan Kasal + + * builtin.c (do_tolower, do_toupper): Fix the wide char handling, + especially when the lowercased char doesn't ocuppy the same + number of bytes as its uppercase equivalent. Make use of ... + (wide_tolower_toupper): ... this new static function. + +Mon Oct 25 11:51:14 2004 Arnold D. Robbins + + * builtin.c (bchunk, bchunk_one, cksize): Change type of `olen' + to size_t from long. It is the 21st century now, after all... + Thanks to Stepan Kasal. + +Mon Oct 11 10:49:09 2004 Arnold D. Robbins + + * awkgram.y (yylex): Improve lint warnings for non-decimal constants. + * node.c (isnondecimal): Made a little smarter, thanks to Stepan Kasal. + +Thu Oct 7 21:59:38 2004 Arnold D. Robbins + + * dfa.c (dfamust): Redo fix of 22 Sep to match code from + current GNU grep. + +Sun Oct 3 23:06:00 2004 Arnold D. Robbins + + * node.c (isnondecimal): Made smarter, so that 0xEE does + register as non-decimal. Added parameter to indicate use of + locale's decimal point and changed declaration and callers. + +Tue Sep 28 18:38:17 2004 Arnold D. Robbins + + * node.c (isnondecimal): New function, now smarter. + * awk.h (isnondecimal): Changed from macro to function. + +Wed Sep 22 11:24:46 2004 Arnold D. Robbins + + * dfa.c (dfamust): At end, check results of `malloc'. + Based on bug report from Sorav Bansal + for grep. + +Mon Sep 20 13:18:18 2004 Arnold D. Robbins + + New --exec option. Needed for gawk CGI scripts to prevent + arbitrary options and/or source getting passed in from the web. + + * main.c (optab): New long option, --exec. + (main): Catch it. Like -f but end option processing. + (usage): Add it to the usage message. + + Thanks to John DuBois and Don Stokes for their input. + + Unrelated: + + * dfa.c (dfaexec): Disabled caching into buffer that bypasses + multibyte initialization, since it can get things wrong. Thanks + to Andreas Schwab . + +Mon Sep 20 12:59:42 2004 Andreas Schwab + + * awkgram.y (nextc): Check for end of lexer buffer before + advancing ring buffer index. + +Wed Sep 8 09:54:53 2004 Arnold D. Robbins + + * main.c (main): Force LC_NUMERIC locale to "C" before parsing + the program, since a variable assignment with -v can leave the + locale set incorrectly. + + Thanks to Sirix for reporting the problem. + +Wed Aug 25 18:55:30 2004 Arnold D. Robbins + + * main.c (UPDATE_YEAR): New constant at top of file, where we + won't miss it. + (copyleft): Use it. + +Sun Aug 22 17:26:39 2004 Stepan Kasal + + Define gawk_mb_cur_max even if there is no mbs support, as + ``const int'' and assign 1 to it. + This fixes a bug in re.c where #ifdef MBS_SUPPORT was missing. + + * awk.h (gawk_mb_cur_max): Declare. + * main.c (gawk_mb_cur_max): Define. + * awkgram.y (nextc_is_1stbyte): Without mbs support, define to 1. + * builtin.c (index_multibyte_buffer): Define a dummy function + when there is no mbs support. + * awkgram.y, builtin.c, re.c: Remove some `#ifdef MBS_SUPPORT'. + +Sun Aug 15 22:08:04 2004 Arnold D. Robbins + + Import current FreeBSD random.c. Make it work for gawk. + Needed for cases where long is more than 32 bits. + + * random.c: Imported from FreeBSD. Header includes tweaked. + * random.h: Typdef gawk_uint32_t appropriately and #define uint32_t + to it. + * configure.ac: Add calls to AC_CHECK_SIZEOF for unsigned int + and unsigned long. + + Started with + http://www.freebsd.org/cgi/cvsweb.cgi/src/lib/libc/stdlib/random.c + Thanks to Andreas Schwab for the pointer. + +Thu Aug 12 13:09:53 2004 Arnold D. Robbins + + * main.c (copyleft): Fix copyright year. + +Mon Aug 2 12:18:15 2004 Arnold D. Robbins + + * Release 3.1.4: Release tar file made. + +Mon Aug 2 12:17:40 2004 Arnold D. Robbins + + * configure.ac: Fix the hack. Do the sed on `Makefile', + not `Makefile.in'. Sigh. + +Sun Aug 1 14:48:30 2004 Arnold D. Robbins + + * configure.ac: MAJOR HACK: At end, remove version.c from Makefile.in + variable `CONFIG_CLEAN_FILES' so that `make distclean' doesn't + remove version.c. + +Mon Jul 19 17:07:27 2004 Arnold D. Robbins + + * config.guess, config.sub: Updated from Savannah CVS. + +Fri Jul 16 10:59:07 2004 Arnold D. Robbins + + * re.c (make_regexp): Bracket code using `gawk_mb_cur_max' + inside `#ifdef MBS_SUPPORT'. + +Thu Jul 15 12:36:25 2004 Arnold D. Robbins + + * dfa.c (parse_bracket_exp_mb): If doing case folding, + include the other case for regular characters inside [...]. + + * re.c (make_regexp): Smarten up handling of IGNORECASE, + particularly for multibyte character sets. Sigh. + +Wed Jul 14 16:25:23 2004 John Haque + + * eval.c (interpret): For `Node_K_return', use `copynode' + and not `dupnode' for non-PERM, non-TEMP values. + (func_call): Don't add TEMP flag to returned value. + + These two fix a problem uncovered by the July 8 change in + `assoc_lookup'. + +Wed Jul 14 16:14:09 2004 Arnold D. Robbins + + * awkgram.y (node_common): Add check `lexeme >= lexptr_begin', + from valgrind run. + +Wed Jul 14 16:00:51 2004 John Haque + + * io.c (rsrescan): Fix off by one error at end of record. + +Thu Jul 8 16:59:51 2004 Stepan Kasal + + * awkgram.y (output_redir): Make sure not to dereference NULL + pointer. The bug was triggered by the following code: + + gawk 'BEGIN{print "date" |& getline}' + + No test case created, beacuse of the following: + Correct interpretation involves executing "1" or "0" -- as the user + may have defined this, we would have to override this in the test + script. It's not worth the hassle. + +Thu Jul 8 12:59:49 2004 Arnold D. Robbins + + * awk.h (load_casetable): Name changed from `load_ignorecase'. + * eval.c (load_casetable): Name changed from `load_ignorecase'. + Fix all uses. + +Thu Jul 8 12:32:13 2004 John Haque + + * awkgram.y (get_src_buf): Fix off-by-one error to avoid "does not end + in newline" messages. + * array.c (assoc_lookup): Small performance hack: for TEMP subs nodes, + use its string memory for ahname. + * ext.c (get_actual_argument): Minor code cleanup. + * builtin.c (do_lshift, do_rshift, do_and, do_or, do_xor, do_compl): + fixed to issue "non-numeric argument" lint warnings before using + `force_number'. + +Mon Jun 21 16:53:35 2004 Arnold D. Robbins + + More changes from John Haque to rationalize extension functions. + + * awk.h (get_curfunc_arg_count): Name changed from + `get_curfunc_parm_count'. + * eval.c (get_curfunc_arg_count): Ditto, body redone to count actual + args passed at call time. + * ext.c (get_argument): Update range check. + (get_actual_argument): Simplify the code. + +Mon Jun 14 14:01:16 2004 Arnold D. Robbins + + Changes from John Haque and ADR to rationalize extension functions. + + * awk.h (check_special, get_curfunc_parm_count, get_actual_argument): + new function declarations. + (get_scalar_argument, get_array_argument): New macros. + * awkgram.y (check_special): New function. + (yylex): Use `check_special' to search `tokentab'. + (dump_funcs): Always count functions, in order to get dynamic ones. + Removed bogus use of `static' on `tab' variable. + * eval.c (struct fcall): Change type of `count' to `size_t'. + (get_curfunc_parm_count): New function. + (push_args): Set `r->rnode' to NULL for local variable. + * ext.c (make_builtin): Add sanity checking for presence and + name of new function, and that it's not a redefinition. + (get_argument): Check that requested arg is within range of actual + number of parameters. Also clean up logic for Node_var_new, + Node_var_array, Node_array_ref. + (get_actual_argument): New function. + * profile.c (pp_builtin): Better handling of dynamic extension function. + +Sun Jun 13 14:32:22 2004 Arnold D. Robbins + + * io.c (redirect): Conditionalize checking for process recovery + on `#ifdef PIPES_SIMULATED'. Needed for MS-DOS and VMS. + * builtin.c (tmp_integer): Change bracketing of magic test to + `#ifdef HAVE_UINTMAX_T' which is more general and more correct. + +Wed Jun 9 21:36:01 2004 Arnold D. Robbins + + * re.c (make_regexp): Add dfa matching into IGNORECASE handling. + +Tue Jun 8 15:38:56 2004 Arnold D. Robbins + + * awk.h (casetable): Remove `const'. + * eval.c (casetable): Remove `const'. + (load_ignorecase): New function. Loads locale-correct values in + upper 128 bytes. + (set_IGNORECASE): Call `load_ignorecase'. + +Tue Jun 8 14:04:19 2004 Arnold D. Robbins + + * awkgram.y (get_src_buf): Make sure that value from + `optimal_bufsize' is reasonable. Increase it if not. + +Tue Jun 8 13:54:28 2004 John E. Haque + + * awkgram.y (statement:LEX_FOR): Fix bug in loop to `delete a' + optimization. + * io.c (format_tree): Check for out of range values for + positional specifiers. + +Mon Jun 7 17:02:48 2004 Arnold D. Robbins + + * builtin.c (tmp_integer): Bracket the magic test inside + `#ifndef VMS'. + + * awk.h (child_catcher): Remove declaration. + * main.c (main): Remove `signal' calls for SIGCLD, SIGCHLD. + * io.c (child_died, child_signo, child_catcher): Removed. + (get_a_record): Remove code checking for death of child. + (redirect): If `rp' matches and is at EOF and type is input + pipe, and `rp->pid' is not -1, call `wait_any' to reap the + child. This is a heuristic, but it works pretty well. + +Sun Jun 6 18:35:17 2004 Arnold D. Robbins + + * io.c (get_a_record): Restore use of `memmove' instead of + memcpy. Otherwise some tests break on some systems. We think. + (child_died): Don't reset signal handler; breaks on some S5 systems. + (get_a_record): Reset handler if child_died. Still flaky on Solaris. + * configure.ac (version.c): Made from version.in again, for + non-Unix systems. + * Makefile.am (base_sources): Add version.c back. + * version.in: Include config.h for definition of const. + * main.c (version_string): Add back declaration, don't + include "version.i". + (main): Don't install child_catcher on Sun. (HACK) + +Thu Jun 3 14:06:06 2004 Arnold D. Robbins + + * main.c (version_string): Removed declaration, since + version.i is included directly. + * version.in: Removed test for definition of const. + +Tue Jun 1 19:23:53 2004 Stepan Kasal + + * Makefile.am (base_sources): Don't mention version.c, so that + it doesn't get distributed. + * po/POTFILES.in: Remove version.c + * configure.ac: Create version.i from version.in. + * main.c: Include version.i. + +Tue Jun 1 18:33:32 2004 Arnold D. Robbins + + Fix problem reported by Stephen Marchant + on Thu, 30 Oct 2003 13:11:42 -0500. + + * regex_internal.h (re_realloc): Allow for SunOS pre-Standard C + `realloc' which doesn't accept NULL pointers. + * awk.h (erealloc): Same. + + Unrelated. Change suggested by Peter Sobisch , have + PROCINFO["version"] be the version of gawk: + + * main.c (load_procinfo): Add in version. + + Unrelated: Avoid warning: + + * main.c (main): Cast calls to `bindtextdomain' and `textdomain' to + void. Avoids diagnostic with `configure --disable-nls'. + * dfa.c (check_matching_with_multibyte_ops): Remove unneeded nested + #ifdef, per Scott Deifik (scottd@amgen.com). Also fix some spelling + errors in comments. + +Tue Jun 1 18:26:45 2004 Paul Eggert + + Fix a bug reported by Mike Romaniw + to bug-gnu-utils on 2003-09-27: compl(compl(0xf0f)) returned 0xfff + on hosts with 64-bit uintmax_t and 64-bit IEEE-764 double, due to + rounding errors. + + * doc/gawk.texi (Bitwise Functions): Leading nonzero bits are + removed in order to fit the result into a C 'double' without rounding + error. + * builtin.c: Include if available. + (FLT_RADIX, FLT_MANT_DIG, DBL_MANT_DIG): Define if not already defined. + (AWKSMALL_MANT_DIG, AWKNUM_MANT_DIG, AWKNUM_FRACTION_BITS): New macros. + (tmp_integer): New function. + (do_lshift, do_rshift, do_and, do_or, do_xor, do_compl): Use them. + +Tue Jun 1 17:40:47 2004 Stepan Kasal + + * eval.c (push_args): Set var_value to Nnull_string for + local variables. + +Mon May 31 11:49:20 2004 Stepan Kasal + + * replace.c: #undef DEBUG before including mktime.c, it has + different meaning there. + +Mon May 31 08:25:30 2004 Arnold D. Robbins + + * array.c (get_actual): Add extra error message for `delete f' + inside body of function `f'. + +Mon May 3 09:53:34 2004 Arnold D. Robbins + + * Makefile.in, */Makefile.in: Updated to automake 1.8.4. + * config.guess, config.sub: Same. + * aclocal.m4, depcomp, install-sh: Same. + +Mon May 3 09:24:45 2004 Arnold D. Robbins + + * configure.ac: Look for missing `strtoul'. + * replace.c: Include missing_d/stroul.c if not HAVE_STRTOUL. + * io.c (devopen): Use `strtoul' instead of `strtod' for + extracting fd number from "/dev/fd/N". (Thanks to Jim Meyering.) + * field.c (set_FIELDWIDTHS): Use `strtoul' instead of `strtod' + when parsing FIELDWIDTHS values. (Thanks to Jim Meyering.) + +Mon Apr 19 20:12:57 2004 Arnold D. Robbins + + * Makefile.in, */Makefile.in: Updated to automake 1.8.3. + * config.guess, config.sub: Same. + +2004-03-18 Stepan Kasal + + * eval.c (make_scalar): Comment clarification. + + * array.c (get_actual): Remove the condition ``canfatal'' + before ``cant_happen()''; if the data are consistent, we + simply cannot get there with a non-func Node_param_list, + no matter whether we are called via get_array or not. + + * awkgram.y (variable): Make one longer message, to help translators. + +Tue Mar 9 17:34:10 2004 Arnold D. Robbins + + Adapted `gofast' patch from Redhat Enterprise version of grep + to current dfa.c. + + * dfa.c (buf_offset): New variable. + (SKIP_REMAINS_MB_IF_INITIAL_STATE): Modified to use it, don't + free `mblen_buf', `inputwcs'. + (match_anychar, match_mb_charset, transit_state_consume_1char, + transit_state): Use buf_offset in mblen_buf. + (dfaexec): Realloc things instead of free and malloc. + +Thu Mar 4 16:46:55 2004 Arnold D. Robbins + + * configure.ac (AC_FUNC_MBRTOWC): Added. + (AC_CHECK_FUNCS): Removed `mbrtwoc'. + (REGEX_MALLOC): Removed. Not needed for new regex* routines. + + * re.c (research): Removed comment and check for return of -2 + since that was for old regex using alloca or REGEX_MALLOC. + +Wed Mar 3 17:10:16 2004 Arnold D. Robbins + + * io.c (close_one): Don't close stdout or stderr; can happen if + /dev/stdout or /dev/stderr are used in redirection and all the + open files get used. + +Sun Feb 29 12:17:37 2004 Arnold D. Robbins + + * regcomp.c (build_charclass, build_charclass_op): Change type of + `class_name' parameter to `const char *' from `const unsigned char *' + and adjust callers. + +Thu Feb 26 15:20:22 2004 Arnold D. Robbins + + * awkgram.y (get_src_buf): Rewritten to better manage input and + supplying newlines on command line programs. Fixes problems reading + source files on Cygwin. + + Unrelated fixes from mary1john8@earthlink.net: + + * node.c (format_val): For no malloc case, free s->stptr if necessary. + * io.c (nextfile): Add missing call to `unref(FILENAME_node->var_value)' + for no files case. + (close_redir): Remove file from redirection list even if fp is + stdout or stderr. + +Tue Feb 24 12:11:34 2004 Arnold D. Robbins + + * regex_internal.c (build_wcs_upper_buffer): Enclose `offsets_needed' + label in `#ifdef _LIBC' to silence `unused label' compiler warning. + +Tue Feb 24 11:57:18 2004 Nelson H.F. Beebe + + * regcomp.c (parse_expression): Add cast to (unsigned char *) in calls + to `build_charclass_op'. + * regex_internal.c (build_wcs_buffer): Add cast to char* in call to + `wcrtomb'. + * regex_internal.h (bitset_not, bitset_merge, bitset_not_merge, + bitset_mask, re_string_char_size_a, re_string_wchar_at, + re_string_elem_size_at): Change to use prototypes. + (re_string_char_size_at, re_string_wchar_at, re_string_elem_size_at): + Declare as `internal_function'. + + * Makefile.am: Add rule to make .i files. This assists in debugging. + * awk.h (m_tree_eval): Add casts to NULL. (Some compilers are just + dumb. ADR) + +Mon Feb 23 15:58:39 2004 Arnold D. Robbins + + Clean up occupied process slots of children that have died: + + * awk.h (child_catcher): New function, declare it. + * main.c (main): Catch SIGCHLD/SIGCLD with `child_catcher'. + * io.c (child_died): New static variable. + (child_catcher): New function, sets `child_died', reinstalls self + as signal handler. + (close_rp): New function: isolates actual fp/iop closing logic. + (close_redir): Call `close_rp'. + (get_a_record): Check `child_died' and call `wait_any(0)' if so. + Add descriptive comment. + + Unrelated clean up: + + * eval.c (fcalls): Renamed from `fcall_list'. All uses changed. + (pop_fcall, push_args, dump_fcall_stack): Adjusted to use indexing + on `fcalls' instead of a pointer into it. Avoids hassles if `fcalls' + is realloc-ed during recursive tree_evals. Thanks to BWK. + + * config.guess, config.sub: Updated from Savannah. + +2004-02-19 gettextize + + * configure.ac (AM_GNU_GETTEXT_VERSION): Bump to 0.14.1. + +Wed Feb 18 12:40:09 2004 Arnold D. Robbins + + * awkgram.y (rule): Use `msg' not `warning' for `must have an + an action part' message. `warning' is wrong, since it's a real error. + +Mon Feb 16 12:17:39 2004 Arnold D. Robbins + + * main.c, eval.c, builtin.c: Change test for `#ifdef HAVE_LOCALE_H' + to `#if ENABLE_NLS && defined(HAVE_LOCALE_H)' so that builds with + `configure --disable-nls' will actually work on non-glibc systems. + +Thu Feb 12 02:05:34 2004 Stepan Kasal + + Lots of misc changes from Stepan Kasal integrated. + + * array.c: Various variables and parameters of static functions + changed from int to long, in order to prevent overflow. + + * eval.c (make_scalar): New function; takes care of everything + that has to be done when a node of type Node_var_new or + Node_array_ref changes to a scalar variable. + (tree_eval, get_lhs): Call it. + (tree_eval): From now on, tree_eval(NULL) doesn't work; + it reports an internal error. + * awk.h (m_tree_eval): Likewise for the two macro versions. + * awkgram.y (statement): Make sure the Node_K_return's lnode is + always the return value, never NULL. + + * Makefile.am (install-exec-hook, uninstall-links): Make use of + $(VERSION). + (INCLUDES): Renamed to AM_CPPFLAGS. + (AM_CPPFLAGS): The file libintl.h is generated in the + build subdirectory intl, not in the directory $(srcdir)/intl. + (diffout): New target is an alias for ``make -C test diffout.'' + * awklib/Makefile.am (INCLUDES): Renamed to AM_CPPFLAGS. + + * README_d/README.hpux: Change the whitespace in the appended patch, + so that it applies to the current source. + * posix/gawkmisc.c: Change a tab to a space (needed for the above). + + Make version control more in the style of current autotools: + + * configure.ac: Remove obsolete versions of macros: + AM_INIT_AUTOMAKE doesn't need any parameters. + AC_OUTPUT shouldn't have any parameters either. + Its parameters go to a new macro: AC_CONFIG_FILES. + AC_CONFIG_HEADERS moved near the end of the file. + * configure.ac: Add [version.c:version.in] to AC_CONFIG_FILES + * version.in: Modify for autoconf substitutions. + * version.c: Remove, it's generated at configure time now. + * fixvers, patchlev.h, unsupported/tandem/ptchlvl.h: Nuke and ... + * Makefile.am, main.c: ... forget them. + +Mon Feb 9 12:57:00 2004 Arnold D. Robbins + + * awk.h builtin.c eval.c field.c (HUGE): Changed to `UNLIMITED'. + Avoids possible conflict with constant in svid-mode math.h. Thanks to + Roman.Putanowicz@iecn.u-nancy.fr for pointing out the problem. + +Fri Feb 6 12:09:55 2004 Arnold D. Robbins + + * configure.ac: Check for `wctype', `wcscoll' and `iswctype'. + * mbsupport.h: New file. Merges and centralizes testing for MBS support. + * Makefile.am (base_sources): Add mbsupport.h to list. + * dfa.c, dfa.h, awk.h (MBS_SUPPORT): Include "mbsupport.h" and use the + test there. + * regex_internal (RE_ENABLE_I18N): Same. + + * Makefile.am (CLEANFILES): Added. + +Thu Feb 5 18:05:12 2004 Arnold D. Robbins + + * configure.ac (HAVE_WCTYPE_T): New test code added. + * dfa.h (wctype_t): Define if system doesn't. Needed here too + for other files that include dfa.h. + * dfa.c (wctype_t): Define if system doesn't. + (lex): Manually fill in arrays used for char class range testing + so will work on c89 and older compilers. + (parse_bracket_exp_mb): Split up an assignment to avoid type complaints. + + * main.c (main): When checking for `close_io' failure, only set + `exit_val' to 1 if not already exiting. + + * regcomp.c (regerror): Remove use of mempcpy. Generates too + many compiler warnings. + * configure.ac (AC_CHECK_FUNCS): Don't bother checking for it. + +Wed Feb 4 17:34:47 2004 Arnold D. Robbins + + * getopt.h (__THROW): Only define it if C++. The __GNU_PREREQ + macro is a major headache. + +2004-02-02 Paolo Bonzini + + * regexec.c (check_matching): Add P_MATCH_FIRST parameter. + (re_search_internal): Pass new parameter to check_matching. + (check_matching): Unless a parenthesized group is found at the + beginning of the regexp, advance P_MATCH_FIRST until we entered + a state different from the initial state. + +Mon Feb 2 15:52:37 2004 Arnold D. Robbins + + * re.c (research): Change last param to re_search to pass + NULL if `need_start' is false. May give us a marginal speed gain. + +Thu Jan 29 17:04:51 2004 Arnold D. Robbins + + * builtin.c (sub_common): Fix logic for `&' in replacement for + multibyte case. Simplify code a bit. + +Tue Jan 20 10:41:45 2004 Arnold D. Robbins + + * configure.ac: Add check for `memmove'. + * replace.c: Include missing_d/memmove.c if don't have `memmove'. + +Sun Jan 18 12:01:29 2004 Arnold D. Robbins + + * builtin.c (sub_common): Add comment and support for 2001 POSIX + behavior when --posix in effect. The masses have been + clamoring for this one. + +2004-01-16 gettextize + + * configure.ac (AM_GNU_GETTEXT_VERSION): Bump to 0.13.1. + * intl/*: Updated to 0.13.1. + +Fri Jan 16 08:16:38 2004 Arnold D. Robbins + + * getopt.h, getopt.c, getopt1.c: Synced to GLIBC version: + getopt.c: 1.51 + getopt.h: 1.18 + getopt1.c: 1.9 + +Thu Jan 15 15:28:48 2004 Arnold D. Robbins + + Here we go again: + + * regcomp.c, regex.h, regex.c, regex_internal.h, regex_internal.c, + regexec.c: Sync to GLIBC version, but with bug fixes. GLIBC + CVS versions: + + regcomp.c: 1.76 + regexec.c: 1.55 + regex.c: 1.125 + regex.h: 1.30 + regex_internal.c: 1.39 + regex_internal.h: 1.45 + regexec.c: 1.55 + + * acinclude.m4: Removed, not needed for automake 1.8.x. + * configure.ac: Updated to autoconf 2.59. + + Everything else updated to automake 1.8x and autoconf 2.59. + +Wed Jan 14 14:26:36 2004 Arnold D. Robbins + + * dfa.c, dfa.h: Updated manually with most of the changes in + grep 2.5.1. That version lost the ability to match newlines + in the data, so the merge had to be done by hand. Sigh. + +2004-01-12 Paolo Bonzini + + ALLOCA patch from + http://sources.redhat.com/ml/libc-alpha/2004-01/msg00099.html + added. + + * regcomp.c [_LIBC && !RE_ENABLE_I18N]: + Drop code to support this, it is never true. + (build_range_exp) [!_LIBC]: Do not create a range + in MBCSET for a single-byte character set. + (build_range_exp) [_LIBC]: Do not create a range + in MBCSET for a single-byte character set without + collation elements. + (init_dfa): Do not conditionalize on _LIBC, it + just makes the code less clear. + (parse_bracket_exp): Use NON_MATCH variable in + addition to "mbcset->non_match", not as an + alternative. + (build_charclass_op): Rename NOT parameter to + NON_MATCH, use it instead of declaring a variable. + (parse_bracket_exp) [!_LIBC]: Pass NULL for MBCSET + if the character set is single-byte. + +Wed Jan 7 15:23:04 2004 Arnold D. Robbins + + * awkgram.y (mk_rexp): Set n->re_cnt to 1. Makes reinstated + dfa code actually take effect! Don't know how I missed this. + + Unrelated: sync regex code to glibc. + + * regcomp.c, regex.h, regex.c, regex_internal.h, regex_internal.c, + regexec.c: Sync to GLIBC version, but with bug fixes. GLIBC + CVS versions: + + regcomp.c: 1.74 + regex.c: 1.124 + regex.h: 1.30 + regex_internal.c: 1.39 + regex_internal.h: 1.43 + regexec.c: 1.55 + + * regcomp.c (peek_token): Temporarily, we hope, disable \s and \S + operators. Too much trouble to document right now. + * dfa.c (lex): Add code for \s and \S but disable it until + next release. + +Wed Dec 24 15:28:57 2003 Arnold D. Robbins + + * eval.c (r_tree_eval): For Node_assign_concat, add + call `free_temp(r)'. Thanks to mary1john8@earthlink.net. + +Mon Dec 1 10:25:52 2003 Arnold D. Robbins + + CONSTVAL not needed if we test PERM instead. Thanks to + mary1john8@earthlink.net. See test/concat3.awk. + + * awk.h [CONSTVAL]: Removed. + * eval.c (flag2str): Removed CONSTVAL from table. + (r_tree_eval): For Node_assign_concat, it's enough to check + if l->flags has PERM clear. + * awkgram.y (yylex): Removed use of CONSTVAL for YSTRING and YNUMBER. + +Mon Nov 3 16:33:26 2003 Arnold D. Robbins + + * awkgram.y (get_src_buf): Replace `memmove' with `memcpy' for + marginal portability gain to older systems. + * io.c (get_a_record): Ditto. + +Sun Nov 2 15:59:27 2003 Arnold D. Robbins + + * awk.h [CONSTVAL]: Renamed from `STRCONST'. + * eval.c (flags2str): Fix in table. + (r_tree_eval): For Node_assign_concat, check for the flag for + both left and right hand sides. Also add a `force_string' call + for the right hand side and the left hand side. + * awkgram.y (yylex): Change flag value for YSTRING and add use + of flag for YNUMBER. + +Wed Oct 29 14:23:29 2003 Arnold D. Robbins + + * awk.h [STRCONST]: New flag value. + * eval.c (flags2str): Add it to table. + (r_tree_eval): For Node_assign_concat, check for the flag so that + we don't clobber string constants given: + s = "" + s = s something + * awkgram.y (yylex): For YSTRING, set STRCONST flag. + +Tue Oct 28 18:00:00 2003 Arnold D. Robbins + + Force SUBSEP to always have a string value. Per bug report + from mary1john8@earthlink.net. + + * awk.h (NODETYPE): New type, Node_SUBSEP. + (set_SUBSEP): Add declaration. + * awkgram.y (isnoeffect, isassignable): Add Node_SUBSPEP case. + * array.c (set_SUBSEP): New function. + * eval.c (nodetypes): Add Node_SUBSEP. + (r_tree_eval, r_get_lhs): Add code for Node_SUBSEP. + * main.c (varinit): Use Node_SUBSEP as type for SUBSEP. + * profile.c (tree_eval, pp_lhs, is_scalar, prec_level): Handle + Node_SUBSEP. + +Tue Oct 7 09:26:33 2003 Arnold D. Robbins + + * awk.h (NODETYPE): New member `Node_assign_concat'. + * awkgram.y (exp): Look for case of `x = x y' and if so, create a + Node_assign_concat. + * eval.c (interpret): Add case for Node_assign_concat. + * profile.c (prec_level): Ditto. + (tree_eval): Ditto. For variables, call new function `vname' to + print name; handles varname field for -v variables, which end up + including the value. + (vname): New function. + +Wed Sep 24 17:32:31 2003 Arnold D. Robbins + + Speed up `avoid_dfa' kludge, at least a little: + + * awk.h (struct Regexp): Add `has_anchor' member. Make it and + `dfa' member shorts; keeps space the same. + * re.c (make_regexp): Set `has_anchor' member correctly. + (avoid_dfa): Test for `has_anchor' member instead of searching + for it each time. + +Sun Sep 21 18:34:32 2003 Arnold D. Robbins + + * builtin.c (state): Only needs to be 256 bytes, initstate() can't + use any more than that. Well whadayaknow. + (do_rand, do_srand): Call `setstate' after calling `initstate'. + +Tue Sep 16 15:44:29 2003 Arnold D. Robbins + + * eval.c (interpret): For Node_K_switch, add kludge_need_start stuff + as used in `match_op'. Sigh. + * re.c (make_regexp): Add `no_dfa' variable, which is true if + GAWK_NO_DFA exists in the environment. This enables run time + testing of things with/without the dfa matcher. + +Mon Sep 15 18:36:38 2003 Arnold D. Robbins + + After much soul searching, reinstated old dfa code. The performance + of the new regex is just disastrous. Sigh. + + * awk.h (re_cnt): Reinstated old definition. + (struct Regexp): Added `dfareg' and `dfa' members. + (make_regexp): New last parameter in function, changed decl. + (avoid_dfa): Added declaration. + * awkgram.y (regexp, mk_rexp): Added use of `re_cnt'. Fixed call + to `make_regexp'. + * Makefile.am: Add dfa.h and dfa.c. + * eval.c (match_op): Complexified: added call to `avoid_dfa' and + `kludge_need_start' variable where used to pass FALSE as last parameter + of research(). + * field.c (set_FS): Fixed call to `make_regexp'. + * io.c (get_a_record, set_RS): Fixed calls to `make_regexp'. + * re.c (make_regexp): Added last paramter (`dfa') to function. + Complexified the code. + (re_update): Fixed call to `make_regexp'. + (research): Complexified the code, added calls to dfa stuff. + (dfaerror): New function. + (re_update): Fixed call to `make_regexp'. + (avoid_dfa): New function. + +Tue Sep 9 15:57:38 2003 Arnold D. Robbins + + * awkgram.y (get_src_buf): Fix calculation of `offset' when shifting + source lines around. In general, improve handling of things when + moving the source code line around. What a mess this code is. + +Mon Sep 8 19:08:55 2003 Arnold D. Robbins + + * eval.c (fmt_ok): Make provision for %F format and printf %'f flag + here too. + +2003-07-23 Christophe Bisiere (tiny change) + + * posix/regex.h (RE_TRANSLATE_TYPE): Define it to "unsigned char," + to avoid problems at hosts with signed char. + * posix/regexec.c (re_search_internal): Don't say + "unsigned RE_TRANSLATE_TYPE." + +Thu Aug 28 11:09:41 2003 Arnold D. Robbins + + * io.c (nextfile): Change use of variable `files' to make it + clearer that it's a boolean flag. + +Tue Aug 26 22:58:15 2003 Arnold D. Robbins + + * io.c (useropen): Add `defined (HAVE_GETGROUPS)' as first test + in `#ifdef'. Brings things in sync with same test in main.c and awk.h. + +Tue Aug 26 22:49:37 2003 Arnold D. Robbins + + * dbug.h: New file. + + * array.c, awkgram.y, builtin.c, eval.c, ext.c, field.c, io.c, + main.c, msg.c, node.c, profile.c, re.c: Converted to use + Fred Fish's `dbug' library. By default compiled out, thus + not affecting speed. + + For the nonce, the `dbug' library itself is not shipped with + gawk, since I expect no-one else but me to be using it. + +Thu Aug 21 23:15:36 2003 Arnold D. Robbins + + * awkgram.y (numfiles): Change extern decl to long, to match what's + in main.c. Keeps things working on 64-bit systems. Thanks to bug + report from Jan Oravec . + +Wed Aug 20 14:53:47 2003 Arnold D. Robbins + + * eval.c (genflags2str): Move test for out-of-space inside test + for is the bit set. + +Mon Aug 11 11:26:51 2003 Arnold D. Robbins + + * regcomp.c (parse_bracket_exp): If `build_charclass' fails, just pass + its value on as the return value. + +Sun Aug 10 16:59:14 2003 Arnold D. Robbins + + * regcomp.c (build_range_exp): Make sure we don't + get WEOF on range characters. + +Tue Aug 5 21:49:32 2003 Arnold D. Robbins + + * array.c (get_actual): In `case Node_param_list' add test for + `&& (symbol->flags & FUNC) == 0' to the if. + +Sun Jul 13 18:28:38 2003 Arnold D. Robbins + + Further bug fix: + + * awkgram.y (variable): Give the new variable an lnode + of Nnull_string if it's not an array, even if it is + a Node_var_new. + +Fri Jul 11 09:32:21 2003 Arnold D. Robbins + + Bug fix: + + * eval.c (r_tree_eval): For Node_array_ref, set + tree->orig_array->var_value to Nnull_string too. + + Unrelated i18n and POSIX change: + + * configure.ac: Add check for local printf supporting %F format. + * awk.h (loc): New variable declaration. + * main.c (loc): Defined. + (main): Call `localeconv' to set loc. + * io.c (format_tree): Add support for printf quote flag, %'d for + decimal formats (not %e, %E), adds thousand separator into value. + +2003-07-10 Paul Eggert + + * io.c (two_way_open): If /bin/sh cannot be executed, exit + with status 126 consistently. + +Mon Jul 7 11:01:43 2003 Arnold D. Robbins + + * Release 3.1.3: Release tar file made. + +Mon Jul 7 09:55:49 2003 Arnold D. Robbins + + * main.c (copyleft, usage): Make sure to fflush output fp. Per Jim + Meyering, if error, exit non-zero. + * ext.c (get_argument): Fix array paramater handling. + +2003-07-06 Paul Eggert + + * builtin.c (do_substr): Issue better diagnostics when + d_substr and d_length are NaN, or when 0 < d_length < 1. + Be careful when comparing double to SIZE_MAX, as + the comparison might return the "wrong" answer when + `(double) SIZE_MAX' is a number that is not equal to + SIZE_MAX. + (do_gensub): Watch out for HOW values that are out of range + or are NaN. + (do_dcngettext): dcngettext wants an argument of type + unsigned long, not long, so use a value of that type. + +Fri Jul 4 10:58:02 2003 Arnold D. Robbins + + * main.c (main): Make option letter 'D' fall through into default + unknown case if not debugging. Let's us have just one version of + `optlist'. + +Thu Jun 26 15:25:57 2003 Arnold D. Robbins + + * array.c (get_actual): Undo Stepan Kasal change of 2003-06-17. + See test/match2.awk. + +Wed Jun 25 15:26:08 2003 Arnold D. Robbins + + * builtin.c (do_rand): Change calculation so that result + obeys constraint: 0 <= N < 1. This is per history and POSIX. + Thanks to Nelson Beebe (beebe@math.utah.edu) for reporting + this issue. + +Mon Jun 23 15:13:39 2003 Arnold D. Robbins + + * io.c (rs1scan): Per advice from Bruno Haible, it's safe + to skip the multibyte checking code if RS is '\n'. See + the comment in the code. Big performance improvement for + multibyte locales. + +2003-06-20 Stepan Kasal + + * eval.c (comp_func): If memcmp returns 0, we have to compare + the lengths. + +2003-06-19 Stepan Kasal + + * eval.c (interpret) : Use NULL, not 0, to + initialize the variable list. + (comp_func): Array indices no longer are string values, + you have to use ahname_str, ahname_len. + +Tue Jun 17 11:53:46 2003 Arnold D. Robbins + + * array.c (get_actual): Make check for isparam + smarter: also check for FUNC flag. + +2003-06-17 Stepan Kasal + + * array.c (get_actual): Even if canfatal is FALSE, don't + tolerate existence of things which can't happen. + +Mon Jun 16 16:21:44 2003 Arnold D. Robbins + + * configure.ac: Removed m4/Makefile. + * m4/Makefile.am: Removed. + +2003-06-16 gettextize + + * configure.ac (AC_OUTPUT): Add m4/Makefile. + (AM_GNU_GETTEXT_VERSION): Bump to 0.12.1. + +Sun Jun 15 20:45:43 2003 Arnold D. Robbins + + * io.c (get_a_record): Enhance logic to fill buffers to include + `|| no_data_left(iop)'. + (rs1scan): Fix logic for setting recm fields for multibyte + character case. + +2003-06-10 Stepan Kasal + + * awkgram.y (release_all_vars): Do not try to release a value of + Node_var_new; after get_lhs, use the lhs directly, do not try + to do (*lhs)->var_value; the Node_var case doesn't need + special treatment. + * builtin.c (do_match): `get_param' is successful iff it returns + Node_var_array---if the variable was new, get_param has already + changed the type. + * field.c (do_split): Likewise. + +Sun Jun 15 19:36:35 2003 Arnold D. Robbins + + * node.c (r_dupnode): Typo fix in hash tables: stptr -> ahname_str. + Thanks to mary1john8@earthlink.net. + * array.c (get_actual): Add `if (canfatal)' before call to + `cant_happen'. + +Sun Jun 15 19:25:49 2003 Patrick T.J. McPhee + + * awk.h (memcpy_ulong): Add ! WIN32 to ifdefs. + +Mon Jun 9 18:38:20 2003 Arnold D. Robbins + + * custom.h (hpux): Added stuff to (hopefully) get `tzset' + declared on HP/UX 10 and up. + +Mon Jun 9 17:12:24 2003 Patrick T.J. McPhee + + * awk.h (ATTRIBUTE_EXPORTED): New macro for dynamic libs on Windows32. + * CONVMFTidx, stack_ptr, do_lint, lintfunc: Now have this attribute. + +Mon Jun 9 13:11:33 2003 Arnold D. Robbins + + Clean up of Stepan's patches. + + * array.c (get_actual): Renamed from r_get_array. Added second + param canfatal if routine should print fatal message when not an array. + (get_actual): Renamed 'prm' to `isparam'. + (array_vname): Add static msglen var; only realloc string if it grows. + Don't use `s += sprintf(...)'. No good on old systems where sprintf + returns char *. Minor formatting cleanups. + (do_adump): Restored separate `a' and `r' variables; helps for debugging. + + * awk.h (SCALAR, UNINITIALIZED): Removed entirely, renumbered other flags. + (get_array, get_param): New macros, calls get_actual. + (get_actual): Declaration changed from that of r_get_array. + + * awkgram.y (release_all_vars): Restored previous version of code; new + version isn't right for Node_xx variables. + (variable): Minor code cleanup for readability. + + * builtin.c (do_match): Use get_param and print our own message when + third parameter is not an array. + + * eval.c: Added a few comments here and there, removed some no longer + needed comments. + + * field.c (do_split): Use get_param and print our own message when + second parameter is not an array. + +Mon Jun 9 11:46:21 2003 Arnold D. Robbins + + * array.c (do_delete): Initialize hash1 and last to keep gcc -Wall happy. + * io.c (rsnullscan): Comment out label skip_leading for same reason. + +Wed May 28 08:31:23 CEST 2003 Stepan Kasal + + * eval.c (forloops_active, in_function): Nuked. + (pop_all_forloops, pop_fcall_stack): Are now inline. + +Wed May 28 07:58:35 2003 Stepan Kasal + + * field.c, awk.h (Null_field): No longer static. + * field.c (init_fields): Initial value of $0 can be Nnull_string, + no need to copy it. + * eval.c (r_get_lhs) : Test for uninitialized field, + which is Nnull_string for $0 and Null_field for $(>0). + * builtin.c (do_print_rec): Test for uninitialized $0. + +Tue May 27 17:03:02 2003 Stepan Kasal + + * awk.h (Node_var_new): New node type for variables which can be + either scalar or array. From now on, Node_var is always scalar. + (Node_gvar_ref): Nuked, its role can be taken by Node_array_ref. + (orig_var): Removed, orig_array is enough. + (SCALAR, UNINITIALIZED): Flags nuked. + (var_uninitialized): New macro to distinguish uninitialized vars; + used in several other macros. + * array.c (r_get_array, array_vname, do_adump): Adapt to the + above changes. + * awkgram.y, eval.c, field.c, main.c, node.c, profile.c: Ditto. + +Tue May 27 14:27:50 2003 Stepan Kasal + + * array.c (r_get_array): New function, which goes all the way + through Node_param_list to actual Node_var_array; if it encounters + non scalar Node_var, it changes it to Node_var_array. + (in_array, do_delete, do_delete_loop, do_adump, assoc_sort_inplace): + Use get_array. + (assoc_lookup): The parameter must be a Node_var_array. + * awk.h (get_array, r_get_array): Declare the new function and define + a macro to speed it up. + * builtin.c (do_match): Use get_array. + * eval.c (interpret) : Ditto. + (r_get_lhs) : Ditto. + * field.c (do_split): Ditto. + +Tue May 27 08:23:51 2003 Stepan Kasal + + Changed node->vname meaning for type Node_array_ref and Node_gvar_ref. + It contains only the reference name; one has to (recursively) follow + node->prev_array to find out the call history for the array. + + * array.c (array_vname): New function to print the array name. + (assoc_lookup, do_delete): Use array_vname. + * eval.c (interpret, r_tree_eval, r_get_lhs): Use array_vname. + (push_args, pop_fcall): Things have simplified. + * awk.h (array_vname): Declare. + (prev_array): Define. + +Sun Jun 8 11:25:36 2003 Stepan Kasal + + * awkgram.y (append_right): When using savetail, remember that it + is not necessarily the tail of the list---it's just a pointer to + the last chunk appended. + +Thu Jun 5 12:01:41 2003 Arnold D. Robbins + + * builtin.c (do_strtonum): Make `strtonum(13)' work. + +Wed Jun 4 17:07:06 2003 Corinna Vinschen + + * io.c (binmode): Include function for __CYGWIN__ too. + +Tue Jun 3 12:40:50 2003 Arnold D. Robbins + + * eval.c (interpret): Node_K_switch. For regex case, don't + call `free_temp' on the result of `force_string' if it's equal to + switch_value. Thanks to John DuBois + for finding the problem. + +Sun Jun 1 13:08:22 2003 Arnold D. Robbins + + * builtin.c (format_tree): For %c, force precision to 1. + +Wed May 28 11:55:48 2003 Arnold D. Robbins + + * awkgram.y (isnoeffect, isassignable): Add Node_TEXTDOMAIN to + switches in both functions. + +Wed May 28 11:38:59 2003 Stepan Kasal + + * awkgram.y (switch_body): Remove rule ``switch_body:/*empty/'' + as ``switch_body:case_statements'' covers it---this disambiguation + fixes a reduce/reduce conflict. + +Sun May 25 16:23:43 2003 Corinna Vinschen + + * configure.ac: Remove linking against /usr/lib/automode.o. + * configure: Regenerate. + +Sun May 25 15:19:19 2003 Stepan Kasal + + * awk.h (get_lhs): For an initialized Node_var, you may return + the address of var_value pointer, no matter whether reference + bit was set or not. We were silly slowing down most of the + assignements. + + * (get_a_record): After grow_iop_buffer, move recm.rt_start even + if recm.len == 0. + +Mon May 19 16:55:59 2003 Arnold D. Robbins + + Code for C-style switch statements. Initial version contributed by + Michael Benzinger . + + Disabled by default, use `configure --enable-switch' to turn it on. + + * configure.ac: New AC_ARG_ENABLE for switch statements. + * awk.h (NODETYPE): New types for switch, case, default keywords + and respective lists. + * awkgram.y: New productions for switch statement. Does checking to + avoid duplicate cases. + * eval.c (nodetypes): New entries for new NODETYPEs. + (interpret): New code to do switch execution. + * profile.c (pprint): New code to print switch statements. + +Mon May 19 15:05:43 2003 Arnold D. Robbins + + * configure.ac: Renamed from configure.in. + * fixvers: Now looks in configure.ac. + * Makefile.am: Now cites configure.ac. + + * Misc other: Updated to Automake 1.7.5. + +Sun May 18 12:03:56 2003 Arnold D. Robbins + + * array.c (do_delete_loop): Fix bracing of logic for + tests. + +Wed May 14 09:01:16 2003 Stepan Kasal + + Misc patches: + + * builtin.c (do_match): If third parameter to `match' is supplied, + store all subexpressions which are applicable, even though there + are some unused between them. + + * awkgram.y (yylex): When returning from unterminated REGEXP + (which is /* kludge */), take care to fake a yylval, to + prevent ``internal error'' later. + +Sun May 11 15:51:00 2003 Stepan Kasal + + * io.c (rsnullscan, get_a_record): Boundary condition bug fixes. + +Sun May 11 15:15:20 2003 Scott Deifik + + * awk.h: Add decls for `memcpy_ulong', `memset_ulong', and + MSC defines. + * regex.c: Include if MSC for size_t. + +Mon May 5 15:11:06 2003 Arnold D. Robbins + + * io.c (get_a_record): Only tweak RT's value in place if the current + RS scanner is the same as the last one. Bug report submitted by + John DuBois (). + +Fri May 2 14:39:48 2003 Arnold D. Robbins + + * io.c (get_a_record): Add logic at end to be smart about setting + RT. Saves considerable time, esp for default case where RS = "\n". + +Wed Apr 30 11:44:38 2003 Arnold D. Robbins + + * field.c (do_split): Add check and code for Node_gvar_ref. + * array.c (in_array, do_delete, asort_actual): Same. + * builtin.c (do_split): Same for 3rd arg array parameter. + * eval.c (interpret): Same for Node_K_array_for. + (push_args): Same for evaluating extra args. + +Tue Apr 29 15:54:28 2003 Arnold D. Robbins + + Record reading code redone/simplified considerably. + + * awk.h (IOBUF): Removed total field, no longer used. + * io.c (at_eof, has_data, no_data_left): New macros. + (RECVALUE, SCANSTATE): New enumerated types. + (rs1get_a_record, rsnull_get_a_record, rsre_get_a_record): Removed. + (get_a_record): Rewritten, again. Now contains just buffer and + record code; searching code moved into these functions: + (rs1scan, rsnullscan, rsrescan): New functions to scan a buffer + for record contents and terminator. Fill in values in: + (struct recmatch): Holds found record and terminator. + (spec_setup): Set iop->dataend to indicate data is already in buffer. + (nextfile, inrec): Use new macros instead of flag and pointer tests. + (set_RS): Set scanning function instead of record function. + + FWIW, it all passes `make test'. + +Sun Apr 27 21:02:39 2003 Arnold D. Robbins + + * io.c (do_close): At end, if do_posix return 0. See comment in code. + +Tue Apr 15 09:56:03 2003 Isamu Hasegawa + + * configure.in: Check existence of wcrtomb, and wcscoll. + * configh.in: Likewise. + * configure: Re-generate. + Thanks to Kimura Koichi for reporting. + +Sun Apr 13 16:02:10 2003 Arnold D. Robbins + + * main.c (main): Add call to `setlocale' for LC_NUMERIC after program is + parsed. + (arg_assign): Switch back to "C" locale for LC_NUMERIC for command + line assignments; this is per POSIX that period is decimal point for + program and command line assignments and the locale's separator + applies for input, output, and string to number conversion. + +2003-03-26 Paul Eggert + + * builtin.c [HAVE_INTTYPES_H]: Include . + [!HAVE_INTTYPES_H && HAVE_STDINT_H]: Include . + (CHAR_BIT, INTMAX_MIN, UINTMAX_MAX): Define if the system does not. + (TYPE_SIGNED, TYPE_MINIMUM, TYPE_MAXIMUM): New macros, taken from + coreutils and many other GNU utilities. + (format_tree): When formatting, use widest possible integers + rather than settling with 'long'. + (do_lshift, do_rshift, do_and, do_or, do_xor, do_compl): Likewise, + when doing bitwise operations. + * configure.in (jm_AC_TYPE_LONG_LONG, jm_AC_TYPE_UNSIGNED_LONG_LONG, + jm_AC_TYPE_INTMAX_T, jm_AC_TYPE_UINTMAX_T): Add, since the mainline + code now needs this. + * doc/gawk.texi (Control Letters, Bitwise Functions): Document this. + * m4/intmax_t.m4: New file, taken from coreutils (but renamed to + avoid collision with our m4/inttypes.m4). + * m4/longlong.m4: New file, taken from coreutils. + * m4/uintmax_t.m4, m4/ulonglong.m4: Remove; superseded by the above + new m4 files. + + * builtin.c (BITS_PER_BYTE): Remove; use CHAR_BIT instead, since + it's the standard name. + (do_lshift, do_rshift): Complain if the shift width is exactly equal + to the word size, too. + +Thu Mar 27 10:44:11 2003 Arnold D. Robbins + + * io.c (rs1_get_a_record, rsnull_get_a_record, rsre_get_a_record): + Enhance check for no data left in file to be only if file has + non-zero size. Linux files such as /proc/filesystems stat as a + regular file of size 0, but actually have contents. Ugh. + Thanks to Martin Schlemmer for the bug report. + +Wed Mar 26 12:19:32 2003 Arnold D. Robbins + + * builtin.c (format_tree): Add a lint warning at label `out_of_range'. + +Tue Mar 25 12:24:38 2003 Arnold D. Robbins + + * awkgram.y (variable): For array subscript, if NAME is in the + symbol table, but not a variable, array, or parameter, generate + a syntax error. + (isarray): New function, tests if a symbol can be an array. + + * custom.h: Add check for HP/UX, needed for GCC. + +Mon Mar 17 09:21:09 2003 Arnold D. Robbins + + Allow simultaneous manipulation of a global array directly + and when passed as a parameter. + + * awk.h (Node_gvar_ref): New nodetype. + [orig_var]: New macro. + * array.c (do_delete_loop, do_delete): Add logic to handle + seeing Node_gvar_ref. + * eval.c (nodetypes): Add Node_gvar_ref. + (r_tree_eval, r_get_lhs): Add Node_gvar_ref case. + +Wed Mar 19 14:10:31 2003 Arnold D. Robbins + + This time for sure. + -- Bullwinkle + + * Release 3.1.2: Release tar file made. + +Wed Mar 19 14:08:11 2003 Arnold D. Robbins + + * awkgram.y: Production `program --> program error'. Add a return so + that we don't produce an infinite stream of error messages. + Thanks to Michael Mauch for pointing this out. + +Wed Mar 19 13:45:50 2003 Corinna Vinschen + + * regex.c [RE_ENBABLE_I18N]: Remove definition; the one in + regex_internal.h is better and makes things work with Cygwin. + +Tue Mar 11 11:54:20 2003 Arnold D. Robbins + + * regex_internal.h: Don't include after was + included in regex.c, since it could redefine RE_DUP_MAX to a lower + value. + (bitset_set, bitset_clear, bitset_contain): Use 1UL instead of 1 in + left shift operations. + * regex.c: Include before + * regcomp.c (re_compile_fastmap_iter, init_word_char, parse_expression): + Use 1UL instead of 1 in left shift operations. + +Mon Mar 10 15:45:37 2003 Corinna Vinschen + + * configure.in: Update CYGWIN case to add /usr/lib/automode.o. + +Thu Mar 6 11:07:36 2003 Arnold D. Robbins + + Updated to automake 1.7.3. + + * config.guess, config.sub: Updated from prep. + * Makefile.am (AUTOMAKE_OPTIONS): Add dist-bzip2 to get .bz2 files. + +Tue Mar 4 10:40:46 2003 Arnold D. Robbins + + * version.in: Added goop for K&R compilers; forgot that I have to fix + this file which then is used to create version.c. + +Mon Mar 3 17:00:44 2003 Arnold D. Robbins + + * configure.in: New option --disable-lint. + * awk.h (do_lint, do_lint_old): Conditionally declare based on NO_LINT. + * eval.c (set_LINT): Ifdef out body if NO_LINT. + * main.c (do_lint, do_lint_old): Conditionally compile properly. + (main): Handle --lint argument code. + +Fri Feb 28 10:43:07 2003 Arnold D. Robbins + + * main.c (main): Add LC_TIME to the things that get set with + setlocale(). + * builtin.c (format_tree): Change test of `n0-- <= 0' to ==, avoids + VMS diagnostic. + +Thu Feb 27 17:48:29 2003 Pat Rankin + + * regexec.c (proceed_next_node): Cast re_string_get_buffer to char *. + (get_subexp): Likewise. + +Tue Feb 25 12:33:41 2003 Arnold D. Robbins + + * regex_internal.h, regex_internal.c, regcomp.c, regexec.c: + Make MB_CUR_MAX into thread local variable re_mb_cur_max. + + Unrelated, from Scott Deifik: + + * io.c (grow_iop_buffer): Add checks for overflow of new buffer size. + +Mon Feb 24 13:30:59 2003 Arnold D. Robbins + + * awk.h (gawk_mb_cur_max): Declared: + * main.c (gawk_mb_cur_max): Defined, init to 1. + (main): Initialize gawk_mb_cur_max. + * awkgram.y, builtin.c, eval.c, field.c, io.c, re.c (mb_cur_max): + Replaces all instances of MB_CUR_MAX, which is a function call (!) + in glibc. Big speed up, especially for -Fx case, where x is a + single character. + + Unrelated: + + * awkgram.y (rule): For non-existent action, use a Node_K_print_rec + node. + +Sun Feb 23 15:45:20 2003 Arnold D. Robbins + + Speed up plain `print' and `print $0': + + * awk.h (Node_K_print_rec): New node type. + (do_print_rec): Declare function. + * awkgram.y (simple_stmt): Create humongous test for plain `print' + or `print $0', and if so, use a Node_K_print_rec for it. Modify + test for lint message. + * builtin.c (redirect_to_fp): New function for common code to get fp + and rp for do_print{,f,_rec} functions. + (do_print): Use redirect_to_fp(). + (do_printf): Use redirect_to_fp(). + (do_print_rec): New function to just print $0 from field_arr[0] + directly; will rebuild the record first if necessary. + * eval.c (nodetypes): Add Node_K_print_rec. + (interpret): Add Node_K_print_rec case. + * profile.c (pprint): Add Node_K_print_rec case. + (pp_print_stmt): If null lnode, print "$0" else print the lnode. + + Unrelated: + + * regex_internal.h: Add ENABLE_NLS to the condition for using + gettext so that --disable-nls really disables it. + +Sat Feb 23 22:46:00 2003 Arnold D. Robbins + + * io.c (rs1_get_a_record, rsnull_get_a_record, rsre_get_a_record): + Modify buffer-filling algorithm to always read one or more multiples + of the blocksize (iop->readsize). + (grow_iop_buffer): Make sure there's room for the current partially + read record and one disk block buffer. + +Thu Feb 20 22:02:00 2003 Arnold D. Robbins + + * re.c (research): Fix typo in cast of precision value to int. + * regex.h, regex.c, re_internal.h, re_internal.c, regcomp.c, regexec.c: + synced to GLIBC source, maintaining K&R portability changes, and bug + fixes, although losing ability to compile each file separately. + * Makefile.am (SOURCES): Moved placement of regex source files from here ... + (EXTRA_DIST): ... to here. + +Tue Feb 18 14:17:33 2003 Arnold D. Robbins + + * re.c (research): Cast precision value to int. + * builtin.c (format_tree): For toofew, cast field width value to int. + * io.c (rsre_get_a_record): Initialize restart and reend. Add a variable + to make sure they're set before used at end of function. + (iopflags2str): Removed decl at top and made not static so that GCC + stops complaining that it's defined but not used. Bleah. + +Mon Feb 17 11:02:34 2003 Arnold D. Robbins + + * config.guess, config.sub: Updated from prep. + +Sun Feb 16 15:47:15 2003 Scott Deifik + + * awk.h (format_tree, make_str_node): Changed decls to match how + they are called. + * builtin.c (format_tree, sub_common): Same. + * node.c (make_str_node): Same. + +Wed Feb 5 14:18:01 2003 Arnold D. Robbins + + * awk.h: Removed duplicate decl of set_prof_file(). Removed + undef of const for non-ANSI C; config.h should handle it. + * msg.c (set_loc): Use srcfile and srcline in regular code to shut up + stupid SGI compiler. + +Tue Feb 4 14:28:06 2003 Arnold D. Robbins + + All relevant files: Copyright year updated to 2003. + +Tue Feb 4 13:40:41 2003 Martin C. Brown + + * intl/libgnuintl.h: Preprocessor fixes for MacOS X. + * regex.h: Ditto. + +Tue Feb 4 13:39:37 2003 Arnold D. Robbins + + * awkgram.y (builtin_func): New string for use in rationalizing + function parsing and installation code. + +Sun Feb 2 16:00:55 2003 Arnold D. Robbins + + Cache function body code pointer so that only have to find it the + first time a function is called. This potential for optimization + brought to my attention by Stepan Kasal. + + * awk.h [funcbody]: New macro. + * awkgram.y (FUNC_CALL): Set $$->funcbody to NULL. + * eval.c (func_call): Changed to take top-level Node_func_call as the + single parameter. Do the lookup and caching. + (r_tree_eval): Change how func_call() is called in switch. + * profile.c (pp_func_call): Similar changes. + (tree_eval): Ditto. + +Sun Feb 2 15:32:42 2003 Stepan Kasal + + ADR: More grammar rationalization/repair from Stepan. + + * awkgram.y (common_exp, simp_exp): The rule from getline (without + pipe) has been moved from common_exp to simp_exp. + + The redirection of print statements reworked. The idea comes from + mawk-1.3.3; much thanks to Michael Brennan! + + * awkgram.y (IO_OUT, IO_IN): New tokens. + (APPEND_OP, TWOWAYIO): Swallowed by the above ones. + (in_print, in_parens): New static variables, to trace whether + IO_OUT is expected. + (yylex): Emit the new tokens, update in_parens on '(' and ')'. + (exp): The print command(s) reworked. + (oputput_redir): Reworked. + (print_expression_list): New non-terminal. + (rexp, rexpression_list opt_rexpression_list): Nuked. + (exp, simp_exp): ``cmd|getline'' rule changed to + ``cmd IO_IN getline'' and moved from exp to simp_exp. + + Unrelated: + + * awkgram.y (variable): Don't return Node_func, issue a fatal + error instead. + * eval.c (r_tree_eval, r_get_lhs): Omit special checks for Node_func, + nodes of this type cannot get into the program tree. + * profile.c (tree_eval, pp_lhs): Likewise. + +Thu Jan 30 17:42:05 2003 Stepan Kasal + + ADR: Applied lots of patches from Stepan. + + * array.c (do_delete_loop): Call after_assign for the loop index. + * field.c (do_split): The third argument to split(), sep, has to be + evaluated and the result dupnoded before assoc_clear is called, + similarily as src. And we needn't to evaluate the third argument + if it's CONSTant regex and the first parameter is null string. + * awk.h (dupnode): Changed to macro, function renamed to r_dupnode. + * node.c (dupnode, r_dupnode): Rename. + * awkgram.y (parms_shadow): Return bool value, ... + (shadow_funcs): ... which will enable us to end the program if + lintfunc is fatal. + (program): Cleanup of the rules defining the ``program'' non-terminal. + (start, program, rule): No value associated, + expression_value is now treated similarily as begin_block and end_block. + (pattern, rule): Bison actions for non-terminal `pattern' now + add a new rule to the appropriate Node_rule_list, action for + non-terminal `rule' now only adds the associated code block + to the rnode of Node_rule_node. + (io_allowed): Renamed to !begin_or_end_rule. + (append_pattern): New function, adds new Node_rule_node to a rule_list. + (mkrangenode): Deleted, this tiny function was called only once. + (function_body): Non-terminal replaced by `action'. + (statements, action, statement): `statements' can now be empty; + both callers had to accomodate to this. + (statements): Don't call isnoeffect($2->type) if + $2 happens to be NULL. + +Mon Jan 27 14:12:19 2003 Arnold D. Robbins + + * io.c (iop_close): Based on report by Stepan Kasal and because of + his changes, don't call reset_record() when saving a copy of contents + of $0. + * awkgram.y: Improved function parsing error messages for case where + user uses a builtin name as a function name. Based on error report + by Stepan Kasal. + * ext.c (make_builtin): Set FUNC flag for new function. Based on error + report by Stepan Kasal. + +Mon Jan 27 14:06:20 2003 Stepan Kasal + + * field.c (reset_record): No longer call set_record(), the code is + moved to the function body. Do not set MAYBE_NUM. + (set_record): Call reset_record() to perform the common tasks. + The prototype has changed, change awk.h and all callers. + +Mon Jan 27 10:50:03 2003 Arnold D. Robbins + + * awk.h (NODE): `proc' renamed to `builtin,' to fix a conflict + on some systems. Replaced on all spots where it was used. + +Sun Jan 26 11:52:01 2003 Arnold D. Robbins + + * awk.h [NUMSUBPATS]: New macro. + * builtin.c (do_match): Use it in loop that fills in subpattern info. + * eval.c (r_tree_eval): For Node_assign, don't call free_temp(), + as assign_val() contains dupnode(), which would clear the TEMP + flag. From Stepan Kasal . + * config.sub: Updated from prep. + +Sun Jan 19 22:34:01 2003 Arnold D. Robbins + + * awk.h (do_asorti): Add declaration. + * awkgram.y (tokentab): Add asorti() function to table. + * array.c (ASORT_TYPE): New enumerated type for VALUE or INDEX array + sorting. + (assoc_sort_inplace): New second arg of type ASORT_TYPE. Additional code + to rearrange array so rest of merge-sorting works; basically values are + tossed and index moved into value spot. + (asort_actual): Renamed from do_asort(). Takes new ASORT_TYPE argument. + (do_asort): Calls asort_actual(tree, VALUE). + (do_asorti): Calls asort_actual(tree, INDEX). + + * main.c (load_procinfo): Free groupset array when done with it. + +Thu Jan 16 18:30:50 2003 Arnold D. Robbins + + * builtin.c (do_match): Revised to provide start and length + indices in array 3rd parameter. + * config.guess, config.sub: Updated from prep. + +Thu Jan 2 11:09:12 2003 Arnold D. Robbins + + Updated to bison 1.875. + +Tue Dec 31 17:14:45 2002 Arnold D. Robbins + + Updated things to automake 1.7.2 and autoconf 2.57. + +Tue Dec 31 16:54:44 2002 Arnold D. Robbins + + * awk.h [IOP_CLOSED]: New flag. + * io.c (iop_close): Set IOP_CLOSED flag. + (inrec): Check for IOP_CLOSED; if set return EOF. + (rs1_get_a_record, rsnull_get_a_record): Check for EOF before + refilling buffers. + (rsre_get_a_record): Ditto. Also, set RT before updating pointers in IOP. + * Makefile.am (efence): New target to compile with Electric Fence. + +2002-12-23 Kaveh R. Ghazi + + * awk.h (catchsig): Delete prototype. + * main.c (catchsig): Make static and remove excess argument. + (main): Delete unnecessary casts. + * io.c (rs1_get_a_record, rsnull_get_a_record): Mark parameter + with ATTRIBUTE_UNUSED. + +Mon Dec 23 11:54:07 2002 Arnold D. Robbins + + * regex_internal.h, regex_internal.c, regcomp.c, regexec.c, version.c: + Fixed to compile, once again, under K&R compilers. + * io.c (grow_iop_buffer): Fix calculation of new size to + first subtract 2, double, then add 2 back in. + +Fri Dec 20 11:48:42 2002 Arnold D. Robbins + + get_a_record split into three routines. + + * awk.h (IOBUF): Structure reworked for new code. + * io.c (get_a_record): Now a pointer to different functions. + (rs1_get_a_record, rsnull_get_a_record, rsre_get_a_record): New functions. + (iop_alloc, iop_close): Reworked for new structure. + (do_getline, inrec): Modifiend for new EOF condition. + (iopflags2str): New routine. + +Fri Dec 20 11:05:50 2002 Isamu Hasegawa + + * regex.c, regex_internal.c, regex_internal.h: Changes to allow separate + compilation of the reg*c files. + * regcomp.c: Fix bug in using translation tables with [[:upper:]] etc. + * Makefile.am: Move regex files into sources from EXTRA_DIST. (ADR) + +Mon Dec 9 14:20:42 2002 Stepan Kasal + + * main.c (main): When processing option '-f' don't ignore spaces + if optarg points at the beginning of the current argument + (like ``gawk -f " " file''). + +2002-11-30 Kaveh R. Ghazi + + * awkgram.y (stopme): Mark parameter with ATTRIBUTE_UNUSED. + (yyerror): Add ATTRIBUTE_PRINTF_1. + * builtin.c (do_systime, do_rand): Likewise. + * field.c (set_field, re_parse_field, def_parse_field, + posix_def_parse_field, null_parse_field, sc_parse_field, + fw_parse_field): Likewise. + * io.c (pidopen, useropen): Likewise. + * main.c (catchsig): Likewise. + * profile.c (init_profiling): Likewise. + * awk.h (err): Add ATTRIBUTE_PRINTF. + * msg.c (err): Delete redundant prototype. Fix format specifier. + +Wed Nov 27 06:04:20 2002 Pat Rankin + + * ext.c [#if !DYNAMIC] (do_ext): Cast string value for error node. + +Sun Nov 24 18:23:29 2002 Arnold D. Robbins + + From Paul Eggert, with some edits by me. + + * builtin.c (do_substr): Consistently use floating point + values for lint messages, so they should be printed pretty + much as the user saw them. Check for overflow before + converting floating point to integer. Do the right thing with + NaNs. + + Check for index out-of-range before checking for length + out-of-range, to avoid some nasty effects if address + arithmetic overflows (e.g., indx + length < index). + + Allow zero-length substrings when checking for lint if + do_lint == LINT_INVALID. + +Sun Nov 24 18:21:06 2002 Arnold D. Robbins + + * awk.h (LINT_ALL, LINT_INVALID): New constants. + * main.c (main): Allow --lint=invalid which restricts warning to + things that aren't valid. + * eval.c (set_LINT): Update setting logic. + +Wed Nov 20 13:14:58 2002 Arnold D. Robbins + + * awk.h (lintfunc): Improve ifdef for attribute to only + work for GCC 3.2 and later. + * io.c (PIPES_SIMULATED): Don't define if on AIX, which + does define TANDEM in one of its header files. Ugh. + +Tue Nov 19 15:33:55 2002 Arnold D. Robbins + + * builtin.c (do_substr): Use %lu in warnings instead of %d. + +Mon Nov 18 14:42:53 2002 Arnold D. Robbins + + * config.guess: Synced from ftp.gnu.org. + * config.sub: Ditto. + +Sun Nov 17 21:32:49 2002 Arnold D. Robbins + + Updated things to automake 1.7.1. + +Sun Nov 3 14:33:30 2002 Arnold D. Robbins + + * eval.c (r_get_lhs): For variables, always clear UNINITIALIZED, + since the variable is about to be assigned to. From Stepan Kasal. + +Fri Nov 1 11:19:01 2002 Arnold D. Robbins + + * awk.h (lintfunc): Can only supply attributes for a function + pointer if GCC >= 3. Added ifdefs. Bah, humbug. + +2002-10-30 Kaveh R. Ghazi + + * array.c (array_init, concat_exp, assoc_find, do_delete): + Const-ify. + * awk.h (redirect, set_record, pp_func, pp_string_fp, format_val, + parse_escape, make_regexp, research, reisstring, remaybelong): + Likewise. + * awkgram.y (dumpintlstr, dumpintlstr2, func_use, dup_parms, + var_comp, finfo, fcompare, func_use, dumpintlstr, dumpintlstr2): + Likewise. + * builtin.c (stdfile, do_fflush, do_index, category_table): + Likewise. + * eval.c (push_forloop, push_args, PUSH_BINDING, RESTORE_BINDING, + cmp_nodes, op_assign, loop_info, fcall, fmt_ok, set_LINT, + comp_func): Likewise. + * ext.c (do_ext): Likewise. + * field.c (set_record): Likewise. + * io.c (gawk_popen, two_way_open, binmode, redirect, getredirect, + fatal): Likewise. + * node.c (values, format_val, make_str_node, parse_escape): Likewise. + * profile.c (pp_string, pp_match_op, pp_func, pp_string, + pp_string_fp): Likewise. + * re.c (make_regexp, research, reisstring, remaybelong): Likewise. + +2002-10-30 Kaveh R. Ghazi + + * awk.h (__attribute__, ATTRIBUTE_UNUSED, ATTRIBUTE_NORETURN, + ATTRIBUTE_PRINTF, ATTRIBUTE_PRINTF_1, __extension__): Define. + (emalloc, erealloc): Fix format specifier warnings. + (do_nextfile):Mark with ATTRIBUTE_NORETURN. + (getredirect): Const-ify. + (msg, error, warning, r_fatal, lintfunc): Mark with + ATTRIBUTE_PRINTF_1. + (r_fatal): Mark with ATTRIBUTE_NORETURN. + * builtin.c (format_tree): Fix format specifier warning. + * eval.c (interpret): Likewise. + * main.c (usage, copyleft, catchsig, nostalgia, version): Mark + with ATTRIBUTE_NORETURN. + * profile.c (dump_and_exit): Likewise. + +2002-10-29 Kaveh R. Ghazi + + * array.c (array_init): Use ISDIGIT, not isdigit. + * awk.h (m_tree_eval, force_number, force_string): Use + __extension__ in statement expressions. + * main.c (lintfunc): Fix !__SDTC__ case. + * regex_internal.c (calc_state_hash): Fix inline declaration. + * regexec.c (proceed_next_node): Cast assignment to correct type. + +2002-10-29 Kaveh R. Ghazi + + * awk.h (exp_node, Func_ptr): Add prototype arguments. + * awkgram.y (yystype, token, getfname, nextc, pushback, + allow_newline, yylex): Likewise. + * io.c (wait_any): Likewise. + * profile.c (indent_in, indent_out): Likewise. + * random.h (random): Likewise. + +2002-10-29 Kaveh R. Ghazi + + * array.c (grow_table): Const-ify. + * awk.h (RE_TRANSLATE_TYPE): Define. + (flagtab, casetable): Const-ify. + (getfname, shadow_funcs, redflags2str): Prototype. + (flags2str, genflags2str, nodetype2str, redflags2str, set_loc, + msg, error, warning, r_fatal): Const-ify. + * awkgram.y (tokentab, snode): Likewise. + * builtin.c (format_tree, do_strftime, + localecategory_from_argument): Likewise. + * eval.c (casetable, nodetypes, nodetype2str, flags2str, + genflags2str): Likewise. + * io.c (redflags2str, socketopen): Likewise. + * main.c (varfile, version_string, lintfunc, optab, copyleft, + varinit, init_vars): Likewise. + * msg.c (srcfile, msg, warning, error, set_loc, r_fatal): + Likewise. + * profile.c (pp_op_assign, pp_match_op, pp_redir): Likewise. + * random.c (sccsid): Likewise. + * version.c, version.in (version_string): Likewise. + +Tue Oct 29 10:50:52 2002 Arnold D. Robbins + + * configure.in: Update version in AC_INIT and AM_INIT_AUTOMAKE + * fixvers: Make grep for pattern a little smarter. + +Mon Oct 28 16:35:39 2002 Arnold D. Robbins + + * awk.h (hash): Now a function pointer. + * array.c (gst_hash_string, scramble): New functions. + (awk_hash): Renamed from hash. + (hash): Now a function pointer. + (array_init): Change hash function based on environment for + experimentation. + +Mon Oct 28 13:21:20 2002 Arnold D. Robbins + + Applied lots of patches from Stepan Kasal, tweaked as needed + for current code base. + + * node.c (dupnode): When n->stref overfows, flag the node as PERM. + Same for n->ahname_ref. + (unref): Remove the check for n->stref == LONG_MAX and + n->ahname_ref == LONG_MAX. + * awk.h (make_string): The third argument to make_str_node changed + from FALSE to 0, it's not Boolean. + (free_temp): Evaluate the argument only once, so that we + can call free_temp(tree_eval(n)) for achieving side effects. + (load_environ, load_procinfo): Changed return type to NODE *. + * main.c (load_environ): The ENVIRON_node should be created with type + Node_var_array and lnode set to NULL. Return pointer to the created node + and create an empty hash even on TANDEM. + (load_procinfo): Same mods for PROCINFO_node. + (init_args): ARGV_node should also have lnode set to NULL. + * eval.c (r_tree_eval): case Node_assign moved just above the other + assignment cases. + (op_assign): ++ and -- cases merged with += and -=, respectively. + (push_args): Evaluate all args, even in cases where more args are + supplied then required. + (interpret): In case Node_K_forarray, flag the variable + num_elems also as volatile, so that it survives longjmp() and + can be trusted when linting code. + (r_get_lhs): Case Node_param_list was unreachable (unless + something breaks really badly), remove it; + (r_tree_eval): Case Node_var_array removed from the last switch, + it was caught in the first switch above. + * profile.c (tree_eval): Again, case Node_var_array was caught above. + * awkgram.y (variable): Code simplified, making use of the above + changes. + * field.c (sc_parse_field): IGNORECASE only applies to regex based + field-splitting, so remove code that pays attention to it. + (do_split): Don't use parse_field if RS_is_null. + (set_FS): Beware of FS == "\\" even if RS_is_null. + + Code changes to make things work better: + * field.c (set_FS): Don't use cmp_nodes() to compare old and new + value of FS, that uses IGNORECASE, which is a bad idea. Improve + logic for choosing sc_parse_field. Ensure that when RS_is_null + but using a single character, that we do pay attention to + case when doing regex splitting. + * io.c (set_RS): Don't use cmp_nodes() to compare old and new + value of RS, that uses IGNORECASE, which is a bad idea. + +Mon Oct 28 09:43:14 2002 Arnold D. Robbins + + * recomp.c (parse_expression): Change return statement into + two so it'll compile for SGI cc. + + * awk.h (STR, CUR): Changed to STRCUR and NUMCUR respectively, + to avoid conflict with STR on some System V systems. Changed + in all source files. + +Thu Oct 24 16:14:34 2002 Arnold D. Robbins + + * array.c (AVG_CHAIN_MAX): Now a variable, to allow easy experimentation. + (array_init): Pulls a new value from env var AVG_CHAIN_MAX if it + exists and sets the variable. + * awk.h: Add declaration for array_init(). + * main.c (main): Call array_init(). + +Tue Oct 22 11:23:56 2002 Arnold D. Robbins + + * bisonfix.sed: Updated for current bison. Death to alloca! + +2002-10-21 Isamu Hasegawa + + * builtin.c (tolower, toupper): Add casts to char* to fix some + compiler warnings. + * eval.c (cmp_nodes): Ditto. + * regcomp.c (peek_token_bracket): Skip the byte already read. + +Wed Oct 16 15:02:09 2002 Arnold D. Robbins + + * io.c (set_RS): Make sure to always call set_FS(). + +2002-10-11 Isamu Hasegawa + + * regcomp.c (re_compile_fastmap_iter): Remove the handling + OP_CONTEXT_NODE. + (regfree): Likewise. + (create_initial_state): Likewise. + (analyze): Remove the substitutions which became useless. + (calc_first): Likewise. + (calc_epsdest): Use edests of OP_BACK_REF in case that it has + epsilon destination. + (duplicate_node_closure): New function. + (duplicate_node): Remove the handling OP_CONTEXT_NODE. + (calc_inveclosure): Likewise. + (calc_eclosure): Likewise. + (calc_eclosure_iter): Invoke duplicate_node_closure instead of + direct invocation of duplicate_node. + (parse): Don't use comma operator in the return to avoid compiler + warning. + (parse_reg_exp): Likewise. + (parse_branch): Likewise. + (parse_expression): Likewise. + (parse_sub_exp): Likewise. + (parse_dup_op): Likewise. + * regex_internal.c (re_dfa_add_node): Remove the substitutions + which became useless. + (create_ci_newstate): Remove the handling OP_CONTEXT_NODE. + (create_cd_newstate): Likewise. + * posix/regex_internal.h (re_token_type_t): Remove the obsolete type. + (re_token_t): Likewise. + (re_dfa_t): Likewise. + (re_node_set_remove): New macro. + * regexec.c (check_matching): Remove the handling + OP_CONTEXT_NODE. + (check_halt_node_context): Likewise. + (proceed_next_node): Likewise. + (pop_fail_stack): Fix the memory leak. + (set_regs): Likewise. + (free_fail_stack_return): New function. + (sift_states_backward): Fix the memory leak. Remove the handling + OP_CONTEXT_NODE. + (update_cur_sifted_state): Append some if clause to avoid redundant + call. + (sub_epsilon_src_nodes): Use IS_EPSILON_NODE since it might be a + back reference. + (check_dst_limits): Remove the handling OP_CONTEXT_NODE. + (check_subexp_limits): Likewise. + (search_subexp): Likewise. + (sift_states_bkref): Likewise. + (transit_state_mb): Likewise. + (transit_state_bkref_loop): Likewise. + (transit_state_bkref_loop): Likewise. + (group_nodes_into_DFAstates): Likewise. + (check_node_accept): Likewise. + (sift_ctx_init): Add initializing. + +Tue Oct 15 14:18:53 2002 Arnold D. Robbins + + * eval.c (set_IGNORECASE): Call set_RS() instead of + set_FS_if_not_FIELDWIDTHS(). The former calls the latter + for us, and also makes IGNORECASE affect RS like it's supposed to. + * field.c (FS_re_yes_case, FS_re_no_case): New variables. + (set_FS): Smarten up routine to not recompile FS_regexp if all + that's changed is IGNORECASE or if switching back to FS from + FIELDWIDTHS. Significant speed-up for cases where IGNORECASE + is assigned to for every record. + * io.c (RS_re_yes_case, RS_re_no_case): New variables. + (set_RS): Similar changes as to set_FS(). In particular, + IGNORECASE changing now affects record splitting too. + * re.c (refree): Set rp->pat.tranaslate to NULL. It comes + from casetable and shouldn't be freed. (Strictly necessary + only for old regex, but a good idea anyway). + Also, call regfree(& rp->pat) instead of manually free()ing + things, since there's dynamically allocated stuff hiding in + the buffer. Avoids a memory leak. + +Mon Oct 14 12:02:39 2002 Arnold D. Robbins + + Major space reduction in array management. Overhead reduced + to two NODE's per element from three. + + * awk.h (ahash): Union is gone. + (hash.ref): New union member. + (ahnext): New definition into hash union. + (ahvalue): New definition into hash union. + (ahname_str): New member, points into hash union. + (ahname_len): New member, points into hash union. + (ahname_ref): New member, points into hash union. + * array.c: Replaces uses of ahname member with string and + length. Set the reference count correctly to 1 on new nodes. + * eval.c (interpret): Case for Node_K_arrayfor. dupnode() the + array indices, and set loop variable to new value made via + make_string(). + * node.c (unref, dupnode): Node_ahash nodes are now also + reference counted, a la strings. Similar code is used to + increment/decrement the counts, and/or copy nodes as + needed. + + Unrelated: + * awk.h (forsub): Removed. Not used. + +Sun Oct 13 16:58:27 2002 Stepan Kasal + + * profile.c (pprint): #undef the temporary defines at the end + of the case. + * eval.c (interpret): Likewise. + (assign_val): We can unref() before doing dupnode(). + Also, move the check for NF < 0 from here ... + * field.c (set_NF): ... to here. + * main.c (varinit): No need to call set_NF(). + * awkgram.y (statements): Don't be so generous when concatenating + `statements' with a `statement'. + + +2002-10-13 Isamu Hasegawa + + * regcomp.c: Synced with development sources. + * regex_internal.c: Synced with development sources. + * regex_internal.h: Synced with development sources. + * regexec.c: Synced with development sources. + +Sun Oct 13 21:35:35 2002 Arnold D. Robbins + + * awk.h (NODE): Reflags is now unsigned long for: + (exec_count): Defined to be sub.nodep.reflags. Using `number' + broke pgawk. + * profile.c (Node_K_delete_loop): Print out as a for loop + with a comment that it's internally the same as `delete array'. + * eval.c (Node_K_delete_loop): Increment the exec_count. Ooops. + * configure.in (AM_GNU_GETTEXT_VERSION): New macro call. + * custom.h: Updated description of the file at the top. + +Thu Oct 10 16:39:51 2002 Arnold D. Robbins + + * awk.h (vname, exec_count): Now macros into different + parts of the NODE structure that can be safely used for them. + Saves 16 bytes per NODE. + * eval.c: Changed use of `vname' to `varname' to avoid new + macro. + * main.c (lintfunc): Made ifdefed decls match awk.h. + * eval.c (comp_func): Use memcmp instead of strcmp. + * configure.in (AC_CONFIG_HEADER): Physically append custom.h + to config.h to avoid subdir compiliation problems. + +Sun Oct 6 17:36:15 2002 Arnold D. Robbins + + Updated to automake 1.7 and bison 1.50. + + * INSTALL: Replaced with current version from automake 1.7. + * config.guess: Replaced with current version from automake 1.7. + * config.sub: Replaced with current version from automake 1.7. + * depcomp: Replaced with current version from automake 1.7. + * doc/texinfo.tex: Replaced with current version from automake 1.7. + * install-sh: Replaced with current version from automake 1.7. + * missing: Replaced with current version from automake 1.7. + * mkinstalldirs: Replaced with current version from automake 1.7. + * ylwrap: Replaced with current version from automake 1.7. + + * configure.in (DYNAMIC): Updated AC_DEFINE(DYNAMIC) to + three-argument form for autoheader. + * acinclude.m4: Removed includes of jm-mktime.m4 and + largefile.m4, which are now standard parts of Autoconf. + + * Makefile.in: Regenerated. + * aclocal.m4: Regenerated. + * awkgram.c: Regenerated. + * awklib/Makefile.in: Regenerated. + * configure: Regenerated. + * doc/Makefile.in: Regenerated. + * test/Makefile.in: Regenerated. + +Sun Sep 29 16:47:49 2002 Arnold D. Robbins + + * custom.h (__WIN32__): Added from gnuwin32 project, via + Stepan Kasal. + + * awkgram.y: For tawk compatibility, added `delete(array)'. + To remain undocumented, since it's WAY non-standard. + +Sun Sep 22 22:23:50 2002 Arnold D. Robbins + + * awk.h (re_cnt): Removed, not needed since no dfa code. + * awkgram.y (regexp, a_regexp): Removed use of re_cnt. + * re.c (re_update): Ditto. + +Thu Sep 19 10:55:37 2002 Arnold D. Robbins + + * io.c (binmode): Create function if defined(WIN32) also. + + Updated to gettext 0.11.5, autoconf 2.54 and automake 1.6.3. + + * aclocal.m4: Regenerated. + * m4/codeset.m4: Updated. + * m4/gettext.m4: Updated. + * m4/glibc21.m4: Updated. + * m4/iconv.m4: Updated. + * m4/lcmessage.m4: Updated. + * m4/lib-ld.m4: Updated. + * m4/lib-link.m4: Updated. + * m4/lib-prefix.m4: Updated. + * m4/progtest.m4: Updated. + * po/Makefile.in.in: Updated. + * po/Rules-quot: Updated. + * po/boldquot.sed: Updated. + * po/en@boldquot.header: Updated. + * po/en@quot.header: Updated. + * po/insert-header.sin: Updated. + * po/quot.sed: Updated. + * po/remove-potcdate.sin: Updated. + +Tue Sep 17 23:46:01 2002 Arnold D. Robbins + + * configure.in: Moved override of INSTALL to just after + AC_INIT so that it takes effect. Necessary for Autoconf 2.5x. + +Mon Sep 16 16:40:57 2002 Stepan Kasal + + * awkgram.y (want_assign): Removed. + (SLASH_BEFORE_EQUAL, ASSIGN): New terminals; ``/='' is now + formed from these two. + (a_slash): New non-terminal, representing either '/' or + SLASH_BEFORE_EQUAL. + (assign_operator): New non-terminal, replaces ASSIGNOP. + (REGEXP): yylex now eats the terminating '/' before + returning REGEXP token. + (exp): The check for C-like comments moved from here + (regexp): ... to here. + (common_exp): New non-terminal; contains common parts of exp + and rexp. (a_relop, relop_or_less): New non-terminals. + (rexp): Some rules updated to be analogous to exp. + (output_redir): Can contain only common_exp, not exp in general. + +Mon Sep 16 22:51:51 2002 Arnold D. Robbins + + * io.c (two_way_open): Move label use_pipes outsidef of ifdef, + just in case. + +Thu Sep 12 15:11:28 2002 Arnold D. Robbins + + * awkgram.y (getfname): Return NULL if not found, remove + fatal error. Could be an extension function. + (dump_funcs): Walk symbol table counting functions before + mallocing table, since there could be extension functions, + func_count could be too small. + * profile.c (pp_builtin): Handle NULL return from getfname(). + Print it as "extension_function()" if so. + +Tue Sep 10 17:33:48 2002 Arnold D. Robbins + + Minor code simplification. + + * awk.h (in_array): Change return type to NODE*. + (assoc_exists): Remove declaration. + * array.c (in_array): Change return type to NODE *. + Return value is pointer to element value or NULL. + (assoc_exists): Removed function. + * eval.c (r_tree_eval): Case Node_in_array, change value + to test return of in_array() against NULL. + * io.c (pty_vs_pipes): Change test to make a tmp_string() + of the index and call in_array(). Add free_temp() of + subscript and free() of full_index (oops). + +2002-09-10 Isamu Hasegawa + + * posix/regcomp.c: Wrap #include wchar.h and wctype.h in #if. + (build_range_exp): Add castings to strlen invocations. + (build_collating_symbol): Restore the type of characters from "char" + to "unsigned char", and supplement castings. + (build_collating_symbol): Likewise. + (build_equiv_class): Likewise. + (build_charclass): Likewise. + (seek_collating_symbol_entry): Likewise. + (parse_bracket_exp): Likewise. + (build_word_op): Supplement a casting. + * posix/regex_internal.c: Wrap #include wchar.h and wctype.h in #if. + (re_string_allocate): Fix castings. + (re_string_construct): Likewise. + (re_string_construct_common): Likewise. + (re_string_realloc_buffers): Likewise. + (build_wcs_buffer): Likewise. + (build_wcs_upper_buffer): Likewise. + (re_string_skip_chars): Likewise. + (re_string_reconstruct): Likewise. + * posix/regex_internal.h: Restore the type of characters in + re_string_t and bracket_elem_t from "char" to "unsigned char". + (re_string_elem_size_at): Fix castings. + * posix/regexec.c: Wrap #include wchar.h and wctype.h in #if. + (transit_state_bkref_loop): Restore the type of characters from + "char" to "unsigned char", and append a cast to "char*" pointer in + array subscript. + (check_node_accept_bytes): Likewise. + (find_collation_sequence_value): Likewise. + +Thu Sep 5 13:15:09 2002 Arnold D. Robbins + + * re.c (remaybelong): New routine. + (reisstring): Simplified the code a bit. + * awk.h (remaybelong): Declaration added. + * io.c (get_a_record): Change fourth grungy special case to + use remaybelong() instead of strchr() on last character. + +Wed Sep 4 13:20:26 2002 Arnold D. Robbins + + * io.c (do_input): Recode guts of main loop to be easier + to trace with a debugger. + (get_a_record): Fourth grungy special case for RE-based + record splitting added. See explanatory comments there + and test/rebuf.awk. + +2002-09-03 Isamu Hasegawa + + * posix/regcomp.c (regcomp): Append "__restrict" modifier to avoid + warnings of some compilers. + (build_collating_symbol): Change the type of characters from + "unsigned char" to "char", and append a cast to "char*" pointer in + array subscript. + (build_collating_symbol): Likewise. + (build_equiv_class): Likewise. + (build_charclass): Likewise. + (re_compile_pattern): Remove incorrect cast. + (re_compile_fastmap_iter): Change the type of characters from + "unsigned char" to "char", and append a cast to "char*" pointer + in array subscript. + (parse_bracket_exp): Likewise. + * posix/regex_internal.c (re_string_construct_common): Likewise. + (re_string_allocate): Likewise. + (re_string_construct): Likewise. + (re_string_realloc_buffers): Likewise. + (build_wcs_buffer): Likewise. + (re_string_reconstruct): Likewise. + * posix/regex_internal.h: Change the type of characters in + re_string_t and bracket_elem_t from "unsigned char" to "char". + * posix/regexec.c (regexec): Append "__restrict" modifier to avoid + warnings of some compilers. + (transit_state_bkref_loop): Change the type of characters from + "unsigned char" to "char", and append a cast to "char*" pointer in + array subscript. + (check_node_accept_bytes): Likewise. + (find_collation_sequence_value): Likewise. + +Wed Aug 21 15:40:36 2002 Corinna Vinschen + + * configure.in: Define --without-libintl-prefix and + --without-libiconv-prefix for Cygwin by default. + * Makefile.am: Call fixvers from $(srcdir). + * awk.h: Don't define O_BINARY on Cygwin. + +Wed Aug 21 15:31:57 2002 Andreas Buening + + * configure.in (AC_OBJEXT, AC_EXEEXT): Added. Removed OS/2 goo. + * Makefile.am (check-local): Add $(EXEEXT) suffixes, remove OS/2 goo. + * regcomp.c, regex_internal.c, regexec.c: Conditionalize include of + and on RE_ENABLE_I18N. + +Wed Aug 21 14:43:57 2002 Arnold D. Robbins + + * gettext.h (ENABLE_NLS): Add include of locale.h so that things + compile even without optimization. Sheesh. + * io.c (two_way_open, pty_vs_pipes): Conditionalize pty code on + HAVE_TERMIOS_H. + +Thu Aug 8 22:16:10 2002 Arnold D. Robbins + + * main.c (main): Force LC_NUMERIC locale to "C", esp. for + M$ systems. Ugh. + +Wed Aug 7 13:42:01 2002 Arnold D. Robbins + + * io.c (get_a_record): Improve test for newlines at beginning of + record but with nothing following it. See test/nulrsend. + +Mon Aug 5 10:12:39 2002 Arnold D. Robbins + + Add option to use ptys instead of pipes for |&. + Basic plumbing originally from Paolo Bonzini . + + * awk.h (RED_PTY): New flag. + (assoc_exists): Add declaration. + * array.c (in_array): Use FALSE not zero for return value. + (assoc_exists): New routine to find and return value for an index + in an array. + * configure.in: Test for termios.h and stropts.h, and grantpt function. + * io.c: Include termios.h and stropts.h if available. + (redflags2str): Add RED_PTY to table. + (redirect): Add RED_PTY to flags turned off when searching. + (close_redir): Close write channel for two-way pipes + that use ptys by sending an EOF. + (two_way_open): If pty_vs_pipe(), use pty's to open two-way pipes as + they are line-buffered by default --> alleviates deadlock problems. + If fails, fall back to using pipes. + (pty_vs_pipe): New function. + * main.c (arg_assign): Clean up English in some of the error messages. + +Sun Aug 4 00:37:38 2002 Stepan Kasal + + * re.c (make_regexp): Don't pass the error message returned by + re_compile_pattern() to gettext(); it's already gettextized. + (make_regexp): Minor reformat of code. + +Wed Jul 31 23:50:31 2002 Arnold D. Robbins + + Removed dfa code from gawk since not really needed with new regex. + + * Makefile.am: Removed dfa.h and dfa.c. + * awk.h (struct Regexp): Removed `dfareg' and `dfa' members. + (make_regexp): Last parameter in function went away, changed decl. + (avoid_dfa): Removed declaration. + * awkgram.y: Fixed call to make_regexp(). + * eval.c (match_op): Simplified: removed call to avoid_dfa() and + `kludge_need_start' variable. Instead, pass FALSE as last parameter + of research(). + * field.c (set_FS): Fixed call to make_regexp(). + * io.c (get_a_record, set_RS): Fixed calls to make_regexp(). + * re.c (make_regexp): Removed last paramter (`dfa') from function. + Simplified the code. + (research): Simplified the code, removed calls to dfa stuff. + (dfaerror): Removed function. + (re_update): Fixed call to make_regexp(). + (avoid_dfa): Removed function. + +Thu Jul 25 21:55:45 2002 Arnold D. Robbins + + * regcomp.c, regex_internal.c, regex_internal.h, regexec.c: Bug + fixes from Isamu Hasegawa and Stepan Kasal + applied. + +Sat Jul 6 23:28:37 2002 Arnold D. Robbins + + * awkgram.y (yyerror): Change text of unexpected newline message to + include end of string. + +Mon Jun 17 17:58:55 2002 Arnold D. Robbins + + * field.c (do_split): Per Michal Jaegermann, move free_temp(fs) + above label `out'. + +Tue Jun 11 23:26:09 2002 Paul Eggert + + Update to autoconf 2.53 and automake 1.6.1. + + * acconfig.h: Removed. + * m4/isc-posix.m4: Removed. + * m4/jm-mktime.m4: Removed. + * m4/largefile.m4: Removed. + * m4/ssize_t.m4: Removed. + * ansi2knr.c: Updated. + * depcomp: Updated. + * install-sh: Updated. + * missing: Updated. + * mkinstalldirs: Updated. + * ylwrap: Updated. + + * configure.in: Improved quoting. + * acinclude.m4: Use `m4_sinclude', not antiquated `sinclude'. + +Tue Jun 11 23:08:40 2002 Arnold D. Robbins + + * configure.in: Add `getgrent' to list of functions checked + so that awklib/grcat is compiled correctly. + +Tue Jun 11 22:18:42 2002 Stepan Kasal + + Improve argument parsing and -v assignment. + + * awk.h (struct src): Add additional enum values. + (arg_assign): Return type and arg list changes. + * io.c (nextfile): Add extra arg in call to `arg_assign'. + * main.c (pre_assign): Nuked. + (allocfiles): New variable. + (srcfiles_add, preassigns_add): New macros. + (main): Logic cleaned up. + (add_src): New function. + + Use `size_t' for optimal_bufsize function. + + * awkgram.y (yylex): `len' is now size_t. + * pc/gawkmisc.pc (optimal_bufsize): Change return type to size_t. + * posix/gawkmisc.c (optimal_bufsize): Change return type to size_t. + * unsupported/atari/gawkmisc.atr (optimal_bufsize): Change return type + to size_t. + * unsupported/tandem/tmisc.c (optimal_bufsize): Change return type to size_t. + * vms/gawkmisc.vms (optimal_bufsize): Change return type to size_t. + * README_d/README.hpux: New file. + +Fri May 24 12:23:01 2002 Arnold D. Robbins + + * profile.c (init_profiling): Remove default initialization + of `prof_fp' to stderr. Per Stepan Kasal . + +Wed May 15 15:39:17 2002 Arnold D. Robbins + + Work through builtin operations to make sure that + anything that might have side effects gets dealt with. + + * array.c (do_delete): Evaluate subscript first before + checking if something is or isn't an array. + * builtin.c (sub_common): Evaluate replacement text, and + free it if no match of regex in source text. + +Wed May 15 15:30:34 2002 Arnold D. Robbins + + Switch to new version of regex from IBM Japan. + + * regcomp.c: New file. + * regex.c: Replaced with new version. + * regex.h: Replaced with new version. + * regex_internal.c: New file. + * regex_internal.h: New file. + * regexec.c: New file. + * Makefile.am (EXTRA_SOURCES): New files added. + +Tue May 14 17:04:05 2002 Arnold D. Robbins + + * awk.h (): Move check and include into gettext.h. + * gettext.h (): Add check and include per patch from + Bruno Haible. + + * field.c (do_split): When checking for split of null string, + evaluate seperator if it's not FS, since could have side effects. + At end, free_temp(fs), not free_temp(sep). + Both of these thanks to Stepan Kasal . + +Mon May 13 00:41:31 2002 Arnold D. Robbins + + * custom.h (ultrix): Add define GETGROUPS_NOT_STANDARD. + * main.c (init_groupset): For GETGROUPS_NOT_STANDARD, use old way + to set `ngroups'. + +2002-05-10 Andreas Schwab + + * dfa.c (parse_bracket_exp_mb): Fix warning. + +Thu May 9 22:28:32 2002 Arnold D. Robbins + + * builtin.c (sub_common): Fix logic for match of null strings to + get correct semantics. See test/gsubtst2.*. + * field.c (do_split): Minor code cleanup; the third arg to split() + is set to be FS by the grammar, so don't need to check it for NULL. + Thanks to Stepan Kasal . + * awk.h (locale.h): Move include before that of "gettext.h" for systems + that define functions that gettext.h would use when NLS is disabled. + Per bug report from Ayamura Kikuchi . + +Tue May 7 17:31:01 2002 Arnold D. Robbins + + Miscellanious patches courtesy of Stepan Kasal . + + * field.c, main.c: Tidy up some comments. + * field.c (set_FIELDWIDTHS): Init fw_alloc to 4 so it isn't + immediately realloced. + * main.c (load_procinfo): Check value of FS/FIELDWIDTHS for + value of PROCINFO["FS"]. + * awk.h (set_FS_if_not_FIELDWIDTHS): Removed decl. + * field.c (set_FS_if_not_FIELDWIDTHS): Removed function. + * eval.c (set_IGNORECASE): Use inline code checking `using_fieldwidths()'. + * io.c (set_IGNORECASE): Ditto. + +Sun May 5 14:28:34 2002 Arnold D. Robbins + + Fix a memory leak in array for loops if the body contains a + `next' or `nextfile' statement. The changes maintain a stack + of active for loops that is pushed and popped for each loop, + and popped entirely for `next', `nextfile', etc. + + * eval.c (forloops_active, pop_forloop, pop_all_forloops, push_forloop): + new functions. + (interpret): Case Node_K_arrayfor, call push and pop functions. + Case Node_rule_list: Pop loops and pop fcalls after longjmp. + Cases Node_K_next, Node_K_nextfile, Node_K_break and + Node_K_continue, removed check before longjmp. + Case Node_K_exit: Add loop check. + (loop_stack, nloops, nloops_active): New variables that implement + the stack. + +Wed May 1 16:41:32 2002 Arnold D. Robbins + + * Release 3.1.1: Release tar file made. + +Wed May 1 16:07:49 2002 Arnold D. Robbins + + * getopt.c: Installed latest version from glibc. + +Sun Apr 28 17:19:07 2002 Arnold D. Robbins + + * fixvers: Changed patterns to allow test versions of the + form `gawk-3.1.1a'. + * patchlev.h: Patchlevel is now a string constant. + * main.c (version): Print patchlevel using %s, not %d. + * Makefile.am: Rework DEFPATH stuff and datadir stuff yet again. + + * config.sub: Updated with current version from ftp.gnu.org. + * config.guess: Ditto. + + Upgrade to gettext-0.11.2: + + * ABOUT-NLS: Replaced with version from gettext 0.11.2. + * config.rpath: Replaced with version from gettext 0.11.2. + * intl/*: Replaced with version from gettext 0.11.2. + * po/Makefile.in.in: Replaced with version from gettext 0.11.2. + * po/Makevars.template: Replaced with version from gettext 0.11.2. + * po/Rules-quot: Replaced with version from gettext 0.11.2. + * po/boldquot.sed: Replaced with version from gettext 0.11.2. + * po/en@boldquot.header: Replaced with version from gettext 0.11.2. + * po/en@quot.header: Replaced with version from gettext 0.11.2. + * po/insert-header.sin: Replaced with version from gettext 0.11.2. + * po/quot.sed: Replaced with version from gettext 0.11.2. + * po/remove-potcdate.sin: Replaced with version from gettext 0.11.2. + * m4/codeset.m4: Replaced with version from gettext 0.11.2. + * m4/gettext.m4: Replaced with version from gettext 0.11.2. + * m4/glibc21.m4: Replaced with version from gettext 0.11.2. + * m4/iconv.m4: Replaced with version from gettext 0.11.2. + * m4/isc-posix.m4: Replaced with version from gettext 0.11.2. + * m4/lcmessage.m4: Replaced with version from gettext 0.11.2. + * m4/lib-ld.m4: Replaced with version from gettext 0.11.2. + * m4/lib-link.m4: Replaced with version from gettext 0.11.2. + * m4/lib-prefix.m4: Replaced with version from gettext 0.11.2. + * m4/progtest.m4: Replaced with version from gettext 0.11.2. + +Wed Apr 17 15:09:45 2002 Arnold D. Robbins + + * regex.c (PREFIX): Change test for token concatenation ability + to `#ifdef HAVE_STRINGIZE'. If a cpp has one, it ought to have + the other. + +Tue Apr 16 12:26:06 2002 Arnold D. Robbins + + * profile.c (tree_eval): Make unary minus case smarter, + use is_scalar test and if false parenthesize expression. + Add Node_TEXTDOMAIN case. + (pp_lhs, is_scalar, prec_level): Add Node_TEXTDOMAIN cases. + +Thu Apr 11 21:28:33 2002 Arnold D. Robbins + + * array.c (do_adump): Spelling fix in output message. + * builtin.c: Ditto, in multiple routines. + (do_toupper, do_tolower): Add cast to size_t in assigment to mbclen + for some compilers. + * re.c (research): Fix way returning is done to silence some + compiler diagnostics. + +Wed Apr 10 19:30:51 2002 Arnold D. Robbins + + * Makefile.am (datadir): Set directly to have `/awk'. + (DEFPATH): Go back to using $(datadir) for path. + +Tue Apr 9 17:34:09 2002 Arnold D. Robbins + + Upgraded to gettext 0.11.1. + + * Makefile.am (LDADD): Use @LIBINTL@ instead of @INTLLIBS@. + * ABOUT-NLS: Version from 0.11.1. + * config.rpath: Version from 0.11.1. + * aclocal.m4: Regenerated based on new files. + * intl/*: Replaced with version from 0.11.1. + * m4/ChangeLog: New file. + * m4/codeset.m4: New file. + * m4/gettext.m4: Version from 0.11.1. + * po/ChangeLog: New file. + * po/Makefile.in.in: Version from 0.11.1. + * po/remove-potcdate.sin: New file. + +Mon Apr 8 22:22:58 2002 Arnold D. Robbins + + * Makefile.am (libexecdir): Set directly to have `/awk'. + (DEFPATH): Use $(pkgdatadir) for path. + (install-exec-hook): Add version link for pgawk. + (uninstall-links): Remove pgawk version link. + +Wed Mar 20 13:44:21 2002 Isamu Hasegawa + + * regex.c (__alignof__): Definition for non-GCC compilers. + +Sun Mar 17 17:41:55 2002 Arnold D. Robbins + + * io.c (do_pathopen): Malloc buffers to hold constructed + filenames: No Arbitrary Limits! Thanks to keoki@techie.com + for the bug report. + +Sun Mar 10 16:59:06 2002 Scott Deifik + + * awk.h (LOCALEDIR): Provide a definition in case not using + i18n stuff. + +Wed Mar 6 18:14:44 2002 Arnold D. Robbins + + * main.c (usage): Add some explanatory text and examples at end. + +Sun Mar 3 16:42:50 2002 Arnold D. Robbins + + * getopt.h, getopt.c, getopt1.c: Update to current version + from glibc CVS. + +Fri Feb 22 15:53:38 2002 Isamu Hasegawa + + * dfa.c (fetch_wc): Fix type from wchar_t to wint_t. + (parse_bracket_exp_mb): Likewise. + * regex.c (extract_number): Retrieve the sign information from + byte-code in case of AIX. + +Thu Feb 21 16:44:24 2002 Arnold D. Robbins + + * re.c (resetup): Moved setting re_max_failures into regex.c. + * regex.c (re_max_failures): Set to really big if REGEX_MALLOC + defined. Do this in both places that define re_max_failures. + +Thu Feb 21 19:02:22 2002 Isamu Hasegawa + + * builtin.c (sub_common): Avoid index_multibyte_buffer invocation + in single byte character environments. + +Thu Feb 21 10:08:56 2002 Isamu Hasegawa + + * dfa.c (parse_bracket_exp_mb): For ':', use wctype_t in MALLOC, + not wchar_t. + +Thu Feb 21 09:52:16 2002 Arnold D. Robbins + + Upgraded to automake 1.5 and gettext-0.11. + Also bug fix to multibyte code. + + * ABOUT-NLS: Upgraded. + * config.guess, config.sub, config.rpath, gettext.h, ylwrap: New files. + * Makefile.am: Added above to appropriate places. + * awk.h: Replace libintl.h and macros with include of gettext.h. + (emalloc, erealloc): Add num bytes to error message, put string inside _(). + (index_multibyte_buffer): Removed decl. + * awklib/Makefile.am: Use $(EXEEXT) for grcat and pwcat targets. + * builtin.c (index_multibyte_buffer): Made static to this file. + (sub_common): Add checks that replacement string is length > 0 so + that we don't try to malloc(0): this fails on some systems. + * configure.in (AM_GNU_GETTEXT): Update macro for gettext 0.11. + (ALL_LINGUAS): Removed. + * m4/codeset.m4: New file. + * m4/gettext.m4: Updated. + * m4/glibc21.m4: New file. + * m4/iconv.m4: New file. + * m4/isc-posix.m4: New file. + * m4/lcmessage.m4: Updated. + * m4/lib-ld.m4: New file. + * m4/lib-link.m4: New file. + * m4/lib-prefix.m4: New file. + * m4/progtest.m4: Updated. + * intl/*: Replaced with version from gettext 0.11. + * po/*: Revised for gettext 0.11. + +Mon Feb 18 14:42:39 2002 Arnold D. Robbins + + * builtin.c (nondec2awknum): Change assert to runtime check + in case user passed in bad data. + +2002-02-17 Paul Eggert + + * re.c (resetup): Try to avoid silly limitation of regex.c by + setting re_max_failures to the largest reasonable value. + +Sun Feb 17 14:57:43 2002 Arnold D. Robbins + + * builtin.c (research): If re_search() returns -2, the + match failed since regex couldn't allocate enough memory + for what it needed. Fail with a fatal message instead. + This is a workaround, not a fix, but I don't mess with + regex.[ch]. + +Fri Feb 8 16:01:11 2002 Arnold D. Robbins + + * awkgram.y (LEX_FOR): Fix case of array loop with body of single + delete statement to actually check the right things to make the + optimization. + * profile.c (tree_eval): Add case for Node_K_delete_loop. + (prec_level): Ditto. + +Mon Feb 4 10:38:00 2002 Bruno Haible + + * awk.h (dcngettext): New macro. + (do_dcngettext): New declaration. + * awkgram.y (tokentab): Add dcngettext. + (snode): Add a warning for incorrect use of dcngettext. + (dumpintlstr): fflush at the end, not in the middle. + (dumpintlstr2): New function. + * builtin.c (localecategory_from_argument): New function, extracted + from do_dcgettext. + (do_dcgettext): Call it. + (do_dcngettext): New function. + +Sun Feb 3 17:56:20 2002 Bruno Haible + + * builtin.c (do_bindtextdomain): Don't free the same variable twice. + * main.c (main): Call setlocale for LC_MESSAGE, to make dcgettext + function work on glibc systems. + +Wed Jan 23 15:03:36 2002 Andreas Buening + + * configure.in (PATH_SEPARATOR): Code added for OS/2. + Makefile.am (PATH_SEPARATOR): Added. + (DEFPATH): Make use of PATH_SEPARATOR. + +Wed Jan 23 14:46:04 2002 Arnold D. Robbins + + * awkgram.y (yylex): Add test for lasttok != '$' when looking + at _"...". See comments in code. + +Wed Aug 15 07:43:10 2001 Isamu Hasegawa + + * regex.c : Implements the codes for exactn_bin to work correctly + in multibyte environments, in case of invalid multibyte sequence. + +Wed Aug 15 07:36:56 2001 Isamu Hasegawa + + * regex.c : Implements the codes for charset/charset_not to + work in multibyte environments. + +Wed Aug 15 05:04:34 2001 Isamu Hasegawa + + * regex.c : Add some comments. + +Wed Aug 15 05:04:15 2001 Isamu Hasegawa + + * regex.c (count_mbs_length): New function, check the mutibyte + strings and count how many wchar_t the substring occupy. + (CHAR_T): New macro, character type depending on + environments(singlebyte/multibyte). + (UCHAR_T): New macro, unsigned character type. + (COMPILED_BUFFER_VAR): New macro, the buffer containing + the compiled buffer. + Adapt singlebyte/multibyte environments with CHAR_T, UCHAR_T, + and COMPILED_BUFFER_VAR. + +Mon Jun 25 09:00:41 2001 Isamu Hasegawa + + * regex.c : Reorganize code to build code twice. byte_* are + for single byte, wcs_* are for multibyte character sets. + Chose functions according to current locale dynamically. + * regex.c (convert_mbs_to_wcs): New function, convert multibyte + strings to wide character strings for multibyte environments. + +Fri Jun 22 05:43:50 2001 Isamu Hasegawa + + * regex.c (MBS_SUPPORT): New macro, defined if the environment + can handle multibyte characters. + (OFFSET_ADDRESS_SIZE): Offset address size in the + compiled buffer. + Rewrite offset addresses with OFFSET_ADDRESS_SIZE. + +Thu Apr 26 08:03:17 2001 Isamu Hasegawa + + * builtin.c (index_multibyte_buffer): Inspect the buffer and write + the index. + (sub_common): In multibyte environment, skip multibyte characters + when we check special characters. + * awk.h (index_multibyte_buffer): Add prototype. + * eval.c (cmp_nodes): In multibyte environment, compare per character. + * field.c (re_parse_field): In multibyte environment, avoid to + call research() on invalid boundary. + (sc_parse_field): In multibyte environment, avoid to compare on + invalid boundary. + (null_parse_field): In multibyte environment, split per + character, not per byte. + * io.c (get_a_record): In multibyte environment, avoid to compare + on invalid boundary. + +Wed Apr 25 08:29:47 2001 Isamu Hasegawa + + * awk.h (strncasecmpmbs): Add prototype. + * builtin.c (strncasecmpmbs): New function like strncasecmp but for + multibyte strings. + (do_index): In multibyte environment, compare per character. + * builtin.c (do_tolower): In multibyte environment, user towlower + instead of TOLOWER. + (do_toupper): In multibyte environment, user towupper instead + of TOUPPER. + +Tue Apr 24 10:38:06 2001 Isamu Hasegawa + + In multibyte environments, handle multibyte characters as single + characters in bracket expressions. + + * dfa.h (mb_char_classes): New structure. + (mbcsets): New variable. + (nmbcsets): New variable. + (mbcsets_alloc): New variable. + * dfa.c (prtok): Handle MBCSET. + (fetch_wc): New function to fetch a wide character. + (parse_bracket_exp_mb): New function to handle multibyte character + in lex(). + (lex): Invoke parse_bracket_exp_mb() for multibyte bracket expression. + (atom): Handle MBCSET. + (epsclosure): Likewise. + (dfaanalyze): Likewise. + (dfastate): Likewise. + (match_mb_charset): New function to judge whether a bracket match + with a multibyte character. + (check_matching_with_multibyte_ops): Handle MBCSET. + (dfainit): Initialize new variables. + (dfafree): Free new variables. + +Mon Apr 23 01:40:09 2001 Isamu Hasegawa + + Implement the mechanism to match with multibyte characters, + and use it for `period' in multibyte environments. + + * dfa.h (mbps): New variable. + * dfa.c (prtok): Handle ANYCHAR. + (lex): Use ANYCHAR for `period' in multibyte environments. + (atom): Handle ANYCHAR. + (state_index): Initialize mbps in multibyte environments. + (epsclosure): Handle ANYCHAR. + (dfaanalyze): Handle ANYCHAR. + (dfastate): Handle ANYCHAR. + (realloc_trans_if_necessary): New function. + (transit_state_singlebyte): New function. + (match_anychar): New function. + (check_matching_with_multibyte_ops): New function. + (transit_state_consume_1char): New function. + (transit_state): New function. + (dfaexec): Invoke transit_state if expression can match with + a multibyte character in multibyte environments. + (dfamust): Handle ANYCHAR. + +Fri Apr 20 11:31:24 2001 Isamu Hasegawa + + Avoid incorrect state transition in multibyte environments. + + * dfa.h (nmultibyte_prop): New variable. + (multibyte_prop): New variable. + * dfa.c (addtok): Set inputwcs. + (dfastate): Avoid incorrect state transition in multibyte + environments. + (dfaexec): Likewise. + (dfainit): Init multibyte_prop. + (dfafree): Free multibyte_prop. + (inputwcs): New variable. + (mblen_buf): New variable contains the amount of remain byte + of corresponding multibyte character in the input string. + +Fri Apr 20 06:28:59 2001 Isamu Hasegawa + + Handle a multibyte character followed by '*', '+', and '{n,m}' + correctly. + + * dfa.c (update_mb_len_index): New function. + Support for multibyte string. + (FETCH): Call update_mb_len_index. + (lex): Check cur_mb_index not to misunderstand multibyte characters. + (atom): Make a tree from a multibyte character. + (dfaparse): Initialize new variables. + (mbs): New variable. + (cur_mb_len): New variable. + (cur_mb_index): New variable. + +Thu Apr 19 09:32:47 2001 Isamu Hasegawa + + * awkgram.y (cur_mbstate): New varialble containing means current + shift state. + (cur_char_ring): New varialbe reffering the buffer which contains + last some character from the buffer. + (cur_ring_idx): New variable containing the current index on + cur_char_ring. + (nextc_is_1stbyte): New macro, means that last nextc() return a + singlebyte character or 1st byte of a multibyte character. + (nextc): Check the buffer and update cur_ring_char in multibyte + environments. + (pushback): Adjust cur_ring_idx in multibyte environments. + (yylex): Add check whether nextc() returned 1st-byte in multibyte + environments. + * re.c (make_regexp): In multibyte environment, skip multibyte + characters when we check special characters. + +Wed Apr 18 07:58:20 2001 Isamu Hasegawa + + * awk.h (MBS_SUPPORT): New flag, means supporting multibyte strings. + * configure.in : Add check for wchar.h, wctype.h, mbrtowc, and mbrlen. + +Wed Jan 16 16:32:40 2002 Arnold D. Robbins + + * builtin.c (do_strtonum): Simplified. Check first if the + value matches a non-decimal number, and if so convert it. + Otherwise do a regular force_number. + +Mon Jan 7 22:12:15 2002 Arnold D. Robbins + + * awkgram.y (statement): Moved delete, print, and expressions into + new non-terminal `simple_stmt'. Allow opt_simple_stmt in the + first and third part of a for loop, per latest POSIX, which documents + an otherwise undocumented historical oddity in Unix awk. This has + the pleasant side effect of making line numbers more accurate for + messages involving delete statements. + (opt_simple_stmt, simple_stmt): New non-terminals. + + Based on bug report from drj@pobox.com. + +Mon Dec 24 14:04:02 2001 Arnold D. Robbins + + * configure.in: Changes for VMS with new strftime: + (AC_HEADER_TIME): Added. + (AC_CHECK_HEADERS): Check for sys/time.h. + (TIME_T_IN_SYS_TYPES_H): Add header check. + * acconfig.h (TIME_T_IN_SYS_TYPES_H): Added. + +Wed Dec 19 16:01:58 2001 Peter J. Farley III + + * configure.in: Add MS-DOS to getpgrp special case. + * dfa.c, getopt.c, regex.c: Fix code to work with --disable-nls. + +Wed Dec 19 15:59:25 2001 Eli Zaretskii + + * profile.c (init_profiling_signals) [__DJGPP__]: Use SIGINT + instead of SIGHUP and SIGQUIT instead of SIGUSR1. + +Tue Dec 18 20:56:07 2001 Andreas Buening + + More OS/2 stuff. + + * awk.h (O_BINARY): Don't redefine for EMX. + * io.c (gawk_popen): Add __EMX__ in case compiling DOS executable. + * configure.in: Add OS/2 to case for manual GETPGRP_VOID. + +Tue Dec 4 17:54:30 2001 Arnold D. Robbins + + New configure time option, --with-whiny-user-strftime. + + * configure.in (AC_ARG_WITH): Add appropriate code for autoconf. + * accondig.h (USE_INCLUDED_STRFTIME): Add #undef for it. + * custom.h (USE_INCLUDED_STRFTIME): Set things up write. + +Tue Dec 4 16:44:07 2001 Andreas Buening + + Mongo patch for updated OS/2 support. + + * awk.h (TOUPPER, TOLOWER): Define only if not already defined. + * awkgram.y (extproc feature): Add ifdef for __EMX__. + * gawkmisc.c (__EMX__): Include pc/gawkmisc.c directly. + * io.c (__EMX__): Added for a number of places in addition to OS2 def. + (two_way_open): Added OS/2 specific code added that uses spawn. + (gawk_popen): Ditto. + +Mon Dec 3 14:07:56 2001 Arnold D. Robbins + + Fix use of getgroups to use dynamic memory, solves + problem of systems where NGROUPS_MAX lies. + + * awk.h (groupset, ngroups): New extern variables. + * configure.in (AC_CHECK_FUNCS): Add getgroups to list. + * io.c (user_open): Use global ngroups and groupset variables, + don't call getgroups here. + * main.c (init_groupset): New function to init global + vars using malloc. Declare it at top. + (main): Call init_groupset(). + (load_procinfo): Use global ngroups and groupset variables. + +Sun Nov 18 11:56:01 2001 Arnold D. Robbins + + * random.c (srandomdev): ifdef-out. Lots of compile time + problems on multiple platforms, and gawk doesn't even + use the routine. The heck with fine-grained solutions. + +Wed Nov 14 16:12:40 2001 Pat Rankin + + * builtin.c (bchunk_one): Use `ofre < 1' instead of `ofre <= 0' + to avoid compiler complaint about suspicious comparison for + unsigned variable. (`ofre == 0' ought to suffice...) + +Tue Nov 13 17:27:52 2001 Arnold D. Robbins + + * awkgram.y (yyerror): Fix the code to behave like it + used to. Keep "no arbitrary limits" by mallocing the + buffer and freeing it. + +Wed Nov 7 16:46:20 2001 Arnold D. Robbins + + * awkgram.y (yyerror): Remove dependency upon buf[] to + hold prepended space and `^' pointer. Avoids core dumps + for long source lines. + +Sat Nov 3 22:27:21 2001 Arnold D. Robbins + + * m4/strtod.m4: Add missing `#endif'. Oops. + +Mon Oct 29 14:53:57 2001 Arnold D. Robbins + + * awkgram.y: Add semicolons in calls to count_args(). + Apparently bisoon adds a semicolon to each body + automatically and byacc doesn't. + +Sun Oct 28 16:53:18 2001 Arnold D. Robbins + + * builtin.c (format_tree): Fix off-by-one error in "ran out + for this one" diagnostic. Also fix lint check for too many + arguments vs. count in format string. + +Wed Oct 10 11:01:47 2001 Arnold D. Robbins + + * fixvers: Check that files exist before doing `cmp', in + case they're in a source code system and aren't there. + Fix from Grant Erickson (gerickson@brocade.com). + +Thu Oct 4 18:20:36 2001 Arnold D. Robbins + + * eval.c (r_tree_eval): For comparison, dupnode() results of + evaluation so that we can hang on to them and avoid memory + corruption. Change calls to free_temp() to unref(). + +Tue Sep 25 15:19:53 2001 Arnold D. Robbins + + * io.c (iop_open): Only call os_close_on_exec() for + fd > fileno(stderr). + +2001-09-07 Paul Eggert + + * io.c (redirect): When deciding to use the fdopen bug hack, + use "__sun" rather than "solaris". No compilers predefine + "solaris", but both GCC and Sun C predefine "__sun". + +Thu Aug 30 15:17:12 2001 Arnold D. Robbins + + * main.c (copyleft): Use a printf %d for last year of update + to avoid translation strings changing when the file + is updated from now on. Suggestion from Ulrich Drepper. + +Thu Aug 23 14:01:14 2001 Arnold D. Robbins + + * awkgram.y (unary minus production): Add check that value + isn't a string. Based on bug report from drj@pobox.com. + * profile.c (tree_eval): For node_val, only test NUMBER + to see if value is numeric, not NUM|NUMBER. + +Thu Aug 16 12:21:28 2001 Arnold D. Robbins + + * configure.in (ALL_LINGUAS): Added `fr' and `tr'. + * po/fr.po, po/tr.fo: New files. + +2001-08-13 Paul Eggert + + This patch fixes a bug that causes gawk to rewind standard + input incorrectly. It also removes all instances of fseek, + from the gawk source proper, which should make gawk a bit + more portable. + + (The original patch removed off_t & lseek too, but I need + that for something else. ADR.) + + * posix/gawkmisc.c (optimal_bufsize): + Don't use lseek on the input, because that might change + its state. Instead, just check whether it is a regular file. + This obviates the need to invoke isatty. + (Also, fix a spelling error in the first line of the source.) + * pc/gawkmisc.pc, unsupported/atari/gawkmisc.atr: Likewise. + + * awk.h (S_ISREG): Move this macro here ... + * io.c (S_ISREG): from here. + + * protos.h (fseek): Remove prototype; no longer used. + +Fri Aug 3 13:38:54 2001 Arnold D. Robbins + + * array.c (assoc_lookup): Change assert test on type to real test + to protect against FS[1] = "x" kinds of things. It'd be better + to do this in the grammar, but this is easier and just as + effective. + + Undid BECAMEARRAY changes of 25 June 2001 in favor of correct code: + * eval.c (pop_fcall): Change test and comment for freeing n->vname. + (flags2str): Removed BECAMEARRAY entry. + * awk.h (BECAMEARRAY): Removed define. + * array.c (assoc_lookup): Removed setting of BECAMEARRAY flag. + +Mon Jul 23 17:33:13 2001 Arnold D. Robbins + + * io.c (get_a_record): Handle case where RS = "" and input file + is only newlines. See test/onlynl. Bug report by + Michel Jouvin . + +Wed Jul 4 18:34:19 2001 Arnold D. Robbins + + * eval.c (assign_val): Don't allow negative values for NF. + * field.c (set_NF): Robustify field-freeing code to make sure + values are always positive. + +Sun Jul 1 19:15:01 2001 Arnold D. Robbins + + * builtin.c (do_index): If second string is "", return 1. + +Mon Jun 25 19:34:24 2001 Arnold D. Robbins + + Further rationalization of treatment of dynamic regexes, + so that profiling code works correctly. + + * awk.h (NODETYPE): New type, Node_dynregex. + * awkgram.y (mk_rexp): Use Node_dynregex. + * eval.c (nodetypes): Add Node_dynregex. + (r_tree_eval): Add Node_dynregex to case for match_op(). + * profile.c (tree_eval): Add Node_dynregex to case for pp_match_op(). + (pp_match_op): Handle Node_dynregex, simplify cases for ~ and !~. + * re.c (re_update): Add assertion that type is Node_regex when flags + indicate CONST. + + New lint warning. + + * awkgram.y (yylex): Added lint warning that constant with leading + zero is treated as octal or hex. + + Generalized code for those who are Strong In The Ways of the Source. + + * awk.h: New boolean variable. + * main.c (main): Set it. + * eval.c (interpret): For arrays, check it. Remove variable 'first', + not needed anymore. + * profile.c (pp_string_fp): Enable printing of non-ASCII characters + verbatim if variable set. + + Fix memory corruption on SCO for array vars as params changed globally. + + * awk.h (BECAMEARRAY): New flag. + * array.c (assoc_lookup): Set the flag as appropriate. + * eval.c (flags2str): Add the flag. + (pop_fcall): Check the flag, don't free memory if set. + +Wed Jun 13 18:07:06 2001 Arnold D. Robbins + + * eval.c (fmt_index): Actually call erealloc() to grow fmt_list + if that's really necessary. Bug report from David Jones, + djones@zoonami.com. + +Sun Jun 10 14:24:48 2001 Arnold D. Robbins + + * profile.c (pp_match_op): Rationalized the code. + +Thu Jun 7 11:54:36 2001 Arnold D. Robbins + + * awk.h (O_BINARY): Don't define if already defined + (as is true for cygwin/gcc --- oops). + +Sun Jun 3 13:04:44 2001 Arnold D. Robbins + + * Release 3.1.0: Release tar file made. And there was + rejoicing. + +Wed Apr 25 11:44:07 2001 Arnold Robbins + + * Makefile.am (AM_MAKEFLAGS): Add definition per advice from + Nelson Beebe. + +Tue Apr 24 14:28:00 2001 Arnold Robbins + + * io.c (devopen): Patch from Jeurgen to robustify pulling + out hostname, port numbers, etc, to avoid any buffer overrun + problems. + +Mon Apr 23 10:26:38 2001 Arnold Robbins + + * awkgram.y: Fix grammar so that `print ... |& ".." |& getline' + dies with a parse-time error message. + +Sun Apr 22 16:46:48 2001 Arnold Robbins + + * io.c (socketopen): Fix from Juergen in recursive call. + +Thu Apr 19 18:39:20 2001 Pat Rankin + + * awk.h: Really fix logic around include of . + + * awk.h (callresult): New name for `result' macro. + * eval.c (r_get_lhs, case Node_builtin): Use it. + +Thu Apr 19 16:31:09 2001 Pat Rankin + + * io.c: Move code around to allow compilation with DEC C. + +Thu Apr 19 16:21:56 2001 Arnold D. Robbins + + * random.h: Move decl of random() here. + * random.c: Remove decl of random(). + +Mon Apr 9 11:41:58 2001 Arnold D. Robbins + + * dfa.c (dfainit): Initialize more members in the structure, + based on bug report in bug.gnu.utils by aaronl@vitelus.com + (Aaron Lehmann). + * awk.h: Fix logic around include of . + +Thu Apr 5 20:12:05 2001 Pat Rankin + + * dfa.c: For VMS, #include instead of . + * missing_d/mktime.c: Likewise. + + * random.c: Reorder include directives to get gawk config info + from random.h sooner. + [fcntl.h]: Guard #include with HAVE_FCNTL_H test. + [unistd.h]: Guard #include with HAVE_UNISTD_H test. + + * random.c (srandomdev): Skip /dev/urandom usage if O_RDONLY + is not defined. + +Tue Mar 20 11:07:11 2001 Arnold D. Robbins + + * awkgram.y (function_body): Add opt_nls to end of production. + +Tue Mar 20 09:30:32 2001 Pat Rankin + + * awk.h (BROKEN_STRNCASECMP): Add decl of strcasecmp. + * io.c (two_way_open): Add `return FALSE;' for fussy compilers. + +Sun Mar 18 15:10:56 2001 Arnold D. Robbins + + * io.c (gawk_pclose): Set the exit value for close correctly + if the pipe died with a signal. + +Wed Mar 7 11:28:52 2001 Arnold D. Robbins + + * io.c (get_a_record): Correctly handle the case of a leading + single newline at the front of the file when RS = "". + +2001-02-26 Paul Eggert + + * COPYING: Incorporate latest version from FSF, which fixes a Y2k bug. + + * builtin.c (do_mktime): Allow the user to specify the + tm_isdst member as an optional trailing integer, and to + specify "out-of-range" members. Check for overflow when + subtracting 1 from month or 1900 from year. Allow years just + past INT_MAX, as they work on some hosts when INT_MAX - 1900 + is representable as an int. + + * doc/gawk.1, doc/gawk.texi: Document the above changes. + Also, document that the origin-zero Gregorian calendar is used. + Fix confusing wording about "midnight" by replacing it with 00:00 + ("midnight" is also 24:00, the end of the day). + Mention the typical range for time stamps. + Do not assume that years are nonnegative and are less than 10,000. + Suggest TZ=UTC0 instead of TZ=GMT0, as that's how recent versions + of GNU date behave. + GMT is not always the time of day in Greenwich these days. + Fix typos: "Emporer/Era", "1980's", "1970's". + + * m4/largefile.m4: Synchronized with latest version. + +Tue Feb 27 12:10:11 2001 Arnold D. Robbins + + * profile.c (pp_in_array): Change test to tree->type == Node_expression_list. + +Wed Feb 7 14:46:50 2001 Arnold D. Robbins + + * awkgram.y (LEX_FOR): Allow newline after `;' in for loops. + Per bug report from Brian Kernighan, bwk@research.bell-labs.com. + +Tue Feb 6 18:35:27 2001 Martin C. Brown + + * io.c (socket_open): Conditionalize various options based on + ifdef. Needed for BeOS port. + +Tue Feb 6 18:17:13 2001 Michal Jaegermann + + * regex.c (re_match_2_internal): Case maybe_pop_jump, for + charset and not_charset: Change cast from (unsigned char) + to (unsigned). Catches last 8 chars with high bit set + if backtracking. See test/rebt8b1.awk, test/rebt8b2.awk. + +Tue Feb 6 11:20:21 2001 Arnold D. Robbins + + Have `for (iggy in foo)' save the elements and loop over them. + Make sorted for loops a dynamic test instead of a compile time test. + Still requires being Strong In The Ways Of The Source. + + * awk.h: (struct search): Removed. + (assoc_scan, assoc_next): Removed declarations. + * array.c (assoc_scan, assoc_next): Removed functions. + * eval.c (interpret): Remove Node_K_array_sorted_for. Change code + at Node_K_arrayfor. + (nodetypes): Remove Node_K_array_sorted_for. + * configure.in: Removed array sorting test. + * awkgram.y: Removed sorted_in keyword and associated code. + +Sun Feb 4 14:57:49 2001 Arnold D. Robbins + + * eval.c (interpret): Use tree->rnode->exec_count to hold count of + times if was true. + profile.c (interpret): Ditto. + * main.c (pre_assign): Gross hack. malloc fresh copy of assign so can + clear the '=', otherwise screws up profiling print out. + +Sun Jan 28 16:16:02 2001 Arnold D. Robbins + + Per request from Nelson Beebe, SIGHUP to pgawk dumps profile + and function call stack and exits, SIGUSR1 dumps and continues + running. + + * eval.c (dump_fcall_stack): New function, dumps awk function call + stack. + * awk.h (dump_fcall_stack): Add declaration. + (init_profiling_signals): Ditto. + * main.c (main): Call init_profiling_signals. + * profile.c (init_profiling_signals, dump_and_exit, just_dump): New + functions. + +Sun Jan 28 15:50:02 2001 Eli Zaretskii + + * io.c (gawk_popen): Restore the mode of stdin before running the + child process and switch it back if BINMODE is in effect after the + child returns. + (redirect): Restore the mode of stdin before running the child + process. + (close_redir): Switch mode of stdin back to binary if BINMODE is + in effect, after the child returns. + + * builtin.c (do_system): Restore the mode of stdin before running + the child process and switch it back if BINMODE is in effect after + the child returns. + + * awk.h (os_restore_mode): Add prototype. + +Thu Jan 18 14:03:06 2001 Arnold D. Robbins + + * custom.h, README_d/README.ultrix: Fixes for Ultrix + from Juergen Kahrs. + +Wed Jan 17 11:03:40 2001 Eli Zaretskii + + * io.c (redirect) [F_GETFL && O_APPEND]: Use binmode in the call + to fdopen. + +Mon Jan 15 16:29:52 2001 Arnold D. Robbins + + * profile.c (prec_level): Made Node_K_getline higher than < + but lower than others. Allows use of getline with redirection + inside an if. + +Wed Jan 10 15:35:06 2001 Arnold D. Robbins + + * eval.c (set_BINMODE): Rationalized string assignment. + +Sun Jan 7 15:26:16 2001 Arnold D. Robbins + + * getopt.h: Removed names in prototypes for getopt_long + and getopt_long_only, fixes problems on MINGW32. + +Thu Jan 4 10:13:46 2001 Arnold D. Robbins + + * configure.in: Add check for mcheck.h + * main.c: Include mcheck.h if have it. + (main): If TIDYMEM turned on in environment, also call mtrace(). + +Wed Jan 3 16:41:33 2001 Arnold D. Robbins + + Fixed minor memory leaks. + * re.c (re_update): When IGNORECASE changed, unref(t->re_text). + * eval.c (pop_fcall): Fix the logic to correctly free the vname + when copying array args back to their underlying source. + + Fixed massive memory leaks. + * node.c (dupnode): If PERM is set, do nothing. + (unref): Fix logic. Always turn off TEMP. Check just for MALLOC + when incrementing the stref. + * array.c (assoc_lookup): Turn off PERM also when saving subscript. + * builtin.c (sub_common): Turn off PERM also when making private copy + of string. + + Add a minor memory cleanup facility (undocumented): + * awk.h (do_tidy_mem, release_all_vars): Add declarations. + * main.c (do_tidy_mem): Add declaration. + (main): If $TIDYMEM exists, do_tidy_mem is true, and call mtrace(). + * awkgram.y (release_all_vars): New function. + +Sun Dec 31 10:47:37 2000 Arnold D. Robbins + + * awkgram.y (in_end_rule): Renamed `parsing_end_rule' to avoid + conflict with global var of same name. + +Sun Dec 24 10:36:54 2000 Eli Zaretskii + + * awkgram.y (snode): Reword the error message about the number of + arguments for a builtin, so as not to use the English `s' as a + plural suffix. + +Tue Dec 12 08:38:03 2000 Arnold D. Robbins + + * ext.c (do_ext): ifdef out use of `dummy'. Duh. + * regex.c (re_error_msgid): Revert to array of `char *' so that can + compile on K&R compilers. Fix all uses appropriately. + (re_error_msgid_idx): Removed. + +Fri Dec 8 11:47:26 2000 Arnold D. Robbins + + * ext.c (dummy): Make gcc specific via ifdef. + * builtin.c (do_dcgettext): Make conditional compilation smarter. + * msg.c (warning, error, r_fatal): Finish switching back to + multi-version function header. + +Wed Dec 6 13:28:58 2000 Arnold D. Robbins + + * random.h: Include to get ssize_t definition. + * awkgram.y (yyerror): Restore multi-version function header, + it seems that what ansi2knr produces doesn't quite do the + job on old compilers. + msg.c (msg): Ditto. + +Tue Dec 5 15:05:35 2000 Arnold D. Robbins + + * configure.in (AC_C_INLINE): Added macro call. + * Makefile.am (LN): Define it for install hooks. + +Sun Dec 3 17:28:53 2000 Arnold D. Robbins + + * awk.h (os_setbinmode): Declare new function. + (setmode): Remove definition: conflicts with MacOS X. + * main.c (main): Change call of setmode to os_setbindmode. + + * builtin.c (do_dcgettext): Improve ifdef for code, fixes MacOS X. + * custom.h (__APPLE__): Force definition of HAVE_MKTIME, won't + link otherwise. Harumph. + +Sun Nov 26 11:58:52 2000 Arnold D. Robbins + + * builtin.c (do_dcgettext, do_bindtextdomain): Add calls to + free_temp the various arguments. Sigh. + * io.c (yylex): Nuked bstart variable, put all uses of mend variable + into TANDEM ifdef. + * main.c (load_environ): Removed cp variable, value never used. + * random.c: Remvoed uses of `inline' keyword. + * Makefile.am (install-exec-hook, uninstall-local): New targets. + Adds creation of gawk-X.Y.Z and awk links, as in 3.0.x. + * configure.in (GAWK_AC_TYPE_SSIZE_T): Added. + m4/ssize_t.m4: New file. + +Wed Nov 22 14:47:18 2000 Arnold D. Robbins + + After consultation with Brian Kernighan and Michael Brennan, + nuked the abort keyword. + + * awk.h (Node_K_abort): Removed. + * eval.c (aborting): Removed decl. + (interpret): Removed Node_K_abort case. + * io.c (do_input): Removed checks for aborting. + * main.c (aborting): Removed. + (main): Removed checks for aborting. + * profile.c (pprint): Removed Node_K_abort case. + * awk.y (LEX_ABORT): All stuff removed. + +Wed Nov 22 10:45:57 2000 Arnold D. Robbins + + * ext.c (dummy): Move inside #ifdef DYNAMIC. Helps on + PCs and other platforms that don't do dynamic loading. + * awk.h (RED_TCP): New flag, means use shutdown. + io.c (redflags2str): Add RED_TCP. + (SHUT_RD, SHUT_WR, SHUT_RDWR): Add conditional defines. + (redirect): Add RED_TCP to tflag if appropriate. Add more + #ifdef HAVE_SOCKETS as needed. + (close_redir): If RED_TCP set, shutdown(2) on each end of the socket. + +Tue Nov 21 16:25:41 2000 Arnold D. Robbins + + * awk.y: for (iggy in foo) loops: Add test that index + in delete statement is a simple variable. + +Tue Nov 14 16:11:39 2000 Arnold D. Robbins + + * awk.h: Add appropriate conditional versions of the gettext + functions if we don't have or if ENABLE_NLS + is not defined or zero. + * configure.in: Add check for libintl.h header. + + From Scott Deifik for PCs. + * awk.h (lintwarn): Call set_loc unconditionally, makes + compilation work on PCs. + * builtin.c (do_dcgettext): Compile out cat_tab and code + if not ENABLE_NLS. + * ext.c: For MSC, no long long variable. + * random.c: Use clock() instead of gettimeofday(). + * builtin.c: Fixed prototypes for new random functions (ADR). + +Sun Nov 12 17:45:44 2000 Arnold D. Robbins + + * builtin.c (parse_next_arg): Fix call to >= num_args so + running out of args check is correct, instead of core dumping. + (format_tree): Save and restore `the_args' and `args_size' + if a nested call is in progress, see explanatory comment. + See also tests/addcomma. + * Makefile.am: Fix things so that gawk/pgawk built first, + even if `make check' called before make. Add some + commentary. + +Wed Nov 8 14:39:20 2000 Arnold D. Robbins + + * configure.in: Only add -rdynamic for Linux. + * dfa.h, dfa.c: Upgraded to versions in grep 2.4.2. + +Tue Nov 7 18:17:17 2000 Arnold D. Robbins + + * All: Switched to ANSI function headers and added + `ansi2knr' automake option. Really cool. + +Tue Nov 7 16:57:49 2000 Arnold D. Robbins + + * io.c (redirect): Check for O_APPEND in flags when doing + fdopen() of /dev/fd/N. Thanks to bug report from + "John H. DuBois III" . + +Tue Nov 7 14:09:14 2000 Arnold D. Robbins + + * awk.h (os_is_setuid): Declare function. + * main.c (main): Call it if do_lint and warn if true. + * awkgram.y (tokentab): + - Made sure all extensions are actually marked as such. Ouch. + - Changed "sort" to "asort". Potential to break too much old code. + * getopt.h, getopt.c, getopt1.c: Replaced with current versions + from glibc CVS archive. + +Mon Nov 6 18:14:33 2000 Arnold D. Robbins + + * random.c: Replaced with recent version from FreeBSD. + +Mon Nov 6 15:37:12 2000 Arnold D. Robbins + + Major simplification of automake machinery. + + * configure.in: + - INSTALL is forced only if not provided in environment + - lots of Makefile.in files removed since move to automake 1.4a + * Makefile.am, */Makefile.am: Moved directories that don't need + the automake machinery into EXTRA_DIST as appropriate and + removed the Makefile{,.am,.in} files as needed. + * eval_p.c, profile_p.c: New files to make it easier with automake + to compile pgawk. + +Tue Oct 24 12:20:18 2000 Arnold D. Robbins + + * awkgram.y (valinfo, var_comp, dump_vars): New functions to dump + the list of global variables. + * awk.h: Declare dump_vars. + * main.c (optab): New option "dump-variables". + (main): Code to handle it, set the output file and then call + dump_vars() at the end. + (usage): New option added to usage message. + +Sat Oct 21 22:59:59 2000 Arnold D. Robbins + + * awkgram.y (parms_shadow): For a function, check if any + parameters shadow global variables and print a warning. + (shadow_funcs): Go through all functions and call parms_shadow(). + (isnoeffect, isassignable): Add Node_LINT and NODE_BINMODE. + * main.c (main): If do_lint, call shadow_funcs(). + * awk.h: Add declaration of shadow_funcs(). + * configure.in: Added m4/Makefile and awklib/eg/network/Makefile + to list of generated makefiles. + +Tue Oct 17 10:47:35 2000 Arnold D. Robbins + + * array.c (assoc_lookup): Reverted change that did dupnode of + array indices. Creates significant problems if index is + numeric value and CONVFMT changes. Added fix to set + bucket->ahname->stfmt to -1 so that force_string never recalculates + the string value, and also turned off NUM and turned on STR. + See test/arynasty.awk. + +Mon Oct 16 12:21:26 2000 Arnold D. Robbins + + * All: Cleaned up various lint warnings for consistent phrasing. + * awk.y (in_end_rule): New variable for warning about unredirected + getline. It's ok in a BEGIN, but not in an END. + +Sun Oct 15 14:14:05 2000 Arnold D. Robbins + + * field.c (set_FS): Add lint warning for FS = "". + (do_split): Ditto for 3rd arg = "". + +Fri Oct 13 09:17:04 2000 Arnold D. Robbins + + * io.c (close_redir): Clear rp->fp on all closes. Remove + rp from list if either closing both ends or both ends + have been closed separately. Add exitwarn message for + co-process. + (flush_io): Add warning message if fflush of co-process + fails. Rationalize return value to either 0 or -1. + * builtin.c (do_gensub): 3rd arg of zero generates a + warning. + (do_fflush): Rationalize return value: -1 for unopen or read-only + redirection, status of fflush otherwise. + +Wed Oct 11 22:11:19 2000 Arnold D. Robbins + + * awk.y (for loop): Check that there is a body as + part of the `is it a delete statement' check. + +Thu Oct 5 11:56:42 2000 Arnold D. Robbins + + * awk.h, awkgram.y, configure.in, eval.c: Enabled + `for (i in_sorted array)' loops for those who + are Strong In The Way Of The Source. So there. + +Mon Oct 2 10:09:32 2000 Arnold D. Robbins + + * io.c (do_close): Make close(x) for non-open x return -1 + and update ERRNO. close(FILENAME) no longer does anything + magic; this is all for better consistency with other awks + and is more logical, anyway. + +Thu Sep 28 17:27:16 2000 Arnold D. Robbins + + * io.c (close_one): Added a lint warning if it becomes + necessary to start multiplexing fd's, per ancient suggestion + from Scott Deifik, . + +Tue Sep 26 14:41:41 2000 Arnold D. Robbins + + * profile.c: Move enum for redirection placement to top + of file, and make the value a parameter to pp_redir. + Fix all the calls. This gets `|&' right everywhere. + +Sun Sep 24 16:38:04 2000 Arnold D. Robbins + + * awk.h (freenode): Set the flags straight to UNINITIALIZED. + * node.c (unref): Fix test for MALLOC|TEMP to test the + actual flags, not zero. + * builtin.c (format_tree): ala print and concat, dupnode + the temp nodes from tree_evaling the arguments. See + test/nasty2.awk. + +Mon Sep 18 10:16:58 2000 Arnold D. Robbins + + * awkgram.y (snode): Make match 3rd arg and close 2nd arg fatal + errors if --tradtional. + +Thu Sep 14 12:22:42 2000 Arnold D. Robbins + + * eval.c (update_ERRNO): Call gettext on result of strerror. + i18n rules. + +Wed Sep 13 14:56:11 2000 Arnold D. Robbins + + * eval.c (r_tree_eval): Case for Node_concat. Dupnode the + strings ala do_print to get more consistent results. + Compare gawk 3.0.6 to nawk/mawk on test/nasty.awk. + Thanks to Andrew Sumner (andrewsumner@yahoo.com) for + pointing this one out. + +Wed Sep 13 10:06:47 2000 Arnold D. Robbins + + * io.c (two_way_close_type): New enumerated type. + (close_redir): New third param of type two_way_close_type. + Add smarts to two-way case for different close types. + Only remove it from the redir list if closing is for both ends. + (gawk_pclose): Check that rp->iop != NULL before closing, + all three versions. + * awkgram.y (tokentab): Allow 2nd argument to close. + (snode): Add lint warning. + +Sun Sep 10 14:16:10 2000 Arnold D. Robbins + + * field.c (set_FIELDWIDTHS): Generate a fatal error upon + encountering a negative width. + +Sun Sep 10 10:37:35 2000 Arnold D. Robbins + + * awkgram.y (snode): If first argument to dcgettext is a + string constant and --gen-po, dump the string constant to + the .po file too. + * main.c (nostalgia): Add call to fflush(stderr). + * eval.c (r_tree_eval): Add entries for Node_LINT and for + NODE_TEXTDOMAIN. + +Thu Sep 7 10:46:20 2000 Arnold D. Robbins + + * builtin.c (do_dcgettext): Per suggestion from Ulrich Drepper, + make the awk interface: + + str = dcgettext(string [, domain [, category]]) + +Wed Sep 6 16:28:12 2000 Arnold D. Robbins + + Bring gettext features out to the awk level! + + * awk.h: Add declarations of new functions `do_dcgettext' + `do_bindtextdomain', `set_TEXTDOMAIN' and variables + `TEXTDOMAIN', `TEXTDOMAIN_node'. New NODETYPE enum + `Node_TEXTDOMAIN'. + * eval.c (nodetypes): Add Node_TEXTDOMAIN at end. + (set_TEXTDOMAIN): New function. + (r_get_lhs): Add case for Node_TEXTDOMAIN. + * main.c (varinit): Add entry for TEXTDOMAIN. + * node.c (format_val): If INTLSTR use dcgettext of string + and TEXTDOMAIN. + * awkgram.y (tokentab): Add entries for "dcgettext" and + "bindtextdomain". + * builtin.c (do_dcgettext, do_bindtextdomain): New functions. + +Tue Sep 5 17:01:34 2000 Arnold D. Robbins + + * profile.c (pp_string_fp): Use lower case versions of + isascii and isprint to avoid printing high-bit-set + characters. Make it smarter to break strings at 70 + chars or after embedded newline, for --gen-po. + Fix the calls to it everywhere for new boolean option + to yes/no break lines. + * m4/strtod.m4: New file, defines GAWK_AC_FUNC_STRTOD_C89. + * configure.in: GAWK_AC_FUNC_STRTOD_C89 call added + * acinclude.m4: Include strtod.m4. + * acconfig.h: Add entry for STRTOD_NOT_C89. + Remove entries for BITOPS and NON_DEC_DATA. + * missing/missing.c: Add check for STRTOD_NOT_C89, use ours + if set. + * missing/strtod.c: Make smarter for input like 0x345. + * awk.h: [STRTOD_NOT_C89]: Define strtod gawk_strtod to get + our version. Avoids linker weirdness. + +Mon Sep 4 09:16:43 2000 Arnold D. Robbins + + * field.c (set_record): Fix from Utz-Uwe Haus + to make sure there's + always enough room in the record. + * builtin.c (nondec2awknum): Fix octal conversions to exit + when hitting a non-digit, and not go to decimal. Make + check for non-octal better. Based on bug report from + Morris_Lee@tvratings.com. + +Sun Sep 3 13:52:11 2000 Arnold D. Robbins + + * builtin.c (format_tree): Allow positional parameters for + %*.* kinds of things. + + Made octal/hex constants and strtonum on by default. Made + --enable-non-decimal-data a runtime switch `--non-decimal-data'. + + * configure.in: Removed AC_ARG_ENABLE for --enable-bitops and + --enable-non-decimal-data. + In .developing check, remove the AC_DEFINEs. + * awk.h: Decls for bitwise functions now there by default. + Add decl of `do_non_decimal_data'. + * main.c (do_non_decimal_data): New variable + (optlist): Add new entry for `--non-decimal-data'. + (main): Turn off `do_non_decimal_data' if `do_traditional'. + (usage): Add the new option. + * node.c (r_force_number): Make check for non-decimal data a + runtime check based on do_non_decimal_data. + * awkgram.y (yylex): Make non-decimal constants a runtime check. + * builtin.c: Remove the ifdefs around the bit functions and + nondec2awknum. + +Tue Aug 29 18:45:56 2000 Arnold D. Robbins + + * configure.in: Go back to ARRAYDEBUG if .developing set. + * awkgram.y: Use ARRAYDEBUG for adump(), use multiple tests + for stopme(). + +Mon Aug 28 17:09:06 2000 Arnold D. Robbins + + * field.c (do_split): Add check for first arg is null string, + if so, skip the work and return zero. + +Mon Aug 14 23:01:55 2000 Arnold D. Robbins + + Add %COUNT$... handling to printf. + + * awk.h (printf_count): New define in NODE structure. + (format_tree): Added decl. + * awkgram.y (count_args): New function to set printf_count in + a node. + [print productions]: Call the function. + * (snode): For do_sprintf, call count_args, set the count + in the lnode. + * builtin.c (format_tree): New fourth arg is argument count. + Add smarts to handle the `$' in a format. + * (do_sprintf): Use new argument to format_tree. + node.c (format_val): Ditto. + +Sun Aug 13 11:10:41 2000 Arnold D. Robbins + + Changes from Alan J. Broder (ajb@woti.com): + - Array third arg to match puts subtexts into the array: + + * awk.y (tokentab): "match" gets third arg, and lint warning + * builtin.c (do_match): If third arg there, fill it with subtexts + + - New builtin sort function: + + * awk.h (do_sort): Declared. + * array.c (do_sort, dup_table, merge, merge_sort, assoc_from_list, + assoc_sort_inplace): New functions. + + * eval.c (tree_eval): In debug code, make uninitialized var + a warning, not a fatal error. Breaks too many things. + +Wed Aug 9 10:51:41 2000 Arnold D. Robbins + + * eval.c (func_call): Increment the exec_count on the + function's node; this allows printing a call count for + functions. + profile.c (pp_func): Print the count for functions. + * ALL: Changed DEBUG to GAWKDEBUG in all gawk files, so that + I don't get regex/dfa debugging. In some cases, changed + memory-related stuff to MEMDEBUG. Still have work to do. + * awk.h, node.c, profile.c: Removed exec_count_init variable; + code has been cleaned up to not need different values for + profiling/not profiling. + +Thu Jul 5 21:10:59 2000 Arnold D. Robbins + + * eval.c (casetable): Removed the USE_PURE_ASCII stuff; it + was never documented. Latin 1 forever. + * main.c (main): Only call `init_profiling' after arg parsing + if `do_profiling' is still false. Avoids resetting `prof_fp' + back to stderr. + +2000-02-17 Akim Demaille + + * m4: New directory. + * acinclude.m4: Removed, replaced by m4/*.m4. + * Makefile.am: Adjusted. + Added ACLOCAL_AMFLAGS. + * configure.in Adjusted. + Use AC_SYS_LARGEFILE not GAWK_AC_SYS_LARGEFILE, jm_FUNC_MKTIME, + not GAWK_FUNC_MKTIME. + * acconfig.h: Removed _FILE_OFFSET_BITS, _LARGEFILE_SOURCE and + _LARGE_FILES now templated by m4/largefile.m4. + +2000-02-15 Arnold Robbins + + * MOVED TO AUTOMAKE AND GETTEXT. + Just about every file touched. Work done by Arno Peters. + +Sun Jan 2 14:48:23 2000 Arnold D. Robbins + + First edit of the new millenium! + * awk.y (yylex): If lint checking, be obnoxious about gotos. + +Mon Oct 25 19:12:02 1999 Arnold D. Robbins + + * awk.h: Remove C_ALLOCA ifdef. + * main.c (main): Remove C_ALLOCA code. + * io.c (do_input): Ditto. + +Mon Aug 9 17:36:24 1999 Arnold D. Robbins + + * bisonfix.sed: Unconditionally #undef YYSTACK_USE_ALLOCA. + * configure.in: Remove all alloca and ALLOCA related stuff. + * Makefile.in: Ditto. + +Thu Jul 29 18:32:05 1999 Arnold D. Robbins + + * awk.h (NODE): exec_count now in #ifndef NO_PROFILING. + * Makefile.in: Changes to only recompile eval.c and profile.c to a + special version for profiling. + * custom.h [MSC_VER]: Turn on NO_PROFILING to omit the exec_count + and save space. + * node.c (more_nodes): Move setting of exec_count to + #ifndef NO_PROFILING. + +Thu Jul 1 12:12:05 1999 Arnold D. Robbins + + * configure.in (AC_PREREQ): Update to 2.13. + GAWK_AC_C_STRINGIZE: convert to AC_C_STRINGIZE. + * aclocal.m4 (GAWK_AC_C_STRINGIZE): Remove definition, now + part of autoconf. + * acconfig.h (HAVE_STRINGIZE): Ditto. + +Wed Apr 28 11:08:05 1999 Arnold D. Robbins + + * array.c (assoc_lookup): Fix call to free_temp(subs) to after + last use of subs. + +Sun Apr 25 16:48:06 1999 Arnold D. Robbins + + * io.c (redirect): Add lint warning when same file is used for + > and >>. + +Thu Apr 22 15:05:30 1999 Arnold D. Robbins + + * array.c (assoc_lookup): Fix call to fatal to lintwarn instead. + * node.c (r_force_number): Use `0 &&' to disable warnings about + conversions: they're overzealous, methinks. + +Thu Apr 8 14:27:58 1999 Arnold D. Robbins + + New features for profiling: + + * awk.h (NODE): Add `exec_count' member. + (freenode): Clear `exec_count' upon free. + * awk.y (func_count): New variable, counts total number of functions. + (func_install): Increment func_count. + (struct finfo): Information for use in sorting functions when + pretty printing. + (fcompare): Compare two finfo structures. + (dump_funcs): Print the functions in sorted order for profiling. + (getfname): Return the name of a builtin function. + * eval.c (INCREMENT): New macro for counting execution of nodes. + (interpret): Call INCREMENT() appropriately. + * main.c (do_profiling): New flag if doing profiling. + `--profiling': New option added to getopt_long machinery. + (main): For profiled version, set do_profile and output file. + Call `dump_prog' and `dump_funcs' if do_profiling at end. + (usage): Add new argument. + * node.c (more_nodes, freenode): Set exec_count to zero. + * profile.c: New file, does pretty printing and prints counts. + * Makefile.in: Update to create two versions of gawk, regular + and `pgawk' which does profiling. + +Wed Mar 10 21:38:14 1999 Arnold D. Robbins + + * io.c (close_redir): Use update_ERRNO() instead of manually + doing it. + +Mon Dec 21 15:58:21 1998 Arnold D. Robbins + + * configure.in: Add BeOS to list of cases where we hardwire + GETPGRP_VOID. + custom.h: Remove the #define from __be_os case. Cleaner to + do it all in configure. Based on email from Martin C. Brown, + mc@whoever.com. + +Mon Nov 30 20:52:52 1998 Arnold D. Robbins + + * eval.c (update_ERRNO): New function, mainly for use by + extension functions. + * awk.h: Add decl. + +Tue Nov 24 18:13:29 1998 Arnold D. Robbins + + * Changes based on submission from Christos Zoulas at D.E. Shaw + that adds the following features: + - checking for use of uninitialized variables + - checking if a string that's not a number converts to 0 + - ability to load a dynamic library to add built-ins + - VERSION variable (may or may not stay) + Additional change: + - --lint=fatal makes lint errors become fatal + - LINT="fatal" has the same effect, any other positive + value makes lint errors be just warnings + * Makefile.in (includedir): New variable for gawk header files + (ext.c, ext.o): New source and object files + (OTHERS, extension): New directory for macro with example extension + (install): Install header files + * acconfig.h (DYNAMIC): New macro, true if can do dynamic loading + * array.c (assoc_lookup): New parameter `reference' is true if we + want to do reference checking. Add appropriate reference checking + code. + * awk.h (UNITITIALIZED): New flag + (lintfunc): Function pointer for correct function to use + (lintwarn): New macro to produce warnings + (result): New macro for func call result, used in commented out + code in eval.c. + (getnode, freenode): Revised to set UNINITIALIZED. + (get_lhs): Third arg for reference checking, change all calls + -- Add appropriate decls of new/changed functions + * awk.y (tokentab): New builtin "extension" for adding extensions + (node_common): Set flags to UNINITIALIZED for Node_var. + * configure.in (dynamic linking): New check. Probably should + be a separate macro. + * eval.c (flag2str): Add UNINITIALIZED to the table. + (r_tree_eval): Add checks for UNINITIALIZED. + (push_args): Appropriate changes for UNINITIALIZED to work. + (r_get_lhs): New third argument for reference checking. + (set_LINT): Add code to handle setting `lintfunc' appropriately. + * ext.c: New file, for doing dynamic library extensions. + * extension/*: New directory with simple example code. + * main.c (VERSION_node, EXTENSION_node): New nodes for new vars. + (optab): Change for "lint" to allow optional argument. + (lintfunc): Definition. + (main): Add case in option processing for --lint. + (varinit): Add entries for VERSION and EXTENSION. + * node.c (r_force_number): Checks that string really is a number. + (morenodes): Set UNITIALIZED in the flags. + * re.c (all): Change `result' to `res' globally to avoid conflict + with new macro. + * GLOBAL: Change lint calls to warning() to lintwarn(). + * GLOBAL: Change all calls to get_lhs() to have 3rd arg. + * GLOBAL: Change all calls to assoc_lookup() to have 3rd arg. + +Sun Nov 22 17:07:39 1998 Arnold D. Robbins + + * patchlev.h: Renamed from patchlevel.h to make life + easier for the PC guys. + (main.c): Changed to include patchlev.h. + (Makefile.in): Changed to ref patchlev.h where needed. + +Sat Nov 7 21:29:52 1998 Arnold D. Robbins + + * eval.c (r_get_lhs): case Node_field_spec. Fix the lint + warnings for field reference of null string or non-numeric value. + When turned on, $0 generated a warning! Oops. + +Thu Nov 5 16:58:38 1998 Arnold D. Robbins + + * main.c (init_fds): New function to pre-open 0, 1, and 2 on + /dev/null if they're not open. Robustness, more or less. + (main): Call init_fds. + * io.c (str2mode): Add smarts for two-letter strings + such as "rw", "r+", "wr", "w+" and "a+". + +Mon Nov 2 16:55:46 1998 Arnold D. Robbins + + * builtin.c (do_*): Added lint checks for non-numeric + and/or non-string arguments, as appropriate. This should + have been done long ago. + +Tue Oct 20 21:56:06 1998 Arnold D. Robbins + + * awk.h (LINT_node): New variable for LINT special var + (Node_LINT): New node type. + (set_LINT): Declare function. + * main.c (varinit): Add LINT variable. + (usage): Print an emphatic pointer to the manual for bug reports. + * eval.c (nodetypes): New entry for Node_LINT. + (r_get_lhs): Case added for Node_LINT. + (set_LINT): Set do_lint from LINT variable. + +Mon Oct 19 22:35:46 1998 Arnold D. Robbins + + * configure.in: For GCC, add -Wall to get warnings for development. + * Makefile.in (awktab.c): Move sed stuff to separate script. + * bisonfix.sed: New script, with old fix and Solaris x86 fix. + * awk.h (nodetype2str): Add declaration. + (load_procinfo): Add declaration. + +Tue Oct 13 22:28:56 1998 Arnold D. Robbins + + Changes to make PROCINFO["FS"] reflect the use of FIELDWIDTHS or FS. + + * eval.c (assign_val): New function that does the mechanics of + assignment + * main.c (load_procinfo): Add setting of PROCINFO["FS"] to "FS". + * field.c (update_PROCINFO): New function to update the array. + (set_FS): Call update_PROCINFO. + (set_FIELDWIDTHS): Ditto. + +Sun Sep 27 10:18:05 1998 Arnold D. Robbins + + * awk.h (reisstring): New prototype. + * re.c (reisstring): New function, returns true if the re did + a simple string match. This is rather simplistic in its logic. + * io.c (get_a_record): In the case that RS is a regexp, AND + the re matched at the exact end of the buffer, add a call to + `reisstring' in case it's a simple string match. If so, we + don't need to read more into the buffer because we don't + have a regex like `x.*y' that might extend longer. + This should be very helpful for interactive /inet clients + where something like `RS = "\r\n"' happens. + +Thu Aug 13 22:07:40 1998 Arnold D. Robbins + + * io.c (socketopen): Fixes from Juergen Kahrs to socket + opening code for "any host". + +Tue Jul 14 19:02:33 1998 Arnold D. Robbins + + * aclocal.m4 (GAWK_AC_LIB_SOCKETS): Removed the caching; + configure gave different results the second time it was run! + +Fri Jul 10 09:11:06 1998 Arnold D. Robbins + + * eval.c (interpret): Minor cleanups: add variable name to + fatal error Node_K_array_for and other minor changes. + +Mon Jun 22 16:53:34 1998 Arnold D. Robbins + + * Makefile.in (tags, TAGS): Add $(LIBSRC). + +Tue Jun 2 15:23:05 1998 Arnold D. Robbins + + * io.c (devopen): Relax previous change, don't require "any", + just that a port be there. The user can put 0 if they + don't care. + +Wed May 27 21:33:45 1998 Arnold D. Robbins + + * io.c (devopen): For /inet, require that local and remote + ports and the remote hostname be there, and that `any' + be used for a port if they don't care. + +Thu May 21 14:13:46 1998 Arnold D. Robbins + + * node.c (parse_escape): Add warning that is always on + for \q for any unknown q inside string or regex constant. + I got bit by this myself once too often. Or else I'm + just getting old and senile. + +Mon May 4 12:42:49 1998 Arnold D. Robbins + + * awk.h (NODETYPE): Sorted the Node_xxx entries for the + builtin variables. Gotta look nice, don't we? + * eval.c (nodetypes): Ditto. + (genflags2str): Added code to check that we don't + overflow the static buffer. This is just a debugging + routine, not worth the hassle of dynamic allocation. + +Mon Mar 2 16:06:16 1998 Arnold D. Robbins + + * Makefile.in (dist): Remove any embedded copied RCS or CVS + directories. + +Mon Feb 23 00:09:52 1998 Arnold D. Robbins + + * awk.h (genflags2str): Add declaration. + * eval.c (genflags2str): New function. + (flags2str): Use new general purpose function. + * io.c (redflags2str): Same. + +Sun Feb 22 23:57:29 1998 Arnold D. Robbins + + Significant changes to add two-way i/o and sockets!!! + + * Makefile.in: Add @SOCKET_LIBS@ to LIBS variable. + * acconfig.h: Add HAVE_SOCKETS and HAVE_PORTALS defs. + * aclocal.m4: New macro GAWK_AC_LIB_SOCKETS. + * awk.h: New node type, Node_redirect_twoway, and new redirection + flags: RED_TWOWAY, and RED_SOCKET. + * awk.y (parser): Add TWOWAYIO token and appropriate productions. + (yylex): Recognize `|&' token if not traditional. + * builtin.c (do_print, do_printf): Flush buffer if TWOWAYIO. + * configure.in: Add header checks for networking header files, + add --enable-portals switch, call GAWK_AC_LIB_SOCKETS + * eval.c (nodetypes): Add string constant for Node_redirect_twoway. + * io.c (redflags2str): New function. + (redirect): Better error message in default case, add code for + Node_redirect_twoway. + (socketopen): New function. + (iop_open, devopen): Add recognition of `/inet/...'. + (two_way_open): New function. + +Sat Dec 13 21:15:07 1997 Arnold D. Robbins + + * awk.h (struct node): New member, `param_list' in union `x', becomes + `node->parmlist' in the code. + * awk.y (func_install): Rearranged a bit, to build up a list of + the function parameter names and to save it in the `parmlist' field. + * eval.c (push_args): New parameter, `varnames', which is the list + of variable names. Use this to set the vname field of each + parameter's value as it's created. Special case arrays to include + where they came from, mainly for array vs. scalar diagnostics. + (r_tree_eval): Don't set the `vname' field for parameters. + (pop_fcall): Free the `vname' field if it's an array. + (func_call): Pass in the `parmlist' field to call of push_args(). + (r_get_lhs): For Node_subscript, change error message to use + the `vname' field. + (stopme): New do-nothing function for use with debugging code + and setting breakpoints. + +Thu Dec 4 15:18:17 1997 Arnold D. Robbins + + * awk.y: Fixed several lint checks and moved some into + test for do_lint_old. + * eval.c (fmt_index): Add value of bad format spec to + error message. + +Tue Nov 18 22:19:02 1997 Arnold D. Robbins + + * Makefile.in (install): Strip the installed binary. + From Anatoly A. Orehovsky (tolik@mpeks.tomsk.su). + +Sun Nov 16 22:12:39 1997 Arnold D. Robbins + + * array.c (in_array, assoc_lookup): Add symbol->vname to + fatal calls for scalar in array context. + +Wed Nov 12 22:18:33 1997 Arnold D. Robbins + + * awk.h [ISASCII]: On all IS* macros, add cast to unsigned char. + [TOUPPER, TOLOWER]: New macros using unsigned char. + * awk.y: Change to use of IS* vs. is* macros. + * builtin.c (nondec2awknum): Change to use of IS* vs. is* macros, + change casts for casetable[] from int to unsigned char. + use new TOLOWER, TOUPPER macros + * dfa.c [ISASCII]: On all IS* macros, add cast to unsigned char. + (lex): Change isdigit to ISDIGIT. + [TOUPPER, TOLOWER]: New macros using unsigned char, now used. + * eval.c (fmt_ok): Change to use of IS* vs. is* macros. + * field.c (sc_parse_field): Change to use of IS* vs. is* macros, + change casts for casetable[] from int to unsigned char. + (set_FS): Change to use of IS* vs. is* macros. + * io.c (get_a_record): Change to use of IS* vs. is* macros, + change casts for casetable[] from int to unsigned char. + * main.c (main): Change to use of IS* vs. is* macros. + * node.c (r_force_number, parse_escape): Change to use of IS* vs. + is* macros. + * re.c (make_regexp): Change to use of IS* vs. is* macros. + * regex.c [ISASCII]: On all IS* macros, add cast to unsigned char. + +Sun Oct 19 12:36:47 1997 Arnold D. Robbins + + * ALL: Change email address to arnold@gnu.org in all relevant places. + +Wed Oct 15 03:38:12 1997 Arnold D. Robbins + + * awk.y (yylex): Don't allow newlines after ? or : if do_posix. + +Thu Oct 9 19:28:39 1997 Arnold D. Robbins + + * custom.h [SEQUENT]: Removed; not needed any more since the + mmap code was ripped out. + +Wed Oct 8 17:22:03 1997 Arnold D. Robbins + + * configure.in: Remove check for madvise; don't need it any more + after nuking use of mmap. + +Tue Oct 7 11:14:21 1997 Arnold D. Robbins + + * eval.c (flags2str): Made the code table driven. Shortened a lot. + +Tue Sep 30 20:59:17 1997 Arnold D. Robbins + + * eval.c (r_get_lhs): case Node_field_spec. Add lint warnings + for field reference of null string or non-numeric value. + Based on patch submitted by Alan Broder, ajb@dtmr.com. + +Wed Sep 24 20:47:59 1997 Arnold D. Robbins + + * custom.h [TANDEM]: New changes. Finishes up Tandem + integration. + +Mon Sep 22 00:42:34 1997 Arnold D. Robbins + + * custom.h [__be_os]: Remove BROKEN_TOKEN definition. + * dfa.c, dfa.h: Change `token' to `dfa_token' to avoid BeOS + compile problems. + +Thu Aug 7 22:35:17 1997 Arnold D. Robbins + + Changes for BeOS from mc@whoever.com + + * awk.h (strncasecmp): Bracket prototype. + custom.h [__be_os]: New stuff. + dfa.h, dfa.c [BROKEN_TOK]: New ifdefs to use dfa_token, not token. + +Fri Aug 1 13:32:49 1997 Arnold D. Robbins + + Tandem changes: + + * awk.h [TANDEM]: Misc additions, as needed. + * io.c (get_a_record): Changes for fixed length records; not used + on other systems. + * main.c (MRL): New variable, TANDEM specific. + (main): Update handling -mr option for TANDEM. + (load_environ): Comment out whole routine if TANDEM. + missing.c [TANDEM]: New includes. + gawkmisc.c [TANDEM]: Include `tmiscc'. + +Wed Jul 30 19:53:52 1997 Arnold D. Robbins + + Close-on-exec changes: + + * awk.h: (os_close_on_exec, os_isdir): New functions. + * gawkmisc.c: Add include fcntl.h. + * configure.in [AC_CHECK_HEADERS]: Add fcntl.h. + * io.c (devopen, iop_open): Change to use os_isdir(), not S_IFDIR(). + (redirect, devopen, iop_open, gawk_popen): Change all calls to + fcntl() to os_close_on_exec(). + +Tue Jul 29 11:09:45 1997 Arnold D. Robbins + + * eval.c (set_BINMODE): Fixed check for digits to use isdigit() + instead of looping over digits and using strchr(). Duh. + +Sat Jul 26 22:52:08 1997 Arnold D. Robbins + + * eval.c (set_BINMODE): Fix so that `-v BINMODE=w' works. + * node.c (r_force_number): Add decl of strtod(); makes things + work on MIPS. + * Makefile.in (install-strip): New target. + +Fri Jul 18 13:28:05 1997 Arnold D. Robbins + + * io.c (redirect, devopen, iop_open, gawk_popen): Set the + close-on-exec flag on all files and pipes opened for I/O. + Keeps children run via system() or other pipes from running out + of file descriptors. + + (Reported by Kenny McCormack, gazelle@yin.interaccess.com.) + +Tue Jul 8 22:18:00 1997 Arnold D. Robbins + + * awk.y [LEX_NEXT]: Removed support for `next file' as two words. + +Tue Jul 8 06:46:32 1997 Arnold D. Robbins + + * dfa.c: Changes from pjr@jet.UK (Paul J Rippin) from an old + bug report against 2.14.0 that speed up initialization and + rewrite the inner loop into readable code. + +Thu Jul 3 11:44:50 1997 Arnold D. Robbins + + * Atari support moved into new `unsupported' directory. + awk.h, Makefile.in, gawkmisc.c, and missing.c modified. + +Sun Jun 29 14:17:37 1997 Arnold D. Robbins + + * awk.y (exp): Fixed warning about `x = /foo/'. + +Wed Jun 25 09:07:57 1997 Arnold D. Robbins + + * PORTS: Removed from distribution. + * Makefile.in (MISC): Removed PORTS. + +Sun Jun 22 11:52:57 1997 Arnold D. Robbins + + BINMODE changes. + + * awk.h (Node_BINMODE): Added. + (struct redirect): Added mode field to save for io.c:close_one(). + (BINMODE, BINMODE_node, set_BINMODE): Add declarations. + * awk.y (isnoeffect): Add Node_BINMODE. + * eval.c (nodetypes): Add Node_BINMODE string. + (r_tree_eval, r_get_lhs): Add cases for Node_BINMODE. + (set_BINMODE): New function. + * io.c (binmode): New function. + (nextfile, redirect, gawk_popen): Add calls to binmode(). + * main.c (BINMODE, BINMODE_node): Add decls. + (main): Add call to setmode() if BINMODE is set. + (varinit): Add entry for BINMODE. + +Wed Jun 4 21:52:25 1997 Arnold D. Robbins + + * configure.in [AC_FUNC_MMAP]: Removed call. + * awk.h [struct iobuf]: Removed IOP_MMAPED flag and `getrec' member. + * io.c: Removed all mmap related code. + +Sun Apr 27 16:23:56 1997 Arnold D. Robbins + + * aclocal.m4 [GAWK_AC_FUNC_MKTIME]: New macro. + * configure.in (GAWK_AC_FUNC_MKTIME): Call it. + +Thu Apr 24 23:25:06 1997 Arnold D. Robbins + + * io.c (devopen): Remove stat test for /dev/foo files. Finally. + +Fri Jul 26 09:23:15 1996 Arnold D. Robbins + + Changes to add an abort statement, a la tawk. + + * awk.h (Node_K_abort): New enum value for NODETYPE. + * main.c (aborting): New flag variable. + (main): Add logic to handle aborting. + * eval.c (interpret): Add case for Node_K_abort. + * io.c (do_input): If aborting, break loop. + * awk.y (tokentab): Add entry for "abort" keyword + (PRODUCTIONS): Add production for LEX_ABORT. + +Wed Jul 24 12:49:52 1996 Arnold D. Robbins + + First cut at changes for i18n. + + * awk.h (do_intl): Declare new flag variable. + [INTLSTR]: New flag def. + (m_tree_eval): Fix definitions for INTLSTR. + (force_string): Fix definitions for INTLSTR. + * awk.y (yylex): Add _"..." for international strings. + (dumpintlstr): New function. + * main.c (do_intl): Define new flag variable. + (optab): Add "gen-po" entry. + (main): If do_intl, exit, don't run the program. + (gawkoption): Add "gen-po" entry. + * node.c (r_force_string): Call gettext if flags indicate INTLSTR. + +Thu Mar 14 06:29:42 1996 Arnold D. Robbins + + * awk.h (do_mktime): Added declaration of new function. + * builtin.c (do_mktime): New function. + * awk.y (tokentab): Added "mktime" to list of gawk extensions. + * missing.c [HAVE_MKTIME]: Added include of mktime.c if needed. + +Mon Feb 26 22:32:19 1996 Arnold D. Robbins + + * io.c (pidopen, useropen): Added warnings to use PROCINFO[], + not special files. + * main.c (load_procinfo): New function. + * awk.y (variable): Added call to load_procinfo() function. + +Mon Aug 7 15:23:00 2000 Arnold D. Robbins + + * Release 3.0.6: Release tar file made. + +Thu Aug 3 17:47:53 2000 Greg McGary + + * regex.c: Patches for gcc bounded pointer handling. + +Thu Aug 3 13:09:09 2000 Arnold D. Robbins + + * array.c (in_array, do_delete): Fix tests for index equality + when searching through the array to work correctly when + index is "". + +Fri Jul 14 21:40:17 2000 Pat Rankin + + * builtin.c (format_tree): Workaround a DEC C V5.7 bug by + splitting `strcpy() + 3' into two expressions (the builtin + inline strcpy evidently has erroneous return type of void * + instead of char *; reputedly fixed in V6.1). + + * eval.c (C): New macro. + [casetable]: Use it to add explicit casts for the character + values outside the range of 0 to 127. + * missing/strncasecmp.c [C, charmap]: Likewise. + + * io.c (redirect): Add EIO check on failed open for VMS. + +Fri Jul 14 11:57:23 2000 Arnold D. Robbins + + Efficiency hack: turn `for (iggy in foo) delete foo[iggy]' + into moral equivalent of `delete foo'. + + * array.c (do_delete_loop): New routine. + * awk.h [NODETYPE]: New Node_K_delete_loop value. + Add declaration of do_delete_loop. + * awk.y [LEX_FOR]: Fix code to recognize special case. + * eval.c (nodetypes): New entry for Node_K_delete_loop. + (interpret): Add case for Node_K_delete_loop, add more + diagnostic info in default (cant_happen) case. + +Tue Jul 11 22:15:10 2000 Pat Rankin + + * awk.y (nextc): Recast unsigned char values back to int to + prevent VAX C from truncating EOF to 255. + +Tue Jul 11 14:08:23 2000 Arnold D. Robbins + + * array.c (do_delete): Switch to string comparison, not + cmp_nodes. + (assoc_find): Add call to force_string on subscript. + * eval.c (interpret): Case Node_K_arrayfor: check for + Node_array_ref and fetch original_array. Yowser. + +Fri Jun 30 21:57:00 2000 Arnold D. Robbins + + * array.c (assoc_lookup): Don't force the subscript + to be a string. Not a good idea after the change + to using dupnode. + +Sun Jun 25 15:08:19 2000 Arnold D. Robbins + + * Release 3.0.5: Release tar file made. + +Wed Jun 14 13:03:45 2000 Arnold D. Robbins + + * field.c (set_record): Manage a private buffer for $0. + Keeps things safe in case `getline var' rearranges the + IOBUF's contents that $0 is still pointing into. + +Tue Jun 13 16:27:55 2000 Paul Eggert + + Upgrade to latest and greatest version of largefile code. + + * configure.in (AC_CANONICAL_HOST): Remove. + (GAWK_AC_SYS_LARGEFILE): Defer until after AC_MINIX, + to avoid autoconf warnings. + + Rewrite largefile configuration so that we don't need to run + getconf and don't need AC_CANONICAL_HOST. + * config.guess, config.sub: Remove these files. + * Makefile.in (MISC): Remove config.guess, config.sub. + * m4/largefile.m4 (GAWK_AC_SYS_LARGEFILE_FLAGS, + GAWK_AC_SYS_LARGEFILE_SPACE_APPEND): Remove. + (GAWK_AC_SYS_LARGEFILE_TEST_INCLUDES): New macro. + (GAWK_AC_SYS_LARGEFILE_MACRO_VALUE): Change arguments from + CODE-TO-SET-DEFAULT to VALUE, INCLUDES, FUNCTION-BODY. + All uses changed. + Instead of inspecting the output of getconf, try to compile the + test program without and with the macro definition. + (GAWK_AC_SYS_LARGEFILE): Do not require AC_CANONICAL_HOST or check + for getconf. Instead, check for the needed flags by compiling + test programs. + + (GAWK_AC_SYS_LARGEFILE): Define _XOPEN_SOURCE to be 500 to + work around glibc 2.1.3 bug. + + (GAWK_AC_SYS_LARGEFILE_FLAGS): Don't use -n32 on IRIX if the + installer said otherwise. + + (GAWK_AC_SYS_LARGEFILE_FLAGS): Work around a bug in the QNX shell, + which doesn't propagate exit status of failed commands inside + shell assignments. + +Wed Jun 7 13:23:09 2000 Arnold D. Robbins + + * Updated copyright dates in appropriate files. + +Mon May 22 17:29:43 2000 Arnold D. Robbins + + * Makefile.in (clean): Get `*/core' too. + +Sun May 7 16:33:05 2000 Arnold D. Robbins + + * array.c (concat_exp): Change ref to `lnode->stlen' and + `lnode->stptr' for SUBSEP to use `var_value->...'. + +Tue May 2 09:54:29 2000 Arnold D. Robbins + + Fix referencing freed memory as shown by test/arynocls.* tests. + * awk.h [Node_array_ref]: New node type. + [orig_array]: New macro element in NODE structure. + * field.c (do_split): Handle case for Node_array_ref, fetch + the original array. + * array.c (in_array, do_delete): Ditto. + * eval.c (nodetypes[]): Add Node_array_ref string. + (r_tree_eval): Handle case for Node_array_ref. + (push_args): Push arrays as Node_array_ref, and pass them on. + (pop_fcall): Don't unref lnode if it's an array when releasing + local arguments. Check for both Node_array and Node_array_ref. + (r_get_lhs): Choke on Node_array_ref as for Node_array. + For Node_subscript, handle Node_array_ref. + +Tue May 2 09:52:12 2000 Bruno Haible + + * io.c (redirect): After reopening a `struct redirect', move it to + the head of the list. + +Sun Apr 2 17:51:40 2000 Arnold D. Robbins + + * re.c (re_update): Check if IGNORECASE has changed, and + if so recompute the re. See test/igncdym.awk. + +Mon Mar 20 16:18:34 2000 Arnold D. Robbins + + * io.c (set_RS): Added a lint warning about multicharacter RS, + per suggestion from Akim DeMaille (akim@epita.fr). + +Sun Feb 13 14:40:32 2000 Arnold D. Robbins + + * eval.c (push_args): Fix from Nide Naoyuki , + re-assign `f' in case tree_eval moved fcall_list around. + +Sun Feb 6 11:39:33 2000 Arnold D. Robbins + + * eval.c (op_assign): Fix it right. For ++ and --, get the lhs + in the operations, do the op, and then return. For += etc, + get the rhs FIRST, since the lhs can move around as a result, + *then* get the lhs and do the operation. See test/opasnidx.awk. + +Tue Feb 1 18:41:40 2000 Arnold D. Robbins + + * eval.c (op_assign): Reget the rval after regetting + the left hand side. See test/opasnslf.awk for why. + +Thu Jan 27 18:06:31 2000 Arnold D. Robbins + + * awk.y (yylex): Made ']' not one of the characters + that sets `want_assign' to false. `a[i] /= 2' was + broken. Per bug report from Kristofer T. Karas + . + +Wed Dec 22 15:06:37 1999 Arnold D. Robbins + + * awk.y: Removed declarations of functions before + definition of `tokentab[]'. They're redundant with + what's in awk.h. + +Thu Dec 9 17:01:07 1999 Arnold D. Robbins + + * node.c (parse_escape): Add lint warning for unrecognized + escape sequences. + +Mon Dec 6 15:17:34 1999 Arnold D. Robbins + + * main.c (usage): Changed bug reporting email addresses to + be a reference to `Bugs' node in the online and printed + doc, instead. + +Thu Dec 2 13:08:18 1999 Arnold D. Robbins + + * builtin.c (do_compl): Test `d' for negative inside the do_lint + test, not uval. Ooops. + +Fri Nov 26 10:58:36 1999 Arnold D. Robbins + + * array.c (assoc_find): ALWAYS compare indexes as strings, + don't use cmp_nodes in case they are numeric. Oh my. + Talk about a Day 1 bug! + +Tue Nov 23 11:58:53 1999 Arnold D. Robbins + + * regex.c (SYNTAX): Cast argument to `unsigned char' instead of + &-ing with 0xFF. Hopefully somewhat more portable, ala 21 Nov 99 + changes to awk.y. + +Sun Nov 21 22:25:27 1999 Paul Eggert + + * aclocal.m4 (AC_SYS_LARGEFILE_FLAGS): Work around a + problem with the QNX 4.25 shell, which doesn't propagate exit + status of failed commands inside shell assignments. + +Sun Nov 21 20:33:35 1999 Arnold D. Robbins + + * awk.h (nextc): Remove declaration, don't need it here. + awk.y (nextc): Cast values to unsigned char so that latin-1 + characters in strings don't turn themselves into EOF. + Most notably y-umlaut, which is decimal 255. + +Mon Nov 1 20:00:25 1999 Arnold D. Robbins + + * regex.c (init_syntax_once): Move below definition of + ISALNUM etc., then use ISALNUM to init the table, so that + the word ops will work if i18n'ed. + (SYNTAX): And subscript with 0xFF for Latin-1 characters. + +Mon Oct 25 18:37:13 1999 Arnold D. Robbins + + * awk.h, main.c, io.c: Undo previous changes (22 Oct 1999). + * main.c (main): Move call to `init_fields()' to before + arg parsing. This allows `-v NF=blah' to work ok. + +Fri Oct 22 17:43:40 1999 Arnold D. Robbins + + * main.c (arg_assign): Add new arg, `initing' for icky special + casing of -v of special variables. Use it to check for NF. + May need to add other cases later. + (pre_assign): Change call arg_assign, passing initing=TRUE; + io.c (nextfile): Change call arg_assign, passing initing=FALSE; + awk.h: Change prototype for arg_assign. + +Tue Oct 19 16:06:48 1999 Paul Eggert + + * io.c (close_redir): Don't munge errno between setting it and + using it. + +Wed Oct 6 17:47:47 1999 Arnold D. Robbins + + * main.c (arg_assign): Return NULL on bad variable. Allows + things like `./3x=stuff' to work as a filename. + +Thu Sep 23 21:35:46 1999 Paul Eggert + + * aclocal.m4 (GAWK_AC_SYS_LARGEFILE_FLAGS): Work around GCC + 2.95.1 bug in HP-UX 10.20 or later. (Had to fix the fix. ADR. :-) + +Tue Sep 21 13:31:36 1999 Arnold D. Robbins + + * builtin.c (format_tree): For '0', only set zero_flag if we + haven't seen the field width or precision yet. + +Mon Aug 9 13:06:01 1999 Arnold D. Robbins + + * array.c (assoc_lookup): Removed code that gave each array + a private copy of each index. Balloons memory usage for + no good reason that I can see. Just use dupnode in all + cases. + * configure.in: Check for $srcdir/.developing adds extra + defines for my testing/debugging use. Yes, hack alert. + +Sun Aug 1 11:02:02 1999 Arnold D. Robbins + + * node.c (dupnode): Turn off FIELD when copying nodes. + * array.c (do_adump, assoc_dump): New functions for array debugging. + * awk.y (tokentab): Conditionally add "adump" function for debugging. + * awk.h: Delcare new functions. + +Thu Jul 29 23:26:40 1999 Arnold D. Robbins + + From wsanchez@apple.com: + * Makefile.in (install-strip): New target, coding stds. compatibility. + * config.guess, config.sub: Add MacOS X recognition. + +Thu Jul 29 19:09:19 1999 Arnold D. Robbins + + * awk.y (func_install): Make `function foo(foo)' a fatal error. + eval.c (r_tree_eval): Diagnose use of a function name as a + variable inside the function. + +Sun Jul 4 16:53:14 1999 Arnold D. Robbins + + * eval.c (eval_condition): Add extra braces to avoid + gcc warning. I'm not going to bother for the library + code like dfa and regex. + +Wed Jun 30 16:14:36 1999 Arnold D. Robbins + + * Release 3.0.4: Release tar file made. This time for sure. + +Wed Jun 30 16:10:11 1999 Arnold D. Robbins + + * awk.h: Add include of , and comment about config.h + having to be included before any system headers. Otherwise, + with egcs-2.91.66 and later on Linux systems, and possibly + others, things break badly, due to the LFS macros. + * awk.y, builtin.c, eval.c, field.c, io.c: Removed include + of assert.h + +Wed Jun 9 11:39:19 1999 Paul Eggert + + Port the large-file code to AIX, HP-UX, and IRIX. + Add cross-compilation support for large files. + + * config.guess, config.sub: New files. + + * configure.in (AC_CANONICAL_HOST): + Add; GAWK_AC_SYS_LARGEFILE needs this. + (GAWK_AC_SYS_LARGEFILE): Renamed from GAWK_AC_LARGE_FILES. + + * aclocal.m4 (GAWK_AC_SYS_LARGEFILE): Renamed from GAWK_AC_LARGE_FILES. + Add support for AIX and HP-UX. + (GAWK_AC_SYS_LARGEFILE_FLAGS, GAWK_AC_SYS_LARGEFILE_SPACE_APPEND, + GAWK_AC_SYS_LARGEFILE_MACRO_VALUE): New macros. + + * acconfig.h (_FILE_OFFSET_BITS, _LARGEFILE_SOURCE, _LARGE_FILES): + New macros. + + * Makefile.in (MISC): Add config.guess and config.sub so they get + included in the distribution. + +Wed Jun 9 11:29:29 1999 Paul Eggert + + * io.c (iop_alloc): Don't mmap files whose sizes don't fit in `int'. + [ This isn't really needed, as HAVE_MMAP is #undef'ed at the top, + but it's there in case people want to take their life in their hands. ] + +Sun Jun 6 11:28:07 1999 Arnold D. Robbins + + * BETA Release 3.0.46: Release tar file made. + +Wed Jun 2 14:36:24 1999 Arnold D. Robbins + + * PORTS: Updated with a more recent list of systems + that gawk compiles and tests ok on. + +Tue Jun 1 14:24:59 1999 Arnold D. Robbins + + * BETA Release 3.0.45: Release tar file made. + +Tue May 25 16:32:37 1999 Arnold D. Robbins + + * builtin.c (format_tree): More smarts for weird cases, such as + zero precisions and zero values used with the `#' flag. + Thanks to Andreas Schwab (schwab@gnu.org) for pointing these out. + +Wed May 19 14:02:54 1999 Arnold D. Robbins + + * io.c (do_close): Move test for `close(FILENAME)' to after + loop through all open redirections. Fixes problems in obscure + cases with redirections in END rules. + +Sun May 16 14:08:39 1999 Arnold D. Robbins + + * awk.y (yylex): Fix group of characters including ',' to + set want_assign = FALSE. Fixes bizarre parsing problems in + function call lists, for example. + * io.c (get_a_record): Repair logic for single-leading-newline + case. + +Tue May 11 16:48:11 1999 Arnold D. Robbins + + * aclocal.m4 (GAWK_AC_AIX_TWEAK): New macro. + * configure.in: Call it + * Makefile.in: (awklib/all): Pass CFLAGS on to sub-make so + that password programs will get AIX magic defines. Avoids + having to tweak program code for those in doc/gawk.texi. + +Mon May 3 16:56:23 1999 Arnold D. Robbins + + * array.c (do_delete): Don't free_temp(subs) until after all + references to it are finished. + +Mon May 3 13:41:16 1999 Arnold D. Robbins + + * BETA Release 3.0.44: Release tar file made. + +Sun May 2 18:25:43 1999 Arnold D. Robbins + + * io.c (get_a_record): Do a really good job of stripping newlines + from the front of records when RS = "" and there's only one + newline at the front of the file, which the regex didn't catch. + +Wed Apr 28 12:27:49 1999 Arnold D. Robbins + + * configure.in: More HP stuff: fix the manual alloca code so that + gawk will compile and link on HP systems. See the comments. + +Sun Apr 25 13:39:16 1999 Arnold D. Robbins + + * Makefile.in (gawk): Add $(CFLAGS) to linking step. + * configure.in: Correctly do AC_FUNC_GETPGRP on HP systems too. + +Tue Apr 13 20:21:00 1999 Arnold D. Robbins + + * BETA Release 3.0.43: Release tar file made. + +Tue Apr 13 19:02:20 1999 Arnold D. Robbins + + * io.c (useropen, pidopen): Add casts to int on arguments to + silence gcc warnings. + * regex.c (regcomp,regexec,regfree): Add ifdef for APPLE. + +Thu Feb 4 10:38:02 1999 Arnold D. Robbins + + * custom.h: Hacks for BeOS. Not documented in the manual right now. + * configure.in: Hacks for BeOS. Check for HP-UX and define C_ALLOCA + if not using gcc. I wish they'd just fix bison already. + +Sun Dec 20 16:57:38 1998 Arnold D. Robbins + + * BETA Release 3.0.42: Release tar file made. + +Sun Nov 15 21:05:39 1998 Arnold D. Robbins + + * io.c (gawk_popen): Add WIN32 to list of systems that use + the non-real-pipe version. From the PC gawk guys. + +Wed Nov 4 11:32:24 1998 Arnold D. Robbins + + * BETA Release 3.0.41: Release tar file made. + +Tue Nov 3 16:24:35 1998 Arnold D. Robbins + + * eval.c (r_get_lhs): Fix the cases for the special variables, + don't unref their current value if it's the same as the internal + copy; perhaps the current one is used in a concatenation or some + other expression somewhere higher up in the call chain. Ouch. + See test/getnr2tm.awk. + +Sun Nov 1 15:24:52 1998 Arnold D. Robbins + + * builtin.c (format_tree): Improve handling of zero-fill + when a precision is present. See test/zeroflag.awk. + +Wed Oct 28 20:40:17 1998 Arnold D. Robbins + + * eval.c (r_tree_eval): Case for Node_concat. Get lengths + separately, in case one expression has a side effect that + that changes another. Ugly, but it keeps gawk from core + dumping. See test/nasty.awk. + +Sun Oct 18 21:27:24 1998 Arnold D. Robbins + + * awk.y (append_right): Bug fix, if `list' or `new' are NULL, + return `list', so that things don't break too badly. + * regex.c (re_compile_fastmap): Remove unused variable `num_regs'. + +Thu Oct 8 19:36:57 1998 Arnold D. Robbins + + * BETA Release 3.0.40: Release tar file made. + +Mon Jul 27 10:14:33 1998 Arnold D. Robbins + + * node.c (parse_escape): Remove assignment with side effects + from ISXDIGIT test. Thanks to "Mihai T. LAZARESCU" + for pointing this out. + +Mon Apr 27 11:31:32 1998 Arnold D. Robbins + + * main.c (usage): Fix the email address for the bug list. + (copyleft): Update the copyright year. + +Mon Mar 23 21:22:32 1998 Arnold D. Robbins + + * eval.c (r_get_lhs): Make sure that values of type + Node_param_list don't have the FUNC flag set. This means + we don't allow the use of a function name as a variable or + array from within the function. + +Sun Mar 22 19:12:32 1998 Paul Eggert + + * aclocal.m4 (GAWK_AC_LARGE_FILES): New macro that checks for + large file support, and updates CPPFLAGS, LDFLAGS, LIBS as + needed. + * configure.in: Call GAWK_AC_LARGE_FILES. + * Makefile.in (CPPFLAGS, LDFLAGS): Let autoconf configure. + (COMPFLAGS): Add $(CPPFLAGS). + +Mon Mar 16 14:06:41 1998 Arnold D. Robbins + + * field.c (using_FIELDWIDTHS): New macro. + (using_fieldwidths): Use new macro. + (do_split): In case for FS_DFLT, also check that + we're not using FIELDWIDTHS. Otherwise, split() would use + FIELDWIDTHS, not current value of FS. Oops. + +Sun Nov 16 20:08:59 1997 Arnold D. Robbins + + * builtin.c (sub_common): Fix for count of matches in gsub + from Geert.Debyser@esat.kuleuven.ac.be. + +Wed Oct 15 03:38:12 1997 Arnold D. Robbins + + * field.c (set_FS): Use `sc_parsefield' if the value of FS is not + alphabetic OR if not ignoring case. Bug fix if IGNORECASE + is true and FS happens to be '^'. Sheesh, talk about obscure. + (rebuild_record): Add more smarts to the code that sets up the + fields. Thanks to Alan J. Broder (ajb@dtmr.com). + +Sun Oct 5 11:56:52 1997 Arnold D. Robbins + + * configure.in: If ISC add -D_SYSV3 to CFLAGS, per email from + Mario Vanoni (vanonim@dial.eunet.ch). + +Fri Sep 26 00:57:49 1997 Arnold D. Robbins + + * awk.y (append_right): Return if either list is NULL. Prevents + syntax errors from causing core dumps. + +Wed Sep 17 15:34:15 1997 Arnold D. Robbins + + * field.c (rebuild_record): Set things up so that all fields point + into the new record and release any changed fields without + causing memory leaks. Avoids problems when fields are extended + with the value of $0 or other fields and then $0 is assigned to. + +Mon Sep 15 16:12:55 1997 Arnold D. Robbins + + * builtin.c (do_print): When testing for NUMBER, make sure + it's not a string too. Thanks to Michael Brennan for + clarifying the semantics. + +Sun Sep 14 19:55:12 1997 Arnold D. Robbins + + * node.c (format_val): Always format values ourselves: avoids + problems if OFMT is bizarre, like %s. + +Sun Sep 14 00:08:53 1997 Arnold D. Robbins + + * io.c (get_a_record): Replace all occurrences of the test + `grRS == FALSE' with `RS_is_null' which makes ` RS = "\0" ' + actually work, is clearer code, and actually makes use of + the `RS_is_null' variable! + +Sun Aug 17 07:15:12 1997 Arnold D. Robbins + + * field.c (set_FS): Change logic to always set parse_field, even + if FS hasn't changed. Thanks to Igor Sheyn for catching this. + +Wed Aug 6 21:04:37 1997 Arnold D. Robbins + + * io.c (VMS et al gawk_popen): Use pclose, not fclose, if + iop_alloc fails. + +Wed Jul 30 19:53:52 1997 Arnold D. Robbins + + * awk.y [variable]: Fix case for subscript if $3 == NULL. + +Sun Jul 27 22:47:30 1997 Arnold D. Robbins + + * awk.y (get_src_buf): Don't close file if it's stdin. + +Sun Jul 27 22:47:15 1997 Pat Rankin + + * io.c (#if VMS: vmsrtl_fileno): New routine. + (#if VMS: fileno): New macro substituted for stdio one. + +Thu Jul 17 20:05:59 1997 Arnold D. Robbins + + * builtin.c (do_print): When OFMT != CONVFMT, create a new + temporary node with just the numeric value valid and format it, + and use that for printing. Avoids memory corruption. + +Wed Jul 16 10:01:16 1997 Arnold D. Robbins + + * regex.c: When SYNTAX_TABLE is defined, but not emacs, then + CHAR_SET_SIZE is not defined, though used in regcomp. It should + be taken out of #ifdef SYNTAX_TABLE. Fix from bug group, from + Akim Demaille, demaille@inf.enst.fr. + * awk.h (isnondecimal): Make test a little smarter. + * builtin.c (nondec2awknum): Add bailout for decimal numbers, e.g. + `00.1'. Fix from Larry Schwimmer . + +Thu Jun 19 19:00:40 1997 Arnold D. Robbins + + * eval.c (interpret): case Node_K_next, Node_K_nextfile: fatal + error if called from BEGIN or END. + (Fixed completely Mon May 3 13:31:42 1999.) + +Mon Jun 9 22:40:04 1997 Arnold D. Robbins + + * builtin.c (nondec2awknum): Allow `f' and `F' in hexadecimal numbers. + Gotta get more sleep... + * array.c (assoc_lookup): Fix from Tom Karzes (karzes@equator.com) + for memory leak when forcing type to Node_var_array. + +Thu May 15 12:49:08 1997 Arnold D. Robbins + + * Release 3.0.3: Release tar file made. + +Wed May 14 08:06:08 1997 Arnold D. Robbins + + * io.c (do_close): Add lint warning if closing something that + isn't open. + +Tue May 13 12:14:12 1997 Arnold D. Robbins + + * random.c, builtin.c: Remove __GLIBC__ tests, since it breaks + `make test'. I prefer consistency across platforms. + * Makefile.in (gawk): Undid April 25 changes and added comment. + Putting COMPLAGS in breaks with -g on VMS POSIX. + +Sun May 11 14:48:04 1997 Darrell Hankerson + + * io.c [MSC_VER]: Add cases for WIN32. + * regex.c [MSC_VER]: Add cases for WIN32. + +Sun May 11 07:04:01 1997 Arnold D. Robbins + + * builtin.c (do_print): In the loop that evaluates each expression + to be printed, do a dupnode to avoid bizarre output. Thanks to + Michal for finding this problem. + * awk.y (yylex): Fix scanning of hexadecimal constants. + +Wed May 7 15:09:25 1997 Arnold D. Robbins + + * io.c (get_a_record): Fix casetable indexing with cast to int. + Keeps Michal happy. + +Tue May 6 16:40:19 1997 Arnold D. Robbins + + * eval.c (func_call): Removed unneeded variables. + +Mon May 5 21:17:37 1997 Pat Rankin + + * missing/strftime.c [case 'v', VMS_EXT]: For VMS date format, two + digit day of month should not be zero padded on the 1st through + the 9th. + +Mon May 5 06:33:47 1997 Arnold D. Robbins + + * regex.h, regex.c: Merge with current GLIBC version. + +Mon May 5 06:33:47 1997 Pat Rankin + + * io.c (nextfile): Move the check for null return from iop_open + in the normal case and add one for the "no args" case. + +Fri Apr 25 16:52:33 1997 Arnold D. Robbins + + * array.c (grow_table): Add a bunch more large primes so arrays + can get really big. Thanks to christos@deshaw.com. + * all files: Remove ifdef'ed out code and update copyrights. + * Makefile.in (gawk): Add $(COMPFLAGS) to command line. + * eval.c (flags2str): Added case for FIELD. + +Thu Apr 24 22:39:23 1997 Arnold D. Robbins + + * COPYING: Changed to current official version from FSF. + * regex.c: Merge with GLIBC version. + * awk.h [_GNU_SOURCE]: Bracket definition inside ifdef. + (NODE.source_line): Move name member out of `x' union and + into `nodep'; avoids problems doing diagnostics. + (nondec2num): Put decl into #if BITOPS || NONDECDATA + * posix/gawkmisc.c, missing/system.c, missing/strtod.c, + missing/strerror.c: Move to generic GPL statement at top. + * builtin.c (nondec2num): Put into #if BITOPS || NONDECDATA + +Wed Apr 23 22:14:14 1997 Arnold D. Robbins + + * dfa.c: Misc changes for really pedantic SGI compilers. + * builtin.c: Bracket defs of random() etc for GLIBC. + * random.c: Bracket whole file for GLIBC. + * configure.in: Extra goop for GETPGRP test for VMS POSIX. + * custom.h [VMS]: Remove hard definition of GETPGRP_VOID. + +Fri Apr 18 07:55:47 1997 Arnold D. Robbins + + * BETA Release 3.0.34: Release tar file made. + +Tue Apr 15 21:35:45 1997 Arnold D. Robbins + + NEW UNDOCUMENTED FEATURE. USE THE SOURCE LUKE! + * acconfig.h [NONDECDATA]: New macro. + * awk.h: Add decl of do_strtonum. + * awk.y (tokentab): Add entry for strtonum function. + * builtin.c (do_strtonum): New function. + * configure.in (non-decimal-data): New --enable-* option. + * node.c (r_force_number): Change to allow non-decimal data inside + ifdef NONDECDATA. + +Tue Apr 15 06:32:50 1997 Pat Rankin + + * missing/strftime.c (malloc, realloc, getenv, strchr): Only + declare these when STDC_HEADERS is not defined. + : Include these when STDC_HEADERS is defined. + * awk.h (freenode, tree_eval, m_tree_eval): Reorganize definitions. + * alloca.c (malloc): If malloc is already defined as a macro, + presumeably by config.h, don't define or declare it. + +Wed Apr 9 22:45:27 1997 Arnold D. Robbins + + * Makefile.in [COMPFLAGS]: Per suggestion from Karl Berry, put + $(CFLAGS) last. + +Tue Apr 8 23:54:46 1997 Arnold D. Robbins + + * eval.c (interpret): For Node_K_break and Node_K_continue, if + treating them like `next', also check the function call stack + and pop it if necessary. + +Mon Apr 7 18:22:37 1997 Arnold D. Robbins + + * awk.h: Add decls of new routines do_compl() and set_loc(). + * awk.y (tokentab): Add entry for "compl" function. + * builtin.c (do_compl): New function to do ones complement. + (do_substr): Rationalized yet again, now notices negative start + and length parameters. + * eval.c (push_args): Fix if call_list gets realloc'ed in the + middle of things. Avoids crash for deeply nested function calls. + * main.c (catch_sig): Add call to set_loc(). + * msg.c (set_loc, srcfile, srcline): New function and private + variables to help out in tracing down source of error messages. + +Fri Mar 28 08:42:27 1997 Arnold D. Robbins + + * io.c (iop_alloc, iop_close): Undo changes of Feb 11, apparently + other cleanups in io.c made mmap stuff start working again. + BAH! It's a mess, the test suite still fails. I'm leaving the + mmap stuff undefined for now. It'll probably get ripped out in 3.1. + +Thu Mar 27 08:48:57 1997 Arnold D. Robbins + + * custom.h [_SEQUENT_]: Undef HAVE_MMAP. + +Wed Mar 26 09:08:16 1997 Arnold D. Robbins + + * io.c (iop_alloc): Fix definition to make it static. + +Mon Mar 24 23:09:07 1997 Arnold D. Robbins + + * field.c (init_fields, etc..): More clean up use of Null_field + and the various flags. + * node.c (unref): If a field, free the node itself. Fixes + memory leak problems. + +Sun Mar 23 22:51:09 1997 Arnold D. Robbins + + * awk.h [FIELD]: New flag for node->flags field. + * builtin.c (sub_common): If FIELD is set, dup the string. + * field.c (init_fields): Set up a new Null_field global var. + (init_fields, set_field, set_record) use the FIELD flag. + (getfield): Use Null_field instead of private variable. + * io.c (wait_any): Comment out calls to pclose and iop_close, + caused weird race conditions. See test/pipeio1.awk. Thanks + to Darrell Hankerson for tracing this one down. + +Tue Mar 18 20:57:18 1997 Arnold D. Robbins + + * dfa.c (inboth): Free templist; plugs memory leak. + * field.c (init_fields, grow_fields_arr, set_field, rebuild_record, + set_record): Remove PERM flag from entries in fields_arr[]. Fixes + nasty memory leak. + +Tue Mar 18 06:33:00 1997 Arnold D. Robbins + + * awk.y (dup_parms): Robustified against parameter errors. + +Sun Mar 16 21:31:40 1997 Arnold D. Robbins + + NEW UNDOCUMENTED FEATURE. USE THE SOURCE LUKE! + * acconfig.h [BITOPS]: New macro. If set, do octal & hex and bit ops. + * awk.h [isnondecimal]: New macro, and decl of new functions. + * awk.y (yylex): Add recognition of octal and hex constants. + * builtin.c (do_and, do_or, do_xor, do_lshift, do_rshift): New + functions that do bit operations. + (nondec2awknum): New function to convert octal or hex to double. + * configure.in: Add AC_ARG_ENABLE for bit operations. + * node.c (r_force_number): Add octal and hex conversion. + +Sun Mar 16 21:28:56 1997 Arnold D. Robbins + + * awk.h [IOP_NOFREE_OBJ]: New macro. + * io.c (iop_open, iop_alloc): Add new third parameter, which is + either NULL, meaning allocate a new IOP, or the address of one + already allocated. Have a static one in the `nextfile' + routine, and use the IOP_NOFREE_OBJ flag for it. All of this + keeps us from reading freed memory. The `swaplns' test fails + otherwise. + (iop_close): If IOP_NOFREE_OBJ is set, don't free the IOBUF. + +Wed Feb 26 06:21:02 1997 Arnold D. Robbins + + * eval.c (in_function, pop_fcall_stack, pop_fcall, push_args): + New functions. These manage "frames" of awk function call arguments. + The problem is that a `next' or a `nextfile' from a function + leaks memory. These changes allow us to free up that memory. + (interpret): for Node_K_next and Node_K_nextfile, check if in + a function call and free all function call frames. + +Fri Feb 21 06:23:19 1997 Arnold D. Robbins + + Misc changes from Katsuyuki Okabe : + + * builtin.c (do_substr): Change a %d to %ld in warning message. + * eval.c (op_assign): Fix format string for warning about %=. + +Wed Feb 19 23:29:02 1997 Arnold D. Robbins + + * main.c (main): Add do_intervals to condition that causes + resetup() to be called again. Makes the --re-interval option + actually work. What a concept. + +Fri Feb 14 09:47:31 1997 Arnold D. Robbins + + * io.c [#include "awk.h"]: Undef HAVE_MMAP to just use the old code. + Something is causing a file descriptor leak, and this is getting to + be just too much hair. I reserve the right to rip out the mmap + code entirely at a future date. + +Tue Feb 11 06:28:29 1997 Arnold D. Robbins + + * io.c (iop_alloc): For an mmap'ed file, close the file descriptor, + and then touch each page to get a private copy. Fixes nasty case + of truncating our input file. + (iop_close): Don't call close on mmap'ed file. + +Wed Feb 5 17:59:04 1997 Arnold D. Robbins + + * eval.c (interpret): For Node_K_delete, just call do_delete; let + it handle the case of `delete array'. + * array.c (do_delete): Changed to handle case of `delete array', + and made smarter if the array is actually an uninitialized + parameter. + +Sun Jan 26 22:58:29 1997 Arnold D. Robbins + + * getopt.h, getopt.c, getopt1.c: Replaced with new versions from + GLIBC 2. + +Sun Jan 19 23:37:03 1997 Arnold D. Robbins + + * eval.c (nodetype2str): Not static, for debugging. + (flags2str): New function for debugging. + * field.c (get_field): Add new var that is like Nnull_string but + does not have numeric attributes, so that new fields are strings. + (set_record): Turn off PERM flag before unrefing fields and field 0. + * array.c (in_array): Always evaluate subscript, could have + side effects. + * builtin.c (do_strftime): Way increase size of buffer to make sure + we don't have overflow problem. Keeps Paul Eggert happy. + * custom.h [__amigaos__]: Define fork to vfork. From Fred Fish. + * dfa.c: Move include of config.h to top, for RSXNT. From Kai + Uwe Rommel. + (ISALPHA, etc): Change from Jacob Engelbrecht (jaen@novo.dk) + to better handle non-ASCII environments. + * gawkmisc.c: Remove amigados case, posix should now work fine. + * amiga/*: Nuked per previous entry. + * Makefile.in: Removed all references to amiga + * io.c [HAVE_SYS_PARAM_H]: Add #undef RE_DUP_MAX to avoid + spurious conflict with regex.h. + (flush_io): Remove amiga ifdefs, not needed anymore. + (spec_setup): Set getrec field for special files. Fix from + Mark Gray (markgray@pdt.net). + * node.c (more_nodes): Fix to get the last entry in the array. + +Wed Jan 8 17:42:37 1997 Andreas Schwab + + * io.c (mmap_get_record): Fix return value if file ends without + record separator. + +Fri Jan 3 19:57:16 1997 Pat Rankin + + * awk.y (get_src_buf): Test for an empty source file by detecting + an initial read of 0 bytes rather than by relying on info from + stat(). + +Wed Dec 25 11:25:22 1996 Arnold D. Robbins + + * Release 3.0.2: Release tar file made. + +Wed Dec 25 11:17:32 1996 Arnold D. Robbins + + * Makefile.in (install, uninstall): Use $(srcdir)/patchlevel.h. + Thanks to Richard Levitte, LeViMS@stacken.kth.se. + (install): Remove chmod command; let $(INSTALL_PROGRAM) use -m. + +Mon Dec 23 20:36:59 1996 Pat Rankin + + * custom.h (#if VMS_POSIX): Define GETPGRP_VOID. + +Fri Dec 20 08:59:55 1996 Arnold D. Robbins + + * getopt.c, getopt1.c: Comment out the `#if defined (_LIBC) || + !defined (__GNU_LIBRARY__)' and `#endif' to force use of this + getopt, even on systems like Linux. This will be handled + better in 3.1 / glibc 2. + +Thu Dec 19 22:52:39 1996 Arnold D. Robbins + + * awk.y (yylex): In several places, after yyerror(), add call to + exit(). Otherwise, infinite messages. This should probably + be handled better. + +Wed Dec 18 22:42:10 1996 Darrel Hankerson + + * getopt.c (_getopt_internal): If 'W' and ';', if optind == argc, + return c, don't fall through. + +Wed Dec 18 10:09:44 1996 Arnold D. Robbins + + * configure.in [AC_PREREQ]: Update to 2.12 in order to switch to + autoconf 2.12. Lots of other files will be rebuilt automatically. + [AM_SANITY_CHECK_CC]: Removed, autoconf does it now. + * aclocal.m4 [AM_SANITY_CHECK_CC]: Removed, autoconf does it now. + +Tue Dec 17 22:23:16 1996 Arnold D. Robbins + + * builtin.c (do_strftime): Fix case if format string is "". + Also fix it if format is not "" but result of strftime is "". + See comments in code. + +Tue Dec 10 23:09:26 1996 Arnold D. Robbins + + * Release 3.0.1: Release tar file made. + +Tue Dec 10 22:39:41 1996 Arnold D. Robbins + + * Makefile.in (dist): Add dependency on `info'. Remove line that + does makeinfo. + (install): Use $(LN) not $(LN_S) to link gawk gawk-version. + +Sun Dec 8 07:53:44 1996 Arnold D. Robbins + + * Makefile.in (gawk): Took COMPFLAGS out of link line for help + on VMS posix. Shouldn't (I hope) affect anything else. + +Thu Nov 28 11:52:24 1996 Arnold D. Robbins + + * configure.in (AC_PROG_INSTALL): Set INSTALL to install-sh. + +Tue Nov 26 22:42:00 1996 Arnold D. Robbins + + * PORTS: Updated list of systems. + * Makefile.in (install): Fix some typos and add some improvements + for Ultrix. + +Sun Nov 24 22:16:26 1996 Arnold D. Robbins + + * builtin.c (do_printf): If no args, fatal error. Return silently + if --traditional. + +Thu Nov 7 20:54:43 1996 Arnold D. Robbins + + * io.c (inrec): Make sure EOF hasn't already happened before + trying to read; prevents accessing freed buffer. Thanks to + Michal Jaegermann. + * Makefile.in [AWKSRC]: Add random.h. + * random.h: New file, redefines names of the `random' functions. + * random.c, builtin.c: Add include of random.h. + +Thu Nov 7 09:06:21 1996 Arnold D. Robbins + + * awk.y (snode): Undo 4 Oct change, put do_split code back. + * field.c (do_split): Restore old code; add test for CONST, so + that re_parse_field is used if third arg to split is a regexp + constant. + +Mon Nov 4 12:57:11 1996 Arnold D. Robbins + + * main.c (main): Research -m[fr] options don't need literal '=' + characters. Brian's documentation was confusing. Fixed, not + that anyone actually uses these options with gawk. + +Sun Nov 3 11:23:21 1996 Arnold D. Robbins + + * field.c (def_parse_field): Add \n to list of acceptable white space. + (posix_def_parse_field): New routine, just like def_parse_field(), + but only allows space and tab as separators. + (do_split, set_FS): Make appropriate choice between the two + *def_parse_field() routines. + +Fri Oct 25 10:13:06 1996 Arnold D. Robbins + + * configure.in: Remove test for random. + * Makefile.in: Add random.c to list of files always compiled. + * missing.c: Remove HAVE_RANDOM test. + * builtin.c: Remove ifdef's for HAVE_RANDOM. + [GAWK_RAND_MAX]: Use constant we know works with our random(). + * random.c: New file - moved from missing/ directory. + +Wed Oct 23 19:46:01 1996 Pat Rankin + + * builtin.c (do_tolower, do_toupper): Add `unsigned char *' casts. + +Tue Oct 22 21:27:52 1996 Arnold D. Robbins + + * builtin.c [GAWK_RANDOM_MAX]: Try to make definition a bit + smarter; don't use RAND_MAX if it's equal to SHRT_MAX, blows + things up. + +Tue Oct 22 08:49:20 1996 Arnold D. Robbins + + * main.c (copyleft): Update copyright date to 1996. + * Too many files to list: Update copyright date to 1996. + +Sun Oct 20 12:21:09 1996 Arnold D. Robbins + + * awk.y, dfa.c, eval.c, io.c, re.c: Added various FIXME comments. + +Sat Oct 19 22:06:42 1996 Arnold D. Robbins + + * eval.c (nodetype2str): Make static, add prototype. + * field.c (sc_parse_field): Cast array subscripts to int to + shut up gcc warnings. + * gawkmisc.c: Add prototype for xmalloc. + * awk.h: Add prototype for getredirect. + * builtin.c (do_fflush): Remove extern decl of getredirect. + * io.c (get_a_record, mmap_get_record): Change decl of rs to int, + to shut up gcc warnings. + * awk.y (isassignable): Add a default to switch to quiet gcc. + * getopt.c (_getopt_internal): Give default value to `indfound'. + +Fri Oct 18 09:00:49 1996 Arnold D. Robbins + + * regex.h [RE_SYNTAX_AWK]: Add RE_CONTEXT_INDEP_ANCHORS. + +Thu Oct 17 22:32:55 1996 Arnold D. Robbins + + * aclocal.m4 [AM_SANITY_CHECK_CC]: Added. + * configure.in: Use it. + +Thu Oct 17 21:43:25 1996 Arnold D. Robbins + + * configure.in: Add checks for locale.h and setlocale(). + * awk.h: Include locale.h and define out setlocale() if not available. + * main.c (main): Call setlocale(). + * builtin.c (do_tolower, do_toupper): Use unsigned char pointers, + to get other charsets right in different locales. + +Wed Oct 16 21:32:53 1996 Arnold D. Robbins + + * builtin.c (format_tree): Change initial buffer size to 512 + and use a constant. Allows large values of %f per bug report + from sheyn@cs.bu.edu. + +Wed Oct 16 21:22:08 1996 Arnold D. Robbins + + * Makefile.in [MISC]: Removed TAGS and tags. + (local-distclean): Added TAGS and tags. + (maintainer-clean): Removed TAGS and tags. + +Wed Oct 16 12:28:43 1996 Arnold D. Robbins + + * main.c (version): Add call to copyleft(), per new standards. + version.c: Fix text of version string to match new standards. + +Sun Oct 6 22:19:45 1996 Arnold D. Robbins + + * regex.c: Updated to Emacs 19.34b base. + +Sun Oct 6 21:57:34 1996 Arnold D. Robbins + + * re.c (make_regexp): Fixed to handle \8 and \9 in the middle + of a regexp. + +Fri Oct 4 10:26:16 1996 Arnold D. Robbins + + * awk.y (snode): Remove case for do_split; always making the + third arg a Node_regex is wrong. + * field.c (do_split): Rationalized to distinguish `/ /' from `" "'. + Generally fixed up. + * node.c (parse_escape): Allow single digit \x escapes. + +1996-10-02 Paul Eggert + + * builtin.c (format_tree): Fix bug in %d and %i format: NaNs, and + values in the range LONG_MAX+1 .. ULONG_MAX, were mishandled. + Don't assume that double values <= -1 are converted to unsigned + long in the expected way; the C Standard doesn't guarantee this. + +1996-10-02 Paul Eggert + + * awk.h (INT_MAX): Remove unused symbol. + +Mon Sep 30 22:19:11 1996 Arnold D. Robbins + + * getopt.c (_getopt_internal): If 'W' is in the optstring followed + by a ';' then search through the long opts table. This makes + `-W foo=bar' same as `--foo=bar'. + * main.c (main): 'W' now prints an error message. + (gawk_option): Deleted the routine. + +Sun Sep 29 23:04:54 1996 Arnold D. Robbins + + * builtin.c (sub_common): Fix several bugs with gsub when + matching null strings. See test/gsubtest.awk. + +Fri Sep 20 17:35:54 1996 Pat Rankin + + * alloca.c (NULL): Don't define if has already done so. + +Fri Sep 20 11:54:31 1996 Arnold D. Robbins + + * builtin.c (do_print): Evaluate all the expressions first and + then print them. Avoids surprising behavior. See test/prtoeval.awk + for an example. + +Tue Sep 10 06:21:40 1996 Arnold D. Robbins + + * awk.h [FUNC]: New flag, marks a Node_parameter_list as really + being the function name; allows more checking in awk.y. + * awk.y (isassignable): Now takes a NODE * instead of a type, to + check if a function parameter is marked FUNC, then it's the function + name, which is not assignable. Fix call from snode(). + (function_prologue): Mark function name as FUNC. + (yyerror): Don't call exit() anymore; gawk will now report + all syntax errors. + +Sun Sep 1 19:36:30 1996 Arnold D. Robbins + + * field.c (rebuild_record): After building new field 0, go through + all old fields, and if they used to point into the old one, + have them point into the new one. Then turn off PERM flag before + unref-ing field 0. + +Wed Aug 28 19:13:34 1996 Arnold D. Robbins + + * eval.c (set_IGNORECASE): Correctly parenthesize bit operations + in test and fix logic for string value. + +Wed Aug 28 22:06:33 1996 Arnold D. Robbins + + * main.c (usage): Add email addresses for bug reporting, per + change in GNU Coding Standards from RMS. + +Sun Aug 11 23:13:22 1996 Arnold D. Robbins + + * Makefile.in (install): Correct use of $(INSTALL_PROGRAM). + +Thu Aug 8 23:29:43 1996 Arnold D. Robbins + + * parse.y (isassignable): New function, checks in type can + be assigned to. + (snode): Changed checking for 3rd arg of gsub to be more + general, supersedes earlier change. + +Thu Aug 8 13:58:26 1996 Arnold D. Robbins + + * parse.y (snode): If third arg to sub or gsub is builtin + function, complain, since can't substitute into result. + * eval.c (r_get_lhs): Diagnose Node_builtin as an error, instead + of falling through into default case and using cant_happen(). + +Thu Aug 1 07:13:14 1996 Arnold D. Robbins + + * regex.h [RE_DEBUG]: New macro. + [RE_SYNTAX_GNU_AWK]: Add RE_DEBUG. + [RE_SYNTAX_POSIX_AWK]: Add RE_INTERVALS. + * regex.c (re_set_syntax): Add #ifdef DEBUG code to turn on `debug' + flag if RE_DEBUG set, and turn off debug if not set and debug + was on. + * main.c (main): Remove `do_intervals = TRUE' from `if (do_posix)', + it's now handled in the definition of RE_SYNTAX_POSIX_AWK. + +Mon Jul 29 17:49:07 1996 Pat Rankin + + * io.c (O_ACCMODE): Define it if doesn't. + +Mon Jul 29 12:02:48 1996 Arnold D. Robbins + + * eval.c (set_IGNORECASE): Made somewhat smarter. gawk -v IGNORECASE=0 + was acting the same as -v IGNORECASE=1. Thanks to Darrell Hankerson + for the bug report. + +Fri Jul 26 12:04:43 1996 Arnold D. Robbins + + * awk.h (format_val): Add declaration of new routine. + * node.c (format_val): New routine, abstracts old guts of + r_forcestring; accepts format string and index as additional params. + (r_force_string): Changed to call format_val. + * builtin.c (do_print): Don't tree_eval the tree twice in case + OFMTidx != CONVFMTidx; doing so could cause side effects + (from bug report by Tobias Rettstadt, xassp@ipds.uni-kiel.de). + Instead, call format_val. + +Mon Jul 22 21:59:15 1996 Arnold D. Robbins + + * io.c (iop_close): Change check for "is $0 in the input buffer" + to use `< (iop->buf + iop->secsiz + iop->size)' instead of + `< iop->end'. The latter is bogus if EOF has been hit on the + file. Fix from Darrel Hankerson based on bug report by + Charles Howes (howes@grid.direct.ca). See test/eofsplit.awk. + +Thu Jul 18 19:43:20 1996 Arnold D. Robbins + + * builtin.c (sub_common): Backed out change of Feb 14 in favor of: + (do_gensub): Changed to use make_string and then to |= TEMP + flag, based on bug report and patch from Katsuyuki Okabe, + hgc02147@niftyserve.or.jp. + +Thu Jul 18 19:23:53 1996 Arnold D. Robbins + + * custom.h: Added ifdef for QNX, based on bug report from + Michael Hunter, mphunter@qnx.com. + +Mon Jul 15 09:31:01 1996 Arnold D. Robbins + + * io.c (redirect): When finding the rp pointer, if it's not + NULL, set str = rp->value. This gets the '\0' terminated + version. Motivated by bug report from John Hawkinson + (jhawk@bbnplanet.com). + +Sun Jul 14 18:40:26 1996 Arnold D. Robbins + + * configure.in: Added call to AC_CHECK_LIB(m, fmod), since + apparently some systems have fmod in the math library. + Portability: The Holy Grail. Sigh. + +Sun Jul 14 18:08:01 1996 Arnold D. Robbins + + * awk.h: Add Jim Meyerings ISASCII etc hacks for ctype macros. + * builtin.c (do_toupper, do_tolower, sub_common): Changed to use + upper-case versions of ctype macros. + * main.c (main): Ditto. + * node.c (r_force_number, parse_escape): Ditto. + +Sun Jul 14 06:34:18 1996 Arnold D. Robbins + + * field.c (set_record): Made it always do the PERM flag. + Fixes cases where $0 is assigned to, e.g. by gsub, keeps + the fields valid. + (get_field): Removed the call to reset_record in + case where ! field0_valid. We want to leave the fields alone + if they've been changed. + +Thu Jul 11 23:04:20 1996 Arnold D. Robbins + + * io.c (devopen): Change tests of (flag & O_fooONLY) to + (flag & O_ACCMODE) == O_fooONLY. Per (long standing) bug + report from Chapman Flack. + (close_redir): Change final conditional to just (status != 0) + so that ERRNO always set; the warning had its own `if (do_lint)' + anyway. + * eval.c (do_split): Force type of array to be Node_var_array + instead of Node_var. Per (long standing) bug report from + Chapman Flack. + +Thu Jul 11 22:17:14 1996 Arnold D. Robbins + + * Makefile.in (install): Added symlink of gawk to awk if + no awk in $(bindir). + (LN_S): New variable for symlinking. + (uninstall): Remove awk if it's the same gawk. + * Configure.in: Added call to AC_PROG_LN_S for Makefile.in. + +Sun Jul 7 15:47:13 1996 Arnold D. Robbins + + * main.c (main): Made `--posix' turn on interval expressions. + Gawk now matches its documentation. (What a concept!) + +Wed Jul 3 15:02:48 1996 Arnold D. Robbins + + * regex.h, regex.c: Upgraded to changes from Emacs 19.31. + +Fri May 17 08:46:07 1996 Arnold D. Robbins + + * io.c (get_a_record): Added `continued' flag. Fix from + Darrell Hankerson for when RS = "\n|something". + +Wed May 15 02:34:55 1996 Arnold D. Robbins + + * Makefile.in (awklib/all): Now depends on gawk, fixes problem + with parallel make. + +Tue May 14 15:02:52 1996 Arnold D. Robbins + + * builtin.c (format_tree): Fix handling of '*' to deal with + negative value for fieldwidth -- make positive and turn on + left justify. Per bug report from Michael Brennan. + +Sun May 12 20:42:06 1996 Arnold D. Robbins + + * eval.c (r_get_lhs): case Node_subscript. Check if array name + is actually a function, fatal error if so. + +Sun May 5 10:11:52 1996 Arnold D. Robbins + + * io.c (redirect): Call flush_io() before creating a new output pipe, + per bug report from Brian Kernighan (bwk@research.bell-labs.com). + +Fri Mar 15 06:38:33 1996 Arnold D. Robbins + + * Makefile.in (install): Use $(INSTALL_PROGRAM), not $(INSTALL). + (local-distclean): Add `*~' to list of files to be removed. + (CFLAGS): Now contains just @CFLAGS@. + (COMPFLAGS): Replaces use of CFLAGS, has CFLAGS plus all the + other stuff. + +Wed Mar 13 14:19:38 1996 Arnold D. Robbins + + * io.c (mmap_get_record): Fixed to not place sentinel at end + of mmap'ed object. Won't work if file is exact multiple of + disk block size. See comments in code for more info. + Thanks to Rick Adams (rick@uunet.uu.net) for help in testing. + +Sun Mar 10 22:50:23 1996 Arnold D. Robbins + + * io.c (do_close): Notice if we were called as `close(FILENAME)' + and arrange to close the current input file. This turns out + to be easy to do, just call `nextfile(TRUE)'. Based on bug report + from Pascal A. Dupuis, . + +Thu Mar 7 08:08:51 1996 Arnold D. Robbins + + * field.c (init_fields, grow_fields, set_field, rebuild_record): + Nuke the `nodes' array everywhere. Anytime a field is unref'ed, + allocate a new node that is a copy of Nnull_string. This avoids + subtle memory management problems when doing a lot of assignment + to fields, and tweaking of NF. Make sure that fields_arr[0] always + has a type of Node_val! + * field.c (set_NF): If NF is decremented, clear fields between + NF and parse_high_water, otherwise if NF incremented, clear + fields between parse_high_water and NF. + * eval.c (nodetype2str): New function, used for diagnostics. + (interpret): Use nodetype2str when finding invalid node. + +Mon Mar 4 09:02:28 1996 Arnold D. Robbins + + * builtin.c (do_toupper, do_tolower): Use isascii along with + isupper/islower before changing case, in case characters have + the high bit set. This is a hack. + +Mon Feb 26 22:24:44 1996 Arnold D. Robbins + + * builtin.c (sub_common): If no match, and called from gensub, + don't free the temporary string, since the tmp_number then + writes over it. + +Sun Feb 25 23:13:01 1996 Arnold D. Robbins + + * builtin.c (format_tree): Fixed %c to treat user input as + numeric also by adding test for MAYBE_NUM. + +Tue Feb 20 12:25:50 1996 Arnold D. Robbins + + * configure.in: Added AC_FUNC_MMAP call and add madvise to + list of functions to look for. + * awk.h [IOP_ISMAPPED]: New flag value for mmap support and new + `getrec' structure member in struct iobuf. + * io.c (iop_alloc, iop_close): Changed to map/unmap input file + into memory if possible. + (mmap_get_record): New function to actually retrieve the + record from mmaped file. + +Thu Feb 1 08:56:46 1996 Arnold D. Robbins + + * builtin.c (do_substr): Fixed lint message to use indx+1 when + start position is past end of string. + +Sun Jan 28 07:00:56 1996 Arnold D. Robbins + + * builtin.c (do_substr): Rationalized handling of missing length + argument, as well as various accompanying lint warnings. Previous + code was slightly bogus. Talk about your Day 1 bugs. + +Thu Jan 25 14:09:11 1996 Arnold D. Robbins + + * builtin.c (do_substr): If length exceeds length of actual + string, do computation of needed substring length *after* + the lint warning. + +Wed Jan 24 10:06:16 1996 Arnold D. Robbins + + * Makefile.in (gawk): Add $(CFLAGS) to link line. + (Makefile): Target depends on the Makefile.in files. + (OTHERS): Added TAGS and tags to the distribution. + (local-distclean): New rule. + (distclean): Use it. + (maintainer-clean): Don't `make distclean' before running submakes, + since that removes makefiles needed for the submakes. + * builtin.c (do_strftime): Remove hard coded limit on length of result. + Based on code from Paul Eggert (eggert@twinsun.com). + +Mon Jan 22 13:16:37 1996 Arnold D. Robbins + + * main.c (usage): Takes new fp parameter which is either + stdout for `--help' (per the GNU Coding Standards) or stderr + if an error occurs. Fix all calls. + (version): Prints to stdout per the coding stds. + (copyleft): Prints to stdout now, not stderr, and exits. + +Fri Jan 19 08:10:29 1996 Arnold D. Robbins + + * regex.h [RE_GNU_AWK]: Added RE_CONTEXT_INDEP_OPS to set of + bits we turn off for regular operation. Breaks things like + /^+[0-9]+/ to match a literal `+' at the beginning of, say, + a phone number. + +Wed Jan 10 23:19:36 1996 Arnold D. Robbins + + * 3.0.0 polished up and release tar file made. + +Wed Dec 27 11:46:16 1995 Arnold D. Robbins + + * 2.94.0 released to porting group (no, I haven't been good + about this file; I'll do better once 3.0 is released). + +Mon Aug 28 23:04:30 1995 Arnold D. Robbins + + * awk.h updated for NeXT - bracket TRUE/FALSE + * io.c (get_a_record): Removed shadowing of 'start' in + * Makefile.in and doc/Makefile.in: Fixed to use gawk.1 and gawk.texi, + instead of gawk.1.in and gawk.texi.in. + +Mon Aug 25 11:04:30 1995 Arnold D. Robbins + + * 2.90.0 released to porting group. + +Fri Aug 18 12:43:31 1995 Arnold D. Robbins + + * ChangeLog created. diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..2099840 --- /dev/null +++ b/INSTALL @@ -0,0 +1,370 @@ +Installation Instructions +************************* + +Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation, +Inc. + + Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. This file is offered as-is, +without warranty of any kind. + +Basic Installation +================== + + Briefly, the shell command `./configure && make && make install' +should configure, build, and install this package. The following +more-detailed instructions are generic; see the `README' file for +instructions specific to this package. Some packages provide this +`INSTALL' file but do not implement all of the features documented +below. The lack of an optional feature in a given package is not +necessarily a bug. More recommendations for GNU packages can be found +in *note Makefile Conventions: (standards)Makefile Conventions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. Caching is +disabled by default to prevent problems with accidental use of stale +cache files. + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You need `configure.ac' if +you want to change it or regenerate `configure' using a newer version +of `autoconf'. + + The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. + + Running `configure' might take a while. While running, it prints + some messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package, generally using the just-built uninstalled binaries. + + 4. Type `make install' to install the programs and any data files and + documentation. When installing into a prefix owned by root, it is + recommended that the package be configured and built as a regular + user, and only the `make install' phase executed with root + privileges. + + 5. Optionally, type `make installcheck' to repeat any self-tests, but + this time using the binaries in their final installed location. + This target does not install anything. Running this target as a + regular user, particularly if the prior `make install' required + root privileges, verifies that the installation completed + correctly. + + 6. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + + 7. Often, you can also type `make uninstall' to remove the installed + files again. In practice, not all packages have tested that + uninstallation works correctly, even though it is required by the + GNU Coding Standards. + + 8. Some packages, particularly those that use Automake, provide `make + distcheck', which can by used by developers to test that all other + targets like `make install' and `make uninstall' work correctly. + This target is generally not run by end users. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. Run `./configure --help' +for details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c99 CFLAGS=-g LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you can use GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. This +is known as a "VPATH" build. + + With a non-GNU `make', it is safer to compile the package for one +architecture at a time in the source code directory. After you have +installed the package for one architecture, use `make distclean' before +reconfiguring for another architecture. + + On MacOS X 10.5 and later systems, you can create libraries and +executables that work on multiple system types--known as "fat" or +"universal" binaries--by specifying multiple `-arch' options to the +compiler but only a single `-arch' option to the preprocessor. Like +this: + + ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CPP="gcc -E" CXXCPP="g++ -E" + + This is not guaranteed to produce working output in all cases, you +may have to build one architecture at a time and combine the results +using the `lipo' tool if you have problems. + +Installation Names +================== + + By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX', where PREFIX must be an +absolute file name. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. In general, the +default for these options is expressed in terms of `${prefix}', so that +specifying just `--prefix' will affect all of the other directory +specifications that were not explicitly provided. + + The most portable way to affect installation locations is to pass the +correct locations to `configure'; however, many packages provide one or +both of the following shortcuts of passing variable assignments to the +`make install' command line to change installation locations without +having to reconfigure or recompile. + + The first method involves providing an override variable for each +affected directory. For example, `make install +prefix=/alternate/directory' will choose an alternate location for all +directory configuration variables that were expressed in terms of +`${prefix}'. Any directories that were specified during `configure', +but not in terms of `${prefix}', must each be overridden at install +time for the entire installation to be relocated. The approach of +makefile variable overrides for each directory variable is required by +the GNU Coding Standards, and ideally causes no recompilation. +However, some platforms have known limitations with the semantics of +shared libraries that end up requiring recompilation when using this +method, particularly noticeable in packages that use GNU Libtool. + + The second method involves providing the `DESTDIR' variable. For +example, `make install DESTDIR=/alternate/directory' will prepend +`/alternate/directory' before all installation names. The approach of +`DESTDIR' overrides is not required by the GNU Coding Standards, and +does not work on platforms that have drive letters. On the other hand, +it does better at avoiding recompilation issues, and works well even +when some directory options were not specified in terms of `${prefix}' +at `configure' time. + +Optional Features +================= + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + + Some packages offer the ability to configure how verbose the +execution of `make' will be. For these packages, running `./configure +--enable-silent-rules' sets the default to minimal output, which can be +overridden with `make V=1'; while running `./configure +--disable-silent-rules' sets the default to verbose, which can be +overridden with `make V=0'. + +Particular systems +================== + + On HP-UX, the default C compiler is not ANSI C compatible. If GNU +CC is not installed, it is recommended to use the following options in +order to use an ANSI C compiler: + + ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" + +and if that doesn't work, install pre-built binaries of GCC for HP-UX. + + HP-UX `make' updates targets which have the same time stamps as +their prerequisites, which makes it generally unusable when shipped +generated files such as `configure' are involved. Use GNU `make' +instead. + + On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot +parse its `' header file. The option `-nodtk' can be used as +a workaround. If GNU CC is not installed, it is therefore recommended +to try + + ./configure CC="cc" + +and if that doesn't work, try + + ./configure CC="cc -nodtk" + + On Solaris, don't put `/usr/ucb' early in your `PATH'. This +directory contains several dysfunctional programs; working variants of +these programs are available in `/usr/bin'. So, if you need `/usr/ucb' +in your `PATH', put it _after_ `/usr/bin'. + + On Haiku, software installed for all users goes in `/boot/common', +not `/usr/local'. It is recommended to use the following options: + + ./configure --prefix=/boot/common + +Specifying the System Type +========================== + + There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS + KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + + Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). + +Unfortunately, this technique does not work for `CONFIG_SHELL' due to +an Autoconf limitation. Until the limitation is lifted, you can use +this workaround: + + CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash + +`configure' Invocation +====================== + + `configure' recognizes the following options to control how it +operates. + +`--help' +`-h' + Print a summary of all of the options to `configure', and exit. + +`--help=short' +`--help=recursive' + Print a summary of the options unique to this package's + `configure', and exit. The `short' variant lists options used + only in the top level, while the `recursive' variant lists options + also present in any nested packages. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--prefix=DIR' + Use DIR as the installation prefix. *note Installation Names:: + for more details, including other options available for fine-tuning + the installation locations. + +`--no-create' +`-n' + Run the configure checks, but stop before creating any output + files. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. diff --git a/LICENSE.BSD b/LICENSE.BSD new file mode 100644 index 0000000..b111f1f --- /dev/null +++ b/LICENSE.BSD @@ -0,0 +1,25 @@ +Copyright (c) 1983, 1993 + The Regents of the University of California. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/LICENSE.GPLv2 b/LICENSE.GPLv2 new file mode 100644 index 0000000..d159169 --- /dev/null +++ b/LICENSE.GPLv2 @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 2 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, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/LICENSE.LGPLv2 b/LICENSE.LGPLv2 new file mode 100644 index 0000000..4362b49 --- /dev/null +++ b/LICENSE.LGPLv2 @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library 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 library 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..0089b86 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,212 @@ +# +# 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 variable insures that aclocal runs +# correctly after changing configure.ac +ACLOCAL_AMFLAGS = -I m4 + +# 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 = \ + ChangeLog.0 \ + COPYING \ + INSTALL \ + NEWS \ + NEWS.0 \ + POSIX.STD \ + README_d \ + config.guess \ + config.rpath \ + config.sub \ + depcomp \ + m4 \ + missing \ + missing_d \ + po/README \ + pc \ + posix \ + 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. +if ENABLE_EXTENSIONS +SUBDIRS += extension +endif + +# 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 +include_HEADERS = gawkapi.h + +# sources for both gawk and dgawk +base_sources = \ + array.c \ + awk.h \ + awkgram.y \ + builtin.c \ + cint_array.c \ + cmd.h \ + command.y \ + custom.h \ + debug.c \ + eval.c \ + ext.c \ + field.c \ + floatcomp.c \ + floatmagic.h \ + gawkapi.c \ + gawkapi.h \ + gawkmisc.c \ + gettext.h \ + int_array.c \ + interpret.h \ + io.c \ + mbsupport.h \ + main.c \ + mpfr.c \ + msg.c \ + node.c \ + nonposix.h \ + profile.c \ + protos.h \ + re.c \ + replace.c \ + str_array.c \ + symbol.c \ + version.c + +gawk_SOURCES = $(base_sources) + +# Get extra libs as needed, Automake will supply LIBINTL and SOCKET_LIBS. +LDADD = support/libsupport.a \ + $(LIBSIGSEGV) $(LIBINTL) $(SOCKET_LIBS) $(LIBREADLINE) $(LIBMPFR) + +# Directory for gawk's data files. Automake supplies datadir. +pkgdatadir = $(datadir)/awk + +# stuff for compiling gawk/pgawk +DEFPATH='".$(PATH_SEPARATOR)$(pkgdatadir)"' + +# shared library support: +SHLIBEXT = "\"$(GAWKLIBEXT)"\" +DEFLIBPATH="\"$(pkgextensiondir)\"" + +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.* + +# We want hard links for install-exec-hook, below +LN= ln + +# For some make's, e.g. OpenBSD, that don't define this +RM = rm -f + +# First, add a link from gawk to gawk-X.Y.Z. +# +# For GNU systems where gawk is awk, add a link to awk. +# (This is done universally, which may not always be right, but +# there's no easy way to distinguish GNU from non-GNU systems.) +# +# Use the transform, in case --program-prefix=XXX +install-exec-hook: + (cd $(DESTDIR)$(bindir); \ + name=`echo gawk | sed '$(transform)'` ; \ + $(LN) $${name}$(EXEEXT) gawk-$(VERSION)$(EXEEXT) 2>/dev/null ; \ + if [ ! -f awk$(EXEEXT) ]; \ + then $(LN_S) $${name}$(EXEEXT) awk$(EXEEXT); \ + fi; exit 0) + +# Undo the above when uninstalling +uninstall-links: + (cd $(DESTDIR)$(bindir); \ + name=`echo gawk | sed '$(transform)'` ; \ + if [ -f awk$(EXEEXT) ] && cmp awk$(EXEEXT) $${name}$(EXEEXT) > /dev/null; then rm -f awk$(EXEEXT); fi ; \ + rm -f gawk-$(VERSION)$(EXEEXT); exit 0) + +uninstall-recursive: uninstall-links + +# force there to be a gawk executable before running tests +check-local: gawk$(EXEEXT) + +# A little extra clean up when making distributions. +# And additional set up for the pc directory. +dist-hook: + cd "$(distdir)"/extension ; rm -f *.o *.so + cd "$(srcdir)"/pc ; \ + chmod u+w config.h ; \ + sed -n -f configpk.sed < ../configure.ac > /tmp/tmp.sed ; \ + sed -f config.sed < ../configh.in > /tmp/config.tmp ; \ + sed -f /tmp/tmp.sed < /tmp/config.tmp > config.h ; \ + $(RM) /tmp/tmp.sed /tmp/config.tmp + pwd + chmod u+w "$(distdir)"/pc/config.h + cp "$(srcdir)"/pc/config.h "$(distdir)"/pc/config.h + +# Special rules for individual files + +awkgram.c: awkgram.y + $(YACC) -o $@ $(AM_YFLAGS) $(YFLAGS) $< + sed 's/parse error/syntax error/g' < $@ > $@.tmp && mv $@.tmp $@ + +command.c: command.y + $(YACC) -o $@ -p zz $< + sed 's/parse error/syntax error/g' < $@ > $@.tmp && mv $@.tmp $@ + +# This is for my development & testing. +efence: gawk + $(CC) $(LDFLAGS) -o gawk $$(ls *.o | grep -v '_p.o$$') $(LDADD) $(LIBS) -lefence + +diffout valgrind-scan: + @cd test && $(MAKE) $(AM_MAKEFLAGS) $@ + +valgrind: + cd test; rm -f log.[0-9]*; \ + make check VALGRIND="valgrind --leak-check=full --log-file=log.%p"; \ + make valgrind-scan + +valgrind-noleak: + cd test; rm -f log.[0-9]*; \ + make check VALGRIND="valgrind --leak-check=no --log-file=log.%p"; \ + make valgrind-scan + +spell: + cd "$(srcdir)"/doc ; $(MAKE) spell diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..ade9835 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,1226 @@ +# 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)) +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@ + +# 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 = . +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 $(top_srcdir)/configure \ + $(am__configure_deps) $(include_HEADERS) $(am__DIST_COMMON) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno config.status.lineno +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +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) \ + eval.$(OBJEXT) ext.$(OBJEXT) field.$(OBJEXT) \ + floatcomp.$(OBJEXT) gawkapi.$(OBJEXT) gawkmisc.$(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 = support/libsupport.a $(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 +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@ +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 = +am__yacc_c2h = sed -e s/cc$$/hh/ -e s/cpp$$/hpp/ -e s/cxx$$/hxx/ \ + -e s/c++$$/h++/ -e s/c$$/h/ +YACCCOMPILE = $(YACC) $(AM_YFLAGS) $(YFLAGS) +AM_V_YACC = $(am__v_YACC_@AM_V@) +am__v_YACC_ = $(am__v_YACC_@AM_DEFAULT_V@) +am__v_YACC_0 = @echo " YACC " $@; +am__v_YACC_1 = +YLWRAP = $(top_srcdir)/ylwrap +SOURCES = $(gawk_SOURCES) +DIST_SOURCES = $(gawk_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +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; }; \ + } +HEADERS = $(include_HEADERS) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + cscope distdir dist dist-all distcheck +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \ + $(LISP)configh.in +# 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 +CSCOPE = cscope +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 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) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + if test -d "$(distdir)"; then \ + find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -rf "$(distdir)" \ + || { sleep 5 && rm -rf "$(distdir)"; }; \ + else :; fi +am__post_remove_distdir = $(am__remove_distdir) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +DIST_ARCHIVES = $(distdir).tar.gz $(distdir).tar.lz $(distdir).tar.xz +GZIP_ENV = --best +DIST_TARGETS = dist-lzip dist-xz dist-gzip +distuninstallcheck_listfiles = find . -type f -print +am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ + | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' +distcleancheck_listfiles = find . -type f -print + +# Directory for gawk's data files. Automake supplies datadir. +pkgdatadir = $(datadir)/awk +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 = -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@ +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 variable insures that aclocal runs +# correctly after changing configure.ac +ACLOCAL_AMFLAGS = -I m4 + +# 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 = \ + ChangeLog.0 \ + COPYING \ + INSTALL \ + NEWS \ + NEWS.0 \ + POSIX.STD \ + README_d \ + config.guess \ + config.rpath \ + config.sub \ + depcomp \ + m4 \ + missing \ + missing_d \ + po/README \ + pc \ + posix \ + 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 awklib after in doc, since we want to extract +# sample files if doc/gawk.texi changed. +SUBDIRS = support . $(am__append_1) extras doc awklib po test +include_HEADERS = gawkapi.h + +# sources for both gawk and dgawk +base_sources = \ + array.c \ + awk.h \ + awkgram.y \ + builtin.c \ + cint_array.c \ + cmd.h \ + command.y \ + custom.h \ + debug.c \ + eval.c \ + ext.c \ + field.c \ + floatcomp.c \ + floatmagic.h \ + gawkapi.c \ + gawkapi.h \ + gawkmisc.c \ + gettext.h \ + int_array.c \ + interpret.h \ + io.c \ + mbsupport.h \ + main.c \ + mpfr.c \ + msg.c \ + node.c \ + nonposix.h \ + profile.c \ + protos.h \ + re.c \ + replace.c \ + str_array.c \ + symbol.c \ + version.c + +gawk_SOURCES = $(base_sources) + +# Get extra libs as needed, Automake will supply LIBINTL and SOCKET_LIBS. +LDADD = support/libsupport.a \ + $(LIBSIGSEGV) $(LIBINTL) $(SOCKET_LIBS) $(LIBREADLINE) $(LIBMPFR) + + +# stuff for compiling gawk/pgawk +DEFPATH = '".$(PATH_SEPARATOR)$(pkgdatadir)"' + +# shared library support: +SHLIBEXT = "\"$(GAWKLIBEXT)"\" +DEFLIBPATH = "\"$(pkgextensiondir)\"" + +# Get rid of core files when cleaning +CLEANFILES = core core.* + +# We want hard links for install-exec-hook, below +LN = ln + +# For some make's, e.g. OpenBSD, that don't define this +RM = rm -f +all: config.h + $(MAKE) $(AM_MAKEFLAGS) all-recursive + +.SUFFIXES: +.SUFFIXES: .c .o .obj .y +am--refresh: Makefile + @: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \ + $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: $(am__configure_deps) + $(am__cd) $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +$(am__aclocal_m4_deps): + +config.h: stamp-h1 + @test -f $@ || rm -f stamp-h1 + @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 + +stamp-h1: $(srcdir)/configh.in $(top_builddir)/config.status + @rm -f stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status config.h +$(srcdir)/configh.in: $(am__configure_deps) + ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) + rm -f stamp-h1 + touch $@ + +distclean-hdr: + -rm -f config.h stamp-h1 +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(bin_PROGRAMS)'; 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 echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + 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; \ + else { print "f", $$3 "/" $$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_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) + +gawk$(EXEEXT): $(gawk_OBJECTS) $(gawk_DEPENDENCIES) $(EXTRA_gawk_DEPENDENCIES) + @rm -f gawk$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gawk_OBJECTS) $(gawk_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/array.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/awkgram.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/builtin.Po@am__quote@ +@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)/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)/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@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mpfr.Po@am__quote@ +@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)/re.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@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/version.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) '$<'` + +.y.c: + $(AM_V_YACC)$(am__skipyacc) $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h `echo $@ | $(am__yacc_c2h)` y.output $*.output -- $(YACCCOMPILE) +install-includeHEADERS: $(include_HEADERS) + @$(NORMAL_INSTALL) + @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(includedir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(includedir)" || 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_HEADER) $$files '$(DESTDIR)$(includedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \ + done + +uninstall-includeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir) + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(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-recursive + +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" +cscope: cscope.files + test ! -s cscope.files \ + || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) +clean-cscope: + -rm -f cscope.files +cscope.files: clean-cscope cscopelist +cscopelist: cscopelist-recursive + +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 + -rm -f cscope.out cscope.in.out cscope.po.out cscope.files + +distdir: $(DISTFILES) + $(am__remove_distdir) + test -d "$(distdir)" || mkdir "$(distdir)" + @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 + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$(top_distdir)" distdir="$(distdir)" \ + dist-hook + -test -n "$(am__skip_mode_fix)" \ + || find "$(distdir)" -type d ! -perm -755 \ + -exec chmod u+rwx,go+rx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r "$(distdir)" +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__post_remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 + $(am__post_remove_distdir) +dist-lzip: distdir + tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz + $(am__post_remove_distdir) +dist-xz: distdir + tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz + $(am__post_remove_distdir) + +dist-tarZ: distdir + @echo WARNING: "Support for distribution archives compressed with" \ + "legacy program 'compress' is deprecated." >&2 + @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__post_remove_distdir) + +dist-shar: distdir + @echo WARNING: "Support for shar distribution archives is" \ + "deprecated." >&2 + @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__post_remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__post_remove_distdir) + +dist dist-all: + $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' + $(am__post_remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.lz*) \ + lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ + *.tar.xz*) \ + xz -dc $(distdir).tar.xz | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir) + chmod u+w $(distdir) + mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst + chmod a-w $(distdir) + test -d $(distdir)/_build || exit 0; \ + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && am__cwd=`pwd` \ + && $(am__cd) $(distdir)/_build/sub \ + && ../../configure \ + $(AM_DISTCHECK_CONFIGURE_FLAGS) \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + --srcdir=../.. --prefix="$$dc_install_base" \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ + && cd "$$am__cwd" \ + || exit 1 + $(am__post_remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' +distuninstallcheck: + @test -n '$(distuninstallcheck_dir)' || { \ + echo 'ERROR: trying to run $@ with an empty' \ + '$$(distuninstallcheck_dir)' >&2; \ + exit 1; \ + }; \ + $(am__cd) '$(distuninstallcheck_dir)' || { \ + echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ + exit 1; \ + }; \ + test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-local +check: check-recursive +all-am: Makefile $(PROGRAMS) $(HEADERS) config.h +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(includedir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +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: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +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." + -rm -f awkgram.c + -rm -f command.c +clean: clean-recursive + +clean-am: clean-binPROGRAMS clean-generic mostlyclean-am + +distclean: distclean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-hdr distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: install-includeHEADERS + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: install-binPROGRAMS + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-exec-hook +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-includeHEADERS + +.MAKE: $(am__recursive_targets) all check-am install-am \ + install-exec-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ + am--refresh check check-am check-local clean clean-binPROGRAMS \ + clean-cscope clean-generic cscope cscopelist-am ctags ctags-am \ + dist dist-all dist-bzip2 dist-gzip dist-hook dist-lzip \ + dist-shar dist-tarZ dist-xz dist-zip distcheck distclean \ + distclean-compile distclean-generic distclean-hdr \ + distclean-tags distcleancheck distdir distuninstallcheck dvi \ + dvi-am html html-am info info-am install install-am \ + install-binPROGRAMS install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-exec-hook \ + install-html install-html-am install-includeHEADERS \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs installdirs-am \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am uninstall-binPROGRAMS \ + uninstall-includeHEADERS + +.PRECIOUS: Makefile + + +# First, add a link from gawk to gawk-X.Y.Z. +# +# For GNU systems where gawk is awk, add a link to awk. +# (This is done universally, which may not always be right, but +# there's no easy way to distinguish GNU from non-GNU systems.) +# +# Use the transform, in case --program-prefix=XXX +install-exec-hook: + (cd $(DESTDIR)$(bindir); \ + name=`echo gawk | sed '$(transform)'` ; \ + $(LN) $${name}$(EXEEXT) gawk-$(VERSION)$(EXEEXT) 2>/dev/null ; \ + if [ ! -f awk$(EXEEXT) ]; \ + then $(LN_S) $${name}$(EXEEXT) awk$(EXEEXT); \ + fi; exit 0) + +# Undo the above when uninstalling +uninstall-links: + (cd $(DESTDIR)$(bindir); \ + name=`echo gawk | sed '$(transform)'` ; \ + if [ -f awk$(EXEEXT) ] && cmp awk$(EXEEXT) $${name}$(EXEEXT) > /dev/null; then rm -f awk$(EXEEXT); fi ; \ + rm -f gawk-$(VERSION)$(EXEEXT); exit 0) + +uninstall-recursive: uninstall-links + +# force there to be a gawk executable before running tests +check-local: gawk$(EXEEXT) + +# A little extra clean up when making distributions. +# And additional set up for the pc directory. +dist-hook: + cd "$(distdir)"/extension ; rm -f *.o *.so + cd "$(srcdir)"/pc ; \ + chmod u+w config.h ; \ + sed -n -f configpk.sed < ../configure.ac > /tmp/tmp.sed ; \ + sed -f config.sed < ../configh.in > /tmp/config.tmp ; \ + sed -f /tmp/tmp.sed < /tmp/config.tmp > config.h ; \ + $(RM) /tmp/tmp.sed /tmp/config.tmp + pwd + chmod u+w "$(distdir)"/pc/config.h + cp "$(srcdir)"/pc/config.h "$(distdir)"/pc/config.h + +# Special rules for individual files + +awkgram.c: awkgram.y + $(YACC) -o $@ $(AM_YFLAGS) $(YFLAGS) $< + sed 's/parse error/syntax error/g' < $@ > $@.tmp && mv $@.tmp $@ + +command.c: command.y + $(YACC) -o $@ -p zz $< + sed 's/parse error/syntax error/g' < $@ > $@.tmp && mv $@.tmp $@ + +# This is for my development & testing. +efence: gawk + $(CC) $(LDFLAGS) -o gawk $$(ls *.o | grep -v '_p.o$$') $(LDADD) $(LIBS) -lefence + +diffout valgrind-scan: + @cd test && $(MAKE) $(AM_MAKEFLAGS) $@ + +valgrind: + cd test; rm -f log.[0-9]*; \ + make check VALGRIND="valgrind --leak-check=full --log-file=log.%p"; \ + make valgrind-scan + +valgrind-noleak: + cd test; rm -f log.[0-9]*; \ + make check VALGRIND="valgrind --leak-check=no --log-file=log.%p"; \ + make valgrind-scan + +spell: + cd "$(srcdir)"/doc ; $(MAKE) spell + +# 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/NEWS b/NEWS new file mode 100644 index 0000000..c2885c8 --- /dev/null +++ b/NEWS @@ -0,0 +1,480 @@ + Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 + Free Software Foundation, Inc. + + Copying and distribution of this file, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. + +Changes from 4.2.0 to 4.2.1 +--------------------------- + +1. Support for OS/2 has been brought up to date. This support was + accidentally omitted from the initial 4.2 release, for which + we apologize. + +2. The manual received a number of updates to make it format better + for PDF. + +3. A new configure option, --enable-versioned-dir, causes the directory + holding extensions to include the API version in its name. + +4. extension/configure.ac has been improved considerably. + +5. In MPFR mode, When ROUNDMODE changes, string values for numerically + type values will be redone. + +6. The various 'inplace' tests now pass on modern BSD systems. + +7. A number of bugs, some of them quite significant, have been fixed. + See the ChangeLog for details. + +Changes from 4.1.4 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. Multiple changes related to the pretty printer: + + * The --pretty-print option no longer runs the program too. + + * Pretty printing now preserves comments and places them into the + pretty-printed file. + + * Pretty-printing now uses the original text of constant numeric values + for pretty-printing and profiling. + + * Pretty-printing now preserves parenthesized expressions as they + were in the source file. This solves several niggling corner cases + with such things. + +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 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. + +6. Gawk now processes a maximum of two hexadecimal digits in \x + escape sequences inside strings. + +7. Setting PROCINFO["redirection", "NONFATAL"] to true makes I/O + errors for "redirection" not fatal, setting ERRNO. Setting + PROCINFO["NONFATAL"] makes all I/O nonfatal. See the manual. + +8. MirBSD is no longer supported. + +9. `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. + +10. Gawk now supports retryable I/O via PROCINFO[input-file, "RETRY"]; see + the manual. + +11. 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. + + See the manual for the new features. + +12. 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. + +13. 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. + +14. The new typeof() function can be used to indicate if a variable or + array element is an array, regexp, string or number. + +15. As promised when 4.1 was released, the old extension mechanism, + using the `extension' function, is now gone. + +16. Support for GNU/Linux on Alpha systems has been removed. + +17. 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. + +18. Gawk now uses fwrite_unlocked if it's available. This yields a 7% - 18% + improvement in raw output speed (gawk '{ print }' on a large file). + +19. Passing negative operands to any of the bitwise functions now + produces a fatal error. + +20. Programs that toggle IGNORECASE a lot should now be noticeably faster. + +21. 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. + +22. 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. + +23. The PROCINFO["argv"] array records all of gawk's command line arguments + as gawk received them (the values of the C level argv array). + +24. The DJGPP port has been revived and now has an official maintainer. + +25. The manual has been translated into Italian! The translation is + included in the distribution. + +Changes from 4.1.3 to 4.1.4 +--------------------------- + +1. Updated to GNU autoconf 2.69, automake 1.15, gettext 0.19.7, + texinfo 6.1, texinfo.tex 2016-02-05.07, libtool 2.4.6. + +2. z/OS support updated. + +3. At the beginning of each statement, the debugger now checks and + reports watchpoints that have fired before checking for breakpoints. + This gives more natural behavior to the user. + +4. The "exit" command has been added to the debugger as an alias + for "quit". + +5. AIX 7.1 should pass the test suite now. Similar for Minix. + +6. VMS support has been updated. + +7. The profiler / pretty-printer now chains else-if statements instead + of causing cascading elses. + +8. The return value of system() has been enhanced to convey more information. + See the doc. + +9. Attempting to write to the "to" end of a two-way pipe that has been + closed is now a fatal error. Similarly, so is reading from the "from" + end that has been closed. + +10. MinGW support has been updated. + +11. The -d option now allows -d- to print to standard output. + +12. Error messages for --help and in other instances should now get + translated correctly. + +13. A new environment variable GAWK_LOCALE_DIR may be set to locate the .mo + file for gawk itself. + +14. The DJGPP port is now officially deprecated. + +15. A number of bugs have been fixed. See the ChangeLog. + +Changes from 4.1.2 to 4.1.3 +--------------------------- + +1. Regexp parsing with extra brackets should now be working again. There + are several new tests to keep this stuff on track. + +2. Updated to latest config.guess and config.sub. + +3. A (small) number of bugs have been fixed. See the ChangeLog. + +Changes from 4.1.1 to 4.1.2 +--------------------------- + +1. The manual has been considerably improved. + - Thoroughly reviewed and updated. + - Out-of-date examples replaced. + - Chapter 15 on MPFR reworked. + - Summary sections added to all chapters. + - Exercises added in several chapters. + - Heavily proof-read and copyedited. + +2. The debugger's "restart" command now works again. + +3. Redirected getline is now allowed inside BEGINFILE/ENDFILE. + +4. A number of bugs have been fixed in the MPFR code. + +5. Indirect function calls now work for both built-in and extension functions. + +6. Built-in functions are now included in FUNCTAB. + +7. POSIX and historical practice require the exclusive use of the English + alphabet in identifiers. In non-English locales, it was accidentally + possible to use "letters" beside those of the English alphabet. This + has been fixed. (isalpha and isalnum are NOT our friends.) + + If you feel that you must have this misfeature, use `configure --help' + to see what option to use when configuring gawk to reenable it. + +8. The "where" command has been added to the debugger as an alias + for "backtrace". This will make life easier for long-time GDB users. + +9. Gawk no longer explicitly checks the current directory after doing + a path search of AWKPATH. The default value continues to have "." at + the front, so most people should not be affected. If you have your own + AWKPATH setting, be sure to put "." in it somewhere. The documentation + has been updated and clarified. + +10. Infrastructure upgrades: Automake 1.15, Gettext 0.19.4, Libtool 2.4.6, + Bison 3.0.4. + +11. If a user-defined function has a parameter with the same name as another + user-defined function, it is no longer possible to call the second + function from inside the first. + +12. POSIX requires that the names of function parameters not be the + same as any of the special built-in variables and also not conflict + with the names of any functions. Gawk has checked for the former + since 3.1.7. With --posix, it now also checks for the latter. + +13. The test suite should check for necessary locales and skip the tests + where it matters if support isn't what it should be. + +14. Gawk now expects to be compiled on a system with multibyte character + support. Systems without such support, at least at the C language + level, are so obsolete as to not be worth supporting anymore. + +15. A number of bugs have been fixed. See the ChangeLog. + +Changes from 4.1.0 to 4.1.1 +--------------------------- + +1. The "stat" extension now includes a "devbsize" element which indicates + the units for the "nblocks" element. + +2. The extension facility now works on MinGW. Many of the extensions can be + built and used directly. + +3. A number of bugs in the pretty-printing / profiling code have been fixed. + +4. Sockets and two-way pipes now work under MinGW. + +5. The debugger now lists source code correctly under Cygwin. + +6. Configuration and building with the Mac OS X libreadline should work now. + +7. The -O option now works again. + +8. The --include option, documented since 4.0, now actually works. + +9. Infrastructure updated to automake 1.13.4, bison 3.0.2, and + libtool 2.4.2.418. + +10. The configure script now accepts a --disable-extensions option, + which disables checking for and building the extensions. + +11. The VMS port has been considerably improved. In particular config.h + is now generated by a DCL script. Also, the extension facility works + and several of the extensions can be built and used. Currently, the + extension facility only works on Alpha and Itanium. + +12. The API now provides functions pointers for malloc(), calloc(), + realloc() and free(), to insure that the same memory allocation + functions are always used. This bumps the minor version by one. + +13. The printf quote flag now works correctly in locales with a different + decimal point character but without a thousands separator character. + If the thousands separator is a string, it will be correctly added + to decimal numbers. + +14. The readfile extension now has an input parser that will read whole + files as a single record. + +15. A number of bugs have been fixed. See the ChangeLog. + +Changes from 4.0.2 to 4.1.0 +--------------------------- + +1. The three executables gawk, pgawk, and dgawk, have been merged into + one, named just gawk. As a result: + * The -R option is gone + * Use -D to run the debugger. An optional file argument is a + list of commands to run first. + * Use -o to do pretty-printing only. + * Use -p to do profiling. + This considerably reduces gawk's "footprint" and eases the documentation + burden as well. + +2. Gawk now supports high precision arithmetic with MPFR. The default is + still double precision, but setting PREC changes things, or using + the -M / --bignum options. This support is not compiled in if the MPFR + library is not available. + +3. The new -i option (from xgawk) is used for loading awk library files. + This differs from -f in that the first non-option argument is treated + as a script. + +4. The new -l option (from xgawk) is used for loading dynamic extensions. + +5. The dynamic extension interface has been completely redone! There is + now a defined API for C extensions to use. A C extension acts like + a function written in awk, except that it cannot do everything that awk + code can. However, this allows interfacing to any facility that is + available from C. This is a major development, see the doc, which has + a nice shiny new chapter describing everything. + + This support is not compiled in if dynamic loading of shared libraries + is not supported. + + The old extension mechanism is still supported for compatiblity, but + it will most definitely be removed at the next major release. + +6. The "inplace" extension, built using the new facility, can be used to + simulate the GNU "sed -i" feature. + +7. The and(), or() and xor() functions now take any number of arguments, + with a minimum of two. + +8. New arrays: SYMTAB, FUNCTAB, and PROCINFO["identifiers"]. SYMTAB allows + indirect access to any defined variable or array; it is possible to + "walk" the symbol table, if that should be necessary. + +9. Support for building gawk with a cross compiler has been improved. + +10. Infrastructure upgrades: bison 2.7.1, gettext 0.18.2.1, automake 1.13.1, + libtool 2.4.2 for the extensions. + +Changes from 4.0.1 to 4.0.2 +--------------------------- + +1. Infrastructure upgrades: Autoconf 2.69, Automake 1.12.6, bison 2.7. + +2. `fflush()', `nextfile', and `delete array' are all now part of POSIX. + +3. fflush() behavior changed to match BWK awk and for POSIX - now both + fflush() and fflush("") flush all open output redirections. + +4. Various minor bug fixes and documentation updates. + +Changes from 4.0.0 to 4.0.1 +--------------------------- + +1. The default handling of backslash in sub() and gsub() has been reverted to + the behavior of 3.1. It was silly to think I could break compatibility that + way, even for standards compliance. + +2. Completed the implementation of Rational Range Interpretation. + +3. Failure to get the group set is no longer a fatal error. + +4. Lots of minor bugs fixed and portability clean-ups along the way. See + the ChangeLog for details. + +Changes from 3.1.8 to 4.0.0 +--------------------------- + +1. The special files /dev/pid, /dev/ppid, /dev/pgrpid and /dev/user are + now completely gone. Use PROCINFO instead. + +2. The POSIX 2008 behavior for `sub' and `gsub' are now the default. + THIS CHANGES BEHAVIOR!!!! + +3. The \s and \S escape sequences are now recognized in regular expressions. + +4. The split() function accepts an optional fourth argument which is an array + to hold the values of the separators. + +5. The new -b / --characters-as-bytes option means "hands off my data"; gawk + won't try to treat input as a multibyte string. + +6. There is a new --sandbox option; see the doc. + +7. Indirect function calls are now available. + +8. Interval expressions are now part of default regular expressions for + GNU Awk syntax. + +9. --gen-po is now correctly named --gen-pot. + +10. switch / case is now enabled by default. There's no longer a need + for a configure-time option. + +11. Gawk now supports BEGINFILE and ENDFILE. See the doc for details. + +12. Directories named on the command line now produce a warning, not + a fatal error, unless --posix or --traditional. + +13. The new FPAT variable allows you to specify a regexp that matches + the fields, instead of matching the field separator. The new patsplit() + function gives the same capability for splitting. + +14. All long options now have short options, for use in `#!' scripts. + +15. Support for IPv6 is added via the /inet6/... special file. /inet4/... + forces IPv4 and /inet chooses the system default (probably IPv4). + +16. Added a warning for /[:space:]/ that should be /[[:space:]]/. + +17. Merged with John Haque's byte code internals. Adds dgawk debugger and + possibly improved performance. + +18. `break' and `continue' are no longer valid outside a loop, even with + --traditional. + +19. POSIX character classes work with --traditional (BWK awk supports them). + +20. Nuked redundant --compat, --copyleft, and --usage long options. + +21. Arrays of arrays added. See the doc. + +22. Per the GNU Coding Standards, dynamic extensions must now define + a global symbol indicating that they are GPL-compatible. See + the documentation and example extensions. + THIS CHANGES BEHAVIOR!!!! + +23. In POSIX mode, string comparisons use strcoll/wcscoll. + THIS CHANGES BEHAVIOR!!!! + +24. The option for raw sockets was removed, since it was never implemented. + +25. Gawk now treats ranges of the form [d-h] as if they were in the C + locale, no matter what kind of regexp is being used, and even if + --posix. The latest POSIX standard allows this, and the documentation + has been updated. Maybe this will stop all the questions about + [a-z] matching uppercase letters. + THIS CHANGES BEHAVIOR!!!! + +26. PROCINFO["strftime"] now holds the default format for strftime(). + +27. Updated to latest infrastructure: Autoconf 2.68, Automake 1.11.1, + Gettext 0.18.1, Bison 2.5. + +28. Many code cleanups. Removed code for many old, unsupported systems: + - Atari + - Amiga + - BeOS + - Cray + - MIPS RiscOS + - MS-DOS with Microsoft Compiler + - MS-Windows with Microsoft Compiler + - NeXT + - SunOS 3.x, Sun 386 (Road Runner) + - Tandem (non-POSIX) + - Prestandard VAX C compiler for VAX/VMS + - Probably others that I've forgotten + +29. If PROCINFO["sorted_in"] exists, for(iggy in foo) loops sort the + indices before looping over them. The value of this element + provides control over how the indices are sorted before the loop + traversal starts. See the manual. + +30. A new isarray() function exists to distinguish if an item is an array + or not, to make it possible to traverse multidimensional arrays. + +31. asort() and asorti() take a third argument specifying how to sort. + See the doc. diff --git a/NEWS.0 b/NEWS.0 new file mode 100644 index 0000000..54e4dc0 --- /dev/null +++ b/NEWS.0 @@ -0,0 +1,2542 @@ + Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, + 2005, 2006, 2007, 2009, 2010 Free Software Foundation, Inc. + + Copying and distribution of this file, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. + +Changes from 3.1.7 to 3.1.8 +--------------------------- +1. The zero flag no longer applies to %c and %s; apparently the standards + changed at some point. + +2. Updated to latest infrastructure: Autoconf 2.65, Automake 1.11.1, + libtool 2.2.6b, Bison 2.4.2. + +3. Failure to open a socket is no longer a fatal error. + +4. dfa.h and dfa.c are now more-or-less in sync with GNU grep, for the first + time in many years. + +5. Gawk no longer includes its own copy of libsigsegv but it will use it if + installed on the build system. The --disable-libsigsegv configure option + is now gone. + +6. The ' flag (%'d) is now just ignored on systems that can't support it. + +7. Lots of bug fixes, see the ChangeLog. + +Changes from 3.1.6 to 3.1.7 +--------------------------- +1. Gawk now has support for z/OS (IBM S/390 architecture). + +2. Gawk now handles multibyte strings better in [s]printf with field + widths and such. + +3. Gawk now uses libsigsegv to print a message before core dumping. This + handles infinite recursion of an awk function a little better. + Use of the library can be disabled at configure time with the + --disable-libsigsegv option for unusual systems. + +4. The handling of BINMODE is now somewhat more sane. + +5. A getline from a directory is no longer fatal; instead it returns -1. + +6. Per POSIX, special variable names (like FS) cannot be used as function + parameter names. + +7. The new -O / --optimize option enables simple constant folding on + the parse tree during parsing. We hope that with time the number + of optimizations will increase. + +8. Updated to the latest autotools: Autoconf 2.63, Automake 1.11, + Libtool 2.2.6a, and Gettext 0.17. Also latest Bison: 2.4.1. + +9. Some improvement in testing for isinf / isnan in builtin.c. + +10. Improved the handling of `a = a b c' to be more general. + +11. Locale handling for %'d should now work on certain non-Unix / + non-Linux systems. + +12. Lots of bugs fixed, see the ChangeLog for the details. + +Changes from 3.1.5 to 3.1.6 +--------------------------- + +1. `gawk 'program' /non/existant/file' no longer core dumps. + +2. Too many people the world over have complained about gawk's use of the + locale's decimal point for parsing input data instead of the traditional + period. So, even though gawk was being nicely standards-compliant, in + a Triumph For The Users, gawk now only uses the locale's decimal point + if --posix is supplied or if POSIXLY_CORRECT is set. It is the sincere + hope that this change will eliminate this FAQ from being asked. + +3. `gawk -v BINMODE=1 ...' works again. + +4. Internal file names like `/dev/user' now work again. (Note that these + file names are obsolete and will go away eventually.) + +5. Problems with wide strings in non "C" locales have been straightened + out everywhere. (At least, we think so.) + +6. Use of `ansi2knr' is no longer supported. Please use an ANSI C compiler. + +7. Updated to Autoconf 2.61, Automake 1.10, and Gettext 0.16.1. + +8. The getopt* and regex* files were synchronized with current GLIBC CVS. + See the ChangeLog for the versions and minor edits made. + +9. There are additional --lint-old warnings. + +10. Gawk now uses getaddrinfo(3) to look up names and IP addresses. This + allows the use of an IPv6 format address and paves the way for + eventual addition of `/inet6/...' and `/inet4/...' hostnames. + +11. We believe gawk to now be valgrind clean. At least when run against + the test suite. + +12. A number of issues dealing with the formatting and printing of very + large numbers in integer formats have been dealt with and fixed. + +13. Gawk now converts "+inf", "-inf", "+nan" and "-nan" into the corresponding + magic IEEE floating point values. Only those strings (case independent) + work. With --posix, gawk calls the system strtod directly. You asked + for it, you got it, you deal with it. + +14. Defining YYDEBUG enables the -D command line option. + +15. Gawk should now work out of the box on Tandem NSK/OSS systems. + +16. Lint messages rationalized: many more of the messages are now printed + only once, instead of every time they are encountered. + +17. The strftime() function now accepts an optional third argument, which + if non-zero or non-null, indicates that the time should be formatted + as UTC instead of as local time. + +18. The precedence of concatenation and `| getline' (in something like + "echo " "date" | getline stuff) has been reverted to the earlier + behavior and now once again matches Unix awk. + +19. New configure time flag --disable-directories-fatal which causes + gawk to silently skip directories on the command line. This behavior + is also enabled for --traditional, since it's what Unix awk does. + +20. A new option, --use-lc-numeric, forces use of the locale's decimal + point without the rest of the draconian restrictions imposed by + --posix. This softens somewhat the stance taken in item #2. + +21. Everything relevant has been updated to the GPL 3. + +22. Array growth should be faster now, at no cost in space. + +23. Lots more tests. + +24. One new translation. + +25. Various bugs fixed, see the ChangeLog for details. + +Changes from 3.1.4 to 3.1.5 +--------------------------- + +1. The random() suite has been updated to a current FreeBSD version, which + works on systems with > 32-bit ints. + +2. A new option, `--exec' has been added. It's like -f but ends option + processing. It also disables `x=y' variable assignments, but not -v. + It's needed mainly for CGI scripts, so that source code can't be + passed in as part of the URL. + +3. dfa.[ch] have been synced with GNU grep development. This also fixes + multiple regex matching problems in multibyte locales. + +4. Updated to Automake 1.9.5. + +5. Updated to Bison 2.0. + +6. The getopt* and regex* files were synchronized with current GLIBC CVS. + See the ChangeLog for the versions and minor edits made. + +7. `configure --disable-nls' now disables just gawk's own translations. + Gawk continues to work with the locale's numeric formatting. This + includes a bug fix in handling the printf ' flag (e.g., %'d). + +8. Gawk is now multibyte aware. This means that index(), length(), + substr() and match() all work in terms of characters, not bytes. + +9. Gawk is now smarter about parsing numeric constants in corner cases. + +11. Not closing open redirections no longer causes gawk to exit non-zero. + +10. The VMS port has been updated. + +11. Changes from Andrew Schorr at the xmlgawk project to provide for + open hooks from extensions are now included. This will let the + xmlgawk extension work in the standard gawk. + +12. Updated to gettext 0.14.4. Gawk no longer includes its own copy + of the gettext `intl' library, following current GNU practice to + rely on there being an external version thereof. + +13. A regexp of the form `//' will now generate a warning that it + is not a C++ comment from --lint (awk.y). + +14. The ^ and ^= operators with an integer exponent now use Exponentiation + by Squaring. This simultaneously fixes a problem with ^= and a negative + integer exponent. + +15. length(array) now returns the number of elements in the array. This is + is a non-standard extension that will fail in POSIX mode. + +16. Carriage return characters are now ignored in program source code. + +17. Four new translations added. + +18. Various minor bugs fixed. See the ChangeLog for the details. + +Changes from 3.1.3 to 3.1.4 +--------------------------- + +1. Gawk now supports the POSIX %F format, falling back to %f if the local + system printf doesn't handle it. + +2. Gawk now supports the ' flag in printf. E.g., %'d in a locale with thousands + separators includes the thousands separator in the value, e.g. 12,345. + + This has one problem; the ' flag is next to impossible to use on the + command line, without major quoting games. Oh well, TANSTAAFL. + +3. The dfa code has been reinstated; the performance degradation was + just too awful. Sigh. (For fun, use `export GAWK_NO_DFA=1' to + see the difference.) + +4. The special case `x = x y' is now recognized in the grammar, and gawk + now uses `realloc' to append the new value to the end of the existing + one. This can speed up the common case of appending onto a string. + +5. The dfa code was upgraded with most of the fixes from grep 2.5.1, and + the regex code was upgraded with GLIBC as mid-January 2004. The regex + code is faster than it was, but still not as fast as the dfa code, so + the dfa code stays in. The getopt code was also synced to current GLIBC. + +6. Support code upgraded to Automake 1.8.5, Autoconf 2.59, and gettext 0.14.1. + +7. When --posix is in effect, sub/gsub now follow the 2001 POSIX behavior. + Yippee. This is even documented in the manual. + +8. Gawk will now recover children that have died (input pipelines, two-way + pipes), upon detecting EOF from them, thus avoiding filling + up the process table. Open file descriptors are not recovered + (unfortunately), since that could break awk semantics. See the + ChangeLog and the source code for the details. + +9. Handling of numbers like `0,1' in non-American locales ought to + work correctly now. + +10. IGNORECASE is now locale-aware for characters with values above 128. + The dfa matcher is now used for IGNORECASE matches too. + +11. Dynamic function loading is better. The documentation has been improved + and some new APIs for use by dynamic functions have been added. + +12. Gawk now has a fighting chance of working on older systems, + a la SunOS 4.1.x. + +13. Issues with multibyte support on HP-UX are now resolved. `configure' now + disables such support there, since it's not up to what gawk needs. + +14. There are now even more tests in the test suite. + +15. Various bugs fixed; see ChangeLog for the details. + +Changes from 3.1.2 to 3.1.3 +--------------------------- + +1. Gawk now follows POSIX in handling of local numeric formats for + input, output and number/string conversions. + +2. Multibyte detection improved. See README_d/README.multibyte for more + info about multibyte locales. + +3. Handling of `close' made more POSIX-compliant for POSIXLY_CORRECT, + see the documentation. + +4. The record reading code was redone, again. This time it's much + better. Really! + +5. For RS = "\n" and RS = "", gawk now only sets RT when it has changed. + This provides considerable performance improvement. + +6. `match' now sets all the subscripts in the third argument array + correctly, even if not all subexpressions matched. + +7. Updated to Automake 1.7.5. configure.in renamed configure.ac. + +8. C-style switch statements are available, but must be enabled at + compile time via `configure --enable-switch'. For 3.2 they'll be + enabled by default. Thanks to Michael Benzinger for the initial + code. + +9. %c now always prints no more than one character, whatever + precision is provided. + +10. strtonum() now works again. + +11. Gawk is now much better about scalar/array typing of global + uninitiailzed variables passed as parameters. Once the parameter + is then used one way or the other, the global var's type is + adjusted accordingly. Thanks to Stepan Kasal for the original + (considerable) changes. + +12. Dynamic function loading under Windows32 should now be possible. See + README_d/README.pcdynamic. Thanks to Patrick T.J. McPhee for the changes. + +13. Updated to gettext 0.12.1. + +14. Gawk now follows historical practice and POSIX for the return + value of `rand': It's now 0 <= N < 1. + +Changes from 3.1.1 to 3.1.2 +--------------------------- + +1. Loops of the form: + + for (iggy in foo) + next + + no longer leak memory. + +2. gawk -v FIELDWIDTHS="..." now sets PROCINFO["FS"] correctly. + +3. All builtin operations and functions should now fully evaluate their + arguments so that side effects take place correctly. + +4. Fixed a logic bug in gsub/gensub for matches to null strings that occurred + later in the string after a nonnull match. + +5. getgroups code now works on Ultrix again. + +6. Completely new version of the full GNU regex engine now in place. + +7. Argument parsing and variable assignment has been cleaned up. + +8. An I/O bug on HP-UX has been documented and worked around. See + README_d/README.hpux. + +9. awklib/grcat should now compile correctly. + +10. Updated to automake 1.7.3, autoconf 2.57 and gettext 0.11.5 ; thanks to + Paul Eggert for the initial automake and autoconf work. + +11. As a result of #6, removed the use of the dfa code from GNU grep. + +12. It is now possible to use ptys for |& two-way pipes instead of + pipes. The basic plumbing for this was provided by Paolo Bonzini. + To make this happen: + + command = "unix command etc" + PROCINFO[command, "pty"] = 1 + + print ... |& command + command |& getline stuff + + In other words, set the element in PROCINFO *before* opening the + two-way pipe, and then gawk will use ptys instead of pipes. + + On systems without ptys or where all the ptys are in use, gawk + will fall back to using plain pipes. + +13. Fixed a regex matching across buffer boundaries bug, with a + heuristic. See io.c:rsre_get_a_record. + +14. Profiling no longer dumps core if there are extension functions in place. + +15. Grammar and scanner cleaned up, courtesy of Stepen Kasal, to hopefully + once and for all fix the `/=' operator vs. `/=.../' regex ambiguity. + Lots of other grammar simplifications applied, as well. + +16. BINMODE should work now on more Windows ports. + +17. Updated to bison 1.875. Includes fix to bisonfix.sed script. + +18. The NODE structure is now 20% (8 bytes) smaller (on x86, anyway), which + should help conserve memory. + +19. Builds not in the source directory should work again. + +20. Arrays now use 2 NODE's per element instead of three. Combined with + #18, (on the x86) this reduces the overhead from 120 bytes per element + to just 64 bytes: almost a 50% improvement. + +21. Programs that make heavy use of changing IGNORECASE should now be + much faster, particularly if using a regular expression for FS or RS. + IGNORECASE now correctly affects RS regex record splitting, as well. + +22. IGNORECASE no longer affects single-character field splitting (FS = "c"), + or single-character record splitting (RS = "c"). + + This cleans up some weird behavior, and makes gawk better match the + documentation, which says it only affects regex-based field splitting + and record splitting. + + The documentation on this was improved, too. + +23. The framework in test/ has been simplified, making it much easier to + add new tests while keeping the size of Makefile.am reasonable. Thanks + for this to Stepan Kasal. + +24. --lint=invalid causes lint warnings only about stuff that's actually + invalid. This needs additional work. + +25. More translations. + +26. The `get_a_record' routine has been revamped (currently by splitting it + into three variants). This should improve long-term maintainability. + +27. `match' now adds more entries to 3rd array arg: + match("the big dog", /([a-z]+) ([a-z]+) ([a-z]+)/, data) + fills in variables: + data[1, "start"], data[1, "length"], and so on. + +28. New `asorti' function with same interface as `asort', but sorts indices + instead of values. + +29. Documentation updated to FDL 1.2. + +30. New `configure' option --disable-lint at compile time disables lint + checking. With GCC dead-code-elimination, cuts almost 200K off the + executable size on GNU/Linux x86. Presumably speeds up runtime. + + Using this will cause some of the tests in the test suite to fail. + This option may be removed at a later date. + +31. Various minor cleanups, see the ChangeLog for details. + +Changes from 3.1.0 to 3.1.1 +--------------------------- + +1. Six new translations. + +2. Having more than 4 different values for OFMT and/or CONVFMT now works. + +3. The handling of dynamic regexes is now more more sane, esp. w.r.t. + the profiling code. The profiling code has been fixed in several + places. + +4. The return value of index("", "") is now 1. + +5. Gawk should no longer close fd 0 in child processes. + +6. Fixed test for strtod semantics and regenerated configure. + +7. Gawk can now be built with byacc; an accidental bison dependency was + removed. + +8. `yyerror' will no longer dump core on long source lines. + +9. Gawk now correctly queries getgroups(2) to figure out how many groups + the process has. + +10. New configure option to force use of included strftime, e.g. on + Solaris systems. See `./configure --help' for the details. Replaced + the included strftime.c with the one from textutils. + +11. OS/2 port has been updated. + +12. Multi-byte character support has been added, courtesy of IBM Japan. + +13. The `for (iggy in foo) delete foo[iggy]' -> `delete foo' optimisation + now works. + +14. Upgraded to gettext 0.11.2 and automake 1.5. + +15. Full gettext compatibility (new dcngettext function). + +16. The O'Reilly copyedits and indexing changes for the documentation have + been folded into the texinfo version of the manuals. + +17. A humongously long value for the AWKPATH environment variable will no + longer dump core. + +18. Configuration / Installation issues have been straightened out in + Makefile.am. + +Changes from 3.0.6 to 3.1.0 +--------------------------- + +1. A new PROCINFO array provides info about the process. The non-I/O /dev/xxx + files are now obsolete, and their use always generates a warning. + +2. A new `mktime' builtin function was added for creating time stamps. The + `mktime' function written in awk was removed from the user's guide. + +3. New `--gen-po' option creates GNU gettext .po files for strings marked + with a leading underscore. + +4. Gawk now completely interprets special file names internally, ignoring the + existence of real /dev/stdin, /dev/stdout files, etc. + +5. The mmap code was removed. It was a worthwhile experiment that just + didn't work out. + +6. The BINMODE variable is new; on non-UNIX systems it affects how gawk + opens files for text vs. binary. + +7. The atari port is now unsupported. + +8. Gawk no longer supports `next file' as two words. + +9. On systems that support it, gawk now sets the `close on exec' flag on all + files and pipes it opens. This makes sure that child processes run via + `system' or pipes have plenty of file descriptors available. + +10. New ports: Tandem and BeOS. The Tandem port is unsupported. + +11. If `--posix' is in effect, newlines are not allowed after ?:. + +12. Weird OFMT/CONVFMT formats no longer cause fatal errors. + +13. Diagnostics about array parameters now include the parameter's name, + not just its number. + +14. configure should now automatically add -D_SYSV3 for ISC Unix. + (This seems to have made it into the gawk 3.0.x line long ago.) + +15. It is now possible to open a two-way pipe via the `|&' operator. + See the discussion in the manual about putting `sort' into such a pipeline, + though. (NOTE! This is borrowed from ksh: it is not the same as + the same operator in csh!) + +16. The `close' function now takes an optional second string argument + that allows closing one or the other end of the two-way pipe to + a co-process. This is needed to use `sort' in a co-process, see + the doc. + +17. If TCP/IP is available, special file names beginning with `/inet' + can be used with `|&' for IPC. Thanks to Juergen Kahrs for the initial + code. + +18. With `--enable-portals' on the configure command line, gawk will also + treat file names that start with `/p/' as a 4.4 BSD type portal file, + i.e., a two-way pipe for `|&'. + +19. Unrecognized escapes, such as "\q" now always generate a warning. + +20. The LINT variable is new; it provides dynamic control over the --lint + option. + +21. Lint warnings can be made fatal by using --lint=fatal or `LINT = "fatal"'. + Use this if you're really serious about portable code. + +22. Due to an enhanced sed script, there is no longer any need to worry + about finding or using alloca. alloca.c is thus now gone. + +23. A number of lint warnings have been added. Most notably, gawk will + detect if a variable is used before assigned to. Warnings for + when a string that isn't a number gets converted to a number are + in the code but disabled; they seem to be too picky in practice. + + Also, gawk will now warn about function parameter names that shadow + global variable names. + +24. It is now possible to dynamically add builtin functions on systems + that support dlopen. This facility is not (yet) as portable or well + integrated as it might be. *** WARNING *** THIS FEATURE WILL EVOLVE! + +25. There are *many* new tests in the test suite. + +26. Profiling has been added! A separate version of gawk, named pgawk, is + built and generates a run-time execution profile. The --profile option + can be used to change the default output file. In regular gawk, this + option pretty-prints the parse tree. + +27. Gawk has been internationalized, using GNU gettext. Translations for + future distributions are most welcome. Simultaneously, gawk was switched + over to using automake. You need Automake 1.4a (from the CVS archive) + if you want to muck with the Makefile.am files. + +28. New `asort' function for sorting arrays. See the doc for details. + +29. The match function takes an optional array third argument to hold + the text matched by parenthesized sub-expressions. + +30. The bit op functions and octal and hex source code constants are on by + default, no longer a configure-time option. Recognition of non-decimal + data is now enabled at runtime with --non-decimal-data command line option. + +31. Internationalization features available at the awk level: new TEXTDOMAIN + variable and `bindtextdomain' and `dcgettext' functions. printf formats + may contain the "%2$3.5d" kind of notation for use in translations. See + the texinfo manual for details. + +32. The return value from `close' has been rationalized. Most notably, + closing something that wasn't open returns -1 but remains non-fatal. + +33. The array effeciency change from 3.0.5 was reverted; the semantics were + not right. Additionally, index values of previously stored elements + can no longer change dynamically. + +34. The new option --dump-variables dumps a list of all global variables and + their final types and values to a file you give, or to `awkvars.out'. + +35. Gawk now uses a recent version of random.c courtesy of the FreeBSD + project. + +36. The gawk source code now uses ANSI C function definitions (new style), + with ansi2knr to translate code for old compilers. + +37. `for (iggy in foo)' loops should be more robust now in the face of + adding/deleting elements in the middle; they loop over just the elements + that are present in the array when the loop starts. + +Changes from 3.0.5 to 3.0.6 +--------------------------- + +This is a bug fix release only, pending further development on 3.1.0. + +Bugs fixed and changes made: + +1. Subscripting an array with a variable that is just a number no + longer magically converts the variable into a string. + +2. Similarly, running a `for (iggy in foo)' loop where `foo' is a + function parameter now works correctly. + +3. Similarly, `i = ""; v[i] = a; if (i in v) ...' now works again. + +4. Gawk now special cases `for (iggy in foo) delete foo[iggy]' and + treats it as the moral equivalent of `delete foo'. This should be + a major efficiency win when portably deleting large arrays. + +5. VMS port brought up to date. + +Changes from 3.0.4 to 3.0.5 +--------------------------- + +This is a bug fix release only, pending further development on 3.1.0. + +Bugs Fixed: + + 1. `function foo(foo)' is now a fatal error. + + 2. Array indexing is now much more efficient: where possible, only one + copy of an index string is kept, even if used in multiple arrays. + + 3. Support was added for MacOS X and an `install-strip' target. + + 4. [s]printf formatting for `0' flag and floating point formats now + works correctly. + + 5. HP-UX large file support with GCC 2.95.1 now works. + + 6. Arguments that contain `=' but that aren't syntactically valid are + now treated as filenames, instead of as fatal errors. + + 7. `-v NF=foo' now works. + + 8. Non-ascii alphanumeric characters are now treated as such in the + right locales by regex.c. Similarly, a Latin-1 y-umlaut (decimal + value 255) in the program text no longer acts like EOF. + + 9. Array indexes are always compared as strings; fixes an obscure bug + when user input gets used for the `x in array' test. + +10. The usage message now points users to the documentation for how + to report bugs. + +11. `/=' now works after an array. + +12. `b += b += 1' now works correctly. + +13. IGNORECASE changing with calls `match' now works better. (Fix for + semi-obscure bug.) + +14. Multicharacter values for RS now generate a lint warning. + +15. The gawk open file caching is now much more efficient. + +16. Global arrays passed to functions are now managed better. In particular, + test/arynocls.awk won't crash referencing freed memory. + +17. In obscure cases, `getline var' can no longer clobber $0. + +Changes from 3.0.3 to 3.0.4 +--------------------------- + +This is a bug fix release only, pending further development on 3.1.0. + +Bugs Fixed: + + 1. A memory leak when turning a function parameter into an array was + fixed. + + 2. The non-decimal data option now works correctly. + + 3. Using an empty pair of brackets as an array subscript no longer causes + a core dump during parsing. In general, syntax errors should not + cause core dumps any more. + + 4. Standard input is no longer closed if it provides program source, + avoiding strange I/O problems. + + 5. Memory corruption during printing with `print' has been fixed. + + 6. The gsub function now correctly counts the number of matches. + + 7. A typo in doc/Makefile.in has been fixed, making installation work. + + 8. Calling `next' or `nextfile' from a BEGIN or END rule is now fatal. + + 9. Subtle problems in rebuilding $0 when fields were changed have been + fixed. + +10. `FS = FS' now correctly turns off the use of FIELDWIDTHS. + +11. Gawk now parses fields correctly when FS is a single character. + +12. It is now possible for RS to be the NUL character ("\0"). + +13. Weird problems with number conversions on MIPS and other systems + have been fixed. + +14. When parsing using FIELDWIDTHS is in effect, `split' with no third + argument will still use the value of FS. + +15. Large File Support for Solaris, HP-UX, AIX, and IRIX is now enabled at + compile time, thanks to Paul Eggert. + +16. Attempting to use the name of a function as a variable or array + from within the function is now caught as a fatal error, instead + of as a core dump. + +17. A bug in parsing hex escapes was fixed. + +18. A weird bug with concatenation where one expression has side effects + that changes another was fixed. + +19. printf/sprintf now behave much better for uses of the '0' and '#' flags + and with precisions and field widths. + +20. Further strangenesses with concatenation and multiple accesses of some + of the special variables was fixed. + +21. The Atari port is marked as no longer supported. + +22. Build problems on HP-UX have been fixed. + +23. Minor fixes and additional explanations added to the documentation. + +24. For RS = "", even a single leading newline is now correctly stripped. + +25. Obscure parsing problems for regex constants like /=.../ fixed, so + that a regex constant is recognized, and not the /= operator. + +26. Fixed a bug when closing a redirection that matched the current + or last FILENAME. + +27. Build problems on AIX fixed. + +Changes from 3.0.2 to 3.0.3 +--------------------------- + +The horrendous per-record memory leak introduced in 3.0.1 is gone, finally. + +The `amiga' directory is now gone; Amiga support is now entirely handled +by the POSIX support. + +Windows32 support has been added in the `pc' directory. See `README_d/README.pc' +for more info. + +The mmap changes are disabled in io.c, and will be removed entirely +in the next big release. They were an interesting experiment that just +really didn't work in practice. + +A minor memory leak that occurred when using `next' from within a +function has also been fixed. + +Problems with I/O from sub-processes via a pipe are now gone. + +Using "/dev/pid" and the other special /dev files no longer causes a core dump. + +The files regex.h, regex.c, getopt.h, getopt.c, and getopt1.c have been +merged with the versions in GNU libc. Thanks to Ulrich Drepper for his help. + +Some new undocumented features have been added. Use the source, Luke! +It is not clear yet whether these will ever be fully supported. + +Array performance should be much better for very very large arrays. "Virtual +memory required, real memory helpful." + +builtin.c:do_substr rationalized, again. + +The --re-interval option now works as advertised. + +The license text on some of the missing/* files is now generic. + +Lots more new test cases. + +Lots of other small bugs fixed, see the ChangeLog files for details. + +Changes from 3.0.1 to 3.0.2 +--------------------------- + +Gawk now uses autoconf 2.12. + +strftime now behaves correctly if passed an empty format string or if +the string formats to an empty result string. + +Several minor compilation and installation problems have been fixed. + +Minor page break issues in the user's guide have been fixed. + +Lexical errors no longer repeat ad infinitum. + +Changes from 3.0.0 to 3.0.1 +--------------------------- + +Troff source for a handy-dandy five color reference card is now provided. +Thanks to SSC for their macros. + +Gawk now behaves like Unix awk and mawk, in that newline acts as white +space for separating fields and for `split', by default. In posix mode, +only space and tab separate fields. The documentation has been updated to +reflect this. + +Tons and tons of small bugs fixed and new tests added, see the ChangeLogs. + +Lots fewer compile time warnings from gcc -Wall. Remaining ones aren't +worth fixing. + +Gawk now pays some attention to the locale settings. + +Fixes to gsub to catch several corner cases. + +The `print' statement now evaluates all expressions first, and then +prints them. This leads to less suprising behaviour if any expression has +output side effects. + +Miscellanious improvements in regex.h and regex.c. + +Gawk will now install itself as gawk-M.N.P in $(bindir), and link +`gawk' to it. This makes it easy to have multiple versions of gawk +simultaneously. It will also now install itself as `awk' in $(bindir) +if there is no `awk' there. This is in addition to installing itself as +`gawk'. This change benefits the Hurd, and possibly other systems. One +day, gawk will drop the `g', but not yet. + +`--posix' turns on interval expressions. Gawk now matches its documentation. + +`close(FILENAME)' now does something meaningful. + +Field management code in field.c majorly overhauled, several times. + +The gensub code has been fixed, several bugs are now gone. + +Gawk will use mmap for data file input if it is available. + +The printf/sprintf code has been improved. + +Minor issues in Makefile setup worked on and improved. + +builtin.c:do_substr rationalized. + +Regex matching fixed so that /+[0-9]/ now matches the leading +. + +For building on vms, the default compiler is now DEC C rather than VAX C. + +Changes from 2.15.6 to 3.0.0 +---------------------------- + +Fixed spelling of `Programming' in the copyright notice in all the files. + +New --re-interval option to turn on interval expressions. They're off +by default, except for --posix, to avoid breaking old programs. + +Passing regexp constants as parameters to user defined functions now +generates a lint warning. + +Several obscure regexp bugs fixed; alas, a small number remain. + +The manual has been thoroughly revised. It's now almost 50% bigger than +it used to be. + +The `+' modifier in printf is now reset correctly for each item. + +The do_unix variable is now named do_traditional. + +Handling of \ in sub and gsub rationalized (somewhat, see the manual for +the gory [and I do mean gory] details). + +IGNORECASE now uses ISO 8859-1 Latin-1 instead of straight ASCII. See the +source for how to revert to pure ASCII. + +--lint will now warn if an assignment occurs in a conditional context. +This may become obnoxious enough to need turning off in the future, but +"it seemed like a good idea at the time." + +%hf and %Lf are now diagnosed as invalid in printf, just like %lf. + +Gawk no longer incorrectly closes stdin in child processes used in +input pipelines. + +For integer formats, gawk now correctly treats the precision as the +number of digits to print, not the number of characters. + +gawk is now much better at catching the use of scalar values when +arrays are needed, both in function calls and the `x in y' constructs. + +New gensub function added. See the manual. + +If do_tradtional is true, octal and hex escapes in regexp constants are +treated literally. This matches historical behavior. + +yylex/nextc fixed so that even null characters can be included +in the source code. + +do_format now handles cases where a format specifier doesn't end in +a control letter. --lint reports an error. + +strftime() now uses a default time format equivalent to that of the +Unix date command, thus it can be called with no arguments. + +Gawk now catches functions that are used but not defined at parse time +instead of at run time. (This is a lint error, making it fatal could break +old code.) + +Arrays that max out are now handled correctly. + +Integer formats outside the range of an unsigned long are now detected +correctly using the SunOS 4.x cc compiler. + +--traditional option added as new preferred name for --compat, in keeping +with GCC. + +--lint-old option added, so that warnings about things not in old awk +are only given if explicitly asked for. + +`next file' has changed to one word, `nextfile'. `next file' is still +accepted but generates a lint warning. `next file' will go away eventually. + +Gawk with --lint will now notice empty source files and empty data files. + +Amiga support using the Unix emulation added. Thanks to fnf@ninemoons.com. + +test/Makefile is now "parallel-make safe". + +Gawk now uses POSIX regexps + GNU regex ops by default. --posix goes to +pure posix regexps, and --compat goes to traditional Unix regexps. However, +interval expressions, even though specified by POSIX, are turned off by +default, to avoid breaking old code. + +IGNORECASE now applies to string comparison as well as regexp operations. + +The AT&T Bell Labs Research awk fflush builtin function is now supported. +fflush is extended to flush stdout if no arg and everything if given +the null string as an argument. + +If RS is more than one character, it is treated as a regular expression +and records are delimited accordingly. The variable RT is set to the record +terminator string. This is disabled in compatibility mode. + +If FS is set to the null string (or the third arg. of split() is the null +string), splitting is done at every single character. This is disabled in +compatibility mode. + +Gawk now uses the Autoconf generated configure script, doing away with all +the config/* files and the machinery that went with them. The Makefile.in +has also changed accordingly, complete with all the standard GNU Makefile +targets. (Non-unix systems may still have their own config.h and Makefile; +see the appropriate README_d/README.* and/or subdirectory.) + +The source code has been cleaned up somewhat and the formatting improved. + +Changes from 2.15.5 to 2.15.6 +----------------------------- + +Copyrights updated on all changed files. + +test directory enhanced with four new tests. + +Gawk now generates a warning for \x without following hexadecimal digits. +In this case, it returns 'x', not \0. + +Several fixes in main.c related to variable initialization: + CONVFMT has a default value + resetup is called before initializing variables + the varinit table fixed up a bit (see the comments) + +gawk.1 updated with new BUG REPORTS section. + +A plain `print' inside a BEGIN or END now generates a lint warning (awk.y). + +Small fix in iop.c:get_a_record to avoid reading uninitialized memory. + +awk.y:yylex now does a better job of handling things if the source file +does not end in a newline. Probably there is more work to be done. + +Memory leaks fixed in awk.y, particularly in cases of duplicate function +parameters. Also, calling a function doesn't leak memory during parsing. + +Empty function bodies are now allowed (awk.y). + +Gawk now detects duplicate parameter names in functions (awk.y). + +New function `error' in msg.c added for use from awk.y. + +eval.c:r_get_lhs now checks if its argument is a parameter on the stack, +and pulls down the real variable. This catches more 'using an array as +a scalar' kinds of errors. + +main.c recovers C alloca space after parsing, this is important for +bison-based parsers. re.c recovers C alloca space after doing an research. +[Changes from Pat Rankin] + +builtin.c now declares the random() related functions based on +RANDOM_MISSING from config.h. [Suggested by Pat Rankin] + +awk.h now handles alloca correctly for HP-UX. [Kaveh Ghazi] + +regex.h and config/cray60 updated for Unicos 8.0. [Hal Peterson] + +Fixed re.c and dfa.c so that gawk no longer leaks memory when using +lots of dynamic regexps. + +Removed dependency on signed chars from `idx' variable in awk.h. Gawk +now passes its test suite if compiled with `gcc -fno-signed-char'. + +Fixed warning on close in io.c to go under lint control. Too many people +have complained about the spurious message, particularly when closing a +child pipeline early. + +Gawk now correctly handles RS = "" when input is from a terminal +(iop.c:get_a_record). + +Config file added for GNU. + +gawk 'BEGIN { exit 1 } ; END { exit }' now exits 1, as it should +(eval.c:interpret). + +sub and gsub now follow posix, \ escapes both & and \. Each \ must +be doubled initially in the program to get it into the string. +Thanks to Mike Brennan for pointing this out (builtin.c:sub_common). + +If FS is "", gawk behaves like mawk and nawk, making the whole record be $1. +Yet Another Dark Corner. Sigh (field.c:def_parse_field). + +Gawk now correctly recomputes string values for numbers if CONVFMT has +changed (awk.h:force_string, node.c:r_force_string). + +A regexp of the form `/* this looks like a comment but is not */' will +now generate a warning from --lint (awk.y). + +Gawk will no longer core dump if given an empty input file (awk.y:get_src_buf, +iop.c:optimal_bufsize). + +A printf format of the form %lf is handled correctly. The `l' generates +a lint warning (builtin.c:format_tree) [Thanks to Mark Moraes]. + +Lynxos config file added. + +`continue' outside a loop treated as `next' only in compatibility mode, +instead of by default; recent att nawk chokes on this now. `break' +outside a loop now treated as `next' in compatibility mode (eval.c). + +Bug fix in string concatenation, an arbitrary number of expressions +are allowed (eval.c). + +$1 += $2 now works correctly (eval.c). + +Changing IGNORECASE no longer resets field-splitting to FS if it was +using FIELDWIDTHS (eval.c, field.c). + +Major enhancement: $0 and NF for last record read are now preserved +into the END rule (io.c). + +Regexp fixes: + /./ now matches a newline (regex.h) + ^ and $ match beginning and end of string only, not any embedded + newlines (re.c) + regex.c should compile and work ok on 64-bit mips/sgi machines + +Changes from 2.15.4 to 2.15.5 +----------------------------- + +FUTURES file updated and re-arranged some with more rational schedule. + +Many prototypes handled better for ANSI C in protos.h. + +getopt.c updated somewhat. + +test/Makefile now removes junk directory, `bardargtest' renamed `badargs.' + +Bug fix in iop.c for RS = "". Eat trailing newlines off of record separator. + +Bug fix in Makefile.bsd44, use leading tab in actions. + +Fix in field.c:set_FS for FS == "\\" and IGNORECASE != 0. + +Config files updated or added: + cray60, DEC OSF/1 2.0, Utek, sgi405, next21, next30, atari/config.h, + sco. + +Fix in io.c for ENFILE as well as EMFILE, update decl of groupset to +include OSF/1. + +Rationalized printing as integers if numbers are outside the range of a long. +Changes to node.c:force_string and builtin.c. + +Made internal NF, NR, and FNR variables longs instead of ints. + +Add LIMITS_H_MISSING stuff to config.in and awk.h, and default defs for +INT_MAX and LONG_MAX, if no limits.h file. Add a standard decl of +the time() function for __STDC__. From ghazi@noc.rutgers.edu. + +Fix tree_eval in awk.h and r_tree_eval in eval.c to deal better with +function parameters, particularly ones that are arrays. + +Fix eval.c to print out array names of arrays used in scalar contexts. + +Fix eval.c in interpret to zero out source and sourceline initially. This +does a better job of providing source file and line number information. + +Fix to re_parse_field in field.c to not use isspace when RS = "", but rather +to explicitly look for blank and tab. + +Fix to sc_parse_field in field.c to catch the case of the FS character at the +end of a record. + +Lots of miscellanious bug fixes for memory leaks, courtesy Mark Moraes, +also fixes for arrays. + +io.c fixed to warn about lack of explicit closes if --lint. + +Updated missing/strftime.c to match posted strftime 6.2. + +Bug fix in builtin.c, in case of non-match in sub_common. + +Updated constant used for division in builtin.c:do_rand for DEC Alpha +and CRAY Y-MP. + +POSIXLY_CORRECT in the environment turns on --posix (fixed in main.c). + +Updated srandom prototype and calls in builtin.c. + +Fix awk.y to enforce posix semantics of unary +: result is numeric. + +Fix array.c to not rearrange the hash chain upon finding an index in +the array. This messed things up in cases like: + for (index1 in array) { + blah + if (index2 in array) # blew away the for + stuff + } + +Fixed spelling errors in the man page. + +Fixes in awk.y so that + gawk '' /path/to/file +will work without core dumping or finding parse errors. + +Fix main.c so that --lint will fuss about an empty program. +Yet another fix for argument parsing in the case of unrecognized options. + +Bug fix in dfa.c to not attempt to free null pointers. + +Bug fix in builtin.c to only use DEFAULT_G_PRECISION for %g or %G. + +Bug fix in field.c to achieve call by value semantics for split. + +Changes from 2.15.3 to 2.15.4 +----------------------------- + +Lots of lint fixes, and do_sprintf made mostly ANSI C compatible. + +Man page updated and edited. + +Copyrights updated. + +Arrays now grow dynamically, initially scaling up by an order of magnitude + and then doubling, up to ~ 64K. This should keep gawk's performance + graceful under heavy load. + +New `delete array' feature added. Only documented in the man page. + +Switched to dfa and regex suites from grep-2.0. These offer the ability to + move to POSIX regexps in the next release. + +Disabled GNU regex ops. + +Research awk -m option now recognized. It does nothing in gawk, since gawk + has no static limits. Only documented in the man page. + +New bionic (faster, better, stronger than before) hashing function. + +Bug fix in argument handling. `gawk -X' now notices there was no program. + Additional bug fixes to make --compat and --lint work again. + +Many changes for systems where sizeof(int) != sizeof(void *). + +Add explicit alloca(0) in io.c to recover space from C alloca. + +Fixed file descriptor leak in io.c. + +The --version option now follows the GNU coding standards and exits. + +Fixed several prototypes in protos.h. + +Several tests updated. On Solaris, warn that the out? tests will fail. + +Configuration files for SunOS with cc and Solaris 2.x added. + +Improved error messages in awk.y on gawk extensions if do_unix or do_compat. + +INSTALL file added. + +Fixed Atari Makefile and several VMS specific changes. + +Better conversion of numbers to strings on systems with broken sprintfs. + +Changes from 2.15.2 to 2.15.3 +----------------------------- + +Increased HASHSIZE to a decent number, 127 was way too small. + +FILENAME is now the null string in a BEGIN rule. + +Argument processing fixed for invalid options and missing arguments. + +This version will build on VMS. This included a fix to close all files + and pipes opened with redirections before closing stdout and stderr. + +More getpgrp() defines. + +Changes for BSD44: in io.c and Makefile.bsd44. + +All directories in the distribution are now writable. + +Separated LDFLAGS and CFLAGS in Makefile. CFLAGS can now be overridden by + user. + +Make dist now builds compressed archives ending in .gz and runs doschk. + +Amiga port. + +New getopt.c fixes Alpha OSF/1 problem. + +Make clean now removes possible test output. + +Improved algorithm for multiple adjacent string concatenations leads to + performance improvements. + +Fix nasty bug whereby command-line assignments, both with -v and at run time, + could create variables with syntactically illegal names. + +Fix obscure bug in printf with %0 flag and filling. + +Add a lint check for substr if provided length exceeds remaining characters + in string. + +Update atari support. + +PC support enhanced to include support for both DOS and OS/2. (Lots more + #ifdefs. Sigh.) + +Config files for Hitachi Unix and OSF/1, courtesy of Yoko Morishita + (morisita@sra.co.jp) + +Changes from 2.15.1 to 2.15.2 +----------------------------- + +Additions to the FUTURES file. + +Document undefined order of output when using both standard output + and /dev/stdout or any of the /dev output files that gawk emulates in + the absence of OS support. + +Clean up the distribution generation in Makefile.in: the info files are + now included, the distributed files are marked read-only and patched + distributions are now unpacked in a directory named with the patch level. + +Changes from 2.15 to 2.15.1 +--------------------------- + +Close stdout and stderr before all redirections on program exit. This allows + detection of write errors and also fixes the messages test on Solaris 2.x. + +Removed YYMAXDEPTH define in awk.y which was limiting the parser stack depth. + +Changes to config/bsd44, Makefile.bsd44 and configure to bring it into line + with the BSD4.4 release. + +Changed Makefile to use prefix, exec_prefix, bindir etc. + +make install now installs info files. + +make install now sets permissions on installed files. + +Make targets added: uninstall, distclean, mostlyclean and realclean. + +Added config.h to cleaner and clobber make targets. + +Changes to config/{hpux8x,sysv3,sysv4,ultrix41} to deal with alloca(). + +Change to getopt.h for portability. + +Added more special cases to the getpgrp() call. + +Added README.ibmrt-aos and config/ibmrt-aos. + +Changes from 2.14 to 2.15 +--------------------------- + +Command-line source can now be mixed with library functions. + +ARGIND variable tracks index in ARGV of FILENAME. + +GNU style long options in addition to short options. + +Plan 9 style special files interpreted by gawk: + /dev/pid + /dev/ppid + /dev/pgrpid + /dev/user + $1 = getuid + $2 = geteuid + $3 = getgid + $4 = getegid + $5 ... $NF = getgroups if supported + +ERRNO variable contains error string if getline or close fails. + +Very old options -a and -e have gone away. + +Inftest has been removed from the default target in test/Makefile -- the + results were too machine specific and resulted in too many false alarms. + +A README.amiga has been added. + +The "too many arguments supplied for format string" warning message is only + in effect under the lint option. + +Code improvements in dfa.c. + +Fixed all reported bugs: + + Writes are checked for failure (such as full filesystem). + + Stopped (at least some) runaway error messages. + + gsub(/^/, "x") does the right thing for $0 of 0, 1, or more length. + + close() on a command being piped to a getline now works properly. + + The input record will no longer be freed upon an explicit close() + of the input file. + + A NUL character in FS now works. + + In a substitute, \\& now means a literal backslash followed by what + was matched. + + Integer overflow of substring length in substr() is caught. + + An input record without a newline termination is handled properly. + + In io.c, check is against only EMFILE so that system file table + is not filled. + + Renamed all files with names longer than 14 characters. + + Escaped characters in regular expressions were being lost when + IGNORECASE was used. + + Long source lines were not being handled properly. + + Sourcefiles that ended in a tab but no newline were bombing. + + Patterns that could match zero characters in split() were not working + properly. + + The parsedebug option was not working. + + The grammar was being a bit too lenient, allowing some very dubious + programs to pass. + + Compilation with DEBUG defined now works. + + A variable read in with getline was not being treated as a potential + number. + + Array subscripts were not always of string type. + + +Changes from 2.13.2 to 2.14 +--------------------------- + +Updated manual! + +Added "next file" to skip efficiently to the next input file. + +Fixed potential of overflowing buffer in do_sprintf(). + +Plugged small memory leak in sub_common(). + +EOF on a redirect is now "sticky" -- it can only be cleared by close()ing + the pipe or file. + +Now works if used via a #! /bin/gawk line at the top of an executable file + when that line ends with whitespace. + +Added some checks to the grammar to catch redefinition of builtin functions. + This could eventually be the basis for an extension to allow redefining + functions, but in the mean time it's a good error catching facility. + +Negative integer exponents now work. + +Modified do_system() to make sure it had a non-null string to be passed + to system(3). Thus, system("") will flush any pending output but not go + through the overhead of forking an un-needed shell. + +A fix to floating point comparisons so that NaNs compare right on IEEE systems. + +Added code to make sure we're not opening directories for reading and such. + +Added code to do better diagnoses of weird or null file names. + +Allow continue outside of a loop, unless in strict posix mode. Lint option + will issue warning. + +New missing/strftime.c. There has been one change that affects gawk. Posix + now defines a %V conversion so the vms conversion has been changed to %v. + If this version is used with gawk -Wlint and they use %V in a call to + strftime, they'll get a warning. + +Error messages now conform to GNU standard (I hope). + +Changed comparisons to conform to the description found in the file POSIX. + This is inconsistent with the current POSIX draft, but that is broken. + Hopefully the final POSIX standard will conform to this version. + (Alas, this will have to wait for 1003.2b, which will be a revision to + the 1003.2 standard. That standard has been frozen with the broken + comparison rules.) + +The length of a string was a short and now is a size_t. + +Updated VMS help. + +Added quite a few new tests to the test suite and deleted many due to lack of + written releases. Test output is only removed if it is identical to the + "good" output. + +Fixed a couple of bugs for reference to $0 when $0 is "" -- particularly in + a BEGIN block. + +Fixed premature freeing in construct "$0 = $0". + +Removed the call to wait_any() in gawk_popen(), since on at least some systems, + if gawk's input was from a pipe, the predecessor process in the pipe was a + child of gawk and this caused a deadlock. + +Regexp can (once again) match a newline, if given explicitly. + +nextopen() makes sure file name is null terminated. + +Fixed VMS pipe simulation. Improved VMS I/O performance. + +Catch . used in variable names. + +Fixed bug in getline without redirect from a file -- it was quitting after the + first EOF, rather than trying the next file. + +Fixed bug in treatment of backslash at the end of a string -- it was bombing + rather than doing something sensible. It is not clear what this should mean, + but for now I issue a warning and take it as a literal backslash. + +Moved setting of regexp syntax to before the option parsing in main(), to + handle things like -v FS='[.,;]' + +Fixed bug when NF is set by user -- fields_arr must be expanded if necessary + and "new" fields must be initialized. + +Fixed several bugs in [g]sub() for no match found or the match is 0-length. + +Fixed bug where in gsub() a pattern anchored at the beginning would still + substitute throughout the string. + +make test does not assume that . is in PATH. + +Fixed bug when a field beyond the end of the record was requested after + $0 was altered (directly or indirectly). + +Fixed bug for assignment to field beyond end of record -- the assigned value + was not found on subsequent reference to that field. + +Fixed bug for FS a regexp and it matches at the end of a record. + +Fixed memory leak for an array local to a function. + +Fixed hanging of pipe redirection to getline + +Fixed coredump on access to $0 inside BEGIN block. + +Fixed treatment of RS = "". It now parses the fields correctly and strips + leading whitespace from a record if FS is a space. + +Fixed faking of /dev/stdin. + +Fixed problem with x += x + +Use of scalar as array and vice versa is now detected. + +IGNORECASE now obeyed for FS (even if FS is a single alphabetic character). + +Switch to GPL version 2. + +Renamed awk.tab.c to awktab.c for MSDOS and VMS tar programs. + +Renamed this file (CHANGES) to NEWS. + +Use fmod() instead of modf() and provide FMOD_MISSING #define to undo + this change. + +Correct the volatile declarations in eval.c. + +Avoid errant closing of the file descriptors for stdin, stdout and stderr. + +Be more flexible about where semi-colons can occur in programs. + +Check for write errors on all output, not just on close(). + +Eliminate the need for missing/{strtol.c,vprintf.c}. + +Use GNU getopt and eliminate missing/getopt.c. + +More "lint" checking. + + +Changes from 2.13.1 to 2.13.2 +----------------------------- + +Toward conformity with GNU standards, configure is a link to mkconf, the latter + to disappear in the next major release. + +Update to config/bsd43. + +Added config/apollo, config/msc60, config/cray2-50, config/interactive2.2 + +sgi33.cc added for compilation using cc rather than gcc. + +Ultrix41 now propagates to config.h properly -- as part of a general + mechanism in configure for kludges -- #define anything from a config file + just gets tacked onto the end of config.h -- to be used sparingly. + +Got rid of an unnecessary and troublesome declaration of vprintf(). + +Small improvement in locality of error messages. + +Try to diagnose use of array as scalar and vice versa -- to be improved in + the future. + +Fix for last bug fix for Cray division code--sigh. + +More changes to test suite to explicitly use sh. Also get rid of + a few generated files. + +Fixed off-by-one bug in string concatenation code. + +Fix for use of array that is passed in from a previous function parameter. + Addition to test suite for above. + +A number of changes associated with changing NF and access to fields + beyond the end of the current record. + +Change to missing/memcmp.c to avoid seg. fault on zero length input. + +Updates to test suite (including some inadvertently left out of the last patch) + to invoke sh explicitly (rather than rely on #!/bin/sh) and remove some + junk files. test/chem/good updated to correspond to bug fixes. + +Changes from 2.13.0 to 2.13.1 +----------------------------- + +More configs and PORTS. + +Fixed bug wherein a simple division produced an erroneous FPE, caused by + the Cray division workaround -- that code is now #ifdef'd only for + Cray *and* fixed. + +Fixed bug in modulus implementation -- it was very close to the above + code, so I noticed it. + +Fixed portability problem with limits.h in missing.c + +Fixed portability problem with tzname and daylight -- define TZNAME_MISSING + if strftime() is missing and tzname is also. + +Better support for Latin-1 character set. + +Fixed portability problem in test Makefile. + +Updated PROBLEMS file. + +=============================== gawk-2.13 released ========================= +Changes from 2.12.42 to 2.12.43 +------------------------------- + +Typo in awk.y + +Fixed up strftime.3 and added doc. for %V. + +Changes from 2.12.41 to 2.12.42 +------------------------------- + +Fixed bug in devopen() -- if you had write permission in /dev, + it would just create /dev/stdout etc.!! + +Final (?) VMS update. + +Make NeXT use GFMT_WORKAROUND + +Fixed bug in sub_common() for substitute on zero-length match. Improved the + code a bit while I was at it. + +Fixed grammar so that $i++ parses as ($i)++ + +Put support/* back in the distribution (didn't I already do this?!) + +Changes from 2.12.40 to 2.12.41 +------------------------------- + +VMS workaround for broken %g format. + +Changes from 2.12.39 to 2.12.40 +------------------------------- + +Minor man page update. + +Fixed latent bug in redirect(). + +Changes from 2.12.38 to 2.12.39 +------------------------------- + +Updates to test suite -- remove dependence on changing gawk.1 man page. + +Changes from 2.12.37 to 2.12.38 +------------------------------- + +Fixed bug in use of *= without whitespace following. + +VMS update. + +Updates to man page. + +Option handling updates in main.c + +test/manyfiles redone and added to bigtest. + +Fixed latent (on Sun) bug in handling of save_fs. + +Changes from 2.12.36 to 2.12.37 +------------------------------- + +Update REL in Makefile-dist. Incorporate test suite into main distribution. + +Minor fix in regtest. + +Changes from 2.12.35 to 2.12.36 +------------------------------- + +Release takes on dual personality -- 2.12.36 and 2.13.0 -- any further + patches before public release won't count for 2.13, although they will for + 2.12 -- be careful to avoid confusion! patchlevel.h will be the last thing + to change. + +Cray updates to deal with arithmetic problems. + +Minor test suite updates. + +Fixed latent bug in parser (freeing memory). + +Changes from 2.12.34 to 2.12.35 +------------------------------- + +VMS updates. + +Flush stdout at top of err() and stderr at bottom. + +Fixed bug in eval_condition() -- it wasn't testing for MAYBE_NUM and + doing the force_number(). + +Included the missing manyfiles.awk and a new test to catch the above bug which + I am amazed wasn't already caught by the test suite -- it's pretty basic. + +Changes from 2.12.33 to 2.12.34 +------------------------------- + +Atari updates -- including bug fix. + +More VMS updates -- also nuke vms/version.com. + +Fixed bug in handling of large numbers of redirections -- it was probably never + tested before (blush!). + +Minor rearrangement of code in r_force_number(). + +Made chem and regtest tests a bit more portable (Ultrix again). + +Added another test -- manyfiles -- not invoked under any other test -- very Unix + specific. + +Rough beginning of LIMITATIONS file -- need my AWK book to complete it. + +Changes from 2.12.32 to 2.12.33 +------------------------------- + +Expunge debug.? from various files. + +Remove vestiges of Floor and Ceil kludge. + +Special case integer division -- mainly for Cray, but maybe someone else + will benefit. + +Workaround for iop_close closing an output pipe descriptor on Cray -- + not conditional since I think it may fix a bug on SGI as well and I don't + think it can hurt elsewhere. + +Fixed memory leak in assoc_lookup(). + +Small cleanup in test suite. + +Changes from 2.12.31 to 2.12.32 +------------------------------- + +Nuked debug.c and debugging flag -- there are better ways. + +Nuked version.sh and version.c in subdirectories. + +Fixed bug in handling of IGNORECASE. + +Fixed bug when FIELDWIDTHS was set via -v option. + +Fixed (obscure) bug when $0 is assigned a numerical value. + +Fixed so that escape sequences in command-line assignments work (as it already + said in the comment). + +Added a few cases to test suite. + +Moved support/* back into distribution. + +VMS updates. + +Changes from 2.12.30 to 2.12.31 +------------------------------- + +Cosmetic manual page changes. + +Updated sunos3 config. + +Small changes in test suite including renaming files over 14 chars. in length. + +Changes from 2.12.29 to 2.12.30 +------------------------------- + +Bug fix for many string concatenations in a row. + +Changes from 2.12.28 to 2.12.29 +------------------------------- + +Minor cleanup in awk.y + +Minor VMS update. + +Minor atari update. + +Changes from 2.12.27 to 2.12.28 +------------------------------- + +Got rid of the debugging goop in eval.c -- there are better ways. + +Sequent port. + +VMS changes left out of the last patch -- sigh! config/vms.h renamed + to config/vms-conf.h. + +Fixed missing/tzset.c + +Removed use of gcvt() and GCVT_MISSING -- turns out it was no faster than + sprintf("%g") and caused all sorts of portability headaches. + +Tuned get_field() -- it was unnecessarily parsing the whole record on reference + to $0. + +Tuned interpret() a bit in the rule_node loop. + +In r_force_number(), worked around bug in Uglix strtod() and got rid of + ugly do{}while(0) at Michal's urging. + +Replaced do_deref() and deref with unref(node) -- much cleaner and a bit faster. + +Got rid of assign_number() -- contrary to comment, it was no faster than + just making a new node and freeing the old one. + +Replaced make_number() and tmp_number() with macros that call mk_number(). + +Changed freenode() and newnode() into macros -- the latter is getnode() + which calls more_nodes() as necessary. + +Changes from 2.12.26 to 2.12.27 +------------------------------- + +Completion of Cray 2 port (includes a kludge for floor() and ceil() + that may go or be changed -- I think that it may just be working around + a bug in chem that is being tweaked on the Cray). + +More VMS updates. + +Moved kludge over yacc's insertion of malloc and realloc declarations + from protos.h to the Makefile. + +Added a lisp interpreter in awk to the test suite. (Invoked under + bigtest.) + +Cleanup in r_force_number() -- I had never gotten around to a thorough + profile of the cache code and it turns out to be not worth it. + +Performance boost -- do lazy force_number()'ing for fields etc. i.e. + flag them (MAYBE_NUM) and call force_number only as necessary. + +Changes from 2.12.25 to 2.12.26 +------------------------------- + +Rework of regexp stuff so that dynamic regexps have reasonable + performance -- string used for compiled regexp is stored and + compared to new string -- if same, no recompilation is necessary. + Also, very dynamic regexps cause dfa-based searching to be turned + off. + +Code in dev_open() is back to returning fileno(std*) rather than + dup()ing it. This will be documented. Sorry for the run-around + on this. + +Minor atari updates. + +Minor vms update. + +Missing file from MSDOS port. + +Added warning (under lint) if third arg. of [g]sub is a constant and + handle it properly in the code (i.e. return how many matches). + +Changes from 2.12.24 to 2.12.25 +------------------------------- + +MSDOS port. + +Non-consequential changes to regexp variables in preparation for + a more serious change to fix a serious performance problem. + +Changes from 2.12.23 to 2.12.24 +------------------------------- + +Fixed bug in output flushing introduced a few patches back. This caused + serious performance losses. + +Changes from 2.12.22 to 2.12.23 +------------------------------- + +Accidentally left config/cray2-60 out of last patch. + +Added some missing dependencies to Makefile. + +Cleaned up mkconf a bit; made yacc the default parser (no alloca needed, + right?); added rs6000 hook for signed characters. + +Made regex.c with NO_ALLOCA undefined work. + +Fixed bug in dfa.c for systems where free(NULL) bombs. + +Deleted a few cant_happen()'s that *really* can't hapen. + +Changes from 2.12.21 to 2.12.22 +------------------------------- + +Added to config stuff the ability to choose YACC rather than bison. + +Fixed CHAR_UNSIGNED in config.h-dist. + +Second arg. of strtod() is char ** rather than const char **. + +stackb is now initially malloc()'ed since it may be realloc()'ed. + +VMS updates. + +Added SIZE_T_MISSING to config stuff and a default typedef to awk.h. + (Maybe it is not needed on any current systems??) + +re_compile_pattern()'s size is now size_t unconditionally. + +Changes from 2.12.20 to 2.12.21 +------------------------------- + +Corrected missing/gcvt.c. + +Got rid of use of dup2() and thus DUP_MISSING. + +Updated config/sgi33. + +Turned on (and fixed) in cmp_nodes() the behaviour that I *hope* will be in + POSIX 1003.2 for relational comparisons. + +Small updates to test suite. + +Changes from 2.12.19 to 2.12.20 +------------------------------- + +Sloppy, sloppy, sloppy!! I didn't even try to compile the last two + patches. This one fixes goofs in regex.c. + +Changes from 2.12.18 to 2.12.19 +------------------------------- + +Cleanup of last patch. + +Changes from 2.12.17 to 2.12.18 +------------------------------- + +Makefile renamed to Makefile-dist. + +Added alloca() configuration to mkconf. (A bit kludgey.) Just + add a single line containing ALLOCA_PW, ALLOCA_S or ALLOCA_C + to the appropriate config file to have Makefile-dist edited + accordingly. + +Reorganized output flushing to correspond with new semantics of + devopen() on "/dev/std*" etc. + +Fixed rest of last goof!! + +Save and restore errno in do_pathopen(). + +Miscellaneous atari updates. + +Get rid of the trailing comma in the NODETYPE definition (Cray + compiler won't take it). + +Try to make the use of `const' consistent since Cray compiler is + fussy about that. See the changes to `basename' and `myname'. + +It turns out that, according to section 3.8.3 (Macro Replacement) + of the ANSI Standard: ``If there are sequences of preprocessing + tokens within the list of arguments that would otherwise act as + preprocessing directives, the behavior is undefined.'' That means + that you cannot count on the behavior of the declaration of + re_compile_pattern in awk.h, and indeed the Cray compiler chokes on it. + +Replaced alloca with malloc/realloc/free in regex.c. It was much simpler + than expected. (Inside NO_ALLOCA for now -- by default no alloca.) + +Added a configuration file, config/cray60, for Unicos-6.0. + +Changes from 2.12.16 to 2.12.17 +------------------------------- + +Ooops. Goofed signal use in last patch. + +Changes from 2.12.15 to 2.12.16 +------------------------------- + +RENAMED *_dir to just * (e.g. missing_dir). + +Numerous VMS changes. + +Proper inclusion of atari and vms files. + +Added experimental (ifdef'd out) RELAXED_CONTINUATION and DEFAULT_FILETYPE + -- please comment on these! + +Moved pathopen() to io.c (sigh). + +Put local directory ahead in default AWKPATH. + +Added facility in mkconf to echo comments on stdout: lines beginning + with "#echo " will have the remainder of the line echoed when mkconf is run. + Any lines starting with "#" will otherwise be treated as comments. The + intent is to be able to say: + "#echo Make sure you uncomment alloca.c in the Makefile" + or the like. + +Prototype fix for V.4 + +Fixed version_string to not print leading @(#). + +Fixed FIELDWIDTHS to work with strict (turned out to be easy). + +Fixed conf for V.2. + +Changed semantics of /dev/fd/n to be like on real /dev/fd. + +Several configuration and updates in the makefile. + +Updated manpage. + +Include tzset.c and system.c from missing_dir that were accidently left out of + the last patch. + +Fixed bug in cmdline variable assignment -- arg was getting freed(!) in + call to variable. + +Backed out of parse-time constant folding for now, until I can figure out + how to do it right. + +Fixed devopen() so that getline <"-" works. + +Changes from 2.12.14 to 2.12.15 +------------------------------- + +Changed config/* to a condensed form that can be used with mkconf to generate + a config.h from config.h-dist -- much easier to maintain. Please check + carefully against what you had before for a particular system and report + any problems. vms.h remains separate since the stuff at the bottom + didn't quite fit the mkconf model -- hopefully cleared up later. + +Fixed bug in grammar -- didn't allow function definition to be separated from + other rules by a semi-colon. + +VMS fix to #includes in missing.c -- should we just be including awk.h? + +Updated README for texinfo.tex version. + +Updating of copyright in all .[chy] files. + +Added but commented out Michal's fix to strftime. + +Added tzset() emulation based on Rick Adams' code. Added TZSET_MISSING to + config.h-dist. + +Added strftime.3 man page for missing_dir + +More posix: func, **, **= don't work in -W posix + +More lint: ^, ^= not in old awk + +gawk.1: removed ref to -DNO_DEV_FD, other minor updating. + +Style change: pushbak becomes pushback() in yylex(). + +Changes from 2.12.13 to 2.12.14 +------------------------------- + +Better (?) organization of awk.h -- attempt to keep all system dependencies + near the top and move some of the non-general things out of the config.h + files. + +Change to handling of SYSTEM_MISSING. + +Small change to ultrix config. + +Do "/dev/fd/*" etc. checking at runtime. + +First pass at VMS port. + +Improvements to error handling (when lexeme spans buffers). + +Fixed backslash handling -- why didn't I notice this sooner? + +Added programs from book to test suite and new target "bigtest" to Makefile. + +Changes from 2.12.12 to 2.12.13 +------------------------------- + +Recognize OFS and ORS specially so that OFS = 9 works without efficiency hit. + Took advantage of opportunity to tune do_print*() for about 10% win on a + print with 5 args (i.e. small but significant). + +Somewhat pervasive changes to reconcile CONVFMT vs. OFMT. + +Better initialization of builtin vars. + +Make config/* consistent wrt STRTOL_MISSING. + +Small portability improvement to alloca.s + +Improvements to lint code in awk.y + +Replaced strtol() with a better one by Chris Torek. + +Changes from 2.12.11 to 2.12.12 +------------------------------- + +Added PORTS file to record successful ports. + +Added #define const to nothing if not STDC and added const to strtod() header. + +Added * to printf capabilities and partially implemented ' ' and '+' (has an + effect for %d only, silently ignored for other formats). I'm afraid that's + as far as I want to go before I look at a complete replacement for + do_sprintf(). + +Added warning for /regexp/ on LHS of MATCHOP. + +Changes from 2.12.10 to 2.12.11 +------------------------------- + +Small Makefile improvements. + +Some remaining nits from the NeXT port. + +Got rid of bcopy() define in awk.h -- not needed anymore (??) + +Changed private in builtin.c -- it is special on Sequent. + +Added subset implementation of strtol() and STRTOL_MISSING. + +A little bit of cleanup in debug.c, dfa.c. + +Changes from 2.12.9 to 2.12.10 +------------------------------ + +Redid compatability checking and checking for # of args. + +Removed all references to variables[] from outside awk.y, in preparation + for a more abstract interface to the symbol table. + +Got rid of a remaining use of bcopy() in regex.c. + +Changes from 2.12.8 to 2.12.9 +----------------------------- + +Portability improvements for atari, next and decstation. + +Bug fix in substr() -- wasn't handling 3rd arg. of -1 properly. + +Manpage updates. + +Moved support from src release to doc release. + +Updated FUTURES file. + +Added some "lint" warnings. + +Changes from 2.12.7 to 2.12.8 +----------------------------- + +Changed time() to systime(). + +Changed warning() in snode() to fatal(). + +strftime() now defaults second arg. to current time. + +Changes from 2.12.6 to 2.12.7 +----------------------------- + +Fixed bug in sub_common() involving inadequate allocation of a buffer. + +Added some missing files to the Makefile. + +Changes from 2.12.5 to 2.12.6 +----------------------------- + +Fixed bug wherein non-redirected getline could call iop_close() just + prior to a call from do_input(). + +Fixed bug in handling of /dev/stdout and /dev/stderr. + +Changes from 2.12.4 to 2.12.5 +----------------------------- + +Updated README and support directory. + +Changes from 2.12.3 to 2.12.4 +----------------------------- + +Updated CHANGES and TODO (should have been done in previous 2 patches). + +Changes from 2.12.2 to 2.12.3 +----------------------------- + +Brought regex.c and alloca.s into line with current FSF versions. + +Changes from 2.12.1 to 2.12.2 +----------------------------- + +Portability improvements; mostly moving system prototypes out of awk.h + +Introduction of strftime. + +Use of CONVFMT. + +Changes from 2.12 to 2.12.1 +----------------------------- + +Consolidated treatment of command-line assignments (thus correcting the +-v treatment). + +Rationalized builtin-variable handling into a table-driven process, thus +simplifying variable() and eliminating spc_var(). + +Fixed bug in handling of command-line source that ended in a newline. + +Simplified install() and lookup(). + +Did away with double-mallocing of identifiers and now free second and later +instances of a name, after the first gets installed into the symbol table. + +Treat IGNORECASE specially, simplifying a lot of code, and allowing +checking against strict conformance only on setting it, rather than on each +pattern match. + +Fixed regexp matching when IGNORECASE is non-zero (broken when dfa.c was +added). + +Fixed bug where $0 was not being marked as valid, even after it was rebuilt. +This caused mangling of $0. + + +Changes from 2.11.1 to 2.12 +----------------------------- + +Makefile: + +Portability improvements in Makefile. +Move configuration stuff into config.h + +FSF files: + +Synchronized alloca.[cs] and regex.[ch] with FSF. + +array.c: + +Rationalized hash routines into one with a different algorithm. +delete() now works if the array is a local variable. +Changed interface of assoc_next() and avoided dereferencing past the end of the + array. + +awk.h: + +Merged non-prototype and prototype declarations in awk.h. +Expanded tree_eval #define to short-circuit more calls of r_tree_eval(). + +awk.y: + +Delinted some of the code in the grammar. +Fixed and improved some of the error message printing. +Changed to accomodate unlimited length source lines. +Line continuation now works as advertised. +Source lines can be arbitrarily long. +Refined grammar hacks so that /= assignment works. Regular expressions + starting with /= are recognized at the beginning of a line, after && or || + and after ~ or !~. More contexts can be added if necessary. +Fixed IGNORECASE (multiple scans for backslash). +Condensed expression_lists in array references. +Detect and warn for correct # args in builtin functions -- call most of them + with a fixed number (i.e. fill in defaults at parse-time rather than at + run-time). +Load ENVIRON only if it is referenced (detected at parse-time). +Treat NF, FS, RS, NR, FNR specially at parse time, to improve run time. +Fold constant expressions at parse time. +Do make_regexp() on third arg. of split() at parse tiem if it is a constant. + +builtin.c: + +srand() returns 0 the first time called. +Replaced alloca() with malloc() in do_sprintf(). +Fixed setting of RSTART and RLENGTH in do_match(). +Got rid of get_{one,two,three} and allowance for variable # of args. at + run-time -- this is now done at parse-time. +Fixed latent bug in [g]sub whereby changes to $0 would never get made. +Rewrote much of sub_common() for simplicity and performance. +Added ctime() and time() builtin functions (unless -DSTRICT). ctime() returns + a time string like the C function, given the number of seconds since the epoch + and time() returns the current time in seconds. +do_sprintf() now checks for mismatch between format string and number of + arguments supplied. + +dfa.c + +This is borrowed (almost unmodified) from GNU grep to provide faster searches. + +eval.c + +Node_var, Node_var_array and Node_param_list handled from macro rather + than in r_tree_eval(). +Changed cmp_nodes() to not do a force_number() -- this, combined with a + force_number() on ARGV[] and ENVIRON[] brings it into line with other awks +Greatly simplified cmp_nodes(). +Separated out Node_NF, Node_FS, Node_RS, Node_NR and Node_FNR in get_lhs(). +All adjacent string concatenations now done at once. + +field.c + +Added support for FIELDWIDTHS. +Fixed bug in get_field() whereby changes to a field were not always + properly reflected in $0. +Reordered tests in parse_field() so that reference off the end of the buffer + doesn't happen. +set_FS() now sets *parse_field i.e. routine to call depending on type of FS. +It also does make_regexp() for FS if needed. get_field() passes FS_regexp + to re_parse_field(), as does do_split(). +Changes to set_field() and set_record() to avoid malloc'ing and free'ing the + field nodes repeatedly. The fields now just point into $0 unless they are + assigned to another variable or changed. force_number() on the field is + *only* done when the field is needed. + +gawk.1 + +Fixed troff formatting problem on .TP lines. + +io.c + +Moved some code out into iop.c. +Output from pipes and system() calls is properly synchronized. +Status from pipe close properly returned. +Bug in getline with no redirect fixed. + +iop.c + +This file contains a totally revamped get_a_record and associated code. + +main.c + +Command line programs no longer use a temporary file. +Therefore, tmpnam() no longer required. +Deprecated -a and -e options -- they will go away in the next release, + but for now they cause a warning. +Moved -C, -V, -c options to -W ala posix. +Added -W posix option: throw out \x +Added -W lint option. + + +node.c + +force_number() now allows pure numerics to have leading whitespace. +Added make_string facility to optimize case of adding an already malloc'd + string. +Cleaned up and simplified do_deref(). +Fixed bug in handling of stref==255 in do_deref(). + +re.c + +contains the interface to regexp code + +Changes from 2.11.1 to FSF version of same +------------------------------------------ +Thu Jan 4 14:19:30 1990 Jim Kingdon (kingdon at albert) + + * Makefile (YACC): Add -y to bison part. + + * missing.c: Add #include . + +Sun Dec 24 16:16:05 1989 David J. MacKenzie (djm at hobbes.ai.mit.edu) + + * Makefile: Add (commented out) default defines for Sony News. + + * awk.h: Move declaration of vprintf so it will compile when + -DVPRINTF_MISSING is defined. + +Mon Nov 13 18:54:08 1989 Robert J. Chassell (bob at apple-gunkies.ai.mit.edu) + + * gawk.texinfo: changed @-commands that are not part of the + standard, currently released texinfmt.el to those that are. + Otherwise, only people with the as-yet unreleased makeinfo.c can + format this file. + +Changes from 2.11beta to 2.11.1 (production) +-------------------------------------------- + +Went from "beta" to production status!!! + +Now flushes stdout before closing pipes or redirected files to +synchronize output. + +MS-DOS changes added in. + +Signal handler return type parameterized in Makefile and awk.h and +some lint removed. debug.c cleaned up. + +Fixed FS splitting to never match null strings, per book. + +Correction to the manual's description of FS. + +Some compilers break on char *foo = "string" + 4 so fixed version.sh and +main.c. + +Changes from 2.10beta to 2.11beta +--------------------------------- + +This release fixes all reported bugs that we could reproduce. Probably +some of the changes are not documented here. + +The next release will probably not be a beta release! + +The most important change is the addition of the -nostalgia option. :-) + +The documentation has been improved and brought up-to-date. + +There has been a lot of general cleaning up of the code that is not otherwise +documented here. There has been a movement toward using standard-conforming +library routines and providing them (in missing.d) for systems lacking them. +Improved (hopefully) configuration through Makfile modifications and missing.c. +In particular, straightened out confusion over vprintf #defines, declarations +etc. + +Deleted RCS log comments from source, to reduce source size by about one third. +Most of them were horribly out-of-date, anyway. + +Renamed source files to reflect (for the most part) their contents. + +More and improved error messages. Cleanup and fixes to yyerror(). +String constants are not altered in input buffer, so error messages come out +better. Fixed usage message. Make use of ANSI C strerror() function +(provided). + +Plugged many more memory leaks. The memory consumption is now quite +reasonable over a wide range of programs. + +Uses volatile declaration if STDC > 0 to avoid problems due to longjmp. + +New -a and -e options to use awk or egrep style regexps, respectively, +since POSIX says awk should use egrep regexps. Default is -a. + +Added -v option for setting variables before the first file is encountered. +Version information now uses -V and copyleft uses -C. + +Added a patchlevel.h file and its use for -V and -C. + +Append_right() optimized for major improvement to programs with a *lot* +of statements. + +Operator precedence has been corrected to match draft Posix. + +Tightened up grammar for builtin functions so that only length +may be called without arguments or parentheses. + +/regex/ is now a normal expression that can appear in any expression +context. + +Allow /= to begin a regexp. Allow ..[../..].. in a regexp. + +Allow empty compound statements ({}). + +Made return and next illegal outside a function and in BEGIN/END respectively. + +Division by zero is now illegal and causes a fatal error. + +Fixed exponentiation so that x ^ 0 and x ^= 0 both return 1. + +Fixed do_sqrt, do_log, and do_exp to do argument/return checking and +print an error message, per the manual. + +Fixed main to catch SIGSEGV to get source and data file line numbers. + +Fixed yyerror to print the ^ at the beginning of the bad token, not the end. + +Fix to substr() builtin: it was failing if the arguments +weren't already strings. + +Added new node value flag NUMERIC to indicate that a variable is +purely a number as opposed to type NUM which indicates that +the node's numeric value is valid. This is set in make_number(), +tmp_number and r_force_number() when appropriate and used in +cmp_nodes(). This fixed a bug in comparison of variables that had +numeric prefixes. The new code uses strtod() and eliminates is_a_number(). +A simple strtod() is provided for systems lacking one. It does no +overflow checking, so could be improved. + +Simplification and efficiency improvement in force_string. + +Added performance tweak in r_force_number(). + +Fixed a bug with nested loops and break/continue in functions. + +Fixed inconsistency in handling of empty fields when $0 has to be rebuilt. +Happens to simplify rebuild_record(). + +Cleaned up the code associated with opening a pipe for reading. Gawk +now has its own popen routine (gawk_popen) that allocates an IOBUF +and keeps track of the pid of the child process. gawk_pclose +marks the appropriate child as defunct in the right struct redirect. + +Cleaned up and fixed close_redir(). + +Fixed an obscure bug to do with redirection. Intermingled ">" and ">>" +redirects did not output in a predictable order. + +Improved handling of output buffering: now all print[f]s redirected to a tty +or pipe are flushed immediately and non-redirected output to a tty is flushed +before the next input record is read. + +Fixed a bug in get_a_record() where bcopy() could have copied over +a random pointer. + +Fixed a bug when RS="" and records separated by multiple blank lines. + +Got rid of SLOWIO code which was out-of-date anyway. + +Fix in get_field() for case where $0 is changed and then $(n) are +changed and then $0 is used. + +Fixed infinite loop on failure to open file for reading from getline. +Now handles redirect file open failures properly. + +Filenames such as /dev/stdin now allowed on the command line as well as +in redirects. + +Fixed so that gawk '$1' where $1 is a zero tests false. + +Fixed parsing so that `RLENGTH -1' parses the same as `RLENGTH - 1', +for example. + +The return from a user-defined function now defaults to the Null node. +This fixes a core-dump-causing bug when the return value of a function +is used and that function returns no value. + +Now catches floating point exceptions to avoid core dumps. + +Bug fix for deleting elements of an array -- under some conditions, it was +deleting more than one element at a time. + +Fix in AWKPATH code for running off the end of the string. + +Fixed handling of precision in *printf calls. %0.2d now works properly, +as does %c. [s]printf now recognizes %i and %X. + +Fixed a bug in printing of very large (>240) strings. + +Cleaned up erroneous behaviour for RS == "". + +Added IGNORECASE support to index(). + +Simplified and fixed newnode/freenode. + +Fixed reference to $(anything) in a BEGIN block. + +Eliminated use of USG rand48(). + +Bug fix in force_string for machines with 16-bit ints. + +Replaced use of mktemp() with tmpnam() and provided a partial implementation of +the latter for systems that don't have it. + +Added a portability check for includes in io.c. + +Minor portability fix in alloc.c plus addition of xmalloc(). + +Portability fix: on UMAX4.2, st_blksize is zero for a pipe, thus breaking +iop_alloc() -- fixed. + +Workaround for compiler bug on Sun386i in do_sprintf. + +More and improved prototypes in awk.h. + +Consolidated C escape parsing code into one place. + +strict flag is now turned on only when invoked with compatability option. +It now applies to fewer things. + +Changed cast of f._ptr in vprintf.c from (unsigned char *) to (char *). +Hopefully this is right for the systems that use this code (I don't). + +Support for pipes under MSDOS added. diff --git a/POSIX.STD b/POSIX.STD new file mode 100644 index 0000000..a236894 --- /dev/null +++ b/POSIX.STD @@ -0,0 +1,56 @@ + Copyright (C) 1992, 1995, 1998, 2001, 2006, 2007, 2010, 2011, 2015 + Free Software Foundation, Inc. + + Copying and distribution of this file, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. +-------------------------------------------------------------------------- +Thu Feb 12 08:51:22 IST 2015 +============================ +This file documents several things related to the 2008 POSIX standard +that I noted after reviewing it. + +1. POSIX leaves undefined what happens for something like + + awk '{ print ; exit }' if=42 /etc/passwd + + Mawk diagnoses this. Gawk and BWK awk do not. This doesn't seem to be + worth the effort to add the code, but at least I'm aware of it. + +2. The 2001-2004 standards accidentally required support for hexadecimal + floating point constants and for Infinity and Not-A-Number (NaN) values. + + The 2008 standard now explicitly allows, but does not require, such + support. + + More discussion is provided in the node `POSIX Floating Point Problems' + in gawk.texi. + +3. String comparison with <, <= etc is supposed to take the locale's collating + sequence into account. By default gawk doesn't do this. Rather, gawk + will do this only if --posix is in effect. + +4. According to POSIX, the function parameters of one function may not have + the same name as another function, making this invalid: + + function foo() { ... } + function bar(foo) { ...} + + Or even: + + function bar(foo) { ...} + function foo() { ... } + + Gawk enforces this only with --posix. + +The following things aren't described by POSIX but ought to be: + +1. The value of $0 in an END rule + +2. The return value of a function that either does return with no value + or that falls off the end of the function body. + +3. What happens with substr() if start is <= 0, or greater than the length + of the string, or if length is <= 0. + +4. Whether "next" can be invoked from a function body. diff --git a/README b/README new file mode 100644 index 0000000..9696fb3 --- /dev/null +++ b/README @@ -0,0 +1,108 @@ + Copyright (C) 2005, 2006, 2007, 2009, 2010, 2011, 2012, 2013, 2014, 2015, + 2016, 2017 Free Software Foundation, Inc. + + Copying and distribution of this file, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. + +README: + +This is GNU Awk 4.2.1. It is upwardly compatible with Brian Kernighan's +version of Unix awk. It is almost completely compliant with the +2008 POSIX 1003.1 standard for awk. (See the note below about POSIX.) + +This is a bug-fix release. See NEWS and ChangeLog for details. + +Work to be done is described briefly in the TODO file, which is available +only in the 'master' branch in the Git repo. + +Changes in this version are summarized in the NEWS file. + +Read the file POSIX.STD for a discussion of issues where the standard +says one thing but gawk does something different. + +To format the documentation with TeX, use at least version 2017-09.16 +of texinfo.tex. There is a usable copy of texinfo.tex in the doc directory. +You should also use at least version 6.1 of texindex and of makeinfo +from the texinfo-6.1 distribution. + +INSTALLATION: + +Check whether there is a system-specific README file for your system under +the `README_d' directory. If there's something there that you should +have read and didn't, and you bug me about it, I'm going to yell at you. + +See the file INSTALL for installation instructions. + +If you don't have Bison, use the awkgram.c file here. It was +generated with Bison, and has no proprietary code in it. (Note that +modifying awkgram.y without Bison will be difficult, at best. You might +want to get a copy of Bison from the FSF too.) + +The build mechanics depend upon Bison. Also, gawk doesn't work correctly +with some versions of yacc, so just use Bison. + +If you have an MS-DOS, MS-Windows, or OS/2 system, use the stuff in the `pc' +directory. Similarly, there is a separate directory for VMS. + +Appendix B of ``GAWK: Effective Awk Programming'' discusses configuration +in detail. The configuration process is based on GNU Autoconf and +Automake. + +After successful compilation, do `make check' to run the test suite. +There should be no output from the `cmp' invocations except in the +cases where there are small differences in floating point values, and +possibly in the case of strftime. There may be differences based on +installed (or not installed) locales and the quality of multibyte +character support on your system. + +Several of the tests ignore errors on purpose; those are not a problem. +If there are other differences, please investigate and report the problem. + +PRINTING THE MANUAL + +The `doc' directory contains a recent version of texinfo.tex, which will +be necessary for printing the manual. Use `make dvi' to get a DVI file +from the manual. In the `doc' directory, use `make postscript' to get +PostScript versions of the manual, the man page, and the reference card. +Use `make pdf' to get PDF versions of the manuals, the man page and +the reference card. + +BUG REPORTS AND FIXES (Un*x systems): + +Please coordinate changes through Arnold Robbins. In particular, see +the section in the manual on reporting bugs. Note that comp.lang.awk +is about the worst place to post a gawk bug report. Please, use the +mechanisms outlined in the manual. + +Email should be sent to bug-gawk@gnu.org. This is a separate mailing +list at GNU Central. The advantage to using this address is that bug +reports are archived at GNU Central. + +Arnold Robbins + +BUG REPORTS AND FIXES, non-Unix systems: + +MS-DOS with DJGPP: + Juan Manuel Guerrero + juan.guerrero@gmx.de + +MS-Windows with MinGW: + Eli Zaretskii + eliz@gnu.org + +OS/2: + Andreas Buening + andreas.buening@nexgo.de + +VMS: + John Malmberg + wb8tyw@qsl.net + +z/OS (OS/390) Contact: + Daniel Richard G. + skunk@iSKUNK.ORG + +z/OS (OS/390) Maintainer Emeritus: + Dave Pitts + dpitts@cozx.com diff --git a/README_d/ChangeLog b/README_d/ChangeLog new file mode 100644 index 0000000..13e5898 --- /dev/null +++ b/README_d/ChangeLog @@ -0,0 +1,178 @@ +2018-02-25 Arnold D. Robbins + + * 4.2.1: Release tar ball made. + +2018-02-23 Arnold D. Robbins + + * README.macosx: Updated. + +2018-02-21 Arnold D. Robbins + + * README.macosx: Updated. + +2018-02-04 Arnold D. Robbins + + * README.macosx: Updated. + +2018-01-25 Arnold D. Robbins + + * README.macosx: Updated. + +2017-11-15 Arnold D. Robbins + + * README.mpfr: Make separate sections for different ports and + update some of the info. + +2017-11-13 Juan Manuel Guerrero + + * README.mpfr: Add info that DJGPP port compiles with MPFR support. + +2017-10-21 Arnold D. Robbins + + * README.os2: Updated with email from Andreas. + +2017-10-19 Arnold D. Robbins + + * 4.2.0: Release tar ball made. + +2017-10-10 Arnold D. Robbins + + * README.rpm: New file. + +2017-09-04 Eli Zaretskii + + * README.pc: Update instructions for building the extensions + without libmpfr. + +2017-08-24 Arnold D. Robbins + + * README.pc: Updated to point to Juan Guerrero for DJGPP. + Thanks to Scott Deifik for the report. + +2017-08-23 Arnold D. Robbins + + * README.alpine: New file. + +2017-08-13 Arnold D. Robbins + + * README.freebsd: New file. + +2016-12-23 Arnold D. Robbins + + * README.macosx: Updated. + +2016-10-31 Arnold D. Robbins + + * README.aix: New file. + * README.zLinux: Typo fix. + +2016-08-25 Arnold D. Robbins + + * 4.1.4: Release tar ball made. + +2016-08-24 Arnold D. Robbins + + * README.macosx: Updated. + +2016-01-25 Arnold D. Robbins + + * README.zLinux: New file. + +2015-05-19 Arnold D. Robbins + + * 4.1.3: Release tar ball made. + +2015-04-29 Arnold D. Robbins + + * 4.1.2: Release tar ball made. + +2015-04-13 Arnold D. Robbins + + * README.macosx: Updated. + +2015-04-09 Arnold D. Robbins + + * README.macosx: New file. + +2014-08-12 Juergen Kahrs + + * README.cmake: Moved file from top-level to here. + +2014-04-08 Arnold D. Robbins + + * 4.1.1: Release tar ball made. + +2014-04-02 Arnold D. Robbins + + * README.gcc-3: New file. + +2014-01-22 Arnold D. Robbins + + * README.solaris: Updated. + +2014-01-12 John E. Malmberg + + * README.VMS: document that the gawk.cld needs a fix. + +2013-12-23 John E. Malmberg + + * README.VMS: Add documentation about building dynamic + extensions. + +2013-12-23 John E. Malmberg + + * README.VMS: Document decoding Gawk VMS exit codes. + +2013-12-16 John E. Malmberg + + * README.VMS: Further updates. + +2013-12-05 John E. Malmberg + + * README.VMS: updated with current build information. + +2013-07-02 Arnold D. Robbins + + * README.pc: Update that |& also now works on MinGW. + +2013-05-14 Eli Zaretskii + + * README.pc: Update the pc build and test instructions. + +2013-05-09 Arnold D. Robbins + + * 4.1.0: Release tar ball made. + +2013-04-16 Arnold D. Robbins + + * README.hacking, README.mpfr, README.pc: Updated. + +2012-12-24 Arnold D. Robbins + + * 4.0.2: Release tar ball made. + +2012-04-11 John Haque + + * README.hacking: New file. + +2012-04-01 John Haque + + * README.mpfr: New file. + +2012-03-28 Arnold D. Robbins + + * 4.0.1: Release tar ball made. + +2011-07-29 Arnold D. Robbins + + * README.pc: Add download location info for DJGPP version. + +2011-07-15 Arnold D. Robbins + + * README.solaris: Info added on using the Solaris C compiler. + +2011-06-23 Arnold D. Robbins + + * ChangeLog.0: Rotated ChangeLog into this file. + * ChangeLog: Created anew for gawk 4.0.0 and on. + * 4.0.0: Release tar ball made. diff --git a/README_d/ChangeLog.0 b/README_d/ChangeLog.0 new file mode 100644 index 0000000..8cea065 --- /dev/null +++ b/README_d/ChangeLog.0 @@ -0,0 +1,8 @@ +2010-12-18 Eli Zaretskii + + * README.pc: Update and simplify. Remove lots of + outdated stuff for systems and configurations no longer supported. + +2010-12-18 Arnold Robbins + + * ChangeLog: Created. diff --git a/README_d/README.VMS b/README_d/README.VMS new file mode 100644 index 0000000..0faabbc --- /dev/null +++ b/README_d/README.VMS @@ -0,0 +1,226 @@ + +Compiling GAWK on VMS: + + There's a DCL command procedure that will issue all the necessary +CC and LINK commands, and there's also a Makefile for use with the MMS +utility. From the source directory, use either + |$ @[.VMS]VMSBUILD.COM +or + |$ MMS/DESCRIPTION=[.VMS]DESCRIP.MMS gawk +or + |$ MMK/DESCRIPTION=[.VMS]DESCRIP.MMS gawk + +Note that on IA64 and Alpha the case of the target may be important. +MMS has had problems on ODS-5 volumes. MMK does not have these issues. +MMK is available free from https://github.com/endlesssoftware/mmk. +The most recent builds of gawk on VMS used MMK. + +Support of the vmsbuild.com may get dropped in a future release. + +DEC C -- use either vmsbuild.com or descrip.mms as is. + DEC C is also known as Compaq C and HP C. + +VAX C -- use `@vmsbuild VAXC' or `MMS/MACRO=("VAXC")'. On a system + with both VAX C and DEC C installed where DEC C is the default, + use `MMS/MACRO=("VAXC","CC=CC/VAXC")' for the MMS variant; for + the vmsbuild.com variant, any need for `/VAXC' will be detected + automatically. + * IMPORTANT NOTE * VAX C should not be used on VAX/VMS 5.5-2 and + later. Use DEC C instead. + +GNU C -- use `@vmsbuild GNUC' or `MMS/MACRO=("GNUC")'. On a system + where the GCC command is not already defined, use either + `@vmsbuild GNUC DO_GNUC_SETUP' or + `MMS/MACRO=("GNUC","DO_GNUC_SETUP")'. + +Most recent builds are using: + OpenVMS VAX 7.3 using DEC C 6.4 + OpenVMS Alpha 8.3 using HP C V 7.3 + OpenVMS Alpha 8.4 using HP C V 7.3 + OpenVMS IA64 8.4 using HP C V 7.3 + +GAWK was originally ported for VMS V4.6 and up. It has not been tested +with a release that old for some time. + +Compiling dynamic extensions on VMS: + +GAWK comes with some dynamic extensions. The extensions that have been +ported to VMS can be built using one of the following commands. + + |$ MMS/DESCRIPTION=[.VMS]DESCRIP.MMS extensions +or + |$ MMK/DESCRIPTION=[.VMS]DESCRIP.MMS extensions + +GAWK uses AWKLIBPATH as either an environment variable or a logical name +to find the dynamic extensions. + +Dynamic extensions need to be compiled with the same compiler options for +floating point, pointer size, and symbol name handling as gawk. +Alpha and Itanium should use IEEE floating point. The pointer size is 32 bits, +and the symbol name handling is to be exact case with CRC shortening for +symbols longer than 32 bits. + +Currently dynamic extensions have only been tested to work on VMS 8.3 and later +on both Alpha and Itanium. Dynamic extensions are not currently working on +VAX/VMS 7.3. + +Compile time are macros needed to be defined before the first VMS supplied +header file is included. Usually this will be done with a config.h file. + +#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 + +Alpha and Itanium: + +/name=(as_is,short) +/float=ieee/ieee_mode=denorm_results + +VAX: + +/name=(as_is,short) + +The linker option files are [.vms]gawk_plugin.opt for Alpha and Itanium. + +As the VAX dynamic plug-in feature is not yet working, the files potentially +needed for a future VAX plugin are in [.vms.vax] directory of the source. + + +Testing GAWK on VMS: + +After you build gawk, you can test it with the [.vms]vmstest.com procedure. +The procedure takes a parameter that is either for a list of tests or +a specific test. The parameter clean cleans up files left over from running +the tests. + + $ set def [.test] + $ @[-.vms]vmstest.com bigtest + $ @[-.vms]vmstest.com clean + $ set def [-] + +To test the dynamic extensions on VMS 8.3 and later, use: + + $ set def [.test] + $ @[-.vms]vmstest.com extension + $ @[-.vms]vmstest.com clean + $ set def [-] + + +Installing GAWK on VMS: + + All that's needed is a 'foreign' command, which is a DCL symbol +whose value begins with a dollar sign. + |$ GAWK :== $device:[directory]GAWK +(Substitute the actual location of gawk.exe for 'device:[directory]'.) +That symbol should be placed in the user's login.com or in the system- +wide sylogin.com procedure so that it will be defined every time the +user logs on. + +If your gawk was installed by a PCSI kit into the GNV$GNU: directory tree, +the program will be known as GNV$GNU:[bin]gnv$gawk.exe and the help file +will be GNV$GNU:[vms_help]gawk.hlp. The GNV$GNU:[vms_bin]gawk_verb.cld can be +used to add GAWK and the alias AWK to a DCL command table. + + Optionally, the help entry can be loaded into a VMS help library. + |$ LIBRARY/HELP SYS$HELP:HELPLIB [.VMS]GAWK.HLP +(You may want to substitute a site-specific help library rather than +the standard VMS library 'HELPLIB'.) After loading the help text, + |$ HELP GAWK +will provide information about both the gawk implementation and the +awk programming language. + + The logical name AWK_LIBRARY can designate a default location +for awk program files. For the '-f' option, if the specified filename +has no device or directory path information in it, Gawk will look in +the current directory first, then in the directory specified by the +translation of AWK_LIBRARY if it the file wasn't found. If the file +still isn't found, then ".awk" will be appended and the file access +will be re-tried. If AWK_LIBRARY is not defined, that portion of the +file search will fail benignly. + + +Running GAWK on VMS: + + Command line parsing and quoting conventions are significantly +different on VMS, so examples in _The_GAWK_Manual_ or the awk book +often need minor changes. They *are* minor though, and all the awk +programs should run correctly. + + Here are a couple of trivial tests: + |$ gawk -- "BEGIN {print ""Hello, World!""}" + |$ gawk -"W" version !could also be -"W version" or "-W version" +Note that upper- and mixed-case text must be quoted. + + The VMS port of Gawk includes a DCL-style interface in addition +to the original shell-style interface. See the help entry for details. +One side-effect of dual command line parsing is that if there's only a +single parameter (as in the quoted string program above), the command +becomes ambiguous. To work-around this, the normally optional "--" +flag is required to force shell rather than DCL parsing. If any other +dash-type options (or multiple parameters such as data files to be +processed) are present, there is no ambiguity and "--" can be omitted. + + The logical name AWKPATH can be used to override the default +search path of "SYS$DISK:[],AWK_LIBRARY:" when looking for awk program +files specified by the '-f' option. The format of AWKPATH is a comma- +separated list of directory specifications. When defining it, the +value should be quoted so that it retains a single translation, not a +multi-translation RMS searchlist. + + The exit status from Gawk is encoded in the the VMS $status exit +value so that the severity bits are set as expected and the original +Gawk exit value can be extracted. + +To extract the actual gawk exit code from the VMS status use: + unix_status = (vms_status .and. &x7f8) / 8 + +The exit value is encoded to comply with VMS coding standards and +will have the C_FACILITY_NO of 0x350000 with the constant 0xA000 +added to the number shifted over by 3 bits to make room for the +severity codes. + +The Gawk exit value of 1 will result in the VMS status having the +ERROR severity status set. The Gawk exit value of 2 will result in +the FATAL severity status set. All other Gawk exit values will have +the Success severity status set. + +This change was needed to provide all Gawk exit values to VMS programs and +for compatibilty with programs written in C and the GNV environment. + +Older versions of Gawk incorrectly mostly passed through the Gawk +status values instead of encoding them. DCL scripts that were checking +the severity values will probably not need changing. DCL scripts that +were checking the exact exit status will need an update. + +VAX/VMS floating point uses unbiased rounding. This is generaly incompatible +with the expected behavior. The ofmta test in the test directory will +fail on VAX. + +Gawk needs the SYS$TIMEZONE_RULE or TZ logical name to be defined or it +will output times in GMT. + +The vmstest.com script needs SYS$TIMEZONE_NAME to be defined to match +the SYS$TIMEZONE_RULE. Older versions of VMS do not define these logical +names. + +TO DO Items (not in order of priority) + +1. Implement dynamic plug-ins on VAX. + +2. With the system() function, the status for DCL commands are not being + returned. + +3. Need gawk to accept logical names GNV$AWKPATH, GNV$AWKLIB, and + GNV$AWK_LIBARARY in addtion to the unprefixed names. This will allow + system wide default values to be set by an installation kit. + +4. Need to fix the gawk.cld file to not require a parameter for the options + that do not use the parameter. diff --git a/README_d/README.aix b/README_d/README.aix new file mode 100644 index 0000000..eb686fe --- /dev/null +++ b/README_d/README.aix @@ -0,0 +1,9 @@ +Mon Oct 31 21:54:05 IST 2016 +============================ + +To compile gawk 4.1.4 correctly with IBM's xlc compiler, you need to +use the -qalias=noansi command line option. Otherwise the compiler +makes incorrect optimizations and the resulting binary core dumps +on many tests. + +Thanks to Tony Reix (tony.reix@atos.net) for the info. diff --git a/README_d/README.alpine b/README_d/README.alpine new file mode 100644 index 0000000..4df5b45 --- /dev/null +++ b/README_d/README.alpine @@ -0,0 +1,15 @@ +Wed Aug 23 08:19:08 IDT 2017 +============================ + +I have a report that Alpine Linux uses BusyBox for its utilities. In +particular, the BusyBox ls does not have a -f option. This option is +needed in at least one of the tests. + +Install coreutils on your Alpine Linux system: + + apk add coreutils + +in order to get a fully POSIX-compliant ls. + +Arnold Robbins +arnold@skeeve.com diff --git a/README_d/README.bootstrap b/README_d/README.bootstrap new file mode 100644 index 0000000..152bbef --- /dev/null +++ b/README_d/README.bootstrap @@ -0,0 +1,32 @@ +Tue Dec 6 21:33:19 IST 2011 +============================ + +As documented in the mail below, if you are using a system without any +version of awk installed, you will have bootstrapping problems (i.e., running +configure). The solution is to install mawk or Brian Kernighan's awk +first. + +Arnold Robbins +------------------------------------ +From: Simon Josefsson +To: bug-gawk@gnu.org +Date: Sat, 19 Nov 2011 15:24:22 +0100 +Message-ID: <87r514faw9.fsf@latte.josefsson.org> +Subject: [bug-gawk] building gawk requires an awk? + +Hello, + +I was not able to build gawk 4.0.0 on a GNU/Hurd machine that didn't +have any awk, the ./configure script failed at the end: + +config.status: creating Makefile +./config.status: line 1169: awk: command not found +config.status: error: could not create Makefile + +Is this a known bootstrapping issue? Same happened for 3.1.8. I looked +in README but didn't find anything obvious. + +Btw, building 'mawk' first and then gawk 4.0.0 works. Running self +checks didn't work because there is no 'cmp' on the system either... + +/Simon diff --git a/README_d/README.cmake b/README_d/README.cmake new file mode 100644 index 0000000..7a61aed --- /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.freebsd b/README_d/README.freebsd new file mode 100644 index 0000000..650d07a --- /dev/null +++ b/README_d/README.freebsd @@ -0,0 +1,17 @@ +Sun Aug 13 21:23:00 IDT 2017 +============================ + +According to a report from Eric Pruitt : + +| When running ./configure for GAWK 4.1.4, the mktime(3) function is not +| detected on FreeBSD 11 when using -static with CFLAGS and LDFLAGS. This +| causes the build to fail. + +Paul Eggert says that using: + + ./configure ac_cv_func_working_mktime=yes + +will cause gawk to use the FreeBSD mktime. + +Arnold Robbins +arnold@skeeve.com diff --git a/README_d/README.gcc-3 b/README_d/README.gcc-3 new file mode 100644 index 0000000..c76a9af --- /dev/null +++ b/README_d/README.gcc-3 @@ -0,0 +1,11 @@ +Wed Apr 2 21:29:17 IDT 2014 +============================ + +I have had a report that on a GNU/Linux system using gcc 3.3.6 (32 bit) +that the aasort test fails. Compiling without -O builds a gawk that +does pass all tests. + +Caveat Emptor. + +Arnold Robbins +arnold@skeeve.com diff --git a/README_d/README.hacking b/README_d/README.hacking new file mode 100644 index 0000000..d179488 --- /dev/null +++ b/README_d/README.hacking @@ -0,0 +1,9 @@ +* Use one of the following macros to access the value of a numeric NODE: + Macro Returned C type + --------------------------------------- + get_number_ui(n) unsigned long + get_number_si(n) long + get_number_d(n) double + get_number_uj(n) uintmax_t + +* Use iszero(n) to test if a numeric NODE is zero. diff --git a/README_d/README.macosx b/README_d/README.macosx new file mode 100644 index 0000000..b46f012 --- /dev/null +++ b/README_d/README.macosx @@ -0,0 +1,44 @@ +Fri Feb 23 10:38:05 IST 2018 +============================ + +On PowerPC Macintosh, things are just weird. + +* Using the stock compiler, you can't build gawk (c99 mode) against MPFR; +there is an issue with duplicate inline functions from GMP. By default, +I have disabled this compilation. + +* If you build GCC 4.2.4 and use that version of GCC, you can compile gawk +with MPFR and the C99 settings. But then the two readfile tests fail. +The call to read(2) simply returns zero. I have no idea why. + +Since nobody but me has one of these left, I'm not going to mess +with it anymore right now. + +Thu Jan 25 20:07:56 IST 2018 +============================ + +You may need to explicitly tell configure where to find the GNU gettext +header file and library with --with-libintl-prefix=...'. Otherwise, +the nlstringtest test will fail. + +Mon Apr 13 09:49:40 IDT 2015 +============================ + +I have reports of success on this compiler: + +$ gcc --version +Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr +--with-gxx-include-dir=/usr/include/c++/4.2.1 +Apple LLVM version 6.0 (clang-600.0.54) (based on LLVM 3.5svn) +Target: x86_64-apple-darwin14.1.0 +Thread model: posix + +Thu Apr 9 10:39:26 IDT 2015 +============================ + +There are reports of compilation issues on Mac OS X 10.10 (Yosemite). +The only compiler reported to have produced a complete pass of +"make check" is the MacPorts compiler, /opt/local/bin/clang-mp-3.5. + +Arnold Robbins +arnold@skeeve.com diff --git a/README_d/README.mpfr b/README_d/README.mpfr new file mode 100644 index 0000000..e16828d --- /dev/null +++ b/README_d/README.mpfr @@ -0,0 +1,55 @@ +-------------------------- DJGPP ----------------------------------- + +2017-11-13 +========== +The DJGPP port of Gawk has been compiled and tested using the +following combinations of MPFR and GMP versions on FreeDOS and +other versions of the DOS operating system: +GNU MPFR 3.1.6, GNU MP 6.1.2 + +Precompiled binaries of GMP and MPFR for DJGPP are available +from DJ Delorie's ftp server and mirrors: + + http://www.delorie.com/pub/djgpp/current/v2gnu/gmp612b.zip + http://www.delorie.com/pub/djgpp/current/v2gnu/mpfr316b.zip + +No previous versions of these libraries are supported. +Newer versions should work. + +------------------------- Mac OS X on PPC ------------------------------- + +Sat Mar 17 07:32:01 CDT 2012 +============================= + +The MPFR and GMP versions known to work for Mac OS X on PPC: +GNU MPFR 3.1.0, GNU MP 4.3.1 + +Wed Nov 15 21:57:29 IST 2017 +============================ + +As of gawk 4.2, MPFR is no longer supported on Mac OS X on PPC. +Gawk switched to C99, and the last PPC version doesn't play well +with C99. + +------------------------ Windows MinGW ---------------------------- + +Precompiled binaries for GMP and MPFR in Windows may be available +from here: + + http://sourceforge.net/projects/ezwinports/files/ + +or here: + + http://sourceforge.net/projects/mingw/files/MinGW/Base/mpfr/ + http://sourceforge.net/projects/mingw/files/MinGW/Base/gmp/ + +You should try to use libraries downloaded from the same site +to avoid possible incompatibilities. + +------------------------- GNU/Linux -------------------------------- + +Gawk has been compiled and tested using the following combinations +of MPFR and GMP versions on GNU/Linux: +GNU MPFR 2.4.2, GNU MP 4.3.2 +GNU MPFR 3.1.0, GNU MP 5.0.2, 5.0.3 +GNU MPFR 3.1.4, GNU MP 6.1.0 diff --git a/README_d/README.multibyte b/README_d/README.multibyte new file mode 100644 index 0000000..135ba86 --- /dev/null +++ b/README_d/README.multibyte @@ -0,0 +1,29 @@ +Fri Jun 3 12:20:17 IDT 2005 +============================ + +As noted in the NEWS file, as of 3.1.5, gawk uses character values instead +of byte values for `index', `length', `substr' and `match'. This works +in multibyte and unicode locales. + +Wed Jun 18 16:47:31 IDT 2003 +============================ + +Multibyte locales can cause occasional weirdness, in particular with +ranges inside brackets: /[....]/. Something that works great for ASCII +will choke for, e.g., en_US.UTF-8. One such program is test/gsubtst5.awk. + +By default, the test suite runs with LC_ALL=C and LANG=C. You +can change this by doing (from a Bourne-style shell): + + $ GAWKLOCALE=some_locale make check + +Then the test suite will set LC_ALL and LANG to the given locale. + +As of this writing, this works for en_US.UTF-8, and all tests +pass except gsubtst5. + +For the normal case of RS = "\n", the locale is largely irrelevant. +For other single byte record separators, using LC_ALL=C will give you +much better performance when reading records. Otherwise, gawk has to +make several function calls, *per input character* to find the record +terminator. You have been warned. diff --git a/README_d/README.os2 b/README_d/README.os2 new file mode 100644 index 0000000..c12f82d --- /dev/null +++ b/README_d/README.os2 @@ -0,0 +1,57 @@ +From andreas.buening@nexgo.de Thu Oct 19 15:34:16 2017 +Date: Thu, 19 Oct 2017 23:34:09 +0200 (CEST) +From: =?UTF-8?Q?Andreas_B=C3=BCning?= +To: arnold@skeeve.com +Message-ID: <1433289104.12656.1508448849820@mail.vodafone.de> +Subject: Re: gawk for OS/2 - any updates? + +Hello Arnold, + +I'd like to inform you about the current state of compiling gawk on +OS/2: + +1. Compilation + +Running ./configure does work but + +- I tried only running with --disable-nls, so with NLS I didn't test. +- Depending on the gcc version you use you may get linker errors. In + that case add 'CFLAGS=-O2 -g -fgnu89-inline' to the configure options + (-O2 -g already is the default). + + +2. Tests + +It is possible to run the built-in checks but many test results depend +on the shell being used. I recommend to use 'make -i check' to run +the tests because some failures might cause a immediate termination +of the make run. + +- If your shell uses \r\n linebreaks (in that case all tests fail) + then you have to run 'make -i check CMP=diff' to ignore the linebreak + differences at the test result comparison. +- Depending on the shell some tests might just hang forever. Press + Ctrl+C and/or Ctrl+Break until the tests continue. +- OS/2 can only load DLLs with filenames up to 8+3 bytes but gawk + creates three internal DLLs with longer names (e.g. filefuncs.dll, + revoutput.dll, revtwoway.dll). Thus, all tests trying to load + filefuncs.dll or the other two DLLs will fail. This is not a bug + of gawk. If you change e.g. the '@load filefuncs' directive to + '@load filefunc' in the according *.awk file then the tests will + succeed. +- The number of failling tests is currently around 50, less if your + shell uses \r\n linebreaks, more otherwise. + +Best wishes, + +Andreas Buening +====================================================== + +Sat Oct 21 21:01:49 IDT 2017 +============================ + +Fixes for loading extension libraries have since been included +in the git repo and will be part of 4.2.1. + +Arnold Robbins +arnold@skeeve.com diff --git a/README_d/README.pc b/README_d/README.pc new file mode 100644 index 0000000..76299d0 --- /dev/null +++ b/README_d/README.pc @@ -0,0 +1,134 @@ +This is the README for GNU awk 4 under Windows32, OS/2, and DOS. + + Gawk has been compiled and tested under OS/2, DOS, and Windows32 using +the GNU development tools from DJ Delorie (DJGPP; DOS with special +support for long filenames on Windows), Eberhard Mattes (EMX; OS/2, +DOS, and Windows32 with rsxnt), and Jan-Jaap van der Heijden and Mumit Khan +(Mingw32; Windows32). + + The Cygwin environment (http://cygwin.com) may also be used +to compile and run gawk under Windows. For Cygwin, building and +installation is the same as under Unix: + + tar -xvpzf gawk-4.2.x.tar.gz + cd gawk-4.2.x + ./configure && make + +The `configure' step takes a long time, but works otherwise. + +******************************** N O T E ******************************* +* The `|&' operator only works when gawk is compiled for Cygwin or for * +* MinGW. Neither socket support nor two-way pipes work in any other * +* Windows environment! * +************************************************************************ + +Building gawk +------------- + +Copy the files in the `pc' directory (EXCEPT for `ChangeLog') to the +directory with the rest of the gawk sources. (The subdirectories of +`pc' need not be copied.) The Makefile contains a configuration +section with comments, and may need to be edited in order to work +with your make utility. If you are building with MinGW, copy the +file Makefile.ext to extension/Makefile. + +The "prefix" line in the Makefile is used during the install of gawk +(and in building igawk.bat and igawk.cmd). Since the libraries for +gawk will be installed under $(prefix)/lib/awk (e.g., /gnu/lib/awk), +it is convenient to have this directory in DEFPATH of config.h. + +The makefile contains a number of targets for building various DOS and +OS/2 versions. A list of targets will be printed if the make command is +given without a target. As an example, to build gawk using the djgpp +tools, enter "make djgpp". + +For the MinGW build, after you build in the top-level directory, chdir +to the extension subdirectory and say "make" there to build the +extensions. If you built gawk without libmpfr, say this instead to +build the extensions: + + make MPFR= MPFR_LIBS= + + +Testing and installing gawk +--------------------------- + +The command "make test" (and possibly "make install") requires several +Unix-like tools, including an sh-like shell, sed, cp, and cmp. Only +dmake and GNU make are known to work on "make test". + +There are two methods for the install: Method 1 uses a typical Unix-like +approach and requires cat, cp, mkdir, sed, and sh; method 2 uses gawk +and batch files. See the configuration section of the makefile. + +The file test/Makefile will need some editing (especially for DOS). A +sample makefile with comments appears in pc/Makefile.tst, and can be +used to modify test/Makefile for your platform. For starters, just +copy pc/Makefile.tst to test/Makefile, then walk through the variables +defined at the beginning and change them as appropriate for your +setup. In addition, some files in the test directory may need to have +their end-of-line markers converted, as described in Makefile.tst. + +As with building gawk, the OS, shell, and long filename issues come into +play when testing, too. If you are testing gawk on a LFN aware system with +some LFN aware tools, you may have problems if the shell that you specify in +test/Makefile is not LFN aware. This problem will apply whether or not +you are building a LFN aware gawk. See the comments in pc/Makefile.tst +for more information on this. + +It is routine to install by hand, but note that the install target also +builds igawk.bat and igawk.cmd, which are used to add an include +facility to gawk (and which require sh). + + +Gawk thanks +----------- + +The DOS maintainers wish to express their thanks to Eli Zaretskii + for his work and for the many conversations concerning +gawk, make, and djgpp. His FAQ for djgpp is essential reading, and he +was always willing to answer our questions (even when we didn't read +the relevant portions of the FAQ :). + +We are indebted to Juan Grigera for +additional help on changes for Windows32. + + +---- +If you have any problems with the DOS or OS/2 versions of Gawk, +please send bug reports (along with the version and compiler used) to + + Juan Manuel Guerrero, juan.guerrero@gmx.de (DJGPP) + +or + + andreas.buening@nexgo.de (OS/2 version) + +Support for Windows32 started in gawk-3.0.3. + +---- +From: Eric Pement +Newsgroups: comp.lang.awk +Subject: djgpp Gawk ver. 4.0 available +Date: Tue, 26 Jul 2011 06:42:00 -0700 (PDT) +MS Windows users: + +The DJGPP compilation of GNU awk v4.0.0 is now available here: + + ftp://ftp.delorie.com/pub/djgpp/current/v2gnu/gwk400b.zip + +For those who don't know the difference between the DGJPP compile and +other versions compiled for Windows, the most noticeable to me is that +it supports Unix-style use of 'single' and "double" quoting. Example: + + [c:\tmp]> :: normal Windows awk requires complex quoting + [c:\tmp]> gawk "BEGIN{ print \"hello, world\" }" + hello, world + [c:\tmp]> :: DJGPP compile of awk permits Unix quoting in CMD + [c:\tmp]> djgawk 'BEGIN{ print "hello, world" }' + hello, world + +Syntactic sugar? Sure. But it makes life easier in a Windows +environment, and without installing Cygwin ... + +Eric P. diff --git a/README_d/README.rpm b/README_d/README.rpm new file mode 100644 index 0000000..4b2831f --- /dev/null +++ b/README_d/README.rpm @@ -0,0 +1,16 @@ +Tue Oct 10 20:58:29 IDT 2017 +============================ + +If you're interested in the RPM .spec file for gawk from the +Fedora project, you can find it at: + + https://src.fedoraproject.org/rpms/gawk/blob/master/f/gawk.spec + +This is very Fedora-specific; it would need work before it could +used in a more generic fashion, but it might be useful as a +starting point. + +Thanks to David Kaspar [Dee'Kej] for the pointer. + +Arnold Robbins +arnold@skeeve.com diff --git a/README_d/README.solaris b/README_d/README.solaris new file mode 100644 index 0000000..91e0c70 --- /dev/null +++ b/README_d/README.solaris @@ -0,0 +1,14 @@ +Wed Jan 22 21:51:59 IST 2014 +============================ + +On Solaris 10 x86, Solaris 11 x86, Solaris 10 sparc and Solaris 11 sparc, +with the Sun compiler (Solaris Studio 12.3) you need to use + + c99 -Xc -D_XPG6 + +to correctly compile gawk and the extensions. + +Various tests can fail if the necessary locales aren't installed. + +Arnold Robbins +arnold@skeeve.com diff --git a/README_d/README.tests b/README_d/README.tests new file mode 100644 index 0000000..4b3d74b --- /dev/null +++ b/README_d/README.tests @@ -0,0 +1,45 @@ +Date: Sat, 22 Apr 2000 06:07:06 -0600 (MDT) +From: "Nelson H. F. Beebe" +Cc: beebe@math.utah.edu, sysstaff@math.utah.edu, othmer@math.utah.edu +Subject: gawk-3.0.4 and a GNU/Linux gotcha + +Yesterday, I was assisting a colleague install some software on his +GNU/Linux machine for which uname -r reports 2.2.14. + +A (mis)feature of this system, which I've never encountered before, +broke the build of one of my programs, and also of gawk-3.0.4. + +Namely, the kernel will not execute anything that resides in /tmp, +though it will if the same script is in /usr/tmp! + +% cat /tmp/foo.sh +#! /bin/sh +echo hello + +ls -l /tmp/foo.sh +-rwxr-xr-x 1 othmer math 22 Apr 21 10:34 /tmp/foo.sh* + +% /tmp/foo.sh +bash: /tmp/foo.sh: Permission denied + +% cp /tmp/foo.sh /usr/tmp + +% /usr/tmp/foo.sh +hello + +Thus, programs that do a temporary install in /tmp, as some of mine do +in order to run the validation suite, will fail. + +gawk-3.0.4, and likely other gawk versions, hits this problem too. It +fails because test/poundbang starts with + +#! /tmp/gawk -f + +I tracked down where it comes from: + +% grep /tmp /etc/fstab +/dev/hda3 /tmp ext2 rw,nosuid,noexec,nouser,auto,async,nodev 1 1 + !!!!!! + +Since this is done via a mount command, potentially ANY directory tree +could be mounted with noexec. diff --git a/README_d/README.zLinux b/README_d/README.zLinux new file mode 100644 index 0000000..e9dbcb6 --- /dev/null +++ b/README_d/README.zLinux @@ -0,0 +1,16 @@ +Mon Jan 25 18:45:06 IST 2016 +============================ + +For z/Linux (CentOS 4, at least), you must fix the optimization level +before compiling: + +1. Run configure. +2. Edit the top-level Makefile and extension/Makefile and change -O2 to -O1. +3. Run `make && make check' as usual. + +If you don't change the optimization level, the testext test will fail. + +In any case, expect the fmtspcl test to fail. + +Arnold Robbins +arnold@skeeve.com diff --git a/README_d/README.zos b/README_d/README.zos new file mode 100644 index 0000000..361a8ae --- /dev/null +++ b/README_d/README.zos @@ -0,0 +1,45 @@ +Fri Dec 24 10:58:16 2010 +Dave Pitts +---------------------------- + +GAWK on z/OS + +1. To unpack the tarball: + + $ gunzip -c gawk-4.0.0.tar.gz | pax -rv from=ISO8859-1,to=IBM-1047 + + This will extract the files and convert them from ASCII to EBCDIC. + + If you do not have the gunzip program on your system you can perform + the operation on another system and copy the tar file to z/OS. Then + unpack as follows: + + $ pax -rv from=ISO8859-1,to=IBM-1047 -f gawk-4.0.0.tar + + +2. To Build + + $ ./configure CC=c89 + $ make + + You will get compilation warnings of the form: + + WARNING CBC3343 ./dfa.c:332 Redeclaration of dfasyntax differs from + previous declaration on line 404 of "./dfa.h". + + Because the IBM compiler complains when a function is decalared using + prototypes in the header and is defined without prototypes in the code + these warnings can be ignored. + + +3. To Install: + + $ make install + + +4. To Test (optional): + + $ make check + + NOTE: Since the test suite was defined for an ASCII and IEEE floating point + environment several of the tests will fail under z/OS. diff --git a/TODO b/TODO new file mode 100644 index 0000000..fa6e117 --- /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 new file mode 100644 index 0000000..2e07e0a --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,1171 @@ +# generated automatically by aclocal 1.15 -*- Autoconf -*- + +# Copyright (C) 1996-2014 Free Software Foundation, Inc. + +# This file 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. + +m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, +[m4_warning([this file was generated for autoconf 2.69. +You have another version of autoconf. It may work, but is not guaranteed to. +If you have problems, you may need to regenerate the build system entirely. +To do so, use the procedure documented by the package, typically 'autoreconf'.])]) + +# Copyright (C) 2002-2014 Free Software Foundation, Inc. +# +# This file 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. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +# (This private macro should not be called outside this file.) +AC_DEFUN([AM_AUTOMAKE_VERSION], +[am__api_version='1.15' +dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to +dnl require some minimum version. Point them to the right macro. +m4_if([$1], [1.15], [], + [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl +]) + +# _AM_AUTOCONF_VERSION(VERSION) +# ----------------------------- +# aclocal traces this macro to find the Autoconf version. +# This is a private macro too. Using m4_define simplifies +# the logic in aclocal, which can simply ignore this definition. +m4_define([_AM_AUTOCONF_VERSION], []) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. +# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.15])dnl +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001-2014 Free Software Foundation, Inc. +# +# This file 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. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to +# '$srcdir', '$srcdir/..', or '$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is '.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +# Expand $ac_aux_dir to an absolute path. +am_aux_dir=`cd "$ac_aux_dir" && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997-2014 Free Software Foundation, Inc. +# +# This file 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. + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ([2.52])dnl + m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +m4_define([_AM_COND_VALUE_$1], [$2])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Copyright (C) 1999-2014 Free Software Foundation, Inc. +# +# This file 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. + + +# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], + [$1], [CXX], [depcc="$CXX" am_compiler_list=], + [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], + [$1], [UPC], [depcc="$UPC" am_compiler_list=], + [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[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_$1_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 + m4_case([$1], [CC], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac], + [CXX], + [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_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES. +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE([dependency-tracking], [dnl +AS_HELP_STRING( + [--enable-dependency-tracking], + [do not reject slow dependency extractors]) +AS_HELP_STRING( + [--disable-dependency-tracking], + [speeds up one-time build])]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' + am__nodep='_no' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +AC_SUBST([am__nodep])dnl +_AM_SUBST_NOTMAKE([am__nodep])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999-2014 Free Software Foundation, Inc. +# +# This file 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. + + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[{ + # Older Autoconf quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named 'Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running 'make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "$am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each '.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996-2014 Free Software Foundation, Inc. +# +# This file 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 macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. +m4_define([AC_PROG_CC], +m4_defn([AC_PROG_CC]) +[_AM_PROG_CC_C_O +]) + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.65])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[AC_DIAGNOSE([obsolete], + [$0: two- and three-arguments forms are deprecated.]) +m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl +dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. +m4_if( + m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), + [ok:ok],, + [m4_fatal([AC_INIT should be called with package and version arguments])])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) + AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) +AM_MISSING_PROG([AUTOCONF], [autoconf]) +AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) +AM_MISSING_PROG([AUTOHEADER], [autoheader]) +AM_MISSING_PROG([MAKEINFO], [makeinfo]) +AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +# For better backward compatibility. To be removed once Automake 1.9.x +# dies out for good. For more background, see: +# +# +AC_SUBST([mkdir_p], ['$(MKDIR_P)']) +# We need awk for the "check" target (and possibly the TAP driver). The +# system "awk" is bad on some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES([CC])], + [m4_define([AC_PROG_CC], + m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES([CXX])], + [m4_define([AC_PROG_CXX], + m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES([OBJC])], + [m4_define([AC_PROG_OBJC], + m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], + [_AM_DEPENDENCIES([OBJCXX])], + [m4_define([AC_PROG_OBJCXX], + m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl +]) +AC_REQUIRE([AM_SILENT_RULES])dnl +dnl The testsuite driver may need to know about EXEEXT, so add the +dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This +dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. +AC_CONFIG_COMMANDS_PRE(dnl +[m4_provide_if([_AM_COMPILER_EXEEXT], + [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl + +# POSIX will say in a future version that running "rm -f" with no argument +# is OK; and we want to be able to make that assumption in our Makefile +# recipes. So use an aggressive probe to check that the usage we want is +# actually supported "in the wild" to an acceptable degree. +# See automake bug#10828. +# To make any issue more visible, cause the running configure to be aborted +# by default if the 'rm' program in use doesn't match our expectations; the +# user can still override this though. +if rm -f && rm -fr && rm -rf; then : OK; else + cat >&2 <<'END' +Oops! + +Your 'rm' program seems unable to run without file operands specified +on the command line, even when the '-f' option is present. This is contrary +to the behaviour of most rm programs out there, and not conforming with +the upcoming POSIX standard: + +Please tell bug-automake@gnu.org about your system, including the value +of your $PATH and any error possibly output before this message. This +can help us improve future automake versions. + +END + if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then + echo 'Configuration will proceed anyway, since you have set the' >&2 + echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 + echo >&2 + else + cat >&2 <<'END' +Aborting the configuration process, to ensure you take notice of the issue. + +You can download and install GNU coreutils to get an 'rm' implementation +that behaves properly: . + +If you want to complete the configuration process using your problematic +'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM +to "yes", and re-run configure. + +END + AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) + fi +fi +dnl The trailing newline in this macro's definition is deliberate, for +dnl backward compatibility and to allow trailing 'dnl'-style comments +dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. +]) + +dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not +dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further +dnl mangled by Autoconf and run in a shell conditional statement. +m4_define([_AC_COMPILER_EXEEXT], +m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_arg=$1 +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001-2014 Free Software Foundation, Inc. +# +# This file 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. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +if test x"${install_sh+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi +AC_SUBST([install_sh])]) + +# Copyright (C) 2003-2014 Free Software Foundation, Inc. +# +# This file 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. + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001-2014 Free Software Foundation, Inc. +# +# This file 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. + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from 'make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997-2014 Free Software Foundation, Inc. +# +# This file 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. + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it is modern enough. +# If it is, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([missing])dnl +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --is-lightweight"; then + am_missing_run="$MISSING " +else + am_missing_run= + AC_MSG_WARN(['missing' script is too old or missing]) +fi +]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001-2014 Free Software Foundation, Inc. +# +# This file 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. + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# -------------------- +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), [1])]) + +# _AM_SET_OPTIONS(OPTIONS) +# ------------------------ +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Copyright (C) 1999-2014 Free Software Foundation, Inc. +# +# This file 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. + +# _AM_PROG_CC_C_O +# --------------- +# Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC +# to automatically call this. +AC_DEFUN([_AM_PROG_CC_C_O], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([compile])dnl +AC_LANG_PUSH([C])dnl +AC_CACHE_CHECK( + [whether $CC understands -c and -o together], + [am_cv_prog_cc_c_o], + [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) + # 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 AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ + && 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]) +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_LANG_POP([C])]) + +# For backward compatibility. +AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) + +# Copyright (C) 2001-2014 Free Software Foundation, Inc. +# +# This file 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. + +# AM_RUN_LOG(COMMAND) +# ------------------- +# Run COMMAND, save the exit status in ac_status, and log it. +# (This has been adapted from Autoconf's _AC_RUN_LOG macro.) +AC_DEFUN([AM_RUN_LOG], +[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD + ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + (exit $ac_status); }]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996-2014 Free Software Foundation, Inc. +# +# This file 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. + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[[\\\"\#\$\&\'\`$am_lf]]*) + AC_MSG_ERROR([unsafe absolute working directory name]);; +esac +case $srcdir in + *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) + AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; +esac + +# Do 'set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + am_has_slept=no + for am_try in 1 2; do + echo "timestamp, slept: $am_has_slept" > conftest.file + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken + alias in your environment]) + fi + if test "$[2]" = conftest.file || test $am_try -eq 2; then + break + fi + # Just in case. + sleep 1 + am_has_slept=yes + done + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT([yes]) +# If we didn't sleep, we still need to ensure time stamps of config.status and +# generated files are strictly newer. +am_sleep_pid= +if grep 'slept: no' conftest.file >/dev/null 2>&1; then + ( sleep 1 ) & + am_sleep_pid=$! +fi +AC_CONFIG_COMMANDS_PRE( + [AC_MSG_CHECKING([that generated files are newer than configure]) + if test -n "$am_sleep_pid"; then + # Hide warnings about reused PIDs. + wait $am_sleep_pid 2>/dev/null + fi + AC_MSG_RESULT([done])]) +rm -f conftest.file +]) + +# Copyright (C) 2009-2014 Free Software Foundation, Inc. +# +# This file 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. + +# AM_SILENT_RULES([DEFAULT]) +# -------------------------- +# Enable less verbose build rules; with the default set to DEFAULT +# ("yes" being less verbose, "no" or empty being verbose). +AC_DEFUN([AM_SILENT_RULES], +[AC_ARG_ENABLE([silent-rules], [dnl +AS_HELP_STRING( + [--enable-silent-rules], + [less verbose build output (undo: "make V=1")]) +AS_HELP_STRING( + [--disable-silent-rules], + [verbose build output (undo: "make V=0")])dnl +]) +case $enable_silent_rules in @%:@ ((( + yes) AM_DEFAULT_VERBOSITY=0;; + no) AM_DEFAULT_VERBOSITY=1;; + *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; +esac +dnl +dnl A few 'make' implementations (e.g., NonStop OS and NextStep) +dnl do not support nested variable expansions. +dnl See automake bug#9928 and bug#10237. +am_make=${MAKE-make} +AC_CACHE_CHECK([whether $am_make supports nested variables], + [am_cv_make_support_nested_variables], + [if AS_ECHO([['TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi]) +if test $am_cv_make_support_nested_variables = yes; then + dnl Using '$V' instead of '$(V)' breaks IRIX make. + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AC_SUBST([AM_V])dnl +AM_SUBST_NOTMAKE([AM_V])dnl +AC_SUBST([AM_DEFAULT_V])dnl +AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl +AC_SUBST([AM_DEFAULT_VERBOSITY])dnl +AM_BACKSLASH='\' +AC_SUBST([AM_BACKSLASH])dnl +_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl +]) + +# Copyright (C) 2001-2014 Free Software Foundation, Inc. +# +# This file 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. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor 'install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in "make install-strip", and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using 'strip' when the user +# run "make install-strip". However 'strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the 'STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Copyright (C) 2006-2014 Free Software Foundation, Inc. +# +# This file 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. + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# AM_SUBST_NOTMAKE(VARIABLE) +# -------------------------- +# Public sister of _AM_SUBST_NOTMAKE. +AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004-2014 Free Software Foundation, Inc. +# +# This file 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. + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of 'v7', 'ustar', or 'pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +# +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. Yes, it's still used +# in the wild :-( We should find a proper way to deprecate it ... +AC_SUBST([AMTAR], ['$${TAR-tar}']) + +# We'll loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' + +m4_if([$1], [v7], + [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], + + [m4_case([$1], + [ustar], + [# The POSIX 1988 'ustar' format is defined with fixed-size fields. + # There is notably a 21 bits limit for the UID and the GID. In fact, + # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 + # and bug#13588). + am_max_uid=2097151 # 2^21 - 1 + am_max_gid=$am_max_uid + # The $UID and $GID variables are not portable, so we need to resort + # to the POSIX-mandated id(1) utility. Errors in the 'id' calls + # below are definitely unexpected, so allow the users to see them + # (that is, avoid stderr redirection). + am_uid=`id -u || echo unknown` + am_gid=`id -g || echo unknown` + AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) + if test $am_uid -le $am_max_uid; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + _am_tools=none + fi + AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) + if test $am_gid -le $am_max_gid; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + _am_tools=none + fi], + + [pax], + [], + + [m4_fatal([Unknown tar format])]) + + AC_MSG_CHECKING([how to create a $1 tar archive]) + + # Go ahead even if we have the value already cached. We do so because we + # need to set the values for the 'am__tar' and 'am__untar' variables. + _am_tools=${am_cv_prog_tar_$1-$_am_tools} + + for _am_tool in $_am_tools; do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works. + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar /dev/null 2>&1 && break + fi + done + rm -rf conftest.dir + + AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) + AC_MSG_RESULT([$am_cv_prog_tar_$1])]) + +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + +m4_include([m4/arch.m4]) +m4_include([m4/codeset.m4]) +m4_include([m4/gettext.m4]) +m4_include([m4/iconv.m4]) +m4_include([m4/intlmacosx.m4]) +m4_include([m4/lcmessage.m4]) +m4_include([m4/lib-ld.m4]) +m4_include([m4/lib-link.m4]) +m4_include([m4/lib-prefix.m4]) +m4_include([m4/libsigsegv.m4]) +m4_include([m4/longlong.m4]) +m4_include([m4/mpfr.m4]) +m4_include([m4/nls.m4]) +m4_include([m4/noreturn.m4]) +m4_include([m4/po.m4]) +m4_include([m4/progtest.m4]) +m4_include([m4/readline.m4]) +m4_include([m4/socket.m4]) +m4_include([m4/ulonglong.m4]) diff --git a/array.c b/array.c new file mode 100644 index 0000000..5d953c0 --- /dev/null +++ b/array.c @@ -0,0 +1,1384 @@ +/* + * array.c - routines for awk arrays. + */ + +/* + * Copyright (C) 1986, 1988, 1989, 1991-2014, 2016, 2018, + * 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 + */ + +#include "awk.h" + +extern FILE *output_fp; +extern NODE **fmt_list; /* declared in eval.c */ + +NODE *success_node; + +static size_t SUBSEPlen; +static char *SUBSEP; +static char indent_char[] = " "; + +static NODE **null_lookup(NODE *symbol, NODE *subs); +static NODE **null_dump(NODE *symbol, NODE *subs); +static afunc_t null_array_func[] = { + (afunc_t) 0, + (afunc_t) 0, + null_length, + null_lookup, + null_afunc, + null_afunc, + null_afunc, + null_afunc, + null_afunc, + null_dump, + (afunc_t) 0, +}; + +#define MAX_ATYPE 10 + +static afunc_t *array_types[MAX_ATYPE]; +static int num_array_types = 0; + +/* array func to index mapping */ +#define AFUNC(F) (F ## _ind) + +/* register_array_func --- add routines to handle arrays */ + +int +register_array_func(afunc_t *afunc) +{ + if (afunc && num_array_types < MAX_ATYPE) { + if (afunc != str_array_func && ! afunc[AFUNC(atypeof)]) + return false; + array_types[num_array_types++] = afunc; + if (afunc[AFUNC(ainit)]) /* execute init routine if any */ + (void) (*afunc[AFUNC(ainit)])(NULL, NULL); + return true; + } + return false; +} + + +/* array_init --- register all builtin array types */ + +void +array_init() +{ + (void) register_array_func(str_array_func); /* the default */ + if (! do_mpfr) { + (void) register_array_func(int_array_func); + (void) register_array_func(cint_array_func); + } +} + + +/* make_array --- create an array node */ + +NODE * +make_array() +{ + NODE *array; + getnode(array); + memset(array, '\0', sizeof(NODE)); + array->type = Node_var_array; + array->array_funcs = null_array_func; + /* vname, flags, and parent_array not set here */ + + return array; +} + + +/* null_array --- force symbol to be an empty typeless array */ + +void +null_array(NODE *symbol) +{ + symbol->type = Node_var_array; + symbol->array_funcs = null_array_func; + symbol->buckets = NULL; + symbol->table_size = symbol->array_size = 0; + symbol->array_capacity = 0; + symbol->flags = 0; + + assert(symbol->xarray == NULL); + + /* vname, parent_array not (re)initialized */ +} + + +/* null_lookup --- assign type to an empty array. */ + +static NODE ** +null_lookup(NODE *symbol, NODE *subs) +{ + int i; + afunc_t *afunc = NULL; + + assert(symbol->table_size == 0); + + /* + * Check which array type wants to accept this sub; traverse + * array type list in reverse order. + */ + for (i = num_array_types - 1; i >= 1; i--) { + afunc = array_types[i]; + if (afunc[AFUNC(atypeof)](symbol, subs) != NULL) + break; + } + if (i == 0 || afunc == NULL) + afunc = array_types[0]; /* default is str_array_func */ + symbol->array_funcs = afunc; + + /* We have the right type of array; install the subscript */ + return symbol->alookup(symbol, subs); +} + +/* null_length --- default function for array length interface */ + +NODE ** +null_length(NODE *symbol, NODE *subs ATTRIBUTE_UNUSED) +{ + static NODE *tmp; + tmp = symbol; + return & tmp; +} + +/* null_afunc --- default function for array interface */ + +NODE ** +null_afunc(NODE *symbol ATTRIBUTE_UNUSED, NODE *subs ATTRIBUTE_UNUSED) +{ + return NULL; +} + +/* null_dump --- dump function for an empty array */ + +static NODE ** +null_dump(NODE *symbol, NODE *subs ATTRIBUTE_UNUSED) +{ + fprintf(output_fp, "array `%s' is empty\n", array_vname(symbol)); + return NULL; +} + + +/* assoc_copy --- duplicate input array "symbol" */ + +NODE * +assoc_copy(NODE *symbol, NODE *newsymb) +{ + assert(newsymb->vname != NULL); + + assoc_clear(newsymb); + (void) symbol->acopy(symbol, newsymb); + newsymb->array_funcs = symbol->array_funcs; + newsymb->flags = symbol->flags; + return newsymb; +} + + +/* assoc_dump --- dump array */ + +void +assoc_dump(NODE *symbol, NODE *ndump) +{ + if (symbol->adump) + (void) symbol->adump(symbol, ndump); +} + + +/* make_aname --- construct a 'vname' for a (sub)array */ + +const char * +make_aname(const NODE *symbol) +{ + static char *aname = NULL; + static size_t alen; + static size_t max_alen; +#define SLEN 256 + + if (symbol->parent_array != NULL) { + size_t slen; + + (void) make_aname(symbol->parent_array); + slen = strlen(symbol->vname); /* subscript in parent array */ + if (alen + slen + 4 > max_alen) { /* sizeof("[\"\"]") = 4 */ + max_alen = alen + slen + 4 + SLEN; + erealloc(aname, char *, (max_alen + 1) * sizeof(char *), "make_aname"); + } + alen += sprintf(aname + alen, "[\"%s\"]", symbol->vname); + } else { + alen = strlen(symbol->vname); + if (aname == NULL) { + max_alen = alen + SLEN; + emalloc(aname, char *, (max_alen + 1) * sizeof(char *), "make_aname"); + } else if (alen > max_alen) { + max_alen = alen + SLEN; + erealloc(aname, char *, (max_alen + 1) * sizeof(char *), "make_aname"); + } + memcpy(aname, symbol->vname, alen + 1); + } + return aname; +} +#undef SLEN + + +/* + * array_vname --- print the name of the array + * + * Returns a pointer to a statically maintained dynamically allocated string. + * It's appropriate for printing the name once; if the caller wants + * to save it, they have to make a copy. + */ + +const char * +array_vname(const NODE *symbol) +{ + static char *message = NULL; + static size_t msglen = 0; + char *s; + size_t len; + int n; + 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) + return symbol->vname; + return make_aname(symbol); + } + + /* First, we have to compute the length of the string: */ + + len = 2; /* " (" */ + n = 0; + while (symbol->type == Node_array_ref) { + len += strlen(symbol->vname); + n++; + symbol = symbol->prev_array; + } + + /* Get the (sub)array name */ + if (symbol->parent_array == NULL) + aname = symbol->vname; + else + aname = make_aname(symbol); + len += strlen(aname); + /* + * Each node contributes by strlen(from) minus the length + * of "%s" in the translation (which is at least 2) + * plus 2 for ", " or ")\0"; this adds up to strlen(from). + */ + len += n * strlen(from); + + /* (Re)allocate memory: */ + if (message == NULL) { + emalloc(message, char *, len, "array_vname"); + msglen = len; + } else if (len > msglen) { + erealloc(message, char *, len, "array_vname"); + msglen = len; + } /* else + current buffer can hold new name */ + + /* We're ready to print: */ + symbol = save_symbol; + s = message; + /* + * Ancient systems have sprintf() returning char *, not int. + * If you have one of those, use sprintf(..); s += strlen(s) instead. + */ + + s += sprintf(s, "%s (", symbol->vname); + for (;;) { + symbol = symbol->prev_array; + if (symbol->type != Node_array_ref) + break; + s += sprintf(s, from, symbol->vname); + s += sprintf(s, ", "); + } + s += sprintf(s, from, aname); + strcpy(s, ")"); + + return message; +} + + +/* + * force_array --- proceed to the actual Node_var_array, + * change Node_var_new to an array. + * If canfatal and type isn't good, die fatally, + * otherwise return the final actual value. + */ + +NODE * +force_array(NODE *symbol, bool canfatal) +{ + NODE *save_symbol = symbol; + bool isparam = false; + + if (symbol->type == Node_param_list) { + save_symbol = symbol = GET_PARAM(symbol->param_cnt); + isparam = true; + if (symbol->type == Node_array_ref) + symbol = symbol->orig_array; + } + + switch (symbol->type) { + case Node_var_new: + symbol->xarray = NULL; /* make sure union is as it should be */ + null_array(symbol); + symbol->parent_array = NULL; /* main array has no parent */ + /* fall through */ + case Node_var_array: + break; + + case Node_array_ref: + default: + /* notably Node_var but catches also e.g. a[1] = "x"; a[1][1] = "y" */ + if (canfatal) { + if (symbol->type == Node_val) + fatal(_("attempt to use a scalar value as array")); + if (isparam) + fatal(_("attempt to use scalar parameter `%s' as an array"), + save_symbol->vname); + else + fatal(_("attempt to use scalar `%s' as an array"), + save_symbol->vname); + } else + break; + } + + return symbol; +} + + +/* set_SUBSEP --- update SUBSEP related variables when SUBSEP assigned to */ + +void +set_SUBSEP() +{ + SUBSEP_node->var_value = force_string(SUBSEP_node->var_value); + SUBSEP = SUBSEP_node->var_value->stptr; + SUBSEPlen = SUBSEP_node->var_value->stlen; +} + + +/* concat_exp --- concatenate expression list into a single string */ + +NODE * +concat_exp(int nargs, bool do_subsep) +{ + /* do_subsep is false for Op_concat */ + NODE *r; + char *str; + char *s; + size_t len; + size_t subseplen = 0; + int i; + extern NODE **args_array; + + if (nargs == 1) + return POP_STRING(); + + if (do_subsep) + subseplen = SUBSEPlen; + + len = 0; + for (i = 1; i <= nargs; i++) { + r = TOP(); + if (r->type == Node_var_array) { + while (--i > 0) + DEREF(args_array[i]); /* avoid memory leak */ + fatal(_("attempt to use array `%s' in a scalar context"), array_vname(r)); + } + r = POP_STRING(); + args_array[i] = r; + len += r->stlen; + } + len += (nargs - 1) * subseplen; + + emalloc(str, char *, len + 1, "concat_exp"); + + r = args_array[nargs]; + memcpy(str, r->stptr, r->stlen); + s = str + r->stlen; + DEREF(r); + for (i = nargs - 1; i > 0; i--) { + if (subseplen == 1) + *s++ = *SUBSEP; + else if (subseplen > 0) { + memcpy(s, SUBSEP, subseplen); + s += subseplen; + } + r = args_array[i]; + memcpy(s, r->stptr, r->stlen); + s += r->stlen; + DEREF(r); + } + + return make_str_node(str, len, ALREADY_MALLOCED); +} + + +/* + * adjust_fcall_stack: remove subarray(s) of symbol[] from + * function call stack. + */ + +static void +adjust_fcall_stack(NODE *symbol, int nsubs) +{ + NODE *func, *r, *n; + NODE **sp; + int pcount; + + /* + * Solve the nasty problem of disappearing subarray arguments: + * + * function f(c, d) { delete c; .. use non-existent array d .. } + * BEGIN { a[0][0] = 1; f(a, a[0]); .. } + * + * The fix is to convert 'd' to a local empty array; This has + * to be done before clearing the parent array to avoid referring to + * already free-ed memory. + * + * Similar situations exist for builtins accepting more than + * one array argument: split, patsplit, asort and asorti. For example: + * + * BEGIN { a[0][0] = 1; split("abc", a, "", a[0]) } + * + * These cases do not involve the function call stack, and are + * handled individually in their respective routines. + */ + + func = frame_ptr->func_node; + if (func == NULL) /* in main */ + return; + pcount = func->param_cnt; + sp = frame_ptr->stack; + + for (; pcount > 0; pcount--) { + r = *sp++; + if (r->type != Node_array_ref + || r->orig_array->type != Node_var_array) + continue; + n = r->orig_array; + + /* Case 1 */ + if (n == symbol + && symbol->parent_array != NULL + && nsubs > 0 + ) { + /* + * 'symbol' is a subarray, and 'r' is the same subarray: + * + * function f(c, d) { delete c[0]; .. } + * BEGIN { a[0][0] = 1; f(a, a[0]); .. } + * + * But excludes cases like (nsubs = 0): + * + * function f(c, d) { delete c; ..} + * 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) { + assert(n->type == Node_var_array); + if (n == symbol) { + /* + * 'r' is a subarray of 'symbol': + * + * function f(c, d) { delete c; .. use d as array .. } + * BEGIN { a[0][0] = 1; f(a, a[0]); .. } + * OR + * BEGIN { a[0][0][0][0] = 1; f(a[0], a[0][0][0]); .. } + * + */ + null_array(r); + r->parent_array = NULL; + break; + } + } + } +} + + +/* do_delete --- perform `delete array[s]' */ + +/* + * `symbol' is array + * `nsubs' is no of subscripts + */ + +void +do_delete(NODE *symbol, int nsubs) +{ + NODE *val, *subs; + int i; + + assert(symbol->type == Node_var_array); + subs = val = NULL; /* silence the compiler */ + + /* + * The force_string() call is needed to make sure that + * the string subscript is reasonable. For example, with it: + * + * $ ./gawk --posix 'BEGIN { CONVFMT="%ld"; delete a[1.233]}' + * gawk: cmd. line:1: fatal: `%l' is not permitted in POSIX awk formats + * + * Without it, the code does not fail. + */ + +#define free_subs(n) do { \ + NODE *s = PEEK(n - 1); \ + if (s->type == Node_val) { \ + (void) force_string(s); /* may have side effects. */ \ + DEREF(s); \ + } \ +} while (--n > 0) + + if (nsubs == 0) { + /* delete array */ + + adjust_fcall_stack(symbol, 0); /* fix function call stack; See above. */ + assoc_clear(symbol); + return; + } + + /* NB: subscripts are in reverse order on stack */ + + for (i = nsubs; i > 0; i--) { + subs = PEEK(i - 1); + if (subs->type != Node_val) { + free_subs(i); + fatal(_("attempt to use array `%s' in a scalar context"), array_vname(subs)); + } + + val = in_array(symbol, subs); + if (val == NULL) { + if (do_lint) { + subs = force_string(subs); + 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); + return; + } + + if (i > 1) { + if (val->type != Node_var_array) { + /* e.g.: a[1] = 1; delete a[1][1] */ + + free_subs(i); + subs = force_string(subs); + fatal(_("attempt to use scalar `%s[\"%.*s\"]' as an array"), + array_vname(symbol), + (int) subs->stlen, + subs->stptr); + } + symbol = val; + DEREF(subs); + } + } + + if (val->type == Node_var_array) { + adjust_fcall_stack(val, nsubs); /* fix function call stack; See above. */ + assoc_clear(val); + /* cleared a sub-array, free Node_var_array */ + efree(val->vname); + freenode(val); + } else + unref(val); + + (void) assoc_remove(symbol, subs); + DEREF(subs); + +#undef free_subs +} + + +/* do_delete_loop --- simulate ``for (iggy in foo) delete foo[iggy]'' */ + +/* + * The primary hassle here is that `iggy' needs to have some arbitrary + * array index put in it before we can clear the array, we can't + * just replace the loop with `delete foo'. + */ + +void +do_delete_loop(NODE *symbol, NODE **lhs) +{ + NODE **list; + NODE akind; + + akind.flags = AINDEX|ADELETE; /* need a single index */ + list = symbol->alist(symbol, & akind); + + if (assoc_empty(symbol)) + return; + + unref(*lhs); + *lhs = list[0]; + efree(list); + + /* blast the array in one shot */ + adjust_fcall_stack(symbol, 0); + assoc_clear(symbol); +} + + +/* value_info --- print scalar node info */ + +static void +value_info(NODE *n) +{ + +#define PREC_NUM -1 + + if (n == Nnull_string || n == Null_field) { + fprintf(output_fp, "<(null)>"); + return; + } + + if ((n->flags & (STRING|STRCUR)) != 0) { + fprintf(output_fp, "<"); + fprintf(output_fp, "\"%.*s\"", (int) n->stlen, n->stptr); + if ((n->flags & (NUMBER|NUMCUR)) != 0) { +#ifdef HAVE_MPFR + if (is_mpg_float(n)) + fprintf(output_fp, ":%s", + mpg_fmt("%.*R*g", PREC_NUM, ROUND_MODE, n->mpg_numbr)); + else if (is_mpg_integer(n)) + fprintf(output_fp, ":%s", mpg_fmt("%Zd", n->mpg_i)); + else +#endif + fprintf(output_fp, ":%.*g", PREC_NUM, n->numbr); + } + fprintf(output_fp, ">"); + } else { +#ifdef HAVE_MPFR + if (is_mpg_float(n)) + fprintf(output_fp, "<%s>", + mpg_fmt("%.*R*g", PREC_NUM, ROUND_MODE, n->mpg_numbr)); + else if (is_mpg_integer(n)) + fprintf(output_fp, "<%s>", mpg_fmt("%Zd", n->mpg_i)); + else +#endif + fprintf(output_fp, "<%.*g>", PREC_NUM, n->numbr); + } + + fprintf(output_fp, ":%s", flags2str(n->flags)); + + 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); + /* + * 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 ? "" + : fmt_list[n->stfmt]->stptr); +#ifdef HAVE_MPFR + fprintf(output_fp, ", RNDMODE=\"%c\"", n->strndmode); +#endif + } + +#undef PREC_NUM +} + + +void +indent(int indent_level) +{ + int i; + for (i = 0; i < indent_level; i++) + fprintf(output_fp, "%s", indent_char); +} + +/* assoc_info --- print index, value info */ + +void +assoc_info(NODE *subs, NODE *val, NODE *ndump, const char *aname) +{ + int indent_level = ndump->alevel; + + indent_level++; + indent(indent_level); + fprintf(output_fp, "I: [%s:", aname); + if ((subs->flags & (MPFN|MPZN|INTIND)) == INTIND) + fprintf(output_fp, "<%ld>", (long) subs->numbr); + else + value_info(subs); + fprintf(output_fp, "]\n"); + + indent(indent_level); + if (val->type == Node_val) { + fprintf(output_fp, "V: [scalar: "); + value_info(val); + } else { + fprintf(output_fp, "V: ["); + ndump->alevel++; + ndump->adepth--; + assoc_dump(val, ndump); + ndump->adepth++; + ndump->alevel--; + indent(indent_level); + } + fprintf(output_fp, "]\n"); +} + + +/* do_adump --- dump an array: interface to assoc_dump */ + +NODE * +do_adump(int nargs) +{ + NODE *symbol, *tmp; + static NODE ndump; + long depth = 0; + + /* + * depth < 0, no index and value info. + * = 0, main array index and value info; does not descend into sub-arrays. + * > 0, descends into 'depth' sub-arrays, and prints index and value info. + */ + + if (nargs == 2) { + tmp = POP_NUMBER(); + depth = get_number_si(tmp); + DEREF(tmp); + } + symbol = POP_PARAM(); + if (symbol->type != Node_var_array) + fatal(_("adump: first argument not an array")); + + ndump.type = Node_dump_array; + ndump.adepth = depth; + ndump.alevel = 0; + assoc_dump(symbol, & ndump); + return make_number((AWKNUM) 0); +} + + +/* asort_actual --- do the actual work to sort the input array */ + +static NODE * +asort_actual(int nargs, sort_context_t ctxt) +{ + NODE *array, *dest = NULL, *result; + NODE *r, *subs, *s; + 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(); + else + s = dupnode(Nnull_string); /* "" => default sorting */ + + 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"; + else + sort_str = "@ind_str_asc"; + } + + if (nargs >= 2) { /* 2nd optional arg */ + dest = POP_PARAM(); + if (dest->type != Node_var_array) { + fatal(ctxt == ASORT ? + _("asort: second argument not an array") : + _("asorti: second argument not an array")); + } + } + + array = POP_PARAM(); + if (array->type != Node_var_array) { + fatal(ctxt == ASORT ? + _("asort: first argument not an array") : + _("asorti: first argument not an array")); + } + + if (dest != NULL) { + for (r = dest->parent_array; r != NULL; r = r->parent_array) { + if (r == array) + fatal(ctxt == ASORT ? + _("asort: cannot use a subarray of first arg for second arg") : + _("asorti: cannot use a subarray of first arg for second arg")); + } + for (r = array->parent_array; r != NULL; r = r->parent_array) { + if (r == dest) + fatal(ctxt == ASORT ? + _("asort: cannot use a subarray of second arg for first arg") : + _("asorti: cannot use a subarray of second arg for first arg")); + } + } + + /* sorting happens inside assoc_list */ + list = assoc_list(array, sort_str, ctxt); + s->stptr[s->stlen] = save; + DEREF(s); + + num_elems = assoc_length(array); + if (num_elems == 0 || list == NULL) { + /* source array is empty */ + if (dest != NULL && dest != array) + assoc_clear(dest); + if (list != NULL) + efree(list); + return make_number((AWKNUM) 0); + } + + /* + * Must not assoc_clear() the source array before constructing + * the output array. assoc_list() does not duplicate array values + * which are needed for asort(). + */ + + if (dest != NULL && dest != array) { + assoc_clear(dest); + result = dest; + } else { + /* use 'result' as a temporary destination array */ + result = make_array(); + result->vname = array->vname; + result->parent_array = array->parent_array; + } + + if (ctxt == ASORTI) { + /* We want the indices of the source array. */ + + for (i = 1, ptr = list; i <= num_elems; i++, ptr += 2) { + subs = make_number(i); + lhs = assoc_lookup(result, subs); + unref(*lhs); + *lhs = *ptr; + if (result->astore != NULL) + (*result->astore)(result, subs); + unref(subs); + } + } else { + /* We want the values of the source array. */ + + for (i = 1, ptr = list; i <= num_elems; i++) { + subs = make_number(i); + + /* free index node */ + r = *ptr++; + unref(r); + + /* value node */ + r = *ptr++; + + if (r->type == Node_val) { + lhs = assoc_lookup(result, subs); + unref(*lhs); + *lhs = dupnode(r); + } else { + NODE *arr; + 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. */ + lhs = assoc_lookup(result, subs); + unref(*lhs); + *lhs = assoc_copy(r, arr); + } + if (result->astore != NULL) + (*result->astore)(result, subs); + unref(subs); + } + } + + efree(list); + + if (result != dest) { + /* dest == NULL or dest == array */ + assoc_clear(array); + *array = *result; /* copy result into array */ + freenode(result); + } /* else + result == dest + dest != NULL and dest != array */ + + return make_number((AWKNUM) num_elems); +} + +/* do_asort --- sort array by value */ + +NODE * +do_asort(int nargs) +{ + return asort_actual(nargs, ASORT); +} + +/* do_asorti --- sort array by index */ + +NODE * +do_asorti(int nargs) +{ + return asort_actual(nargs, ASORTI); +} + + +/* + * cmp_strings --- compare two strings; logic similar to cmp_nodes() in eval.c + * except the extra case-sensitive comparison when the case-insensitive + * result is a match. + */ + +static int +cmp_strings(const NODE *n1, const NODE *n2) +{ + char *s1, *s2; + size_t len1, len2; + int ret; + size_t lmin; + + s1 = n1->stptr; + len1 = n1->stlen; + s2 = n2->stptr; + len2 = n2->stlen; + + if (len1 == 0) + return len2 == 0 ? 0 : -1; + if (len2 == 0) + return 1; + + /* len1 > 0 && len2 > 0 */ + lmin = len1 < len2 ? len1 : len2; + + if (IGNORECASE) { + const unsigned char *cp1 = (const unsigned char *) s1; + const unsigned char *cp2 = (const unsigned char *) s2; + + if (gawk_mb_cur_max > 1) { + ret = strncasecmpmbs((const unsigned char *) cp1, + (const unsigned char *) cp2, lmin); + } else { + for (ret = 0; lmin-- > 0 && ret == 0; cp1++, cp2++) + ret = casetable[*cp1] - casetable[*cp2]; + } + if (ret != 0) + return ret; + /* + * If case insensitive result is "they're the same", + * use case sensitive comparison to force distinct order. + */ + } + + ret = memcmp(s1, s2, lmin); + if (ret != 0 || len1 == len2) + return ret; + return (len1 < len2) ? -1 : 1; +} + +/* sort_up_index_string --- qsort comparison function; ascending index strings. */ + +static int +sort_up_index_string(const void *p1, const void *p2) +{ + const NODE *t1, *t2; + + /* Array indices are strings */ + t1 = *((const NODE *const *) p1); + t2 = *((const NODE *const *) p2); + return cmp_strings(t1, t2); +} + + +/* sort_down_index_str --- qsort comparison function; descending index strings. */ + +static int +sort_down_index_string(const void *p1, const void *p2) +{ + /* + * Negation versus transposed arguments: when all keys are + * distinct, as with array indices here, either method will + * transform an ascending sort into a descending one. But if + * there are equal keys--such as when IGNORECASE is honored-- + * that get disambiguated into a determisitc order, negation + * will reverse those but transposed arguments would retain + * their relative order within the rest of the reversed sort. + */ + return -sort_up_index_string(p1, p2); +} + + +/* sort_up_index_number --- qsort comparison function; ascending index numbers. */ + +static int +sort_up_index_number(const void *p1, const void *p2) +{ + const NODE *t1, *t2; + int ret; + + t1 = *((const NODE *const *) p1); + t2 = *((const NODE *const *) p2); + + ret = cmp_numbers(t1, t2); + if (ret != 0) + return ret; + + /* break a tie with the index string itself */ + t1 = force_string((NODE *) t1); + t2 = force_string((NODE *) t2); + return cmp_strings(t1, t2); +} + +/* sort_down_index_number --- qsort comparison function; descending index numbers */ + +static int +sort_down_index_number(const void *p1, const void *p2) +{ + return -sort_up_index_number(p1, p2); +} + + +/* sort_up_value_string --- qsort comparison function; ascending value string */ + +static int +sort_up_value_string(const void *p1, const void *p2) +{ + const NODE *t1, *t2; + + t1 = *((const NODE *const *) p1 + 1); + t2 = *((const NODE *const *) p2 + 1); + + if (t1->type == Node_var_array) { + /* return 0 if t2 is a sub-array too, else return 1 */ + return (t2->type != Node_var_array); + } + if (t2->type == Node_var_array) + return -1; /* t1 (scalar) < t2 (sub-array) */ + + /* t1 and t2 both have string values */ + return cmp_strings(t1, t2); +} + + +/* sort_down_value_string --- qsort comparison function; descending value string */ + +static int +sort_down_value_string(const void *p1, const void *p2) +{ + return -sort_up_value_string(p1, p2); +} + + +/* sort_up_value_number --- qsort comparison function; ascending value number */ + +static int +sort_up_value_number(const void *p1, const void *p2) +{ + NODE *t1, *t2; + int ret; + + t1 = *((NODE *const *) p1 + 1); + t2 = *((NODE *const *) p2 + 1); + + if (t1->type == Node_var_array) { + /* return 0 if t2 is a sub-array too, else return 1 */ + return (t2->type != Node_var_array); + } + if (t2->type == Node_var_array) + return -1; /* t1 (scalar) < t2 (sub-array) */ + + ret = cmp_numbers(t1, t2); + if (ret != 0) + return ret; + + /* + * Use string value to guarantee same sort order on all + * versions of qsort(). + */ + t1 = force_string(t1); + t2 = force_string(t2); + return cmp_strings(t1, t2); +} + + +/* sort_down_value_number --- qsort comparison function; descending value number */ + +static int +sort_down_value_number(const void *p1, const void *p2) +{ + return -sort_up_value_number(p1, p2); +} + + +/* sort_up_value_type --- qsort comparison function; ascending value type */ + +static int +sort_up_value_type(const void *p1, const void *p2) +{ + NODE *n1, *n2; + + /* we want to compare the element values */ + n1 = *((NODE *const *) p1 + 1); + n2 = *((NODE *const *) p2 + 1); + + /* 1. Arrays vs. scalar, scalar is less than array */ + if (n1->type == Node_var_array) { + /* return 0 if n2 is a sub-array too, else return 1 */ + return (n2->type != Node_var_array); + } + if (n2->type == Node_var_array) { + return -1; /* n1 (scalar) < n2 (sub-array) */ + } + + /* two scalars */ + (void) fixtype(n1); + (void) fixtype(n2); + + if ((n1->flags & NUMBER) != 0 && (n2->flags & NUMBER) != 0) { + return cmp_numbers(n1, n2); + } + + /* 3. All numbers are less than all strings. This is aribitrary. */ + if ((n1->flags & NUMBER) != 0 && (n2->flags & STRING) != 0) { + return -1; + } else if ((n1->flags & STRING) != 0 && (n2->flags & NUMBER) != 0) { + return 1; + } + + /* 4. Two strings */ + return cmp_strings(n1, n2); +} + +/* sort_down_value_type --- qsort comparison function; descending value type */ + +static int +sort_down_value_type(const void *p1, const void *p2) +{ + return -sort_up_value_type(p1, p2); +} + +/* sort_user_func --- user defined qsort comparison function */ + +static int +sort_user_func(const void *p1, const void *p2) +{ + NODE *idx1, *idx2, *val1, *val2, *r; + int ret; + INSTRUCTION *code; + + idx1 = *((NODE *const *) p1); + idx2 = *((NODE *const *) p2); + val1 = *((NODE *const *) p1 + 1); + val2 = *((NODE *const *) p2 + 1); + + code = TOP()->code_ptr; /* comparison function call instructions */ + + /* setup 4 arguments to comp_func() */ + UPREF(idx1); + PUSH(idx1); + if (val1->type == Node_val) + UPREF(val1); + PUSH(val1); + + UPREF(idx2); + PUSH(idx2); + if (val2->type == Node_val) + UPREF(val2); + PUSH(val2); + + /* execute the comparison function */ + (void) (*interpret)(code); + + /* return value of the comparison function */ + r = POP_NUMBER(); +#ifdef HAVE_MPFR + /* + * mpfr_sgn(mpz_sgn): Returns a positive value if op > 0, + * zero if op = 0, and a negative value if op < 0. + */ + if (is_mpg_float(r)) + ret = mpfr_sgn(r->mpg_numbr); + else if (is_mpg_integer(r)) + ret = mpz_sgn(r->mpg_i); + else +#endif + ret = (r->numbr < 0.0) ? -1 : (r->numbr > 0.0); + DEREF(r); + return ret; +} + + +/* 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) +{ + typedef int (*qsort_compfunc)(const void *, const void *); + + static const struct qsort_funcs { + const char *name; + qsort_compfunc comp_func; + assoc_kind_t kind; + } sort_funcs[] = { +{ "@ind_str_asc", sort_up_index_string, AINDEX|AISTR|AASC }, +{ "@ind_num_asc", sort_up_index_number, AINDEX|AINUM|AASC }, +{ "@val_str_asc", sort_up_value_string, AVALUE|AVSTR|AASC }, +{ "@val_num_asc", sort_up_value_number, AVALUE|AVNUM|AASC }, +{ "@ind_str_desc", sort_down_index_string, AINDEX|AISTR|ADESC }, +{ "@ind_num_desc", sort_down_index_number, AINDEX|AINUM|ADESC }, +{ "@val_str_desc", sort_down_value_string, AVALUE|AVSTR|ADESC }, +{ "@val_num_desc", sort_down_value_number, AVALUE|AVNUM|ADESC }, +{ "@val_type_asc", sort_up_value_type, AVALUE|AASC }, +{ "@val_type_desc", sort_down_value_type, AVALUE|ADESC }, +{ "@unsorted", 0, AINDEX }, +}; + + /* + * N.B.: AASC and ADESC are hints to the specific array types. + * See cint_list() in cint_array.c. + */ + + NODE **list; + NODE akind; + unsigned long num_elems, j; + int elem_size, qi; + qsort_compfunc cmp_func = 0; + INSTRUCTION *code = NULL; + 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++) { + if (strcmp(sort_funcs[qi].name, sort_str) == 0) + break; + } + + if (qi < j) { + cmp_func = sort_funcs[qi].comp_func; + assoc_kind = sort_funcs[qi].kind; + + if (symbol->array_funcs != cint_array_func) + assoc_kind &= ~(AASC|ADESC); + + if (sort_ctxt != SORTED_IN || (assoc_kind & AVALUE) != 0) { + /* need index and value pair in the list */ + + assoc_kind |= (AINDEX|AVALUE); + elem_size = 2; + } + + } else { /* unrecognized */ + NODE *f; + const char *sp; + + for (sp = sort_str; *sp != '\0' && ! isspace((unsigned char) *sp); sp++) + continue; + + /* empty string or string with space(s) not valid as function name */ + if (sp == sort_str || *sp != '\0') + fatal(_("`%s' is invalid as a function name"), sort_str); + + f = lookup(sort_str); + if (f == NULL || f->type != Node_func) + fatal(_("sort comparison function `%s' is not defined"), sort_str); + + cmp_func = sort_user_func; + + /* need index and value pair in the list */ + assoc_kind |= (AVALUE|AINDEX); + elem_size = 2; + + /* make function call instructions */ + code = bcalloc(Op_func_call, 2, 0); + 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); + + /* + * make non-redirected getline, exit, `next' and `nextfile' fatal in + * callback function by setting currule in interpret() + * to undefined (0). + */ + + save_rule = currule; /* save current rule */ + currule = 0; + + PUSH_CODE(code); + } + + akind.flags = (unsigned int) assoc_kind; /* kludge */ + list = symbol->alist(symbol, & akind); + assoc_kind = (assoc_kind_t) akind.flags; /* symbol->alist can modify it */ + + /* 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]; + + /* give back extra memory */ + + erealloc(list, NODE **, num_elems * sizeof(NODE *), "assoc_list"); + } + } + + if (cmp_func == sort_user_func) { + code = POP_CODE(); + currule = save_rule; /* restore current rule */ + bcfree(code->nexti); /* Op_stop */ + bcfree(code); /* Op_func_call */ + } + + return list; +} diff --git a/awk.h b/awk.h new file mode 100644 index 0000000..3b351c2 --- /dev/null +++ b/awk.h @@ -0,0 +1,2048 @@ +/* + * awk.h -- Definitions for gawk. + */ + +/* + * Copyright (C) 1986, 1988, 1989, 1991-2018 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 + */ + +/* ------------------------------ Includes ------------------------------ */ + +/* + * config.h absolutely, positively, *M*U*S*T* be included before + * any system headers. Otherwise, extreme death, destruction + * and loss of life results. + */ +#if defined(_TANDEM_SOURCE) +/* + * config.h forces this even on non-tandem systems but it + * causes problems elsewhere if used in the check below. + * so workaround it. bleah. + */ +#define tandem_for_real 1 +#endif + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 /* enable GNU extensions */ +#endif /* _GNU_SOURCE */ + +#if defined(tandem_for_real) && ! defined(_SCO_DS) +#define _XOPEN_SOURCE_EXTENDED 1 +#endif + +#include +#include +#ifdef HAVE_LIMITS_H +#include +#endif /* HAVE_LIMITS_H */ +#include +#include + +#include "gettext.h" +#define _(msgid) gettext(msgid) +#define N_(msgid) msgid + +#if ! (defined(HAVE_LIBINTL_H) && defined(ENABLE_NLS) && ENABLE_NLS > 0) +#ifndef LOCALEDIR +#define LOCALEDIR NULL +#endif /* LOCALEDIR */ +#endif + +#if !defined(__STDC__) || __STDC__ < 1 +#error "gawk no longer supports non-C89 environments (no __STDC__ or __STDC__ < 1)" +#endif + +#if defined(HAVE_STDARG_H) +#include +#else +#error "gawk no longer supports . Please update your compiler and runtime" +#endif +#include +#include +#include +#if ! defined(errno) +extern int errno; +#endif + +#ifdef STDC_HEADERS +#include +#endif /* not STDC_HEADERS */ + +#ifdef HAVE_STDBOOL_H +#include +#else +#include "missing_d/gawkbool.h" +#endif + +/* We can handle multibyte strings. */ +#include +#include + +#include "mbsupport.h" /* defines stuff for DJGPP to fake MBS */ + +#ifdef STDC_HEADERS +#include +#endif + +#undef CHARBITS +#undef INTBITS + +#if HAVE_INTTYPES_H +# include +#endif +#if HAVE_STDINT_H +# include +#endif + +/* ----------------- System dependencies (with more includes) -----------*/ + +/* This section is the messiest one in the file, not a lot that can be done */ + +#ifndef VMS +#ifdef HAVE_FCNTL_H +#include +#endif +#include +#include +#else /* VMS */ +#include +#include +#include /* avoid in io.c */ +/* debug.c needs this; when _DECC_V4_SOURCE is defined (as it is + in our config.h [vms/vms-conf.h]), off_t won't get declared */ +# if !defined(__OFF_T) && !defined(_OFF_T) +# if defined(____OFF_T) || defined(___OFF_T) +typedef __off_t off_t; /* __off_t is either int or __int64 */ +# else +typedef int off_t; +# endif +# endif +#endif /* VMS */ + +#include "protos.h" + +#ifdef HAVE_STRING_H +#include +#ifdef NEED_MEMORY_H +#include +#endif /* NEED_MEMORY_H */ +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +#include +#endif /* HAVE_STRINGS_H */ + +#if HAVE_UNISTD_H +#include +#endif /* HAVE_UNISTD_H */ + +#ifdef VMS +#include +#include "vms/redirect.h" +#endif /*VMS*/ + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#ifndef HAVE_SETLOCALE +#define setlocale(locale, val) /* nothing */ +#endif /* HAVE_SETLOCALE */ + +#if HAVE_MEMCPY_ULONG +extern char *memcpy_ulong(char *dest, const char *src, unsigned long l); +#define memcpy memcpy_ulong +#endif +#if HAVE_MEMSET_ULONG +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(__DJGPP__) || defined(__EMX__) || defined(__MINGW32__) +#include "nonposix.h" +#endif /* defined(__DJGPP__) || defined(__EMX__) || defined(__MINGW32__) */ + +/* use this as lintwarn("...") + this is a hack but it gives us the right semantics */ +#define lintwarn (*(set_loc(__FILE__, __LINE__),lintfunc)) +/* same thing for warning */ +#define warning (*(set_loc(__FILE__, __LINE__),r_warning)) + +#ifdef HAVE_MPFR +#include +#include +#ifndef MPFR_RNDN +/* for compatibility with MPFR 2.X */ +#define MPFR_RNDN GMP_RNDN +#define MPFR_RNDZ GMP_RNDZ +#define MPFR_RNDU GMP_RNDU +#define MPFR_RNDD GMP_RNDD +#endif +#endif + +#include "regex.h" +#include "dfa.h" +typedef struct Regexp { + struct re_pattern_buffer pat; + struct re_registers regs; + struct dfa *dfareg; + 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] +#define SUBPATSTART(rp,s,n) (rp)->regs.start[n] +#define SUBPATEND(rp,s,n) (rp)->regs.end[n] +#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 */ + +#include "gawkapi.h" + +/* Stuff for losing systems. */ +#if !defined(HAVE_STRTOD) +extern double gawk_strtod(); +#define strtod gawk_strtod +#endif + +#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) +# define __attribute__(x) +#endif + +#ifndef ATTRIBUTE_UNUSED +#define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) +#endif /* ATTRIBUTE_UNUSED */ + +#ifndef ATTRIBUTE_NORETURN +#define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__)) +#endif /* ATTRIBUTE_NORETURN */ + +#ifndef ATTRIBUTE_PRINTF +#define ATTRIBUTE_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n))) +#define ATTRIBUTE_PRINTF_1 ATTRIBUTE_PRINTF(1, 2) +#define ATTRIBUTE_PRINTF_2 ATTRIBUTE_PRINTF(2, 3) +#endif /* ATTRIBUTE_PRINTF */ + +/* ------------------ Constants, Structures, Typedefs ------------------ */ + +#define AWKNUM double + +enum defrule { BEGIN = 1, Rule, END, BEGINFILE, ENDFILE, + MAXRULE /* sentinel, not legal */ }; +extern const char *const ruletab[]; + + +typedef enum nodevals { + /* illegal entry == 0 */ + Node_illegal, + + Node_val, /* node is a value - type in flags */ + Node_regex, /* a regexp, text, compiled, flags, etc */ + Node_dynregex, /* a dynamic regexp */ + + /* symbol table values */ + Node_var, /* scalar variable, lnode is value */ + Node_var_array, /* array is ptr to elements, table_size num of eles */ + Node_var_new, /* newly created variable, may become an array */ + 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_builtin_func, /* built-in function, main use is for FUNCTAB */ + + Node_array_ref, /* array passed by ref as parameter */ + Node_array_tree, /* Hashed array tree (HAT) */ + Node_array_leaf, /* Linear 1-D array */ + Node_dump_array, /* array info */ + + /* program execution -- stack item types */ + Node_arrayfor, + Node_frame, + Node_instruction, + + Node_final /* sentry value, not legal */ +} NODETYPE; + +struct exp_node; + +typedef union bucket_item { + struct { + union bucket_item *next; + char *str; + size_t len; + size_t code; + struct exp_node *name; + struct exp_node *val; + } hs; + struct { + union bucket_item *next; + long li[2]; + struct exp_node *val[2]; + size_t cnt; + } hi; +} BUCKET; + +/* string hash table */ +#define ahnext hs.next +#define ahname hs.name /* a string index node */ +#define ahname_str hs.str /* shallow copy; = ahname->stptr */ +#define ahname_len hs.len /* = ahname->stlen */ +#define ahvalue hs.val +#define ahcode hs.code + +/* integer hash table */ +#define ainext hi.next +#define ainum hi.li /* integer indices */ +#define aivalue hi.val +#define aicount hi.cnt + +struct exp_instruction; + +typedef int (*Func_print)(FILE *, const char *, ...); +typedef struct exp_node **(*afunc_t)(struct exp_node *, struct exp_node *); + +/* + * NOTE - this struct is a rather kludgey -- it is packed to minimize + * space usage, at the expense of cleanliness. Alter at own risk. + */ +typedef struct exp_node { + union { + struct { + union { + struct exp_node *lptr; + struct exp_instruction *li; + long ll; + afunc_t *lp; + } l; + union { + struct exp_node *rptr; + Regexp *preg[2]; + struct exp_node **av; + BUCKET **bv; + void (*uptr)(void); + struct exp_instruction *iptr; + } r; + union { + struct exp_node *extra; + void (*aptr)(void); + long xl; + } x; + char *name; + size_t reserved; + struct exp_node *rn; + unsigned long cnt; + unsigned long reflags; +# define CONSTANT 1 +# define FS_DFLT 2 + } nodep; + + struct { +#ifdef HAVE_MPFR + union { + AWKNUM fltnum; + mpfr_t mpnum; + mpz_t mpi; + } nm; + int rndmode; +#else + AWKNUM fltnum; +#endif + char *sp; + size_t slen; + long sref; + int idx; + wchar_t *wsp; + size_t wslen; + struct exp_node *typre; + } val; + } sub; + NODETYPE type; + unsigned int flags; + +/* type = Node_val */ + /* + * 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, + * + * a = 5 # NUMBER | NUMCUR + * b = a "" # Adds STRCUR to a, since a string value + * # is now available. But the type hasn't changed! + * + * a = "42" # STRING | STRCUR + * b = a + 0 # Adds NUMCUR to a, since numeric value + * # is now available. But the type hasn't changed! + * + * 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|USER_INPUT and then when used where + * a number is needed, it gets turned into a NUMBER and STRING + * 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.) + * we create the corresponding wide character string and store it, + * and add WSTRCUR to the flags so that we don't have to do the + * conversion more than once. + * + * The NUMINT flag may be used with a value of any type -- NUMBER, + * STRING, or STRNUM. It indicates that the string representation + * equals the result of sprintf("%ld", ). So, for + * example, NUMINT should NOT be set if it's a strnum or string value + * where the string is " 1" or "01" or "+1" or "1.0" or "0.1E1". This + * is a hint to indicate that an integer array optimization may be + * used when this value appears as a subscript. + * + * 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 USER_INPUT 0x0020 /* user input: if NUMERIC then + * a NUMBER */ +# 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 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 0x4000 /* array is at max size */ +# define HALFHAT 0x8000 /* half-capacity Hashed Array Tree; + * See cint_array.c */ +# 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 rnode sub.nodep.r.rptr + +/* Node_param_list */ +#define param vname +#define dup_ent sub.nodep.r.rptr + +/* Node_param_list, Node_func */ +#define param_cnt sub.nodep.l.ll + +/* Node_func */ +#define fparms sub.nodep.rn +#define code_ptr sub.nodep.r.iptr + +/* Node_regex, Node_dynregex */ +#define re_reg sub.nodep.r.preg +#define re_flags sub.nodep.reflags +#define re_text lnode +#define re_exp sub.nodep.x.extra +#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 +#define stfmt sub.val.idx +#define strndmode sub.val.rndmode +#define wstptr sub.val.wsp +#define wstlen sub.val.wslen +#ifdef HAVE_MPFR +#define mpg_numbr sub.val.nm.mpnum +#define mpg_i sub.val.nm.mpi +#define numbr sub.val.nm.fltnum +#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 +#define for_list_size sub.nodep.reflags +#define cur_idx sub.nodep.l.ll +#define for_array sub.nodep.rn + +/* Node_frame: */ +#define stack sub.nodep.r.av +#define func_node sub.nodep.x.extra +#define prev_frame_size sub.nodep.reflags +#define reti sub.nodep.l.li +#define num_tail_calls sub.nodep.cnt + +/* Node_var: */ +#define var_value lnode +#define var_update sub.nodep.r.uptr +#define var_assign sub.nodep.x.aptr + +/* Node_var_array: */ +#define buckets sub.nodep.r.bv +#define nodes sub.nodep.r.av +#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 ainit array_funcs[0] +#define ainit_ind 0 +#define atypeof array_funcs[1] +#define atypeof_ind 1 +#define alength array_funcs[2] +#define alength_ind 2 +#define alookup array_funcs[3] +#define alookup_ind 3 +#define aexists array_funcs[4] +#define aexists_ind 4 +#define aclear array_funcs[5] +#define aclear_ind 5 +#define aremove array_funcs[6] +#define aremove_ind 6 +#define alist array_funcs[7] +#define alist_ind 7 +#define acopy array_funcs[8] +#define acopy_ind 8 +#define adump array_funcs[9] +#define adump_ind 9 +#define astore array_funcs[10] +#define astore_ind 10 +#define NUM_AFUNCS 11 /* # of entries in array_funcs */ + +/* Node_array_ref: */ +#define orig_array lnode +#define prev_array rnode + +/* Node_array_print */ +#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, + LINT_assign_in_cond, + LINT_no_effect +} LINTTYPE; + +/* --------------------------------Instruction ---------------------------------- */ + +typedef enum opcodeval { + Op_illegal = 0, /* illegal entry */ + + /* binary operators */ + Op_times, + Op_times_i, + Op_quotient, + Op_quotient_i, + Op_mod, + Op_mod_i, + Op_plus, + Op_plus_i, + Op_minus, + Op_minus_i, + Op_exp, + Op_exp_i, + Op_concat, + + /* line range instruction pair */ + Op_line_range, /* flags for Op_cond_pair */ + Op_cond_pair, /* conditional pair */ + + Op_subscript, + Op_sub_array, + + /* unary operators */ + Op_preincrement, + Op_predecrement, + Op_postincrement, + Op_postdecrement, + Op_unary_minus, + Op_unary_plus, + Op_field_spec, + + /* unary relationals */ + Op_not, + + /* assignments */ + Op_assign, + Op_store_var, /* simple variable assignment optimization */ + Op_store_sub, /* array[subscript] assignment optimization */ + Op_store_field, /* $n assignment optimization */ + Op_assign_times, + Op_assign_quotient, + Op_assign_mod, + Op_assign_plus, + Op_assign_minus, + Op_assign_exp, + Op_assign_concat, + + /* boolean binaries */ + Op_and, /* a left subexpression in && */ + Op_and_final, /* right subexpression of && */ + Op_or, + Op_or_final, + + /* binary relationals */ + Op_equal, + Op_notequal, + Op_less, + Op_greater, + Op_leq, + Op_geq, + Op_match, + Op_match_rec, /* match $0 */ + Op_nomatch, + + Op_rule, + + /* keywords */ + Op_K_case, + Op_K_default, + Op_K_break, + Op_K_continue, + Op_K_print, + Op_K_print_rec, + Op_K_printf, + Op_K_next, + Op_K_exit, + Op_K_return, + Op_K_delete, + Op_K_delete_loop, + Op_K_getline_redir, + Op_K_getline, + Op_K_nextfile, + + Op_builtin, + Op_sub_builtin, /* sub, gsub and gensub */ + Op_ext_builtin, + Op_in_array, /* boolean test of membership in array */ + + /* function call instruction */ + Op_func_call, + Op_indirect_func_call, + + 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, + Op_push_param, + Op_push_lhs, + Op_subscript_lhs, + Op_field_spec_lhs, + Op_no_op, /* jump target */ + Op_pop, /* pop an item from the runtime stack */ + Op_jmp, + Op_jmp_true, + Op_jmp_false, + Op_get_record, + Op_newfile, + Op_arrayfor_init, + Op_arrayfor_incr, + Op_arrayfor_final, + + Op_var_update, /* update value of NR, NF or FNR */ + Op_var_assign, + Op_field_assign, + Op_subscript_assign, + Op_after_beginfile, + Op_after_endfile, + + Op_func, + + Op_comment, /* for pretty printing */ + Op_exec_count, + Op_breakpoint, + Op_lint, + Op_atexit, + Op_stop, + + /* parsing (yylex and yyparse), should never appear in valid compiled code */ + Op_token, + Op_symbol, + Op_list, + + /* program structures -- for use in the profiler/pretty printer */ + Op_K_do, + Op_K_for, + Op_K_arrayfor, + Op_K_while, + Op_K_switch, + Op_K_if, + Op_K_else, + Op_K_function, + Op_cond_exp, + Op_parens, + Op_final /* sentry value, not legal */ +} OPCODE; + +enum redirval { + /* I/O redirections */ + redirect_none = 0, + redirect_output, + redirect_append, + redirect_pipe, + redirect_pipein, + redirect_input, + redirect_twoway +}; + +struct break_point; + +typedef struct exp_instruction { + struct exp_instruction *nexti; + union { + NODE *dn; + struct exp_instruction *di; + NODE *(*fptr)(int); + awk_value_t *(*efptr)(int num_actual_args, + awk_value_t *result, + struct awk_ext_func *finfo); + long dl; + char *name; + } d; + + union { + long xl; + NODE *xn; + 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; + +#define func_name d.name + +#define memory d.dn +#define builtin d.fptr +#define extfunc d.efptr +#define builtin_idx d.dl + +#define expr_count x.xl + +#define c_function x.exf + +#define target_continue d.di +#define target_jmp d.di +#define target_break x.xi + +/* Op_sub_builtin */ +#define sub_flags d.dl +#define GSUB 0x01 /* builtin is gsub */ +#define GENSUB 0x02 /* builtin is gensub */ +#define LITERAL 0x04 /* target is a literal string */ + + +/* Op_K_exit */ +#define target_end d.di +#define target_atexit x.xi + +/* Op_newfile, Op_K_getline, Op_nextfile */ +#define target_endfile x.xi + +/* Op_newfile */ +#define target_get_record x.xi + +/* Op_get_record, Op_K_nextfile */ +#define target_newfile d.di + +/* Op_K_getline */ +#define target_beginfile d.di + +/* Op_get_record */ +#define has_endfile x.xl + +/* Op_token */ +#define lextok d.name +#define param_count x.xl + +/* Op_rule */ +#define in_rule x.xl +#define source_file d.name + + /* Op_K_case, Op_K_default */ +#define case_stmt x.xi +#define case_exp d.di +#define stmt_start case_exp +#define stmt_end case_stmt +#define match_exp x.xl + +#define target_stmt x.xi + +/* Op_K_switch */ +#define switch_end x.xi +#define switch_start d.di + +/* Op_K_getline, Op_K_getline_redir */ +#define into_var x.xl + +/* Op_K_getline_redir, Op_K_print, Op_K_print_rec, Op_K_printf */ +#define redir_type d.dl + +/* Op_arrayfor_incr */ +#define array_var x.xn + +/* Op_line_range */ +#define triggered x.xl + +/* Op_cond_pair */ +#define line_range x.xi + +/* Op_func_call, Op_func */ +#define func_body x.xn + +/* Op_func_call */ +#define tail_call d.dl + +/* Op_subscript */ +#define sub_count d.dl + +/* Op_push_lhs, Op_subscript_lhs, Op_field_spec_lhs */ +#define do_reference x.xl + +/* Op_list, Op_rule, Op_func */ +#define lasti d.di +#define firsti x.xi + +/* Op_rule, Op_func */ +#define last_line x.xl +#define first_line source_line + +/* Op_lint */ +#define lint_type d.dl + +/* Op_field_spec_lhs */ +#define target_assign d.di + +/* Op_var_assign */ +#define assign_var x.aptr + +/* Op_var_update */ +#define update_var x.aptr + +/* Op_field_assign */ +#define field_assign x.aptr + +/* Op_field_assign, Op_var_assign */ +#define assign_ctxt d.dl + +/* Op_concat */ +#define concat_flag d.dl +#define CSUBSEP 1 +#define CSVAR 2 + +/* Op_breakpoint */ +#define break_pt x.bpt + +/*------------------ pretty printing/profiling --------*/ +/* Op_exec_count */ +#define exec_count d.dl + +/* Op_K_while */ +#define while_body d.di + +/* Op_K_do */ +#define doloop_cond d.di + +/* Op_K_for */ +#define forloop_cond d.di +#define forloop_body x.xi + +/* Op_K_if */ +#define branch_if d.di +#define branch_else x.xi + +/* Op_K_else */ +#define branch_end x.xi + +/* Op_line_range */ +#define condpair_left d.di +#define condpair_right x.xi + +/* Op_store_var */ +#define initval x.xn + +typedef struct iobuf { + awk_input_buf_t public; /* exposed to extensions */ + char *buf; /* start data buffer */ + char *off; /* start of current record in buffer */ + char *dataend; /* first byte in buffer to hold new data, + NULL if not read yet */ + char *end; /* end of buffer */ + size_t readsize; /* set from fstat call */ + size_t size; /* buffer size */ + ssize_t count; /* amount read last time */ + size_t scanoff; /* where we were in the buffer when we had + to regrow/refill */ + bool valid; + int errcode; + + int flag; +# define IOP_IS_TTY 1 +# define IOP_AT_EOF 2 +# define IOP_CLOSED 4 +# define IOP_AT_START 8 +} IOBUF; + +typedef void (*Func_ptr)(void); + +/* structure used to dynamically maintain a linked-list of open files/pipes */ +struct redirect { + unsigned int flag; +# define RED_FILE 1 +# define RED_PIPE 2 +# define RED_READ 4 +# define RED_WRITE 8 +# define RED_APPEND 16 +# define RED_NOBUF 32 +# define RED_USED 64 /* closed temporarily to reuse fd */ +# define RED_EOF 128 +# define RED_TWOWAY 256 +# define RED_PTY 512 +# define RED_SOCKET 1024 +# define RED_TCP 2048 + char *value; + FILE *ifp; /* input fp, needed for PIPES_SIMULATED */ + IOBUF *iop; + int pid; + int status; + struct redirect *prev; + struct redirect *next; + const char *mode; + awk_output_buf_t output; +}; + +/* values for BINMODE, used as bit flags */ + +enum binmode_values { + TEXT_TRANSLATE = 0, /* usual \r\n ---> \n translation */ + BINMODE_INPUT = 1, /* no translation for input files */ + BINMODE_OUTPUT = 2, /* no translation for output files */ + BINMODE_BOTH = 3 /* no translation for either */ +}; + +/* + * structure for our source, either a command line string or a source file. + */ + +typedef struct srcfile { + struct srcfile *next; + struct srcfile *prev; + + enum srctype { + SRC_CMDLINE = 1, + SRC_STDIN, + SRC_FILE, + SRC_INC, + SRC_EXTLIB + } stype; + char *src; /* name on command line or include statement */ + char *fullpath; /* full path after AWKPATH search */ + time_t mtime; + struct stat sbuf; + int srclines; /* no of lines in source */ + size_t bufsize; + char *buf; + int *line_offset; /* offset to the beginning of each line */ + int fd; + int maxlen; /* size of the longest line */ + + void (*fini_func)(); /* dynamic extension of type SRC_EXTLIB */ + + char *lexptr; + char *lexend; + char *lexeme; + char *lexptr_begin; + 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_POOL pools; + NODE symbols; + INSTRUCTION rule_list; + SRCFILE srcfiles; + int sourceline; + char *source; + void (*install_func)(NODE *); + struct context *prev; +} AWK_CONTEXT; + +/* for debugging purposes */ +struct flagtab { + int val; + const char *name; +}; + + +struct block_item { + struct block_item *freep; +}; + +struct block_header { + struct block_item *freep; + size_t size; +}; + +enum block_id { + BLOCK_NODE = 0, + BLOCK_BUCKET, + BLOCK_MPFR, + BLOCK_MPZ, + BLOCK_MAX /* count */ +}; + +typedef int (*Func_pre_exec)(INSTRUCTION **); +typedef void (*Func_post_exec)(INSTRUCTION *); + +#ifndef LONG_MAX +#define LONG_MAX ((long)(~(1L << (sizeof (long) * 8 - 1)))) +#endif +#ifndef ULONG_MAX +#define ULONG_MAX (~(unsigned long)0) +#endif +#ifndef LONG_MIN +#define LONG_MIN ((long)(-LONG_MAX - 1L)) +#endif +#define UNLIMITED LONG_MAX + +/* -------------------------- External variables -------------------------- */ +/* gawk builtin variables */ +extern long NF; +extern long NR; +extern long FNR; +extern int BINMODE; +extern bool IGNORECASE; +extern bool RS_is_null; +extern char *OFS; +extern int OFSlen; +extern char *ORS; +extern int ORSlen; +extern char *OFMT; +extern char *CONVFMT; +extern int CONVFMTidx; +extern int OFMTidx; +#ifdef HAVE_MPFR +extern int MPFR_round_mode; +#endif +extern char *TEXTDOMAIN; +extern NODE *BINMODE_node, *CONVFMT_node, *FIELDWIDTHS_node, *FILENAME_node; +extern NODE *FNR_node, *FS_node, *IGNORECASE_node, *NF_node; +extern NODE *NR_node, *OFMT_node, *OFS_node, *ORS_node, *RLENGTH_node; +extern NODE *RSTART_node, *RS_node, *RT_node, *SUBSEP_node, *PROCINFO_node; +extern NODE *LINT_node, *ERRNO_node, *TEXTDOMAIN_node, *FPAT_node; +extern NODE *PREC_node, *ROUNDMODE_node; +extern NODE *Nnull_string; +extern NODE *Null_field; +extern NODE **fields_arr; +extern int sourceline; +extern char *source; +extern int (*interpret)(INSTRUCTION *); /* interpreter routine */ +extern NODE *(*make_number)(double); /* double instead of AWKNUM on purpose */ +extern NODE *(*str2number)(NODE *); +extern NODE *(*format_val)(const char *, int, NODE *); +extern int (*cmp_numbers)(const NODE *, const NODE *); + +/* built-in array types */ +extern afunc_t str_array_func[]; +extern afunc_t cint_array_func[]; +extern afunc_t int_array_func[]; + +/* special node used to indicate success in array routines (not NULL) */ +extern NODE *success_node; + +extern struct block_header nextfree[]; +extern bool field0_valid; + +extern int do_flags; + +extern SRCFILE *srcfiles; /* source files */ + +enum do_flag_values { + DO_LINT_INVALID = 0x0001, /* only warn about invalid */ + DO_LINT_ALL = 0x0002, /* warn about all things */ + DO_LINT_OLD = 0x0004, /* warn about stuff not in V7 awk */ + DO_TRADITIONAL = 0x0008, /* no gnu extensions, add traditional weirdnesses */ + DO_POSIX = 0x0010, /* turn off gnu and unix extensions */ + DO_INTL = 0x0020, /* dump locale-izable strings to stdout */ + DO_NON_DEC_DATA = 0x0040, /* allow octal/hex C style DATA. Use with caution! */ + DO_INTERVALS = 0x0080, /* allow {...,...} in regexps, see resetup() */ + DO_PRETTY_PRINT = 0x0100, /* pretty print the program */ + DO_DUMP_VARS = 0x0200, /* dump all global variables at end */ + DO_TIDY_MEM = 0x0400, /* release vars when done */ + DO_SANDBOX = 0x0800, /* sandbox mode - disable 'system' function & redirections */ + DO_PROFILE = 0x1000, /* profile the program */ + DO_DEBUG = 0x2000, /* debug the program */ + DO_MPFR = 0x4000 /* arbitrary-precision floating-point math */ +}; + +#define do_traditional (do_flags & DO_TRADITIONAL) +#define do_posix (do_flags & DO_POSIX) +#define do_intl (do_flags & DO_INTL) +#define do_non_decimal_data (do_flags & DO_NON_DEC_DATA) +#define do_intervals (do_flags & DO_INTERVALS) +#define do_pretty_print (do_flags & DO_PRETTY_PRINT) +#define do_profile (do_flags & DO_PROFILE) +#define do_dump_vars (do_flags & DO_DUMP_VARS) +#define do_tidy_mem (do_flags & DO_TIDY_MEM) +#define do_sandbox (do_flags & DO_SANDBOX) +#define do_debug (do_flags & DO_DEBUG) +#define do_mpfr (do_flags & DO_MPFR) + +extern bool do_optimize; +extern int use_lc_numeric; +extern int exit_val; + +#ifdef NO_LINT +#define do_lint 0 +#define do_lint_old 0 +#else +#define do_lint (do_flags & (DO_LINT_INVALID|DO_LINT_ALL)) +#define do_lint_old (do_flags & DO_LINT_OLD) +#endif +extern int gawk_mb_cur_max; + +#if defined (HAVE_GETGROUPS) && defined(NGROUPS_MAX) && NGROUPS_MAX > 0 +extern GETGROUPS_T *groupset; +extern int ngroups; +#endif + +#ifdef HAVE_LOCALE_H +extern struct lconv loc; +#endif /* HAVE_LOCALE_H */ + +#ifdef HAVE_MPFR +extern mpfr_prec_t PRECISION; +extern mpfr_rnd_t ROUND_MODE; +extern mpz_t MNR; +extern mpz_t MFNR; +extern mpz_t mpzval; +extern bool do_ieee_fmt; /* emulate IEEE 754 floating-point format */ +#endif + + +extern const char *myname; +extern const char def_strftime_format[]; + +extern char quote; +extern char *defpath; +extern char *deflibpath; +extern char envsep; + +extern char casetable[]; /* for case-independent regexp matching */ + +/* ------------------------- Runtime stack -------------------------------- */ + +typedef union stack_item { + NODE *rptr; /* variable etc. */ + NODE **lptr; /* address of a variable etc. */ +} STACK_ITEM; + +extern STACK_ITEM *stack_ptr; +extern NODE *frame_ptr; +extern STACK_ITEM *stack_bottom; +extern STACK_ITEM *stack_top; + +#define decr_sp() (stack_ptr--) +#define incr_sp() ((stack_ptr < stack_top) ? ++stack_ptr : grow_stack()) +#define stack_adj(n) (stack_ptr += (n)) +#define stack_empty() (stack_ptr < stack_bottom) + +#define POP() (decr_sp()->rptr) +#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 PUSH(r) (void) (incr_sp()->rptr = (r)) +#define PUSH_ADDRESS(l) (void) (incr_sp()->lptr = (l)) +#define REPLACE(r) (void) (stack_ptr->rptr = (r)) +#define REPLACE_ADDRESS(l) (void) (stack_ptr->lptr = (l)) + +/* function param */ +#define GET_PARAM(n) frame_ptr->stack[n] + +/* + * UPREF --- simplified versions of dupnode, does not handle FIELD node. + * Most appropriate use is for elements on the runtime stack. + * When in doubt, use dupnode. + */ + +#define UPREF(r) (void) ((r)->valref++) + +extern void r_unref(NODE *tmp); + +static inline void +DEREF(NODE *r) +{ + assert(r->valref > 0); + if (--r->valref == 0) + r_unref(r); +} + +#define POP_NUMBER() force_number(POP_SCALAR()) +#define TOP_NUMBER() force_number(TOP_SCALAR()) + +/* ------------------------- 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) 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)) + +#define mpg_float() mpg_node(MPFN) +#define mpg_integer() mpg_node(MPZN) +#define is_mpg_float(n) (((n)->flags & MPFN) != 0) +#define is_mpg_integer(n) (((n)->flags & MPZN) != 0) +#define is_mpg_number(n) (((n)->flags & (MPZN|MPFN)) != 0) +#else +#define get_number_ui(n) (unsigned long) (n)->numbr +#define get_number_si(n) (long) (n)->numbr +#define get_number_d(n) (double) (n)->numbr +#define get_number_uj(n) (uintmax_t) (n)->numbr + +#define is_mpg_number(n) 0 +#define is_mpg_float(n) 0 +#define is_mpg_integer(n) 0 +#define iszero(n) ((n)->numbr == 0.0) +#endif + +#define var_uninitialized(n) ((n)->var_value == Nnull_string) + +#define get_lhs(n, r) (n)->type == Node_var && ! var_uninitialized(n) ? \ + &((n)->var_value) : r_get_lhs((n), (r)) + +#define getblock(p, id, ty) (void) ((p = (ty) nextfree[id].freep) ? \ + (ty) (nextfree[id].freep = ((struct block_item *) p)->freep) \ + : (p = (ty) more_blocks(id))) +#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) + +#define getbucket(b) getblock(b, BLOCK_BUCKET, BUCKET *) +#define freebucket(b) freeblock(b, BLOCK_BUCKET) + +#define make_string(s, l) make_str_node((s), (l), 0) + +#define SCAN 1 +#define ALREADY_MALLOCED 2 + +#define cant_happen() r_fatal("internal error line %d, file: %s", \ + __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) + +#define fatal (*(set_loc(__FILE__, __LINE__), r_fatal)) + +extern jmp_buf fatal_tag; +extern int fatal_tag_valid; + +#define PUSH_BINDING(stack, tag, val) \ +if (val++) \ + memcpy((char *) (stack), (const char *) tag, sizeof(jmp_buf)) +#define POP_BINDING(stack, tag, val) \ +if (--val) \ + memcpy((char *) tag, (const char *) (stack), sizeof(jmp_buf)) + +#define assoc_length(a) ((*((a)->alength(a, NULL)))->table_size) +#define assoc_empty(a) (assoc_length(a) == 0) +#define assoc_lookup(a, s) ((a)->alookup(a, s)) + +/* assoc_clear --- flush all the values in symbol[] */ +#define assoc_clear(a) (void) ((a)->aclear(a, NULL)) + +/* assoc_remove --- remove an index from symbol[] */ +#define assoc_remove(a, s) ((a)->aremove(a, s) != NULL) + +/* ------------- Function prototypes or defs (as appropriate) ------------- */ +/* array.c */ +typedef enum { SORTED_IN = 1, ASORT, ASORTI } sort_context_t; +typedef enum { + ANONE = 0x00, /* "unused" value */ + AINDEX = 0x001, /* list of indices */ + AVALUE = 0x002, /* list of values */ + AINUM = 0x004, /* numeric index */ + AISTR = 0x008, /* string index */ + AVNUM = 0x010, /* numeric scalar value */ + AVSTR = 0x020, /* string scalar value */ + AASC = 0x040, /* ascending order */ + ADESC = 0x080, /* descending order */ + ADELETE = 0x100 /* need a single index; for use in do_delete_loop */ +} assoc_kind_t; + +extern NODE *make_array(void); +extern void null_array(NODE *symbol); +extern NODE *force_array(NODE *symbol, bool canfatal); +extern const char *make_aname(const NODE *symbol); +extern const char *array_vname(const NODE *symbol); +extern void array_init(void); +extern int register_array_func(afunc_t *afunc); +extern NODE **null_length(NODE *symbol, NODE *subs); +extern NODE **null_afunc(NODE *symbol, NODE *subs); +extern void set_SUBSEP(void); +extern NODE *concat_exp(int nargs, bool do_subsep); +extern NODE *assoc_copy(NODE *symbol, NODE *newsymb); +extern void assoc_dump(NODE *symbol, NODE *p); +extern NODE **assoc_list(NODE *symbol, const char *sort_str, sort_context_t sort_ctxt); +extern void assoc_info(NODE *subs, NODE *val, NODE *p, const char *aname); +extern void do_delete(NODE *symbol, int nsubs); +extern void do_delete_loop(NODE *symbol, NODE **lhs); +extern NODE *do_adump(int nargs); +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); +extern void track_ext_func(const char *name); +extern void dump_funcs(void); +extern void dump_vars(const char *fname); +extern const char *getfname(NODE *(*)(int)); +extern NODE *stopme(int nargs); +extern void shadow_funcs(void); +extern int check_special(const char *name); +extern SRCFILE *add_srcfile(enum srctype stype, char *src, SRCFILE *curr, bool *already_included, int *errcode); +extern void free_srcfile(SRCFILE *thisfile); +extern int files_are_same(char *path, SRCFILE *src); +extern void valinfo(NODE *n, Func_print print_func, FILE *fp); +extern void negate_num(NODE *n); +typedef NODE *(*builtin_func_t)(int); /* function that implements a built-in */ +extern builtin_func_t lookup_builtin(const char *name); +extern void install_builtins(void); +extern bool is_alpha(int c); +extern bool is_alnum(int c); +extern bool is_letter(int c); +extern bool is_identchar(int c); +extern NODE *make_regnode(int type, NODE *exp); +/* builtin.c */ +extern double double_to_int(double d); +extern NODE *do_exp(int nargs); +extern NODE *do_fflush(int nargs); +extern NODE *do_index(int nargs); +extern NODE *do_int(int nargs); +extern NODE *do_isarray(int nargs); +extern NODE *do_length(int nargs); +extern NODE *do_log(int nargs); +extern NODE *do_mktime(int nargs); +extern NODE *do_sprintf(int nargs); +extern void do_printf(int nargs, int redirtype); +extern void print_simple(NODE *tree, FILE *fp); +extern NODE *do_sqrt(int nargs); +extern NODE *do_substr(int nargs); +extern NODE *do_strftime(int nargs); +extern NODE *do_systime(int nargs); +extern NODE *do_system(int nargs); +extern void do_print(int nargs, int redirtype); +extern void do_print_rec(int args, int redirtype); +extern NODE *do_tolower(int nargs); +extern NODE *do_toupper(int nargs); +extern NODE *do_atan2(int nargs); +extern NODE *do_sin(int nargs); +extern NODE *do_cos(int nargs); +extern NODE *do_rand(int nargs); +extern NODE *do_srand(int nargs); +extern NODE *do_match(int nargs); +extern NODE *do_sub(int nargs, unsigned int flags); +extern NODE *call_sub(const char *name, int nargs); +extern NODE *call_match(int nargs); +extern NODE *call_split_func(const char *name, int nargs); +extern NODE *format_tree(const char *, size_t, NODE **, long); +extern NODE *do_lshift(int nargs); +extern NODE *do_rshift(int nargs); +extern NODE *do_and(int nargs); +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, 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, bool use_strcmp); +extern int cmp_awknums(const NODE *t1, const NODE *t2); +extern void set_IGNORECASE(void); +extern void set_OFS(void); +extern void set_ORS(void); +extern void set_OFMT(void); +extern void set_CONVFMT(void); +extern void set_BINMODE(void); +extern void set_LINT(void); +extern void set_TEXTDOMAIN(void); +extern void update_ERRNO_int(int); +extern void update_ERRNO_string(const char *string); +extern void unset_ERRNO(void); +extern void update_NR(void); +extern void update_NF(void); +extern void update_FNR(void); +extern const char *redflags2str(int); +extern const char *flags2str(int); +extern const char *genflags2str(int flagval, const struct flagtab *tab); +extern const char *nodetype2str(NODETYPE type); +extern void load_casetable(void); +extern AWKNUM calc_exp(AWKNUM x1, AWKNUM x2); +extern const char *opcode2str(OPCODE type); +extern const char *op2str(OPCODE type); +extern NODE **r_get_lhs(NODE *n, bool reference); +extern STACK_ITEM *grow_stack(void); +extern void dump_fcall_stack(FILE *fp); +extern int register_exec_hook(Func_pre_exec preh, Func_post_exec posth); +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 void close_extensions(void); +#ifdef DYNAMIC +extern awk_bool_t make_builtin(const awk_ext_func_t *); +extern NODE *get_argument(int); +extern NODE *get_actual_argument(NODE *, int, bool); +#define get_scalar_argument(n, i) get_actual_argument((n), (i), false) +#define get_array_argument(n, i) get_actual_argument((n), (i), true) +#endif +/* field.c */ +extern void init_fields(void); +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); +extern NODE **get_field(long num, Func_ptr *assign); +extern NODE *do_split(int nargs); +extern NODE *do_patsplit(int nargs); +extern void set_FS(void); +extern void set_RS(void); +extern void set_FIELDWIDTHS(void); +extern void set_FPAT(void); +extern void update_PROCINFO_str(const char *subscript, const char *str); +extern void update_PROCINFO_num(const char *subscript, AWKNUM val); + +typedef enum { + Using_FS, + Using_FIELDWIDTHS, + 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; +extern void init_ext_api(void); +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); +extern void os_arg_fixup(int *argcp, char ***argvp); +extern int os_devopen(const char *name, int flag); +extern void os_close_on_exec(int fd, const char *name, const char *what, const char *dir); +extern int os_isatty(int fd); +extern int os_isdir(int fd); +extern int os_isreadable(const awk_input_buf_t *iobuf, bool *isdir); +extern int os_is_setuid(void); +extern int os_setbinmode(int fd, int mode); +extern void os_restore_mode(int fd); +extern size_t optimal_bufsize(int fd, struct stat *sbuf); +extern int ispath(const char *file); +extern int isdirpunct(int c); + +/* io.c */ +extern void init_sockets(void); +extern void init_io(void); +extern void register_input_parser(awk_input_parser_t *input_parser); +extern void register_output_wrapper(awk_output_wrapper_t *wrapper); +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, 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); +typedef enum { CLOSE_ALL, CLOSE_TO, CLOSE_FROM } two_way_close_type; +extern int close_rp(struct redirect *rp, two_way_close_type how); +extern int devopen_simple(const char *name, const char *mode, bool try_real_open); +extern int devopen(const char *name, const char *mode); +extern int srcopen(SRCFILE *s); +extern char *find_source(const char *src, struct stat *stb, int *errcode, int is_extlib); +extern NODE *do_getline_redir(int intovar, enum redirval redirtype); +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); +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); +extern void set_ROUNDMODE(void); +extern void mpfr_unset(NODE *n); +#ifdef HAVE_MPFR +extern int mpg_cmp(const NODE *, const NODE *); +extern int format_ieee(mpfr_ptr, int); +extern NODE *mpg_update_var(NODE *); +extern long mpg_set_var(NODE *); +extern NODE *do_mpfr_and(int); +extern NODE *do_mpfr_atan2(int); +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); +extern NODE *do_mpfr_rand(int); +extern NODE *do_mpfr_rshift(int); +extern NODE *do_mpfr_sin(int); +extern NODE *do_mpfr_sqrt(int); +extern NODE *do_mpfr_srand(int); +extern NODE *do_mpfr_strtonum(int); +extern NODE *do_mpfr_xor(int); +extern void init_mpfr(mpfr_prec_t, const char *); +extern void cleanup_mpfr(void); +extern NODE *mpg_node(unsigned int); +extern const char *mpg_fmt(const char *, ...); +extern int mpg_strtoui(mpz_ptr, char *, size_t, char **, int); +#endif +/* msg.c */ +extern void gawk_exit(int status); +extern void final_exit(int status) ATTRIBUTE_NORETURN; +extern void err(bool isfatal, const char *s, const char *emsg, va_list argp) ATTRIBUTE_PRINTF(3, 0); +extern void msg (const char *mesg, ...) ATTRIBUTE_PRINTF_1; +extern void error (const char *mesg, ...) ATTRIBUTE_PRINTF_1; +extern void r_warning (const char *mesg, ...) ATTRIBUTE_PRINTF_1; +extern void set_loc (const char *file, int line); +extern void r_fatal (const char *mesg, ...) ATTRIBUTE_PRINTF_1; +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2) +extern void (*lintfunc)(const char *mesg, ...) ATTRIBUTE_PRINTF_1; +#else +extern void (*lintfunc)(const char *mesg, ...); +#endif +/* profile.c */ +extern void init_profiling_signals(void); +extern void set_prof_file(const char *filename); +extern void dump_prog(INSTRUCTION *code); +extern char *pp_number(NODE *n); +extern char *pp_string(const char *in_str, size_t len, int delim); +extern char *pp_node(NODE *n); +extern int pp_func(INSTRUCTION *pc, void *); +extern void pp_string_fp(Func_print print_func, FILE *fp, const char *str, + size_t namelen, int delim, bool breaklines); +/* node.c */ +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); +extern NODE *wstr2str(NODE *n); +#define force_wstring(n) str2wstr(n, NULL) +extern const wchar_t *wstrstr(const wchar_t *haystack, size_t hs_len, + const wchar_t *needle, size_t needle_len); +extern const wchar_t *wcasestrstr(const wchar_t *haystack, size_t hs_len, + const wchar_t *needle, size_t needle_len); +extern void r_free_wstr(NODE *n); +#define free_wstr(n) do { if ((n)->flags & WSTRCUR) r_free_wstr(n); } while(0) +extern wint_t btowc_cache[]; +#define btowc_cache(x) btowc_cache[(x)&0xFF] +extern void init_btowc_cache(); +#define is_valid_character(b) (btowc_cache[(b)&0xFF] != WEOF) +/* re.c */ +extern Regexp *make_regexp(const char *s, size_t len, bool ignorecase, bool dfa, bool canfatal); +extern int research(Regexp *rp, char *str, int start, size_t len, int flags); +extern void refree(Regexp *rp); +extern void reg_error(const char *s); +extern Regexp *re_update(NODE *t); +extern void resyntax(int syntax); +extern void resetup(void); +extern int reisstring(const char *text, size_t len, Regexp *re, const char *buf); +extern int get_numbase(const char *str, size_t len, bool use_locale); +extern bool using_utf8(void); + +/* symbol.c */ +extern void load_symbols(); +extern void init_symbol_table(); +extern NODE *symbol_table; +extern NODE *func_table; +extern NODE *install_symbol(const char *name, NODETYPE type); +extern NODE *remove_symbol(NODE *r); +extern void destroy_symbol(NODE *r); +extern void release_symbols(NODE *symlist, int keep_globals); +extern void append_symbol(NODE *r); +extern NODE *lookup(const char *name); +extern NODE *make_params(char **pnames, int pcount); +extern void install_params(NODE *func); +extern void remove_params(NODE *func); +extern void release_all_vars(void); +extern int foreach_func(NODE **table, int (*)(INSTRUCTION *, void *), void *); +extern INSTRUCTION *bcalloc(OPCODE op, int size, int srcline); +extern void bcfree(INSTRUCTION *); +extern AWK_CONTEXT *new_context(void); +extern void push_context(AWK_CONTEXT *ctxt); +extern void pop_context(); +extern int in_main_context(); +extern void free_context(AWK_CONTEXT *ctxt, bool keep_globals); +extern NODE **variable_list(); +extern NODE **function_list(bool sort); +extern void print_vars(NODE **table, Func_print print_func, FILE *fp); +extern bool check_param_names(void); + +/* floatcomp.c */ +#ifdef HAVE_UINTMAX_T +extern uintmax_t adjust_uint(uintmax_t n); +#else +#define adjust_uint(n) (n) +#endif + +#ifdef HAVE_SYS_WAIT_H +#include +#endif +#ifndef WEXITSTATUS +#if defined(VMS) +#define WEXITSTATUS(stat_val) (stat_val) +#else /* ! defined(VMS) */ +#define WEXITSTATUS(stat_val) ((((unsigned) (stat_val)) >> 8) & 0xFF) +#endif /* ! defined(VMS)) */ +#endif /* WEXITSTATUS */ + +/* For z/OS, from Dave Pitts. EXIT_FAILURE is normally 8, make it 1. */ +#if defined(EXIT_FAILURE) && EXIT_FAILURE == 8 +# undef EXIT_FAILURE +#endif + +/* EXIT_SUCCESS and EXIT_FAILURE normally come from */ +#ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +#endif +#ifndef EXIT_FAILURE +# define EXIT_FAILURE 1 +#endif +/* EXIT_FATAL is specific to gawk, not part of Standard C */ +#ifndef EXIT_FATAL +# define EXIT_FATAL 2 +#endif + +/* ------------------ Inline Functions ------------------ */ + +/* + * These must come last to get all the function declarations and + * macro definitions before their bodies. + * + * This is wasteful if the compiler doesn't support inline. We won't + * worry about it until someone complains. + */ + +/* POP_ARRAY --- get the array at the top of the stack */ + +static inline NODE * +POP_ARRAY() +{ + NODE *t = POP(); + + return (t->type == Node_var_array) ? t : force_array(t, true); +} + +/* POP_PARAM --- get the top parameter, array or scalar */ + +static inline NODE * +POP_PARAM() +{ + NODE *t = POP(); + + return (t->type == Node_var_array) ? t : force_array(t, false); +} + +/* POP_SCALAR --- pop the scalar at the top of the stack */ + +static inline NODE * +POP_SCALAR() +{ + NODE *t = POP(); + + if (t->type == Node_var_array) + fatal(_("attempt to use array `%s' in a scalar context"), array_vname(t)); + + return t; +} + +/* TOP_SCALAR --- get the scalar at the top of the stack */ + +static inline NODE * +TOP_SCALAR() +{ + NODE *t = TOP(); + + if (t->type == Node_var_array) + fatal(_("attempt to use array `%s' in a scalar context"), array_vname(t)); + + return t; +} + +/* POP_STRING --- pop the string at the top of the stack */ +#define POP_STRING() force_string(POP_SCALAR()) + +/* TOP_STRING --- get the string at the top of the stack */ +#define TOP_STRING() force_string(TOP_SCALAR()) + +/* in_array --- return pointer to element in array if there */ + +static inline NODE * +in_array(NODE *a, NODE *s) +{ + NODE **ret; + + ret = a->aexists(a, s); + + return ret ? *ret : NULL; +} + +#ifdef GAWKDEBUG +#define dupnode r_dupnode +#else +/* dupnode --- up the reference on a node */ + +static inline NODE * +dupnode(NODE *n) +{ + if ((n->flags & MALLOC) != 0) { + n->valref++; + return n; + } + return r_dupnode(n); +} +#endif + +/* + * 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. + * + * Additional twist: If ROUNDMODE changed at some point we have to + * recompute also. + */ + +static inline NODE * +force_string_fmt(NODE *s, const char *fmtstr, int fmtidx) +{ + if ((s->flags & STRCUR) != 0 + && (s->stfmt == STFMT_UNUSED || (s->stfmt == fmtidx +#ifdef HAVE_MPFR + && s->strndmode == MPFR_round_mode +#endif + ))) + return 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 +#else /* not GAWKDEBUG */ + +/* unref --- decrease the reference count and/or free a node */ + +static inline void +unref(NODE *r) +{ + if (r != NULL && --r->valref <= 0) + r_unref(r); +} + +/* force_number --- force a node to have a numeric value */ + +static inline NODE * +force_number(NODE *n) +{ + return (n->flags & NUMCUR) != 0 ? n : str2number(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 * +emalloc_real(size_t count, const char *where, const char *var, const char *file, int line) +{ + void *ret; + + if (count == 0) + fatal("%s:%d: emalloc called with zero bytes", file, line); + + ret = (void *) malloc(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; +} + +/* 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 * +erealloc_real(void *ptr, size_t count, const char *where, const char *var, const char *file, int line) +{ + void *ret; + + if (count == 0) + fatal("%s:%d: erealloc called with zero bytes", file, line); + + ret = (void *) realloc(ptr, count); + if (ret == NULL) + fatal(_("%s:%d:%s: %s: can't reallocate %ld bytes of memory (%s)"), + file, line, where, var, (long) count, strerror(errno)); + + return ret; +} + +/* make_number_node --- make node with the given flags */ + +static inline NODE * +make_number_node(unsigned int flags) +{ + NODE *r; + getnode(r); + memset(r, 0, sizeof(*r)); + r->type = Node_val; + r->valref = 1; + r->flags = (flags|MALLOC|NUMBER|NUMCUR); + return r; +} + +/* + * 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 new file mode 100644 index 0000000..52821ea --- /dev/null +++ b/awkgram.c @@ -0,0 +1,8780 @@ +/* A Bison parser, made by GNU Bison 3.0.4. */ + +/* Bison implementation for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015 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 . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "3.0.4" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 0 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + + + + +/* Copy the first part of user declarations. */ +#line 26 "awkgram.y" /* yacc.c:339 */ + +#ifdef GAWKDEBUG +#define YYDEBUG 12 +#endif + +#include "awk.h" + +#if defined(__STDC__) && __STDC__ < 1 /* VMS weirdness, maybe elsewhere */ +#define signed /**/ +#endif + +static void yyerror(const char *m, ...) ATTRIBUTE_PRINTF_1; +static void error_ln(int line, const char *m, ...) ATTRIBUTE_PRINTF_2; +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); +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); +static NODE *mk_rexp(INSTRUCTION *exp); +static void param_sanity(INSTRUCTION *arglist); +static int parms_shadow(INSTRUCTION *pc, bool *shadow); +#ifndef NO_LINT +static int isnoeffect(OPCODE type); +#endif +static INSTRUCTION *make_assignable(INSTRUCTION *ip); +static void dumpintlstr(const char *str, size_t len); +static void dumpintlstr2(const char *str1, size_t len1, const char *str2, size_t len2); +static int include_source(INSTRUCTION *file); +static int load_library(INSTRUCTION *file); +static 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) + +static INSTRUCTION *mk_program(void); +static INSTRUCTION *append_rule(INSTRUCTION *pattern, INSTRUCTION *action); +static INSTRUCTION *mk_function(INSTRUCTION *fi, INSTRUCTION *def); +static INSTRUCTION *mk_condition(INSTRUCTION *cond, INSTRUCTION *ifp, INSTRUCTION *true_branch, + INSTRUCTION *elsep, INSTRUCTION *false_branch); +static INSTRUCTION *mk_expression_list(INSTRUCTION *list, INSTRUCTION *s1); +static INSTRUCTION *mk_for_loop(INSTRUCTION *forp, INSTRUCTION *init, INSTRUCTION *cond, + INSTRUCTION *incr, INSTRUCTION *body); +static void fix_break_continue(INSTRUCTION *list, INSTRUCTION *b_target, INSTRUCTION *c_target); +static INSTRUCTION *mk_binary(INSTRUCTION *s1, INSTRUCTION *s2, INSTRUCTION *op); +static INSTRUCTION *mk_boolean(INSTRUCTION *left, INSTRUCTION *right, INSTRUCTION *op); +static INSTRUCTION *mk_assignment(INSTRUCTION *lhs, INSTRUCTION *rhs, INSTRUCTION *op); +static INSTRUCTION *mk_getline(INSTRUCTION *op, INSTRUCTION *opt_var, INSTRUCTION *redir, int redirtype); +static int count_expressions(INSTRUCTION **list, bool isarg); +static INSTRUCTION *optimize_assignment(INSTRUCTION *exp); +static void add_lint(INSTRUCTION *list, LINTTYPE linttype); + +enum defref { FUNC_DEFINE, FUNC_USE, FUNC_EXT }; +static void func_use(const char *name, enum defref how); +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; + +const char *const ruletab[] = { + "?", + "BEGIN", + "Rule", + "END", + "BEGINFILE", + "ENDFILE", +}; + +static bool in_print = false; /* lexical scanning kludge for print */ +static int in_parens = 0; /* lexical scanning kludge for print */ +static int sub_counter = 0; /* array dimension counter for use in delete */ +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 char *thisline = NULL; +static int in_braces = 0; /* count braces for firstline, lastline in an 'action' */ +static int lastline = 0; +static int firstline = 0; +static SRCFILE *sourcefile = NULL; /* current program source */ +static int lasttok = 0; +static bool eof_warned = false; /* GLOBAL: want warning for each file */ +static int break_allowed; /* kludge for break */ +static int continue_allowed; /* kludge for continue */ + +#define END_FILE -1000 +#define END_SRC -2000 + +#define YYDEBUG_LEXER_TEXT (lexeme) +static char *tokstart = NULL; +static char *tok = NULL; +static char *tokend; +static int errcount = 0; + +extern char *source; +extern int sourceline; +extern SRCFILE *srcfiles; +extern INSTRUCTION *rule_list; +extern int max_args; +extern NODE **args_array; + +static INSTRUCTION *rule_block[sizeof(ruletab)]; + +static INSTRUCTION *ip_rec; +static INSTRUCTION *ip_newfile; +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 216 "awkgram.c" /* yacc.c:339 */ + +# ifndef YY_NULLPTR +# if defined __cplusplus && 201103L <= __cplusplus +# define YY_NULLPTR nullptr +# else +# define YY_NULLPTR 0 +# endif +# endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + + +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int yydebug; +#endif + +/* Token type. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + enum yytokentype + { + FUNC_CALL = 258, + NAME = 259, + REGEXP = 260, + FILENAME = 261, + YNUMBER = 262, + YSTRING = 263, + 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. */ +#define FUNC_CALL 258 +#define NAME 259 +#define REGEXP 260 +#define FILENAME 261 +#define YNUMBER 262 +#define YSTRING 263 +#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 +typedef int YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define YYSTYPE_IS_DECLARED 1 +#endif + + +extern YYSTYPE yylval; + +int yyparse (void); + + + +/* Copy the second part of user declarations. */ + +#line 372 "awkgram.c" /* yacc.c:358 */ + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#else +typedef signed char yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_(Msgid) dgettext ("bison-runtime", Msgid) +# endif +# endif +# ifndef YY_ +# define YY_(Msgid) Msgid +# endif +#endif + +#ifndef YY_ATTRIBUTE +# if (defined __GNUC__ \ + && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \ + || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C +# define YY_ATTRIBUTE(Spec) __attribute__(Spec) +# else +# define YY_ATTRIBUTE(Spec) /* empty */ +# endif +#endif + +#ifndef YY_ATTRIBUTE_PURE +# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__)) +#endif + +#ifndef YY_ATTRIBUTE_UNUSED +# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) +#endif + +#if !defined _Noreturn \ + && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112) +# if defined _MSC_VER && 1200 <= _MSC_VER +# define _Noreturn __declspec (noreturn) +# else +# define _Noreturn YY_ATTRIBUTE ((__noreturn__)) +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(E) ((void) (E)) +#else +# define YYUSE(E) /* empty */ +#endif + +#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ +/* Suppress an incorrect diagnostic about yylval being uninitialized. */ +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ + _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ + _Pragma ("GCC diagnostic pop") +#else +# define YY_INITIAL_VALUE(Value) Value +#endif +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_END +#endif +#ifndef YY_INITIAL_VALUE +# define YY_INITIAL_VALUE(Value) /* Nothing. */ +#endif + + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS +# include /* INFRINGES ON USER NAME SPACE */ + /* Use EXIT_SUCCESS as a witness for stdlib.h. */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's 'empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined EXIT_SUCCESS \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined EXIT_SUCCESS +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined EXIT_SUCCESS +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +# define YYCOPY_NEEDED 1 + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (0) + +#endif + +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from SRC to DST. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(Dst, Src, Count) \ + __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) +# else +# define YYCOPY(Dst, Src, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (Dst)[yyi] = (Src)[yyi]; \ + } \ + while (0) +# endif +# endif +#endif /* !YYCOPY_NEEDED */ + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 2 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 1236 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 76 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 70 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 203 +/* YYNSTATES -- Number of states. */ +#define YYNSTATES 350 + +/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned + by yylex, with out-of-bounds checking. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 309 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM + as returned by yylex, without out-of-bounds checking. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 64, 2, 2, 67, 63, 2, 2, + 68, 69, 61, 59, 56, 60, 2, 62, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 55, 75, + 57, 2, 58, 54, 70, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 71, 2, 72, 66, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 73, 2, 74, 2, 2, 2, 2, + 2, 2, 2, 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, 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, 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, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 65 +}; + +#if YYDEBUG + /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 215, 215, 217, 222, 223, 227, 239, 244, 255, + 262, 268, 277, 285, 287, 292, 300, 302, 308, 316, + 326, 356, 370, 384, 392, 403, 415, 417, 419, 425, + 433, 434, 438, 438, 484, 483, 517, 532, 534, 539, + 549, 596, 601, 602, 606, 608, 610, 617, 707, 749, + 791, 904, 911, 918, 929, 939, 949, 959, 971, 988, + 987, 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, 1621, 1623, 1625, 1627, 1629, 1631, 1633, + 1635, 1649, 1654, 1659, 1684, 1690, 1692, 1694, 1696, 1698, + 1700, 1705, 1709, 1741, 1748, 1754, 1760, 1773, 1774, 1775, + 1780, 1785, 1789, 1793, 1808, 1829, 1834, 1871, 1900, 1901, + 1907, 1908, 1913, 1915, 1922, 1939, 1956, 1958, 1965, 1970, + 1978, 1988, 2000, 2009, 2013, 2017, 2021, 2025, 2029, 2032, + 2034, 2038, 2042, 2046 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || 0 +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "FUNC_CALL", "NAME", "REGEXP", + "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 + +# ifdef YYPRINT +/* YYTOKNUM[NUM] -- (External) token number corresponding to the + (internal) symbol number NUM (which must be that of a token). */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 63, 58, 44, 60, 62, 43, + 45, 42, 47, 37, 33, 309, 94, 36, 40, 41, + 64, 91, 93, 123, 125, 59 +}; +# endif + +#define YYPACT_NINF -275 + +#define yypact_value_is_default(Yystate) \ + (!!((Yystate) == (-275))) + +#define YYTABLE_NINF -115 + +#define yytable_value_is_error(Yytable_value) \ + (!!((Yytable_value) == (-115))) + + /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +static const yytype_int16 yypact[] = +{ + -275, 376, -275, -275, -12, -9, -275, -275, -275, -275, + 171, -275, -275, 44, 44, 44, 5, 40, -275, -275, + -275, 1139, 1139, -275, 1139, 1166, 869, 27, -275, -18, + 2, -275, -275, 89, 884, 1065, 192, 214, -275, -275, + -275, -275, 248, 795, 869, -275, 10, -275, -275, -275, + -275, -275, 116, 82, -275, 115, -275, -275, -275, 795, + 795, 166, 107, 104, 107, 107, 1139, 117, -275, -275, + 15, 349, 23, 45, -275, 125, -275, -275, -275, 89, + -275, 125, -275, 178, -275, -275, 1092, 172, 1139, 1139, + 1139, 125, -275, -275, -275, 1139, 146, 192, 1139, 1139, + 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, + -275, 181, -275, -275, 173, 1139, -275, -275, -275, 128, + 73, -275, 1107, 14, 1107, -275, -275, -275, -275, 1139, + -275, 128, 128, 349, -275, -275, -275, 1139, 125, -275, + 152, 916, -275, -275, 16, 92, -275, 20, 92, 89, + -275, 599, -275, -275, -275, 148, -275, 124, 22, 1048, + 1139, 199, 44, 265, 265, 107, 107, 107, 107, 265, + 265, 107, 107, 107, 107, -275, -275, 1107, -275, 1092, + 842, -275, 43, 192, -275, -275, 1107, -275, 172, -275, + 1107, -275, -275, -275, -275, -275, 133, -275, 41, 144, + 145, 125, 147, 92, 92, -275, -275, 92, 1139, 92, + 125, -275, -275, 92, -275, -275, 1107, -275, 151, 125, + 1139, 1107, -275, -275, -275, -275, -275, -275, 128, 76, + -275, 1139, 1139, -275, 224, 1139, 1139, 715, 949, -275, + -275, -275, 92, 1107, -275, -275, -275, 646, 599, 125, + -275, -275, 1107, 125, -275, 49, 349, 92, -9, 160, + 349, 349, 206, 113, -275, 151, -275, 869, 225, -275, + 169, -275, -275, -275, -275, -275, 125, -275, -275, 11, + -275, -275, -275, 125, 125, 179, 172, 125, 15, -275, + -275, 715, -275, -275, 2, 715, 1139, 128, 762, 152, + 1139, 219, -275, -275, 349, 125, 275, 125, 1065, 125, + 112, 125, 715, 125, 997, 715, -275, 261, 205, -275, + 191, -275, -275, 997, 128, -275, -275, -275, 271, 272, + -275, -275, 205, -275, 125, -275, 128, 125, -275, -275, + 125, -275, 125, 715, -275, 449, 715, -275, 524, -275 +}; + + /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE does not specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 2, 0, 1, 6, 0, 189, 171, 172, 21, 22, + 0, 23, 24, 178, 0, 0, 0, 166, 5, 90, + 38, 0, 0, 37, 0, 0, 0, 0, 3, 0, + 0, 161, 34, 4, 19, 132, 140, 141, 143, 167, + 175, 191, 168, 0, 0, 186, 0, 190, 27, 26, + 30, 31, 0, 0, 28, 94, 179, 169, 170, 0, + 0, 0, 174, 168, 173, 162, 0, 195, 168, 109, + 0, 107, 0, 0, 176, 92, 201, 7, 8, 42, + 39, 92, 9, 0, 91, 136, 0, 0, 0, 0, + 0, 92, 137, 139, 138, 0, 0, 142, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 134, 133, 151, 152, 0, 0, 117, 36, 122, 0, + 0, 115, 121, 0, 107, 188, 187, 29, 32, 0, + 150, 0, 0, 0, 193, 194, 192, 110, 92, 198, + 0, 0, 163, 14, 0, 0, 17, 0, 0, 93, + 196, 0, 43, 35, 127, 128, 129, 125, 126, 0, + 0, 130, 178, 148, 149, 145, 146, 147, 144, 159, + 160, 156, 157, 158, 155, 124, 135, 123, 177, 118, + 0, 185, 0, 95, 164, 165, 111, 203, 0, 112, + 108, 13, 10, 16, 11, 41, 0, 59, 0, 0, + 0, 92, 0, 0, 0, 81, 82, 0, 103, 0, + 92, 40, 53, 0, 62, 46, 67, 39, 199, 92, + 0, 20, 154, 119, 120, 116, 100, 98, 0, 0, + 153, 0, 103, 64, 0, 0, 0, 0, 68, 54, + 55, 56, 0, 104, 57, 197, 61, 0, 0, 92, + 200, 44, 131, 92, 101, 0, 0, 0, 180, 0, + 0, 0, 0, 189, 69, 0, 58, 0, 85, 83, + 0, 45, 25, 33, 102, 99, 92, 60, 65, 0, + 182, 184, 66, 92, 92, 0, 0, 92, 0, 86, + 63, 0, 181, 183, 0, 0, 0, 0, 0, 84, + 0, 88, 70, 48, 0, 92, 0, 92, 87, 92, + 0, 92, 0, 92, 68, 0, 72, 0, 0, 71, + 0, 49, 50, 68, 0, 89, 75, 78, 0, 0, + 79, 80, 0, 202, 92, 47, 0, 92, 77, 76, + 92, 39, 92, 0, 39, 0, 0, 52, 0, 51 +}; + + /* YYPGOTO[NTERM-NUM]. */ +static const yytype_int16 yypgoto[] = +{ + -275, -275, -275, -275, -275, -275, 252, -275, -275, -275, + -275, -33, -275, -80, -275, -213, 100, -144, -275, -275, + -231, -275, -275, -274, -275, -275, -275, -275, -275, -275, + -275, -275, 7, 62, -275, -275, -275, 54, -275, -43, + 1, -275, -23, -1, -275, -275, -275, -13, 17, -275, + 263, -275, 8, 127, -275, -275, 21, -36, -275, -275, + -78, -2, -275, -27, -230, -65, -275, -15, -38, -94 +}; + + /* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int16 yydefgoto[] = +{ + -1, 1, 28, 145, 148, 29, 77, 53, 54, 30, + 182, 31, 83, 118, 32, 151, 78, 211, 212, 232, + 213, 247, 258, 265, 310, 319, 332, 214, 268, 290, + 300, 215, 149, 150, 130, 228, 229, 242, 269, 70, + 119, 120, 121, 216, 115, 94, 95, 35, 36, 37, + 38, 39, 40, 55, 278, 279, 280, 45, 46, 47, + 41, 42, 136, 217, 218, 142, 249, 219, 334, 141 +}; + + /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule whose + number is the opposite. If YYTABLE_NINF, syntax error. */ +static const yytype_int16 yytable[] = +{ + 34, 123, 80, 80, 248, 140, 154, 264, 33, 156, + 126, 56, 57, 58, 81, 137, 137, 191, 271, 63, + 63, 193, 63, 68, 143, 71, 180, 125, 292, 144, + 4, 175, 85, 63, 19, 74, 79, 86, 62, 64, + 324, 65, 122, 124, 226, 233, 146, 227, 5, 336, + 274, 147, 97, 275, 178, 75, 43, 76, 122, 122, + 131, 132, 44, 87, 88, 133, 184, 185, -12, 74, + 138, 138, -15, 59, 179, 75, 72, 254, 73, 92, + 93, 44, 44, 264, 139, 155, 181, 157, 158, 159, + 335, -12, 264, 262, 161, -15, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 60, 234, + 230, 25, -96, 316, 177, 163, 164, 165, 166, 167, + 168, 169, 170, 171, 172, 173, 174, 63, 345, 138, + 81, 348, 138, 81, 85, 255, 186, 317, 318, 86, + 190, 84, -114, 152, 19, -97, 183, 301, 112, 113, + 128, 303, 79, 160, 286, 79, 223, 225, 85, 221, + 56, 134, 135, 253, 19, 87, 127, 76, 322, 4, + 137, 325, 129, 103, 48, 49, 5, 19, 122, 122, + -106, 92, 93, 153, 44, 162, -92, 176, 81, 81, + 117, 276, 81, 188, 81, 283, 284, 139, 81, 347, + 187, 231, 349, 250, 270, 92, 93, 243, 297, -115, + 79, 79, 235, 236, 79, 238, 79, 50, 51, 252, + 79, -106, 281, 299, 288, 138, 76, 81, 259, 282, + 256, 243, 305, 285, 260, 261, 289, 331, -106, 311, + 309, 52, 81, 281, -106, 192, 124, 296, 194, 79, + 287, 98, 99, 100, 101, 102, -115, -115, 103, 337, + 333, 110, 111, 237, 79, 210, 71, 302, 326, 327, + 117, 342, 245, 104, 105, 106, 107, 108, 338, 339, + 109, 251, 82, 307, 330, 85, 257, 308, 67, 222, + 86, 313, 112, 113, 340, 304, 0, 306, 63, 0, + 293, 114, 0, 239, 240, 0, 63, 241, 0, 244, + 0, 272, 0, 246, 20, 273, 87, 88, 89, 0, + 328, 329, 0, 23, 0, 97, 100, 101, 102, 90, + 0, 103, 92, 93, 0, 0, 0, 0, 291, 0, + 0, 0, 266, 0, 0, 294, 295, 0, 0, 298, + 76, 0, 0, 0, 0, 0, 0, 277, 0, 85, + 0, 0, 0, 0, 86, 0, 0, 312, 0, 314, + 0, 315, 320, 321, 0, 323, 2, 3, 0, 4, + 5, 0, 0, 6, 7, 0, 0, 0, 0, 0, + 87, 88, 89, 0, 8, 9, 341, 0, 0, 343, + 0, 0, 344, 90, 346, 0, 92, 93, 0, 0, + 0, 0, 10, 11, 12, 13, 0, 0, 139, 0, + 14, 15, 16, 17, 18, 0, 0, 0, 19, 20, + 0, 0, 0, 0, 0, 21, 22, 0, 23, 0, + 24, 0, 0, 25, 26, 0, 27, 0, 0, -18, + 195, -18, 4, 5, 0, 0, 6, 7, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 196, + 0, 197, 198, 199, -74, -74, 200, 201, 202, 203, + 204, 205, 206, 207, 208, 0, 0, 0, 13, 209, + 0, 0, 0, 14, 15, 16, 17, 0, 0, 0, + 0, -74, 20, 0, 0, 0, 0, 0, 21, 22, + 0, 23, 0, 24, 0, 0, 25, 26, 0, 61, + 0, 0, 75, -74, 76, 195, 0, 4, 5, 0, + 0, 6, 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 196, 0, 197, 198, 199, -73, + -73, 200, 201, 202, 203, 204, 205, 206, 207, 208, + 0, 0, 0, 13, 209, 0, 0, 0, 14, 15, + 16, 17, 0, 0, 0, 0, -73, 20, 0, 0, + 0, 0, 0, 21, 22, 0, 23, 0, 24, 0, + 0, 25, 26, 0, 61, 0, 0, 75, -73, 76, + 195, 0, 4, 5, 0, 0, 6, 7, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 196, + 0, 197, 198, 199, 0, 0, 200, 201, 202, 203, + 204, 205, 206, 207, 208, 0, 0, 0, 13, 209, + 0, 0, 0, 14, 15, 16, 17, 69, 0, 4, + 5, 0, 20, 6, 7, 0, 0, -105, 21, 22, + 0, 23, 0, 24, 0, 0, 25, 26, 0, 61, + 0, 0, 75, 210, 76, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, + 14, 15, 16, 17, 0, 0, 0, 0, -105, 20, + 0, 0, 0, 0, 0, 21, 22, 0, 23, 0, + 24, 0, 0, 25, 267, -105, 61, 0, 4, 5, + 0, -105, 6, 7, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 196, 0, 197, 198, 199, + 0, 0, 200, 201, 202, 203, 204, 205, 206, 207, + 208, 0, 0, 0, 13, 209, 0, 0, 0, 14, + 15, 16, 17, 0, 0, 4, 5, 0, 20, 6, + 7, 0, 0, 0, 21, 22, 0, 23, 0, 24, + 0, 0, 25, 26, 0, 61, 0, 0, 75, 0, + 76, 0, 0, 0, 0, 0, 116, 0, 4, 5, + 0, 13, 6, 7, 117, 0, 14, 15, 16, 17, + 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, + 0, 21, 22, 0, 23, 0, 24, 0, 0, 25, + 26, 0, 61, 0, 13, 0, 0, 76, 0, 14, + 15, 16, 17, 224, 0, 4, 5, 0, 20, 6, + 7, 117, 0, 0, 21, 22, 0, 23, 0, 24, + 0, 0, 25, 26, -113, 61, 0, 0, 0, 0, + 69, 0, 4, 5, 0, 0, 6, 7, 0, 0, + 0, 13, 0, 0, 0, 0, 14, 15, 16, 17, + 0, 0, 0, 0, 85, 20, 0, 0, 0, 86, + 0, 21, 22, 0, 23, 0, 24, 0, 13, 25, + 26, 0, 61, 14, 15, 16, 17, 189, 0, 4, + 5, 0, 20, 6, 7, 87, 88, 89, 21, 22, + 0, 23, 0, 24, 0, 0, 25, 26, 90, 61, + 91, 92, 93, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 263, 0, 13, 6, 7, 0, 0, + 14, 15, 16, 17, 0, 0, 0, 0, 0, 20, + 0, 0, 198, 0, 0, 21, 22, 0, 23, 0, + 24, 205, 206, 25, 26, 0, 61, 0, 13, 0, + 0, 0, 0, 14, 15, 16, 17, 0, 0, 0, + 4, 5, 20, 0, 6, 7, 0, 0, 21, 22, + 0, 23, 0, 24, 0, 0, 25, 26, 0, 61, + 198, 0, 0, 0, 0, 0, 0, 0, 0, 205, + 206, 0, 0, 0, 0, 0, 13, 0, 0, 0, + 0, 14, 15, 16, 17, 0, 0, 0, 0, 0, + 20, 0, 0, 0, 0, 0, 21, 22, 85, 23, + 0, 24, 0, 86, 25, 26, 0, 61, 4, 5, + 0, 0, 6, 7, 0, 0, 0, 96, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 87, + 88, 89, 0, 0, 0, 4, 5, 0, 0, 6, + 7, 117, 90, 220, 13, 92, 93, 0, 0, 14, + 15, 16, 17, 0, 0, 0, 0, 85, 20, 0, + 0, 0, 86, 0, 21, 22, 0, 23, 0, 24, + 0, 13, 25, 26, 0, 61, 14, 15, 16, 17, + 0, 0, 4, 5, 0, 20, 6, 7, 87, 88, + 89, 21, 22, 0, 23, 0, 24, 0, 0, 25, + 26, 90, 61, 0, 92, 93, 0, 0, 0, 4, + 5, 0, 0, 6, 7, 0, 0, 0, 13, 0, + 0, 0, 0, 14, 15, 16, 17, 0, 0, 0, + 0, 0, 20, 0, 0, 0, 0, 0, 21, 22, + 0, 23, 0, 24, 0, 0, 25, 26, 0, 61, + 14, 15, 16, 17, 0, 0, 0, 0, 0, 20, + 0, 0, 0, 0, 0, 21, 22, 0, 23, 0, + 24, 0, 0, 25, 66, 0, 61 +}; + +static const yytype_int16 yycheck[] = +{ + 1, 44, 29, 30, 217, 70, 86, 238, 1, 87, + 46, 13, 14, 15, 29, 1, 1, 1, 248, 21, + 22, 1, 24, 25, 1, 26, 120, 17, 17, 6, + 3, 111, 10, 35, 52, 27, 29, 15, 21, 22, + 314, 24, 43, 44, 1, 4, 1, 4, 4, 323, + 1, 6, 35, 4, 119, 73, 68, 75, 59, 60, + 59, 60, 71, 41, 42, 66, 131, 132, 52, 61, + 56, 56, 52, 68, 1, 73, 49, 1, 51, 57, + 58, 71, 71, 314, 69, 86, 72, 88, 89, 90, + 320, 75, 323, 237, 95, 75, 98, 99, 100, 101, + 102, 103, 104, 105, 106, 107, 108, 109, 68, 68, + 188, 67, 69, 1, 115, 98, 99, 100, 101, 102, + 103, 104, 105, 106, 107, 108, 109, 129, 341, 56, + 145, 344, 56, 148, 10, 229, 137, 25, 26, 15, + 141, 52, 69, 81, 52, 69, 129, 291, 44, 45, + 68, 295, 145, 91, 41, 148, 179, 180, 10, 160, + 162, 44, 45, 228, 52, 41, 50, 75, 312, 3, + 1, 315, 57, 66, 3, 4, 4, 52, 179, 180, + 11, 57, 58, 5, 71, 39, 74, 14, 203, 204, + 9, 256, 207, 41, 209, 260, 261, 69, 213, 343, + 138, 68, 346, 218, 247, 57, 58, 208, 286, 10, + 203, 204, 68, 68, 207, 68, 209, 46, 47, 220, + 213, 52, 258, 288, 267, 56, 75, 242, 4, 69, + 231, 232, 297, 27, 235, 236, 11, 317, 69, 304, + 21, 70, 257, 279, 75, 145, 247, 68, 148, 242, + 265, 59, 60, 61, 62, 63, 57, 58, 66, 324, + 55, 13, 14, 201, 257, 74, 267, 294, 7, 8, + 9, 336, 210, 59, 60, 61, 62, 63, 7, 7, + 66, 219, 30, 298, 317, 10, 232, 300, 25, 162, + 15, 306, 44, 45, 332, 296, -1, 298, 300, -1, + 279, 53, -1, 203, 204, -1, 308, 207, -1, 209, + -1, 249, -1, 213, 53, 253, 41, 42, 43, -1, + 59, 60, -1, 62, -1, 308, 61, 62, 63, 54, + -1, 66, 57, 58, -1, -1, -1, -1, 276, -1, + -1, -1, 242, -1, -1, 283, 284, -1, -1, 287, + 75, -1, -1, -1, -1, -1, -1, 257, -1, 10, + -1, -1, -1, -1, 15, -1, -1, 305, -1, 307, + -1, 309, 310, 311, -1, 313, 0, 1, -1, 3, + 4, -1, -1, 7, 8, -1, -1, -1, -1, -1, + 41, 42, 43, -1, 18, 19, 334, -1, -1, 337, + -1, -1, 340, 54, 342, -1, 57, 58, -1, -1, + -1, -1, 36, 37, 38, 39, -1, -1, 69, -1, + 44, 45, 46, 47, 48, -1, -1, -1, 52, 53, + -1, -1, -1, -1, -1, 59, 60, -1, 62, -1, + 64, -1, -1, 67, 68, -1, 70, -1, -1, 73, + 1, 75, 3, 4, -1, -1, 7, 8, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 20, + -1, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, -1, -1, -1, 39, 40, + -1, -1, -1, 44, 45, 46, 47, -1, -1, -1, + -1, 52, 53, -1, -1, -1, -1, -1, 59, 60, + -1, 62, -1, 64, -1, -1, 67, 68, -1, 70, + -1, -1, 73, 74, 75, 1, -1, 3, 4, -1, + -1, 7, 8, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 20, -1, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + -1, -1, -1, 39, 40, -1, -1, -1, 44, 45, + 46, 47, -1, -1, -1, -1, 52, 53, -1, -1, + -1, -1, -1, 59, 60, -1, 62, -1, 64, -1, + -1, 67, 68, -1, 70, -1, -1, 73, 74, 75, + 1, -1, 3, 4, -1, -1, 7, 8, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 20, + -1, 22, 23, 24, -1, -1, 27, 28, 29, 30, + 31, 32, 33, 34, 35, -1, -1, -1, 39, 40, + -1, -1, -1, 44, 45, 46, 47, 1, -1, 3, + 4, -1, 53, 7, 8, -1, -1, 11, 59, 60, + -1, 62, -1, 64, -1, -1, 67, 68, -1, 70, + -1, -1, 73, 74, 75, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 39, -1, -1, -1, -1, + 44, 45, 46, 47, -1, -1, -1, -1, 52, 53, + -1, -1, -1, -1, -1, 59, 60, -1, 62, -1, + 64, -1, -1, 67, 68, 69, 70, -1, 3, 4, + -1, 75, 7, 8, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 20, -1, 22, 23, 24, + -1, -1, 27, 28, 29, 30, 31, 32, 33, 34, + 35, -1, -1, -1, 39, 40, -1, -1, -1, 44, + 45, 46, 47, -1, -1, 3, 4, -1, 53, 7, + 8, -1, -1, -1, 59, 60, -1, 62, -1, 64, + -1, -1, 67, 68, -1, 70, -1, -1, 73, -1, + 75, -1, -1, -1, -1, -1, 1, -1, 3, 4, + -1, 39, 7, 8, 9, -1, 44, 45, 46, 47, + -1, -1, -1, -1, -1, 53, -1, -1, -1, -1, + -1, 59, 60, -1, 62, -1, 64, -1, -1, 67, + 68, -1, 70, -1, 39, -1, -1, 75, -1, 44, + 45, 46, 47, 1, -1, 3, 4, -1, 53, 7, + 8, 9, -1, -1, 59, 60, -1, 62, -1, 64, + -1, -1, 67, 68, 69, 70, -1, -1, -1, -1, + 1, -1, 3, 4, -1, -1, 7, 8, -1, -1, + -1, 39, -1, -1, -1, -1, 44, 45, 46, 47, + -1, -1, -1, -1, 10, 53, -1, -1, -1, 15, + -1, 59, 60, -1, 62, -1, 64, -1, 39, 67, + 68, -1, 70, 44, 45, 46, 47, 1, -1, 3, + 4, -1, 53, 7, 8, 41, 42, 43, 59, 60, + -1, 62, -1, 64, -1, -1, 67, 68, 54, 70, + 56, 57, 58, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 3, 4, -1, 39, 7, 8, -1, -1, + 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, 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, 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. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 0, 2, 2, 2, 2, 2, 2, 2, + 4, 4, 1, 2, 1, 1, 2, 1, 0, 1, + 4, 1, 1, 1, 1, 5, 1, 1, 1, 2, + 1, 1, 0, 7, 0, 3, 1, 1, 1, 0, + 2, 2, 1, 2, 2, 3, 1, 9, 6, 8, + 8, 12, 11, 1, 2, 2, 2, 2, 3, 0, + 4, 2, 0, 4, 0, 4, 4, 1, 0, 1, + 0, 2, 2, 5, 4, 1, 2, 2, 1, 1, + 1, 1, 1, 1, 3, 0, 0, 3, 6, 9, + 1, 2, 0, 1, 0, 2, 0, 1, 1, 3, + 1, 2, 3, 0, 1, 0, 1, 1, 3, 1, + 2, 3, 3, 0, 1, 1, 3, 1, 2, 3, + 3, 1, 1, 3, 3, 3, 3, 3, 3, 3, + 3, 5, 1, 1, 1, 2, 1, 1, 1, 1, + 1, 1, 2, 1, 3, 3, 3, 3, 3, 3, + 3, 2, 2, 5, 4, 3, 3, 3, 3, 3, + 3, 1, 2, 3, 4, 4, 1, 1, 1, 2, + 2, 1, 1, 2, 2, 1, 2, 4, 0, 1, + 0, 2, 1, 2, 1, 3, 1, 2, 2, 1, + 2, 1, 3, 1, 1, 0, 2, 2, 1, 0, + 1, 1, 1, 2 +}; + + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (yylen); \ + yystate = *yyssp; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (0) + +/* Error token number */ +#define YYTERROR 1 +#define YYERRCODE 256 + + + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) + +/* This macro is provided for backward compatibility. */ +#ifndef YY_LOCATION_PRINT +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +#endif + + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (0) + + +/*----------------------------------------. +| Print this symbol's value on YYOUTPUT. | +`----------------------------------------*/ + +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +{ + FILE *yyo = yyoutput; + YYUSE (yyo); + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# endif + YYUSE (yytype); +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +{ + YYFPRINTF (yyoutput, "%s %s (", + yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (0) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +static void +yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule) +{ + unsigned long int yylno = yyrline[yyrule]; + int yynrhs = yyr2[yyrule]; + int yyi; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, + yystos[yyssp[yyi + 1 - yynrhs]], + &(yyvsp[(yyi + 1) - (yynrhs)]) + ); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyssp, yyvsp, Rule); \ +} while (0) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +static YYSIZE_T +yystrlen (const char *yystr) +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +yystpcpy (char *yydest, const char *yysrc) +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message + about the unexpected token YYTOKEN for the state stack whose top is + YYSSP. + + Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is + not large enough to hold the message. In that case, also set + *YYMSG_ALLOC to the required number of bytes. Return 2 if the + required number of bytes is too large to store. */ +static int +yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, + yytype_int16 *yyssp, int yytoken) +{ + YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); + YYSIZE_T yysize = yysize0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + /* Internationalized format string. */ + const char *yyformat = YY_NULLPTR; + /* Arguments of yyformat. */ + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + /* Number of reported tokens (one for the "unexpected", one per + "expected"). */ + int yycount = 0; + + /* There are many possibilities here to consider: + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yychar) is if + this state is a consistent state with a default action. Thus, + detecting the absence of a lookahead is sufficient to determine + that there is no unexpected or expected token to report. In that + case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is a + consistent state with a default action. There might have been a + previous inconsistent state, consistent state with a non-default + action, or user semantic action that manipulated yychar. + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state merging + (from LALR or IELR) and default reductions corrupt the expected + token list. However, the list is correct for canonical LR with + one exception: it will still contain any token that will not be + accepted due to an error action in a later state. + */ + if (yytoken != YYEMPTY) + { + int yyn = yypact[*yyssp]; + yyarg[yycount++] = yytname[yytoken]; + if (!yypact_value_is_default (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yyx; + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR + && !yytable_value_is_error (yytable[yyx + yyn])) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + break; + } + yyarg[yycount++] = yytname[yyx]; + { + YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); + if (! (yysize <= yysize1 + && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + } + } + } + + switch (yycount) + { +# define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + YYCASE_(0, YY_("syntax error")); + YYCASE_(1, YY_("syntax error, unexpected %s")); + YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +# undef YYCASE_ + } + + { + YYSIZE_T yysize1 = yysize + yystrlen (yyformat); + if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + + if (*yymsg_alloc < yysize) + { + *yymsg_alloc = 2 * yysize; + if (! (yysize <= *yymsg_alloc + && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) + *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; + return 1; + } + + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + { + char *yyp = *yymsg; + int yyi = 0; + while ((*yyp = *yyformat) != '\0') + if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyformat += 2; + } + else + { + yyp++; + yyformat++; + } + } + return 0; +} +#endif /* YYERROR_VERBOSE */ + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) +{ + YYUSE (yyvaluep); + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + YYUSE (yytype); + YY_IGNORE_MAYBE_UNINITIALIZED_END +} + + + + +/* The lookahead symbol. */ +int yychar; + +/* The semantic value of the lookahead symbol. */ +YYSTYPE yylval; +/* Number of syntax errors so far. */ +int yynerrs; + + +/*----------. +| yyparse. | +`----------*/ + +int +yyparse (void) +{ + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + 'yyss': related to states. + 'yyvs': related to semantic values. + + Refer to the stacks through separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken = 0; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yyssp = yyss = yyssa; + yyvsp = yyvs = yyvsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yypact_value_is_default (yyn)) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = yylex (); + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yytable_value_is_error (yyn)) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + '$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 3: +#line 218 "awkgram.y" /* yacc.c:1646 */ + { + rule = 0; + yyerrok; + } +#line 1897 "awkgram.c" /* yacc.c:1646 */ + break; + + case 5: +#line 224 "awkgram.y" /* yacc.c:1646 */ + { + next_sourcefile(); + } +#line 1905 "awkgram.c" /* yacc.c:1646 */ + break; + + case 6: +#line 228 "awkgram.y" /* yacc.c:1646 */ + { + rule = 0; + /* + * If errors, give up, don't produce an infinite + * stream of syntax error messages. + */ + /* yyerrok; */ + } +#line 1918 "awkgram.c" /* yacc.c:1646 */ + break; + + case 7: +#line 240 "awkgram.y" /* yacc.c:1646 */ + { + (void) append_rule((yyvsp[-1]), (yyvsp[0])); + first_rule = false; + } +#line 1927 "awkgram.c" /* yacc.c:1646 */ + break; + + case 8: +#line 245 "awkgram.y" /* yacc.c:1646 */ + { + if (rule != Rule) { + msg(_("%s blocks must have an action part"), ruletab[rule]); + errcount++; + } else if ((yyvsp[-1]) == NULL) { + msg(_("each rule must have a pattern or an action part")); + errcount++; + } else /* pattern rule with non-empty pattern */ + (void) append_rule((yyvsp[-1]), NULL); + } +#line 1942 "awkgram.c" /* yacc.c:1646 */ + break; + + case 9: +#line 256 "awkgram.y" /* yacc.c:1646 */ + { + in_function = NULL; + (void) mk_function((yyvsp[-1]), (yyvsp[0])); + want_param_names = DONT_CHECK; + yyerrok; + } +#line 1953 "awkgram.c" /* yacc.c:1646 */ + break; + + case 10: +#line 263 "awkgram.y" /* yacc.c:1646 */ + { + want_source = false; + at_seen = false; + yyerrok; + } +#line 1963 "awkgram.c" /* yacc.c:1646 */ + break; + + case 11: +#line 269 "awkgram.y" /* yacc.c:1646 */ + { + want_source = false; + at_seen = false; + yyerrok; + } +#line 1973 "awkgram.c" /* yacc.c:1646 */ + break; + + case 12: +#line 278 "awkgram.y" /* yacc.c:1646 */ + { + if (include_source((yyvsp[0])) < 0) + YYABORT; + efree((yyvsp[0])->lextok); + bcfree((yyvsp[0])); + (yyval) = NULL; + } +#line 1985 "awkgram.c" /* yacc.c:1646 */ + break; + + case 13: +#line 286 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = NULL; } +#line 1991 "awkgram.c" /* yacc.c:1646 */ + break; + + case 14: +#line 288 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = NULL; } +#line 1997 "awkgram.c" /* yacc.c:1646 */ + break; + + case 15: +#line 293 "awkgram.y" /* yacc.c:1646 */ + { + if (load_library((yyvsp[0])) < 0) + YYABORT; + efree((yyvsp[0])->lextok); + bcfree((yyvsp[0])); + (yyval) = NULL; + } +#line 2009 "awkgram.c" /* yacc.c:1646 */ + break; + + case 16: +#line 301 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = NULL; } +#line 2015 "awkgram.c" /* yacc.c:1646 */ + break; + + case 17: +#line 303 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = NULL; } +#line 2021 "awkgram.c" /* yacc.c:1646 */ + break; + + case 18: +#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 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 327 "awkgram.y" /* yacc.c:1646 */ + { + INSTRUCTION *tp; + + add_lint((yyvsp[-3]), LINT_assign_in_cond); + add_lint((yyvsp[0]), LINT_assign_in_cond); + + tp = instruction(Op_no_op); + list_prepend((yyvsp[-3]), bcalloc(Op_line_range, !!do_pretty_print + 1, 0)); + (yyvsp[-3])->nexti->triggered = false; + (yyvsp[-3])->nexti->target_jmp = (yyvsp[0])->nexti; + + list_append((yyvsp[-3]), instruction(Op_cond_pair)); + (yyvsp[-3])->lasti->line_range = (yyvsp[-3])->nexti; + (yyvsp[-3])->lasti->target_jmp = tp; + + list_append((yyvsp[0]), instruction(Op_cond_pair)); + (yyvsp[0])->lasti->line_range = (yyvsp[-3])->nexti; + (yyvsp[0])->lasti->target_jmp = tp; + if (do_pretty_print) { + ((yyvsp[-3])->nexti + 1)->condpair_left = (yyvsp[-3])->lasti; + ((yyvsp[-3])->nexti + 1)->condpair_right = (yyvsp[0])->lasti; + } + 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 2081 "awkgram.c" /* yacc.c:1646 */ + break; + + case 21: +#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 2099 "awkgram.c" /* yacc.c:1646 */ + break; + + case 22: +#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 2117 "awkgram.c" /* yacc.c:1646 */ + break; + + case 23: +#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 2129 "awkgram.c" /* yacc.c:1646 */ + break; + + case 24: +#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 2141 "awkgram.c" /* yacc.c:1646 */ + break; + + case 25: +#line 404 "awkgram.y" /* yacc.c:1646 */ + { + INSTRUCTION *ip; + if ((yyvsp[-3]) == NULL) + ip = list_create(instruction(Op_no_op)); + else + ip = (yyvsp[-3]); + (yyval) = ip; + } +#line 2154 "awkgram.c" /* yacc.c:1646 */ + break; + + case 26: +#line 416 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[0]); } +#line 2160 "awkgram.c" /* yacc.c:1646 */ + break; + + case 27: +#line 418 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[0]); } +#line 2166 "awkgram.c" /* yacc.c:1646 */ + break; + + case 28: +#line 420 "awkgram.y" /* yacc.c:1646 */ + { + yyerror(_("`%s' is a built-in function, it cannot be redefined"), + tokstart); + YYABORT; + } +#line 2176 "awkgram.c" /* yacc.c:1646 */ + break; + + case 29: +#line 426 "awkgram.y" /* yacc.c:1646 */ + { + (yyval) = (yyvsp[0]); + at_seen = false; + } +#line 2185 "awkgram.c" /* yacc.c:1646 */ + break; + + case 32: +#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 */ + { + /* + * 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[-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 2233 "awkgram.c" /* yacc.c:1646 */ + break; + + case 34: +#line 484 "awkgram.y" /* yacc.c:1646 */ + { want_regexp = true; } +#line 2239 "awkgram.c" /* yacc.c:1646 */ + break; + + case 35: +#line 486 "awkgram.y" /* yacc.c:1646 */ + { + NODE *n, *exp; + char *re; + size_t len; + + re = (yyvsp[0])->lextok; + (yyvsp[0])->lextok = NULL; + len = strlen(re); + if (do_lint) { + if (len == 0) + lintwarn_ln((yyvsp[0])->source_line, + _("regexp constant `//' looks like a C++ comment, but is not")); + else if (re[0] == '*' && re[len-1] == '*') + /* possible C comment */ + lintwarn_ln((yyvsp[0])->source_line, + _("regexp constant `/%s/' looks like a C comment, but is not"), re); + } + + exp = make_str_node(re, len, ALREADY_MALLOCED); + n = make_regnode(Node_regex, exp); + if (n == NULL) { + unref(exp); + YYABORT; + } + (yyval) = (yyvsp[0]); + (yyval)->opcode = Op_match_rec; + (yyval)->memory = n; + } +#line 2272 "awkgram.c" /* yacc.c:1646 */ + break; + + 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 533 "awkgram.y" /* yacc.c:1646 */ + { bcfree((yyvsp[0])); } +#line 2295 "awkgram.c" /* yacc.c:1646 */ + break; + + case 39: +#line 539 "awkgram.y" /* yacc.c:1646 */ + { + 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) { + 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; + } +#line 2361 "awkgram.c" /* yacc.c:1646 */ + break; + + case 41: +#line 597 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = NULL; } +#line 2367 "awkgram.c" /* yacc.c:1646 */ + break; + + case 44: +#line 607 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = NULL; } +#line 2373 "awkgram.c" /* yacc.c:1646 */ + break; + + case 45: +#line 609 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[-1]); } +#line 2379 "awkgram.c" /* yacc.c:1646 */ + break; + + 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 2390 "awkgram.c" /* yacc.c:1646 */ + break; + + case 47: +#line 618 "awkgram.y" /* yacc.c:1646 */ + { + INSTRUCTION *dflt, *curr = NULL, *cexp, *cstmt; + INSTRUCTION *ip, *nextc, *tbreak; + const char **case_values = NULL; + int maxcount = 128; + int case_count = 0; + int i; + + tbreak = instruction(Op_no_op); + cstmt = list_create(tbreak); + cexp = list_create(instruction(Op_pop)); + dflt = instruction(Op_jmp); + dflt->target_jmp = tbreak; /* if no case match and no explicit default */ + + if ((yyvsp[-2]) != NULL) { + curr = (yyvsp[-2])->nexti; + bcfree((yyvsp[-2])); /* Op_list */ + } /* else + curr = NULL; */ + + for (; curr != NULL; curr = nextc) { + INSTRUCTION *caseexp = curr->case_exp; + INSTRUCTION *casestmt = curr->case_stmt; + + nextc = curr->nexti; + if (curr->opcode == Op_K_case) { + if (caseexp->opcode == Op_push_i) { + /* a constant scalar */ + char *caseval; + caseval = force_string(caseexp->memory)->stptr; + for (i = 0; i < case_count; i++) { + if (strcmp(caseval, case_values[i]) == 0) + 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) { + maxcount += 128; + erealloc(case_values, const char **, sizeof(char*) * maxcount, "statement"); + } + case_values[case_count++] = caseval; + } else { + /* match a constant regex against switch expression. */ + (curr + 1)->match_exp = true; + } + curr->stmt_start = casestmt->nexti; + curr->stmt_end = casestmt->lasti; + (void) list_prepend(cexp, curr); + (void) list_prepend(cexp, caseexp); + } else { + if (dflt->target_jmp != tbreak) + error_ln(curr->source_line, + _("duplicate `default' detected in switch body")); + else + dflt->target_jmp = casestmt->nexti; + + if (do_pretty_print) { + curr->stmt_start = casestmt->nexti; + curr->stmt_end = casestmt->lasti; + (void) list_prepend(cexp, curr); + } else + bcfree(curr); + } + + cstmt = list_merge(casestmt, cstmt); + } + + if (case_values != NULL) + efree(case_values); + + ip = (yyvsp[-6]); + if (do_pretty_print) { + (void) list_prepend(ip, (yyvsp[-8])); + (void) list_prepend(ip, instruction(Op_exec_count)); + (yyvsp[-8])->target_break = tbreak; + ((yyvsp[-8]) + 1)->switch_start = cexp->nexti; + ((yyvsp[-8]) + 1)->switch_end = cexp->lasti; + }/* else + $1 is NULL */ + + (void) list_append(cexp, dflt); + (void) list_merge(ip, cexp); + (yyval) = list_merge(ip, cstmt); + + break_allowed--; + fix_break_continue(ip, tbreak, NULL); + } +#line 2484 "awkgram.c" /* yacc.c:1646 */ + break; + + case 48: +#line 708 "awkgram.y" /* yacc.c:1646 */ + { + /* + * ----------------- + * tc: + * cond + * ----------------- + * [Op_jmp_false tb ] + * ----------------- + * body + * ----------------- + * [Op_jmp tc ] + * tb:[Op_no_op ] + */ + + INSTRUCTION *ip, *tbreak, *tcont; + + tbreak = instruction(Op_no_op); + add_lint((yyvsp[-3]), LINT_assign_in_cond); + tcont = (yyvsp[-3])->nexti; + ip = list_append((yyvsp[-3]), instruction(Op_jmp_false)); + ip->lasti->target_jmp = tbreak; + + if (do_pretty_print) { + (void) list_append(ip, instruction(Op_exec_count)); + (yyvsp[-5])->target_break = tbreak; + (yyvsp[-5])->target_continue = tcont; + ((yyvsp[-5]) + 1)->while_body = ip->lasti; + (void) list_prepend(ip, (yyvsp[-5])); + }/* else + $1 is NULL */ + + if ((yyvsp[0]) != NULL) + (void) list_merge(ip, (yyvsp[0])); + (void) list_append(ip, instruction(Op_jmp)); + ip->lasti->target_jmp = tcont; + (yyval) = list_append(ip, tbreak); + + break_allowed--; + continue_allowed--; + fix_break_continue(ip, tbreak, tcont); + } +#line 2530 "awkgram.c" /* yacc.c:1646 */ + break; + + case 49: +#line 750 "awkgram.y" /* yacc.c:1646 */ + { + /* + * ----------------- + * z: + * body + * ----------------- + * tc: + * cond + * ----------------- + * [Op_jmp_true | z ] + * tb:[Op_no_op ] + */ + + INSTRUCTION *ip, *tbreak, *tcont; + + tbreak = instruction(Op_no_op); + tcont = (yyvsp[-2])->nexti; + add_lint((yyvsp[-2]), LINT_assign_in_cond); + if ((yyvsp[-5]) != NULL) + ip = list_merge((yyvsp[-5]), (yyvsp[-2])); + else + ip = list_prepend((yyvsp[-2]), instruction(Op_no_op)); + if (do_pretty_print) + (void) list_prepend(ip, instruction(Op_exec_count)); + (void) list_append(ip, instruction(Op_jmp_true)); + ip->lasti->target_jmp = ip->nexti; + (yyval) = list_append(ip, tbreak); + + break_allowed--; + continue_allowed--; + fix_break_continue(ip, tbreak, tcont); + + if (do_pretty_print) { + (yyvsp[-7])->target_break = tbreak; + (yyvsp[-7])->target_continue = tcont; + ((yyvsp[-7]) + 1)->doloop_cond = tcont; + (yyval) = list_prepend(ip, (yyvsp[-7])); + bcfree((yyvsp[-4])); + } /* else + $1 and $4 are NULLs */ + } +#line 2576 "awkgram.c" /* yacc.c:1646 */ + break; + + case 50: +#line 792 "awkgram.y" /* yacc.c:1646 */ + { + INSTRUCTION *ip; + char *var_name = (yyvsp[-5])->lextok; + + if ((yyvsp[0]) != NULL + && (yyvsp[0])->lasti->opcode == Op_K_delete + && (yyvsp[0])->lasti->expr_count == 1 + && (yyvsp[0])->nexti->opcode == Op_push + && ((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) + * delete foo[iggy] + * + * and treat it as if it were + * + * delete foo + * + * 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; + if ((yyvsp[-3])->nexti->opcode == Op_push && (yyvsp[-3])->lasti == (yyvsp[-3])->nexti) + arr = (yyvsp[-3])->nexti->memory; + if (arr != NULL + && ip->opcode == Op_no_op + && ip->nexti->opcode == Op_push_array + && strcmp(ip->nexti->memory->vname, arr->vname) == 0 + && ip->nexti->nexti == (yyvsp[0])->lasti + ) { + (void) make_assignable((yyvsp[0])->nexti); + (yyvsp[0])->lasti->opcode = Op_K_delete_loop; + (yyvsp[0])->lasti->expr_count = 0; + if ((yyvsp[-7]) != NULL) + bcfree((yyvsp[-7])); + efree(var_name); + bcfree((yyvsp[-5])); + bcfree((yyvsp[-4])); + bcfree((yyvsp[-3])); + (yyval) = (yyvsp[0]); + } else + goto regular_loop; + } else { + INSTRUCTION *tbreak, *tcont; + + /* [ Op_push_array a ] + * [ Op_arrayfor_init | ib ] + * ic:[ Op_arrayfor_incr | ib ] + * [ Op_var_assign if any ] + * + * body + * + * [Op_jmp | ic ] + * ib:[Op_arrayfor_final ] + */ +regular_loop: + ip = (yyvsp[-3]); + ip->nexti->opcode = Op_push_array; + + tbreak = instruction(Op_arrayfor_final); + (yyvsp[-4])->opcode = Op_arrayfor_incr; + (yyvsp[-4])->array_var = variable((yyvsp[-5])->source_line, var_name, Node_var); + (yyvsp[-4])->target_jmp = tbreak; + tcont = (yyvsp[-4]); + (yyvsp[-5])->opcode = Op_arrayfor_init; + (yyvsp[-5])->target_jmp = tbreak; + (void) list_append(ip, (yyvsp[-5])); + + if (do_pretty_print) { + (yyvsp[-7])->opcode = Op_K_arrayfor; + (yyvsp[-7])->target_continue = tcont; + (yyvsp[-7])->target_break = tbreak; + (void) list_append(ip, (yyvsp[-7])); + } /* else + $1 is NULL */ + + /* 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; + } + (void) list_append(ip, (yyvsp[-4])); + + /* add set_FOO instruction if necessary */ + if ((yyvsp[-4])->array_var->type == Node_var && (yyvsp[-4])->array_var->var_assign) { + (void) list_append(ip, instruction(Op_var_assign)); + ip->lasti->assign_var = (yyvsp[-4])->array_var->var_assign; + } + + 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; + } + + if ((yyvsp[0]) != NULL) + (void) list_merge(ip, (yyvsp[0])); + + (void) list_append(ip, instruction(Op_jmp)); + ip->lasti->target_jmp = (yyvsp[-4]); + (yyval) = list_append(ip, tbreak); + fix_break_continue(ip, tbreak, tcont); + } + + break_allowed--; + continue_allowed--; + } +#line 2693 "awkgram.c" /* yacc.c:1646 */ + break; + + 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 2704 "awkgram.c" /* yacc.c:1646 */ + break; + + 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 2715 "awkgram.c" /* yacc.c:1646 */ + break; + + 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 2727 "awkgram.c" /* yacc.c:1646 */ + break; + + 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 2741 "awkgram.c" /* yacc.c:1646 */ + break; + + 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 2755 "awkgram.c" /* yacc.c:1646 */ + break; + + case 56: +#line 950 "awkgram.y" /* yacc.c:1646 */ + { + /* if inside function (rule = 0), resolve context at run-time */ + if (rule && rule != Rule) + error_ln((yyvsp[-1])->source_line, + _("`next' used in %s action"), ruletab[rule]); + (yyvsp[-1])->target_jmp = ip_rec; + (yyval) = list_create((yyvsp[-1])); + (yyval) = add_pending_comment((yyval)); + } +#line 2769 "awkgram.c" /* yacc.c:1646 */ + break; + + 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) + error_ln((yyvsp[-1])->source_line, + _("`nextfile' used in %s action"), ruletab[rule]); + + (yyvsp[-1])->target_newfile = ip_newfile; + (yyvsp[-1])->target_endfile = ip_endfile; + (yyval) = list_create((yyvsp[-1])); + (yyval) = add_pending_comment((yyval)); + } +#line 2785 "awkgram.c" /* yacc.c:1646 */ + break; + + case 58: +#line 972 "awkgram.y" /* yacc.c:1646 */ + { + /* Initialize the two possible jump targets, the actual target + * 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 */ + + if ((yyvsp[-1]) == NULL) { + (yyval) = list_create((yyvsp[-2])); + (void) list_prepend((yyval), instruction(Op_push_i)); + (yyval)->nexti->memory = dupnode(Nnull_string); + } else + (yyval) = list_append((yyvsp[-1]), (yyvsp[-2])); + (yyval) = add_pending_comment((yyval)); + } +#line 2805 "awkgram.c" /* yacc.c:1646 */ + break; + + case 59: +#line 988 "awkgram.y" /* yacc.c:1646 */ + { + if (! in_function) + yyerror(_("`return' used outside function context")); + } +#line 2814 "awkgram.c" /* yacc.c:1646 */ + break; + + case 60: +#line 991 "awkgram.y" /* yacc.c:1646 */ + { + if ((yyvsp[-1]) == NULL) { + (yyval) = list_create((yyvsp[-3])); + (void) list_prepend((yyval), instruction(Op_push_i)); + (yyval)->nexti->memory = dupnode(Nnull_string); + } else { + if (do_optimize + && (yyvsp[-1])->lasti->opcode == Op_func_call + && strcmp((yyvsp[-1])->lasti->func_name, in_function) == 0 + ) { + /* Do tail recursion optimization. Tail + * call without a return value is recognized + * in mk_function(). + */ + ((yyvsp[-1])->lasti + 1)->tail_call = true; + } + + (yyval) = list_append((yyvsp[-1]), (yyvsp[-3])); + } + (yyval) = add_pending_comment((yyval)); + } +#line 2840 "awkgram.c" /* yacc.c:1646 */ + break; + + case 62: +#line 1024 "awkgram.y" /* yacc.c:1646 */ + { in_print = true; in_parens = 0; } +#line 2846 "awkgram.c" /* yacc.c:1646 */ + break; + + case 63: +#line 1025 "awkgram.y" /* yacc.c:1646 */ + { + /* + * Optimization: plain `print' has no expression list, so $3 is null. + * If $3 is NULL or is a bytecode list for $0 use Op_K_print_rec, + * which is faster for these two cases. + */ + + if ((yyvsp[-3])->opcode == Op_K_print && + ((yyvsp[-1]) == NULL + || ((yyvsp[-1])->lasti->opcode == Op_field_spec + && (yyvsp[-1])->nexti->nexti->nexti == (yyvsp[-1])->lasti + && (yyvsp[-1])->nexti->nexti->opcode == Op_push_i + && (yyvsp[-1])->nexti->nexti->memory->type == Node_val) + ) + ) { + static bool warned = false; + /* ----------------- + * output_redir + * [ redirect exp ] + * ----------------- + * expression_list + * ------------------ + * [Op_K_print_rec | NULL | redir_type | expr_count] + */ + + if ((yyvsp[-1]) != NULL) { + NODE *n = (yyvsp[-1])->nexti->nexti->memory; + + if (! iszero(n)) + goto regular_print; + + bcfree((yyvsp[-1])->lasti); /* Op_field_spec */ + unref(n); /* Node_val */ + bcfree((yyvsp[-1])->nexti->nexti); /* Op_push_i */ + bcfree((yyvsp[-1])->nexti); /* Op_list */ + bcfree((yyvsp[-1])); /* Op_list */ + } else { + if (do_lint && (rule == BEGIN || rule == END) && ! warned) { + warned = true; + lintwarn_ln((yyvsp[-3])->source_line, + _("plain `print' in BEGIN or END rule should probably be `print \"\"'")); + } + } + + (yyvsp[-3])->expr_count = 0; + (yyvsp[-3])->opcode = Op_K_print_rec; + if ((yyvsp[0]) == NULL) { /* no redircetion */ + (yyvsp[-3])->redir_type = redirect_none; + (yyval) = list_create((yyvsp[-3])); + } else { + INSTRUCTION *ip; + ip = (yyvsp[0])->nexti; + (yyvsp[-3])->redir_type = ip->redir_type; + (yyvsp[0])->nexti = ip->nexti; + bcfree(ip); + (yyval) = list_append((yyvsp[0]), (yyvsp[-3])); + } + } else { + /* ----------------- + * [ output_redir ] + * [ redirect exp ] + * ----------------- + * [ expression_list ] + * ------------------ + * [$1 | NULL | redir_type | expr_count] + * + */ +regular_print: + if ((yyvsp[0]) == NULL) { /* no redirection */ + if ((yyvsp[-1]) == NULL) { /* printf without arg */ + (yyvsp[-3])->expr_count = 0; + (yyvsp[-3])->redir_type = redirect_none; + (yyval) = list_create((yyvsp[-3])); + } else { + INSTRUCTION *t = (yyvsp[-1]); + (yyvsp[-3])->expr_count = count_expressions(&t, false); + (yyvsp[-3])->redir_type = redirect_none; + (yyval) = list_append(t, (yyvsp[-3])); + } + } else { + INSTRUCTION *ip; + ip = (yyvsp[0])->nexti; + (yyvsp[-3])->redir_type = ip->redir_type; + (yyvsp[0])->nexti = ip->nexti; + bcfree(ip); + if ((yyvsp[-1]) == NULL) { + (yyvsp[-3])->expr_count = 0; + (yyval) = list_append((yyvsp[0]), (yyvsp[-3])); + } else { + INSTRUCTION *t = (yyvsp[-1]); + (yyvsp[-3])->expr_count = count_expressions(&t, false); + (yyval) = list_append(list_merge((yyvsp[0]), t), (yyvsp[-3])); + } + } + } + (yyval) = add_pending_comment((yyval)); + } +#line 2948 "awkgram.c" /* yacc.c:1646 */ + break; + + case 64: +#line 1123 "awkgram.y" /* yacc.c:1646 */ + { sub_counter = 0; } +#line 2954 "awkgram.c" /* yacc.c:1646 */ + break; + + case 65: +#line 1124 "awkgram.y" /* yacc.c:1646 */ + { + char *arr = (yyvsp[-2])->lextok; + + (yyvsp[-2])->opcode = Op_push_array; + (yyvsp[-2])->memory = variable((yyvsp[-2])->source_line, arr, Node_var_new); + + if (! do_posix && ! do_traditional) { + if ((yyvsp[-2])->memory == symbol_table) + fatal(_("`delete' is not allowed with SYMTAB")); + else if ((yyvsp[-2])->memory == func_table) + fatal(_("`delete' is not allowed with FUNCTAB")); + } + + if ((yyvsp[0]) == NULL) { + /* + * As of September 2012, POSIX has added support + * for `delete array'. See: + * http://austingroupbugs.net/view.php?id=544 + * + * Thanks to Nathan Weeks for the initiative. + * + * Thus we no longer warn or check do_posix. + * Also, since BWK awk supports it, we don't have to + * check do_traditional either. + */ + (yyvsp[-3])->expr_count = 0; + (yyval) = list_append(list_create((yyvsp[-2])), (yyvsp[-3])); + } else { + (yyvsp[-3])->expr_count = sub_counter; + (yyval) = list_append(list_append((yyvsp[0]), (yyvsp[-2])), (yyvsp[-3])); + } + (yyval) = add_pending_comment((yyval)); + } +#line 2992 "awkgram.c" /* yacc.c:1646 */ + break; + + case 66: +#line 1162 "awkgram.y" /* yacc.c:1646 */ + { + static bool warned = false; + char *arr = (yyvsp[-1])->lextok; + + if (do_lint && ! warned) { + warned = true; + lintwarn_ln((yyvsp[-3])->source_line, + _("`delete(array)' is a non-portable tawk extension")); + } + if (do_traditional) { + error_ln((yyvsp[-3])->source_line, + _("`delete(array)' is a non-portable tawk extension")); + } + (yyvsp[-1])->memory = variable((yyvsp[-1])->source_line, arr, Node_var_new); + (yyvsp[-1])->opcode = Op_push_array; + (yyvsp[-3])->expr_count = 0; + (yyval) = list_append(list_create((yyvsp[-1])), (yyvsp[-3])); + + if (! do_posix && ! do_traditional) { + if ((yyvsp[-1])->memory == symbol_table) + fatal(_("`delete' is not allowed with SYMTAB")); + else if ((yyvsp[-1])->memory == func_table) + fatal(_("`delete' is not allowed with FUNCTAB")); + } + (yyval) = add_pending_comment((yyval)); + } +#line 3023 "awkgram.c" /* yacc.c:1646 */ + break; + + 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 68: +#line 1197 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = NULL; } +#line 3038 "awkgram.c" /* yacc.c:1646 */ + break; + + case 69: +#line 1199 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[0]); } +#line 3044 "awkgram.c" /* yacc.c:1646 */ + break; + + case 70: +#line 1204 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = NULL; } +#line 3050 "awkgram.c" /* yacc.c:1646 */ + break; + + 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 3061 "awkgram.c" /* yacc.c:1646 */ + break; + + case 72: +#line 1213 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = NULL; } +#line 3067 "awkgram.c" /* yacc.c:1646 */ + break; + + case 73: +#line 1218 "awkgram.y" /* yacc.c:1646 */ + { + INSTRUCTION *casestmt = (yyvsp[0]); + if ((yyvsp[0]) == NULL) + 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]); + (yyvsp[-4])->case_stmt = casestmt; + bcfree((yyvsp[-2])); + (yyval) = (yyvsp[-4]); + } +#line 3083 "awkgram.c" /* yacc.c:1646 */ + break; + + case 74: +#line 1230 "awkgram.y" /* yacc.c:1646 */ + { + INSTRUCTION *casestmt = (yyvsp[0]); + if ((yyvsp[0]) == NULL) + casestmt = list_create(instruction(Op_no_op)); + if (do_pretty_print) + (void) list_prepend(casestmt, instruction(Op_exec_count)); + bcfree((yyvsp[-2])); + (yyvsp[-3])->case_stmt = casestmt; + (yyval) = (yyvsp[-3]); + } +#line 3098 "awkgram.c" /* yacc.c:1646 */ + break; + + case 75: +#line 1244 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[0]); } +#line 3104 "awkgram.c" /* yacc.c:1646 */ + break; + + 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 3116 "awkgram.c" /* yacc.c:1646 */ + break; + + 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 3127 "awkgram.c" /* yacc.c:1646 */ + break; + + case 78: +#line 1261 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[0]); } +#line 3133 "awkgram.c" /* yacc.c:1646 */ + break; + + 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 3155 "awkgram.c" /* yacc.c:1646 */ + break; + + case 81: +#line 1280 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[0]); } +#line 3161 "awkgram.c" /* yacc.c:1646 */ + break; + + case 82: +#line 1282 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[0]); } +#line 3167 "awkgram.c" /* yacc.c:1646 */ + break; + + case 84: +#line 1292 "awkgram.y" /* yacc.c:1646 */ + { + (yyval) = (yyvsp[-1]); + } +#line 3175 "awkgram.c" /* yacc.c:1646 */ + break; + + case 85: +#line 1299 "awkgram.y" /* yacc.c:1646 */ + { + in_print = false; + in_parens = 0; + (yyval) = NULL; + } +#line 3185 "awkgram.c" /* yacc.c:1646 */ + break; + + case 86: +#line 1304 "awkgram.y" /* yacc.c:1646 */ + { in_print = false; in_parens = 0; } +#line 3191 "awkgram.c" /* yacc.c:1646 */ + break; + + case 87: +#line 1305 "awkgram.y" /* yacc.c:1646 */ + { + if ((yyvsp[-2])->redir_type == redirect_twoway + && (yyvsp[0])->lasti->opcode == Op_K_getline_redir + && (yyvsp[0])->lasti->redir_type == redirect_twoway) + yyerror(_("multistage two-way pipelines don't work")); + (yyval) = list_prepend((yyvsp[0]), (yyvsp[-2])); + } +#line 3203 "awkgram.c" /* yacc.c:1646 */ + break; + + case 88: +#line 1316 "awkgram.y" /* yacc.c:1646 */ + { + (yyval) = mk_condition((yyvsp[-3]), (yyvsp[-5]), (yyvsp[0]), NULL, NULL); + } +#line 3211 "awkgram.c" /* yacc.c:1646 */ + break; + + case 89: +#line 1321 "awkgram.y" /* yacc.c:1646 */ + { + (yyval) = mk_condition((yyvsp[-6]), (yyvsp[-8]), (yyvsp[-3]), (yyvsp[-2]), (yyvsp[0])); + } +#line 3219 "awkgram.c" /* yacc.c:1646 */ + break; + + case 94: +#line 1338 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = NULL; } +#line 3225 "awkgram.c" /* yacc.c:1646 */ + break; + + case 95: +#line 1340 "awkgram.y" /* yacc.c:1646 */ + { + bcfree((yyvsp[-1])); + (yyval) = (yyvsp[0]); + } +#line 3234 "awkgram.c" /* yacc.c:1646 */ + break; + + case 96: +#line 1348 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = NULL; } +#line 3240 "awkgram.c" /* yacc.c:1646 */ + break; + + case 97: +#line 1350 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[0]); } +#line 3246 "awkgram.c" /* yacc.c:1646 */ + break; + + case 98: +#line 1355 "awkgram.y" /* yacc.c:1646 */ + { + (yyvsp[0])->param_count = 0; + (yyval) = list_create((yyvsp[0])); + } +#line 3255 "awkgram.c" /* yacc.c:1646 */ + break; + + 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; + (yyval) = list_append((yyvsp[-2]), (yyvsp[0])); + yyerrok; + } else + (yyval) = NULL; + } +#line 3268 "awkgram.c" /* yacc.c:1646 */ + break; + + case 100: +#line 1369 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = NULL; } +#line 3274 "awkgram.c" /* yacc.c:1646 */ + break; + + case 101: +#line 1371 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[-1]); } +#line 3280 "awkgram.c" /* yacc.c:1646 */ + break; + + case 102: +#line 1373 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[-2]); } +#line 3286 "awkgram.c" /* yacc.c:1646 */ + break; + + case 103: +#line 1379 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = NULL; } +#line 3292 "awkgram.c" /* yacc.c:1646 */ + break; + + case 104: +#line 1381 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[0]); } +#line 3298 "awkgram.c" /* yacc.c:1646 */ + break; + + case 105: +#line 1386 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = NULL; } +#line 3304 "awkgram.c" /* yacc.c:1646 */ + break; + + case 106: +#line 1388 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[0]); } +#line 3310 "awkgram.c" /* yacc.c:1646 */ + break; + + case 107: +#line 1393 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = mk_expression_list(NULL, (yyvsp[0])); } +#line 3316 "awkgram.c" /* yacc.c:1646 */ + break; + + case 108: +#line 1395 "awkgram.y" /* yacc.c:1646 */ + { + (yyval) = mk_expression_list((yyvsp[-2]), (yyvsp[0])); + yyerrok; + } +#line 3325 "awkgram.c" /* yacc.c:1646 */ + break; + + case 109: +#line 1400 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = NULL; } +#line 3331 "awkgram.c" /* yacc.c:1646 */ + break; + + case 110: +#line 1402 "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 3343 "awkgram.c" /* yacc.c:1646 */ + break; + + case 111: +#line 1410 "awkgram.y" /* yacc.c:1646 */ + { + /* Ditto */ + (yyval) = mk_expression_list((yyvsp[-2]), (yyvsp[0])); + } +#line 3352 "awkgram.c" /* yacc.c:1646 */ + break; + + case 112: +#line 1415 "awkgram.y" /* yacc.c:1646 */ + { + /* Ditto */ + (yyval) = (yyvsp[-2]); + } +#line 3361 "awkgram.c" /* yacc.c:1646 */ + break; + + 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 3447 "awkgram.c" /* yacc.c:1646 */ + break; + + 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 3461 "awkgram.c" /* yacc.c:1646 */ + break; + + case 126: +#line 1479 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = mk_boolean((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } +#line 3467 "awkgram.c" /* yacc.c:1646 */ + break; + + 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 */ + (yyval) = list_append((yyvsp[-2]), (yyvsp[-1])); + } else { + (yyvsp[-1])->memory = make_regnode(Node_dynregex, NULL); + (yyval) = list_append(list_merge((yyvsp[-2]), (yyvsp[0])), (yyvsp[-1])); + } + } +#line 3505 "awkgram.c" /* yacc.c:1646 */ + break; + + case 129: +#line 1511 "awkgram.y" /* yacc.c:1646 */ + { + if (do_lint_old) + warning_ln((yyvsp[-1])->source_line, + _("old awk does not support the keyword `in' except after `for'")); + (yyvsp[0])->nexti->opcode = Op_push_array; + (yyvsp[-1])->opcode = Op_in_array; + (yyvsp[-1])->expr_count = 1; + (yyval) = list_append(list_merge((yyvsp[-2]), (yyvsp[0])), (yyvsp[-1])); + } +#line 3519 "awkgram.c" /* yacc.c:1646 */ + break; + + 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 3530 "awkgram.c" /* yacc.c:1646 */ + break; + + case 131: +#line 1528 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = mk_condition((yyvsp[-4]), (yyvsp[-3]), (yyvsp[-2]), (yyvsp[-1]), (yyvsp[0])); } +#line 3536 "awkgram.c" /* yacc.c:1646 */ + break; + + case 132: +#line 1530 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[0]); } +#line 3542 "awkgram.c" /* yacc.c:1646 */ + break; + + case 133: +#line 1535 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[0]); } +#line 3548 "awkgram.c" /* yacc.c:1646 */ + break; + + case 134: +#line 1537 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[0]); } +#line 3554 "awkgram.c" /* yacc.c:1646 */ + break; + + case 135: +#line 1539 "awkgram.y" /* yacc.c:1646 */ + { + (yyvsp[0])->opcode = Op_assign_quotient; + (yyval) = (yyvsp[0]); + } +#line 3563 "awkgram.c" /* yacc.c:1646 */ + break; + + case 136: +#line 1547 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[0]); } +#line 3569 "awkgram.c" /* yacc.c:1646 */ + break; + + case 137: +#line 1549 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[0]); } +#line 3575 "awkgram.c" /* yacc.c:1646 */ + break; + + case 138: +#line 1554 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[0]); } +#line 3581 "awkgram.c" /* yacc.c:1646 */ + break; + + case 139: +#line 1556 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[0]); } +#line 3587 "awkgram.c" /* yacc.c:1646 */ + break; + + case 140: +#line 1561 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[0]); } +#line 3593 "awkgram.c" /* yacc.c:1646 */ + break; + + case 141: +#line 1563 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[0]); } +#line 3599 "awkgram.c" /* yacc.c:1646 */ + break; + + case 142: +#line 1565 "awkgram.y" /* yacc.c:1646 */ + { + int count = 2; + bool is_simple_var = false; + + if ((yyvsp[-1])->lasti->opcode == Op_concat) { + /* multiple (> 2) adjacent strings optimization */ + is_simple_var = ((yyvsp[-1])->lasti->concat_flag & CSVAR) != 0; + count = (yyvsp[-1])->lasti->expr_count + 1; + (yyvsp[-1])->lasti->opcode = Op_no_op; + } else { + is_simple_var = ((yyvsp[-1])->nexti->opcode == Op_push + && (yyvsp[-1])->lasti == (yyvsp[-1])->nexti); /* first exp. is a simple + * variable?; kludge for use + * in Op_assign_concat. + */ + } + + if (do_optimize + && (yyvsp[-1])->nexti == (yyvsp[-1])->lasti && (yyvsp[-1])->nexti->opcode == Op_push_i + && (yyvsp[0])->nexti == (yyvsp[0])->lasti && (yyvsp[0])->nexti->opcode == Op_push_i + ) { + NODE *n1 = (yyvsp[-1])->nexti->memory; + 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. + // Also can't fold if one or the other is translatable. + if ((n1->flags & (NUMBER|NUMINT|INTLSTR)) != 0 || (n2->flags & (NUMBER|NUMINT|INTLSTR)) != 0) + goto plain_concat; + + n1 = force_string(n1); + n2 = force_string(n2); + nlen = n1->stlen + n2->stlen; + erealloc(n1->stptr, char *, nlen + 1, "constant fold"); + memcpy(n1->stptr + n1->stlen, n2->stptr, n2->stlen); + n1->stlen = nlen; + n1->stptr[nlen] = '\0'; + n1->flags &= ~(NUMCUR|NUMBER|NUMINT); + n1->flags |= (STRING|STRCUR); + unref(n2); + bcfree((yyvsp[0])->nexti); + 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; + if (count > max_args) + max_args = count; + } + } +#line 3657 "awkgram.c" /* yacc.c:1646 */ + break; + + case 144: +#line 1624 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } +#line 3663 "awkgram.c" /* yacc.c:1646 */ + break; + + case 145: +#line 1626 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } +#line 3669 "awkgram.c" /* yacc.c:1646 */ + break; + + case 146: +#line 1628 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } +#line 3675 "awkgram.c" /* yacc.c:1646 */ + break; + + case 147: +#line 1630 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } +#line 3681 "awkgram.c" /* yacc.c:1646 */ + break; + + case 148: +#line 1632 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } +#line 3687 "awkgram.c" /* yacc.c:1646 */ + break; + + case 149: +#line 1634 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } +#line 3693 "awkgram.c" /* yacc.c:1646 */ + break; + + case 150: +#line 1636 "awkgram.y" /* yacc.c:1646 */ + { + /* + * In BEGINFILE/ENDFILE, allow `getline [var] < file' + */ + + if ((rule == BEGINFILE || rule == ENDFILE) && (yyvsp[0]) == NULL) + error_ln((yyvsp[-2])->source_line, + _("non-redirected `getline' invalid inside `%s' rule"), ruletab[rule]); + if (do_lint && rule == END && (yyvsp[0]) == NULL) + lintwarn_ln((yyvsp[-2])->source_line, + _("non-redirected `getline' undefined inside END action")); + (yyval) = mk_getline((yyvsp[-2]), (yyvsp[-1]), (yyvsp[0]), redirect_input); + } +#line 3711 "awkgram.c" /* yacc.c:1646 */ + break; + + case 151: +#line 1650 "awkgram.y" /* yacc.c:1646 */ + { + (yyvsp[0])->opcode = Op_postincrement; + (yyval) = mk_assignment((yyvsp[-1]), NULL, (yyvsp[0])); + } +#line 3720 "awkgram.c" /* yacc.c:1646 */ + break; + + case 152: +#line 1655 "awkgram.y" /* yacc.c:1646 */ + { + (yyvsp[0])->opcode = Op_postdecrement; + (yyval) = mk_assignment((yyvsp[-1]), NULL, (yyvsp[0])); + } +#line 3729 "awkgram.c" /* yacc.c:1646 */ + break; + + case 153: +#line 1660 "awkgram.y" /* yacc.c:1646 */ + { + if (do_lint_old) { + warning_ln((yyvsp[-1])->source_line, + _("old awk does not support the keyword `in' except after `for'")); + warning_ln((yyvsp[-1])->source_line, + _("old awk does not support multidimensional arrays")); + } + (yyvsp[0])->nexti->opcode = Op_push_array; + (yyvsp[-1])->opcode = Op_in_array; + if ((yyvsp[-3]) == NULL) { /* error */ + errcount++; + (yyvsp[-1])->expr_count = 0; + (yyval) = list_merge((yyvsp[0]), (yyvsp[-1])); + } else { + INSTRUCTION *t = (yyvsp[-3]); + (yyvsp[-1])->expr_count = count_expressions(&t, false); + (yyval) = list_append(list_merge(t, (yyvsp[0])), (yyvsp[-1])); + } + } +#line 3753 "awkgram.c" /* yacc.c:1646 */ + break; + + case 154: +#line 1685 "awkgram.y" /* yacc.c:1646 */ + { + (yyval) = mk_getline((yyvsp[-1]), (yyvsp[0]), (yyvsp[-3]), (yyvsp[-2])->redir_type); + bcfree((yyvsp[-2])); + } +#line 3762 "awkgram.c" /* yacc.c:1646 */ + break; + + case 155: +#line 1691 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } +#line 3768 "awkgram.c" /* yacc.c:1646 */ + break; + + case 156: +#line 1693 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } +#line 3774 "awkgram.c" /* yacc.c:1646 */ + break; + + case 157: +#line 1695 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } +#line 3780 "awkgram.c" /* yacc.c:1646 */ + break; + + case 158: +#line 1697 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } +#line 3786 "awkgram.c" /* yacc.c:1646 */ + break; + + case 159: +#line 1699 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } +#line 3792 "awkgram.c" /* yacc.c:1646 */ + break; + + case 160: +#line 1701 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); } +#line 3798 "awkgram.c" /* yacc.c:1646 */ + break; + + case 161: +#line 1706 "awkgram.y" /* yacc.c:1646 */ + { + (yyval) = list_create((yyvsp[0])); + } +#line 3806 "awkgram.c" /* yacc.c:1646 */ + break; + + case 162: +#line 1710 "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 = 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 { + if (do_optimize && (yyvsp[0])->nexti == (yyvsp[0])->lasti + && (yyvsp[0])->nexti->opcode == Op_push_i + && ((yyvsp[0])->nexti->memory->flags & (MPFN|MPZN|INTLSTR)) == 0 + ) { + NODE *n = (yyvsp[0])->nexti->memory; + if ((n->flags & STRING) != 0) { + n->numbr = (AWKNUM) (n->stlen == 0); + n->flags &= ~(STRCUR|STRING); + n->flags |= (NUMCUR|NUMBER); + efree(n->stptr); + n->stptr = NULL; + n->stlen = 0; + } else + n->numbr = (AWKNUM) (n->numbr == 0.0); + bcfree((yyvsp[-1])); + (yyval) = (yyvsp[0]); + } else { + (yyvsp[-1])->opcode = Op_not; + add_lint((yyvsp[0]), LINT_assign_in_cond); + (yyval) = list_append((yyvsp[0]), (yyvsp[-1])); + } + } + } +#line 3842 "awkgram.c" /* yacc.c:1646 */ + break; + + case 163: +#line 1742 "awkgram.y" /* yacc.c:1646 */ + { + if (do_pretty_print) + (yyval) = list_append((yyvsp[-1]), bcalloc(Op_parens, 1, sourceline)); + else + (yyval) = (yyvsp[-1]); + } +#line 3853 "awkgram.c" /* yacc.c:1646 */ + break; + + case 164: +#line 1749 "awkgram.y" /* yacc.c:1646 */ + { + (yyval) = snode((yyvsp[-1]), (yyvsp[-3])); + if ((yyval) == NULL) + YYABORT; + } +#line 3863 "awkgram.c" /* yacc.c:1646 */ + break; + + case 165: +#line 1755 "awkgram.y" /* yacc.c:1646 */ + { + (yyval) = snode((yyvsp[-1]), (yyvsp[-3])); + if ((yyval) == NULL) + YYABORT; + } +#line 3873 "awkgram.c" /* yacc.c:1646 */ + break; + + case 166: +#line 1761 "awkgram.y" /* yacc.c:1646 */ + { + static bool warned = false; + + if (do_lint && ! warned) { + warned = true; + lintwarn_ln((yyvsp[0])->source_line, + _("call of `length' without parentheses is not portable")); + } + (yyval) = snode(NULL, (yyvsp[0])); + if ((yyval) == NULL) + YYABORT; + } +#line 3890 "awkgram.c" /* yacc.c:1646 */ + break; + + case 169: +#line 1776 "awkgram.y" /* yacc.c:1646 */ + { + (yyvsp[-1])->opcode = Op_preincrement; + (yyval) = mk_assignment((yyvsp[0]), NULL, (yyvsp[-1])); + } +#line 3899 "awkgram.c" /* yacc.c:1646 */ + break; + + case 170: +#line 1781 "awkgram.y" /* yacc.c:1646 */ + { + (yyvsp[-1])->opcode = Op_predecrement; + (yyval) = mk_assignment((yyvsp[0]), NULL, (yyvsp[-1])); + } +#line 3908 "awkgram.c" /* yacc.c:1646 */ + break; + + case 171: +#line 1786 "awkgram.y" /* yacc.c:1646 */ + { + (yyval) = list_create((yyvsp[0])); + } +#line 3916 "awkgram.c" /* yacc.c:1646 */ + break; + + case 172: +#line 1790 "awkgram.y" /* yacc.c:1646 */ + { + (yyval) = list_create((yyvsp[0])); + } +#line 3924 "awkgram.c" /* yacc.c:1646 */ + break; + + case 173: +#line 1794 "awkgram.y" /* yacc.c:1646 */ + { + if ((yyvsp[0])->lasti->opcode == Op_push_i + && ((yyvsp[0])->lasti->memory->flags & STRING) == 0 + ) { + NODE *n = (yyvsp[0])->lasti->memory; + (void) force_number(n); + negate_num(n); + (yyval) = (yyvsp[0]); + bcfree((yyvsp[-1])); + } else { + (yyvsp[-1])->opcode = Op_unary_minus; + (yyval) = list_append((yyvsp[0]), (yyvsp[-1])); + } + } +#line 3943 "awkgram.c" /* yacc.c:1646 */ + break; + + case 174: +#line 1809 "awkgram.y" /* yacc.c:1646 */ + { + 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 3965 "awkgram.c" /* yacc.c:1646 */ + break; + + case 175: +#line 1830 "awkgram.y" /* yacc.c:1646 */ + { + func_use((yyvsp[0])->lasti->func_name, FUNC_USE); + (yyval) = (yyvsp[0]); + } +#line 3974 "awkgram.c" /* yacc.c:1646 */ + break; + + case 176: +#line 1835 "awkgram.y" /* yacc.c:1646 */ + { + /* indirect function call */ + INSTRUCTION *f, *t; + char *name; + NODE *indirect_var; + static bool warned = false; + const char *msg = _("indirect function calls are a gawk extension"); + + if (do_traditional || do_posix) + yyerror("%s", msg); + else if (do_lint && ! warned) { + warned = true; + lintwarn("%s", msg); + } + + f = (yyvsp[0])->lasti; + f->opcode = Op_indirect_func_call; + name = estrdup(f->func_name, strlen(f->func_name)); + if (is_std_var(name)) + yyerror(_("can not use special variable `%s' for indirect function call"), name); + indirect_var = variable(f->source_line, name, Node_var_new); + t = instruction(Op_push); + t->memory = indirect_var; + + /* prepend indirect var instead of appending to arguments (opt_expression_list), + * and pop it off in setup_frame (eval.c) (left to right evaluation order); Test case: + * f = "fun" + * @f(f="real_fun") + */ + + (yyval) = list_prepend((yyvsp[0]), t); + at_seen = false; + } +#line 4012 "awkgram.c" /* yacc.c:1646 */ + break; + + case 177: +#line 1872 "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) { + error_ln((yyvsp[-3])->source_line, + _("attempt to use non-function `%s' in function call"), + (yyvsp[-3])->func_name); + } + } + param_sanity((yyvsp[-1])); + (yyvsp[-3])->opcode = Op_func_call; + (yyvsp[-3])->func_body = NULL; + if ((yyvsp[-1]) == NULL) { /* no argument or error */ + ((yyvsp[-3]) + 1)->expr_count = 0; + (yyval) = list_create((yyvsp[-3])); + } else { + INSTRUCTION *t = (yyvsp[-1]); + ((yyvsp[-3]) + 1)->expr_count = count_expressions(&t, true); + (yyval) = list_append(t, (yyvsp[-3])); + } + } +#line 4041 "awkgram.c" /* yacc.c:1646 */ + break; + + case 178: +#line 1900 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = NULL; } +#line 4047 "awkgram.c" /* yacc.c:1646 */ + break; + + case 179: +#line 1902 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[0]); } +#line 4053 "awkgram.c" /* yacc.c:1646 */ + break; + + case 180: +#line 1907 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = NULL; } +#line 4059 "awkgram.c" /* yacc.c:1646 */ + break; + + case 181: +#line 1909 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[-1]); } +#line 4065 "awkgram.c" /* yacc.c:1646 */ + break; + + case 182: +#line 1914 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[0]); } +#line 4071 "awkgram.c" /* yacc.c:1646 */ + break; + + case 183: +#line 1916 "awkgram.y" /* yacc.c:1646 */ + { + (yyval) = list_merge((yyvsp[-1]), (yyvsp[0])); + } +#line 4079 "awkgram.c" /* yacc.c:1646 */ + break; + + case 184: +#line 1923 "awkgram.y" /* yacc.c:1646 */ + { + 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 */ + ip->opcode = Op_concat; + ip->concat_flag = CSUBSEP; + ip->expr_count = count; + } else + ip->opcode = Op_no_op; + sub_counter++; /* count # of dimensions */ + (yyval) = (yyvsp[0]); + } +#line 4097 "awkgram.c" /* yacc.c:1646 */ + break; + + case 185: +#line 1940 "awkgram.y" /* yacc.c:1646 */ + { + INSTRUCTION *t = (yyvsp[-1]); + if ((yyvsp[-1]) == NULL) { + error_ln((yyvsp[0])->source_line, + _("invalid subscript expression")); + /* install Null string as subscript. */ + t = list_create(instruction(Op_push_i)); + t->nexti->memory = dupnode(Nnull_string); + (yyvsp[0])->sub_count = 1; + } else + (yyvsp[0])->sub_count = count_expressions(&t, false); + (yyval) = list_append(t, (yyvsp[0])); + } +#line 4115 "awkgram.c" /* yacc.c:1646 */ + break; + + case 186: +#line 1957 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[0]); } +#line 4121 "awkgram.c" /* yacc.c:1646 */ + break; + + case 187: +#line 1959 "awkgram.y" /* yacc.c:1646 */ + { + (yyval) = list_merge((yyvsp[-1]), (yyvsp[0])); + } +#line 4129 "awkgram.c" /* yacc.c:1646 */ + break; + + case 188: +#line 1966 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[-1]); } +#line 4135 "awkgram.c" /* yacc.c:1646 */ + break; + + case 189: +#line 1971 "awkgram.y" /* yacc.c:1646 */ + { + char *var_name = (yyvsp[0])->lextok; + + (yyvsp[0])->opcode = Op_push; + (yyvsp[0])->memory = variable((yyvsp[0])->source_line, var_name, Node_var_new); + (yyval) = list_create((yyvsp[0])); + } +#line 4147 "awkgram.c" /* yacc.c:1646 */ + break; + + case 190: +#line 1979 "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 4158 "awkgram.c" /* yacc.c:1646 */ + break; + + case 191: +#line 1989 "awkgram.y" /* yacc.c:1646 */ + { + INSTRUCTION *ip = (yyvsp[0])->nexti; + if (ip->opcode == Op_push + && ip->memory->type == Node_var + && ip->memory->var_update + ) { + (yyval) = list_prepend((yyvsp[0]), instruction(Op_var_update)); + (yyval)->nexti->update_var = ip->memory->var_update; + } else + (yyval) = (yyvsp[0]); + } +#line 4174 "awkgram.c" /* yacc.c:1646 */ + break; + + case 192: +#line 2001 "awkgram.y" /* yacc.c:1646 */ + { + (yyval) = list_append((yyvsp[-1]), (yyvsp[-2])); + if ((yyvsp[0]) != NULL) + mk_assignment((yyvsp[-1]), NULL, (yyvsp[0])); + } +#line 4184 "awkgram.c" /* yacc.c:1646 */ + break; + + case 193: +#line 2010 "awkgram.y" /* yacc.c:1646 */ + { + (yyvsp[0])->opcode = Op_postincrement; + } +#line 4192 "awkgram.c" /* yacc.c:1646 */ + break; + + case 194: +#line 2014 "awkgram.y" /* yacc.c:1646 */ + { + (yyvsp[0])->opcode = Op_postdecrement; + } +#line 4200 "awkgram.c" /* yacc.c:1646 */ + break; + + case 195: +#line 2017 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = NULL; } +#line 4206 "awkgram.c" /* yacc.c:1646 */ + break; + + case 197: +#line 2025 "awkgram.y" /* yacc.c:1646 */ + { yyerrok; } +#line 4212 "awkgram.c" /* yacc.c:1646 */ + break; + + case 198: +#line 2029 "awkgram.y" /* yacc.c:1646 */ + { yyerrok; } +#line 4218 "awkgram.c" /* yacc.c:1646 */ + break; + + case 201: +#line 2038 "awkgram.y" /* yacc.c:1646 */ + { yyerrok; } +#line 4224 "awkgram.c" /* yacc.c:1646 */ + break; + + case 202: +#line 2042 "awkgram.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[0]); yyerrok; } +#line 4230 "awkgram.c" /* yacc.c:1646 */ + break; + + case 203: +#line 2046 "awkgram.y" /* yacc.c:1646 */ + { yyerrok; } +#line 4236 "awkgram.c" /* yacc.c:1646 */ + break; + + +#line 4240 "awkgram.c" /* yacc.c:1646 */ + default: break; + } + /* User semantic actions sometimes alter yychar, and that requires + that yytoken be updated with the new translation. We take the + approach of translating immediately before every use of yytoken. + One alternative is translating here after every semantic action, + but that translation would be missed if the semantic action invokes + YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or + if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an + incorrect destructor might then be invoked immediately. In the + case of YYERROR or YYBACKUP, subsequent parser actions might lead + to an incorrect destructor call or verbose syntax error message + before the lookahead is translated. */ + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + /* Now 'shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*--------------------------------------. +| yyerrlab -- here on detecting error. | +`--------------------------------------*/ +yyerrlab: + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); + + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (YY_("syntax error")); +#else +# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ + yyssp, yytoken) + { + char const *yymsgp = YY_("syntax error"); + int yysyntax_error_status; + yysyntax_error_status = YYSYNTAX_ERROR; + if (yysyntax_error_status == 0) + yymsgp = yymsg; + else if (yysyntax_error_status == 1) + { + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); + if (!yymsg) + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + yysyntax_error_status = 2; + } + else + { + yysyntax_error_status = YYSYNTAX_ERROR; + yymsgp = yymsg; + } + } + yyerror (yymsgp); + if (yysyntax_error_status == 2) + goto yyexhaustedlab; + } +# undef YYSYNTAX_ERROR +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule whose action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (!yypact_value_is_default (yyn)) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined yyoverflow || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + { + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = YYTRANSLATE (yychar); + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); + } + /* Do not reclaim the symbols of the rule whose action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + return yyresult; +} +#line 2048 "awkgram.y" /* yacc.c:1906 */ + + +struct token { + const char *operator; /* text to match */ + OPCODE value; /* type */ + int class; /* lexical class */ + unsigned flags; /* # of args. allowed and compatability */ +# define ARGS 0xFF /* 0, 1, 2, 3 args allowed (any combination */ +# define A(n) (1<<(n)) +# define VERSION_MASK 0xFF00 /* old awk is zero */ +# define NOT_OLD 0x0100 /* feature not in old awk */ +# define NOT_POSIX 0x0200 /* feature not in POSIX */ +# define GAWKX 0x0400 /* gawk extension */ +# define BREAK 0x0800 /* break allowed inside */ +# define CONTINUE 0x1000 /* continue allowed inside */ +# define DEBUG_USE 0x2000 /* for use by developers */ + + NODE *(*ptr)(int); /* function that implements this keyword */ + NODE *(*ptr2)(int); /* alternate arbitrary-precision function */ +}; + +#ifdef USE_EBCDIC +/* tokcompare --- lexicographically compare token names for sorting */ + +static int +tokcompare(const void *l, const void *r) +{ + struct token *lhs, *rhs; + + lhs = (struct token *) l; + rhs = (struct token *) r; + + return strcmp(lhs->operator, rhs->operator); +} +#endif + +/* + * Tokentab is sorted ASCII ascending order, so it can be binary searched. + * See check_special(), which sorts the table on EBCDIC systems. + * Function pointers come from declarations in awk.h. + */ + +#ifdef HAVE_MPFR +#define MPF(F) do_mpfr_##F +#else +#define MPF(F) 0 +#endif + +static const struct token tokentab[] = { +{"BEGIN", Op_rule, LEX_BEGIN, 0, 0, 0}, +{"BEGINFILE", Op_rule, LEX_BEGINFILE, GAWKX, 0, 0}, +{"END", Op_rule, LEX_END, 0, 0, 0}, +{"ENDFILE", Op_rule, LEX_ENDFILE, GAWKX, 0, 0}, +#ifdef ARRAYDEBUG +{"adump", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|DEBUG_USE, do_adump, 0}, +#endif +{"and", Op_builtin, LEX_BUILTIN, GAWKX, do_and, MPF(and)}, +{"asort", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_asort, 0}, +{"asorti", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_asorti, 0}, +{"atan2", Op_builtin, LEX_BUILTIN, NOT_OLD|A(2), do_atan2, MPF(atan2)}, +{"bindtextdomain", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2), do_bindtextdomain, 0}, +{"break", Op_K_break, LEX_BREAK, 0, 0, 0}, +{"case", Op_K_case, LEX_CASE, GAWKX, 0, 0}, +{"close", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1)|A(2), do_close, 0}, +{"compl", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_compl, MPF(compl)}, +{"continue", Op_K_continue, LEX_CONTINUE, 0, 0, 0}, +{"cos", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_cos, MPF(cos)}, +{"dcgettext", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_dcgettext, 0}, +{"dcngettext", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3)|A(4)|A(5), do_dcngettext, 0}, +{"default", Op_K_default, LEX_DEFAULT, GAWKX, 0, 0}, +{"delete", Op_K_delete, LEX_DELETE, NOT_OLD, 0, 0}, +{"do", Op_K_do, LEX_DO, NOT_OLD|BREAK|CONTINUE, 0, 0}, +{"else", Op_K_else, LEX_ELSE, 0, 0, 0}, +{"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)}, +{"fflush", Op_builtin, LEX_BUILTIN, A(0)|A(1), do_fflush, 0}, +{"for", Op_K_for, LEX_FOR, BREAK|CONTINUE, 0, 0}, +{"func", Op_func, LEX_FUNCTION, NOT_POSIX|NOT_OLD, 0, 0}, +{"function",Op_func, LEX_FUNCTION, NOT_OLD, 0, 0}, +{"gensub", Op_sub_builtin, LEX_BUILTIN, GAWKX|A(3)|A(4), 0, 0}, +{"getline", Op_K_getline_redir, LEX_GETLINE, NOT_OLD, 0, 0}, +{"gsub", Op_sub_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), 0, 0}, +{"if", Op_K_if, LEX_IF, 0, 0, 0}, +{"in", Op_symbol, LEX_IN, 0, 0, 0}, +{"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)}, +#ifdef SUPPLY_INTDIV +{"intdiv0", Op_builtin, LEX_BUILTIN, GAWKX|A(3), do_intdiv, MPF(intdiv)}, +#endif +{"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)|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)}, +{"patsplit", Op_builtin, LEX_BUILTIN, GAWKX|A(2)|A(3)|A(4), do_patsplit, 0}, +{"print", Op_K_print, LEX_PRINT, 0, 0, 0}, +{"printf", Op_K_printf, LEX_PRINTF, 0, 0, 0}, +{"rand", Op_builtin, LEX_BUILTIN, NOT_OLD|A(0), do_rand, MPF(rand)}, +{"return", Op_K_return, LEX_RETURN, NOT_OLD, 0, 0}, +{"rshift", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_rshift, MPF(rshift)}, +{"sin", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_sin, MPF(sin)}, +{"split", Op_builtin, LEX_BUILTIN, A(2)|A(3)|A(4), do_split, 0}, +{"sprintf", Op_builtin, LEX_BUILTIN, 0, do_sprintf, 0}, +{"sqrt", Op_builtin, LEX_BUILTIN, A(1), do_sqrt, MPF(sqrt)}, +{"srand", Op_builtin, LEX_BUILTIN, NOT_OLD|A(0)|A(1), do_srand, MPF(srand)}, +#if defined(GAWKDEBUG) || defined(ARRAYDEBUG) /* || ... */ +{"stopme", Op_builtin, LEX_BUILTIN, GAWKX|A(0)|DEBUG_USE, stopme, 0}, +#endif +{"strftime", Op_builtin, LEX_BUILTIN, GAWKX|A(0)|A(1)|A(2)|A(3), do_strftime, 0}, +{"strtonum", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_strtonum, MPF(strtonum)}, +{"sub", Op_sub_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), 0, 0}, +{"substr", Op_builtin, LEX_BUILTIN, A(2)|A(3), do_substr, 0}, +{"switch", Op_K_switch, LEX_SWITCH, GAWKX|BREAK, 0, 0}, +{"system", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_system, 0}, +{"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)}, +}; + +/* Variable containing the current shift state. */ +static mbstate_t cur_mbstate; +/* Ring buffer containing current characters. */ +#define MAX_CHAR_IN_RING_BUFFER 8 +#define RING_BUFFER_SIZE (MAX_CHAR_IN_RING_BUFFER * MB_LEN_MAX) +static char cur_char_ring[RING_BUFFER_SIZE]; +/* Index for ring buffers. */ +static int cur_ring_idx; +/* This macro means that last nextc() return a singlebyte character + or 1st byte of a multibyte character. */ +#define nextc_is_1stbyte (cur_char_ring[cur_ring_idx] == 1) + +/* getfname --- return name of a builtin function (for pretty printing) */ + +const char * +getfname(NODE *(*fptr)(int)) +{ + int i, j; + + j = sizeof(tokentab) / sizeof(tokentab[0]); + /* linear search, no other way to do it */ + for (i = 0; i < j; i++) + if (tokentab[i].ptr == fptr || tokentab[i].ptr2 == fptr) + return tokentab[i].operator; + + return NULL; +} + +/* negate_num --- negate a number in NODE */ + +void +negate_num(NODE *n) +{ +#ifdef HAVE_MPFR + int tval = 0; +#endif + + add_sign_to_num(n, '-'); + + if (! is_mpg_number(n)) { + n->numbr = -n->numbr; + return; + } + +#ifdef HAVE_MPFR + if (is_mpg_integer(n)) { + if (! iszero(n)) { + mpz_neg(n->mpg_i, n->mpg_i); + return; + } + + /* + * 0 --> -0 conversion. Requires turning the MPG integer + * into an MPFR float. + */ + + mpz_clear(n->mpg_i); /* release the integer storage */ + + /* Convert and fall through. */ + tval = mpfr_set_d(n->mpg_numbr, 0.0, ROUND_MODE); + IEEE_FMT(n->mpg_numbr, tval); + n->flags &= ~MPZN; + n->flags |= MPFN; + } + + /* mpfr float case */ + tval = mpfr_neg(n->mpg_numbr, n->mpg_numbr, ROUND_MODE); + IEEE_FMT(n->mpg_numbr, tval); +#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 +print_included_from() +{ + int saveline, line; + SRCFILE *s; + + /* suppress current file name, line # from `.. included from ..' msgs */ + saveline = sourceline; + sourceline = 0; + + for (s = sourcefile; s != NULL && s->stype == SRC_INC; ) { + s = s->next; + if (s == NULL || s->fd <= INVALID_HANDLE) + continue; + line = s->srclines; + + /* if last token is NEWLINE, line number is off by 1. */ + if (s->lasttok == NEWLINE) + line--; + msg("%s %s:%d%c", + s->prev == sourcefile ? "In file included from" + : " from", + (s->stype == SRC_INC || + s->stype == SRC_FILE) ? s->src : "cmd. line", + line, + s->stype == SRC_INC ? ',' : ':' + ); + } + sourceline = saveline; +} + +/* warning_ln --- print a warning message with location */ + +static void +warning_ln(int line, const char *mesg, ...) +{ + va_list args; + int saveline; + + saveline = sourceline; + sourceline = line; + print_included_from(); + va_start(args, mesg); + err(false, _("warning: "), mesg, args); + va_end(args); + sourceline = saveline; +} + +/* lintwarn_ln --- print a lint warning and location */ + +static void +lintwarn_ln(int line, const char *mesg, ...) +{ + va_list args; + int saveline; + + saveline = sourceline; + sourceline = line; + print_included_from(); + va_start(args, mesg); + if (lintfunc == r_fatal) + err(true, _("fatal: "), mesg, args); + else + err(false, _("warning: "), mesg, args); + va_end(args); + sourceline = saveline; + if (lintfunc == r_fatal) + gawk_exit(EXIT_FATAL); +} + +/* error_ln --- print an error message and location */ + +static void +error_ln(int line, const char *m, ...) +{ + va_list args; + int saveline; + + saveline = sourceline; + sourceline = line; + print_included_from(); + errcount++; + va_start(args, m); + err(false, "error: ", m, args); + va_end(args); + sourceline = saveline; +} + +/* yyerror --- print a syntax error message, show where */ + +static void +yyerror(const char *m, ...) +{ + va_list args; + const char *mesg = NULL; + char *bp, *cp; + char *scan; + char *buf; + int count; + static char end_of_file_line[] = "(END OF FILE)"; + + print_included_from(); + + errcount++; + /* Find the current line in the input file */ + if (lexptr && lexeme) { + if (thisline == NULL) { + cp = lexeme; + if (*cp == '\n') { + if (cp > lexptr_begin) + cp--; + mesg = _("unexpected newline or end of string"); + } + for (; cp != lexptr_begin && *cp != '\n'; --cp) + continue; + if (*cp == '\n') + cp++; + thisline = cp; + } + /* NL isn't guaranteed */ + bp = lexeme; + if (bp < thisline) + bp = thisline + 1; + while (bp < lexend && *bp && *bp != '\n') + bp++; + } else { + thisline = end_of_file_line; + bp = thisline + strlen(thisline); + } + + msg("%.*s", (int) (bp - thisline), thisline); + + va_start(args, m); + if (mesg == NULL) + mesg = m; + + count = strlen(mesg) + 1; + if (lexptr != NULL) + count += (lexeme - thisline) + 2; + ezalloc(buf, char *, count+1, "yyerror"); + + bp = buf; + + if (lexptr != NULL) { + scan = thisline; + while (scan < lexeme) + if (*scan++ == '\t') + *bp++ = '\t'; + else + *bp++ = ' '; + *bp++ = '^'; + *bp++ = ' '; + } + strcpy(bp, mesg); + err(false, "", buf, args); + va_end(args); + efree(buf); +} + +/* mk_program --- create a single list of instructions */ + +static INSTRUCTION * +mk_program() +{ + INSTRUCTION *cp, *tmp; + +#define begin_block rule_block[BEGIN] +#define end_block rule_block[END] +#define prog_block rule_block[Rule] +#define beginfile_block rule_block[BEGINFILE] +#define endfile_block rule_block[ENDFILE] + + if (end_block == NULL) + end_block = list_create(ip_end); + else + (void) list_prepend(end_block, ip_end); + + if (! in_main_context()) { + if (begin_block != NULL && prog_block != NULL) + cp = list_merge(begin_block, prog_block); + else + cp = (begin_block != NULL) ? begin_block : prog_block; + + if (cp != NULL) + (void) list_merge(cp, end_block); + else + cp = end_block; + + (void) list_append(cp, instruction(Op_stop)); + goto out; + } + + if (endfile_block == NULL) + endfile_block = list_create(ip_endfile); + else { + ip_rec->has_endfile = true; + (void) list_prepend(endfile_block, ip_endfile); + } + + if (beginfile_block == NULL) + beginfile_block = list_create(ip_beginfile); + else + (void) list_prepend(beginfile_block, ip_beginfile); + + if (prog_block == NULL) { + if (end_block->nexti == end_block->lasti + && beginfile_block->nexti == beginfile_block->lasti + && endfile_block->nexti == endfile_block->lasti + ) { + /* no pattern-action and (real) end, beginfile or endfile blocks */ + bcfree(ip_rec); + bcfree(ip_newfile); + ip_rec = ip_newfile = NULL; + + list_append(beginfile_block, instruction(Op_after_beginfile)); + (void) list_append(endfile_block, instruction(Op_after_endfile)); + + if (begin_block == NULL) /* no program at all */ + 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)); + + /* append beginfile_block and endfile_block for sole use + * in getline without redirection (Op_K_getline). + */ + + (void) list_merge(cp, beginfile_block); + (void) list_merge(cp, endfile_block); + + goto out; + + } else { + /* install a do-nothing prog block */ + prog_block = list_create(instruction(Op_no_op)); + } + } + + (void) list_append(endfile_block, instruction(Op_after_endfile)); + (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); + (void) list_prepend(cp, ip_newfile); + (void) list_merge(cp, endfile_block); + (void) list_merge(cp, end_block); + 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)); + +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 +} + +/* parse_program --- read in the program and convert into a list of instructions */ + +int +parse_program(INSTRUCTION **pcode) +{ + int ret; + + /* pre-create non-local jump targets + * ip_end (Op_no_op) -- used as jump target for `exit' + * outside an END block. + */ + ip_end = instruction(Op_no_op); + + if (! in_main_context()) + ip_newfile = ip_rec = ip_atexit = ip_beginfile = ip_endfile = NULL; + else { + ip_endfile = 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; + ip_newfile->target_endfile = ip_endfile; + (ip_newfile + 1)->target_get_record = ip_rec; + ip_rec->target_newfile = ip_newfile; + ip_atexit = instruction(Op_atexit); /* target for `exit' in END block */ + } + + for (sourcefile = srcfiles->next; sourcefile->stype == SRC_EXTLIB; + sourcefile = sourcefile->next) + ; + + lexeof = false; + lexptr = NULL; + lasttok = 0; + memset(rule_block, 0, sizeof(ruletab) * sizeof(INSTRUCTION *)); + errcount = 0; + tok = tokstart != NULL ? tokstart : tokexpand(); + + ret = yyparse(); + *pcode = mk_program(); + + /* avoid false source indications */ + source = NULL; + sourceline = 0; + if (ret == 0) /* avoid spurious warning if parser aborted with YYABORT */ + check_funcs(); + + if (do_posix && ! check_param_names()) + errcount++; + + if (args_array == NULL) + emalloc(args_array, NODE **, (max_args + 2) * sizeof(NODE *), "parse_program"); + else + erealloc(args_array, NODE **, (max_args + 2) * sizeof(NODE *), "parse_program"); + + return (ret || errcount); +} + +/* free_srcfile --- free a SRCFILE struct */ + +void +free_srcfile(SRCFILE *thisfile) +{ + efree(thisfile->src); + efree(thisfile); +} + +/* do_add_srcfile --- add one item to srcfiles */ + +static SRCFILE * +do_add_srcfile(enum srctype stype, char *src, char *path, SRCFILE *thisfile) +{ + SRCFILE *s; + + ezalloc(s, SRCFILE *, sizeof(SRCFILE), "do_add_srcfile"); + s->src = estrdup(src, strlen(src)); + s->fullpath = path; + s->stype = stype; + s->fd = INVALID_HANDLE; + s->next = thisfile; + s->prev = thisfile->prev; + thisfile->prev->next = s; + thisfile->prev = s; + return s; +} + +/* add_srcfile --- add one item to srcfiles after checking if + * a source file exists and not already in list. + */ + +SRCFILE * +add_srcfile(enum srctype stype, char *src, SRCFILE *thisfile, bool *already_included, int *errcode) +{ + SRCFILE *s; + struct stat sbuf; + char *path; + int errno_val = 0; + + if (already_included) + *already_included = false; + if (errcode) + *errcode = 0; + if (stype == SRC_CMDLINE || stype == SRC_STDIN) + return do_add_srcfile(stype, src, NULL, thisfile); + + path = find_source(src, & sbuf, & errno_val, stype == SRC_EXTLIB); + if (path == NULL) { + if (errcode) { + *errcode = errno_val; + return NULL; + } + /* use full messages to ease translation */ + fatal(stype != SRC_EXTLIB + ? _("can't open source file `%s' for reading (%s)") + : _("can't open shared library `%s' for reading (%s)"), + src, + errno_val ? strerror(errno_val) : _("reason unknown")); + } + + /* N.B. We do not eliminate duplicate SRC_FILE (-f) programs. */ + for (s = srcfiles->next; s != srcfiles; s = s->next) { + if ((s->stype == SRC_FILE || s->stype == SRC_INC || s->stype == SRC_EXTLIB) && files_are_same(path, s)) { + if (stype == SRC_INC || stype == SRC_EXTLIB) { + /* eliminate duplicates */ + if ((stype == SRC_INC) && (s->stype == SRC_FILE)) + fatal(_("can't include `%s' and use it as a program file"), src); + + if (do_lint) { + int line = sourceline; + /* Kludge: the line number may be off for `@include file'. + * Since, this function is also used for '-f file' in main.c, + * sourceline > 1 check ensures that the call is at + * parse time. + */ + if (sourceline > 1 && lasttok == NEWLINE) + line--; + lintwarn_ln(line, + stype != SRC_EXTLIB + ? _("already included source file `%s'") + : _("already loaded shared library `%s'"), + src); + } + efree(path); + if (already_included) + *already_included = true; + return NULL; + } else { + /* 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 + * they must be of homogeneous type */ + break; + } + } + } + + s = do_add_srcfile(stype, src, path, thisfile); + s->sbuf = sbuf; + s->mtime = sbuf.st_mtime; + return s; +} + +/* include_source --- read program from source included using `@include' */ + +static int +include_source(INSTRUCTION *file) +{ + SRCFILE *s; + char *src = file->lextok; + int errcode; + bool already_included; + + if (do_traditional || do_posix) { + error_ln(file->source_line, _("@include is a gawk extension")); + return -1; + } + + if (strlen(src) == 0) { + if (do_lint) + lintwarn_ln(file->source_line, _("empty filename after @include")); + return 0; + } + + s = add_srcfile(SRC_INC, src, sourcefile, &already_included, &errcode); + if (s == NULL) { + if (already_included) + return 0; + error_ln(file->source_line, + _("can't open source file `%s' for reading (%s)"), + src, errcode ? strerror(errcode) : _("reason unknown")); + return -1; + } + + /* save scanner state for the current sourcefile */ + sourcefile->srclines = sourceline; + sourcefile->lexptr = lexptr; + sourcefile->lexend = lexend; + sourcefile->lexptr_begin = lexptr_begin; + sourcefile->lexeme = lexeme; + sourcefile->lasttok = lasttok; + + /* included file becomes the current source */ + sourcefile = s; + lexptr = NULL; + sourceline = 0; + source = NULL; + lasttok = 0; + lexeof = false; + eof_warned = false; + return 0; +} + +/* load_library --- load a shared library */ + +static int +load_library(INSTRUCTION *file) +{ + SRCFILE *s; + char *src = file->lextok; + int errcode; + bool already_included; + + if (do_traditional || do_posix) { + error_ln(file->source_line, _("@load is a gawk extension")); + return -1; + } + + if (strlen(src) == 0) { + if (do_lint) + lintwarn_ln(file->source_line, _("empty filename after @load")); + return 0; + } + + s = add_srcfile(SRC_EXTLIB, src, sourcefile, &already_included, &errcode); + if (s == NULL) { + if (already_included) + return 0; + error_ln(file->source_line, + _("can't open shared library `%s' for reading (%s)"), + src, errcode ? strerror(errcode) : _("reason unknown")); + return -1; + } + + load_ext(s->fullpath); + return 0; +} + +/* next_sourcefile --- read program from the next source in srcfiles */ + +static void +next_sourcefile() +{ + static int (*closefunc)(int fd) = NULL; + + if (closefunc == NULL) { + char *cp = getenv("AWKREADFUNC"); + + /* If necessary, one day, test value for different functions. */ + if (cp == NULL) + closefunc = close; + else + closefunc = one_line_close; + } + + /* + * This won't be true if there's an invalid character in + * the source file or source string (e.g., user typo). + * Previous versions of gawk did not core dump in such a + * case. + * + * assert(lexeof == true); + */ + + lexeof = false; + eof_warned = false; + sourcefile->srclines = sourceline; /* total no of lines in current file */ + if (sourcefile->fd > INVALID_HANDLE) { + if (sourcefile->fd != fileno(stdin)) /* safety */ + (*closefunc)(sourcefile->fd); + sourcefile->fd = INVALID_HANDLE; + } + if (sourcefile->buf != NULL) { + efree(sourcefile->buf); + sourcefile->buf = NULL; + sourcefile->lexptr_begin = NULL; + } + + while ((sourcefile = sourcefile->next) != NULL) { + if (sourcefile == srcfiles) + return; + if (sourcefile->stype != SRC_EXTLIB) + break; + } + + if (sourcefile->lexptr_begin != NULL) { + /* resume reading from already opened file (postponed to process '@include') */ + lexptr = sourcefile->lexptr; + lexend = sourcefile->lexend; + lasttok = sourcefile->lasttok; + lexptr_begin = sourcefile->lexptr_begin; + lexeme = sourcefile->lexeme; + sourceline = sourcefile->srclines; + source = sourcefile->src; + } else { + lexptr = NULL; + sourceline = 0; + source = NULL; + lasttok = 0; + } +} + +/* get_src_buf --- read the next buffer of source program */ + +static char * +get_src_buf() +{ + int n; + char *scan; + bool newfile; + int savelen; + struct stat sbuf; + + /* + * No argument prototype on readfunc on purpose, + * avoids problems with some ancient systems where + * the types of arguments to read() aren't up to date. + */ + static ssize_t (*readfunc)() = 0; + + if (readfunc == NULL) { + char *cp = getenv("AWKREADFUNC"); + + /* If necessary, one day, test value for different functions. */ + if (cp == NULL) + /* + * cast is to remove warnings on systems with + * different return types for read. + */ + readfunc = ( ssize_t(*)() ) read; + else + readfunc = read_one_line; + } + + newfile = false; + if (sourcefile == srcfiles) + return NULL; + + if (sourcefile->stype == SRC_CMDLINE) { + if (sourcefile->bufsize == 0) { + sourcefile->bufsize = strlen(sourcefile->src); + lexptr = lexptr_begin = lexeme = sourcefile->src; + lexend = lexptr + sourcefile->bufsize; + sourceline = 1; + if (sourcefile->bufsize == 0) { + /* + * Yet Another Special case: + * gawk '' /path/name + * Sigh. + */ + static bool warned = false; + + if (do_lint && ! warned) { + warned = true; + lintwarn(_("empty program text on command line")); + } + lexeof = true; + } + } else if (sourcefile->buf == NULL && *(lexptr-1) != '\n') { + /* + * The following goop is to ensure that the source + * ends with a newline and that the entire current + * line is available for error messages. + */ + int offset; + char *buf; + + offset = lexptr - lexeme; + for (scan = lexeme; scan > lexptr_begin; scan--) + if (*scan == '\n') { + scan++; + break; + } + savelen = lexptr - scan; + emalloc(buf, char *, savelen + 1, "get_src_buf"); + memcpy(buf, scan, savelen); + thisline = buf; + lexptr = buf + savelen; + *lexptr = '\n'; + lexeme = lexptr - offset; + lexptr_begin = buf; + lexend = lexptr + 1; + sourcefile->buf = buf; + } else + lexeof = true; + return lexptr; + } + + if (sourcefile->fd <= INVALID_HANDLE) { + int fd; + int l; + + source = sourcefile->src; + if (source == NULL) + return NULL; + fd = srcopen(sourcefile); + if (fd <= INVALID_HANDLE) { + char *in; + + /* suppress file name and line no. in error mesg */ + in = source; + source = NULL; + error(_("can't open source file `%s' for reading (%s)"), + in, strerror(errno)); + errcount++; + lexeof = true; + return sourcefile->src; + } + + sourcefile->fd = fd; + l = optimal_bufsize(fd, &sbuf); + /* + * Make sure that something silly like + * AWKBUFSIZE=8 make check + * works ok. + */ +#define A_DECENT_BUFFER_SIZE 128 + if (l < A_DECENT_BUFFER_SIZE) + l = A_DECENT_BUFFER_SIZE; +#undef A_DECENT_BUFFER_SIZE + sourcefile->bufsize = l; + newfile = true; + emalloc(sourcefile->buf, char *, sourcefile->bufsize, "get_src_buf"); + lexptr = lexptr_begin = lexeme = sourcefile->buf; + savelen = 0; + sourceline = 1; + thisline = NULL; + } else { + /* + * Here, we retain the current source line in the beginning of the buffer. + */ + int offset; + for (scan = lexeme; scan > lexptr_begin; scan--) + if (*scan == '\n') { + scan++; + break; + } + + savelen = lexptr - scan; + offset = lexptr - lexeme; + + if (savelen > 0) { + /* + * Need to make sure we have room left for reading new text; + * grow the buffer (by doubling, an arbitrary choice), if the retained line + * takes up more than a certain percentage (50%, again an arbitrary figure) + * of the available space. + */ + + if (savelen > sourcefile->bufsize / 2) { /* long line or token */ + sourcefile->bufsize *= 2; + erealloc(sourcefile->buf, char *, sourcefile->bufsize, "get_src_buf"); + scan = sourcefile->buf + (scan - lexptr_begin); + lexptr_begin = sourcefile->buf; + } + + thisline = lexptr_begin; + memmove(thisline, scan, savelen); + lexptr = thisline + savelen; + lexeme = lexptr - offset; + } else { + savelen = 0; + lexptr = lexeme = lexptr_begin; + thisline = NULL; + } + } + + n = (*readfunc)(sourcefile->fd, lexptr, sourcefile->bufsize - savelen); + if (n == -1) { + error(_("can't read sourcefile `%s' (%s)"), + source, strerror(errno)); + errcount++; + lexeof = true; + } else { + lexend = lexptr + n; + if (n == 0) { + static bool warned = false; + if (do_lint && newfile && ! warned) { + warned = true; + sourceline = 0; + lintwarn(_("source file `%s' is empty"), source); + } + lexeof = true; + } + } + return sourcefile->buf; +} + +/* tokadd --- add a character to the token buffer */ + +#define tokadd(x) (*tok++ = (x), tok == tokend ? tokexpand() : tok) + +/* tokexpand --- grow the token buffer */ + +static char * +tokexpand() +{ + static int toksize; + int tokoffset; + + if (tokstart != NULL) { + tokoffset = tok - tokstart; + toksize *= 2; + erealloc(tokstart, char *, toksize, "tokexpand"); + tok = tokstart + tokoffset; + } else { + toksize = 60; + emalloc(tokstart, char *, toksize, "tokexpand"); + tok = tokstart; + } + tokend = tokstart + toksize; + return tok; +} + +/* check_bad_char --- fatal if c isn't allowed in gawk source code */ + +/* + * The error message was inspired by someone who decided to put + * a physical \0 byte into the source code to see what would + * happen and then filed a bug report about it. Sigh. + */ + +static void +check_bad_char(int c) +{ + /* allow escapes. needed for autoconf. bleah. */ + switch (c) { + case '\a': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + return; + default: + break; + } + + if (iscntrl(c) && ! isspace(c)) + fatal(_("PEBKAC error: invalid character '\\%03o' in source code"), c & 0xFF); +} + +/* nextc --- get the next input character */ + +static int +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; + return END_SRC; + } + + /* Update the buffer index. */ + cur_ring_idx = (cur_ring_idx == RING_BUFFER_SIZE - 1)? 0 : + cur_ring_idx + 1; + + /* Did we already check the current character? */ + if (cur_char_ring[cur_ring_idx] == 0) { + /* No, we need to check the next character on the buffer. */ + int idx, work_ring_idx = cur_ring_idx; + mbstate_t tmp_state; + size_t mbclen; + + for (idx = 0; lexptr + idx < lexend; idx++) { + tmp_state = cur_mbstate; + mbclen = mbrlen(lexptr, idx + 1, &tmp_state); + + if (mbclen == 1 || mbclen == (size_t)-1 || mbclen == 0) { + /* It is a singlebyte character, non-complete multibyte + character or EOF. We treat it as a singlebyte + character. */ + cur_char_ring[work_ring_idx] = 1; + break; + } else if (mbclen == (size_t)-2) { + /* It is not a complete multibyte character. */ + cur_char_ring[work_ring_idx] = idx + 1; + } else { + /* mbclen > 1 */ + cur_char_ring[work_ring_idx] = mbclen; + break; + } + work_ring_idx = (work_ring_idx == RING_BUFFER_SIZE - 1)? + 0 : work_ring_idx + 1; + } + cur_mbstate = tmp_state; + + /* Put a mark on the position on which we write next character. */ + work_ring_idx = (work_ring_idx == RING_BUFFER_SIZE - 1)? + 0 : work_ring_idx + 1; + cur_char_ring[work_ring_idx] = 0; + } + if (check_for_bad || *lexptr == '\0') + check_bad_char(*lexptr); + + 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); + return ((int) (unsigned char) *lexptr++); + } + } while (get_src_buf()); + return END_SRC; + } +} + +/* pushback --- push a character back on the input */ + +static inline void +pushback(void) +{ + if (gawk_mb_cur_max > 1) + cur_ring_idx = (cur_ring_idx == 0)? RING_BUFFER_SIZE - 1 : + cur_ring_idx - 1; + (! 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 : */ + +static void +allow_newline(void) +{ + int c; + + for (;;) { + c = nextc(true); + if (c == END_FILE) { + pushback(); + break; + } + if (c == '#') { + 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; + } + } + if (c == '\n') + sourceline++; + if (! isspace(c)) { + pushback(); + break; + } + } +} + +/* newline_eof --- return newline or EOF as needed and adjust variables */ + +/* + * This routine used to be a macro, however GCC 4.6.2 warned about + * the result of a computation not being used. Converting to a function + * removes the warnings. + */ + +static int +newline_eof() +{ + /* NB: a newline at end does not start a source line. */ + if (lasttok != NEWLINE) { + pushback(); + if (do_lint && ! eof_warned) { + lintwarn(_("source file does not end in newline")); + eof_warned = true; + } + sourceline++; + return NEWLINE; + } + + sourceline--; + eof_warned = false; + return LEX_EOF; +} + +/* yylex --- Read the input and turn it into tokens. */ + +static int +#ifdef USE_EBCDIC +yylex_ebcdic(void) +#else +yylex(void) +#endif +{ + int c; + bool seen_e = false; /* These are for numbers */ + bool seen_point = false; + bool esc_seen; /* for literal strings */ + int mid; + int base; + static bool did_newline = false; + char *tokkey; + bool inhex = false; + bool intlstr = false; + AWKNUM d; + bool collecting_typed_regexp = false; + +#define GET_INSTRUCTION(op) bcalloc(op, 1, sourceline) + +#define NEWLINE_EOF newline_eof() + + yylval = (INSTRUCTION *) NULL; + if (lasttok == SUBSCRIPT) { + lasttok = 0; + return SUBSCRIPT; + } + + if (lasttok == LEX_EOF) /* error earlier in current source, must give up !! */ + return 0; + + c = nextc(! want_regexp); + if (c == END_SRC) + return 0; + if (c == END_FILE) + return lasttok = NEWLINE_EOF; + pushback(); + +#if defined __EMX__ + /* + * added for OS/2's extproc feature of cmd.exe + * (like #! in BSD sh) + */ + if (strncasecmp(lexptr, "extproc ", 8) == 0) { + while (*lexptr && *lexptr != '\n') + lexptr++; + } +#endif + + lexeme = lexptr; + thisline = NULL; + +collect_regexp: + if (want_regexp) { + int in_brack = 0; /* count brackets, [[:alnum:]] allowed */ + int b_index = -1; + int cur_index = 0; + + /* + * Here is what's ok with brackets: + * + * [..[..] []] [^]] [.../...] + * [...\[...] [...\]...] [...\/...] + * + * (Remember that all of the above are inside /.../) + * + * The code for \ handles \[, \] and \/. + * + * Otherwise, track the first open [ position, and if + * an embedded ] occurs, allow it to pass through + * if it's right after the first [ or after [^. + * + * Whew! + */ + + want_regexp = false; + tok = tokstart; + for (;;) { + c = nextc(false); + + cur_index = tok - tokstart; + if (gawk_mb_cur_max == 1 || nextc_is_1stbyte) switch (c) { + case '[': + if (nextc(false) == ':' || in_brack == 0) { + in_brack++; + if (in_brack == 1) + b_index = tok - tokstart; + } + pushback(); + break; + case ']': + if (in_brack > 0 + && (cur_index == b_index + 1 + || (cur_index == b_index + 2 && tok[-1] == '^'))) + ; /* do nothing */ + else { + in_brack--; + if (in_brack == 0) + b_index = -1; + } + break; + case '\\': + if ((c = nextc(false)) == END_FILE) { + pushback(); + yyerror(_("unterminated regexp ends with `\\' at end of file")); + goto end_regexp; /* kludge */ + } + if (c == '\r') /* allow MS-DOS files. bleah */ + c = nextc(true); + if (c == '\n') { + sourceline++; + continue; + } else { + tokadd('\\'); + tokadd(c); + continue; + } + break; + case '/': /* end of the regexp */ + if (in_brack > 0) + break; +end_regexp: + yylval = GET_INSTRUCTION(Op_token); + yylval->lextok = estrdup(tokstart, tok - tokstart); + if (do_lint) { + int peek = nextc(true); + + pushback(); + if (peek == 'i' || peek == 's') { + if (source) + lintwarn( + _("%s: %d: tawk regex modifier `/.../%c' doesn't work in gawk"), + source, sourceline, peek); + else + lintwarn( + _("tawk regex modifier `/.../%c' doesn't work in gawk"), + peek); + } + } + if (collecting_typed_regexp) { + collecting_typed_regexp = false; + lasttok = TYPED_REGEXP; + } else + lasttok = REGEXP; + + return lasttok; + case '\n': + pushback(); + yyerror(_("unterminated regexp")); + goto end_regexp; /* kludge */ + case END_FILE: + pushback(); + yyerror(_("unterminated regexp at end of file")); + goto end_regexp; /* kludge */ + } + tokadd(c); + } + } +retry: + + /* skipping \r is a hack, but windows is just too pervasive. sigh. */ + while ((c = nextc(true)) == ' ' || c == '\t' || c == '\r') + continue; + + lexeme = lexptr ? lexptr - 1 : lexptr; + thisline = NULL; + tok = tokstart; + + if (gawk_mb_cur_max == 1 || nextc_is_1stbyte) + switch (c) { + case END_SRC: + return 0; + + case END_FILE: + return lasttok = NEWLINE_EOF; + + case '\n': + sourceline++; + return lasttok = NEWLINE; + + case '#': /* it's a comment */ + 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 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. + */ + if (! do_traditional) { + /* strip trailing white-space and/or comment */ + while ((c = nextc(true)) == ' ' || c == '\t' || c == '\r') + continue; + if (c == '#') { + static bool warned = false; + + if (do_lint && ! warned) { + warned = true; + lintwarn( + _("use of `\\ #...' line continuation is not portable")); + } + if (do_pretty_print && ! do_profile) + c = get_comment(EOL_COMMENT); + else { + while ((c = nextc(false)) != '\n') + if (c == END_FILE) + break; + } + } + pushback(); + } +#endif /* RELAXED_CONTINUATION */ + c = nextc(true); + if (c == '\r') /* allow MS-DOS files. bleah */ + c = nextc(true); + if (c == '\n') { + sourceline++; + goto retry; + } else { + yyerror(_("backslash not last character on line")); + return lasttok = LEX_EOF; + } + break; + + case ':': + case '?': + yylval = GET_INSTRUCTION(Op_cond_exp); + if (! do_posix) + allow_newline(); + return lasttok = c; + + /* + * in_parens is undefined unless we are parsing a print + * statement (in_print), but why bother with a check? + */ + case ')': + in_parens--; + return lasttok = c; + + case '(': + in_parens++; + return lasttok = c; + case '$': + yylval = GET_INSTRUCTION(Op_field_spec); + return lasttok = c; + case '{': + if (++in_braces == 1) + firstline = sourceline; + case ';': + case ',': + case '[': + return lasttok = c; + case ']': + c = nextc(true); + pushback(); + if (c == '[') { + if (do_traditional) + fatal(_("multidimensional arrays are a gawk extension")); + if (do_lint) + lintwarn(_("multidimensional arrays are a gawk extension")); + yylval = GET_INSTRUCTION(Op_sub_array); + lasttok = ']'; + } else { + yylval = GET_INSTRUCTION(Op_subscript); + lasttok = SUBSCRIPT; /* end of subscripts */ + } + return ']'; + + case '*': + if ((c = nextc(true)) == '=') { + yylval = GET_INSTRUCTION(Op_assign_times); + return lasttok = ASSIGNOP; + } else if (do_posix) { + pushback(); + yylval = GET_INSTRUCTION(Op_times); + return lasttok = '*'; + } else if (c == '*') { + /* make ** and **= aliases for ^ and ^= */ + static bool did_warn_op = false, did_warn_assgn = false; + + if (nextc(true) == '=') { + if (! did_warn_assgn) { + did_warn_assgn = true; + if (do_lint) + lintwarn(_("POSIX does not allow operator `**='")); + if (do_lint_old) + warning(_("old awk does not support operator `**='")); + } + yylval = GET_INSTRUCTION(Op_assign_exp); + return ASSIGNOP; + } else { + pushback(); + if (! did_warn_op) { + did_warn_op = true; + if (do_lint) + lintwarn(_("POSIX does not allow operator `**'")); + if (do_lint_old) + warning(_("old awk does not support operator `**'")); + } + yylval = GET_INSTRUCTION(Op_exp); + return lasttok = '^'; + } + } + pushback(); + yylval = GET_INSTRUCTION(Op_times); + return lasttok = '*'; + + case '/': + if (nextc(false) == '=') { + pushback(); + return lasttok = SLASH_BEFORE_EQUAL; + } + pushback(); + yylval = GET_INSTRUCTION(Op_quotient); + return lasttok = '/'; + + case '%': + if (nextc(true) == '=') { + yylval = GET_INSTRUCTION(Op_assign_mod); + return lasttok = ASSIGNOP; + } + pushback(); + yylval = GET_INSTRUCTION(Op_mod); + return lasttok = '%'; + + case '^': + { + static bool did_warn_op = false, did_warn_assgn = false; + + if (nextc(true) == '=') { + if (do_lint_old && ! did_warn_assgn) { + did_warn_assgn = true; + warning(_("operator `^=' is not supported in old awk")); + } + yylval = GET_INSTRUCTION(Op_assign_exp); + return lasttok = ASSIGNOP; + } + pushback(); + if (do_lint_old && ! did_warn_op) { + did_warn_op = true; + warning(_("operator `^' is not supported in old awk")); + } + yylval = GET_INSTRUCTION(Op_exp); + return lasttok = '^'; + } + + case '+': + if ((c = nextc(true)) == '=') { + yylval = GET_INSTRUCTION(Op_assign_plus); + return lasttok = ASSIGNOP; + } + if (c == '+') { + yylval = GET_INSTRUCTION(Op_symbol); + return lasttok = INCREMENT; + } + pushback(); + yylval = GET_INSTRUCTION(Op_plus); + return lasttok = '+'; + + case '!': + if ((c = nextc(true)) == '=') { + yylval = GET_INSTRUCTION(Op_notequal); + return lasttok = RELOP; + } + if (c == '~') { + yylval = GET_INSTRUCTION(Op_nomatch); + return lasttok = MATCHOP; + } + pushback(); + yylval = GET_INSTRUCTION(Op_symbol); + return lasttok = '!'; + + case '<': + if (nextc(true) == '=') { + yylval = GET_INSTRUCTION(Op_leq); + return lasttok = RELOP; + } + yylval = GET_INSTRUCTION(Op_less); + pushback(); + return lasttok = '<'; + + case '=': + if (nextc(true) == '=') { + yylval = GET_INSTRUCTION(Op_equal); + return lasttok = RELOP; + } + yylval = GET_INSTRUCTION(Op_assign); + pushback(); + return lasttok = ASSIGN; + + case '>': + if ((c = nextc(true)) == '=') { + yylval = GET_INSTRUCTION(Op_geq); + return lasttok = RELOP; + } else if (c == '>') { + yylval = GET_INSTRUCTION(Op_symbol); + yylval->redir_type = redirect_append; + return lasttok = IO_OUT; + } + pushback(); + if (in_print && in_parens == 0) { + yylval = GET_INSTRUCTION(Op_symbol); + yylval->redir_type = redirect_output; + return lasttok = IO_OUT; + } + yylval = GET_INSTRUCTION(Op_greater); + return lasttok = '>'; + + case '~': + yylval = GET_INSTRUCTION(Op_match); + return lasttok = MATCHOP; + + case '}': + /* + * Added did newline stuff. Easier than + * hacking the grammar. + */ + if (did_newline) { + did_newline = false; + if (--in_braces == 0) + lastline = sourceline; + return lasttok = c; + } + did_newline = true; + --lexptr; /* pick up } next time */ + return lasttok = NEWLINE; + + case '"': + string: + esc_seen = false; + /* + * Allow any kind of junk in quoted string, + * so pass false to nextc(). + */ + while ((c = nextc(false)) != '"') { + if (c == '\n') { + pushback(); + yyerror(_("unterminated string")); + return lasttok = LEX_EOF; + } + if ((gawk_mb_cur_max == 1 || nextc_is_1stbyte) && + c == '\\') { + c = nextc(true); + if (c == '\r') /* allow MS-DOS files. bleah */ + c = nextc(true); + if (c == '\n') { + sourceline++; + continue; + } + esc_seen = true; + if (! want_source || c != '"') + tokadd('\\'); + } + if (c == END_FILE) { + pushback(); + yyerror(_("unterminated string")); + return lasttok = LEX_EOF; + } + tokadd(c); + } + yylval = GET_INSTRUCTION(Op_token); + if (want_source) { + 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); + if (intlstr) { + yylval->memory->flags |= INTLSTR; + intlstr = false; + if (do_intl) + dumpintlstr(yylval->memory->stptr, yylval->memory->stlen); + } + return lasttok = YSTRING; + + case '-': + if ((c = nextc(true)) == '=') { + yylval = GET_INSTRUCTION(Op_assign_minus); + return lasttok = ASSIGNOP; + } + if (c == '-') { + yylval = GET_INSTRUCTION(Op_symbol); + return lasttok = DECREMENT; + } + pushback(); + yylval = GET_INSTRUCTION(Op_minus); + return lasttok = '-'; + + case '.': + c = nextc(true); + pushback(); + if (! isdigit(c)) + return lasttok = '.'; + else + c = '.'; + /* FALL THROUGH */ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + /* It's a number */ + for (;;) { + bool gotnumber = false; + + tokadd(c); + switch (c) { + case 'x': + case 'X': + if (do_traditional) + goto done; + if (tok == tokstart + 2) { + int peek = nextc(true); + + if (isxdigit(peek)) { + inhex = true; + pushback(); /* following digit */ + } else { + pushback(); /* x or X */ + goto done; + } + } + break; + case '.': + /* period ends exponent part of floating point number */ + if (seen_point || seen_e) { + gotnumber = true; + break; + } + seen_point = true; + break; + case 'e': + case 'E': + if (inhex) + break; + if (seen_e) { + gotnumber = true; + break; + } + seen_e = true; + if ((c = nextc(true)) == '-' || c == '+') { + int c2 = nextc(true); + + if (isdigit(c2)) { + tokadd(c); + tokadd(c2); + } else { + pushback(); /* non-digit after + or - */ + pushback(); /* + or - */ + pushback(); /* e or E */ + } + } else if (! isdigit(c)) { + pushback(); /* character after e or E */ + pushback(); /* e or E */ + } else { + pushback(); /* digit */ + } + break; + case 'a': + case 'A': + case 'b': + case 'B': + case 'c': + case 'C': + case 'D': + case 'd': + case 'f': + case 'F': + if (do_traditional || ! inhex) + goto done; + /* fall through */ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + break; + default: + done: + gotnumber = true; + } + if (gotnumber) + break; + c = nextc(true); + } + pushback(); + + tokadd('\0'); + yylval = GET_INSTRUCTION(Op_push_i); + + base = 10; + if (! do_traditional) { + base = get_numbase(tokstart, strlen(tokstart)-1, false); + if (do_lint) { + if (base == 8) + lintwarn("numeric constant `%.*s' treated as octal", + (int) strlen(tokstart)-1, tokstart); + else if (base == 16) + lintwarn("numeric constant `%.*s' treated as hexadecimal", + (int) strlen(tokstart)-1, tokstart); + } + } + +#ifdef HAVE_MPFR + if (do_mpfr) { + NODE *r; + + if (! seen_point && ! seen_e) { + r = mpg_integer(); + mpg_strtoui(r->mpg_i, tokstart, strlen(tokstart), NULL, base); + errno = 0; + } else { + int tval; + r = mpg_float(); + tval = mpfr_strtofr(r->mpg_numbr, tokstart, NULL, base, ROUND_MODE); + errno = 0; + IEEE_FMT(r->mpg_numbr, tval); + } + yylval->memory = set_profile_text(r, tokstart, strlen(tokstart)-1); + return lasttok = YNUMBER; + } +#endif + if (base != 10) + d = nondec2awknum(tokstart, strlen(tokstart)-1, NULL); + else + d = atof(tokstart); + 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; + + case '&': + if ((c = nextc(true)) == '&') { + yylval = GET_INSTRUCTION(Op_and); + allow_newline(); + return lasttok = LEX_AND; + } + pushback(); + yylval = GET_INSTRUCTION(Op_symbol); + return lasttok = '&'; + + case '|': + if ((c = nextc(true)) == '|') { + yylval = GET_INSTRUCTION(Op_or); + allow_newline(); + return lasttok = LEX_OR; + } else if (! do_traditional && c == '&') { + yylval = GET_INSTRUCTION(Op_symbol); + yylval->redir_type = redirect_twoway; + return lasttok = (in_print && in_parens == 0 ? IO_OUT : IO_IN); + } + pushback(); + if (in_print && in_parens == 0) { + yylval = GET_INSTRUCTION(Op_symbol); + yylval->redir_type = redirect_pipe; + return lasttok = IO_OUT; + } else { + yylval = GET_INSTRUCTION(Op_symbol); + yylval->redir_type = redirect_pipein; + return lasttok = IO_IN; + } + } + + if (! is_letter(c)) { + yyerror(_("invalid char '%c' in expression"), c); + return lasttok = LEX_EOF; + } + + /* + * Lots of fog here. Consider: + * + * print "xyzzy"$_"foo" + * + * Without the check for ` lasttok != '$' ', this is parsed as + * + * print "xxyzz" $(_"foo") + * + * With the check, it is "correctly" parsed as three + * string concatenations. Sigh. This seems to be + * "more correct", but this is definitely one of those + * occasions where the interactions are funny. + */ + if (! do_traditional && c == '_' && lasttok != '$') { + if ((c = nextc(true)) == '"') { + intlstr = true; + goto string; + } + pushback(); + c = '_'; + } + + /* it's some type of name-type-thing. Find its length. */ + tok = tokstart; + while (c != END_FILE && is_identchar(c)) { + tokadd(c); + c = nextc(true); + } + tokadd('\0'); + pushback(); + + /* See if it is a special token. */ + if ((mid = check_special(tokstart)) >= 0) { + static int warntab[sizeof(tokentab) / sizeof(tokentab[0])]; + int class = tokentab[mid].class; + + if ((class == LEX_INCLUDE || class == LEX_LOAD || class == LEX_EVAL) + && lasttok != '@') + goto out; + + /* 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"), + tokentab[mid].operator); + warntab[mid] |= GAWKX; + } + if ((tokentab[mid].flags & NOT_POSIX) != 0 && (warntab[mid] & NOT_POSIX) == 0) { + lintwarn(_("POSIX does not allow `%s'"), + tokentab[mid].operator); + warntab[mid] |= NOT_POSIX; + } + } + if (do_lint_old && (tokentab[mid].flags & NOT_OLD) != 0 + && (warntab[mid] & NOT_OLD) == 0 + ) { + warning(_("`%s' is not supported in old awk"), + tokentab[mid].operator); + warntab[mid] |= NOT_OLD; + } + + if ((tokentab[mid].flags & BREAK) != 0) + break_allowed++; + if ((tokentab[mid].flags & CONTINUE) != 0) + continue_allowed++; + + switch (class) { + case LEX_INCLUDE: + case LEX_LOAD: + want_source = true; + break; + case LEX_EVAL: + if (in_main_context()) + goto out; + emalloc(tokkey, char *, tok - tokstart + 1, "yylex"); + tokkey[0] = '@'; + memcpy(tokkey + 1, tokstart, tok - tokstart); + yylval = GET_INSTRUCTION(Op_token); + yylval->lextok = tokkey; + break; + + case LEX_FUNCTION: + case LEX_BEGIN: + case LEX_END: + case LEX_BEGINFILE: + case LEX_ENDFILE: + yylval = bcalloc(tokentab[mid].value, 3, sourceline); + break; + + case LEX_FOR: + case LEX_WHILE: + case LEX_DO: + case LEX_SWITCH: + if (! do_pretty_print) + return lasttok = class; + /* fall through */ + case LEX_CASE: + yylval = bcalloc(tokentab[mid].value, 2, sourceline); + break; + + /* + * These must be checked here, due to the LALR nature of the parser, + * the rules for continue and break may not be reduced until after + * a token that increments the xxx_allowed varibles is seen. Bleah. + */ + case LEX_CONTINUE: + if (! continue_allowed) { + error_ln(sourceline, + _("`continue' is not allowed outside a loop")); + errcount++; + } + goto make_instruction; + + case LEX_BREAK: + if (! break_allowed) { + error_ln(sourceline, + _("`break' is not allowed outside a loop or switch")); + errcount++; + } + goto make_instruction; + + default: +make_instruction: + yylval = GET_INSTRUCTION(tokentab[mid].value); + if (class == LEX_BUILTIN || class == LEX_LENGTH) + yylval->builtin_idx = mid; + break; + } + return lasttok = class; + } +out: + tokkey = estrdup(tokstart, tok - tokstart); + if (*lexptr == '(') { + yylval = bcalloc(Op_token, 2, sourceline); + yylval->lextok = tokkey; + return lasttok = FUNC_CALL; + } else { + static bool goto_warned = false; + + yylval = GET_INSTRUCTION(Op_token); + yylval->lextok = tokkey; + +#define SMART_ALECK 1 + if (SMART_ALECK && do_lint + && ! goto_warned && strcasecmp(tokkey, "goto") == 0) { + goto_warned = true; + lintwarn(_("`goto' considered harmful!\n")); + } + return lasttok = NAME; + } + +#undef GET_INSTRUCTION +#undef NEWLINE_EOF +} + +/* It's EBCDIC in a Bison grammar, run for the hills! + + Or, convert single-character tokens coming out of yylex() from EBCDIC to + ASCII values on-the-fly so that the parse tables need not be regenerated + for EBCDIC systems. */ +#ifdef USE_EBCDIC +static int +yylex(void) +{ + static char etoa_xlate[256]; + static int do_etoa_init = 1; + int tok; + + if (do_etoa_init) + { + for (tok = 0; tok < 256; tok++) + etoa_xlate[tok] = (char) tok; +#ifdef HAVE___ETOA_L + /* IBM helpfully provides this function. */ + __etoa_l(etoa_xlate, sizeof(etoa_xlate)); +#else +# error "An EBCDIC-to-ASCII translation function is needed for this system" +#endif + do_etoa_init = 0; + } + + tok = yylex_ebcdic(); + + if (tok >= 0 && tok <= 0xFF) + tok = etoa_xlate[tok]; + + return tok; +} +#endif /* USE_EBCDIC */ + +/* snode --- instructions for builtin functions. Checks for arg. count + and supplies defaults where possible. */ + +static INSTRUCTION * +snode(INSTRUCTION *subn, INSTRUCTION *r) +{ + INSTRUCTION *arg; + INSTRUCTION *ip; + NODE *n; + int nexp = 0; + int args_allowed; + int idx = r->builtin_idx; + + if (subn != NULL) { + INSTRUCTION *tp; + for (tp = subn->nexti; tp; tp = tp->nexti) { + tp = tp->lasti; + nexp++; + } + assert(nexp > 0); + } + + /* check against how many args. are allowed for this builtin */ + args_allowed = tokentab[idx].flags & ARGS; + if (args_allowed && (args_allowed & A(nexp)) == 0) { + yyerror(_("%d is invalid as number of arguments for %s"), + nexp, tokentab[idx].operator); + return NULL; + } + + /* special processing for sub, gsub and gensub */ + + if (tokentab[idx].value == Op_sub_builtin) { + const char *operator = tokentab[idx].operator; + + r->sub_flags = 0; + + arg = subn->nexti; /* first arg list */ + (void) mk_rexp(arg); + + if (strcmp(operator, "gensub") != 0) { + /* sub and gsub */ + + if (strcmp(operator, "gsub") == 0) + r->sub_flags |= GSUB; + + arg = arg->lasti->nexti; /* 2nd arg list */ + if (nexp == 2) { + INSTRUCTION *expr; + + expr = list_create(instruction(Op_push_i)); + expr->nexti->memory = set_profile_text(make_number(0.0), "0", 1); + (void) mk_expression_list(subn, + list_append(expr, instruction(Op_field_spec))); + } + + arg = arg->lasti->nexti; /* third arg list */ + ip = arg->lasti; + if (ip->opcode == Op_push_i) { + if (do_lint) + lintwarn(_("%s: string literal as last arg of substitute has no effect"), + operator); + r->sub_flags |= LITERAL; + } else { + if (make_assignable(ip) == NULL) + yyerror(_("%s third parameter is not a changeable object"), + operator); + else + ip->do_reference = true; + } + + r->expr_count = count_expressions(&subn, false); + ip = subn->lasti; + + (void) list_append(subn, r); + + /* add after_assign code */ + if (ip->opcode == Op_push_lhs && ip->memory->type == Node_var && ip->memory->var_assign) { + (void) list_append(subn, instruction(Op_var_assign)); + subn->lasti->assign_ctxt = Op_sub_builtin; + subn->lasti->assign_var = ip->memory->var_assign; + } else if (ip->opcode == Op_field_spec_lhs) { + (void) list_append(subn, instruction(Op_field_assign)); + subn->lasti->assign_ctxt = Op_sub_builtin; + subn->lasti->field_assign = (Func_ptr) 0; + ip->target_assign = subn->lasti; + } else if (ip->opcode == Op_subscript_lhs) { + (void) list_append(subn, instruction(Op_subscript_assign)); + subn->lasti->assign_ctxt = Op_sub_builtin; + } + + return subn; + + } else { + /* gensub */ + + r->sub_flags |= GENSUB; + if (nexp == 3) { + ip = instruction(Op_push_i); + 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))); + } + + r->expr_count = count_expressions(&subn, false); + return list_append(subn, r); + } + } + +#ifdef HAVE_MPFR + /* N.B.: If necessary, add special processing for alternate builtin, below */ + if (do_mpfr && tokentab[idx].ptr2) + r->builtin = tokentab[idx].ptr2; + else +#endif + r->builtin = tokentab[idx].ptr; + + /* special case processing for a few builtins */ + + if (r->builtin == do_length) { + if (nexp == 0) { + /* no args. Use $0 */ + + INSTRUCTION *list; + 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 = 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 || r->builtin == do_typeof) { + arg = subn->nexti; + if (arg->nexti == arg->lasti && arg->nexti->opcode == Op_push) + arg->nexti->opcode = Op_push_arg_untyped; /* argument may be untyped */ +#ifdef SUPPLY_INTDIV + } 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; +#endif /* SUPPLY_INTDIV */ + } else if (r->builtin == do_match) { + static bool warned = false; + + arg = subn->nexti->lasti->nexti; /* 2nd arg list */ + (void) mk_rexp(arg); + + if (nexp == 3) { /* 3rd argument there */ + if (do_lint && ! warned) { + warned = true; + lintwarn(_("match: third argument is a gawk extension")); + } + if (do_traditional) { + yyerror(_("match: third argument is a gawk extension")); + return NULL; + } + + arg = arg->lasti->nexti; /* third arg list */ + ip = arg->lasti; + if (/*ip == arg->nexti && */ ip->opcode == Op_push) + ip->opcode = Op_push_array; + } + } else if (r->builtin == do_split) { + arg = subn->nexti->lasti->nexti; /* 2nd arg list */ + ip = arg->lasti; + if (ip->opcode == Op_push) + ip->opcode = Op_push_array; + if (nexp == 2) { + INSTRUCTION *expr; + expr = list_create(instruction(Op_push)); + expr->nexti->memory = FS_node; + (void) mk_expression_list(subn, expr); + } + arg = arg->lasti->nexti; + n = mk_rexp(arg); + if (nexp == 2) + n->re_flags |= FS_DFLT; + if (nexp == 4) { + arg = arg->lasti->nexti; + ip = arg->lasti; + if (ip->opcode == Op_push) + ip->opcode = Op_push_array; + } + } else if (r->builtin == do_patsplit) { + arg = subn->nexti->lasti->nexti; /* 2nd arg list */ + ip = arg->lasti; + if (ip->opcode == Op_push) + ip->opcode = Op_push_array; + if (nexp == 2) { + INSTRUCTION *expr; + expr = list_create(instruction(Op_push)); + expr->nexti->memory = FPAT_node; + (void) mk_expression_list(subn, expr); + } + arg = arg->lasti->nexti; + n = mk_rexp(arg); + if (nexp == 4) { + arg = arg->lasti->nexti; + ip = arg->lasti; + if (ip->opcode == Op_push) + ip->opcode = Op_push_array; + } + } else if (r->builtin == do_close) { + static bool warned = false; + if (nexp == 2) { + if (do_lint && ! warned) { + warned = true; + lintwarn(_("close: second argument is a gawk extension")); + } + if (do_traditional) { + yyerror(_("close: second argument is a gawk extension")); + return NULL; + } + } + } 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 & STRING) != 0) { /* it's a string constant */ + /* ala xgettext, dcgettext("some string" ...) dumps the string */ + NODE *str = subn->nexti->lasti->memory; + + if ((str->flags & INTLSTR) != 0) + warning(_("use of dcgettext(_\"...\") is incorrect: remove leading underscore")); + /* don't dump it, the lexer already did */ + else + dumpintlstr(str->stptr, str->stlen); + } 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 & 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 & 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; + + if (((str1->flags | str2->flags) & INTLSTR) != 0) + warning(_("use of dcngettext(_\"...\") is incorrect: remove leading underscore")); + else + dumpintlstr2(str1->stptr, str1->stlen, str2->stptr, str2->stlen); + } else if (r->builtin == do_asort || r->builtin == do_asorti) { + arg = subn->nexti; /* 1st arg list */ + ip = arg->lasti; + if (ip->opcode == Op_push) + ip->opcode = Op_push_array; + if (nexp >= 2) { + arg = ip->nexti; + ip = arg->lasti; + if (ip->opcode == Op_push) + ip->opcode = Op_push_array; + } + } + else if (r->builtin == do_index) { + arg = subn->nexti->lasti->nexti; /* 2nd arg list */ + ip = arg->lasti; + if (ip->opcode == Op_match_rec) + fatal(_("index: regexp constant as second argument is not allowed")); + } +#ifdef ARRAYDEBUG + else if (r->builtin == do_adump) { + ip = subn->nexti->lasti; + if (ip->opcode == Op_push) + ip->opcode = Op_push_array; + } +#endif + + if (subn != NULL) { + r->expr_count = count_expressions(&subn, false); + return list_append(subn, r); + } + + r->expr_count = 0; + return list_create(r); +} + + +/* parms_shadow --- check if parameters shadow globals */ + +static int +parms_shadow(INSTRUCTION *pc, bool *shadow) +{ + int pcount, i; + bool ret = false; + NODE *func, *fp; + char *fname; + + func = pc->func_body; + fname = func->vname; + fp = func->fparms; + +#if 0 /* can't happen, already exited if error ? */ + if (fname == NULL || func == NULL) /* error earlier */ + return false; +#endif + + pcount = func->param_cnt; + + if (pcount == 0) /* no args, no problem */ + return 0; + + source = pc->source_file; + sourceline = pc->source_line; + /* + * Use warning() and not lintwarn() so that can warn + * about all shadowed parameters. + */ + for (i = 0; i < pcount; i++) { + if (lookup(fp[i].param) != NULL) { + warning( + _("function `%s': parameter `%s' shadows global variable"), + fname, fp[i].param); + ret = true; + } + } + + *shadow |= ret; + return 0; +} + +/* valinfo --- dump var info */ + +void +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"); + } else if ((n->flags & NUMBER) != 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)); +} + + +/* dump_vars --- dump the symbol table */ + +void +dump_vars(const char *fname) +{ + FILE *fp; + NODE **vars; + + if (fname == NULL) + fp = stderr; + else if (strcmp(fname, "-") == 0) + fp = stdout; + else if ((fp = fopen(fname, "w")) == NULL) { + warning(_("could not open `%s' for writing (%s)"), fname, strerror(errno)); + warning(_("sending variable list to standard error")); + fp = stderr; + } + + vars = variable_list(); + print_vars(vars, fprintf, fp); + efree(vars); + if (fp != stdout && fp != stderr && fclose(fp) != 0) + warning(_("%s: close failed (%s)"), fname, strerror(errno)); +} + +/* dump_funcs --- print all functions */ + +void +dump_funcs() +{ + NODE **funcs; + funcs = function_list(true); + (void) foreach_func(funcs, (int (*)(INSTRUCTION *, void *)) pp_func, (void *) 0); + efree(funcs); +} + + +/* shadow_funcs --- check all functions for parameters that shadow globals */ + +void +shadow_funcs() +{ + static int calls = 0; + bool shadow = false; + NODE **funcs; + + if (calls++ != 0) + fatal(_("shadow_funcs() called twice!")); + + funcs = function_list(true); + (void) foreach_func(funcs, (int (*)(INSTRUCTION *, void *)) parms_shadow, & shadow); + efree(funcs); + + /* End with fatal if the user requested it. */ + if (shadow && lintfunc == r_fatal) + lintwarn(_("there were shadowed variables.")); +} + + +/* mk_function --- finalize function definition node; remove parameters + * out of the symbol table. + */ + +static INSTRUCTION * +mk_function(INSTRUCTION *fi, INSTRUCTION *def) +{ + NODE *thisfunc; + + thisfunc = fi->func_body; + assert(thisfunc != NULL); + + if (do_optimize && def->lasti->opcode == Op_pop) { + /* tail call which does not return any value. */ + + INSTRUCTION *t; + + for (t = def->nexti; t->nexti != def->lasti; t = t->nexti) + ; + if (t->opcode == Op_func_call + && strcmp(t->func_name, thisfunc->vname) == 0) + (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 + */ + + (void) list_append(def, instruction(Op_push_i)); + def->lasti->memory = dupnode(Nnull_string); + (void) list_append(def, instruction(Op_K_return)); + + if (do_pretty_print) + (void) list_prepend(def, instruction(Op_exec_count)); + + /* fi->opcode = Op_func */ + (fi + 1)->firsti = def->nexti; + (fi + 1)->lasti = def->lasti; + (fi + 2)->first_line = fi->source_line; + (fi + 2)->last_line = lastline; + fi->nexti = def->nexti; + bcfree(def); + + (void) list_append(rule_list, fi + 1); /* debugging */ + + /* update lint table info */ + func_use(thisfunc->vname, FUNC_DEFINE); + + /* remove params from symbol table */ + remove_params(thisfunc); + return fi; +} + +/* + * install_function: + * install function name in the symbol table. + * Extra work, build up and install a list of the parameter names. + */ + +static int +install_function(char *fname, INSTRUCTION *fi, INSTRUCTION *plist) +{ + NODE *r, *f; + int pcount = 0; + + r = lookup(fname); + if (r != NULL) { + error_ln(fi->source_line, _("function name `%s' previously defined"), fname); + return -1; + } + + if (plist != NULL) + pcount = plist->lasti->param_count + 1; + f = install_symbol(fname, Node_func); + fi->func_body = f; + f->param_cnt = pcount; + f->code_ptr = fi; + f->fparms = NULL; + if (pcount > 0) { + char **pnames; + pnames = check_params(fname, pcount, plist); /* frees plist */ + f->fparms = make_params(pnames, pcount); + efree(pnames); + install_params(f); + } + return 0; +} + + +/* check_params --- build a list of function parameter names after + * making sure that the names are valid and there are no duplicates. + */ + +static char ** +check_params(char *fname, int pcount, INSTRUCTION *list) +{ + INSTRUCTION *p, *np; + int i, j; + char *name; + char **pnames; + + assert(pcount > 0); + + emalloc(pnames, char **, pcount * sizeof(char *), "check_params"); + + for (i = 0, p = list->nexti; p != NULL; i++, p = np) { + np = p->nexti; + name = p->lextok; + p->lextok = NULL; + + if (strcmp(name, fname) == 0) { + /* check for function foo(foo) { ... }. bleah. */ + error_ln(p->source_line, + _("function `%s': can't use function name as parameter name"), fname); + } else if (is_std_var(name)) { + error_ln(p->source_line, + _("function `%s': can't use special variable `%s' as a function parameter"), + fname, name); + } + + /* check for duplicate parameters */ + for (j = 0; j < i; j++) { + if (strcmp(name, pnames[j]) == 0) { + error_ln(p->source_line, + _("function `%s': parameter #%d, `%s', duplicates parameter #%d"), + fname, i + 1, name, j + 1); + } + } + + pnames[i] = name; + bcfree(p); + } + bcfree(list); + + return pnames; +} + + +#ifdef HASHSIZE +undef HASHSIZE +#endif +#define HASHSIZE 1021 + +static struct fdesc { + char *name; + short used; + short defined; + short extension; + struct fdesc *next; +} *ftable[HASHSIZE]; + +/* func_use --- track uses and definitions of functions */ + +static void +func_use(const char *name, enum defref how) +{ + struct fdesc *fp; + int len; + int ind; + + len = strlen(name); + ind = hash(name, len, HASHSIZE, NULL); + + for (fp = ftable[ind]; fp != NULL; fp = fp->next) + if (strcmp(fp->name, name) == 0) + goto update_value; + + /* not in the table, fall through to allocate a new one */ + + 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]; + ftable[ind] = fp; + +update_value: + if (how == FUNC_DEFINE) + fp->defined++; + else if (how == FUNC_EXT) { + fp->defined++; + fp->extension++; + } else + fp->used++; +} + +/* track_ext_func --- add an extension function to the table */ + +void +track_ext_func(const char *name) +{ + func_use(name, FUNC_EXT); +} + +/* check_funcs --- verify functions that are called but not defined */ + +static void +check_funcs() +{ + struct fdesc *fp, *next; + int i; + + if (! in_main_context()) + goto free_mem; + + for (i = 0; i < HASHSIZE; i++) { + for (fp = ftable[i]; fp != NULL; fp = fp->next) { +#ifdef REALLYMEAN + /* making this the default breaks old code. sigh. */ + if (fp->defined == 0 && ! fp->extension) { + error( + _("function `%s' called but never defined"), fp->name); + errcount++; + } +#else + if (do_lint && fp->defined == 0 && ! fp->extension) + lintwarn( + _("function `%s' called but never defined"), fp->name); +#endif + + if (do_lint && fp->used == 0 && ! fp->extension) { + lintwarn(_("function `%s' defined but never called directly"), + fp->name); + } + } + } + +free_mem: + /* now let's free all the memory */ + for (i = 0; i < HASHSIZE; i++) { + for (fp = ftable[i]; fp != NULL; fp = next) { + next = fp->next; + efree(fp->name); + efree(fp); + } + ftable[i] = NULL; + } +} + +/* param_sanity --- look for parameters that are regexp constants */ + +static void +param_sanity(INSTRUCTION *arglist) +{ + INSTRUCTION *argl, *arg; + int i = 1; + + if (arglist == NULL) + return; + for (argl = arglist->nexti; argl; ) { + arg = argl->lasti; + if (arg->opcode == Op_match_rec) + warning_ln(arg->source_line, + _("regexp constant for parameter #%d yields boolean value"), i); + argl = arg->nexti; + i++; + } +} + +/* variable --- make sure NAME is in the symbol table */ + +NODE * +variable(int location, char *name, NODETYPE type) +{ + NODE *r; + + if ((r = lookup(name)) != NULL) { + if (r->type == Node_func || r->type == Node_ext_func ) + error_ln(location, _("function `%s' called with space between name and `(',\nor used as a variable or an array"), + r->vname); + } else { + /* not found */ + return install_symbol(name, type); + } + efree(name); + return r; +} + +/* make_regnode --- make a regular expression node */ + +NODE * +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[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; + } + n->re_exp = exp; + n->re_flags = CONSTANT; + } + return n; +} + + +/* mk_rexp --- make a regular expression constant */ + +static NODE * +mk_rexp(INSTRUCTION *list) +{ + INSTRUCTION *ip; + + 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); + ip->nexti = list->lasti->nexti; + list->lasti->nexti = ip; + list->lasti = ip; + } + return ip->memory; +} + +#ifndef NO_LINT +/* isnoeffect --- when used as a statement, has no side effects */ + +static int +isnoeffect(OPCODE type) +{ + switch (type) { + case Op_times: + case Op_times_i: + case Op_quotient: + case Op_quotient_i: + case Op_mod: + case Op_mod_i: + case Op_plus: + case Op_plus_i: + case Op_minus: + case Op_minus_i: + case Op_subscript: + case Op_concat: + case Op_exp: + case Op_exp_i: + case Op_unary_minus: + case Op_field_spec: + case Op_and_final: + case Op_or_final: + case Op_equal: + case Op_notequal: + case Op_less: + case Op_greater: + case Op_leq: + case Op_geq: + case Op_match: + case Op_nomatch: + case Op_match_rec: + case Op_not: + case Op_in_array: + return true; + default: + break; /* keeps gcc -Wall happy */ + } + + return false; +} +#endif /* NO_LINT */ + + +/* make_assignable --- make this operand an assignable one if posiible */ + +static INSTRUCTION * +make_assignable(INSTRUCTION *ip) +{ + switch (ip->opcode) { + case Op_push: + ip->opcode = Op_push_lhs; + return ip; + case Op_field_spec: + ip->opcode = Op_field_spec_lhs; + return ip; + case Op_subscript: + ip->opcode = Op_subscript_lhs; + return ip; + default: + break; /* keeps gcc -Wall happy */ + } + return NULL; +} + +/* stopme --- for debugging */ + +NODE * +stopme(int nargs ATTRIBUTE_UNUSED) +{ + return make_number(0.0); +} + +/* dumpintlstr --- write out an initial .po file entry for the string */ + +static void +dumpintlstr(const char *str, size_t len) +{ + char *cp; + + /* See the GNU gettext distribution for details on the file format */ + + if (source != NULL) { + /* ala the gettext sources, remove leading `./'s */ + for (cp = source; cp[0] == '.' && cp[1] == '/'; cp += 2) + continue; + printf("#: %s:%d\n", cp, sourceline); + } + + printf("msgid "); + pp_string_fp(fprintf, stdout, str, len, '"', true); + putchar('\n'); + printf("msgstr \"\"\n\n"); + fflush(stdout); +} + +/* dumpintlstr2 --- write out an initial .po file entry for the string and its plural */ + +static void +dumpintlstr2(const char *str1, size_t len1, const char *str2, size_t len2) +{ + char *cp; + + /* See the GNU gettext distribution for details on the file format */ + + if (source != NULL) { + /* ala the gettext sources, remove leading `./'s */ + for (cp = source; cp[0] == '.' && cp[1] == '/'; cp += 2) + continue; + printf("#: %s:%d\n", cp, sourceline); + } + + printf("msgid "); + pp_string_fp(fprintf, stdout, str1, len1, '"', true); + putchar('\n'); + printf("msgid_plural "); + pp_string_fp(fprintf, stdout, str2, len2, '"', true); + putchar('\n'); + printf("msgstr[0] \"\"\nmsgstr[1] \"\"\n\n"); + fflush(stdout); +} + +/* mk_binary --- instructions for binary operators */ + +static INSTRUCTION * +mk_binary(INSTRUCTION *s1, INSTRUCTION *s2, INSTRUCTION *op) +{ + INSTRUCTION *ip1,*ip2; + AWKNUM res; + + ip2 = s2->nexti; + if (s2->lasti == ip2 && ip2->opcode == Op_push_i) { + /* do any numeric constant folding */ + ip1 = s1->nexti; + if (do_optimize + && ip1 == s1->lasti && ip1->opcode == Op_push_i + && (ip1->memory->flags & (MPFN|MPZN|STRCUR|STRING)) == 0 + && (ip2->memory->flags & (MPFN|MPZN|STRCUR|STRING)) == 0 + ) { + NODE *n1 = ip1->memory, *n2 = ip2->memory; + res = force_number(n1)->numbr; + (void) force_number(n2); + switch (op->opcode) { + case Op_times: + res *= n2->numbr; + break; + case Op_quotient: + if (n2->numbr == 0.0) { + /* don't fatalize, allow parsing rest of the input */ + error_ln(op->source_line, _("division by zero attempted")); + goto regular; + } + + res /= n2->numbr; + break; + case Op_mod: + if (n2->numbr == 0.0) { + /* don't fatalize, allow parsing rest of the input */ + error_ln(op->source_line, _("division by zero attempted in `%%'")); + goto regular; + } +#ifdef HAVE_FMOD + res = fmod(res, n2->numbr); +#else /* ! HAVE_FMOD */ + (void) modf(res / n2->numbr, &res); + res = n1->numbr - res * n2->numbr; +#endif /* ! HAVE_FMOD */ + break; + case Op_plus: + res += n2->numbr; + break; + case Op_minus: + res -= n2->numbr; + break; + case Op_exp: + res = calc_exp(res, n2->numbr); + break; + default: + goto regular; + } + + 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); + bcfree(ip1); + bcfree(ip2); + bcfree(s1); + bcfree(s2); + return list_create(op); + } else { + /* do basic arithmetic optimisation */ + /* convert (Op_push_i Node_val) + (Op_plus) to (Op_plus_i Node_val) */ + switch (op->opcode) { + case Op_times: + op->opcode = Op_times_i; + break; + case Op_quotient: + op->opcode = Op_quotient_i; + break; + case Op_mod: + op->opcode = Op_mod_i; + break; + case Op_plus: + op->opcode = Op_plus_i; + break; + case Op_minus: + op->opcode = Op_minus_i; + break; + case Op_exp: + op->opcode = Op_exp_i; + break; + default: + goto regular; + } + + op->memory = ip2->memory; + bcfree(ip2); + bcfree(s2); /* Op_list */ + return list_append(s1, op); + } + } + +regular: + /* append lists s1, s2 and add `op' bytecode */ + (void) list_merge(s1, s2); + return list_append(s1, op); +} + +/* mk_boolean --- instructions for boolean and, or */ + +static INSTRUCTION * +mk_boolean(INSTRUCTION *left, INSTRUCTION *right, INSTRUCTION *op) +{ + INSTRUCTION *tp; + OPCODE opc, final_opc; + + opc = op->opcode; /* Op_and or Op_or */ + final_opc = (opc == Op_or) ? Op_or_final : Op_and_final; + + add_lint(right, LINT_assign_in_cond); + + tp = left->lasti; + + if (tp->opcode != final_opc) { /* x || y */ + list_append(right, instruction(final_opc)); + add_lint(left, LINT_assign_in_cond); + (void) list_append(left, op); + left->lasti->target_jmp = right->lasti; + + /* NB: target_stmt points to previous Op_and(Op_or) in a chain; + * target_stmt only used in the parser (see below). + */ + + left->lasti->target_stmt = left->lasti; + 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; + tp->opcode = opc; + tp->target_jmp = op; + + /* update jump targets */ + for (ip = tp->target_stmt; ; ip = ip->target_stmt) { + assert(ip->opcode == opc); + assert(ip->target_jmp == tp); + /* if (ip->opcode == opc && ip->target_jmp == tp) */ + ip->target_jmp = op; + if (ip->target_stmt == ip) + break; + } + } + + return list_merge(left, right); +} + +/* mk_condition --- if-else and conditional */ + +static INSTRUCTION * +mk_condition(INSTRUCTION *cond, INSTRUCTION *ifp, INSTRUCTION *true_branch, + INSTRUCTION *elsep, INSTRUCTION *false_branch) +{ + /* + * ---------------- + * cond + * ---------------- + * t: [Op_jmp_false f ] + * ---------------- + * true_branch + * + * ---------------- + * [Op_jmp y] + * ---------------- + * f: + * false_branch + * ---------------- + * y: [Op_no_op] + * ---------------- + */ + + INSTRUCTION *ip; + bool setup_else_part = true; + + if (false_branch == NULL) { + false_branch = list_create(instruction(Op_no_op)); + if (elsep == NULL) { /* else { } */ + setup_else_part = false; + } + } else { + /* assert(elsep != NULL); */ + + /* avoid a series of no_op's: if .. else if .. else if .. */ + if (false_branch->lasti->opcode != Op_no_op) + (void) list_append(false_branch, instruction(Op_no_op)); + } + + if (setup_else_part) { + if (do_pretty_print) { + (void) list_prepend(false_branch, elsep); + false_branch->nexti->branch_end = false_branch->lasti; + (void) list_prepend(false_branch, instruction(Op_exec_count)); + } else + bcfree(elsep); + } + + (void) list_prepend(false_branch, instruction(Op_jmp)); + false_branch->nexti->target_jmp = false_branch->lasti; + + add_lint(cond, LINT_assign_in_cond); + ip = list_append(cond, instruction(Op_jmp_false)); + ip->lasti->target_jmp = false_branch->nexti->nexti; + + if (do_pretty_print) { + (void) list_prepend(ip, ifp); + (void) list_append(ip, instruction(Op_exec_count)); + ip->nexti->branch_if = ip->lasti; + ip->nexti->branch_else = false_branch->nexti; + } else + bcfree(ifp); + + if (true_branch != NULL) + list_merge(ip, true_branch); + return list_merge(ip, false_branch); +} + +enum defline { FIRST_LINE, LAST_LINE }; + +/* find_line -- find the first(last) line in a list of (pattern) instructions */ + +static int +find_line(INSTRUCTION *pattern, enum defline what) +{ + INSTRUCTION *ip; + int lineno = 0; + + for (ip = pattern->nexti; ip; ip = ip->nexti) { + if (what == LAST_LINE) { + if (ip->source_line > lineno) + lineno = ip->source_line; + } else { /* FIRST_LINE */ + if (ip->source_line > 0 + && (lineno == 0 || ip->source_line < lineno)) + lineno = ip->source_line; + } + if (ip == pattern->lasti) + break; + } + assert(lineno > 0); + return lineno; +} + +/* append_rule --- pattern-action instructions */ + +static INSTRUCTION * +append_rule(INSTRUCTION *pattern, INSTRUCTION *action) +{ + /* + * ---------------- + * pattern + * ---------------- + * [Op_jmp_false f ] + * ---------------- + * action + * ---------------- + * f: [Op_no_op ] + * ---------------- + */ + + INSTRUCTION *rp; + INSTRUCTION *tp; + INSTRUCTION *ip; + + if (rule != Rule) { + rp = pattern; + if (do_pretty_print) + (void) list_append(action, instruction(Op_no_op)); + (rp + 1)->firsti = action->nexti; + (rp + 1)->lasti = action->lasti; + (rp + 2)->first_line = pattern->source_line; + (rp + 2)->last_line = lastline; + if (block_comment != NULL) { + ip = list_prepend(list_prepend(action, block_comment), rp); + block_comment = NULL; + } else + ip = list_prepend(action, rp); + + } else { + rp = bcalloc(Op_rule, 3, 0); + rp->in_rule = Rule; + rp->source_file = source; + tp = instruction(Op_no_op); + + if (pattern == NULL) { + /* assert(action != NULL); */ + if (do_pretty_print) + (void) list_prepend(action, instruction(Op_exec_count)); + (rp + 1)->firsti = action->nexti; + (rp + 1)->lasti = tp; + (rp + 2)->first_line = firstline; + (rp + 2)->last_line = lastline; + rp->source_line = firstline; + ip = list_prepend(list_append(action, tp), rp); + } else { + (void) list_append(pattern, instruction(Op_jmp_false)); + pattern->lasti->target_jmp = tp; + (rp + 2)->first_line = find_line(pattern, FIRST_LINE); + rp->source_line = (rp + 2)->first_line; + if (action == NULL) { + (rp + 2)->last_line = find_line(pattern, LAST_LINE); + action = list_create(instruction(Op_K_print_rec)); + if (do_pretty_print) + (void) list_prepend(action, instruction(Op_exec_count)); + } else + (rp + 2)->last_line = lastline; + + if (do_pretty_print) { + (void) list_prepend(pattern, instruction(Op_exec_count)); + (void) list_prepend(action, instruction(Op_exec_count)); + } + (rp + 1)->firsti = action->nexti; + (rp + 1)->lasti = tp; + ip = list_append( + list_merge(list_prepend(pattern, rp), + action), + tp); + } + } + + list_append(rule_list, rp + 1); + + if (rule_block[rule] == NULL) + rule_block[rule] = ip; + else + (void) list_merge(rule_block[rule], ip); + + return rule_block[rule]; +} + +/* mk_assignment --- assignment bytecodes */ + +static INSTRUCTION * +mk_assignment(INSTRUCTION *lhs, INSTRUCTION *rhs, INSTRUCTION *op) +{ + INSTRUCTION *tp; + INSTRUCTION *ip; + + tp = lhs->lasti; + switch (tp->opcode) { + case Op_field_spec: + tp->opcode = Op_field_spec_lhs; + break; + case Op_subscript: + tp->opcode = Op_subscript_lhs; + break; + case Op_push: + case Op_push_array: + tp->opcode = Op_push_lhs; + break; + case Op_field_assign: + yyerror(_("cannot assign a value to the result of a field post-increment expression")); + break; + default: + yyerror(_("invalid target of assignment (opcode %s)"), + opcode2str(tp->opcode)); + break; + } + + tp->do_reference = (op->opcode != Op_assign); /* check for uninitialized reference */ + + if (rhs != NULL) + ip = list_merge(rhs, lhs); + else + ip = lhs; + + (void) list_append(ip, op); + + if (tp->opcode == Op_push_lhs + && tp->memory->type == Node_var + && tp->memory->var_assign + ) { + tp->do_reference = false; /* no uninitialized reference checking + * for a special variable. + */ + (void) list_append(ip, instruction(Op_var_assign)); + ip->lasti->assign_var = tp->memory->var_assign; + } else if (tp->opcode == Op_field_spec_lhs) { + (void) list_append(ip, instruction(Op_field_assign)); + ip->lasti->field_assign = (Func_ptr) 0; + tp->target_assign = ip->lasti; + } else if (tp->opcode == Op_subscript_lhs) { + (void) list_append(ip, instruction(Op_subscript_assign)); + } + + return ip; +} + +/* optimize_assignment --- peephole optimization for assignment */ + +static INSTRUCTION * +optimize_assignment(INSTRUCTION *exp) +{ + INSTRUCTION *i1, *i2, *i3; + + /* + * Optimize assignment statements array[subs] = x; var = x; $n = x; + * string concatenation of the form s = s t. + * + * 1) Array element assignment array[subs] = x: + * 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. + * + * 3) Field assignment $n = x: + * Replaces Op_field_spec_lhs + Op_assign + Op_field_assign + Op_pop + * with Op_store_field. + * + * 4) Optimization for string concatenation: + * For cases like x = x y, uses realloc to include y in x; + * also eliminates instructions Op_push_lhs and Op_pop. + */ + + /* + * N.B.: do not append Op_pop instruction to the returned + * instruction list if optimized. None of these + * optimized instructions pushes the r-value of assignment + * onto the runtime stack. + */ + + i2 = NULL; + i1 = exp->lasti; + + if ( i1->opcode != Op_assign + && i1->opcode != Op_field_assign) + return list_append(exp, instruction(Op_pop)); + + for (i2 = exp->nexti; i2 != i1; i2 = i2->nexti) { + switch (i2->opcode) { + case Op_concat: + if (i2->nexti->opcode == Op_push_lhs /* l.h.s is a simple variable */ + && (i2->concat_flag & CSVAR) != 0 /* 1st exp in r.h.s is a simple variable; + * see Op_concat in the grammer above. + */ + && i2->nexti->memory == exp->nexti->memory /* and the same as in l.h.s */ + && i2->nexti->nexti == i1 + && i1->opcode == Op_assign + ) { + /* s = s ... optimization */ + + /* avoid stuff like x = x (x = y) or x = x gsub(/./, "b", x); + * check for l-value reference to this variable in the r.h.s. + * Also, avoid function calls in general to guard against + * global variable assignment. + */ + + for (i3 = exp->nexti->nexti; i3 != i2; i3 = i3->nexti) { + if ((i3->opcode == Op_push_lhs && i3->memory == i2->nexti->memory) + || i3->opcode == Op_func_call) + return list_append(exp, instruction(Op_pop)); /* no optimization */ + } + + /* remove the variable from r.h.s */ + i3 = exp->nexti; + exp->nexti = i3->nexti; + bcfree(i3); + + if (--i2->expr_count == 1) /* one less expression in Op_concat */ + i2->opcode = Op_no_op; + + i3 = i2->nexti; + assert(i3->opcode == Op_push_lhs); + i3->opcode = Op_assign_concat; /* change Op_push_lhs to Op_assign_concat */ + i3->nexti = NULL; + bcfree(i1); /* Op_assign */ + exp->lasti = i3; /* update Op_list */ + return exp; + } + break; + + case Op_field_spec_lhs: + if (i2->nexti->opcode == Op_assign + && i2->nexti->nexti == i1 + && i1->opcode == Op_field_assign + ) { + /* $n = .. */ + i2->opcode = Op_store_field; + bcfree(i2->nexti); /* Op_assign */ + i2->nexti = NULL; + bcfree(i1); /* Op_field_assign */ + exp->lasti = i2; /* update Op_list */ + return exp; + } + break; + + case Op_push_array: + if (i2->nexti->nexti->opcode == Op_subscript_lhs) { + i3 = i2->nexti->nexti; + if (i3->sub_count == 1 + && i3->nexti == i1 + && i1->opcode == Op_assign + ) { + /* array[sub] = .. */ + i3->opcode = Op_store_sub; + i3->memory = i2->memory; + i3->expr_count = 1; /* sub_count shadows memory, + * so use expr_count instead. + */ + i3->nexti = NULL; + i2->opcode = Op_no_op; + bcfree(i1); /* Op_assign */ + exp->lasti = i3; /* update Op_list */ + return exp; + } + } + break; + + case Op_push_lhs: + if (i2->nexti == i1 + && i1->opcode == Op_assign + ) { + /* var = .. */ + i2->opcode = Op_store_var; + i2->nexti = NULL; + bcfree(i1); /* Op_assign */ + exp->lasti = i2; /* update Op_list */ + + i3 = exp->nexti; + if (i3->opcode == Op_push_i + && (i3->memory->flags & INTLSTR) == 0 + && i3->nexti == i2 + ) { + /* constant initializer */ + i2->initval = i3->memory; + bcfree(i3); + exp->nexti = i2; + } else + i2->initval = NULL; + + return exp; + } + break; + + default: + break; + } + } + + /* no optimization */ + return list_append(exp, instruction(Op_pop)); +} + + +/* mk_getline --- make instructions for getline */ + +static INSTRUCTION * +mk_getline(INSTRUCTION *op, INSTRUCTION *var, INSTRUCTION *redir, int redirtype) +{ + INSTRUCTION *ip; + INSTRUCTION *tp; + INSTRUCTION *asgn = NULL; + + /* + * getline [var] < [file] + * + * [ file (simp_exp)] + * [ [ var ] ] + * [ Op_K_getline_redir|NULL|redir_type|into_var] + * [ [var_assign] ] + * + */ + + if (redir == NULL) { + int sline = op->source_line; + bcfree(op); + op = bcalloc(Op_K_getline, 2, sline); + (op + 1)->target_endfile = ip_endfile; + (op + 1)->target_beginfile = ip_beginfile; + } + + if (var != NULL) { + tp = make_assignable(var->lasti); + assert(tp != NULL); + + /* check if we need after_assign bytecode */ + if (tp->opcode == Op_push_lhs + && tp->memory->type == Node_var + && tp->memory->var_assign + ) { + asgn = instruction(Op_var_assign); + asgn->assign_ctxt = op->opcode; + asgn->assign_var = tp->memory->var_assign; + } else if (tp->opcode == Op_field_spec_lhs) { + asgn = instruction(Op_field_assign); + asgn->assign_ctxt = op->opcode; + asgn->field_assign = (Func_ptr) 0; /* determined at run time */ + tp->target_assign = asgn; + } else if (tp->opcode == Op_subscript_lhs) { + asgn = instruction(Op_subscript_assign); + asgn->assign_ctxt = op->opcode; + } + + if (redir != NULL) { + ip = list_merge(redir, var); + (void) list_append(ip, op); + } else + ip = list_append(var, op); + } else if (redir != NULL) + ip = list_append(redir, op); + else + ip = list_create(op); + op->into_var = (var != NULL); + op->redir_type = (redir != NULL) ? redirtype : redirect_none; + + return (asgn == NULL ? ip : list_append(ip, asgn)); +} + + +/* mk_for_loop --- for loop bytecodes */ + +static INSTRUCTION * +mk_for_loop(INSTRUCTION *forp, INSTRUCTION *init, INSTRUCTION *cond, + INSTRUCTION *incr, INSTRUCTION *body) +{ + /* + * ------------------------ + * init (may be NULL) + * ------------------------ + * x: + * cond (Op_no_op if NULL) + * ------------------------ + * [ Op_jmp_false tb ] + * ------------------------ + * body (may be NULL) + * ------------------------ + * tc: + * incr (may be NULL) + * [ Op_jmp x ] + * ------------------------ + * tb:[ Op_no_op ] + */ + + INSTRUCTION *ip, *tbreak, *tcont; + INSTRUCTION *jmp; + INSTRUCTION *pp_cond; + INSTRUCTION *ret; + + tbreak = instruction(Op_no_op); + + if (cond != NULL) { + add_lint(cond, LINT_assign_in_cond); + pp_cond = cond->nexti; + ip = cond; + (void) list_append(ip, instruction(Op_jmp_false)); + ip->lasti->target_jmp = tbreak; + } else { + pp_cond = instruction(Op_no_op); + ip = list_create(pp_cond); + } + + if (init != NULL) + ip = list_merge(init, ip); + + if (do_pretty_print) { + (void) list_append(ip, instruction(Op_exec_count)); + (forp + 1)->forloop_cond = pp_cond; + (forp + 1)->forloop_body = ip->lasti; + } + + if (body != NULL) + (void) list_merge(ip, body); + + jmp = instruction(Op_jmp); + jmp->target_jmp = pp_cond; + if (incr == NULL) + tcont = jmp; + else { + tcont = incr->nexti; + (void) list_merge(ip, incr); + } + + (void) list_append(ip, jmp); + ret = list_append(ip, tbreak); + fix_break_continue(ret, tbreak, tcont); + + if (do_pretty_print) { + forp->target_break = tbreak; + forp->target_continue = tcont; + ret = list_prepend(ret, forp); + } /* else + forp is NULL */ + + return ret; +} + +/* add_lint --- add lint warning bytecode if needed */ + +static void +add_lint(INSTRUCTION *list, LINTTYPE linttype) +{ +#ifndef NO_LINT + INSTRUCTION *ip; + + switch (linttype) { + case LINT_assign_in_cond: + ip = list->lasti; + if (ip->opcode == Op_var_assign || ip->opcode == Op_field_assign) { + assert(ip != list->nexti); + for (ip = list->nexti; ip->nexti != list->lasti; ip = ip->nexti) + ; + } + + if (ip->opcode == Op_assign || ip->opcode == Op_assign_concat) { + list_append(list, instruction(Op_lint)); + list->lasti->lint_type = linttype; + } + break; + + case LINT_no_effect: + if (list->lasti->opcode == Op_pop && list->nexti != list->lasti) { + 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)) { + 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 */ + list_append(list, instruction(Op_lint)); + list->lasti->lint_type = linttype; + } + } + break; + + default: + break; + } +#endif +} + +/* mk_expression_list --- list of bytecode lists */ + +static INSTRUCTION * +mk_expression_list(INSTRUCTION *list, INSTRUCTION *s1) +{ + INSTRUCTION *r; + + /* 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| ... ]------ + * | + * [Op_list| ... ] -- | + * ... | | + * ... <------- | + * [Op_list| ... ] -- | + * ... | | + * ... | | + * ... <------- -- + */ + + assert(s1 != NULL && s1->opcode == Op_list); + if (list == NULL) { + list = instruction(Op_list); + list->nexti = s1; + list->lasti = s1->lasti; + return list; + } + + /* append expression to the end of the list */ + + r = list->lasti; + r->nexti = s1; + list->lasti = s1->lasti; + return list; +} + +/* count_expressions --- fixup expression_list from mk_expression_list. + * returns no of expressions in list. isarg is true + * for function arguments. + */ + +static int +count_expressions(INSTRUCTION **list, bool isarg) +{ + INSTRUCTION *expr; + INSTRUCTION *r = NULL; + int count = 0; + + if (*list == NULL) /* error earlier */ + return 0; + + for (expr = (*list)->nexti; expr; ) { + INSTRUCTION *t1, *t2; + t1 = expr->nexti; + t2 = expr->lasti; + if (isarg && t1 == t2 && t1->opcode == Op_push) + t1->opcode = Op_push_param; + if (++count == 1) + r = expr; + else + (void) list_merge(r, expr); + expr = t2->nexti; + } + + assert(count > 0); + if (! isarg && count > max_args) + max_args = count; + bcfree(*list); + *list = r; + return count; +} + +/* fix_break_continue --- fix up break & continue codes in loop bodies */ + +static void +fix_break_continue(INSTRUCTION *list, INSTRUCTION *b_target, INSTRUCTION *c_target) +{ + INSTRUCTION *ip; + + list->lasti->nexti = NULL; /* just to make sure */ + + for (ip = list->nexti; ip != NULL; ip = ip->nexti) { + switch (ip->opcode) { + case Op_K_break: + if (ip->target_jmp == NULL) + ip->target_jmp = b_target; + break; + + case Op_K_continue: + if (ip->target_jmp == NULL) + ip->target_jmp = c_target; + break; + + default: + /* this is to keep the compiler happy. sheesh. */ + break; + } + } +} + +static inline INSTRUCTION * +list_create(INSTRUCTION *x) +{ + INSTRUCTION *l; + + l = instruction(Op_list); + l->nexti = x; + l->lasti = x; + return l; +} + +static inline INSTRUCTION * +list_append(INSTRUCTION *l, INSTRUCTION *x) +{ +#ifdef GAWKDEBUG + if (l->opcode != Op_list) + cant_happen(); +#endif + l->lasti->nexti = x; + l->lasti = x; + return l; +} + +static inline INSTRUCTION * +list_prepend(INSTRUCTION *l, INSTRUCTION *x) +{ +#ifdef GAWKDEBUG + if (l->opcode != Op_list) + cant_happen(); +#endif + x->nexti = l->nexti; + l->nexti = x; + return l; +} + +static inline INSTRUCTION * +list_merge(INSTRUCTION *l1, INSTRUCTION *l2) +{ +#ifdef GAWKDEBUG + if (l1->opcode != Op_list) + cant_happen(); + if (l2->opcode != Op_list) + cant_happen(); +#endif + l1->lasti->nexti = l2->nexti; + l1->lasti = l2->lasti; + bcfree(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 +check_special(const char *name) +{ + int low, high, mid; + int i; + int non_standard_flags = 0; +#ifdef USE_EBCDIC + static bool did_sort = false; + + if (! did_sort) { + qsort((void *) tokentab, + sizeof(tokentab) / sizeof(tokentab[0]), + sizeof(tokentab[0]), tokcompare); + did_sort = true; + } +#endif + + if (do_traditional) + non_standard_flags |= GAWKX; + if (do_posix) + non_standard_flags |= NOT_POSIX; + + low = 0; + high = (sizeof(tokentab) / sizeof(tokentab[0])) - 1; + while (low <= high) { + mid = (low + high) / 2; + i = *name - tokentab[mid].operator[0]; + if (i == 0) + i = strcmp(name, tokentab[mid].operator); + + if (i < 0) /* token < mid */ + high = mid - 1; + else if (i > 0) /* token > mid */ + low = mid + 1; + else { + if ((tokentab[mid].flags & non_standard_flags) != 0) + return -1; + return mid; + } + } + return -1; +} + +/* + * This provides a private version of functions that act like VMS's + * variable-length record filesystem, where there was a bug on + * certain source files. + */ + +static FILE *fp = NULL; + +/* read_one_line --- return one input line at a time. mainly for debugging. */ + +static ssize_t +read_one_line(int fd, void *buffer, size_t count) +{ + char buf[BUFSIZ]; + + /* Minor potential memory leak here. Too bad. */ + if (fp == NULL) { + fp = fdopen(fd, "r"); + if (fp == NULL) { + fprintf(stderr, "ugh. fdopen: %s\n", strerror(errno)); + gawk_exit(EXIT_FAILURE); + } + } + + if (fgets(buf, sizeof buf, fp) == NULL) + return 0; + + memcpy(buffer, buf, strlen(buf)); + return strlen(buf); +} + +/* one_line_close --- close the open file being read with read_one_line() */ + +static int +one_line_close(int fd) +{ + int ret; + + if (fp == NULL || fd != fileno(fp)) + fatal("debugging read/close screwed up!"); + + ret = fclose(fp); + fp = NULL; + return ret; +} + + +/* lookup_builtin --- find a builtin function or return NULL */ + +builtin_func_t +lookup_builtin(const char *name) +{ + int mid = check_special(name); + + if (mid == -1) + return NULL; + + switch (tokentab[mid].class) { + case LEX_BUILTIN: + case LEX_LENGTH: + break; + default: + return NULL; + } + + /* And another special case... */ + if (tokentab[mid].value == Op_sub_builtin) + return (builtin_func_t) do_sub; + +#ifdef HAVE_MPFR + if (do_mpfr) + return tokentab[mid].ptr2; +#endif + + return tokentab[mid].ptr; +} + +/* install_builtins --- add built-in functions to FUNCTAB */ + +void +install_builtins(void) +{ + int i, j; + int flags_that_must_be_clear = DEBUG_USE; + + if (do_traditional) + flags_that_must_be_clear |= GAWKX; + + if (do_posix) + flags_that_must_be_clear |= NOT_POSIX; + + + j = sizeof(tokentab) / sizeof(tokentab[0]); + for (i = 0; i < j; i++) { + if ( (tokentab[i].class == LEX_BUILTIN + || tokentab[i].class == LEX_LENGTH) + && (tokentab[i].flags & flags_that_must_be_clear) == 0) { + (void) install_symbol(tokentab[i].operator, Node_builtin_func); + } + } +} + +/* + * 9/2014: Gawk cannot use isalpha or isalnum when + * parsing the program since that can let through non-English + * letters. So, we supply our own. !@#$%^&*()-ing locales! + */ + +/* is_alpha --- return true if c is an English letter */ + +/* + * 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. + */ + +bool +is_alpha(int c) +{ +#ifdef I_DONT_KNOW_WHAT_IM_DOING + return isalpha(c); +#else /* ! I_DONT_KNOW_WHAT_IM_DOING */ + switch (c) { + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': + case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': + case 's': case 't': case 'u': case 'v': case 'w': case 'x': + case 'y': case 'z': + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': + case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': + case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': + case 'Y': case 'Z': + return true; + } + return false; +#endif /* ! I_DONT_KNOW_WHAT_IM_DOING */ +} + +/* is_alnum --- return true for alphanumeric, English only letters */ + +bool +is_alnum(int c) +{ + /* digit test is good for EBCDIC too. so there. */ + return (is_alpha(c) || ('0' <= c && c <= '9')); +} + + +/* + * is_letter --- function to check letters + * isalpha() isn't good enough since it can look at the locale. + * Underscore counts as a letter in awk identifiers + */ + +bool +is_letter(int c) +{ + return (is_alpha(c) || c == '_'); +} + +/* is_identchar --- return true if c can be in an identifier */ + +bool +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; +#ifdef HAVE_MPFR + n->strndmode = MPFR_round_mode; +#endif + } + + return n; +} diff --git a/awkgram.y b/awkgram.y new file mode 100644 index 0000000..ad830a5 --- /dev/null +++ b/awkgram.y @@ -0,0 +1,6360 @@ +/* + * awkgram.y --- yacc/bison parser + */ + +/* + * Copyright (C) 1986, 1988, 1989, 1991-2018 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 GAWKDEBUG +#define YYDEBUG 12 +#endif + +#include "awk.h" + +#if defined(__STDC__) && __STDC__ < 1 /* VMS weirdness, maybe elsewhere */ +#define signed /**/ +#endif + +static void yyerror(const char *m, ...) ATTRIBUTE_PRINTF_1; +static void error_ln(int line, const char *m, ...) ATTRIBUTE_PRINTF_2; +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); +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); +static NODE *mk_rexp(INSTRUCTION *exp); +static void param_sanity(INSTRUCTION *arglist); +static int parms_shadow(INSTRUCTION *pc, bool *shadow); +#ifndef NO_LINT +static int isnoeffect(OPCODE type); +#endif +static INSTRUCTION *make_assignable(INSTRUCTION *ip); +static void dumpintlstr(const char *str, size_t len); +static void dumpintlstr2(const char *str1, size_t len1, const char *str2, size_t len2); +static int include_source(INSTRUCTION *file); +static int load_library(INSTRUCTION *file); +static 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) + +static INSTRUCTION *mk_program(void); +static INSTRUCTION *append_rule(INSTRUCTION *pattern, INSTRUCTION *action); +static INSTRUCTION *mk_function(INSTRUCTION *fi, INSTRUCTION *def); +static INSTRUCTION *mk_condition(INSTRUCTION *cond, INSTRUCTION *ifp, INSTRUCTION *true_branch, + INSTRUCTION *elsep, INSTRUCTION *false_branch); +static INSTRUCTION *mk_expression_list(INSTRUCTION *list, INSTRUCTION *s1); +static INSTRUCTION *mk_for_loop(INSTRUCTION *forp, INSTRUCTION *init, INSTRUCTION *cond, + INSTRUCTION *incr, INSTRUCTION *body); +static void fix_break_continue(INSTRUCTION *list, INSTRUCTION *b_target, INSTRUCTION *c_target); +static INSTRUCTION *mk_binary(INSTRUCTION *s1, INSTRUCTION *s2, INSTRUCTION *op); +static INSTRUCTION *mk_boolean(INSTRUCTION *left, INSTRUCTION *right, INSTRUCTION *op); +static INSTRUCTION *mk_assignment(INSTRUCTION *lhs, INSTRUCTION *rhs, INSTRUCTION *op); +static INSTRUCTION *mk_getline(INSTRUCTION *op, INSTRUCTION *opt_var, INSTRUCTION *redir, int redirtype); +static int count_expressions(INSTRUCTION **list, bool isarg); +static INSTRUCTION *optimize_assignment(INSTRUCTION *exp); +static void add_lint(INSTRUCTION *list, LINTTYPE linttype); + +enum defref { FUNC_DEFINE, FUNC_USE, FUNC_EXT }; +static void func_use(const char *name, enum defref how); +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; + +const char *const ruletab[] = { + "?", + "BEGIN", + "Rule", + "END", + "BEGINFILE", + "ENDFILE", +}; + +static bool in_print = false; /* lexical scanning kludge for print */ +static int in_parens = 0; /* lexical scanning kludge for print */ +static int sub_counter = 0; /* array dimension counter for use in delete */ +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 char *thisline = NULL; +static int in_braces = 0; /* count braces for firstline, lastline in an 'action' */ +static int lastline = 0; +static int firstline = 0; +static SRCFILE *sourcefile = NULL; /* current program source */ +static int lasttok = 0; +static bool eof_warned = false; /* GLOBAL: want warning for each file */ +static int break_allowed; /* kludge for break */ +static int continue_allowed; /* kludge for continue */ + +#define END_FILE -1000 +#define END_SRC -2000 + +#define YYDEBUG_LEXER_TEXT (lexeme) +static char *tokstart = NULL; +static char *tok = NULL; +static char *tokend; +static int errcount = 0; + +extern char *source; +extern int sourceline; +extern SRCFILE *srcfiles; +extern INSTRUCTION *rule_list; +extern int max_args; +extern NODE **args_array; + +static INSTRUCTION *rule_block[sizeof(ruletab)]; + +static INSTRUCTION *ip_rec; +static INSTRUCTION *ip_newfile; +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 * +%} + +%token FUNC_CALL NAME REGEXP FILENAME +%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_GETLINE LEX_NEXTFILE +%token LEX_IN +%token LEX_AND LEX_OR INCREMENT DECREMENT +%token LEX_BUILTIN LEX_LENGTH +%token LEX_EOF +%token LEX_INCLUDE LEX_EVAL LEX_LOAD +%token NEWLINE + +/* Lowest to highest */ +%right ASSIGNOP ASSIGN SLASH_BEFORE_EQUAL +%right '?' ':' +%left LEX_OR +%left LEX_AND +%left LEX_GETLINE +%nonassoc LEX_IN +%left FUNC_CALL LEX_BUILTIN LEX_LENGTH +%nonassoc ',' +%left MATCHOP +%nonassoc RELOP '<' '>' IO_IN IO_OUT +%left CONCAT_OP +%left YSTRING YNUMBER TYPED_REGEXP +%left '+' '-' +%left '*' '/' '%' +%right '!' UNARY +%right '^' +%left INCREMENT DECREMENT +%left '$' +%left '(' ')' +%% + +program + : /* empty */ + | program rule + { + rule = 0; + yyerrok; + } + | program nls + | program LEX_EOF + { + next_sourcefile(); + } + | program error + { + rule = 0; + /* + * If errors, give up, don't produce an infinite + * stream of syntax error messages. + */ + /* yyerrok; */ + } + ; + +rule + : pattern action + { + (void) append_rule($1, $2); + first_rule = false; + } + | pattern statement_term + { + if (rule != Rule) { + msg(_("%s blocks must have an action part"), ruletab[rule]); + errcount++; + } else if ($1 == NULL) { + msg(_("each rule must have a pattern or an action part")); + errcount++; + } else /* pattern rule with non-empty pattern */ + (void) append_rule($1, NULL); + } + | function_prologue action + { + in_function = NULL; + (void) mk_function($1, $2); + want_param_names = DONT_CHECK; + yyerrok; + } + | '@' LEX_INCLUDE source statement_term + { + want_source = false; + at_seen = false; + yyerrok; + } + | '@' LEX_LOAD library statement_term + { + want_source = false; + at_seen = false; + yyerrok; + } + ; + +source + : FILENAME + { + if (include_source($1) < 0) + YYABORT; + efree($1->lextok); + bcfree($1); + $$ = NULL; + } + | FILENAME error + { $$ = NULL; } + | error + { $$ = NULL; } + ; + +library + : FILENAME + { + if (load_library($1) < 0) + YYABORT; + efree($1->lextok); + bcfree($1); + $$ = NULL; + } + | FILENAME error + { $$ = NULL; } + | error + { $$ = NULL; } + ; + +pattern + : /* empty */ + { + rule = Rule; + if (comment != NULL) { + $$ = list_create(comment); + comment = NULL; + } else + $$ = NULL; + } + | exp + { + rule = Rule; + if (comment != NULL) { + $$ = list_prepend($1, comment); + comment = NULL; + } else + $$ = $1; + } + + | exp ',' opt_nls exp + { + INSTRUCTION *tp; + + add_lint($1, LINT_assign_in_cond); + add_lint($4, LINT_assign_in_cond); + + tp = instruction(Op_no_op); + list_prepend($1, bcalloc(Op_line_range, !!do_pretty_print + 1, 0)); + $1->nexti->triggered = false; + $1->nexti->target_jmp = $4->nexti; + + list_append($1, instruction(Op_cond_pair)); + $1->lasti->line_range = $1->nexti; + $1->lasti->target_jmp = tp; + + list_append($4, instruction(Op_cond_pair)); + $4->lasti->line_range = $1->nexti; + $4->lasti->target_jmp = tp; + if (do_pretty_print) { + ($1->nexti + 1)->condpair_left = $1->lasti; + ($1->nexti + 1)->condpair_right = $4->lasti; + } + 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; + } + ; + +action + : l_brace statements r_brace opt_semi opt_nls + { + INSTRUCTION *ip; + if ($2 == NULL) + ip = list_create(instruction(Op_no_op)); + else + ip = $2; + $$ = ip; + } + ; + +func_name + : NAME + { $$ = $1; } + | FUNC_CALL + { $$ = $1; } + | lex_builtin + { + yyerror(_("`%s' is a built-in function, it cannot be redefined"), + tokstart); + YYABORT; + } + | '@' LEX_EVAL + { + $$ = $2; + at_seen = false; + } + ; + +lex_builtin + : LEX_BUILTIN + | LEX_LENGTH + ; + +function_prologue + : LEX_FUNCTION func_name '(' { want_param_names = FUNC_HEADER; } opt_param_list r_paren opt_nls + { + /* + * treat any comments between BOF and the first function + * definition (with no intervening BEGIN etc block) as + * program comments. Special kludge: iff there are more + * than one such comments, treat the last as a function + * comment. + */ + if (prior_comment != NULL) { + comment_to_save = prior_comment; + prior_comment = NULL; + } else if (comment != NULL) { + comment_to_save = comment; + comment = NULL; + } else + comment_to_save = NULL; + + if (comment_to_save != NULL && func_first + && strstr(comment_to_save->memory->stptr, "\n\n") != NULL) + split_comment(); + + /* save any other pre-function comment as function comment */ + if (comment_to_save != NULL) { + function_comment = comment_to_save; + comment_to_save = NULL; + } + func_first = false; + $1->source_file = source; + if (install_function($2->lextok, $1, $5) < 0) + YYABORT; + in_function = $2->lextok; + $2->lextok = NULL; + bcfree($2); + /* $5 already free'd in install_function */ + $$ = $1; + want_param_names = FUNC_BODY; + } + ; + +regexp + /* + * In this rule, want_regexp tells yylex that the next thing + * is a regexp so it should read up to the closing slash. + */ + : a_slash + { want_regexp = true; } + REGEXP /* The terminating '/' is consumed by yylex(). */ + { + NODE *n, *exp; + char *re; + size_t len; + + re = $3->lextok; + $3->lextok = NULL; + len = strlen(re); + if (do_lint) { + if (len == 0) + lintwarn_ln($3->source_line, + _("regexp constant `//' looks like a C++ comment, but is not")); + else if (re[0] == '*' && re[len-1] == '*') + /* possible C comment */ + lintwarn_ln($3->source_line, + _("regexp constant `/%s/' looks like a C comment, but is not"), re); + } + + exp = make_str_node(re, len, ALREADY_MALLOCED); + n = make_regnode(Node_regex, exp); + if (n == NULL) { + unref(exp); + YYABORT; + } + $$ = $3; + $$->opcode = Op_match_rec; + $$->memory = n; + } + ; + +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); } + | SLASH_BEFORE_EQUAL + ; + +statements + : /* empty */ + { + 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) { + 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) { + 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; + } + | statements error + { $$ = NULL; } + ; + +statement_term + : nls + | semi opt_nls + ; + +statement + : semi opt_nls + { $$ = NULL; } + | l_brace statements r_brace + { $$ = $2; } + | if_statement + { + if (do_pretty_print) + $$ = list_prepend($1, instruction(Op_exec_count)); + else + $$ = $1; + } + | LEX_SWITCH '(' exp r_paren opt_nls l_brace case_statements opt_nls r_brace + { + INSTRUCTION *dflt, *curr = NULL, *cexp, *cstmt; + INSTRUCTION *ip, *nextc, *tbreak; + const char **case_values = NULL; + int maxcount = 128; + int case_count = 0; + int i; + + tbreak = instruction(Op_no_op); + cstmt = list_create(tbreak); + cexp = list_create(instruction(Op_pop)); + dflt = instruction(Op_jmp); + dflt->target_jmp = tbreak; /* if no case match and no explicit default */ + + if ($7 != NULL) { + curr = $7->nexti; + bcfree($7); /* Op_list */ + } /* else + curr = NULL; */ + + for (; curr != NULL; curr = nextc) { + INSTRUCTION *caseexp = curr->case_exp; + INSTRUCTION *casestmt = curr->case_stmt; + + nextc = curr->nexti; + if (curr->opcode == Op_K_case) { + if (caseexp->opcode == Op_push_i) { + /* a constant scalar */ + char *caseval; + caseval = force_string(caseexp->memory)->stptr; + for (i = 0; i < case_count; i++) { + if (strcmp(caseval, case_values[i]) == 0) + 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) { + maxcount += 128; + erealloc(case_values, const char **, sizeof(char*) * maxcount, "statement"); + } + case_values[case_count++] = caseval; + } else { + /* match a constant regex against switch expression. */ + (curr + 1)->match_exp = true; + } + curr->stmt_start = casestmt->nexti; + curr->stmt_end = casestmt->lasti; + (void) list_prepend(cexp, curr); + (void) list_prepend(cexp, caseexp); + } else { + if (dflt->target_jmp != tbreak) + error_ln(curr->source_line, + _("duplicate `default' detected in switch body")); + else + dflt->target_jmp = casestmt->nexti; + + if (do_pretty_print) { + curr->stmt_start = casestmt->nexti; + curr->stmt_end = casestmt->lasti; + (void) list_prepend(cexp, curr); + } else + bcfree(curr); + } + + cstmt = list_merge(casestmt, cstmt); + } + + if (case_values != NULL) + efree(case_values); + + ip = $3; + if (do_pretty_print) { + (void) list_prepend(ip, $1); + (void) list_prepend(ip, instruction(Op_exec_count)); + $1->target_break = tbreak; + ($1 + 1)->switch_start = cexp->nexti; + ($1 + 1)->switch_end = cexp->lasti; + }/* else + $1 is NULL */ + + (void) list_append(cexp, dflt); + (void) list_merge(ip, cexp); + $$ = list_merge(ip, cstmt); + + 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 ] + * tb:[Op_no_op ] + */ + + INSTRUCTION *ip, *tbreak, *tcont; + + tbreak = instruction(Op_no_op); + add_lint($3, LINT_assign_in_cond); + tcont = $3->nexti; + ip = list_append($3, instruction(Op_jmp_false)); + ip->lasti->target_jmp = tbreak; + + if (do_pretty_print) { + (void) list_append(ip, instruction(Op_exec_count)); + $1->target_break = tbreak; + $1->target_continue = tcont; + ($1 + 1)->while_body = ip->lasti; + (void) list_prepend(ip, $1); + }/* else + $1 is NULL */ + + if ($6 != NULL) + (void) list_merge(ip, $6); + (void) list_append(ip, instruction(Op_jmp)); + ip->lasti->target_jmp = tcont; + $$ = list_append(ip, tbreak); + + break_allowed--; + continue_allowed--; + fix_break_continue(ip, tbreak, tcont); + } + | LEX_DO opt_nls statement LEX_WHILE '(' exp r_paren opt_nls + { + /* + * ----------------- + * z: + * body + * ----------------- + * tc: + * cond + * ----------------- + * [Op_jmp_true | z ] + * tb:[Op_no_op ] + */ + + INSTRUCTION *ip, *tbreak, *tcont; + + tbreak = instruction(Op_no_op); + tcont = $6->nexti; + add_lint($6, LINT_assign_in_cond); + if ($3 != NULL) + ip = list_merge($3, $6); + else + ip = list_prepend($6, instruction(Op_no_op)); + if (do_pretty_print) + (void) list_prepend(ip, instruction(Op_exec_count)); + (void) list_append(ip, instruction(Op_jmp_true)); + ip->lasti->target_jmp = ip->nexti; + $$ = list_append(ip, tbreak); + + break_allowed--; + continue_allowed--; + fix_break_continue(ip, tbreak, tcont); + + if (do_pretty_print) { + $1->target_break = tbreak; + $1->target_continue = tcont; + ($1 + 1)->doloop_cond = tcont; + $$ = list_prepend(ip, $1); + bcfree($4); + } /* else + $1 and $4 are NULLs */ + } + | LEX_FOR '(' NAME LEX_IN simple_variable r_paren opt_nls statement + { + INSTRUCTION *ip; + char *var_name = $3->lextok; + + if ($8 != NULL + && $8->lasti->opcode == Op_K_delete + && $8->lasti->expr_count == 1 + && $8->nexti->opcode == Op_push + && ($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) + * delete foo[iggy] + * + * and treat it as if it were + * + * delete foo + * + * 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; + if ($5->nexti->opcode == Op_push && $5->lasti == $5->nexti) + arr = $5->nexti->memory; + if (arr != NULL + && ip->opcode == Op_no_op + && ip->nexti->opcode == Op_push_array + && strcmp(ip->nexti->memory->vname, arr->vname) == 0 + && ip->nexti->nexti == $8->lasti + ) { + (void) make_assignable($8->nexti); + $8->lasti->opcode = Op_K_delete_loop; + $8->lasti->expr_count = 0; + if ($1 != NULL) + bcfree($1); + efree(var_name); + bcfree($3); + bcfree($4); + bcfree($5); + $$ = $8; + } else + goto regular_loop; + } else { + INSTRUCTION *tbreak, *tcont; + + /* [ Op_push_array a ] + * [ Op_arrayfor_init | ib ] + * ic:[ Op_arrayfor_incr | ib ] + * [ Op_var_assign if any ] + * + * body + * + * [Op_jmp | ic ] + * ib:[Op_arrayfor_final ] + */ +regular_loop: + ip = $5; + ip->nexti->opcode = Op_push_array; + + tbreak = instruction(Op_arrayfor_final); + $4->opcode = Op_arrayfor_incr; + $4->array_var = variable($3->source_line, var_name, Node_var); + $4->target_jmp = tbreak; + tcont = $4; + $3->opcode = Op_arrayfor_init; + $3->target_jmp = tbreak; + (void) list_append(ip, $3); + + if (do_pretty_print) { + $1->opcode = Op_K_arrayfor; + $1->target_continue = tcont; + $1->target_break = tbreak; + (void) list_append(ip, $1); + } /* else + $1 is NULL */ + + /* 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; + } + (void) list_append(ip, $4); + + /* add set_FOO instruction if necessary */ + if ($4->array_var->type == Node_var && $4->array_var->var_assign) { + (void) list_append(ip, instruction(Op_var_assign)); + ip->lasti->assign_var = $4->array_var->var_assign; + } + + if (do_pretty_print) { + (void) list_append(ip, instruction(Op_exec_count)); + ($1 + 1)->forloop_cond = $4; + ($1 + 1)->forloop_body = ip->lasti; + } + + if ($8 != NULL) + (void) list_merge(ip, $8); + + (void) list_append(ip, instruction(Op_jmp)); + ip->lasti->target_jmp = $4; + $$ = list_append(ip, tbreak); + fix_break_continue(ip, tbreak, tcont); + } + + break_allowed--; + continue_allowed--; + } + | LEX_FOR '(' opt_simple_stmt semi opt_nls exp semi opt_nls opt_simple_stmt r_paren opt_nls statement + { + $$ = mk_for_loop($1, $3, $6, $9, $12); + + break_allowed--; + continue_allowed--; + } + | LEX_FOR '(' opt_simple_stmt semi opt_nls semi opt_nls opt_simple_stmt r_paren opt_nls statement + { + $$ = mk_for_loop($1, $3, (INSTRUCTION *) NULL, $8, $11); + + break_allowed--; + continue_allowed--; + } + | non_compound_stmt + { + if (do_pretty_print) + $$ = 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 + { + if (! continue_allowed) + error_ln($1->source_line, + _("`continue' is not allowed outside a loop")); + $1->target_jmp = NULL; + $$ = list_create($1); + $$ = add_pending_comment($$); + + } + | LEX_NEXT statement_term + { + /* if inside function (rule = 0), resolve context at run-time */ + if (rule && rule != Rule) + error_ln($1->source_line, + _("`next' used in %s action"), ruletab[rule]); + $1->target_jmp = ip_rec; + $$ = list_create($1); + $$ = add_pending_comment($$); + } + | LEX_NEXTFILE statement_term + { + /* if inside function (rule = 0), resolve context at run-time */ + if (rule == BEGIN || rule == END || rule == ENDFILE) + error_ln($1->source_line, + _("`nextfile' used in %s action"), ruletab[rule]); + + $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. + */ + $1->target_end = ip_end; /* first instruction in end_block */ + $1->target_atexit = ip_atexit; /* cleanup and go home */ + + if ($2 == NULL) { + $$ = list_create($1); + (void) list_prepend($$, instruction(Op_push_i)); + $$->nexti->memory = dupnode(Nnull_string); + } else + $$ = list_append($2, $1); + $$ = add_pending_comment($$); + } + | LEX_RETURN + { + if (! in_function) + yyerror(_("`return' used outside function context")); + } opt_exp statement_term { + if ($3 == NULL) { + $$ = list_create($1); + (void) list_prepend($$, instruction(Op_push_i)); + $$->nexti->memory = dupnode(Nnull_string); + } else { + if (do_optimize + && $3->lasti->opcode == Op_func_call + && strcmp($3->lasti->func_name, in_function) == 0 + ) { + /* Do tail recursion optimization. Tail + * call without a return value is recognized + * in mk_function(). + */ + ($3->lasti + 1)->tail_call = true; + } + + $$ = list_append($3, $1); + } + $$ = add_pending_comment($$); + } + | simple_stmt statement_term + ; + + /* + * A simple_stmt exists to satisfy a constraint in the POSIX + * grammar allowing them to occur as the 1st and 3rd parts + * in a `for (...;...;...)' loop. This is a historical oddity + * inherited from Unix awk, not at all documented in the AK&W + * awk book. We support it, as this was reported as a bug. + * We don't bother to document it though. So there. + */ +simple_stmt + : print { in_print = true; in_parens = 0; } print_expression_list output_redir + { + /* + * Optimization: plain `print' has no expression list, so $3 is null. + * If $3 is NULL or is a bytecode list for $0 use Op_K_print_rec, + * which is faster for these two cases. + */ + + if ($1->opcode == Op_K_print && + ($3 == NULL + || ($3->lasti->opcode == Op_field_spec + && $3->nexti->nexti->nexti == $3->lasti + && $3->nexti->nexti->opcode == Op_push_i + && $3->nexti->nexti->memory->type == Node_val) + ) + ) { + static bool warned = false; + /* ----------------- + * output_redir + * [ redirect exp ] + * ----------------- + * expression_list + * ------------------ + * [Op_K_print_rec | NULL | redir_type | expr_count] + */ + + if ($3 != NULL) { + NODE *n = $3->nexti->nexti->memory; + + if (! iszero(n)) + goto regular_print; + + bcfree($3->lasti); /* Op_field_spec */ + unref(n); /* Node_val */ + bcfree($3->nexti->nexti); /* Op_push_i */ + bcfree($3->nexti); /* Op_list */ + bcfree($3); /* Op_list */ + } else { + if (do_lint && (rule == BEGIN || rule == END) && ! warned) { + warned = true; + lintwarn_ln($1->source_line, + _("plain `print' in BEGIN or END rule should probably be `print \"\"'")); + } + } + + $1->expr_count = 0; + $1->opcode = Op_K_print_rec; + if ($4 == NULL) { /* no redircetion */ + $1->redir_type = redirect_none; + $$ = list_create($1); + } else { + INSTRUCTION *ip; + ip = $4->nexti; + $1->redir_type = ip->redir_type; + $4->nexti = ip->nexti; + bcfree(ip); + $$ = list_append($4, $1); + } + } else { + /* ----------------- + * [ output_redir ] + * [ redirect exp ] + * ----------------- + * [ expression_list ] + * ------------------ + * [$1 | NULL | redir_type | expr_count] + * + */ +regular_print: + if ($4 == NULL) { /* no redirection */ + if ($3 == NULL) { /* printf without arg */ + $1->expr_count = 0; + $1->redir_type = redirect_none; + $$ = list_create($1); + } else { + INSTRUCTION *t = $3; + $1->expr_count = count_expressions(&t, false); + $1->redir_type = redirect_none; + $$ = list_append(t, $1); + } + } else { + INSTRUCTION *ip; + ip = $4->nexti; + $1->redir_type = ip->redir_type; + $4->nexti = ip->nexti; + bcfree(ip); + if ($3 == NULL) { + $1->expr_count = 0; + $$ = list_append($4, $1); + } else { + INSTRUCTION *t = $3; + $1->expr_count = count_expressions(&t, false); + $$ = list_append(list_merge($4, t), $1); + } + } + } + $$ = add_pending_comment($$); + } + + | LEX_DELETE NAME { sub_counter = 0; } delete_subscript_list + { + char *arr = $2->lextok; + + $2->opcode = Op_push_array; + $2->memory = variable($2->source_line, arr, Node_var_new); + + if (! do_posix && ! do_traditional) { + if ($2->memory == symbol_table) + fatal(_("`delete' is not allowed with SYMTAB")); + else if ($2->memory == func_table) + fatal(_("`delete' is not allowed with FUNCTAB")); + } + + if ($4 == NULL) { + /* + * As of September 2012, POSIX has added support + * for `delete array'. See: + * http://austingroupbugs.net/view.php?id=544 + * + * Thanks to Nathan Weeks for the initiative. + * + * Thus we no longer warn or check do_posix. + * Also, since BWK awk supports it, we don't have to + * check do_traditional either. + */ + $1->expr_count = 0; + $$ = list_append(list_create($2), $1); + } else { + $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 + * should always be done. + */ + { + static bool warned = false; + char *arr = $3->lextok; + + if (do_lint && ! warned) { + warned = true; + lintwarn_ln($1->source_line, + _("`delete(array)' is a non-portable tawk extension")); + } + if (do_traditional) { + error_ln($1->source_line, + _("`delete(array)' is a non-portable tawk extension")); + } + $3->memory = variable($3->source_line, arr, Node_var_new); + $3->opcode = Op_push_array; + $1->expr_count = 0; + $$ = list_append(list_create($3), $1); + + if (! do_posix && ! do_traditional) { + if ($3->memory == symbol_table) + fatal(_("`delete' is not allowed with SYMTAB")); + else if ($3->memory == func_table) + fatal(_("`delete' is not allowed with FUNCTAB")); + } + $$ = add_pending_comment($$); + } + | exp + { + $$ = optimize_assignment($1); + $$ = add_pending_comment($$); + } + ; + +opt_simple_stmt + : /* empty */ + { $$ = NULL; } + | simple_stmt + { $$ = $1; } + ; + +case_statements + : /* empty */ + { $$ = NULL; } + | case_statements case_statement + { + if ($1 == NULL) + $$ = list_create($2); + else + $$ = list_prepend($1, $2); + } + | case_statements error + { $$ = NULL; } + ; + +case_statement + : LEX_CASE case_value colon opt_nls statements + { + INSTRUCTION *casestmt = $5; + if ($5 == NULL) + casestmt = list_create(instruction(Op_no_op)); + if (do_pretty_print) + (void) list_prepend(casestmt, instruction(Op_exec_count)); + $1->case_exp = $2; + $1->case_stmt = casestmt; + bcfree($3); + $$ = $1; + } + | LEX_DEFAULT colon opt_nls statements + { + INSTRUCTION *casestmt = $4; + if ($4 == NULL) + casestmt = list_create(instruction(Op_no_op)); + if (do_pretty_print) + (void) list_prepend(casestmt, instruction(Op_exec_count)); + bcfree($2); + $1->case_stmt = casestmt; + $$ = $1; + } + ; + +case_value + : YNUMBER + { $$ = $1; } + | '-' YNUMBER %prec UNARY + { + NODE *n = $2->memory; + (void) force_number(n); + negate_num(n); + bcfree($1); + $$ = $2; + } + | '+' YNUMBER %prec UNARY + { + NODE *n = $2->lasti->memory; + bcfree($1); + add_sign_to_num(n, '+'); + $$ = $2; + } + | YSTRING + { $$ = $1; } + | 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; + } + ; + +print + : LEX_PRINT + { $$ = $1; } + | LEX_PRINTF + { $$ = $1; } + ; + + /* + * Note: ``print(x)'' is already parsed by the first rule, + * so there is no good in covering it by the second one too. + */ +print_expression_list + : opt_expression_list + | '(' expression_list r_paren + { + $$ = $2; + } + ; + +output_redir + : /* empty */ + { + in_print = false; + in_parens = 0; + $$ = NULL; + } + | IO_OUT { in_print = false; in_parens = 0; } common_exp + { + if ($1->redir_type == redirect_twoway + && $3->lasti->opcode == Op_K_getline_redir + && $3->lasti->redir_type == redirect_twoway) + yyerror(_("multistage two-way pipelines don't work")); + $$ = list_prepend($3, $1); + } + ; + +if_statement + : LEX_IF '(' exp r_paren opt_nls statement + { + $$ = mk_condition($3, $1, $6, NULL, NULL); + } + | LEX_IF '(' exp r_paren opt_nls statement + LEX_ELSE opt_nls statement + { + $$ = mk_condition($3, $1, $6, $7, $9); + } + ; + +nls + : NEWLINE + | nls NEWLINE + ; + +opt_nls + : /* empty */ + | nls + ; + +input_redir + : /* empty */ + { $$ = NULL; } + | '<' simp_exp + { + bcfree($1); + $$ = $2; + } + ; + +opt_param_list + : /* empty */ + { $$ = NULL; } + | param_list + { $$ = $1; } + ; + +param_list + : NAME + { + $1->param_count = 0; + $$ = list_create($1); + } + | param_list comma NAME + { + if ($1 != NULL && $3 != NULL) { + $3->param_count = $1->lasti->param_count + 1; + $$ = list_append($1, $3); + yyerrok; + } else + $$ = NULL; + } + | error + { $$ = NULL; } + | param_list error + { $$ = $1; } + | param_list comma error + { $$ = $1; } + ; + +/* optional expression, as in for loop */ +opt_exp + : /* empty */ + { $$ = NULL; } + | exp + { $$ = $1; } + ; + +opt_expression_list + : /* empty */ + { $$ = NULL; } + | expression_list + { $$ = $1; } + ; + +expression_list + : exp + { $$ = mk_expression_list(NULL, $1); } + | expression_list comma exp + { + $$ = mk_expression_list($1, $3); + yyerrok; + } + | error + { $$ = NULL; } + | expression_list error + { + /* + * Returning the expression list instead of NULL lets + * snode get a list of arguments that it can count. + */ + $$ = $1; + } + | expression_list error exp + { + /* Ditto */ + $$ = mk_expression_list($1, $3); + } + | expression_list comma error + { + /* Ditto */ + $$ = $1; + } + ; + +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 + { + if (do_lint && $3->lasti->opcode == Op_match_rec) + lintwarn_ln($2->source_line, + _("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) + warning_ln($2->source_line, + _("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 */ + $$ = list_append($1, $2); + } else { + $2->memory = make_regnode(Node_dynregex, NULL); + $$ = list_append(list_merge($1, $3), $2); + } + } + | exp LEX_IN simple_variable + { + if (do_lint_old) + warning_ln($2->source_line, + _("old awk does not support the keyword `in' except after `for'")); + $3->nexti->opcode = Op_push_array; + $2->opcode = Op_in_array; + $2->expr_count = 1; + $$ = list_append(list_merge($1, $3), $2); + } + | exp a_relop exp %prec RELOP + { + if (do_lint && $3->lasti->opcode == Op_match_rec) + lintwarn_ln($2->source_line, + _("regular expression on right of comparison")); + $$ = list_append(list_merge($1, $3), $2); + } + | exp '?' exp ':' exp + { $$ = mk_condition($1, $2, $3, $4, $5); } + | common_exp + { $$ = $1; } + ; + +assign_operator + : ASSIGN + { $$ = $1; } + | ASSIGNOP + { $$ = $1; } + | SLASH_BEFORE_EQUAL ASSIGN /* `/=' */ + { + $2->opcode = Op_assign_quotient; + $$ = $2; + } + ; + +relop_or_less + : RELOP + { $$ = $1; } + | '<' + { $$ = $1; } + ; + +a_relop + : relop_or_less + { $$ = $1; } + | '>' + { $$ = $1; } + ; + +common_exp + : simp_exp + { $$ = $1; } + | simp_exp_nc + { $$ = $1; } + | common_exp simp_exp %prec CONCAT_OP + { + int count = 2; + bool is_simple_var = false; + + if ($1->lasti->opcode == Op_concat) { + /* multiple (> 2) adjacent strings optimization */ + is_simple_var = ($1->lasti->concat_flag & CSVAR) != 0; + count = $1->lasti->expr_count + 1; + $1->lasti->opcode = Op_no_op; + } else { + is_simple_var = ($1->nexti->opcode == Op_push + && $1->lasti == $1->nexti); /* first exp. is a simple + * variable?; kludge for use + * in Op_assign_concat. + */ + } + + if (do_optimize + && $1->nexti == $1->lasti && $1->nexti->opcode == Op_push_i + && $2->nexti == $2->lasti && $2->nexti->opcode == Op_push_i + ) { + NODE *n1 = $1->nexti->memory; + 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. + // Also can't fold if one or the other is translatable. + if ((n1->flags & (NUMBER|NUMINT|INTLSTR)) != 0 || (n2->flags & (NUMBER|NUMINT|INTLSTR)) != 0) + goto plain_concat; + + n1 = force_string(n1); + n2 = force_string(n2); + nlen = n1->stlen + n2->stlen; + erealloc(n1->stptr, char *, nlen + 1, "constant fold"); + memcpy(n1->stptr + n1->stlen, n2->stptr, n2->stlen); + n1->stlen = nlen; + n1->stptr[nlen] = '\0'; + n1->flags &= ~(NUMCUR|NUMBER|NUMINT); + n1->flags |= (STRING|STRCUR); + unref(n2); + bcfree($2->nexti); + 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; + if (count > max_args) + max_args = count; + } + } + ; + +simp_exp + : non_post_simp_exp + /* Binary operators in order of decreasing precedence. */ + | simp_exp '^' simp_exp + { $$ = mk_binary($1, $3, $2); } + | simp_exp '*' simp_exp + { $$ = mk_binary($1, $3, $2); } + | simp_exp '/' simp_exp + { $$ = mk_binary($1, $3, $2); } + | simp_exp '%' simp_exp + { $$ = mk_binary($1, $3, $2); } + | simp_exp '+' simp_exp + { $$ = mk_binary($1, $3, $2); } + | simp_exp '-' simp_exp + { $$ = mk_binary($1, $3, $2); } + | LEX_GETLINE opt_variable input_redir + { + /* + * In BEGINFILE/ENDFILE, allow `getline [var] < file' + */ + + if ((rule == BEGINFILE || rule == ENDFILE) && $3 == NULL) + error_ln($1->source_line, + _("non-redirected `getline' invalid inside `%s' rule"), ruletab[rule]); + if (do_lint && rule == END && $3 == NULL) + lintwarn_ln($1->source_line, + _("non-redirected `getline' undefined inside END action")); + $$ = mk_getline($1, $2, $3, redirect_input); + } + | variable INCREMENT + { + $2->opcode = Op_postincrement; + $$ = mk_assignment($1, NULL, $2); + } + | variable DECREMENT + { + $2->opcode = Op_postdecrement; + $$ = mk_assignment($1, NULL, $2); + } + | '(' expression_list r_paren LEX_IN simple_variable + { + if (do_lint_old) { + warning_ln($4->source_line, + _("old awk does not support the keyword `in' except after `for'")); + warning_ln($4->source_line, + _("old awk does not support multidimensional arrays")); + } + $5->nexti->opcode = Op_push_array; + $4->opcode = Op_in_array; + if ($2 == NULL) { /* error */ + errcount++; + $4->expr_count = 0; + $$ = list_merge($5, $4); + } else { + INSTRUCTION *t = $2; + $4->expr_count = count_expressions(&t, false); + $$ = list_append(list_merge(t, $5), $4); + } + } + ; + +/* Expressions containing "| getline" lose the ability to be on the + right-hand side of a concatenation. */ +simp_exp_nc + : common_exp IO_IN LEX_GETLINE opt_variable + { + $$ = mk_getline($3, $4, $1, $2->redir_type); + bcfree($2); + } + /* Binary operators in order of decreasing precedence. */ + | simp_exp_nc '^' simp_exp + { $$ = mk_binary($1, $3, $2); } + | simp_exp_nc '*' simp_exp + { $$ = mk_binary($1, $3, $2); } + | simp_exp_nc '/' simp_exp + { $$ = mk_binary($1, $3, $2); } + | simp_exp_nc '%' simp_exp + { $$ = mk_binary($1, $3, $2); } + | simp_exp_nc '+' simp_exp + { $$ = mk_binary($1, $3, $2); } + | simp_exp_nc '-' simp_exp + { $$ = mk_binary($1, $3, $2); } + ; + +non_post_simp_exp + : regexp + { + $$ = list_create($1); + } + | '!' simp_exp %prec UNARY + { + if ($2->opcode == Op_match_rec) { + $2->opcode = Op_nomatch; + $1->opcode = Op_push_i; + $1->memory = set_profile_text(make_number(0.0), "0", 1); + $$ = list_append(list_append(list_create($1), + instruction(Op_field_spec)), $2); + } else { + if (do_optimize && $2->nexti == $2->lasti + && $2->nexti->opcode == Op_push_i + && ($2->nexti->memory->flags & (MPFN|MPZN|INTLSTR)) == 0 + ) { + NODE *n = $2->nexti->memory; + if ((n->flags & STRING) != 0) { + n->numbr = (AWKNUM) (n->stlen == 0); + n->flags &= ~(STRCUR|STRING); + n->flags |= (NUMCUR|NUMBER); + efree(n->stptr); + n->stptr = NULL; + n->stlen = 0; + } else + n->numbr = (AWKNUM) (n->numbr == 0.0); + bcfree($1); + $$ = $2; + } else { + $1->opcode = Op_not; + add_lint($2, LINT_assign_in_cond); + $$ = list_append($2, $1); + } + } + } + | '(' exp 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_fcall_expression_list r_paren + { + $$ = snode($3, $1); + if ($$ == NULL) + YYABORT; + } + | LEX_LENGTH + { + static bool warned = false; + + if (do_lint && ! warned) { + warned = true; + lintwarn_ln($1->source_line, + _("call of `length' without parentheses is not portable")); + } + $$ = snode(NULL, $1); + if ($$ == NULL) + YYABORT; + } + | func_call + | variable + | INCREMENT variable + { + $1->opcode = Op_preincrement; + $$ = mk_assignment($2, NULL, $1); + } + | DECREMENT variable + { + $1->opcode = Op_predecrement; + $$ = mk_assignment($2, NULL, $1); + } + | YNUMBER + { + $$ = list_create($1); + } + | YSTRING + { + $$ = list_create($1); + } + | '-' simp_exp %prec UNARY + { + if ($2->lasti->opcode == Op_push_i + && ($2->lasti->memory->flags & STRING) == 0 + ) { + NODE *n = $2->lasti->memory; + (void) force_number(n); + negate_num(n); + $$ = $2; + bcfree($1); + } else { + $1->opcode = Op_unary_minus; + $$ = list_append($2, $1); + } + } + | '+' simp_exp %prec UNARY + { + 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); + } + } + ; + +func_call + : direct_func_call + { + func_use($1->lasti->func_name, FUNC_USE); + $$ = $1; + } + | '@' direct_func_call + { + /* indirect function call */ + INSTRUCTION *f, *t; + char *name; + NODE *indirect_var; + static bool warned = false; + const char *msg = _("indirect function calls are a gawk extension"); + + if (do_traditional || do_posix) + yyerror("%s", msg); + else if (do_lint && ! warned) { + warned = true; + lintwarn("%s", msg); + } + + f = $2->lasti; + f->opcode = Op_indirect_func_call; + name = estrdup(f->func_name, strlen(f->func_name)); + if (is_std_var(name)) + yyerror(_("can not use special variable `%s' for indirect function call"), name); + indirect_var = variable(f->source_line, name, Node_var_new); + t = instruction(Op_push); + t->memory = indirect_var; + + /* prepend indirect var instead of appending to arguments (opt_expression_list), + * and pop it off in setup_frame (eval.c) (left to right evaluation order); Test case: + * f = "fun" + * @f(f="real_fun") + */ + + $$ = list_prepend($2, t); + at_seen = false; + } + ; + +direct_func_call + : 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) { + error_ln($1->source_line, + _("attempt to use non-function `%s' in function call"), + $1->func_name); + } + } + param_sanity($3); + $1->opcode = Op_func_call; + $1->func_body = NULL; + if ($3 == NULL) { /* no argument or error */ + ($1 + 1)->expr_count = 0; + $$ = list_create($1); + } else { + INSTRUCTION *t = $3; + ($1 + 1)->expr_count = count_expressions(&t, true); + $$ = list_append(t, $1); + } + } + ; + +opt_variable + : /* empty */ + { $$ = NULL; } + | variable + { $$ = $1; } + ; + +delete_subscript_list + : /* empty */ + { $$ = NULL; } + | delete_subscript SUBSCRIPT + { $$ = $1; } + ; + +delete_subscript + : delete_exp_list + { $$ = $1; } + | delete_subscript delete_exp_list + { + $$ = list_merge($1, $2); + } + ; + +delete_exp_list + : bracketed_exp_list + { + 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 */ + ip->opcode = Op_concat; + ip->concat_flag = CSUBSEP; + ip->expr_count = count; + } else + ip->opcode = Op_no_op; + sub_counter++; /* count # of dimensions */ + $$ = $1; + } + ; + +bracketed_exp_list + : '[' expression_list ']' + { + INSTRUCTION *t = $2; + if ($2 == NULL) { + error_ln($3->source_line, + _("invalid subscript expression")); + /* install Null string as subscript. */ + t = list_create(instruction(Op_push_i)); + t->nexti->memory = dupnode(Nnull_string); + $3->sub_count = 1; + } else + $3->sub_count = count_expressions(&t, false); + $$ = list_append(t, $3); + } + ; + +subscript + : bracketed_exp_list + { $$ = $1; } + | subscript bracketed_exp_list + { + $$ = list_merge($1, $2); + } + ; + +subscript_list + : subscript SUBSCRIPT + { $$ = $1; } + ; + +simple_variable + : NAME + { + char *var_name = $1->lextok; + + $1->opcode = Op_push; + $1->memory = variable($1->source_line, var_name, Node_var_new); + $$ = list_create($1); + } + | NAME subscript_list + { + char *arr = $1->lextok; + $1->memory = variable($1->source_line, arr, Node_var_new); + $1->opcode = Op_push_array; + $$ = list_prepend($2, $1); + } + ; + +variable + : simple_variable + { + INSTRUCTION *ip = $1->nexti; + if (ip->opcode == Op_push + && ip->memory->type == Node_var + && ip->memory->var_update + ) { + $$ = list_prepend($1, instruction(Op_var_update)); + $$->nexti->update_var = ip->memory->var_update; + } else + $$ = $1; + } + | '$' non_post_simp_exp opt_incdec + { + $$ = list_append($2, $1); + if ($3 != NULL) + mk_assignment($2, NULL, $3); + } + ; + +opt_incdec + : INCREMENT + { + $1->opcode = Op_postincrement; + } + | DECREMENT + { + $1->opcode = Op_postdecrement; + } + | /* empty */ { $$ = NULL; } + ; + +l_brace + : '{' opt_nls + ; + +r_brace + : '}' opt_nls { yyerrok; } + ; + +r_paren + : ')' { yyerrok; } + ; + +opt_semi + : /* empty */ + | semi + ; + +semi + : ';' { yyerrok; } + ; + +colon + : ':' { $$ = $1; yyerrok; } + ; + +comma + : ',' opt_nls { yyerrok; } + ; +%% + +struct token { + const char *operator; /* text to match */ + OPCODE value; /* type */ + int class; /* lexical class */ + unsigned flags; /* # of args. allowed and compatability */ +# define ARGS 0xFF /* 0, 1, 2, 3 args allowed (any combination */ +# define A(n) (1<<(n)) +# define VERSION_MASK 0xFF00 /* old awk is zero */ +# define NOT_OLD 0x0100 /* feature not in old awk */ +# define NOT_POSIX 0x0200 /* feature not in POSIX */ +# define GAWKX 0x0400 /* gawk extension */ +# define BREAK 0x0800 /* break allowed inside */ +# define CONTINUE 0x1000 /* continue allowed inside */ +# define DEBUG_USE 0x2000 /* for use by developers */ + + NODE *(*ptr)(int); /* function that implements this keyword */ + NODE *(*ptr2)(int); /* alternate arbitrary-precision function */ +}; + +#ifdef USE_EBCDIC +/* tokcompare --- lexicographically compare token names for sorting */ + +static int +tokcompare(const void *l, const void *r) +{ + struct token *lhs, *rhs; + + lhs = (struct token *) l; + rhs = (struct token *) r; + + return strcmp(lhs->operator, rhs->operator); +} +#endif + +/* + * Tokentab is sorted ASCII ascending order, so it can be binary searched. + * See check_special(), which sorts the table on EBCDIC systems. + * Function pointers come from declarations in awk.h. + */ + +#ifdef HAVE_MPFR +#define MPF(F) do_mpfr_##F +#else +#define MPF(F) 0 +#endif + +static const struct token tokentab[] = { +{"BEGIN", Op_rule, LEX_BEGIN, 0, 0, 0}, +{"BEGINFILE", Op_rule, LEX_BEGINFILE, GAWKX, 0, 0}, +{"END", Op_rule, LEX_END, 0, 0, 0}, +{"ENDFILE", Op_rule, LEX_ENDFILE, GAWKX, 0, 0}, +#ifdef ARRAYDEBUG +{"adump", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|DEBUG_USE, do_adump, 0}, +#endif +{"and", Op_builtin, LEX_BUILTIN, GAWKX, do_and, MPF(and)}, +{"asort", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_asort, 0}, +{"asorti", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_asorti, 0}, +{"atan2", Op_builtin, LEX_BUILTIN, NOT_OLD|A(2), do_atan2, MPF(atan2)}, +{"bindtextdomain", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2), do_bindtextdomain, 0}, +{"break", Op_K_break, LEX_BREAK, 0, 0, 0}, +{"case", Op_K_case, LEX_CASE, GAWKX, 0, 0}, +{"close", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1)|A(2), do_close, 0}, +{"compl", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_compl, MPF(compl)}, +{"continue", Op_K_continue, LEX_CONTINUE, 0, 0, 0}, +{"cos", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_cos, MPF(cos)}, +{"dcgettext", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_dcgettext, 0}, +{"dcngettext", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3)|A(4)|A(5), do_dcngettext, 0}, +{"default", Op_K_default, LEX_DEFAULT, GAWKX, 0, 0}, +{"delete", Op_K_delete, LEX_DELETE, NOT_OLD, 0, 0}, +{"do", Op_K_do, LEX_DO, NOT_OLD|BREAK|CONTINUE, 0, 0}, +{"else", Op_K_else, LEX_ELSE, 0, 0, 0}, +{"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)}, +{"fflush", Op_builtin, LEX_BUILTIN, A(0)|A(1), do_fflush, 0}, +{"for", Op_K_for, LEX_FOR, BREAK|CONTINUE, 0, 0}, +{"func", Op_func, LEX_FUNCTION, NOT_POSIX|NOT_OLD, 0, 0}, +{"function",Op_func, LEX_FUNCTION, NOT_OLD, 0, 0}, +{"gensub", Op_sub_builtin, LEX_BUILTIN, GAWKX|A(3)|A(4), 0, 0}, +{"getline", Op_K_getline_redir, LEX_GETLINE, NOT_OLD, 0, 0}, +{"gsub", Op_sub_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), 0, 0}, +{"if", Op_K_if, LEX_IF, 0, 0, 0}, +{"in", Op_symbol, LEX_IN, 0, 0, 0}, +{"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)}, +#ifdef SUPPLY_INTDIV +{"intdiv0", Op_builtin, LEX_BUILTIN, GAWKX|A(3), do_intdiv, MPF(intdiv)}, +#endif +{"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)|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)}, +{"patsplit", Op_builtin, LEX_BUILTIN, GAWKX|A(2)|A(3)|A(4), do_patsplit, 0}, +{"print", Op_K_print, LEX_PRINT, 0, 0, 0}, +{"printf", Op_K_printf, LEX_PRINTF, 0, 0, 0}, +{"rand", Op_builtin, LEX_BUILTIN, NOT_OLD|A(0), do_rand, MPF(rand)}, +{"return", Op_K_return, LEX_RETURN, NOT_OLD, 0, 0}, +{"rshift", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_rshift, MPF(rshift)}, +{"sin", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_sin, MPF(sin)}, +{"split", Op_builtin, LEX_BUILTIN, A(2)|A(3)|A(4), do_split, 0}, +{"sprintf", Op_builtin, LEX_BUILTIN, 0, do_sprintf, 0}, +{"sqrt", Op_builtin, LEX_BUILTIN, A(1), do_sqrt, MPF(sqrt)}, +{"srand", Op_builtin, LEX_BUILTIN, NOT_OLD|A(0)|A(1), do_srand, MPF(srand)}, +#if defined(GAWKDEBUG) || defined(ARRAYDEBUG) /* || ... */ +{"stopme", Op_builtin, LEX_BUILTIN, GAWKX|A(0)|DEBUG_USE, stopme, 0}, +#endif +{"strftime", Op_builtin, LEX_BUILTIN, GAWKX|A(0)|A(1)|A(2)|A(3), do_strftime, 0}, +{"strtonum", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_strtonum, MPF(strtonum)}, +{"sub", Op_sub_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), 0, 0}, +{"substr", Op_builtin, LEX_BUILTIN, A(2)|A(3), do_substr, 0}, +{"switch", Op_K_switch, LEX_SWITCH, GAWKX|BREAK, 0, 0}, +{"system", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_system, 0}, +{"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)}, +}; + +/* Variable containing the current shift state. */ +static mbstate_t cur_mbstate; +/* Ring buffer containing current characters. */ +#define MAX_CHAR_IN_RING_BUFFER 8 +#define RING_BUFFER_SIZE (MAX_CHAR_IN_RING_BUFFER * MB_LEN_MAX) +static char cur_char_ring[RING_BUFFER_SIZE]; +/* Index for ring buffers. */ +static int cur_ring_idx; +/* This macro means that last nextc() return a singlebyte character + or 1st byte of a multibyte character. */ +#define nextc_is_1stbyte (cur_char_ring[cur_ring_idx] == 1) + +/* getfname --- return name of a builtin function (for pretty printing) */ + +const char * +getfname(NODE *(*fptr)(int)) +{ + int i, j; + + j = sizeof(tokentab) / sizeof(tokentab[0]); + /* linear search, no other way to do it */ + for (i = 0; i < j; i++) + if (tokentab[i].ptr == fptr || tokentab[i].ptr2 == fptr) + return tokentab[i].operator; + + return NULL; +} + +/* negate_num --- negate a number in NODE */ + +void +negate_num(NODE *n) +{ +#ifdef HAVE_MPFR + int tval = 0; +#endif + + add_sign_to_num(n, '-'); + + if (! is_mpg_number(n)) { + n->numbr = -n->numbr; + return; + } + +#ifdef HAVE_MPFR + if (is_mpg_integer(n)) { + if (! iszero(n)) { + mpz_neg(n->mpg_i, n->mpg_i); + return; + } + + /* + * 0 --> -0 conversion. Requires turning the MPG integer + * into an MPFR float. + */ + + mpz_clear(n->mpg_i); /* release the integer storage */ + + /* Convert and fall through. */ + tval = mpfr_set_d(n->mpg_numbr, 0.0, ROUND_MODE); + IEEE_FMT(n->mpg_numbr, tval); + n->flags &= ~MPZN; + n->flags |= MPFN; + } + + /* mpfr float case */ + tval = mpfr_neg(n->mpg_numbr, n->mpg_numbr, ROUND_MODE); + IEEE_FMT(n->mpg_numbr, tval); +#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 +print_included_from() +{ + int saveline, line; + SRCFILE *s; + + /* suppress current file name, line # from `.. included from ..' msgs */ + saveline = sourceline; + sourceline = 0; + + for (s = sourcefile; s != NULL && s->stype == SRC_INC; ) { + s = s->next; + if (s == NULL || s->fd <= INVALID_HANDLE) + continue; + line = s->srclines; + + /* if last token is NEWLINE, line number is off by 1. */ + if (s->lasttok == NEWLINE) + line--; + msg("%s %s:%d%c", + s->prev == sourcefile ? "In file included from" + : " from", + (s->stype == SRC_INC || + s->stype == SRC_FILE) ? s->src : "cmd. line", + line, + s->stype == SRC_INC ? ',' : ':' + ); + } + sourceline = saveline; +} + +/* warning_ln --- print a warning message with location */ + +static void +warning_ln(int line, const char *mesg, ...) +{ + va_list args; + int saveline; + + saveline = sourceline; + sourceline = line; + print_included_from(); + va_start(args, mesg); + err(false, _("warning: "), mesg, args); + va_end(args); + sourceline = saveline; +} + +/* lintwarn_ln --- print a lint warning and location */ + +static void +lintwarn_ln(int line, const char *mesg, ...) +{ + va_list args; + int saveline; + + saveline = sourceline; + sourceline = line; + print_included_from(); + va_start(args, mesg); + if (lintfunc == r_fatal) + err(true, _("fatal: "), mesg, args); + else + err(false, _("warning: "), mesg, args); + va_end(args); + sourceline = saveline; + if (lintfunc == r_fatal) + gawk_exit(EXIT_FATAL); +} + +/* error_ln --- print an error message and location */ + +static void +error_ln(int line, const char *m, ...) +{ + va_list args; + int saveline; + + saveline = sourceline; + sourceline = line; + print_included_from(); + errcount++; + va_start(args, m); + err(false, "error: ", m, args); + va_end(args); + sourceline = saveline; +} + +/* yyerror --- print a syntax error message, show where */ + +static void +yyerror(const char *m, ...) +{ + va_list args; + const char *mesg = NULL; + char *bp, *cp; + char *scan; + char *buf; + int count; + static char end_of_file_line[] = "(END OF FILE)"; + + print_included_from(); + + errcount++; + /* Find the current line in the input file */ + if (lexptr && lexeme) { + if (thisline == NULL) { + cp = lexeme; + if (*cp == '\n') { + if (cp > lexptr_begin) + cp--; + mesg = _("unexpected newline or end of string"); + } + for (; cp != lexptr_begin && *cp != '\n'; --cp) + continue; + if (*cp == '\n') + cp++; + thisline = cp; + } + /* NL isn't guaranteed */ + bp = lexeme; + if (bp < thisline) + bp = thisline + 1; + while (bp < lexend && *bp && *bp != '\n') + bp++; + } else { + thisline = end_of_file_line; + bp = thisline + strlen(thisline); + } + + msg("%.*s", (int) (bp - thisline), thisline); + + va_start(args, m); + if (mesg == NULL) + mesg = m; + + count = strlen(mesg) + 1; + if (lexptr != NULL) + count += (lexeme - thisline) + 2; + ezalloc(buf, char *, count+1, "yyerror"); + + bp = buf; + + if (lexptr != NULL) { + scan = thisline; + while (scan < lexeme) + if (*scan++ == '\t') + *bp++ = '\t'; + else + *bp++ = ' '; + *bp++ = '^'; + *bp++ = ' '; + } + strcpy(bp, mesg); + err(false, "", buf, args); + va_end(args); + efree(buf); +} + +/* mk_program --- create a single list of instructions */ + +static INSTRUCTION * +mk_program() +{ + INSTRUCTION *cp, *tmp; + +#define begin_block rule_block[BEGIN] +#define end_block rule_block[END] +#define prog_block rule_block[Rule] +#define beginfile_block rule_block[BEGINFILE] +#define endfile_block rule_block[ENDFILE] + + if (end_block == NULL) + end_block = list_create(ip_end); + else + (void) list_prepend(end_block, ip_end); + + if (! in_main_context()) { + if (begin_block != NULL && prog_block != NULL) + cp = list_merge(begin_block, prog_block); + else + cp = (begin_block != NULL) ? begin_block : prog_block; + + if (cp != NULL) + (void) list_merge(cp, end_block); + else + cp = end_block; + + (void) list_append(cp, instruction(Op_stop)); + goto out; + } + + if (endfile_block == NULL) + endfile_block = list_create(ip_endfile); + else { + ip_rec->has_endfile = true; + (void) list_prepend(endfile_block, ip_endfile); + } + + if (beginfile_block == NULL) + beginfile_block = list_create(ip_beginfile); + else + (void) list_prepend(beginfile_block, ip_beginfile); + + if (prog_block == NULL) { + if (end_block->nexti == end_block->lasti + && beginfile_block->nexti == beginfile_block->lasti + && endfile_block->nexti == endfile_block->lasti + ) { + /* no pattern-action and (real) end, beginfile or endfile blocks */ + bcfree(ip_rec); + bcfree(ip_newfile); + ip_rec = ip_newfile = NULL; + + list_append(beginfile_block, instruction(Op_after_beginfile)); + (void) list_append(endfile_block, instruction(Op_after_endfile)); + + if (begin_block == NULL) /* no program at all */ + 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)); + + /* append beginfile_block and endfile_block for sole use + * in getline without redirection (Op_K_getline). + */ + + (void) list_merge(cp, beginfile_block); + (void) list_merge(cp, endfile_block); + + goto out; + + } else { + /* install a do-nothing prog block */ + prog_block = list_create(instruction(Op_no_op)); + } + } + + (void) list_append(endfile_block, instruction(Op_after_endfile)); + (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); + (void) list_prepend(cp, ip_newfile); + (void) list_merge(cp, endfile_block); + (void) list_merge(cp, end_block); + 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)); + +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 +} + +/* parse_program --- read in the program and convert into a list of instructions */ + +int +parse_program(INSTRUCTION **pcode) +{ + int ret; + + /* pre-create non-local jump targets + * ip_end (Op_no_op) -- used as jump target for `exit' + * outside an END block. + */ + ip_end = instruction(Op_no_op); + + if (! in_main_context()) + ip_newfile = ip_rec = ip_atexit = ip_beginfile = ip_endfile = NULL; + else { + ip_endfile = 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; + ip_newfile->target_endfile = ip_endfile; + (ip_newfile + 1)->target_get_record = ip_rec; + ip_rec->target_newfile = ip_newfile; + ip_atexit = instruction(Op_atexit); /* target for `exit' in END block */ + } + + for (sourcefile = srcfiles->next; sourcefile->stype == SRC_EXTLIB; + sourcefile = sourcefile->next) + ; + + lexeof = false; + lexptr = NULL; + lasttok = 0; + memset(rule_block, 0, sizeof(ruletab) * sizeof(INSTRUCTION *)); + errcount = 0; + tok = tokstart != NULL ? tokstart : tokexpand(); + + ret = yyparse(); + *pcode = mk_program(); + + /* avoid false source indications */ + source = NULL; + sourceline = 0; + if (ret == 0) /* avoid spurious warning if parser aborted with YYABORT */ + check_funcs(); + + if (do_posix && ! check_param_names()) + errcount++; + + if (args_array == NULL) + emalloc(args_array, NODE **, (max_args + 2) * sizeof(NODE *), "parse_program"); + else + erealloc(args_array, NODE **, (max_args + 2) * sizeof(NODE *), "parse_program"); + + return (ret || errcount); +} + +/* free_srcfile --- free a SRCFILE struct */ + +void +free_srcfile(SRCFILE *thisfile) +{ + efree(thisfile->src); + efree(thisfile); +} + +/* do_add_srcfile --- add one item to srcfiles */ + +static SRCFILE * +do_add_srcfile(enum srctype stype, char *src, char *path, SRCFILE *thisfile) +{ + SRCFILE *s; + + ezalloc(s, SRCFILE *, sizeof(SRCFILE), "do_add_srcfile"); + s->src = estrdup(src, strlen(src)); + s->fullpath = path; + s->stype = stype; + s->fd = INVALID_HANDLE; + s->next = thisfile; + s->prev = thisfile->prev; + thisfile->prev->next = s; + thisfile->prev = s; + return s; +} + +/* add_srcfile --- add one item to srcfiles after checking if + * a source file exists and not already in list. + */ + +SRCFILE * +add_srcfile(enum srctype stype, char *src, SRCFILE *thisfile, bool *already_included, int *errcode) +{ + SRCFILE *s; + struct stat sbuf; + char *path; + int errno_val = 0; + + if (already_included) + *already_included = false; + if (errcode) + *errcode = 0; + if (stype == SRC_CMDLINE || stype == SRC_STDIN) + return do_add_srcfile(stype, src, NULL, thisfile); + + path = find_source(src, & sbuf, & errno_val, stype == SRC_EXTLIB); + if (path == NULL) { + if (errcode) { + *errcode = errno_val; + return NULL; + } + /* use full messages to ease translation */ + fatal(stype != SRC_EXTLIB + ? _("can't open source file `%s' for reading (%s)") + : _("can't open shared library `%s' for reading (%s)"), + src, + errno_val ? strerror(errno_val) : _("reason unknown")); + } + + /* N.B. We do not eliminate duplicate SRC_FILE (-f) programs. */ + for (s = srcfiles->next; s != srcfiles; s = s->next) { + if ((s->stype == SRC_FILE || s->stype == SRC_INC || s->stype == SRC_EXTLIB) && files_are_same(path, s)) { + if (stype == SRC_INC || stype == SRC_EXTLIB) { + /* eliminate duplicates */ + if ((stype == SRC_INC) && (s->stype == SRC_FILE)) + fatal(_("can't include `%s' and use it as a program file"), src); + + if (do_lint) { + int line = sourceline; + /* Kludge: the line number may be off for `@include file'. + * Since, this function is also used for '-f file' in main.c, + * sourceline > 1 check ensures that the call is at + * parse time. + */ + if (sourceline > 1 && lasttok == NEWLINE) + line--; + lintwarn_ln(line, + stype != SRC_EXTLIB + ? _("already included source file `%s'") + : _("already loaded shared library `%s'"), + src); + } + efree(path); + if (already_included) + *already_included = true; + return NULL; + } else { + /* 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 + * they must be of homogeneous type */ + break; + } + } + } + + s = do_add_srcfile(stype, src, path, thisfile); + s->sbuf = sbuf; + s->mtime = sbuf.st_mtime; + return s; +} + +/* include_source --- read program from source included using `@include' */ + +static int +include_source(INSTRUCTION *file) +{ + SRCFILE *s; + char *src = file->lextok; + int errcode; + bool already_included; + + if (do_traditional || do_posix) { + error_ln(file->source_line, _("@include is a gawk extension")); + return -1; + } + + if (strlen(src) == 0) { + if (do_lint) + lintwarn_ln(file->source_line, _("empty filename after @include")); + return 0; + } + + s = add_srcfile(SRC_INC, src, sourcefile, &already_included, &errcode); + if (s == NULL) { + if (already_included) + return 0; + error_ln(file->source_line, + _("can't open source file `%s' for reading (%s)"), + src, errcode ? strerror(errcode) : _("reason unknown")); + return -1; + } + + /* save scanner state for the current sourcefile */ + sourcefile->srclines = sourceline; + sourcefile->lexptr = lexptr; + sourcefile->lexend = lexend; + sourcefile->lexptr_begin = lexptr_begin; + sourcefile->lexeme = lexeme; + sourcefile->lasttok = lasttok; + + /* included file becomes the current source */ + sourcefile = s; + lexptr = NULL; + sourceline = 0; + source = NULL; + lasttok = 0; + lexeof = false; + eof_warned = false; + return 0; +} + +/* load_library --- load a shared library */ + +static int +load_library(INSTRUCTION *file) +{ + SRCFILE *s; + char *src = file->lextok; + int errcode; + bool already_included; + + if (do_traditional || do_posix) { + error_ln(file->source_line, _("@load is a gawk extension")); + return -1; + } + + if (strlen(src) == 0) { + if (do_lint) + lintwarn_ln(file->source_line, _("empty filename after @load")); + return 0; + } + + s = add_srcfile(SRC_EXTLIB, src, sourcefile, &already_included, &errcode); + if (s == NULL) { + if (already_included) + return 0; + error_ln(file->source_line, + _("can't open shared library `%s' for reading (%s)"), + src, errcode ? strerror(errcode) : _("reason unknown")); + return -1; + } + + load_ext(s->fullpath); + return 0; +} + +/* next_sourcefile --- read program from the next source in srcfiles */ + +static void +next_sourcefile() +{ + static int (*closefunc)(int fd) = NULL; + + if (closefunc == NULL) { + char *cp = getenv("AWKREADFUNC"); + + /* If necessary, one day, test value for different functions. */ + if (cp == NULL) + closefunc = close; + else + closefunc = one_line_close; + } + + /* + * This won't be true if there's an invalid character in + * the source file or source string (e.g., user typo). + * Previous versions of gawk did not core dump in such a + * case. + * + * assert(lexeof == true); + */ + + lexeof = false; + eof_warned = false; + sourcefile->srclines = sourceline; /* total no of lines in current file */ + if (sourcefile->fd > INVALID_HANDLE) { + if (sourcefile->fd != fileno(stdin)) /* safety */ + (*closefunc)(sourcefile->fd); + sourcefile->fd = INVALID_HANDLE; + } + if (sourcefile->buf != NULL) { + efree(sourcefile->buf); + sourcefile->buf = NULL; + sourcefile->lexptr_begin = NULL; + } + + while ((sourcefile = sourcefile->next) != NULL) { + if (sourcefile == srcfiles) + return; + if (sourcefile->stype != SRC_EXTLIB) + break; + } + + if (sourcefile->lexptr_begin != NULL) { + /* resume reading from already opened file (postponed to process '@include') */ + lexptr = sourcefile->lexptr; + lexend = sourcefile->lexend; + lasttok = sourcefile->lasttok; + lexptr_begin = sourcefile->lexptr_begin; + lexeme = sourcefile->lexeme; + sourceline = sourcefile->srclines; + source = sourcefile->src; + } else { + lexptr = NULL; + sourceline = 0; + source = NULL; + lasttok = 0; + } +} + +/* get_src_buf --- read the next buffer of source program */ + +static char * +get_src_buf() +{ + int n; + char *scan; + bool newfile; + int savelen; + struct stat sbuf; + + /* + * No argument prototype on readfunc on purpose, + * avoids problems with some ancient systems where + * the types of arguments to read() aren't up to date. + */ + static ssize_t (*readfunc)() = 0; + + if (readfunc == NULL) { + char *cp = getenv("AWKREADFUNC"); + + /* If necessary, one day, test value for different functions. */ + if (cp == NULL) + /* + * cast is to remove warnings on systems with + * different return types for read. + */ + readfunc = ( ssize_t(*)() ) read; + else + readfunc = read_one_line; + } + + newfile = false; + if (sourcefile == srcfiles) + return NULL; + + if (sourcefile->stype == SRC_CMDLINE) { + if (sourcefile->bufsize == 0) { + sourcefile->bufsize = strlen(sourcefile->src); + lexptr = lexptr_begin = lexeme = sourcefile->src; + lexend = lexptr + sourcefile->bufsize; + sourceline = 1; + if (sourcefile->bufsize == 0) { + /* + * Yet Another Special case: + * gawk '' /path/name + * Sigh. + */ + static bool warned = false; + + if (do_lint && ! warned) { + warned = true; + lintwarn(_("empty program text on command line")); + } + lexeof = true; + } + } else if (sourcefile->buf == NULL && *(lexptr-1) != '\n') { + /* + * The following goop is to ensure that the source + * ends with a newline and that the entire current + * line is available for error messages. + */ + int offset; + char *buf; + + offset = lexptr - lexeme; + for (scan = lexeme; scan > lexptr_begin; scan--) + if (*scan == '\n') { + scan++; + break; + } + savelen = lexptr - scan; + emalloc(buf, char *, savelen + 1, "get_src_buf"); + memcpy(buf, scan, savelen); + thisline = buf; + lexptr = buf + savelen; + *lexptr = '\n'; + lexeme = lexptr - offset; + lexptr_begin = buf; + lexend = lexptr + 1; + sourcefile->buf = buf; + } else + lexeof = true; + return lexptr; + } + + if (sourcefile->fd <= INVALID_HANDLE) { + int fd; + int l; + + source = sourcefile->src; + if (source == NULL) + return NULL; + fd = srcopen(sourcefile); + if (fd <= INVALID_HANDLE) { + char *in; + + /* suppress file name and line no. in error mesg */ + in = source; + source = NULL; + error(_("can't open source file `%s' for reading (%s)"), + in, strerror(errno)); + errcount++; + lexeof = true; + return sourcefile->src; + } + + sourcefile->fd = fd; + l = optimal_bufsize(fd, &sbuf); + /* + * Make sure that something silly like + * AWKBUFSIZE=8 make check + * works ok. + */ +#define A_DECENT_BUFFER_SIZE 128 + if (l < A_DECENT_BUFFER_SIZE) + l = A_DECENT_BUFFER_SIZE; +#undef A_DECENT_BUFFER_SIZE + sourcefile->bufsize = l; + newfile = true; + emalloc(sourcefile->buf, char *, sourcefile->bufsize, "get_src_buf"); + lexptr = lexptr_begin = lexeme = sourcefile->buf; + savelen = 0; + sourceline = 1; + thisline = NULL; + } else { + /* + * Here, we retain the current source line in the beginning of the buffer. + */ + int offset; + for (scan = lexeme; scan > lexptr_begin; scan--) + if (*scan == '\n') { + scan++; + break; + } + + savelen = lexptr - scan; + offset = lexptr - lexeme; + + if (savelen > 0) { + /* + * Need to make sure we have room left for reading new text; + * grow the buffer (by doubling, an arbitrary choice), if the retained line + * takes up more than a certain percentage (50%, again an arbitrary figure) + * of the available space. + */ + + if (savelen > sourcefile->bufsize / 2) { /* long line or token */ + sourcefile->bufsize *= 2; + erealloc(sourcefile->buf, char *, sourcefile->bufsize, "get_src_buf"); + scan = sourcefile->buf + (scan - lexptr_begin); + lexptr_begin = sourcefile->buf; + } + + thisline = lexptr_begin; + memmove(thisline, scan, savelen); + lexptr = thisline + savelen; + lexeme = lexptr - offset; + } else { + savelen = 0; + lexptr = lexeme = lexptr_begin; + thisline = NULL; + } + } + + n = (*readfunc)(sourcefile->fd, lexptr, sourcefile->bufsize - savelen); + if (n == -1) { + error(_("can't read sourcefile `%s' (%s)"), + source, strerror(errno)); + errcount++; + lexeof = true; + } else { + lexend = lexptr + n; + if (n == 0) { + static bool warned = false; + if (do_lint && newfile && ! warned) { + warned = true; + sourceline = 0; + lintwarn(_("source file `%s' is empty"), source); + } + lexeof = true; + } + } + return sourcefile->buf; +} + +/* tokadd --- add a character to the token buffer */ + +#define tokadd(x) (*tok++ = (x), tok == tokend ? tokexpand() : tok) + +/* tokexpand --- grow the token buffer */ + +static char * +tokexpand() +{ + static int toksize; + int tokoffset; + + if (tokstart != NULL) { + tokoffset = tok - tokstart; + toksize *= 2; + erealloc(tokstart, char *, toksize, "tokexpand"); + tok = tokstart + tokoffset; + } else { + toksize = 60; + emalloc(tokstart, char *, toksize, "tokexpand"); + tok = tokstart; + } + tokend = tokstart + toksize; + return tok; +} + +/* check_bad_char --- fatal if c isn't allowed in gawk source code */ + +/* + * The error message was inspired by someone who decided to put + * a physical \0 byte into the source code to see what would + * happen and then filed a bug report about it. Sigh. + */ + +static void +check_bad_char(int c) +{ + /* allow escapes. needed for autoconf. bleah. */ + switch (c) { + case '\a': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + return; + default: + break; + } + + if (iscntrl(c) && ! isspace(c)) + fatal(_("PEBKAC error: invalid character '\\%03o' in source code"), c & 0xFF); +} + +/* nextc --- get the next input character */ + +static int +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; + return END_SRC; + } + + /* Update the buffer index. */ + cur_ring_idx = (cur_ring_idx == RING_BUFFER_SIZE - 1)? 0 : + cur_ring_idx + 1; + + /* Did we already check the current character? */ + if (cur_char_ring[cur_ring_idx] == 0) { + /* No, we need to check the next character on the buffer. */ + int idx, work_ring_idx = cur_ring_idx; + mbstate_t tmp_state; + size_t mbclen; + + for (idx = 0; lexptr + idx < lexend; idx++) { + tmp_state = cur_mbstate; + mbclen = mbrlen(lexptr, idx + 1, &tmp_state); + + if (mbclen == 1 || mbclen == (size_t)-1 || mbclen == 0) { + /* It is a singlebyte character, non-complete multibyte + character or EOF. We treat it as a singlebyte + character. */ + cur_char_ring[work_ring_idx] = 1; + break; + } else if (mbclen == (size_t)-2) { + /* It is not a complete multibyte character. */ + cur_char_ring[work_ring_idx] = idx + 1; + } else { + /* mbclen > 1 */ + cur_char_ring[work_ring_idx] = mbclen; + break; + } + work_ring_idx = (work_ring_idx == RING_BUFFER_SIZE - 1)? + 0 : work_ring_idx + 1; + } + cur_mbstate = tmp_state; + + /* Put a mark on the position on which we write next character. */ + work_ring_idx = (work_ring_idx == RING_BUFFER_SIZE - 1)? + 0 : work_ring_idx + 1; + cur_char_ring[work_ring_idx] = 0; + } + if (check_for_bad || *lexptr == '\0') + check_bad_char(*lexptr); + + 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); + return ((int) (unsigned char) *lexptr++); + } + } while (get_src_buf()); + return END_SRC; + } +} + +/* pushback --- push a character back on the input */ + +static inline void +pushback(void) +{ + if (gawk_mb_cur_max > 1) + cur_ring_idx = (cur_ring_idx == 0)? RING_BUFFER_SIZE - 1 : + cur_ring_idx - 1; + (! 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 : */ + +static void +allow_newline(void) +{ + int c; + + for (;;) { + c = nextc(true); + if (c == END_FILE) { + pushback(); + break; + } + if (c == '#') { + 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; + } + } + if (c == '\n') + sourceline++; + if (! isspace(c)) { + pushback(); + break; + } + } +} + +/* newline_eof --- return newline or EOF as needed and adjust variables */ + +/* + * This routine used to be a macro, however GCC 4.6.2 warned about + * the result of a computation not being used. Converting to a function + * removes the warnings. + */ + +static int +newline_eof() +{ + /* NB: a newline at end does not start a source line. */ + if (lasttok != NEWLINE) { + pushback(); + if (do_lint && ! eof_warned) { + lintwarn(_("source file does not end in newline")); + eof_warned = true; + } + sourceline++; + return NEWLINE; + } + + sourceline--; + eof_warned = false; + return LEX_EOF; +} + +/* yylex --- Read the input and turn it into tokens. */ + +static int +#ifdef USE_EBCDIC +yylex_ebcdic(void) +#else +yylex(void) +#endif +{ + int c; + bool seen_e = false; /* These are for numbers */ + bool seen_point = false; + bool esc_seen; /* for literal strings */ + int mid; + int base; + static bool did_newline = false; + char *tokkey; + bool inhex = false; + bool intlstr = false; + AWKNUM d; + bool collecting_typed_regexp = false; + +#define GET_INSTRUCTION(op) bcalloc(op, 1, sourceline) + +#define NEWLINE_EOF newline_eof() + + yylval = (INSTRUCTION *) NULL; + if (lasttok == SUBSCRIPT) { + lasttok = 0; + return SUBSCRIPT; + } + + if (lasttok == LEX_EOF) /* error earlier in current source, must give up !! */ + return 0; + + c = nextc(! want_regexp); + if (c == END_SRC) + return 0; + if (c == END_FILE) + return lasttok = NEWLINE_EOF; + pushback(); + +#if defined __EMX__ + /* + * added for OS/2's extproc feature of cmd.exe + * (like #! in BSD sh) + */ + if (strncasecmp(lexptr, "extproc ", 8) == 0) { + while (*lexptr && *lexptr != '\n') + lexptr++; + } +#endif + + lexeme = lexptr; + thisline = NULL; + +collect_regexp: + if (want_regexp) { + int in_brack = 0; /* count brackets, [[:alnum:]] allowed */ + int b_index = -1; + int cur_index = 0; + + /* + * Here is what's ok with brackets: + * + * [..[..] []] [^]] [.../...] + * [...\[...] [...\]...] [...\/...] + * + * (Remember that all of the above are inside /.../) + * + * The code for \ handles \[, \] and \/. + * + * Otherwise, track the first open [ position, and if + * an embedded ] occurs, allow it to pass through + * if it's right after the first [ or after [^. + * + * Whew! + */ + + want_regexp = false; + tok = tokstart; + for (;;) { + c = nextc(false); + + cur_index = tok - tokstart; + if (gawk_mb_cur_max == 1 || nextc_is_1stbyte) switch (c) { + case '[': + if (nextc(false) == ':' || in_brack == 0) { + in_brack++; + if (in_brack == 1) + b_index = tok - tokstart; + } + pushback(); + break; + case ']': + if (in_brack > 0 + && (cur_index == b_index + 1 + || (cur_index == b_index + 2 && tok[-1] == '^'))) + ; /* do nothing */ + else { + in_brack--; + if (in_brack == 0) + b_index = -1; + } + break; + case '\\': + if ((c = nextc(false)) == END_FILE) { + pushback(); + yyerror(_("unterminated regexp ends with `\\' at end of file")); + goto end_regexp; /* kludge */ + } + if (c == '\r') /* allow MS-DOS files. bleah */ + c = nextc(true); + if (c == '\n') { + sourceline++; + continue; + } else { + tokadd('\\'); + tokadd(c); + continue; + } + break; + case '/': /* end of the regexp */ + if (in_brack > 0) + break; +end_regexp: + yylval = GET_INSTRUCTION(Op_token); + yylval->lextok = estrdup(tokstart, tok - tokstart); + if (do_lint) { + int peek = nextc(true); + + pushback(); + if (peek == 'i' || peek == 's') { + if (source) + lintwarn( + _("%s: %d: tawk regex modifier `/.../%c' doesn't work in gawk"), + source, sourceline, peek); + else + lintwarn( + _("tawk regex modifier `/.../%c' doesn't work in gawk"), + peek); + } + } + if (collecting_typed_regexp) { + collecting_typed_regexp = false; + lasttok = TYPED_REGEXP; + } else + lasttok = REGEXP; + + return lasttok; + case '\n': + pushback(); + yyerror(_("unterminated regexp")); + goto end_regexp; /* kludge */ + case END_FILE: + pushback(); + yyerror(_("unterminated regexp at end of file")); + goto end_regexp; /* kludge */ + } + tokadd(c); + } + } +retry: + + /* skipping \r is a hack, but windows is just too pervasive. sigh. */ + while ((c = nextc(true)) == ' ' || c == '\t' || c == '\r') + continue; + + lexeme = lexptr ? lexptr - 1 : lexptr; + thisline = NULL; + tok = tokstart; + + if (gawk_mb_cur_max == 1 || nextc_is_1stbyte) + switch (c) { + case END_SRC: + return 0; + + case END_FILE: + return lasttok = NEWLINE_EOF; + + case '\n': + sourceline++; + return lasttok = NEWLINE; + + case '#': /* it's a comment */ + 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 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. + */ + if (! do_traditional) { + /* strip trailing white-space and/or comment */ + while ((c = nextc(true)) == ' ' || c == '\t' || c == '\r') + continue; + if (c == '#') { + static bool warned = false; + + if (do_lint && ! warned) { + warned = true; + lintwarn( + _("use of `\\ #...' line continuation is not portable")); + } + if (do_pretty_print && ! do_profile) + c = get_comment(EOL_COMMENT); + else { + while ((c = nextc(false)) != '\n') + if (c == END_FILE) + break; + } + } + pushback(); + } +#endif /* RELAXED_CONTINUATION */ + c = nextc(true); + if (c == '\r') /* allow MS-DOS files. bleah */ + c = nextc(true); + if (c == '\n') { + sourceline++; + goto retry; + } else { + yyerror(_("backslash not last character on line")); + return lasttok = LEX_EOF; + } + break; + + case ':': + case '?': + yylval = GET_INSTRUCTION(Op_cond_exp); + if (! do_posix) + allow_newline(); + return lasttok = c; + + /* + * in_parens is undefined unless we are parsing a print + * statement (in_print), but why bother with a check? + */ + case ')': + in_parens--; + return lasttok = c; + + case '(': + in_parens++; + return lasttok = c; + case '$': + yylval = GET_INSTRUCTION(Op_field_spec); + return lasttok = c; + case '{': + if (++in_braces == 1) + firstline = sourceline; + case ';': + case ',': + case '[': + return lasttok = c; + case ']': + c = nextc(true); + pushback(); + if (c == '[') { + if (do_traditional) + fatal(_("multidimensional arrays are a gawk extension")); + if (do_lint) + lintwarn(_("multidimensional arrays are a gawk extension")); + yylval = GET_INSTRUCTION(Op_sub_array); + lasttok = ']'; + } else { + yylval = GET_INSTRUCTION(Op_subscript); + lasttok = SUBSCRIPT; /* end of subscripts */ + } + return ']'; + + case '*': + if ((c = nextc(true)) == '=') { + yylval = GET_INSTRUCTION(Op_assign_times); + return lasttok = ASSIGNOP; + } else if (do_posix) { + pushback(); + yylval = GET_INSTRUCTION(Op_times); + return lasttok = '*'; + } else if (c == '*') { + /* make ** and **= aliases for ^ and ^= */ + static bool did_warn_op = false, did_warn_assgn = false; + + if (nextc(true) == '=') { + if (! did_warn_assgn) { + did_warn_assgn = true; + if (do_lint) + lintwarn(_("POSIX does not allow operator `**='")); + if (do_lint_old) + warning(_("old awk does not support operator `**='")); + } + yylval = GET_INSTRUCTION(Op_assign_exp); + return ASSIGNOP; + } else { + pushback(); + if (! did_warn_op) { + did_warn_op = true; + if (do_lint) + lintwarn(_("POSIX does not allow operator `**'")); + if (do_lint_old) + warning(_("old awk does not support operator `**'")); + } + yylval = GET_INSTRUCTION(Op_exp); + return lasttok = '^'; + } + } + pushback(); + yylval = GET_INSTRUCTION(Op_times); + return lasttok = '*'; + + case '/': + if (nextc(false) == '=') { + pushback(); + return lasttok = SLASH_BEFORE_EQUAL; + } + pushback(); + yylval = GET_INSTRUCTION(Op_quotient); + return lasttok = '/'; + + case '%': + if (nextc(true) == '=') { + yylval = GET_INSTRUCTION(Op_assign_mod); + return lasttok = ASSIGNOP; + } + pushback(); + yylval = GET_INSTRUCTION(Op_mod); + return lasttok = '%'; + + case '^': + { + static bool did_warn_op = false, did_warn_assgn = false; + + if (nextc(true) == '=') { + if (do_lint_old && ! did_warn_assgn) { + did_warn_assgn = true; + warning(_("operator `^=' is not supported in old awk")); + } + yylval = GET_INSTRUCTION(Op_assign_exp); + return lasttok = ASSIGNOP; + } + pushback(); + if (do_lint_old && ! did_warn_op) { + did_warn_op = true; + warning(_("operator `^' is not supported in old awk")); + } + yylval = GET_INSTRUCTION(Op_exp); + return lasttok = '^'; + } + + case '+': + if ((c = nextc(true)) == '=') { + yylval = GET_INSTRUCTION(Op_assign_plus); + return lasttok = ASSIGNOP; + } + if (c == '+') { + yylval = GET_INSTRUCTION(Op_symbol); + return lasttok = INCREMENT; + } + pushback(); + yylval = GET_INSTRUCTION(Op_plus); + return lasttok = '+'; + + case '!': + if ((c = nextc(true)) == '=') { + yylval = GET_INSTRUCTION(Op_notequal); + return lasttok = RELOP; + } + if (c == '~') { + yylval = GET_INSTRUCTION(Op_nomatch); + return lasttok = MATCHOP; + } + pushback(); + yylval = GET_INSTRUCTION(Op_symbol); + return lasttok = '!'; + + case '<': + if (nextc(true) == '=') { + yylval = GET_INSTRUCTION(Op_leq); + return lasttok = RELOP; + } + yylval = GET_INSTRUCTION(Op_less); + pushback(); + return lasttok = '<'; + + case '=': + if (nextc(true) == '=') { + yylval = GET_INSTRUCTION(Op_equal); + return lasttok = RELOP; + } + yylval = GET_INSTRUCTION(Op_assign); + pushback(); + return lasttok = ASSIGN; + + case '>': + if ((c = nextc(true)) == '=') { + yylval = GET_INSTRUCTION(Op_geq); + return lasttok = RELOP; + } else if (c == '>') { + yylval = GET_INSTRUCTION(Op_symbol); + yylval->redir_type = redirect_append; + return lasttok = IO_OUT; + } + pushback(); + if (in_print && in_parens == 0) { + yylval = GET_INSTRUCTION(Op_symbol); + yylval->redir_type = redirect_output; + return lasttok = IO_OUT; + } + yylval = GET_INSTRUCTION(Op_greater); + return lasttok = '>'; + + case '~': + yylval = GET_INSTRUCTION(Op_match); + return lasttok = MATCHOP; + + case '}': + /* + * Added did newline stuff. Easier than + * hacking the grammar. + */ + if (did_newline) { + did_newline = false; + if (--in_braces == 0) + lastline = sourceline; + return lasttok = c; + } + did_newline = true; + --lexptr; /* pick up } next time */ + return lasttok = NEWLINE; + + case '"': + string: + esc_seen = false; + /* + * Allow any kind of junk in quoted string, + * so pass false to nextc(). + */ + while ((c = nextc(false)) != '"') { + if (c == '\n') { + pushback(); + yyerror(_("unterminated string")); + return lasttok = LEX_EOF; + } + if ((gawk_mb_cur_max == 1 || nextc_is_1stbyte) && + c == '\\') { + c = nextc(true); + if (c == '\r') /* allow MS-DOS files. bleah */ + c = nextc(true); + if (c == '\n') { + sourceline++; + continue; + } + esc_seen = true; + if (! want_source || c != '"') + tokadd('\\'); + } + if (c == END_FILE) { + pushback(); + yyerror(_("unterminated string")); + return lasttok = LEX_EOF; + } + tokadd(c); + } + yylval = GET_INSTRUCTION(Op_token); + if (want_source) { + 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); + if (intlstr) { + yylval->memory->flags |= INTLSTR; + intlstr = false; + if (do_intl) + dumpintlstr(yylval->memory->stptr, yylval->memory->stlen); + } + return lasttok = YSTRING; + + case '-': + if ((c = nextc(true)) == '=') { + yylval = GET_INSTRUCTION(Op_assign_minus); + return lasttok = ASSIGNOP; + } + if (c == '-') { + yylval = GET_INSTRUCTION(Op_symbol); + return lasttok = DECREMENT; + } + pushback(); + yylval = GET_INSTRUCTION(Op_minus); + return lasttok = '-'; + + case '.': + c = nextc(true); + pushback(); + if (! isdigit(c)) + return lasttok = '.'; + else + c = '.'; + /* FALL THROUGH */ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + /* It's a number */ + for (;;) { + bool gotnumber = false; + + tokadd(c); + switch (c) { + case 'x': + case 'X': + if (do_traditional) + goto done; + if (tok == tokstart + 2) { + int peek = nextc(true); + + if (isxdigit(peek)) { + inhex = true; + pushback(); /* following digit */ + } else { + pushback(); /* x or X */ + goto done; + } + } + break; + case '.': + /* period ends exponent part of floating point number */ + if (seen_point || seen_e) { + gotnumber = true; + break; + } + seen_point = true; + break; + case 'e': + case 'E': + if (inhex) + break; + if (seen_e) { + gotnumber = true; + break; + } + seen_e = true; + if ((c = nextc(true)) == '-' || c == '+') { + int c2 = nextc(true); + + if (isdigit(c2)) { + tokadd(c); + tokadd(c2); + } else { + pushback(); /* non-digit after + or - */ + pushback(); /* + or - */ + pushback(); /* e or E */ + } + } else if (! isdigit(c)) { + pushback(); /* character after e or E */ + pushback(); /* e or E */ + } else { + pushback(); /* digit */ + } + break; + case 'a': + case 'A': + case 'b': + case 'B': + case 'c': + case 'C': + case 'D': + case 'd': + case 'f': + case 'F': + if (do_traditional || ! inhex) + goto done; + /* fall through */ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + break; + default: + done: + gotnumber = true; + } + if (gotnumber) + break; + c = nextc(true); + } + pushback(); + + tokadd('\0'); + yylval = GET_INSTRUCTION(Op_push_i); + + base = 10; + if (! do_traditional) { + base = get_numbase(tokstart, strlen(tokstart)-1, false); + if (do_lint) { + if (base == 8) + lintwarn("numeric constant `%.*s' treated as octal", + (int) strlen(tokstart)-1, tokstart); + else if (base == 16) + lintwarn("numeric constant `%.*s' treated as hexadecimal", + (int) strlen(tokstart)-1, tokstart); + } + } + +#ifdef HAVE_MPFR + if (do_mpfr) { + NODE *r; + + if (! seen_point && ! seen_e) { + r = mpg_integer(); + mpg_strtoui(r->mpg_i, tokstart, strlen(tokstart), NULL, base); + errno = 0; + } else { + int tval; + r = mpg_float(); + tval = mpfr_strtofr(r->mpg_numbr, tokstart, NULL, base, ROUND_MODE); + errno = 0; + IEEE_FMT(r->mpg_numbr, tval); + } + yylval->memory = set_profile_text(r, tokstart, strlen(tokstart)-1); + return lasttok = YNUMBER; + } +#endif + if (base != 10) + d = nondec2awknum(tokstart, strlen(tokstart)-1, NULL); + else + d = atof(tokstart); + 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; + + case '&': + if ((c = nextc(true)) == '&') { + yylval = GET_INSTRUCTION(Op_and); + allow_newline(); + return lasttok = LEX_AND; + } + pushback(); + yylval = GET_INSTRUCTION(Op_symbol); + return lasttok = '&'; + + case '|': + if ((c = nextc(true)) == '|') { + yylval = GET_INSTRUCTION(Op_or); + allow_newline(); + return lasttok = LEX_OR; + } else if (! do_traditional && c == '&') { + yylval = GET_INSTRUCTION(Op_symbol); + yylval->redir_type = redirect_twoway; + return lasttok = (in_print && in_parens == 0 ? IO_OUT : IO_IN); + } + pushback(); + if (in_print && in_parens == 0) { + yylval = GET_INSTRUCTION(Op_symbol); + yylval->redir_type = redirect_pipe; + return lasttok = IO_OUT; + } else { + yylval = GET_INSTRUCTION(Op_symbol); + yylval->redir_type = redirect_pipein; + return lasttok = IO_IN; + } + } + + if (! is_letter(c)) { + yyerror(_("invalid char '%c' in expression"), c); + return lasttok = LEX_EOF; + } + + /* + * Lots of fog here. Consider: + * + * print "xyzzy"$_"foo" + * + * Without the check for ` lasttok != '$' ', this is parsed as + * + * print "xxyzz" $(_"foo") + * + * With the check, it is "correctly" parsed as three + * string concatenations. Sigh. This seems to be + * "more correct", but this is definitely one of those + * occasions where the interactions are funny. + */ + if (! do_traditional && c == '_' && lasttok != '$') { + if ((c = nextc(true)) == '"') { + intlstr = true; + goto string; + } + pushback(); + c = '_'; + } + + /* it's some type of name-type-thing. Find its length. */ + tok = tokstart; + while (c != END_FILE && is_identchar(c)) { + tokadd(c); + c = nextc(true); + } + tokadd('\0'); + pushback(); + + /* See if it is a special token. */ + if ((mid = check_special(tokstart)) >= 0) { + static int warntab[sizeof(tokentab) / sizeof(tokentab[0])]; + int class = tokentab[mid].class; + + if ((class == LEX_INCLUDE || class == LEX_LOAD || class == LEX_EVAL) + && lasttok != '@') + goto out; + + /* 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"), + tokentab[mid].operator); + warntab[mid] |= GAWKX; + } + if ((tokentab[mid].flags & NOT_POSIX) != 0 && (warntab[mid] & NOT_POSIX) == 0) { + lintwarn(_("POSIX does not allow `%s'"), + tokentab[mid].operator); + warntab[mid] |= NOT_POSIX; + } + } + if (do_lint_old && (tokentab[mid].flags & NOT_OLD) != 0 + && (warntab[mid] & NOT_OLD) == 0 + ) { + warning(_("`%s' is not supported in old awk"), + tokentab[mid].operator); + warntab[mid] |= NOT_OLD; + } + + if ((tokentab[mid].flags & BREAK) != 0) + break_allowed++; + if ((tokentab[mid].flags & CONTINUE) != 0) + continue_allowed++; + + switch (class) { + case LEX_INCLUDE: + case LEX_LOAD: + want_source = true; + break; + case LEX_EVAL: + if (in_main_context()) + goto out; + emalloc(tokkey, char *, tok - tokstart + 1, "yylex"); + tokkey[0] = '@'; + memcpy(tokkey + 1, tokstart, tok - tokstart); + yylval = GET_INSTRUCTION(Op_token); + yylval->lextok = tokkey; + break; + + case LEX_FUNCTION: + case LEX_BEGIN: + case LEX_END: + case LEX_BEGINFILE: + case LEX_ENDFILE: + yylval = bcalloc(tokentab[mid].value, 3, sourceline); + break; + + case LEX_FOR: + case LEX_WHILE: + case LEX_DO: + case LEX_SWITCH: + if (! do_pretty_print) + return lasttok = class; + /* fall through */ + case LEX_CASE: + yylval = bcalloc(tokentab[mid].value, 2, sourceline); + break; + + /* + * These must be checked here, due to the LALR nature of the parser, + * the rules for continue and break may not be reduced until after + * a token that increments the xxx_allowed varibles is seen. Bleah. + */ + case LEX_CONTINUE: + if (! continue_allowed) { + error_ln(sourceline, + _("`continue' is not allowed outside a loop")); + errcount++; + } + goto make_instruction; + + case LEX_BREAK: + if (! break_allowed) { + error_ln(sourceline, + _("`break' is not allowed outside a loop or switch")); + errcount++; + } + goto make_instruction; + + default: +make_instruction: + yylval = GET_INSTRUCTION(tokentab[mid].value); + if (class == LEX_BUILTIN || class == LEX_LENGTH) + yylval->builtin_idx = mid; + break; + } + return lasttok = class; + } +out: + tokkey = estrdup(tokstart, tok - tokstart); + if (*lexptr == '(') { + yylval = bcalloc(Op_token, 2, sourceline); + yylval->lextok = tokkey; + return lasttok = FUNC_CALL; + } else { + static bool goto_warned = false; + + yylval = GET_INSTRUCTION(Op_token); + yylval->lextok = tokkey; + +#define SMART_ALECK 1 + if (SMART_ALECK && do_lint + && ! goto_warned && strcasecmp(tokkey, "goto") == 0) { + goto_warned = true; + lintwarn(_("`goto' considered harmful!\n")); + } + return lasttok = NAME; + } + +#undef GET_INSTRUCTION +#undef NEWLINE_EOF +} + +/* It's EBCDIC in a Bison grammar, run for the hills! + + Or, convert single-character tokens coming out of yylex() from EBCDIC to + ASCII values on-the-fly so that the parse tables need not be regenerated + for EBCDIC systems. */ +#ifdef USE_EBCDIC +static int +yylex(void) +{ + static char etoa_xlate[256]; + static int do_etoa_init = 1; + int tok; + + if (do_etoa_init) + { + for (tok = 0; tok < 256; tok++) + etoa_xlate[tok] = (char) tok; +#ifdef HAVE___ETOA_L + /* IBM helpfully provides this function. */ + __etoa_l(etoa_xlate, sizeof(etoa_xlate)); +#else +# error "An EBCDIC-to-ASCII translation function is needed for this system" +#endif + do_etoa_init = 0; + } + + tok = yylex_ebcdic(); + + if (tok >= 0 && tok <= 0xFF) + tok = etoa_xlate[tok]; + + return tok; +} +#endif /* USE_EBCDIC */ + +/* snode --- instructions for builtin functions. Checks for arg. count + and supplies defaults where possible. */ + +static INSTRUCTION * +snode(INSTRUCTION *subn, INSTRUCTION *r) +{ + INSTRUCTION *arg; + INSTRUCTION *ip; + NODE *n; + int nexp = 0; + int args_allowed; + int idx = r->builtin_idx; + + if (subn != NULL) { + INSTRUCTION *tp; + for (tp = subn->nexti; tp; tp = tp->nexti) { + tp = tp->lasti; + nexp++; + } + assert(nexp > 0); + } + + /* check against how many args. are allowed for this builtin */ + args_allowed = tokentab[idx].flags & ARGS; + if (args_allowed && (args_allowed & A(nexp)) == 0) { + yyerror(_("%d is invalid as number of arguments for %s"), + nexp, tokentab[idx].operator); + return NULL; + } + + /* special processing for sub, gsub and gensub */ + + if (tokentab[idx].value == Op_sub_builtin) { + const char *operator = tokentab[idx].operator; + + r->sub_flags = 0; + + arg = subn->nexti; /* first arg list */ + (void) mk_rexp(arg); + + if (strcmp(operator, "gensub") != 0) { + /* sub and gsub */ + + if (strcmp(operator, "gsub") == 0) + r->sub_flags |= GSUB; + + arg = arg->lasti->nexti; /* 2nd arg list */ + if (nexp == 2) { + INSTRUCTION *expr; + + expr = list_create(instruction(Op_push_i)); + expr->nexti->memory = set_profile_text(make_number(0.0), "0", 1); + (void) mk_expression_list(subn, + list_append(expr, instruction(Op_field_spec))); + } + + arg = arg->lasti->nexti; /* third arg list */ + ip = arg->lasti; + if (ip->opcode == Op_push_i) { + if (do_lint) + lintwarn(_("%s: string literal as last arg of substitute has no effect"), + operator); + r->sub_flags |= LITERAL; + } else { + if (make_assignable(ip) == NULL) + yyerror(_("%s third parameter is not a changeable object"), + operator); + else + ip->do_reference = true; + } + + r->expr_count = count_expressions(&subn, false); + ip = subn->lasti; + + (void) list_append(subn, r); + + /* add after_assign code */ + if (ip->opcode == Op_push_lhs && ip->memory->type == Node_var && ip->memory->var_assign) { + (void) list_append(subn, instruction(Op_var_assign)); + subn->lasti->assign_ctxt = Op_sub_builtin; + subn->lasti->assign_var = ip->memory->var_assign; + } else if (ip->opcode == Op_field_spec_lhs) { + (void) list_append(subn, instruction(Op_field_assign)); + subn->lasti->assign_ctxt = Op_sub_builtin; + subn->lasti->field_assign = (Func_ptr) 0; + ip->target_assign = subn->lasti; + } else if (ip->opcode == Op_subscript_lhs) { + (void) list_append(subn, instruction(Op_subscript_assign)); + subn->lasti->assign_ctxt = Op_sub_builtin; + } + + return subn; + + } else { + /* gensub */ + + r->sub_flags |= GENSUB; + if (nexp == 3) { + ip = instruction(Op_push_i); + 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))); + } + + r->expr_count = count_expressions(&subn, false); + return list_append(subn, r); + } + } + +#ifdef HAVE_MPFR + /* N.B.: If necessary, add special processing for alternate builtin, below */ + if (do_mpfr && tokentab[idx].ptr2) + r->builtin = tokentab[idx].ptr2; + else +#endif + r->builtin = tokentab[idx].ptr; + + /* special case processing for a few builtins */ + + if (r->builtin == do_length) { + if (nexp == 0) { + /* no args. Use $0 */ + + INSTRUCTION *list; + 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 = 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 || r->builtin == do_typeof) { + arg = subn->nexti; + if (arg->nexti == arg->lasti && arg->nexti->opcode == Op_push) + arg->nexti->opcode = Op_push_arg_untyped; /* argument may be untyped */ +#ifdef SUPPLY_INTDIV + } 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; +#endif /* SUPPLY_INTDIV */ + } else if (r->builtin == do_match) { + static bool warned = false; + + arg = subn->nexti->lasti->nexti; /* 2nd arg list */ + (void) mk_rexp(arg); + + if (nexp == 3) { /* 3rd argument there */ + if (do_lint && ! warned) { + warned = true; + lintwarn(_("match: third argument is a gawk extension")); + } + if (do_traditional) { + yyerror(_("match: third argument is a gawk extension")); + return NULL; + } + + arg = arg->lasti->nexti; /* third arg list */ + ip = arg->lasti; + if (/*ip == arg->nexti && */ ip->opcode == Op_push) + ip->opcode = Op_push_array; + } + } else if (r->builtin == do_split) { + arg = subn->nexti->lasti->nexti; /* 2nd arg list */ + ip = arg->lasti; + if (ip->opcode == Op_push) + ip->opcode = Op_push_array; + if (nexp == 2) { + INSTRUCTION *expr; + expr = list_create(instruction(Op_push)); + expr->nexti->memory = FS_node; + (void) mk_expression_list(subn, expr); + } + arg = arg->lasti->nexti; + n = mk_rexp(arg); + if (nexp == 2) + n->re_flags |= FS_DFLT; + if (nexp == 4) { + arg = arg->lasti->nexti; + ip = arg->lasti; + if (ip->opcode == Op_push) + ip->opcode = Op_push_array; + } + } else if (r->builtin == do_patsplit) { + arg = subn->nexti->lasti->nexti; /* 2nd arg list */ + ip = arg->lasti; + if (ip->opcode == Op_push) + ip->opcode = Op_push_array; + if (nexp == 2) { + INSTRUCTION *expr; + expr = list_create(instruction(Op_push)); + expr->nexti->memory = FPAT_node; + (void) mk_expression_list(subn, expr); + } + arg = arg->lasti->nexti; + n = mk_rexp(arg); + if (nexp == 4) { + arg = arg->lasti->nexti; + ip = arg->lasti; + if (ip->opcode == Op_push) + ip->opcode = Op_push_array; + } + } else if (r->builtin == do_close) { + static bool warned = false; + if (nexp == 2) { + if (do_lint && ! warned) { + warned = true; + lintwarn(_("close: second argument is a gawk extension")); + } + if (do_traditional) { + yyerror(_("close: second argument is a gawk extension")); + return NULL; + } + } + } 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 & STRING) != 0) { /* it's a string constant */ + /* ala xgettext, dcgettext("some string" ...) dumps the string */ + NODE *str = subn->nexti->lasti->memory; + + if ((str->flags & INTLSTR) != 0) + warning(_("use of dcgettext(_\"...\") is incorrect: remove leading underscore")); + /* don't dump it, the lexer already did */ + else + dumpintlstr(str->stptr, str->stlen); + } 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 & 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 & 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; + + if (((str1->flags | str2->flags) & INTLSTR) != 0) + warning(_("use of dcngettext(_\"...\") is incorrect: remove leading underscore")); + else + dumpintlstr2(str1->stptr, str1->stlen, str2->stptr, str2->stlen); + } else if (r->builtin == do_asort || r->builtin == do_asorti) { + arg = subn->nexti; /* 1st arg list */ + ip = arg->lasti; + if (ip->opcode == Op_push) + ip->opcode = Op_push_array; + if (nexp >= 2) { + arg = ip->nexti; + ip = arg->lasti; + if (ip->opcode == Op_push) + ip->opcode = Op_push_array; + } + } + else if (r->builtin == do_index) { + arg = subn->nexti->lasti->nexti; /* 2nd arg list */ + ip = arg->lasti; + if (ip->opcode == Op_match_rec) + fatal(_("index: regexp constant as second argument is not allowed")); + } +#ifdef ARRAYDEBUG + else if (r->builtin == do_adump) { + ip = subn->nexti->lasti; + if (ip->opcode == Op_push) + ip->opcode = Op_push_array; + } +#endif + + if (subn != NULL) { + r->expr_count = count_expressions(&subn, false); + return list_append(subn, r); + } + + r->expr_count = 0; + return list_create(r); +} + + +/* parms_shadow --- check if parameters shadow globals */ + +static int +parms_shadow(INSTRUCTION *pc, bool *shadow) +{ + int pcount, i; + bool ret = false; + NODE *func, *fp; + char *fname; + + func = pc->func_body; + fname = func->vname; + fp = func->fparms; + +#if 0 /* can't happen, already exited if error ? */ + if (fname == NULL || func == NULL) /* error earlier */ + return false; +#endif + + pcount = func->param_cnt; + + if (pcount == 0) /* no args, no problem */ + return 0; + + source = pc->source_file; + sourceline = pc->source_line; + /* + * Use warning() and not lintwarn() so that can warn + * about all shadowed parameters. + */ + for (i = 0; i < pcount; i++) { + if (lookup(fp[i].param) != NULL) { + warning( + _("function `%s': parameter `%s' shadows global variable"), + fname, fp[i].param); + ret = true; + } + } + + *shadow |= ret; + return 0; +} + +/* valinfo --- dump var info */ + +void +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"); + } else if ((n->flags & NUMBER) != 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)); +} + + +/* dump_vars --- dump the symbol table */ + +void +dump_vars(const char *fname) +{ + FILE *fp; + NODE **vars; + + if (fname == NULL) + fp = stderr; + else if (strcmp(fname, "-") == 0) + fp = stdout; + else if ((fp = fopen(fname, "w")) == NULL) { + warning(_("could not open `%s' for writing (%s)"), fname, strerror(errno)); + warning(_("sending variable list to standard error")); + fp = stderr; + } + + vars = variable_list(); + print_vars(vars, fprintf, fp); + efree(vars); + if (fp != stdout && fp != stderr && fclose(fp) != 0) + warning(_("%s: close failed (%s)"), fname, strerror(errno)); +} + +/* dump_funcs --- print all functions */ + +void +dump_funcs() +{ + NODE **funcs; + funcs = function_list(true); + (void) foreach_func(funcs, (int (*)(INSTRUCTION *, void *)) pp_func, (void *) 0); + efree(funcs); +} + + +/* shadow_funcs --- check all functions for parameters that shadow globals */ + +void +shadow_funcs() +{ + static int calls = 0; + bool shadow = false; + NODE **funcs; + + if (calls++ != 0) + fatal(_("shadow_funcs() called twice!")); + + funcs = function_list(true); + (void) foreach_func(funcs, (int (*)(INSTRUCTION *, void *)) parms_shadow, & shadow); + efree(funcs); + + /* End with fatal if the user requested it. */ + if (shadow && lintfunc == r_fatal) + lintwarn(_("there were shadowed variables.")); +} + + +/* mk_function --- finalize function definition node; remove parameters + * out of the symbol table. + */ + +static INSTRUCTION * +mk_function(INSTRUCTION *fi, INSTRUCTION *def) +{ + NODE *thisfunc; + + thisfunc = fi->func_body; + assert(thisfunc != NULL); + + if (do_optimize && def->lasti->opcode == Op_pop) { + /* tail call which does not return any value. */ + + INSTRUCTION *t; + + for (t = def->nexti; t->nexti != def->lasti; t = t->nexti) + ; + if (t->opcode == Op_func_call + && strcmp(t->func_name, thisfunc->vname) == 0) + (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 + */ + + (void) list_append(def, instruction(Op_push_i)); + def->lasti->memory = dupnode(Nnull_string); + (void) list_append(def, instruction(Op_K_return)); + + if (do_pretty_print) + (void) list_prepend(def, instruction(Op_exec_count)); + + /* fi->opcode = Op_func */ + (fi + 1)->firsti = def->nexti; + (fi + 1)->lasti = def->lasti; + (fi + 2)->first_line = fi->source_line; + (fi + 2)->last_line = lastline; + fi->nexti = def->nexti; + bcfree(def); + + (void) list_append(rule_list, fi + 1); /* debugging */ + + /* update lint table info */ + func_use(thisfunc->vname, FUNC_DEFINE); + + /* remove params from symbol table */ + remove_params(thisfunc); + return fi; +} + +/* + * install_function: + * install function name in the symbol table. + * Extra work, build up and install a list of the parameter names. + */ + +static int +install_function(char *fname, INSTRUCTION *fi, INSTRUCTION *plist) +{ + NODE *r, *f; + int pcount = 0; + + r = lookup(fname); + if (r != NULL) { + error_ln(fi->source_line, _("function name `%s' previously defined"), fname); + return -1; + } + + if (plist != NULL) + pcount = plist->lasti->param_count + 1; + f = install_symbol(fname, Node_func); + fi->func_body = f; + f->param_cnt = pcount; + f->code_ptr = fi; + f->fparms = NULL; + if (pcount > 0) { + char **pnames; + pnames = check_params(fname, pcount, plist); /* frees plist */ + f->fparms = make_params(pnames, pcount); + efree(pnames); + install_params(f); + } + return 0; +} + + +/* check_params --- build a list of function parameter names after + * making sure that the names are valid and there are no duplicates. + */ + +static char ** +check_params(char *fname, int pcount, INSTRUCTION *list) +{ + INSTRUCTION *p, *np; + int i, j; + char *name; + char **pnames; + + assert(pcount > 0); + + emalloc(pnames, char **, pcount * sizeof(char *), "check_params"); + + for (i = 0, p = list->nexti; p != NULL; i++, p = np) { + np = p->nexti; + name = p->lextok; + p->lextok = NULL; + + if (strcmp(name, fname) == 0) { + /* check for function foo(foo) { ... }. bleah. */ + error_ln(p->source_line, + _("function `%s': can't use function name as parameter name"), fname); + } else if (is_std_var(name)) { + error_ln(p->source_line, + _("function `%s': can't use special variable `%s' as a function parameter"), + fname, name); + } + + /* check for duplicate parameters */ + for (j = 0; j < i; j++) { + if (strcmp(name, pnames[j]) == 0) { + error_ln(p->source_line, + _("function `%s': parameter #%d, `%s', duplicates parameter #%d"), + fname, i + 1, name, j + 1); + } + } + + pnames[i] = name; + bcfree(p); + } + bcfree(list); + + return pnames; +} + + +#ifdef HASHSIZE +undef HASHSIZE +#endif +#define HASHSIZE 1021 + +static struct fdesc { + char *name; + short used; + short defined; + short extension; + struct fdesc *next; +} *ftable[HASHSIZE]; + +/* func_use --- track uses and definitions of functions */ + +static void +func_use(const char *name, enum defref how) +{ + struct fdesc *fp; + int len; + int ind; + + len = strlen(name); + ind = hash(name, len, HASHSIZE, NULL); + + for (fp = ftable[ind]; fp != NULL; fp = fp->next) + if (strcmp(fp->name, name) == 0) + goto update_value; + + /* not in the table, fall through to allocate a new one */ + + 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]; + ftable[ind] = fp; + +update_value: + if (how == FUNC_DEFINE) + fp->defined++; + else if (how == FUNC_EXT) { + fp->defined++; + fp->extension++; + } else + fp->used++; +} + +/* track_ext_func --- add an extension function to the table */ + +void +track_ext_func(const char *name) +{ + func_use(name, FUNC_EXT); +} + +/* check_funcs --- verify functions that are called but not defined */ + +static void +check_funcs() +{ + struct fdesc *fp, *next; + int i; + + if (! in_main_context()) + goto free_mem; + + for (i = 0; i < HASHSIZE; i++) { + for (fp = ftable[i]; fp != NULL; fp = fp->next) { +#ifdef REALLYMEAN + /* making this the default breaks old code. sigh. */ + if (fp->defined == 0 && ! fp->extension) { + error( + _("function `%s' called but never defined"), fp->name); + errcount++; + } +#else + if (do_lint && fp->defined == 0 && ! fp->extension) + lintwarn( + _("function `%s' called but never defined"), fp->name); +#endif + + if (do_lint && fp->used == 0 && ! fp->extension) { + lintwarn(_("function `%s' defined but never called directly"), + fp->name); + } + } + } + +free_mem: + /* now let's free all the memory */ + for (i = 0; i < HASHSIZE; i++) { + for (fp = ftable[i]; fp != NULL; fp = next) { + next = fp->next; + efree(fp->name); + efree(fp); + } + ftable[i] = NULL; + } +} + +/* param_sanity --- look for parameters that are regexp constants */ + +static void +param_sanity(INSTRUCTION *arglist) +{ + INSTRUCTION *argl, *arg; + int i = 1; + + if (arglist == NULL) + return; + for (argl = arglist->nexti; argl; ) { + arg = argl->lasti; + if (arg->opcode == Op_match_rec) + warning_ln(arg->source_line, + _("regexp constant for parameter #%d yields boolean value"), i); + argl = arg->nexti; + i++; + } +} + +/* variable --- make sure NAME is in the symbol table */ + +NODE * +variable(int location, char *name, NODETYPE type) +{ + NODE *r; + + if ((r = lookup(name)) != NULL) { + if (r->type == Node_func || r->type == Node_ext_func ) + error_ln(location, _("function `%s' called with space between name and `(',\nor used as a variable or an array"), + r->vname); + } else { + /* not found */ + return install_symbol(name, type); + } + efree(name); + return r; +} + +/* make_regnode --- make a regular expression node */ + +NODE * +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[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; + } + n->re_exp = exp; + n->re_flags = CONSTANT; + } + return n; +} + + +/* mk_rexp --- make a regular expression constant */ + +static NODE * +mk_rexp(INSTRUCTION *list) +{ + INSTRUCTION *ip; + + 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); + ip->nexti = list->lasti->nexti; + list->lasti->nexti = ip; + list->lasti = ip; + } + return ip->memory; +} + +#ifndef NO_LINT +/* isnoeffect --- when used as a statement, has no side effects */ + +static int +isnoeffect(OPCODE type) +{ + switch (type) { + case Op_times: + case Op_times_i: + case Op_quotient: + case Op_quotient_i: + case Op_mod: + case Op_mod_i: + case Op_plus: + case Op_plus_i: + case Op_minus: + case Op_minus_i: + case Op_subscript: + case Op_concat: + case Op_exp: + case Op_exp_i: + case Op_unary_minus: + case Op_field_spec: + case Op_and_final: + case Op_or_final: + case Op_equal: + case Op_notequal: + case Op_less: + case Op_greater: + case Op_leq: + case Op_geq: + case Op_match: + case Op_nomatch: + case Op_match_rec: + case Op_not: + case Op_in_array: + return true; + default: + break; /* keeps gcc -Wall happy */ + } + + return false; +} +#endif /* NO_LINT */ + + +/* make_assignable --- make this operand an assignable one if posiible */ + +static INSTRUCTION * +make_assignable(INSTRUCTION *ip) +{ + switch (ip->opcode) { + case Op_push: + ip->opcode = Op_push_lhs; + return ip; + case Op_field_spec: + ip->opcode = Op_field_spec_lhs; + return ip; + case Op_subscript: + ip->opcode = Op_subscript_lhs; + return ip; + default: + break; /* keeps gcc -Wall happy */ + } + return NULL; +} + +/* stopme --- for debugging */ + +NODE * +stopme(int nargs ATTRIBUTE_UNUSED) +{ + return make_number(0.0); +} + +/* dumpintlstr --- write out an initial .po file entry for the string */ + +static void +dumpintlstr(const char *str, size_t len) +{ + char *cp; + + /* See the GNU gettext distribution for details on the file format */ + + if (source != NULL) { + /* ala the gettext sources, remove leading `./'s */ + for (cp = source; cp[0] == '.' && cp[1] == '/'; cp += 2) + continue; + printf("#: %s:%d\n", cp, sourceline); + } + + printf("msgid "); + pp_string_fp(fprintf, stdout, str, len, '"', true); + putchar('\n'); + printf("msgstr \"\"\n\n"); + fflush(stdout); +} + +/* dumpintlstr2 --- write out an initial .po file entry for the string and its plural */ + +static void +dumpintlstr2(const char *str1, size_t len1, const char *str2, size_t len2) +{ + char *cp; + + /* See the GNU gettext distribution for details on the file format */ + + if (source != NULL) { + /* ala the gettext sources, remove leading `./'s */ + for (cp = source; cp[0] == '.' && cp[1] == '/'; cp += 2) + continue; + printf("#: %s:%d\n", cp, sourceline); + } + + printf("msgid "); + pp_string_fp(fprintf, stdout, str1, len1, '"', true); + putchar('\n'); + printf("msgid_plural "); + pp_string_fp(fprintf, stdout, str2, len2, '"', true); + putchar('\n'); + printf("msgstr[0] \"\"\nmsgstr[1] \"\"\n\n"); + fflush(stdout); +} + +/* mk_binary --- instructions for binary operators */ + +static INSTRUCTION * +mk_binary(INSTRUCTION *s1, INSTRUCTION *s2, INSTRUCTION *op) +{ + INSTRUCTION *ip1,*ip2; + AWKNUM res; + + ip2 = s2->nexti; + if (s2->lasti == ip2 && ip2->opcode == Op_push_i) { + /* do any numeric constant folding */ + ip1 = s1->nexti; + if (do_optimize + && ip1 == s1->lasti && ip1->opcode == Op_push_i + && (ip1->memory->flags & (MPFN|MPZN|STRCUR|STRING)) == 0 + && (ip2->memory->flags & (MPFN|MPZN|STRCUR|STRING)) == 0 + ) { + NODE *n1 = ip1->memory, *n2 = ip2->memory; + res = force_number(n1)->numbr; + (void) force_number(n2); + switch (op->opcode) { + case Op_times: + res *= n2->numbr; + break; + case Op_quotient: + if (n2->numbr == 0.0) { + /* don't fatalize, allow parsing rest of the input */ + error_ln(op->source_line, _("division by zero attempted")); + goto regular; + } + + res /= n2->numbr; + break; + case Op_mod: + if (n2->numbr == 0.0) { + /* don't fatalize, allow parsing rest of the input */ + error_ln(op->source_line, _("division by zero attempted in `%%'")); + goto regular; + } +#ifdef HAVE_FMOD + res = fmod(res, n2->numbr); +#else /* ! HAVE_FMOD */ + (void) modf(res / n2->numbr, &res); + res = n1->numbr - res * n2->numbr; +#endif /* ! HAVE_FMOD */ + break; + case Op_plus: + res += n2->numbr; + break; + case Op_minus: + res -= n2->numbr; + break; + case Op_exp: + res = calc_exp(res, n2->numbr); + break; + default: + goto regular; + } + + 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); + bcfree(ip1); + bcfree(ip2); + bcfree(s1); + bcfree(s2); + return list_create(op); + } else { + /* do basic arithmetic optimisation */ + /* convert (Op_push_i Node_val) + (Op_plus) to (Op_plus_i Node_val) */ + switch (op->opcode) { + case Op_times: + op->opcode = Op_times_i; + break; + case Op_quotient: + op->opcode = Op_quotient_i; + break; + case Op_mod: + op->opcode = Op_mod_i; + break; + case Op_plus: + op->opcode = Op_plus_i; + break; + case Op_minus: + op->opcode = Op_minus_i; + break; + case Op_exp: + op->opcode = Op_exp_i; + break; + default: + goto regular; + } + + op->memory = ip2->memory; + bcfree(ip2); + bcfree(s2); /* Op_list */ + return list_append(s1, op); + } + } + +regular: + /* append lists s1, s2 and add `op' bytecode */ + (void) list_merge(s1, s2); + return list_append(s1, op); +} + +/* mk_boolean --- instructions for boolean and, or */ + +static INSTRUCTION * +mk_boolean(INSTRUCTION *left, INSTRUCTION *right, INSTRUCTION *op) +{ + INSTRUCTION *tp; + OPCODE opc, final_opc; + + opc = op->opcode; /* Op_and or Op_or */ + final_opc = (opc == Op_or) ? Op_or_final : Op_and_final; + + add_lint(right, LINT_assign_in_cond); + + tp = left->lasti; + + if (tp->opcode != final_opc) { /* x || y */ + list_append(right, instruction(final_opc)); + add_lint(left, LINT_assign_in_cond); + (void) list_append(left, op); + left->lasti->target_jmp = right->lasti; + + /* NB: target_stmt points to previous Op_and(Op_or) in a chain; + * target_stmt only used in the parser (see below). + */ + + left->lasti->target_stmt = left->lasti; + 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; + tp->opcode = opc; + tp->target_jmp = op; + + /* update jump targets */ + for (ip = tp->target_stmt; ; ip = ip->target_stmt) { + assert(ip->opcode == opc); + assert(ip->target_jmp == tp); + /* if (ip->opcode == opc && ip->target_jmp == tp) */ + ip->target_jmp = op; + if (ip->target_stmt == ip) + break; + } + } + + return list_merge(left, right); +} + +/* mk_condition --- if-else and conditional */ + +static INSTRUCTION * +mk_condition(INSTRUCTION *cond, INSTRUCTION *ifp, INSTRUCTION *true_branch, + INSTRUCTION *elsep, INSTRUCTION *false_branch) +{ + /* + * ---------------- + * cond + * ---------------- + * t: [Op_jmp_false f ] + * ---------------- + * true_branch + * + * ---------------- + * [Op_jmp y] + * ---------------- + * f: + * false_branch + * ---------------- + * y: [Op_no_op] + * ---------------- + */ + + INSTRUCTION *ip; + bool setup_else_part = true; + + if (false_branch == NULL) { + false_branch = list_create(instruction(Op_no_op)); + if (elsep == NULL) { /* else { } */ + setup_else_part = false; + } + } else { + /* assert(elsep != NULL); */ + + /* avoid a series of no_op's: if .. else if .. else if .. */ + if (false_branch->lasti->opcode != Op_no_op) + (void) list_append(false_branch, instruction(Op_no_op)); + } + + if (setup_else_part) { + if (do_pretty_print) { + (void) list_prepend(false_branch, elsep); + false_branch->nexti->branch_end = false_branch->lasti; + (void) list_prepend(false_branch, instruction(Op_exec_count)); + } else + bcfree(elsep); + } + + (void) list_prepend(false_branch, instruction(Op_jmp)); + false_branch->nexti->target_jmp = false_branch->lasti; + + add_lint(cond, LINT_assign_in_cond); + ip = list_append(cond, instruction(Op_jmp_false)); + ip->lasti->target_jmp = false_branch->nexti->nexti; + + if (do_pretty_print) { + (void) list_prepend(ip, ifp); + (void) list_append(ip, instruction(Op_exec_count)); + ip->nexti->branch_if = ip->lasti; + ip->nexti->branch_else = false_branch->nexti; + } else + bcfree(ifp); + + if (true_branch != NULL) + list_merge(ip, true_branch); + return list_merge(ip, false_branch); +} + +enum defline { FIRST_LINE, LAST_LINE }; + +/* find_line -- find the first(last) line in a list of (pattern) instructions */ + +static int +find_line(INSTRUCTION *pattern, enum defline what) +{ + INSTRUCTION *ip; + int lineno = 0; + + for (ip = pattern->nexti; ip; ip = ip->nexti) { + if (what == LAST_LINE) { + if (ip->source_line > lineno) + lineno = ip->source_line; + } else { /* FIRST_LINE */ + if (ip->source_line > 0 + && (lineno == 0 || ip->source_line < lineno)) + lineno = ip->source_line; + } + if (ip == pattern->lasti) + break; + } + assert(lineno > 0); + return lineno; +} + +/* append_rule --- pattern-action instructions */ + +static INSTRUCTION * +append_rule(INSTRUCTION *pattern, INSTRUCTION *action) +{ + /* + * ---------------- + * pattern + * ---------------- + * [Op_jmp_false f ] + * ---------------- + * action + * ---------------- + * f: [Op_no_op ] + * ---------------- + */ + + INSTRUCTION *rp; + INSTRUCTION *tp; + INSTRUCTION *ip; + + if (rule != Rule) { + rp = pattern; + if (do_pretty_print) + (void) list_append(action, instruction(Op_no_op)); + (rp + 1)->firsti = action->nexti; + (rp + 1)->lasti = action->lasti; + (rp + 2)->first_line = pattern->source_line; + (rp + 2)->last_line = lastline; + if (block_comment != NULL) { + ip = list_prepend(list_prepend(action, block_comment), rp); + block_comment = NULL; + } else + ip = list_prepend(action, rp); + + } else { + rp = bcalloc(Op_rule, 3, 0); + rp->in_rule = Rule; + rp->source_file = source; + tp = instruction(Op_no_op); + + if (pattern == NULL) { + /* assert(action != NULL); */ + if (do_pretty_print) + (void) list_prepend(action, instruction(Op_exec_count)); + (rp + 1)->firsti = action->nexti; + (rp + 1)->lasti = tp; + (rp + 2)->first_line = firstline; + (rp + 2)->last_line = lastline; + rp->source_line = firstline; + ip = list_prepend(list_append(action, tp), rp); + } else { + (void) list_append(pattern, instruction(Op_jmp_false)); + pattern->lasti->target_jmp = tp; + (rp + 2)->first_line = find_line(pattern, FIRST_LINE); + rp->source_line = (rp + 2)->first_line; + if (action == NULL) { + (rp + 2)->last_line = find_line(pattern, LAST_LINE); + action = list_create(instruction(Op_K_print_rec)); + if (do_pretty_print) + (void) list_prepend(action, instruction(Op_exec_count)); + } else + (rp + 2)->last_line = lastline; + + if (do_pretty_print) { + (void) list_prepend(pattern, instruction(Op_exec_count)); + (void) list_prepend(action, instruction(Op_exec_count)); + } + (rp + 1)->firsti = action->nexti; + (rp + 1)->lasti = tp; + ip = list_append( + list_merge(list_prepend(pattern, rp), + action), + tp); + } + } + + list_append(rule_list, rp + 1); + + if (rule_block[rule] == NULL) + rule_block[rule] = ip; + else + (void) list_merge(rule_block[rule], ip); + + return rule_block[rule]; +} + +/* mk_assignment --- assignment bytecodes */ + +static INSTRUCTION * +mk_assignment(INSTRUCTION *lhs, INSTRUCTION *rhs, INSTRUCTION *op) +{ + INSTRUCTION *tp; + INSTRUCTION *ip; + + tp = lhs->lasti; + switch (tp->opcode) { + case Op_field_spec: + tp->opcode = Op_field_spec_lhs; + break; + case Op_subscript: + tp->opcode = Op_subscript_lhs; + break; + case Op_push: + case Op_push_array: + tp->opcode = Op_push_lhs; + break; + case Op_field_assign: + yyerror(_("cannot assign a value to the result of a field post-increment expression")); + break; + default: + yyerror(_("invalid target of assignment (opcode %s)"), + opcode2str(tp->opcode)); + break; + } + + tp->do_reference = (op->opcode != Op_assign); /* check for uninitialized reference */ + + if (rhs != NULL) + ip = list_merge(rhs, lhs); + else + ip = lhs; + + (void) list_append(ip, op); + + if (tp->opcode == Op_push_lhs + && tp->memory->type == Node_var + && tp->memory->var_assign + ) { + tp->do_reference = false; /* no uninitialized reference checking + * for a special variable. + */ + (void) list_append(ip, instruction(Op_var_assign)); + ip->lasti->assign_var = tp->memory->var_assign; + } else if (tp->opcode == Op_field_spec_lhs) { + (void) list_append(ip, instruction(Op_field_assign)); + ip->lasti->field_assign = (Func_ptr) 0; + tp->target_assign = ip->lasti; + } else if (tp->opcode == Op_subscript_lhs) { + (void) list_append(ip, instruction(Op_subscript_assign)); + } + + return ip; +} + +/* optimize_assignment --- peephole optimization for assignment */ + +static INSTRUCTION * +optimize_assignment(INSTRUCTION *exp) +{ + INSTRUCTION *i1, *i2, *i3; + + /* + * Optimize assignment statements array[subs] = x; var = x; $n = x; + * string concatenation of the form s = s t. + * + * 1) Array element assignment array[subs] = x: + * 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. + * + * 3) Field assignment $n = x: + * Replaces Op_field_spec_lhs + Op_assign + Op_field_assign + Op_pop + * with Op_store_field. + * + * 4) Optimization for string concatenation: + * For cases like x = x y, uses realloc to include y in x; + * also eliminates instructions Op_push_lhs and Op_pop. + */ + + /* + * N.B.: do not append Op_pop instruction to the returned + * instruction list if optimized. None of these + * optimized instructions pushes the r-value of assignment + * onto the runtime stack. + */ + + i2 = NULL; + i1 = exp->lasti; + + if ( i1->opcode != Op_assign + && i1->opcode != Op_field_assign) + return list_append(exp, instruction(Op_pop)); + + for (i2 = exp->nexti; i2 != i1; i2 = i2->nexti) { + switch (i2->opcode) { + case Op_concat: + if (i2->nexti->opcode == Op_push_lhs /* l.h.s is a simple variable */ + && (i2->concat_flag & CSVAR) != 0 /* 1st exp in r.h.s is a simple variable; + * see Op_concat in the grammer above. + */ + && i2->nexti->memory == exp->nexti->memory /* and the same as in l.h.s */ + && i2->nexti->nexti == i1 + && i1->opcode == Op_assign + ) { + /* s = s ... optimization */ + + /* avoid stuff like x = x (x = y) or x = x gsub(/./, "b", x); + * check for l-value reference to this variable in the r.h.s. + * Also, avoid function calls in general to guard against + * global variable assignment. + */ + + for (i3 = exp->nexti->nexti; i3 != i2; i3 = i3->nexti) { + if ((i3->opcode == Op_push_lhs && i3->memory == i2->nexti->memory) + || i3->opcode == Op_func_call) + return list_append(exp, instruction(Op_pop)); /* no optimization */ + } + + /* remove the variable from r.h.s */ + i3 = exp->nexti; + exp->nexti = i3->nexti; + bcfree(i3); + + if (--i2->expr_count == 1) /* one less expression in Op_concat */ + i2->opcode = Op_no_op; + + i3 = i2->nexti; + assert(i3->opcode == Op_push_lhs); + i3->opcode = Op_assign_concat; /* change Op_push_lhs to Op_assign_concat */ + i3->nexti = NULL; + bcfree(i1); /* Op_assign */ + exp->lasti = i3; /* update Op_list */ + return exp; + } + break; + + case Op_field_spec_lhs: + if (i2->nexti->opcode == Op_assign + && i2->nexti->nexti == i1 + && i1->opcode == Op_field_assign + ) { + /* $n = .. */ + i2->opcode = Op_store_field; + bcfree(i2->nexti); /* Op_assign */ + i2->nexti = NULL; + bcfree(i1); /* Op_field_assign */ + exp->lasti = i2; /* update Op_list */ + return exp; + } + break; + + case Op_push_array: + if (i2->nexti->nexti->opcode == Op_subscript_lhs) { + i3 = i2->nexti->nexti; + if (i3->sub_count == 1 + && i3->nexti == i1 + && i1->opcode == Op_assign + ) { + /* array[sub] = .. */ + i3->opcode = Op_store_sub; + i3->memory = i2->memory; + i3->expr_count = 1; /* sub_count shadows memory, + * so use expr_count instead. + */ + i3->nexti = NULL; + i2->opcode = Op_no_op; + bcfree(i1); /* Op_assign */ + exp->lasti = i3; /* update Op_list */ + return exp; + } + } + break; + + case Op_push_lhs: + if (i2->nexti == i1 + && i1->opcode == Op_assign + ) { + /* var = .. */ + i2->opcode = Op_store_var; + i2->nexti = NULL; + bcfree(i1); /* Op_assign */ + exp->lasti = i2; /* update Op_list */ + + i3 = exp->nexti; + if (i3->opcode == Op_push_i + && (i3->memory->flags & INTLSTR) == 0 + && i3->nexti == i2 + ) { + /* constant initializer */ + i2->initval = i3->memory; + bcfree(i3); + exp->nexti = i2; + } else + i2->initval = NULL; + + return exp; + } + break; + + default: + break; + } + } + + /* no optimization */ + return list_append(exp, instruction(Op_pop)); +} + + +/* mk_getline --- make instructions for getline */ + +static INSTRUCTION * +mk_getline(INSTRUCTION *op, INSTRUCTION *var, INSTRUCTION *redir, int redirtype) +{ + INSTRUCTION *ip; + INSTRUCTION *tp; + INSTRUCTION *asgn = NULL; + + /* + * getline [var] < [file] + * + * [ file (simp_exp)] + * [ [ var ] ] + * [ Op_K_getline_redir|NULL|redir_type|into_var] + * [ [var_assign] ] + * + */ + + if (redir == NULL) { + int sline = op->source_line; + bcfree(op); + op = bcalloc(Op_K_getline, 2, sline); + (op + 1)->target_endfile = ip_endfile; + (op + 1)->target_beginfile = ip_beginfile; + } + + if (var != NULL) { + tp = make_assignable(var->lasti); + assert(tp != NULL); + + /* check if we need after_assign bytecode */ + if (tp->opcode == Op_push_lhs + && tp->memory->type == Node_var + && tp->memory->var_assign + ) { + asgn = instruction(Op_var_assign); + asgn->assign_ctxt = op->opcode; + asgn->assign_var = tp->memory->var_assign; + } else if (tp->opcode == Op_field_spec_lhs) { + asgn = instruction(Op_field_assign); + asgn->assign_ctxt = op->opcode; + asgn->field_assign = (Func_ptr) 0; /* determined at run time */ + tp->target_assign = asgn; + } else if (tp->opcode == Op_subscript_lhs) { + asgn = instruction(Op_subscript_assign); + asgn->assign_ctxt = op->opcode; + } + + if (redir != NULL) { + ip = list_merge(redir, var); + (void) list_append(ip, op); + } else + ip = list_append(var, op); + } else if (redir != NULL) + ip = list_append(redir, op); + else + ip = list_create(op); + op->into_var = (var != NULL); + op->redir_type = (redir != NULL) ? redirtype : redirect_none; + + return (asgn == NULL ? ip : list_append(ip, asgn)); +} + + +/* mk_for_loop --- for loop bytecodes */ + +static INSTRUCTION * +mk_for_loop(INSTRUCTION *forp, INSTRUCTION *init, INSTRUCTION *cond, + INSTRUCTION *incr, INSTRUCTION *body) +{ + /* + * ------------------------ + * init (may be NULL) + * ------------------------ + * x: + * cond (Op_no_op if NULL) + * ------------------------ + * [ Op_jmp_false tb ] + * ------------------------ + * body (may be NULL) + * ------------------------ + * tc: + * incr (may be NULL) + * [ Op_jmp x ] + * ------------------------ + * tb:[ Op_no_op ] + */ + + INSTRUCTION *ip, *tbreak, *tcont; + INSTRUCTION *jmp; + INSTRUCTION *pp_cond; + INSTRUCTION *ret; + + tbreak = instruction(Op_no_op); + + if (cond != NULL) { + add_lint(cond, LINT_assign_in_cond); + pp_cond = cond->nexti; + ip = cond; + (void) list_append(ip, instruction(Op_jmp_false)); + ip->lasti->target_jmp = tbreak; + } else { + pp_cond = instruction(Op_no_op); + ip = list_create(pp_cond); + } + + if (init != NULL) + ip = list_merge(init, ip); + + if (do_pretty_print) { + (void) list_append(ip, instruction(Op_exec_count)); + (forp + 1)->forloop_cond = pp_cond; + (forp + 1)->forloop_body = ip->lasti; + } + + if (body != NULL) + (void) list_merge(ip, body); + + jmp = instruction(Op_jmp); + jmp->target_jmp = pp_cond; + if (incr == NULL) + tcont = jmp; + else { + tcont = incr->nexti; + (void) list_merge(ip, incr); + } + + (void) list_append(ip, jmp); + ret = list_append(ip, tbreak); + fix_break_continue(ret, tbreak, tcont); + + if (do_pretty_print) { + forp->target_break = tbreak; + forp->target_continue = tcont; + ret = list_prepend(ret, forp); + } /* else + forp is NULL */ + + return ret; +} + +/* add_lint --- add lint warning bytecode if needed */ + +static void +add_lint(INSTRUCTION *list, LINTTYPE linttype) +{ +#ifndef NO_LINT + INSTRUCTION *ip; + + switch (linttype) { + case LINT_assign_in_cond: + ip = list->lasti; + if (ip->opcode == Op_var_assign || ip->opcode == Op_field_assign) { + assert(ip != list->nexti); + for (ip = list->nexti; ip->nexti != list->lasti; ip = ip->nexti) + ; + } + + if (ip->opcode == Op_assign || ip->opcode == Op_assign_concat) { + list_append(list, instruction(Op_lint)); + list->lasti->lint_type = linttype; + } + break; + + case LINT_no_effect: + if (list->lasti->opcode == Op_pop && list->nexti != list->lasti) { + 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)) { + 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 */ + list_append(list, instruction(Op_lint)); + list->lasti->lint_type = linttype; + } + } + break; + + default: + break; + } +#endif +} + +/* mk_expression_list --- list of bytecode lists */ + +static INSTRUCTION * +mk_expression_list(INSTRUCTION *list, INSTRUCTION *s1) +{ + INSTRUCTION *r; + + /* 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| ... ]------ + * | + * [Op_list| ... ] -- | + * ... | | + * ... <------- | + * [Op_list| ... ] -- | + * ... | | + * ... | | + * ... <------- -- + */ + + assert(s1 != NULL && s1->opcode == Op_list); + if (list == NULL) { + list = instruction(Op_list); + list->nexti = s1; + list->lasti = s1->lasti; + return list; + } + + /* append expression to the end of the list */ + + r = list->lasti; + r->nexti = s1; + list->lasti = s1->lasti; + return list; +} + +/* count_expressions --- fixup expression_list from mk_expression_list. + * returns no of expressions in list. isarg is true + * for function arguments. + */ + +static int +count_expressions(INSTRUCTION **list, bool isarg) +{ + INSTRUCTION *expr; + INSTRUCTION *r = NULL; + int count = 0; + + if (*list == NULL) /* error earlier */ + return 0; + + for (expr = (*list)->nexti; expr; ) { + INSTRUCTION *t1, *t2; + t1 = expr->nexti; + t2 = expr->lasti; + if (isarg && t1 == t2 && t1->opcode == Op_push) + t1->opcode = Op_push_param; + if (++count == 1) + r = expr; + else + (void) list_merge(r, expr); + expr = t2->nexti; + } + + assert(count > 0); + if (! isarg && count > max_args) + max_args = count; + bcfree(*list); + *list = r; + return count; +} + +/* fix_break_continue --- fix up break & continue codes in loop bodies */ + +static void +fix_break_continue(INSTRUCTION *list, INSTRUCTION *b_target, INSTRUCTION *c_target) +{ + INSTRUCTION *ip; + + list->lasti->nexti = NULL; /* just to make sure */ + + for (ip = list->nexti; ip != NULL; ip = ip->nexti) { + switch (ip->opcode) { + case Op_K_break: + if (ip->target_jmp == NULL) + ip->target_jmp = b_target; + break; + + case Op_K_continue: + if (ip->target_jmp == NULL) + ip->target_jmp = c_target; + break; + + default: + /* this is to keep the compiler happy. sheesh. */ + break; + } + } +} + +static inline INSTRUCTION * +list_create(INSTRUCTION *x) +{ + INSTRUCTION *l; + + l = instruction(Op_list); + l->nexti = x; + l->lasti = x; + return l; +} + +static inline INSTRUCTION * +list_append(INSTRUCTION *l, INSTRUCTION *x) +{ +#ifdef GAWKDEBUG + if (l->opcode != Op_list) + cant_happen(); +#endif + l->lasti->nexti = x; + l->lasti = x; + return l; +} + +static inline INSTRUCTION * +list_prepend(INSTRUCTION *l, INSTRUCTION *x) +{ +#ifdef GAWKDEBUG + if (l->opcode != Op_list) + cant_happen(); +#endif + x->nexti = l->nexti; + l->nexti = x; + return l; +} + +static inline INSTRUCTION * +list_merge(INSTRUCTION *l1, INSTRUCTION *l2) +{ +#ifdef GAWKDEBUG + if (l1->opcode != Op_list) + cant_happen(); + if (l2->opcode != Op_list) + cant_happen(); +#endif + l1->lasti->nexti = l2->nexti; + l1->lasti = l2->lasti; + bcfree(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 +check_special(const char *name) +{ + int low, high, mid; + int i; + int non_standard_flags = 0; +#ifdef USE_EBCDIC + static bool did_sort = false; + + if (! did_sort) { + qsort((void *) tokentab, + sizeof(tokentab) / sizeof(tokentab[0]), + sizeof(tokentab[0]), tokcompare); + did_sort = true; + } +#endif + + if (do_traditional) + non_standard_flags |= GAWKX; + if (do_posix) + non_standard_flags |= NOT_POSIX; + + low = 0; + high = (sizeof(tokentab) / sizeof(tokentab[0])) - 1; + while (low <= high) { + mid = (low + high) / 2; + i = *name - tokentab[mid].operator[0]; + if (i == 0) + i = strcmp(name, tokentab[mid].operator); + + if (i < 0) /* token < mid */ + high = mid - 1; + else if (i > 0) /* token > mid */ + low = mid + 1; + else { + if ((tokentab[mid].flags & non_standard_flags) != 0) + return -1; + return mid; + } + } + return -1; +} + +/* + * This provides a private version of functions that act like VMS's + * variable-length record filesystem, where there was a bug on + * certain source files. + */ + +static FILE *fp = NULL; + +/* read_one_line --- return one input line at a time. mainly for debugging. */ + +static ssize_t +read_one_line(int fd, void *buffer, size_t count) +{ + char buf[BUFSIZ]; + + /* Minor potential memory leak here. Too bad. */ + if (fp == NULL) { + fp = fdopen(fd, "r"); + if (fp == NULL) { + fprintf(stderr, "ugh. fdopen: %s\n", strerror(errno)); + gawk_exit(EXIT_FAILURE); + } + } + + if (fgets(buf, sizeof buf, fp) == NULL) + return 0; + + memcpy(buffer, buf, strlen(buf)); + return strlen(buf); +} + +/* one_line_close --- close the open file being read with read_one_line() */ + +static int +one_line_close(int fd) +{ + int ret; + + if (fp == NULL || fd != fileno(fp)) + fatal("debugging read/close screwed up!"); + + ret = fclose(fp); + fp = NULL; + return ret; +} + + +/* lookup_builtin --- find a builtin function or return NULL */ + +builtin_func_t +lookup_builtin(const char *name) +{ + int mid = check_special(name); + + if (mid == -1) + return NULL; + + switch (tokentab[mid].class) { + case LEX_BUILTIN: + case LEX_LENGTH: + break; + default: + return NULL; + } + + /* And another special case... */ + if (tokentab[mid].value == Op_sub_builtin) + return (builtin_func_t) do_sub; + +#ifdef HAVE_MPFR + if (do_mpfr) + return tokentab[mid].ptr2; +#endif + + return tokentab[mid].ptr; +} + +/* install_builtins --- add built-in functions to FUNCTAB */ + +void +install_builtins(void) +{ + int i, j; + int flags_that_must_be_clear = DEBUG_USE; + + if (do_traditional) + flags_that_must_be_clear |= GAWKX; + + if (do_posix) + flags_that_must_be_clear |= NOT_POSIX; + + + j = sizeof(tokentab) / sizeof(tokentab[0]); + for (i = 0; i < j; i++) { + if ( (tokentab[i].class == LEX_BUILTIN + || tokentab[i].class == LEX_LENGTH) + && (tokentab[i].flags & flags_that_must_be_clear) == 0) { + (void) install_symbol(tokentab[i].operator, Node_builtin_func); + } + } +} + +/* + * 9/2014: Gawk cannot use isalpha or isalnum when + * parsing the program since that can let through non-English + * letters. So, we supply our own. !@#$%^&*()-ing locales! + */ + +/* is_alpha --- return true if c is an English letter */ + +/* + * 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. + */ + +bool +is_alpha(int c) +{ +#ifdef I_DONT_KNOW_WHAT_IM_DOING + return isalpha(c); +#else /* ! I_DONT_KNOW_WHAT_IM_DOING */ + switch (c) { + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': + case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': + case 's': case 't': case 'u': case 'v': case 'w': case 'x': + case 'y': case 'z': + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': + case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': + case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': + case 'Y': case 'Z': + return true; + } + return false; +#endif /* ! I_DONT_KNOW_WHAT_IM_DOING */ +} + +/* is_alnum --- return true for alphanumeric, English only letters */ + +bool +is_alnum(int c) +{ + /* digit test is good for EBCDIC too. so there. */ + return (is_alpha(c) || ('0' <= c && c <= '9')); +} + + +/* + * is_letter --- function to check letters + * isalpha() isn't good enough since it can look at the locale. + * Underscore counts as a letter in awk identifiers + */ + +bool +is_letter(int c) +{ + return (is_alpha(c) || c == '_'); +} + +/* is_identchar --- return true if c can be in an identifier */ + +bool +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; +#ifdef HAVE_MPFR + n->strndmode = MPFR_round_mode; +#endif + } + + return n; +} diff --git a/awklib/ChangeLog b/awklib/ChangeLog new file mode 100644 index 0000000..17fb3ca --- /dev/null +++ b/awklib/ChangeLog @@ -0,0 +1,87 @@ +2018-02-25 Arnold D. Robbins + + * 4.2.1: Release tar ball made. + +2017-10-19 Arnold D. Robbins + + * 4.2.0: Release tar ball made. + +2016-08-25 Arnold D. Robbins + + * 4.1.4: Release tar ball made. + +2015-08-28 Daniel Richard G. + + * Makefile.am: Build pwcat.c and grcat.c with (copied) + source in the current directory, so that (1) we can use + Automake-generated build rules instead of rolling our own, and + (2) Automake doesn't then admonish us to enable subdir-objects + due to the source files being in another directory. + * Makefile.am: Make the $(srcdir)/stamp-eg rule depend + on gawktexi.in instead of the gawk.texi file that is generated + from same, so that the build doesn't break if the latter is + missing. + +2015-06-19 Arnold D. Robbins + + * extract.awk: Sync with current version in the doc. Thanks to + Antonio Columbo for pointing this out. + +2015-05-19 Arnold D. Robbins + + * 4.1.3: Release tar ball made. + +2015-04-29 Arnold D. Robbins + + * 4.1.2: Release tar ball made. + +2014-11-05 Juergen Kahrs + + * Makefile.am (AWKPROG): Add quotes around the name in case the + build dir has spaces in it. + +2014-10-17 Andrew J. Schorr + + * Makefile.am (stamp-eg): Use explicit ./extract.awk to avoid + assumptions about AWKPATH in the environment. + +2014-04-08 Arnold D. Robbins + + * 4.1.1: Release tar ball made. + +2014-03-17 Arnold D. Robbins + + * Makefile.am (clean-local): Clean up .dSYM directories for Mac OS X. + Thanks to Hermann Piefer for the suggestion. + +2013-05-09 Arnold D. Robbins + + * 4.1.0: Release tar ball made. + +2013-02-03 Arnold D. Robbins + + * Makefile.am (AWKPROG): Add definition and conditional for + cross compiling. Thanks to Juergen Kahrs. + +2013-01-08 Andrew J. Schorr + + * eg/lib/inplace.awk: Add new file generated from doc/gawk.texi. + +2012-12-24 Arnold D. Robbins + + * 4.0.2: Release tar ball made. + +2012-03-28 Arnold D. Robbins + + * 4.0.1: Release tar ball made. + +2011-06-24 Arnold D. Robbins + + * Makefile.am (EXTRA_DIST): Add ChangeLog.0. + * 4.0.0: Remake the tar ball. + +2011-06-23 Arnold D. Robbins + + * ChangeLog.0: Rotated ChangeLog into this file. + * ChangeLog: Created anew for gawk 4.0.0 and on. + * 4.0.0: Release tar ball made. diff --git a/awklib/ChangeLog.0 b/awklib/ChangeLog.0 new file mode 100644 index 0000000..e3f24da --- /dev/null +++ b/awklib/ChangeLog.0 @@ -0,0 +1,180 @@ +Mon Jan 10 21:40:05 2011 Andreas Buening + + * Makefile.am (AWKPROG): Get correct path to gawk executable. + +Fri Nov 19 11:53:16 2010 Arnold D. Robbins + + * Makefile.am: Remove special handling of CVS directories. + +Thu May 6 20:55:14 2010 Arnold D. Robbins + + * Release 3.1.8: Release tar file made. + +Tue Jul 21 22:28:56 2009 Arnold D. Robbins + + * Release 3.1.7: Release tar file made. + +Mon Oct 22 08:49:05 2007 Arnold D. Robbins + + * Release 3.1.6: Release tar file made. + +2007-05-25 Andreas Schwab + + * Makefile.am: Add missing dependencies on stamp-eg. + +Wed Mar 14 13:22:52 2007 Andrew J. Schorr + + * Makefile.am (AWKPROG): New macro to set locale sanely. + (stamp-eg): Use it instead of $AWK to do the extractions. + +Wed Mar 14 13:16:28 2007 Arnold D. Robbins + + * Makefile.am (clean-local): Remove `eg.old' also. + +Sat Jan 13 21:17:33 2007 Ralf Wildenhues + + * Makefile.am (stamp-eg): Allow rebuilding from a VPATH build. + +Tue Jul 26 21:46:16 2005 Arnold D. Robbins + + * Release 3.1.5: Release tar file made. + +Mon Jun 20 23:20:22 2005 Andreas Schwab + + * Makefile.am: Install pwcat and grcat in pkglibexecdir instead of + libexecdir. + +Wed Feb 9 10:13:27 2005 Arnold D. Robbins + + * Makefile.am (pkgdatadir, pkglibexecdir): Use $(datadir) and + $(libexecdir) instead of @datadir@ and @libexecdir@ for coolest + GNU Coding Standards compatibility and functionality. Per Stepan + Kasal. + +Tue Feb 8 18:57:08 2005 Arnold D. Robbins + + * Makefile.am (pkgdatadir, pkglibexecdir): New variables for compatibility + with current GNU Coding Standards. Fixed uses. Thanks to Stepan Kasal + and the discussion in bug-gnu-utils. + +Mon Aug 2 12:18:15 2004 Arnold D. Robbins + + * Release 3.1.4: Release tar file made. + +Thu Mar 18 17:43:59 2004 Arnold D. Robbins + + * Makefile.am (INCLUDES): Renamed to AM_CPPFLAGS. Per + Stepan Kasal. + +Mon Jul 7 11:01:43 2003 Arnold D. Robbins + + * Release 3.1.3: Release tar file made. + +Wed Mar 19 14:10:31 2003 Arnold D. Robbins + + This time for sure. + -- Bullwinkle + + * Release 3.1.2: Release tar file made. + +Thu Oct 10 13:24:09 2002 Arnold D. Robbins + + * Makefile.am (INCLUDES): Added to get .. for build dir + which will have config.h in it. + (grcat,pwcat): Use $(COMPILE) instead of $(CC) to get + $(INCLUDES) included. + +Tue Jun 11 23:43:36 2002 Arnold D. Robbins + + * Makefile.am (grcat): Add def for config.h and -I flag. + +Wed May 1 16:41:32 2002 Arnold D. Robbins + + * Release 3.1.1: Release tar file made. + +Wed Apr 17 15:20:27 2002 Arnold D. Robbins + + * Makefile.am (clean): Add *.exe to list of files to be cleaned. + +2002-01-27 Bruno Haible + + * eg/lib/libintl.awk (dcngettext): New function. + +Sun Jun 3 13:04:44 2001 Arnold D. Robbins + + * Release 3.1.0: Release tar file made. And there was + rejoicing. + +2001-02-26 Paul Eggert + + * Makefile.am (stamp-eg): Use $(AWK), not awk, as the + native awk might not work. + +2001-02-26 Andreas Schwab + + * Makefile.am: Install igawk as script. + +Mon Nov 6 15:29:08 2000 Arnold D. Robbins + + * Makefile.am: Fixed to have all functionality from before + the switch to automake. + * extract.awk: Updated to match version in the doc. + +Sat Jul 26 23:08:29 1997 Arnold D. Robbins + + * Makefile.in (install-strip): new target. + +Mon Aug 7 15:23:00 2000 Arnold D. Robbins + + * Release 3.0.6: Release tar file made. + +Sun Jun 25 15:08:19 2000 Arnold D. Robbins + + * Release 3.0.5: Release tar file made. + +Wed Jun 30 16:14:36 1999 Arnold D. Robbins + + * Release 3.0.4: Release tar file made. This time for sure. + +Thu May 15 12:49:08 1997 Arnold D. Robbins + + * Release 3.0.3: Release tar file made. + +Fri Apr 18 07:55:47 1997 Arnold D. Robbins + + * BETA Release 3.0.34: Release tar file made. + +Sun Apr 13 15:40:55 1997 Arnold D. Robbins + + * Makefile.in (install): fix second for loop to use $$i. Sigh. + +Wed Dec 25 11:25:22 1996 Arnold D. Robbins + + * Release 3.0.2: Release tar file made. + +Wed Dec 25 11:17:32 1996 Arnold D. Robbins + + * Makefile.in (install): remove chmod command; let + $(INSTALL_PROGRAM) use -m. + +Tue Dec 17 22:29:49 1996 Arnold D. Robbins + + * Makefile.in (install): fix installation of files in eg/lib. + +Tue Dec 10 23:09:26 1996 Arnold D. Robbins + + * Release 3.0.1: Release tar file made. + +Sun Oct 20 12:30:41 1996 Arnold D. Robbins + + * Makefile.in (install): minor tweaks for portability. + +Fri Mar 15 06:33:38 1996 Arnold D. Robbins + + * Makefile.in (pwcat, grcat): Add $(LDFLAGS). + (clean): add `*~' to list of files to be removed. + +Wed Jan 24 10:06:16 1996 Arnold D. Robbins + + * Makefile.in (clean): Remove $(AUXAWK). + (maintainer-clean): Depend on distclean, not the other way around. diff --git a/awklib/Makefile.am b/awklib/Makefile.am new file mode 100644 index 0000000..902c193 --- /dev/null +++ b/awklib/Makefile.am @@ -0,0 +1,90 @@ +# +# awklib/Makefile.am --- automake input file for gawk +# +# Copyright (C) 1995-2006 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 + +EXTRA_DIST = ChangeLog ChangeLog.0 extract.awk eg $(srcdir)/stamp-eg +# With some locales, the script extract.awk fails. +# So we fix the locale to some sensible value. + +if TEST_CROSS_COMPILE +AWKPROG = LC_ALL=C LANG=C awk$(EXEEXT) +else +AWKPROG = LC_ALL=C LANG=C "$(abs_top_builddir)/gawk$(EXEEXT)" +endif + +# Get config.h from the build directory and custom.h from the source directory. +AM_CPPFLAGS = -I$(top_builddir) -I$(top_srcdir) + +pkgdatadir = $(datadir)/awk +pkglibexecdir = $(libexecdir)/awk + +pkglibexec_PROGRAMS = pwcat grcat +AUXAWK = passwd.awk group.awk +nodist_grcat_SOURCES = grcat.c +nodist_pwcat_SOURCES = pwcat.c + +CLEANFILES = $(nodist_grcat_SOURCES) $(nodist_pwcat_SOURCES) + +all: $(srcdir)/stamp-eg $(AUXPROGS) $(AUXAWK) + +install-exec-hook: $(AUXAWK) + $(mkinstalldirs) $(DESTDIR)$(pkgdatadir) + for i in $(AUXAWK) $(srcdir)/eg/lib/*.awk ; do \ + progname=`echo $$i | sed 's;.*/;;'` ; \ + $(INSTALL_DATA) $$i $(DESTDIR)$(pkgdatadir)/$$progname ; \ + done + +# pkglibexecdir and pkgdatadir are removed in the top level Makefile's uninstall +uninstall-local: + rm -fr $(DESTDIR)$(pkglibexecdir)/* $(DESTDIR)$(pkgdatadir)/* + +clean-local: + rm -f $(AUXAWK) *.exe + rm -fr eg.old + rm -fr grcat.dSYM pwcat.dSYM + +$(srcdir)/stamp-eg: $(srcdir)/../doc/gawktexi.in $(srcdir)/../doc/gawkinet.texi + cd $(srcdir) && \ + rm -fr eg && \ + rm -fr stamp-eg && \ + $(AWKPROG) -f ./extract.awk ../doc/gawktexi.in ../doc/gawkinet.texi + @echo 'some makes are stupid and will not check a directory' > $(srcdir)/stamp-eg + @echo 'against a file, so this file is a place holder. gack.' >> $(srcdir)/stamp-eg + +pwcat.c: $(srcdir)/eg/lib/pwcat.c + rm -f $@ + $(LN_S) $(srcdir)/eg/lib/pwcat.c . + +grcat.c: $(srcdir)/eg/lib/grcat.c + rm -f $@ + $(LN_S) $(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; @: + +passwd.awk: $(srcdir)/eg/lib/passwdawk.in + sed 's;/usr/local/libexec/awk;$(pkglibexecdir);' < $(srcdir)/eg/lib/passwdawk.in > passwd.awk + +group.awk: $(srcdir)/eg/lib/groupawk.in + sed 's;/usr/local/libexec/awk;$(pkglibexecdir);' < $(srcdir)/eg/lib/groupawk.in > group.awk diff --git a/awklib/Makefile.in b/awklib/Makefile.in new file mode 100644 index 0000000..16f8132 --- /dev/null +++ b/awklib/Makefile.in @@ -0,0 +1,703 @@ +# 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@ + +# +# awklib/Makefile.am --- automake input file for gawk +# +# Copyright (C) 1995-2006 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)) +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@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@ +pkglibexec_PROGRAMS = pwcat$(EXEEXT) grcat$(EXEEXT) +subdir = awklib +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__installdirs = "$(DESTDIR)$(pkglibexecdir)" +PROGRAMS = $(pkglibexec_PROGRAMS) +nodist_grcat_OBJECTS = grcat.$(OBJEXT) +grcat_OBJECTS = $(nodist_grcat_OBJECTS) +grcat_LDADD = $(LDADD) +nodist_pwcat_OBJECTS = pwcat.$(OBJEXT) +pwcat_OBJECTS = $(nodist_pwcat_OBJECTS) +pwcat_LDADD = $(LDADD) +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 = $(nodist_grcat_SOURCES) $(nodist_pwcat_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__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) +pkgdatadir = $(datadir)/awk +pkglibexecdir = $(libexecdir)/awk +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@ +EXTRA_DIST = ChangeLog ChangeLog.0 extract.awk eg $(srcdir)/stamp-eg +@TEST_CROSS_COMPILE_FALSE@AWKPROG = LC_ALL=C LANG=C "$(abs_top_builddir)/gawk$(EXEEXT)" +# With some locales, the script extract.awk fails. +# So we fix the locale to some sensible value. +@TEST_CROSS_COMPILE_TRUE@AWKPROG = LC_ALL=C LANG=C awk$(EXEEXT) + +# Get config.h from the build directory and custom.h from the source directory. +AM_CPPFLAGS = -I$(top_builddir) -I$(top_srcdir) +AUXAWK = passwd.awk group.awk +nodist_grcat_SOURCES = grcat.c +nodist_pwcat_SOURCES = pwcat.c +CLEANFILES = $(nodist_grcat_SOURCES) $(nodist_pwcat_SOURCES) +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 awklib/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu awklib/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-pkglibexecPROGRAMS: $(pkglibexec_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(pkglibexec_PROGRAMS)'; test -n "$(pkglibexecdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(pkglibexecdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(pkglibexecdir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + 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; \ + else { print "f", $$3 "/" $$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_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(pkglibexecdir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(pkglibexecdir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-pkglibexecPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(pkglibexec_PROGRAMS)'; test -n "$(pkglibexecdir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkglibexecdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkglibexecdir)" && rm -f $$files + +clean-pkglibexecPROGRAMS: + -test -z "$(pkglibexec_PROGRAMS)" || rm -f $(pkglibexec_PROGRAMS) + +grcat$(EXEEXT): $(grcat_OBJECTS) $(grcat_DEPENDENCIES) $(EXTRA_grcat_DEPENDENCIES) + @rm -f grcat$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(grcat_OBJECTS) $(grcat_LDADD) $(LIBS) + +pwcat$(EXEEXT): $(pwcat_OBJECTS) $(pwcat_DEPENDENCIES) $(EXTRA_pwcat_DEPENDENCIES) + @rm -f pwcat$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(pwcat_OBJECTS) $(pwcat_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/grcat.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pwcat.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 $(PROGRAMS) +installdirs: + for dir in "$(DESTDIR)$(pkglibexecdir)"; 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: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +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-local clean-pkglibexecPROGRAMS \ + 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-pkglibexecPROGRAMS + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-exec-hook +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: uninstall-local uninstall-pkglibexecPROGRAMS + +.MAKE: install-am install-exec-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + 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-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) $(AUXAWK) + +install-exec-hook: $(AUXAWK) + $(mkinstalldirs) $(DESTDIR)$(pkgdatadir) + for i in $(AUXAWK) $(srcdir)/eg/lib/*.awk ; do \ + progname=`echo $$i | sed 's;.*/;;'` ; \ + $(INSTALL_DATA) $$i $(DESTDIR)$(pkgdatadir)/$$progname ; \ + done + +# pkglibexecdir and pkgdatadir are removed in the top level Makefile's uninstall +uninstall-local: + rm -fr $(DESTDIR)$(pkglibexecdir)/* $(DESTDIR)$(pkgdatadir)/* + +clean-local: + rm -f $(AUXAWK) *.exe + rm -fr eg.old + rm -fr grcat.dSYM pwcat.dSYM + +$(srcdir)/stamp-eg: $(srcdir)/../doc/gawktexi.in $(srcdir)/../doc/gawkinet.texi + cd $(srcdir) && \ + rm -fr eg && \ + rm -fr stamp-eg && \ + $(AWKPROG) -f ./extract.awk ../doc/gawktexi.in ../doc/gawkinet.texi + @echo 'some makes are stupid and will not check a directory' > $(srcdir)/stamp-eg + @echo 'against a file, so this file is a place holder. gack.' >> $(srcdir)/stamp-eg + +pwcat.c: $(srcdir)/eg/lib/pwcat.c + rm -f $@ + $(LN_S) $(srcdir)/eg/lib/pwcat.c . + +grcat.c: $(srcdir)/eg/lib/grcat.c + rm -f $@ + $(LN_S) $(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; @: + +passwd.awk: $(srcdir)/eg/lib/passwdawk.in + sed 's;/usr/local/libexec/awk;$(pkglibexecdir);' < $(srcdir)/eg/lib/passwdawk.in > passwd.awk + +group.awk: $(srcdir)/eg/lib/groupawk.in + sed 's;/usr/local/libexec/awk;$(pkglibexecdir);' < $(srcdir)/eg/lib/groupawk.in > group.awk + +# 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/awklib/eg/data/class_data1 b/awklib/eg/data/class_data1 new file mode 100644 index 0000000..864c284 --- /dev/null +++ b/awklib/eg/data/class_data1 @@ -0,0 +1,3 @@ +Biology_101 sum average data: 87.0 92.4 78.5 94.9 +Chemistry_305 sum average data: 75.2 98.3 94.7 88.2 +English_401 sum average data: 100.0 95.6 87.1 93.4 diff --git a/awklib/eg/data/class_data2 b/awklib/eg/data/class_data2 new file mode 100644 index 0000000..f5de0e2 --- /dev/null +++ b/awklib/eg/data/class_data2 @@ -0,0 +1,3 @@ +Biology_101 sum average sort rsort data: 87.0 92.4 78.5 94.9 +Chemistry_305 sum average sort rsort data: 75.2 98.3 94.7 88.2 +English_401 sum average sort rsort data: 100.0 95.6 87.1 93.4 diff --git a/awklib/eg/data/guide-mellow.po b/awklib/eg/data/guide-mellow.po new file mode 100644 index 0000000..98c388d --- /dev/null +++ b/awklib/eg/data/guide-mellow.po @@ -0,0 +1,8 @@ +#: guide.awk:4 +msgid "Don't Panic" +msgstr "Hey man, relax!" + +#: guide.awk:5 +msgid "The Answer Is" +msgstr "Like, the scoop is" + diff --git a/awklib/eg/data/guide.po b/awklib/eg/data/guide.po new file mode 100644 index 0000000..de21218 --- /dev/null +++ b/awklib/eg/data/guide.po @@ -0,0 +1,8 @@ +#: guide.awk:4 +msgid "Don't Panic" +msgstr "" + +#: guide.awk:5 +msgid "The Answer Is" +msgstr "" + diff --git a/awklib/eg/data/inventory-shipped b/awklib/eg/data/inventory-shipped new file mode 100644 index 0000000..6788a0e --- /dev/null +++ b/awklib/eg/data/inventory-shipped @@ -0,0 +1,17 @@ +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 diff --git a/awklib/eg/data/mail-list b/awklib/eg/data/mail-list new file mode 100644 index 0000000..37ff350 --- /dev/null +++ b/awklib/eg/data/mail-list @@ -0,0 +1,11 @@ +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 diff --git a/awklib/eg/lib/assert.awk b/awklib/eg/lib/assert.awk new file mode 100644 index 0000000..c8e1349 --- /dev/null +++ b/awklib/eg/lib/assert.awk @@ -0,0 +1,20 @@ +# assert --- assert that a condition is true. Otherwise, exit. + +# +# Arnold Robbins, arnold@skeeve.com, Public Domain +# May, 1993 + +function assert(condition, string) +{ + if (! condition) { + printf("%s:%d: assertion failed: %s\n", + FILENAME, FNR, string) > "/dev/stderr" + _assert_exit = 1 + exit 1 + } +} + +END { + if (_assert_exit) + exit 1 +} diff --git a/awklib/eg/lib/bits2str.awk b/awklib/eg/lib/bits2str.awk new file mode 100644 index 0000000..5dddc1c --- /dev/null +++ b/awklib/eg/lib/bits2str.awk @@ -0,0 +1,16 @@ +# bits2str --- turn an integer into readable ones and zeros + +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 +} diff --git a/awklib/eg/lib/cliff_rand.awk b/awklib/eg/lib/cliff_rand.awk new file mode 100644 index 0000000..e6a793a --- /dev/null +++ b/awklib/eg/lib/cliff_rand.awk @@ -0,0 +1,14 @@ +# cliff_rand.awk --- generate Cliff random numbers +# +# Arnold Robbins, arnold@skeeve.com, Public Domain +# December 2000 + +BEGIN { _cliff_seed = 0.1 } + +function cliff_rand() +{ + _cliff_seed = (100 * log(_cliff_seed)) % 1 + if (_cliff_seed < 0) + _cliff_seed = - _cliff_seed + return _cliff_seed +} diff --git a/awklib/eg/lib/ctime.awk b/awklib/eg/lib/ctime.awk new file mode 100644 index 0000000..cea25b7 --- /dev/null +++ b/awklib/eg/lib/ctime.awk @@ -0,0 +1,12 @@ +# ctime.awk +# +# awk version of C ctime(3) function + +function ctime(ts, format) +{ + format = "%a %b %e %H:%M:%S %Z %Y" + + if (ts == 0) + ts = systime() # use current time as default + return strftime(format, ts) +} diff --git a/awklib/eg/lib/ftrans.awk b/awklib/eg/lib/ftrans.awk new file mode 100644 index 0000000..6461eff --- /dev/null +++ b/awklib/eg/lib/ftrans.awk @@ -0,0 +1,15 @@ +# ftrans.awk --- handle datafile transitions +# +# user supplies beginfile() and endfile() functions +# +# Arnold Robbins, arnold@skeeve.com, Public Domain +# November 1992 + +FNR == 1 { + if (_filename_ != "") + endfile(_filename_) + _filename_ = FILENAME + beginfile(FILENAME) +} + +END { endfile(_filename_) } diff --git a/awklib/eg/lib/getopt.awk b/awklib/eg/lib/getopt.awk new file mode 100644 index 0000000..6b1f4c5 --- /dev/null +++ b/awklib/eg/lib/getopt.awk @@ -0,0 +1,79 @@ +# getopt.awk --- Do C library getopt(3) function in awk +# +# Arnold Robbins, arnold@skeeve.com, Public Domain +# +# Initial version: March, 1991 +# Revised: May, 1993 + +# External variables: +# Optind -- index in ARGV of first nonoption argument +# Optarg -- string value of argument to current option +# Opterr -- if nonzero, print our own diagnostic +# Optopt -- current option letter + +# Returns: +# -1 at end of options +# "?" for unrecognized option +# a character representing the current option + +# Private Data: +# _opti -- index in multiflag option, e.g., -abc +function getopt(argc, argv, options, thisopt, i) +{ + if (length(options) == 0) # no options given + return -1 + + if (argv[Optind] == "--") { # all done + Optind++ + _opti = 0 + return -1 + } else if (argv[Optind] !~ /^-[^:[:space:]]/) { + _opti = 0 + return -1 + } + if (_opti == 0) + _opti = 2 + thisopt = substr(argv[Optind], _opti, 1) + Optopt = thisopt + i = index(options, thisopt) + if (i == 0) { + if (Opterr) + printf("%c -- invalid option\n", thisopt) > "/dev/stderr" + if (_opti >= length(argv[Optind])) { + Optind++ + _opti = 0 + } else + _opti++ + return "?" + } + if (substr(options, i + 1, 1) == ":") { + # get option argument + if (length(substr(argv[Optind], _opti + 1)) > 0) + Optarg = substr(argv[Optind], _opti + 1) + else + Optarg = argv[++Optind] + _opti = 0 + } else + Optarg = "" + if (_opti == 0 || _opti >= length(argv[Optind])) { + Optind++ + _opti = 0 + } else + _opti++ + return thisopt +} +BEGIN { + Opterr = 1 # default is to diagnose + Optind = 1 # skip ARGV[0] + + # test program + if (_getopt_test) { + while ((_go_c = getopt(ARGC, ARGV, "ab:cd")) != -1) + printf("c = <%c>, Optarg = <%s>\n", + _go_c, Optarg) + printf("non-option arguments:\n") + for (; Optind < ARGC; Optind++) + printf("\tARGV[%d] = <%s>\n", + Optind, ARGV[Optind]) + } +} diff --git a/awklib/eg/lib/gettime.awk b/awklib/eg/lib/gettime.awk new file mode 100644 index 0000000..4cb5633 --- /dev/null +++ b/awklib/eg/lib/gettime.awk @@ -0,0 +1,62 @@ +# getlocaltime.awk --- get the time of day in a usable format +# +# Arnold Robbins, arnold@skeeve.com, Public Domain, May 1993 +# + +# Returns a string in the format of output of date(1) +# Populates the array argument time with individual values: +# time["second"] -- seconds (0 - 59) +# time["minute"] -- minutes (0 - 59) +# time["hour"] -- hours (0 - 23) +# time["althour"] -- hours (0 - 12) +# time["monthday"] -- day of month (1 - 31) +# time["month"] -- month of year (1 - 12) +# time["monthname"] -- name of the month +# time["shortmonth"] -- short name of the month +# time["year"] -- year modulo 100 (0 - 99) +# time["fullyear"] -- full year +# time["weekday"] -- day of week (Sunday = 0) +# time["altweekday"] -- day of week (Monday = 0) +# time["dayname"] -- name of weekday +# time["shortdayname"] -- short name of weekday +# time["yearday"] -- day of year (0 - 365) +# time["timezone"] -- abbreviation of timezone name +# time["ampm"] -- AM or PM designation +# time["weeknum"] -- week number, Sunday first day +# time["altweeknum"] -- week number, Monday first day + +function getlocaltime(time, ret, now, i) +{ + # get time once, avoids unnecessary system calls + now = systime() + + # return date(1)-style output + ret = strftime("%a %b %e %H:%M:%S %Z %Y", now) + + # clear out target array + delete time + + # fill in values, force numeric values to be + # numeric by adding 0 + time["second"] = strftime("%S", now) + 0 + time["minute"] = strftime("%M", now) + 0 + time["hour"] = strftime("%H", now) + 0 + time["althour"] = strftime("%I", now) + 0 + time["monthday"] = strftime("%d", now) + 0 + time["month"] = strftime("%m", now) + 0 + time["monthname"] = strftime("%B", now) + time["shortmonth"] = strftime("%b", now) + time["year"] = strftime("%y", now) + 0 + time["fullyear"] = strftime("%Y", now) + 0 + time["weekday"] = strftime("%w", now) + 0 + time["altweekday"] = strftime("%u", now) + 0 + time["dayname"] = strftime("%A", now) + time["shortdayname"] = strftime("%a", now) + time["yearday"] = strftime("%j", now) + 0 + time["timezone"] = strftime("%Z", now) + time["ampm"] = strftime("%p", now) + time["weeknum"] = strftime("%U", now) + 0 + time["altweeknum"] = strftime("%W", now) + 0 + + return ret +} diff --git a/awklib/eg/lib/grcat.c b/awklib/eg/lib/grcat.c new file mode 100644 index 0000000..30e81cc --- /dev/null +++ b/awklib/eg/lib/grcat.c @@ -0,0 +1,49 @@ +/* + * grcat.c + * + * Generate a printable version of the group database. + */ +/* + * Arnold Robbins, arnold@skeeve.com, May 1993 + * Public Domain + * December 2010, move to ANSI C definition for main(). + */ + +#if HAVE_CONFIG_H +#include +#endif + +#if defined (STDC_HEADERS) +#include +#endif + +#ifndef HAVE_GETGRENT +int main() { return 0; } +#else +#include +#include + +int +main(int argc, char **argv) +{ + struct group *g; + int i; + + while ((g = getgrent()) != NULL) { +#ifdef HAVE_STRUCT_GROUP_GR_PASSWD + printf("%s:%s:%ld:", g->gr_name, g->gr_passwd, + (long) g->gr_gid); +#else + printf("%s:*:%ld:", g->gr_name, (long) g->gr_gid); +#endif + for (i = 0; g->gr_mem[i] != NULL; i++) { + printf("%s", g->gr_mem[i]); + if (g->gr_mem[i+1] != NULL) + putchar(','); + } + putchar('\n'); + } + endgrent(); + return 0; +} +#endif /* HAVE_GETGRENT */ diff --git a/awklib/eg/lib/groupawk.in b/awklib/eg/lib/groupawk.in new file mode 100644 index 0000000..f9e1e20 --- /dev/null +++ b/awklib/eg/lib/groupawk.in @@ -0,0 +1,83 @@ +# group.awk --- functions for dealing with the group file +# +# Arnold Robbins, arnold@skeeve.com, Public Domain +# May 1993 +# Revised October 2000 +# Revised December 2010 + +BEGIN { + # Change to suit your system + _gr_awklib = "/usr/local/libexec/awk/" +} + +function _gr_init( oldfs, oldrs, olddol0, grcat, + using_fw, using_fpat, n, a, i) +{ + if (_gr_inited) + 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_count] = $0 + } + close(grcat) + _gr_count = 0 + _gr_inited++ + FS = oldfs + if (using_fw) + FIELDWIDTHS = FIELDWIDTHS + else if (using_fpat) + FPAT = FPAT + RS = oldrs + $0 = olddol0 +} +function getgrnam(group) +{ + _gr_init() + return _gr_byname[group] +} +function getgrgid(gid) +{ + _gr_init() + return _gr_bygid[gid] +} +function getgruser(user) +{ + _gr_init() + return _gr_groupsbyuser[user] +} +function getgrent() +{ + _gr_init() + if (++_gr_count in _gr_bycount) + return _gr_bycount[_gr_count] + return "" +} +function endgrent() +{ + _gr_count = 0 +} diff --git a/awklib/eg/lib/have_mpfr.awk b/awklib/eg/lib/have_mpfr.awk new file mode 100644 index 0000000..90bd523 --- /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/inplace.awk b/awklib/eg/lib/inplace.awk new file mode 100644 index 0000000..6771bc4 --- /dev/null +++ b/awklib/eg/lib/inplace.awk @@ -0,0 +1,55 @@ +# inplace --- load and invoke the inplace extension. +# +# Copyright (C) 2013, 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 +# +# Andrew J. Schorr, aschorr@telemetry-investments.com +# January 2013 + +@load "inplace" + +# Please set INPLACE_SUFFIX to make a backup copy. For example, you may +# want to set INPLACE_SUFFIX to .bak on the command line or in a BEGIN rule. + +# By default, each filename on the command line will be edited inplace. +# But you can selectively disable this by adding an inplace=0 argument +# prior to files that you do not want to process this way. You can then +# reenable it later on the commandline by putting inplace=1 before files +# that you wish to be subject to inplace editing. + +# N.B. We call inplace_end() in the BEGINFILE and END rules so that any +# actions in an ENDFILE rule will be redirected as expected. + +BEGIN { + inplace = 1 # enabled by 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) +} diff --git a/awklib/eg/lib/intdiv0.awk b/awklib/eg/lib/intdiv0.awk new file mode 100644 index 0000000..9de5978 --- /dev/null +++ b/awklib/eg/lib/intdiv0.awk @@ -0,0 +1,23 @@ +# intdiv0 --- do integer division + +# +# Arnold Robbins, arnold@skeeve.com, Public Domain +# July, 2014 +# +# Name changed from div() to intdiv() +# April, 2015 +# +# Changed to intdiv0() +# April, 2016 + +function intdiv0(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/lib/join.awk b/awklib/eg/lib/join.awk new file mode 100644 index 0000000..4a4ac92 --- /dev/null +++ b/awklib/eg/lib/join.awk @@ -0,0 +1,16 @@ +# join.awk --- join an array into a string +# +# Arnold Robbins, arnold@skeeve.com, Public Domain +# May 1993 + +function join(array, start, end, sep, result, i) +{ + if (sep == "") + sep = " " + else if (sep == SUBSEP) # magic value + sep = "" + result = array[start] + for (i = start + 1; i <= end; i++) + result = result sep array[i] + return result +} diff --git a/awklib/eg/lib/libintl.awk b/awklib/eg/lib/libintl.awk new file mode 100644 index 0000000..7efd2b4 --- /dev/null +++ b/awklib/eg/lib/libintl.awk @@ -0,0 +1,14 @@ +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) +} diff --git a/awklib/eg/lib/noassign.awk b/awklib/eg/lib/noassign.awk new file mode 100644 index 0000000..99227b3 --- /dev/null +++ b/awklib/eg/lib/noassign.awk @@ -0,0 +1,17 @@ +# noassign.awk --- library file to avoid the need for a +# special option that disables command-line assignments +# +# Arnold Robbins, arnold@skeeve.com, Public Domain +# October 1999 + +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 (No_command_assign) + disable_assigns(ARGC, ARGV) +} diff --git a/awklib/eg/lib/ord.awk b/awklib/eg/lib/ord.awk new file mode 100644 index 0000000..be47e15 --- /dev/null +++ b/awklib/eg/lib/ord.awk @@ -0,0 +1,44 @@ +# ord.awk --- do ord and chr + +# Global identifiers: +# _ord_: numerical values indexed by characters +# _ord_init: function to initialize _ord_ +# +# Arnold Robbins, arnold@skeeve.com, Public Domain +# 16 January, 1992 +# 20 July, 1992, revised + +BEGIN { _ord_init() } + +function _ord_init( low, high, i, t) +{ + low = sprintf("%c", 7) # BEL is ascii 7 + if (low == "\a") { # regular ascii + low = 0 + high = 127 + } else if (sprintf("%c", 128 + 7) == "\a") { + # ascii, mark parity + low = 128 + high = 255 + } else { # ebcdic(!) + low = 0 + high = 255 + } + + for (i = low; i <= high; i++) { + t = sprintf("%c", i) + _ord_[t] = i + } +} +function ord(str, c) +{ + # only first character is of interest + c = substr(str, 1, 1) + return _ord_[c] +} + +function chr(c) +{ + # force c to be numeric by adding 0 + return sprintf("%c", c + 0) +} diff --git a/awklib/eg/lib/passwdawk.in b/awklib/eg/lib/passwdawk.in new file mode 100644 index 0000000..d2442ad --- /dev/null +++ b/awklib/eg/lib/passwdawk.in @@ -0,0 +1,63 @@ +# passwd.awk --- access password file information +# +# Arnold Robbins, arnold@skeeve.com, Public Domain +# May 1993 +# Revised October 2000 +# Revised December 2010 + +BEGIN { + # tailor this to suit your system + _pw_awklib = "/usr/local/libexec/awk/" +} + +function _pw_init( oldfs, oldrs, olddol0, pwcat, using_fw, using_fpat) +{ + if (_pw_inited) + 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_total] = $0 + } + close(pwcat) + _pw_count = 0 + _pw_inited = 1 + FS = oldfs + if (using_fw) + FIELDWIDTHS = FIELDWIDTHS + else if (using_fpat) + FPAT = FPAT + RS = oldrs + $0 = olddol0 +} +function getpwnam(name) +{ + _pw_init() + return _pw_byname[name] +} +function getpwuid(uid) +{ + _pw_init() + return _pw_byuid[uid] +} +function getpwent() +{ + _pw_init() + if (_pw_count < _pw_total) + return _pw_bycount[++_pw_count] + return "" +} +function endpwent() +{ + _pw_count = 0 +} diff --git a/awklib/eg/lib/processarray.awk b/awklib/eg/lib/processarray.awk new file mode 100644 index 0000000..79a86d1 --- /dev/null +++ b/awklib/eg/lib/processarray.awk @@ -0,0 +1,12 @@ +function process_array(arr, name, process, do_arrays, i, new_name) +{ + for (i in arr) { + new_name = (name "[" i "]") + if (isarray(arr[i])) { + if (do_arrays) + @process(new_name, arr[i]) + process_array(arr[i], new_name, process, do_arrays) + } else + @process(new_name, arr[i]) + } +} diff --git a/awklib/eg/lib/pwcat.c b/awklib/eg/lib/pwcat.c new file mode 100644 index 0000000..cfe250c --- /dev/null +++ b/awklib/eg/lib/pwcat.c @@ -0,0 +1,41 @@ +/* + * pwcat.c + * + * Generate a printable version of the password database. + */ +/* + * Arnold Robbins, arnold@skeeve.com, May 1993 + * Public Domain + * December 2010, move to ANSI C definition for main(). + */ + +#if HAVE_CONFIG_H +#include +#endif + +#include +#include + +#if defined (STDC_HEADERS) +#include +#endif + +int +main(int argc, char **argv) +{ + struct passwd *p; + + while ((p = getpwent()) != NULL) +#ifdef HAVE_STRUCT_PASSWD_PW_PASSWD + 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); +#else + printf("%s:*:%ld:%ld:%s:%s\n", + p->pw_name, (long) p->pw_uid, + (long) p->pw_gid, p->pw_dir, p->pw_shell); +#endif + + endpwent(); + return 0; +} diff --git a/awklib/eg/lib/quicksort.awk b/awklib/eg/lib/quicksort.awk new file mode 100644 index 0000000..e0ed8bc --- /dev/null +++ b/awklib/eg/lib/quicksort.awk @@ -0,0 +1,35 @@ +# quicksort.awk --- Quicksort algorithm, with user-supplied +# comparison function +# +# Arnold Robbins, arnold@skeeve.com, Public Domain +# January 2009 + + +# quicksort --- C.A.R. Hoare's quicksort algorithm. See Wikipedia +# or almost any algorithms or computer science text. +# +# Adapted from K&R-II, page 110 + +function quicksort(data, left, right, less_than, i, last) +{ + if (left >= right) # do nothing if array contains fewer + return # than two elements + + quicksort_swap(data, left, int((left + right) / 2)) + last = left + for (i = left + 1; i <= right; i++) + if (@less_than(data[i], data[left])) + quicksort_swap(data, ++last, i) + quicksort_swap(data, left, last) + quicksort(data, left, last - 1, less_than) + quicksort(data, last + 1, right, less_than) +} + +# quicksort_swap --- helper function for quicksort, should really be inline + +function quicksort_swap(data, i, j, temp) +{ + temp = data[i] + data[i] = data[j] + data[j] = temp +} diff --git a/awklib/eg/lib/readable.awk b/awklib/eg/lib/readable.awk new file mode 100644 index 0000000..37970a8 --- /dev/null +++ b/awklib/eg/lib/readable.awk @@ -0,0 +1,17 @@ +# readable.awk --- library file to skip over unreadable files +# +# Arnold Robbins, arnold@skeeve.com, Public Domain +# October 2000 +# December 2010 + +BEGIN { + for (i = 1; i < ARGC; i++) { + if (ARGV[i] ~ /^[a-zA-Z_][a-zA-Z0-9_]*=.*/ \ + || ARGV[i] == "-" || ARGV[i] == "/dev/stdin") + continue # assignment or standard input + else if ((getline junk < ARGV[i]) < 0) # unreadable + delete ARGV[i] + else + close(ARGV[i]) + } +} diff --git a/awklib/eg/lib/readfile.awk b/awklib/eg/lib/readfile.awk new file mode 100644 index 0000000..9137b26 --- /dev/null +++ b/awklib/eg/lib/readfile.awk @@ -0,0 +1,15 @@ +# readfile.awk --- read an entire file at once +# +# Original idea by Denis Shirokov, cosmogen@gmail.com, April 2013 +# + +function readfile(file, tmp, save_rs) +{ + save_rs = RS + RS = "^$" + getline tmp < file + close(file) + RS = save_rs + + return tmp +} diff --git a/awklib/eg/lib/rewind.awk b/awklib/eg/lib/rewind.awk new file mode 100644 index 0000000..a646eac --- /dev/null +++ b/awklib/eg/lib/rewind.awk @@ -0,0 +1,20 @@ +# rewind.awk --- rewind the current file and start over +# +# Arnold Robbins, arnold@skeeve.com, Public Domain +# September 2000 + +function rewind( i) +{ + # shift remaining arguments up + for (i = ARGC; i > ARGIND; i--) + ARGV[i] = ARGV[i-1] + + # make sure gawk knows to keep going + ARGC++ + + # make current file next to get done + ARGV[ARGIND+1] = FILENAME + + # do it + nextfile +} diff --git a/awklib/eg/lib/round.awk b/awklib/eg/lib/round.awk new file mode 100644 index 0000000..899645f --- /dev/null +++ b/awklib/eg/lib/round.awk @@ -0,0 +1,29 @@ +# round.awk --- do normal rounding +# +# Arnold Robbins, arnold@skeeve.com, Public Domain +# August, 1996 + +function round(x, ival, aval, fraction) +{ + ival = int(x) # integer part, int() truncates + + # see if fractional part + if (ival == x) # no fraction + return ival # ensure no decimals + + if (x < 0) { + aval = -x # absolute value + ival = int(aval) + fraction = aval - ival + if (fraction >= .5) + return int(x) - 1 # -2.5 --> -3 + else + return int(x) # -2.3 --> -2 + } else { + fraction = x - ival + if (fraction >= .5) + return ival + 1 + else + return ival + } +} diff --git a/awklib/eg/lib/shellquote.awk b/awklib/eg/lib/shellquote.awk new file mode 100644 index 0000000..cd943dc --- /dev/null +++ b/awklib/eg/lib/shellquote.awk @@ -0,0 +1,22 @@ +# shell_quote --- quote an argument for passing to the shell +# +# Michael Brennan +# brennan@madronabluff.com +# September 2014 + +function shell_quote(s, # parameter + SINGLE, QSINGLE, i, X, n, ret) # locals +{ + if (s == "") + return "\"\"" + + SINGLE = "\x27" # single quote + QSINGLE = "\"\x27\"" + n = split(s, X, SINGLE) + + ret = SINGLE X[1] SINGLE + for (i = 2; i <= n; i++) + ret = ret QSINGLE SINGLE X[i] SINGLE + + return ret +} diff --git a/awklib/eg/lib/strtonum.awk b/awklib/eg/lib/strtonum.awk new file mode 100644 index 0000000..783496e --- /dev/null +++ b/awklib/eg/lib/strtonum.awk @@ -0,0 +1,58 @@ +# mystrtonum --- convert string to number + +# +# Arnold Robbins, arnold@skeeve.com, Public Domain +# February, 2004 +# Revised June, 2014 + +function mystrtonum(str, ret, n, i, k, c) +{ + if (str ~ /^0[0-7]*$/) { + # octal + n = length(str) + ret = 0 + for (i = 1; i <= n; i++) { + c = substr(str, i, 1) + # index() returns 0 if c not in string, + # includes c == "0" + k = index("1234567", c) + + ret = ret * 8 + k + } + } else if (str ~ /^0[xX][[:xdigit:]]+$/) { + # hexadecimal + str = substr(str, 3) # lop off leading 0x + n = length(str) + ret = 0 + for (i = 1; i <= n; i++) { + c = substr(str, i, 1) + c = tolower(c) + # index() returns 0 if c not in string, + # includes c == "0" + k = index("123456789abcdef", c) + + ret = ret * 16 + k + } + } else if (str ~ \ + /^[-+]?([0-9]+([.][0-9]*([Ee][0-9]+)?)?|([.][0-9]+([Ee][-+]?[0-9]+)?))$/) { + # decimal number, possibly floating point + ret = str + 0 + } else + ret = "NOT-A-NUMBER" + + return ret +} + +# BEGIN { # gawk test harness +# 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]) +# } diff --git a/awklib/eg/lib/walkarray.awk b/awklib/eg/lib/walkarray.awk new file mode 100644 index 0000000..5e36f46 --- /dev/null +++ b/awklib/eg/lib/walkarray.awk @@ -0,0 +1,9 @@ +function walk_array(arr, name, i) +{ + for (i in arr) { + if (isarray(arr[i])) + walk_array(arr[i], (name "[" i "]")) + else + printf("%s[%s] = %s\n", name, i, arr[i]) + } +} diff --git a/awklib/eg/lib/zerofile.awk b/awklib/eg/lib/zerofile.awk new file mode 100644 index 0000000..8ea549c --- /dev/null +++ b/awklib/eg/lib/zerofile.awk @@ -0,0 +1,19 @@ +# zerofile.awk --- library file to process empty input files +# +# Arnold Robbins, arnold@skeeve.com, Public Domain +# June 2003 + +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) +} diff --git a/awklib/eg/misc/addresses.csv b/awklib/eg/misc/addresses.csv new file mode 100644 index 0000000..a9eee0b --- /dev/null +++ b/awklib/eg/misc/addresses.csv @@ -0,0 +1 @@ +Robbins,Arnold,"1234 A Pretty Street, NE",MyTown,MyState,12345-6789,USA diff --git a/awklib/eg/misc/arraymax.awk b/awklib/eg/misc/arraymax.awk new file mode 100644 index 0000000..64197f5 --- /dev/null +++ b/awklib/eg/misc/arraymax.awk @@ -0,0 +1,10 @@ +{ + if ($1 > max) + max = $1 + arr[$1] = $0 +} + +END { + for (x = 1; x <= max; x++) + print arr[x] +} diff --git a/awklib/eg/misc/arraymax.data b/awklib/eg/misc/arraymax.data new file mode 100644 index 0000000..dbee328 --- /dev/null +++ b/awklib/eg/misc/arraymax.data @@ -0,0 +1,5 @@ +5 I am the Five man +2 Who are you? The new number two! +4 . . . And four on the floor +1 Who is number one? +3 I three you. diff --git a/awklib/eg/misc/findpat.awk b/awklib/eg/misc/findpat.awk new file mode 100644 index 0000000..9d79943 --- /dev/null +++ b/awklib/eg/misc/findpat.awk @@ -0,0 +1,9 @@ +{ + if ($1 == "FIND") + regex = $2 + else { + where = match($0, regex) + if (where != 0) + print "Match of", regex, "found at", where, "in", $0 + } +} diff --git a/awklib/eg/misc/findpat.data b/awklib/eg/misc/findpat.data new file mode 100644 index 0000000..9f72969 --- /dev/null +++ b/awklib/eg/misc/findpat.data @@ -0,0 +1,7 @@ +FIND ru+n +My program runs +but not very quickly +FIND Melvin +JF+KM +This line is property of Reality Engineering Co. +Melvin was here. diff --git a/awklib/eg/misc/simple-csv.awk b/awklib/eg/misc/simple-csv.awk new file mode 100644 index 0000000..36cb4a6 --- /dev/null +++ b/awklib/eg/misc/simple-csv.awk @@ -0,0 +1,10 @@ +BEGIN { + FPAT = "([^,]+)|(\"[^\"]+\")" +} + +{ + print "NF = ", NF + for (i = 1; i <= NF; i++) { + printf("$%d = <%s>\n", i, $i) + } +} diff --git a/awklib/eg/network/PostAgent.sh b/awklib/eg/network/PostAgent.sh new file mode 100644 index 0000000..ccf9a68 --- /dev/null +++ b/awklib/eg/network/PostAgent.sh @@ -0,0 +1,9 @@ +#!/bin/sh +MobAg=/tmp/MobileAgent.$$ +# direct script to mobile agent file +cat > $MobAg +# execute agent concurrently +gawk -f $MobAg $MobAg > /dev/null & +# HTTP header, terminator and body +gawk 'BEGIN { print "\r\nAgent started" }' +rm $MobAg # delete script file of agent diff --git a/awklib/eg/network/coreserv.awk b/awklib/eg/network/coreserv.awk new file mode 100644 index 0000000..a5c8b1e --- /dev/null +++ b/awklib/eg/network/coreserv.awk @@ -0,0 +1,113 @@ +# CGI Library and core of a web server +# +# Juergen Kahrs, Juergen.Kahrs@vr-web.de +# with Arnold Robbins, arnold@skeeve.com +# September 2000 + +# Global arrays +# GETARG --- arguments to CGI GET command +# MENU --- menu items (path names) +# PARAM --- parameters of form x=y + +# Optional variable MyHost contains host address +# Optional variable MyPort contains port number +# Needs TopHeader, TopDoc, TopFooter +# Sets MyPrefix, HttpService, Status, Reason + +BEGIN { + if (MyHost == "") { + "uname -n" | getline MyHost + close("uname -n") + } + if (MyPort == 0) MyPort = 8080 + HttpService = "/inet/tcp/" MyPort "/0/0" + MyPrefix = "http://" MyHost ":" MyPort + SetUpServer() + while ("awk" != "complex") { + # header lines are terminated this way + RS = ORS = "\r\n" + Status = 200 # this means OK + Reason = "OK" + Header = TopHeader + Document = TopDoc + Footer = TopFooter + if (GETARG["Method"] == "GET") { + HandleGET() + } else if (GETARG["Method"] == "HEAD") { + # not yet implemented + } else if (GETARG["Method"] != "") { + print "bad method", GETARG["Method"] + } + Prompt = Header Document Footer + print "HTTP/1.0", Status, Reason |& HttpService + print "Connection: Close" |& HttpService + print "Pragma: no-cache" |& HttpService + len = length(Prompt) + length(ORS) + print "Content-length:", len |& HttpService + print ORS Prompt |& HttpService + # ignore all the header lines + while ((HttpService |& getline) > 0) + continue + # stop talking to this client + close(HttpService) + # wait for new client request + HttpService |& getline + # do some logging + print systime(), strftime(), $0 + CGI_setup($1, $2, $3) + } +} + +function CGI_setup( method, uri, version, i) +{ + delete GETARG + delete MENU + delete PARAM + GETARG["Method"] = method + GETARG["URI"] = uri + GETARG["Version"] = version + + i = index(uri, "?") + if (i > 0) { # is there a "?" indicating a CGI request? + split(substr(uri, 1, i-1), MENU, "[/:]") + split(substr(uri, i+1), PARAM, "&") + for (i in PARAM) { + PARAM[i] = _CGI_decode(PARAM[i]) + j = index(PARAM[i], "=") + GETARG[substr(PARAM[i], 1, j-1)] = \ + substr(PARAM[i], j+1) + } + } else { # there is no "?", no need for splitting PARAMs + split(uri, MENU, "[/:]") + } + for (i in MENU) # decode characters in path + if (i > 4) # but not those in host name + MENU[i] = _CGI_decode(MENU[i]) +} +function _CGI_decode(str, hexdigs, i, pre, code1, code2, + val, result) +{ + hexdigs = "123456789abcdef" + + i = index(str, "%") + if (i == 0) # no work to do + return str + + do { + pre = substr(str, 1, i-1) # part before %xx + code1 = substr(str, i+1, 1) # first hex digit + code2 = substr(str, i+2, 1) # second hex digit + str = substr(str, i+3) # rest of string + + code1 = tolower(code1) + code2 = tolower(code2) + val = index(hexdigs, code1) * 16 \ + + index(hexdigs, code2) + + result = result pre sprintf("%c", val) + i = index(str, "%") + } while (i != 0) + if (length(str) > 0) + result = result str + return result +} diff --git a/awklib/eg/network/eliza.awk b/awklib/eg/network/eliza.awk new file mode 100644 index 0000000..15ee2c4 --- /dev/null +++ b/awklib/eg/network/eliza.awk @@ -0,0 +1,270 @@ +function SetUpServer() { + SetUpEliza() + TopHeader = \ + "An HTTP-based System with GAWK\ + \ + " + TopDoc = "\ +

Please choose one of the following actions:

\ +
" + TopFooter = "" +} +function HandleGET() { + # A real HTTP server would treat some parts of the URI as a file name. + # We take parts of the URI as menu choices and go on accordingly. + if(MENU[2] == "AboutServer") { + Document = "This is not a CGI script.\ + This is an httpd, an HTML file, and a CGI script all \ + in one GAWK script. It needs no separate www-server, \ + no installation, and no root privileges.\ +

To run it, do this:

    \ +
  • start this script with \"gawk -f httpserver.awk\",
  • \ +
  • and on the same host let your www browser open location\ + \"http://localhost:8080\"
  • \ +
\

\ Details of HTTP come from:

    \ +
  • Hethmon: Illustrated Guide to HTTP

    \ +
  • RFC 2068

JK 14.9.1997

" + } else if (MENU[2] == "AboutELIZA") { + Document = "This is an implementation of the famous ELIZA\ + program by Joseph Weizenbaum. It is written in GAWK and\ + uses an HTML GUI." + } else if (MENU[2] == "StartELIZA") { + gsub(/\+/, " ", GETARG["YouSay"]) + # Here we also have to substitute coded special characters + Document = "
" \ + "

" ElizaSays(GETARG["YouSay"]) "

\ +

\ +

" + } +} +function ElizaSays(YouSay) { + if (YouSay == "") { + cost = 0 + answer = "HI, IM ELIZA, TELL ME YOUR PROBLEM" + } else { + q = toupper(YouSay) + gsub("'", "", q) + if(q == qold) { + answer = "PLEASE DONT REPEAT YOURSELF !" + } else { + if (index(q, "SHUT UP") > 0) { + answer = "WELL, PLEASE PAY YOUR BILL. ITS EXACTLY ... $"\ + int(100*rand()+30+cost/100) + } else { + qold = q + w = "-" # no keyword recognized yet + for (i in k) { # search for keywords + if (index(q, i) > 0) { + w = i + break + } + } + if (w == "-") { # no keyword, take old subject + w = wold + subj = subjold + } else { # find subject + subj = substr(q, index(q, w) + length(w)+1) + wold = w + subjold = subj # remember keyword and subject + } + for (i in conj) + gsub(i, conj[i], q) # conjugation + # from all answers to this keyword, select one randomly + answer = r[indices[int(split(k[w], indices) * rand()) + 1]] + # insert subject into answer + gsub("_", subj, answer) + } + } + } + cost += length(answer) # for later payment : 1 cent per character + return answer +} +function SetUpEliza() { + srand() + wold = "-" + subjold = " " + + # table for conjugation + conj[" ARE " ] = " AM " + conj["WERE " ] = "WAS " + conj[" YOU " ] = " I " + conj["YOUR " ] = "MY " + conj[" IVE " ] =\ + conj[" I HAVE " ] = " YOU HAVE " + conj[" YOUVE " ] =\ + conj[" YOU HAVE "] = " I HAVE " + conj[" IM " ] =\ + conj[" I AM " ] = " YOU ARE " + conj[" YOURE " ] =\ + conj[" YOU ARE " ] = " I AM " + + # table of all answers + r[1] = "DONT YOU BELIEVE THAT I CAN _" + r[2] = "PERHAPS YOU WOULD LIKE TO BE ABLE TO _ ?" + r[3] = "YOU WANT ME TO BE ABLE TO _ ?" + r[4] = "PERHAPS YOU DONT WANT TO _ " + r[5] = "DO YOU WANT TO BE ABLE TO _ ?" + r[6] = "WHAT MAKES YOU THINK I AM _ ?" + r[7] = "DOES IT PLEASE YOU TO BELIEVE I AM _ ?" + r[8] = "PERHAPS YOU WOULD LIKE TO BE _ ?" + r[9] = "DO YOU SOMETIMES WISH YOU WERE _ ?" + r[10] = "DONT YOU REALLY _ ?" + r[11] = "WHY DONT YOU _ ?" + r[12] = "DO YOU WISH TO BE ABLE TO _ ?" + r[13] = "DOES THAT TROUBLE YOU ?" + r[14] = "TELL ME MORE ABOUT SUCH FEELINGS" + r[15] = "DO YOU OFTEN FEEL _ ?" + r[16] = "DO YOU ENJOY FEELING _ ?" + r[17] = "DO YOU REALLY BELIEVE I DONT _ ?" + r[18] = "PERHAPS IN GOOD TIME I WILL _ " + r[19] = "DO YOU WANT ME TO _ ?" + r[20] = "DO YOU THINK YOU SHOULD BE ABLE TO _ ?" + r[21] = "WHY CANT YOU _ ?" + r[22] = "WHY ARE YOU INTERESTED IN WHETHER OR NOT I AM _ ?" + r[23] = "WOULD YOU PREFER IF I WERE NOT _ ?" + r[24] = "PERHAPS IN YOUR FANTASIES I AM _ " + r[25] = "HOW DO YOU KNOW YOU CANT _ ?" + r[26] = "HAVE YOU TRIED ?" + r[27] = "PERHAPS YOU CAN NOW _ " + r[28] = "DID YOU COME TO ME BECAUSE YOU ARE _ ?" + r[29] = "HOW LONG HAVE YOU BEEN _ ?" + r[30] = "DO YOU BELIEVE ITS NORMAL TO BE _ ?" + r[31] = "DO YOU ENJOY BEING _ ?" + r[32] = "WE WERE DISCUSSING YOU -- NOT ME" + r[33] = "Oh, I _" + r[34] = "YOU'RE NOT REALLY TALKING ABOUT ME, ARE YOU ?" + r[35] = "WHAT WOULD IT MEAN TO YOU, IF YOU GOT _ ?" + r[36] = "WHY DO YOU WANT _ ?" + r[37] = "SUPPOSE YOU SOON GOT _" + r[38] = "WHAT IF YOU NEVER GOT _ ?" + r[39] = "I SOMETIMES ALSO WANT _" + r[40] = "WHY DO YOU ASK ?" + r[41] = "DOES THAT QUESTION INTEREST YOU ?" + r[42] = "WHAT ANSWER WOULD PLEASE YOU THE MOST ?" + r[43] = "WHAT DO YOU THINK ?" + r[44] = "ARE SUCH QUESTIONS IN YOUR MIND OFTEN ?" + r[45] = "WHAT IS IT THAT YOU REALLY WANT TO KNOW ?" + r[46] = "HAVE YOU ASKED ANYONE ELSE ?" + r[47] = "HAVE YOU ASKED SUCH QUESTIONS BEFORE ?" + r[48] = "WHAT ELSE COMES TO MIND WHEN YOU ASK THAT ?" + r[49] = "NAMES DON'T INTEREST ME" + r[50] = "I DONT CARE ABOUT NAMES -- PLEASE GO ON" + r[51] = "IS THAT THE REAL REASON ?" + r[52] = "DONT ANY OTHER REASONS COME TO MIND ?" + r[53] = "DOES THAT REASON EXPLAIN ANYTHING ELSE ?" + r[54] = "WHAT OTHER REASONS MIGHT THERE BE ?" + r[55] = "PLEASE DON'T APOLOGIZE !" + r[56] = "APOLOGIES ARE NOT NECESSARY" + r[57] = "WHAT FEELINGS DO YOU HAVE WHEN YOU APOLOGIZE ?" + r[58] = "DON'T BE SO DEFENSIVE" + r[59] = "WHAT DOES THAT DREAM SUGGEST TO YOU ?" + r[60] = "DO YOU DREAM OFTEN ?" + r[61] = "WHAT PERSONS APPEAR IN YOUR DREAMS ?" + r[62] = "ARE YOU DISTURBED BY YOUR DREAMS ?" + r[63] = "HOW DO YOU DO ... PLEASE STATE YOUR PROBLEM" + r[64] = "YOU DON'T SEEM QUITE CERTAIN" + r[65] = "WHY THE UNCERTAIN TONE ?" + r[66] = "CAN'T YOU BE MORE POSITIVE ?" + r[67] = "YOU AREN'T SURE ?" + r[68] = "DON'T YOU KNOW ?" + r[69] = "WHY NO _ ?" + r[70] = "DON'T SAY NO, IT'S ALWAYS SO NEGATIVE" + r[71] = "WHY NOT ?" + r[72] = "ARE YOU SURE ?" + r[73] = "WHY NO ?" + r[74] = "WHY ARE YOU CONCERNED ABOUT MY _ ?" + r[75] = "WHAT ABOUT YOUR OWN _ ?" + r[76] = "CAN'T YOU THINK ABOUT A SPECIFIC EXAMPLE ?" + r[77] = "WHEN ?" + r[78] = "WHAT ARE YOU THINKING OF ?" + r[79] = "REALLY, ALWAYS ?" + r[80] = "DO YOU REALLY THINK SO ?" + r[81] = "BUT YOU ARE NOT SURE YOU _ " + r[82] = "DO YOU DOUBT YOU _ ?" + r[83] = "IN WHAT WAY ?" + r[84] = "WHAT RESEMBLANCE DO YOU SEE ?" + r[85] = "WHAT DOES THE SIMILARITY SUGGEST TO YOU ?" + r[86] = "WHAT OTHER CONNECTION DO YOU SEE ?" + r[87] = "COULD THERE REALLY BE SOME CONNECTIONS ?" + r[88] = "HOW ?" + r[89] = "YOU SEEM QUITE POSITIVE" + r[90] = "ARE YOU SURE ?" + r[91] = "I SEE" + r[92] = "I UNDERSTAND" + r[93] = "WHY DO YOU BRING UP THE TOPIC OF FRIENDS ?" + r[94] = "DO YOUR FRIENDS WORRY YOU ?" + r[95] = "DO YOUR FRIENDS PICK ON YOU ?" + r[96] = "ARE YOU SURE YOU HAVE ANY FRIENDS ?" + r[97] = "DO YOU IMPOSE ON YOUR FRIENDS ?" + r[98] = "PERHAPS YOUR LOVE FOR FRIENDS WORRIES YOU" + r[99] = "DO COMPUTERS WORRY YOU ?" + r[100] = "ARE YOU TALKING ABOUT ME IN PARTICULAR ?" + r[101] = "ARE YOU FRIGHTENED BY MACHINES ?" + r[102] = "WHY DO YOU MENTION COMPUTERS ?" + r[103] = "WHAT DO YOU THINK MACHINES HAVE TO DO WITH YOUR PROBLEMS ?" + r[104] = "DON'T YOU THINK COMPUTERS CAN HELP PEOPLE ?" + r[105] = "WHAT IS IT ABOUT MACHINES THAT WORRIES YOU ?" + r[106] = "SAY, DO YOU HAVE ANY PSYCHOLOGICAL PROBLEMS ?" + r[107] = "WHAT DOES THAT SUGGEST TO YOU ?" + r[108] = "I SEE" + r[109] = "IM NOT SURE I UNDERSTAND YOU FULLY" + r[110] = "COME COME ELUCIDATE YOUR THOUGHTS" + r[111] = "CAN YOU ELABORATE ON THAT ?" + r[112] = "THAT IS QUITE INTERESTING" + r[113] = "WHY DO YOU HAVE PROBLEMS WITH MONEY ?" + r[114] = "DO YOU THINK MONEY IS EVERYTHING ?" + r[115] = "ARE YOU SURE THAT MONEY IS THE PROBLEM ?" + r[116] = "I THINK WE WANT TO TALK ABOUT YOU, NOT ABOUT ME" + r[117] = "WHAT'S ABOUT ME ?" + r[118] = "WHY DO YOU ALWAYS BRING UP MY NAME ?" + # table for looking up answers that + # fit to a certain keyword + k["CAN YOU"] = "1 2 3" + k["CAN I"] = "4 5" + k["YOU ARE"] =\ + k["YOURE"] = "6 7 8 9" + k["I DONT"] = "10 11 12 13" + k["I FEEL"] = "14 15 16" + k["WHY DONT YOU"] = "17 18 19" + k["WHY CANT I"] = "20 21" + k["ARE YOU"] = "22 23 24" + k["I CANT"] = "25 26 27" + k["I AM"] =\ + k["IM "] = "28 29 30 31" + k["YOU "] = "32 33 34" + k["I WANT"] = "35 36 37 38 39" + k["WHAT"] =\ + k["HOW"] =\ + k["WHO"] =\ + k["WHERE"] =\ + k["WHEN"] =\ + k["WHY"] = "40 41 42 43 44 45 46 47 48" + k["NAME"] = "49 50" + k["CAUSE"] = "51 52 53 54" + k["SORRY"] = "55 56 57 58" + k["DREAM"] = "59 60 61 62" + k["HELLO"] =\ + k["HI "] = "63" + k["MAYBE"] = "64 65 66 67 68" + k[" NO "] = "69 70 71 72 73" + k["YOUR"] = "74 75" + k["ALWAYS"] = "76 77 78 79" + k["THINK"] = "80 81 82" + k["LIKE"] = "83 84 85 86 87 88 89" + k["YES"] = "90 91 92" + k["FRIEND"] = "93 94 95 96 97 98" + k["COMPUTER"] = "99 100 101 102 103 104 105" + k["-"] = "106 107 108 109 110 111 112" + k["MONEY"] = "113 114 115" + k["ELIZA"] = "116 117 118" +} diff --git a/awklib/eg/network/fingerclient.awk b/awklib/eg/network/fingerclient.awk new file mode 100644 index 0000000..bcc2c94 --- /dev/null +++ b/awklib/eg/network/fingerclient.awk @@ -0,0 +1,7 @@ +BEGIN { + NetService = "/inet/tcp/0/localhost/finger" + print "var{name}" |& NetService + while ((NetService |& getline) > 0) + print $0 + close(NetService) +} diff --git a/awklib/eg/network/geturl.awk b/awklib/eg/network/geturl.awk new file mode 100644 index 0000000..53853e5 --- /dev/null +++ b/awklib/eg/network/geturl.awk @@ -0,0 +1,24 @@ +BEGIN { + if (ARGC != 2) { + print "GETURL - retrieve Web page via HTTP 1.0" + print "IN:\n the URL as a command-line parameter" + print "PARAM(S):\n -v Proxy=MyProxy" + print "OUT:\n the page content on stdout" + print " the page header on stderr" + print "JK 16.05.1997" + print "ADR 13.08.2000" + exit + } + URL = ARGV[1]; ARGV[1] = "" + if (Proxy == "") Proxy = "127.0.0.1" + if (ProxyPort == 0) ProxyPort = 80 + if (Method == "") Method = "GET" + HttpService = "/inet/tcp/0/" Proxy "/" ProxyPort + ORS = RS = "\r\n\r\n" + print Method " " URL " HTTP/1.0" |& HttpService + HttpService |& getline Header + print Header > "/dev/stderr" + while ((HttpService |& getline) > 0) + printf "%s", $0 + close(HttpService) +} diff --git a/awklib/eg/network/hello-serv.awk b/awklib/eg/network/hello-serv.awk new file mode 100644 index 0000000..003ee08 --- /dev/null +++ b/awklib/eg/network/hello-serv.awk @@ -0,0 +1,14 @@ +BEGIN { + RS = ORS = "\r\n" + HttpService = "/inet/tcp/8080/0/0" + Hello = "" \ + "A Famous Greeting" \ + "

Hello, world

" + Len = length(Hello) + length(ORS) + print "HTTP/1.0 200 OK" |& HttpService + print "Content-Length: " Len ORS |& HttpService + print Hello |& HttpService + while ((HttpService |& getline) > 0) + continue; + close(HttpService) +} diff --git a/awklib/eg/network/maze.awk b/awklib/eg/network/maze.awk new file mode 100644 index 0000000..97c535f --- /dev/null +++ b/awklib/eg/network/maze.awk @@ -0,0 +1,73 @@ +function SetUpServer() { + TopHeader = "Walk through a maze" + TopDoc = "\ +

Please choose one of the following actions:

\ + " + TopFooter = "" + srand() +} +function HandleGET() { + if (MENU[2] == "AboutServer") { + Document = "If your browser has a VRML 2 plugin,\ + this server shows you a simple VRML scene." + } else if (MENU[2] == "VRMLtest") { + XSIZE = YSIZE = 11 # initially, everything is wall + for (y = 0; y < YSIZE; y++) + for (x = 0; x < XSIZE; x++) + Maze[x, y] = "#" + delete Maze[0, 1] # entry is not wall + delete Maze[XSIZE-1, YSIZE-2] # exit is not wall + MakeMaze(1, 1) + Document = "\ +#VRML V2.0 utf8\n\ +Group {\n\ + children [\n\ + PointLight {\n\ + ambientIntensity 0.2\n\ + color 0.7 0.7 0.7\n\ + location 0.0 8.0 10.0\n\ + }\n\ + DEF B1 Background {\n\ + skyColor [0 0 0, 1.0 1.0 1.0 ]\n\ + skyAngle 1.6\n\ + groundColor [1 1 1, 0.8 0.8 0.8, 0.2 0.2 0.2 ]\n\ + groundAngle [ 1.2 1.57 ]\n\ + }\n\ + DEF Wall Shape {\n\ + geometry Box {size 1 1 1}\n\ + appearance Appearance { material Material { diffuseColor 0 0 1 } }\n\ + }\n\ + DEF Entry Viewpoint {\n\ + position 0.5 1.0 5.0\n\ + orientation 0.0 0.0 -1.0 0.52\n\ + }\n" + for (i in Maze) { + split(i, t, SUBSEP) + Document = Document " Transform { translation " + Document = Document t[1] " 0 -" t[2] " children USE Wall }\n" + } + Document = Document " ] # end of group for world\n}" + Reason = "OK" ORS "Content-type: model/vrml" + Header = Footer = "" + } +} +function MakeMaze(x, y) { + delete Maze[x, y] # here we are, we have no wall here + p = 0 # count unvisited fields in all directions + if (x-2 SUBSEP y in Maze) d[p++] = "-x" + if (x SUBSEP y-2 in Maze) d[p++] = "-y" + if (x+2 SUBSEP y in Maze) d[p++] = "+x" + if (x SUBSEP y+2 in Maze) d[p++] = "+y" + if (p>0) { # if there are unvisited fields, go there + p = int(p*rand()) # choose one unvisited field at random + if (d[p] == "-x") { delete Maze[x - 1, y]; MakeMaze(x - 2, y) + } else if (d[p] == "-y") { delete Maze[x, y - 1]; MakeMaze(x, y - 2) + } else if (d[p] == "+x") { delete Maze[x + 1, y]; MakeMaze(x + 2, y) + } else if (d[p] == "+y") { delete Maze[x, y + 1]; MakeMaze(x, y + 2) + } # we are back from recursion + MakeMaze(x, y); # try again while there are unvisited fields + } +} diff --git a/awklib/eg/network/mobag.awk b/awklib/eg/network/mobag.awk new file mode 100644 index 0000000..a8c5500 --- /dev/null +++ b/awklib/eg/network/mobag.awk @@ -0,0 +1,72 @@ +BEGIN { + if (ARGC != 2) { + print "MOBAG - a simple mobile agent" + print "CALL:\n gawk -f mobag.awk mobag.awk" + print "IN:\n the name of this script as a command-line parameter" + print "PARAM:\n -v MyOrigin=myhost.com" + print "OUT:\n the result on stdout" + print "JK 29.03.1998 01.04.1998" + exit + } + if (MyOrigin == "") { + "uname -n" | getline MyOrigin + close("uname -n") + } +} +#ReadMySelf +/^function / { FUNC = $2 } +/^END/ || /^#ReadMySelf/ { FUNC = $1 } +FUNC != "" { MOBFUN[FUNC] = MOBFUN[FUNC] RS $0 } +(FUNC != "") && (/^}/ || /^#EndOfMySelf/) \ + { FUNC = "" } +#EndOfMySelf +function migrate(Destination, MobCode, Label) { + MOBVAR["Label"] = Label + MOBVAR["Destination"] = Destination + RS = ORS = "\r\n" + HttpService = "/inet/tcp/0/" Destination + for (i in MOBFUN) + MobCode = (MobCode "\n" MOBFUN[i]) + MobCode = MobCode "\n\nBEGIN {" + for (i in MOBVAR) + MobCode = (MobCode "\n MOBVAR[\"" i "\"] = \"" MOBVAR[i] "\"") + MobCode = MobCode "\n}\n" + print "POST /cgi-bin/PostAgent.sh HTTP/1.0" |& HttpService + print "Content-length:", length(MobCode) ORS |& HttpService + printf "%s", MobCode |& HttpService + while ((HttpService |& getline) > 0) + print $0 + close(HttpService) +} +END { + if (ARGC != 2) exit # stop when called with wrong parameters + if (MyOrigin != "") # is this the originating host? + MyInit() # if so, initialize the application + else # we are on a host with migrated data + MyJob() # so we do our job +} +function MyInit() { + MOBVAR["MyOrigin"] = MyOrigin + MOBVAR["Machines"] = "localhost/80 max/80 moritz/80 castor/80" + split(MOBVAR["Machines"], Machines) # which host is the first? + migrate(Machines[1], "", "") # go to the first host + while (("/inet/tcp/8080/0/0" |& getline) > 0) # wait for result + print $0 # print result + close("/inet/tcp/8080/0/0") +} +function MyJob() { + # forget this host + sub(MOBVAR["Destination"], "", MOBVAR["Machines"]) + MOBVAR["Result"]=MOBVAR["Result"] SUBSEP SUBSEP MOBVAR["Destination"] ":" + while (("who" | getline) > 0) # who is logged in? + MOBVAR["Result"] = MOBVAR["Result"] SUBSEP $0 + close("who") + if (index(MOBVAR["Machines"], "/") > 0) { # any more machines to visit? + split(MOBVAR["Machines"], Machines) # which host is next? + migrate(Machines[1], "", "") # go there + } else { # no more machines + gsub(SUBSEP, "\n", MOBVAR["Result"]) # send result to origin + print MOBVAR["Result"] |& "/inet/tcp/0/" MOBVAR["MyOrigin"] "/8080" + close("/inet/tcp/0/" MOBVAR["MyOrigin"] "/8080") + } +} diff --git a/awklib/eg/network/panic.awk b/awklib/eg/network/panic.awk new file mode 100644 index 0000000..6db8c46 --- /dev/null +++ b/awklib/eg/network/panic.awk @@ -0,0 +1,18 @@ +BEGIN { + RS = ORS = "\r\n" + if (MyPort == 0) MyPort = 8080 + HttpService = "/inet/tcp/" MyPort "/0/0" + Hello = "Out Of Service" \ + "

" \ + "This site is temporarily out of service." \ + "

" + Len = length(Hello) + length(ORS) + while ("awk" != "complex") { + print "HTTP/1.0 200 OK" |& HttpService + print "Content-Length: " Len ORS |& HttpService + print Hello |& HttpService + while ((HttpService |& getline) > 0) + continue; + close(HttpService) + } +} diff --git a/awklib/eg/network/protbase.awk b/awklib/eg/network/protbase.awk new file mode 100644 index 0000000..f4a911c --- /dev/null +++ b/awklib/eg/network/protbase.awk @@ -0,0 +1,11 @@ +{ request = request "\n" $0 } + +END { + BLASTService = "/inet/tcp/0/www.ncbi.nlm.nih.gov/80" + printf "POST /cgi-bin/BLAST/nph-blast_report HTTP/1.0\n" |& BLASTService + printf "Content-Length: " length(request) "\n\n" |& BLASTService + printf request |& BLASTService + while ((BLASTService |& getline) > 0) + print $0 + close(BLASTService) +} diff --git a/awklib/eg/network/protbase.request b/awklib/eg/network/protbase.request new file mode 100644 index 0000000..4c5c3d2 --- /dev/null +++ b/awklib/eg/network/protbase.request @@ -0,0 +1,7 @@ +PROGRAM blastn +DATALIB month +EXPECT 0.75 +BEGIN +>GAWK310 the gawking gene GNU AWK +tgcttggctgaggagccataggacgagagcttcctggtgaagtgtgtttcttgaaatcat +caccaccatggacagcaaa diff --git a/awklib/eg/network/protbase.result b/awklib/eg/network/protbase.result new file mode 100644 index 0000000..a087af4 --- /dev/null +++ b/awklib/eg/network/protbase.result @@ -0,0 +1,9 @@ +Sequences producing significant alignments: (bits) Value + +gb|AC021182.14|AC021182 Homo sapiens chromosome 7 clone RP11-733... 38 0.20 +gb|AC021056.12|AC021056 Homo sapiens chromosome 3 clone RP11-115... 38 0.20 +emb|AL160278.10|AL160278 Homo sapiens chromosome 9 clone RP11-57... 38 0.20 +emb|AL391139.11|AL391139 Homo sapiens chromosome X clone RP11-35... 38 0.20 +emb|AL365192.6|AL365192 Homo sapiens chromosome 6 clone RP3-421H... 38 0.20 +emb|AL138812.9|AL138812 Homo sapiens chromosome 11 clone RP1-276... 38 0.20 +gb|AC073881.3|AC073881 Homo sapiens chromosome 15 clone CTD-2169... 38 0.20 diff --git a/awklib/eg/network/remconf.awk b/awklib/eg/network/remconf.awk new file mode 100644 index 0000000..ef92226 --- /dev/null +++ b/awklib/eg/network/remconf.awk @@ -0,0 +1,54 @@ +function SetUpServer() { + TopHeader = "Remote Configuration" + TopDoc = "\ +

Please choose one of the following actions:

\ + " + TopFooter = "" + if (ConfigFile == "") ConfigFile = "config.asc" +} +function HandleGET() { + if(MENU[2] == "AboutServer") { + Document = "This is a GUI for remote configuration of an\ + embedded system. It is is implemented as one GAWK script." + } else if (MENU[2] == "ReadConfig") { + RS = "\n" + while ((getline < ConfigFile) > 0) + config[$1] = $2; + close(ConfigFile) + RS = "\r\n" + Document = "Configuration has been read." + } else if (MENU[2] == "CheckConfig") { + Document = "" + for (i in config) + Document = Document "" \ + "" + Document = Document "
" i "" config[i] "
" + } else if (MENU[2] == "ChangeConfig") { + if ("Param" in GETARG) { # any parameter to set? + if (GETARG["Param"] in config) { # is parameter valid? + config[GETARG["Param"]] = GETARG["Value"] + Document = (GETARG["Param"] " = " GETARG["Value"] ".") + } else { + Document = "Parameter " GETARG["Param"] " is invalid." + } + } else { + Document = "

Change one parameter

\ + \ + \ + \ + \ +
ParameterValue
" + } + } else if (MENU[2] == "SaveConfig") { + for (i in config) + printf("%s %s\n", i, config[i]) > ConfigFile + close(ConfigFile) + Document = "Configuration has been saved." + } +} diff --git a/awklib/eg/network/statist.awk b/awklib/eg/network/statist.awk new file mode 100644 index 0000000..a4fc55c --- /dev/null +++ b/awklib/eg/network/statist.awk @@ -0,0 +1,85 @@ +function SetUpServer() { + TopHeader = "Statistics with GAWK" + TopDoc = "\ +

Please choose one of the following actions:

\ + " + TopFooter = "" + GnuPlot = "gnuplot 2>&1" + m1=m2=0; v1=v2=1; n1=n2=10 +} +function HandleGET() { + if(MENU[2] == "AboutServer") { + Document = "This is a GUI for a statistical computation.\ + It compares means and variances of two distributions.\ + It is implemented as one GAWK script and uses GNUPLOT." + } else if (MENU[2] == "EnterParameters") { + Document = "" + if ("m1" in GETARG) { # are there parameters to compare? + Document = Document "" + m1 = GETARG["m1"]; v1 = GETARG["v1"]; n1 = GETARG["n1"] + m2 = GETARG["m2"]; v2 = GETARG["v2"]; n2 = GETARG["n2"] + t = (m1-m2)/sqrt(v1/n1+v2/n2) + df = (v1/n1+v2/n2)*(v1/n1+v2/n2)/((v1/n1)*(v1/n1)/(n1-1) \ + + (v2/n2)*(v2/n2) /(n2-1)) + if (v1>v2) { + f = v1/v2 + df1 = n1 - 1 + df2 = n2 - 1 + } else { + f = v2/v1 + df1 = n2 - 1 + df2 = n1 - 1 + } + print "pt=ibeta(" df/2 ",0.5," df/(df+t*t) ")" |& GnuPlot + print "pF=2.0*ibeta(" df2/2 "," df1/2 "," \ + df2/(df2+df1*f) ")" |& GnuPlot + print "print pt, pF" |& GnuPlot + RS="\n"; GnuPlot |& getline; RS="\r\n" # $1 is pt, $2 is pF + print "invsqrt2pi=1.0/sqrt(2.0*pi)" |& GnuPlot + print "nd(x)=invsqrt2pi/sd*exp(-0.5*((x-mu)/sd)**2)" |& GnuPlot + print "set term png small color" |& GnuPlot + #print "set term postscript color" |& GnuPlot + #print "set term gif medium size 320,240" |& GnuPlot + print "set yrange[-0.3:]" |& GnuPlot + print "set label 'p(m1=m2) =" $1 "' at 0,-0.1 left" |& GnuPlot + print "set label 'p(v1=v2) =" $2 "' at 0,-0.2 left" |& GnuPlot + print "plot mu=" m1 ",sd=" sqrt(v1) ", nd(x) title 'sample 1',\ + mu=" m2 ",sd=" sqrt(v2) ", nd(x) title 'sample 2'" |& GnuPlot + print "quit" |& GnuPlot + GnuPlot |& getline Image + while ((GnuPlot |& getline) > 0) + Image = Image RS $0 + close(GnuPlot) + } + Document = Document "\ +

Do these samples have the same Gaussian distribution?

\ +
\ + \ + + \ + + \ + + \ + \ + + \ + + \ + + \ + \ +
1. Mean 1. Variance1. Count
2. Mean 2. Variance2. Count

" + } else if (MENU[2] ~ "Image") { + Reason = "OK" ORS "Content-type: image/png" + #Reason = "OK" ORS "Content-type: application/x-postscript" + #Reason = "OK" ORS "Content-type: image/gif" + Header = Footer = "" + Document = Image + } +} diff --git a/awklib/eg/network/stoxdata.txt b/awklib/eg/network/stoxdata.txt new file mode 100644 index 0000000..1b6d015 --- /dev/null +++ b/awklib/eg/network/stoxdata.txt @@ -0,0 +1,4 @@ +Date,Open,High,Low,Close,Volume +9-Oct-00,22.75,22.75,21.375,22.375,7888500 +6-Oct-00,23.8125,24.9375,21.5625,22,10701100 +5-Oct-00,24.4375,24.625,23.125,23.50,5810300 diff --git a/awklib/eg/network/stoxpred.awk b/awklib/eg/network/stoxpred.awk new file mode 100644 index 0000000..62744c1 --- /dev/null +++ b/awklib/eg/network/stoxpred.awk @@ -0,0 +1,116 @@ +function ReadQuotes() { + # Retrieve historical data for each ticker symbol + FS = "," + for (stock = 1; stock <= StockCount; stock++) { + URL = "http://chart.yahoo.com/table.csv?s=" name[stock] \ + "&a=" month "&b=" day "&c=" year-1 \ + "&d=" month "&e=" day "&f=" year \ + "g=d&q=q&y=0&z=" name[stock] "&x=.csv" + printf("GET " URL " HTTP/1.0\r\n\r\n") |& YahooData + while ((YahooData |& getline) > 0) { + if (NF == 6 && $1 ~ /Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec/) { + if (stock == 1) + days[++daycount] = $1; + quote[$1, stock] = $5 + } + } + close(YahooData) + } + FS = " " +} +function CleanUp() { + # clean up time series; eliminate incomplete data sets + for (d = 1; d <= daycount; d++) { + for (stock = 1; stock <= StockCount; stock++) + if (! ((days[d], stock) in quote)) + stock = StockCount + 10 + if (stock > StockCount + 1) + continue + datacount++ + for (stock = 1; stock <= StockCount; stock++) + data[datacount, stock] = int(0.5 + quote[days[d], stock]) + } + delete quote + delete days +} +function Prediction() { + # Predict each ticker symbol by prolonging yesterday's trend + for (stock = 1; stock <= StockCount; stock++) { + if (data[1, stock] > data[2, stock]) { + predict[stock] = "up" + } else if (data[1, stock] < data[2, stock]) { + predict[stock] = "down" + } else { + predict[stock] = "neutral" + } + if ((data[1, stock] > data[2, stock]) && (data[2, stock] > data[3, stock])) + hot[stock] = 1 + if ((data[1, stock] < data[2, stock]) && (data[2, stock] < data[3, stock])) + avoid[stock] = 1 + } + # Do a plausibility check: how many predictions proved correct? + for (s = 1; s <= StockCount; s++) { + for (d = 1; d <= datacount-2; d++) { + if (data[d+1, s] > data[d+2, s]) { + UpCount++ + } else if (data[d+1, s] < data[d+2, s]) { + DownCount++ + } else { + NeutralCount++ + } + if (((data[d, s] > data[d+1, s]) && (data[d+1, s] > data[d+2, s])) || + ((data[d, s] < data[d+1, s]) && (data[d+1, s] < data[d+2, s])) || + ((data[d, s] == data[d+1, s]) && (data[d+1, s] == data[d+2, s]))) + CorrectCount++ + } + } +} +function Report() { + # Generate report + report = "\nThis is your daily " + report = report "stock market report for "strftime("%A, %B %d, %Y")".\n" + report = report "Here are the predictions for today:\n\n" + for (stock = 1; stock <= StockCount; stock++) + report = report "\t" name[stock] "\t" predict[stock] "\n" + for (stock in hot) { + if (HotCount++ == 0) + report = report "\nThe most promising shares for today are these:\n\n" + report = report "\t" name[stock] "\t\thttp://biz.yahoo.com/n/" \ + tolower(substr(name[stock], 1, 1)) "/" tolower(name[stock]) ".html\n" + } + for (stock in avoid) { + if (AvoidCount++ == 0) + report = report "\nThe stock shares to avoid today are these:\n\n" + report = report "\t" name[stock] "\t\thttp://biz.yahoo.com/n/" \ + tolower(substr(name[stock], 1, 1)) "/" tolower(name[stock]) ".html\n" + } + report = report "\nThis sums up to " HotCount+0 " winners and " AvoidCount+0 + report = report " losers. When using this kind\nof prediction scheme for" + report = report " the 12 months which lie behind us,\nwe get " UpCount + report = report " 'ups' and " DownCount " 'downs' and " NeutralCount + report = report " 'neutrals'. Of all\nthese " UpCount+DownCount+NeutralCount + report = report " predictions " CorrectCount " proved correct next day.\n" + report = report "A success rate of "\ + int(100*CorrectCount/(UpCount+DownCount+NeutralCount)) "%.\n" + report = report "Random choice would have produced a 33% success rate.\n" + report = report "Disclaimer: Like every other prediction of the stock\n" + report = report "market, this report is, of course, complete nonsense.\n" + report = report "If you are stupid enough to believe these predictions\n" + report = report "you should visit a doctor who can treat your ailment." +} +function SendMail() { + # send report to customers + customer["uncle.scrooge@ducktown.gov"] = "Uncle Scrooge" + customer["more@utopia.org" ] = "Sir Thomas More" + customer["spinoza@denhaag.nl" ] = "Baruch de Spinoza" + customer["marx@highgate.uk" ] = "Karl Marx" + customer["keynes@the.long.run" ] = "John Maynard Keynes" + customer["bierce@devil.hell.org" ] = "Ambrose Bierce" + customer["laplace@paris.fr" ] = "Pierre Simon de Laplace" + for (c in customer) { + MailPipe = "mail -s 'Daily Stock Prediction Newsletter'" c + print "Good morning " customer[c] "," | MailPipe + print report "\n.\n" | MailPipe + close(MailPipe) + } +} diff --git a/awklib/eg/network/testserv.awk b/awklib/eg/network/testserv.awk new file mode 100644 index 0000000..812bfe6 --- /dev/null +++ b/awklib/eg/network/testserv.awk @@ -0,0 +1,12 @@ +BEGIN { + CGI_setup("GET", + "http://www.gnu.org/cgi-bin/foo?p1=stuff&p2=stuff%26junk" \ + "&percent=a %25 sign", + "1.0") + for (i in MENU) + printf "MENU[\"%s\"] = %s\n", i, MENU[i] + for (i in PARAM) + printf "PARAM[\"%s\"] = %s\n", i, PARAM[i] + for (i in GETARG) + printf "GETARG[\"%s\"] = %s\n", i, GETARG[i] +} diff --git a/awklib/eg/network/urlchk.awk b/awklib/eg/network/urlchk.awk new file mode 100644 index 0000000..6ddedfa --- /dev/null +++ b/awklib/eg/network/urlchk.awk @@ -0,0 +1,28 @@ +BEGIN { + if (ARGC != 2) { + print "URLCHK - check if URLs have changed" + print "IN:\n the file with URLs as a command-line parameter" + print " file contains URL, old length, new length" + print "PARAMS:\n -v Proxy=MyProxy -v ProxyPort=8080" + print "OUT:\n same as file with URLs" + print "JK 02.03.1998" + exit + } + URLfile = ARGV[1]; ARGV[1] = "" + if (Proxy != "") Proxy = " -v Proxy=" Proxy + if (ProxyPort != "") ProxyPort = " -v ProxyPort=" ProxyPort + while ((getline < URLfile) > 0) + Length[$1] = $3 + 0 + close(URLfile) # now, URLfile is read in and can be updated + GetHeader = "gawk " Proxy ProxyPort " -v Method=\"HEAD\" -f geturl.awk " + for (i in Length) { + GetThisHeader = GetHeader i " 2>&1" + while ((GetThisHeader | getline) > 0) + if (toupper($0) ~ /CONTENT-LENGTH/) NewLength = $2 + 0 + close(GetThisHeader) + print i, Length[i], NewLength > URLfile + if (Length[i] != NewLength) # report only changed URLs + print i, Length[i], NewLength + } + close(URLfile) +} diff --git a/awklib/eg/network/webgrab.awk b/awklib/eg/network/webgrab.awk new file mode 100644 index 0000000..4173880 --- /dev/null +++ b/awklib/eg/network/webgrab.awk @@ -0,0 +1,6 @@ +BEGIN { RS = "http://[#%&\\+\\-\\./0-9\\:;\\?A-Z_a-z\\~]*" } +RT != "" { + command = ("gawk -v Proxy=MyProxy -f geturl.awk " RT \ + " > doc" NR ".html") + print command +} diff --git a/awklib/eg/prog/alarm.awk b/awklib/eg/prog/alarm.awk new file mode 100644 index 0000000..59630ea --- /dev/null +++ b/awklib/eg/prog/alarm.awk @@ -0,0 +1,90 @@ +# alarm.awk --- set an alarm +# +# Requires getlocaltime() library function +# +# Arnold Robbins, arnold@skeeve.com, Public Domain +# May 1993 +# Revised December 2010 + +# usage: alarm time [ "message" [ count [ delay ] ] ] + +BEGIN { + # Initial argument sanity checking + usage1 = "usage: alarm time ['message' [count [delay]]]" + usage2 = sprintf("\t(%s) time ::= hh:mm", ARGV[1]) + + if (ARGC < 2) { + print usage1 > "/dev/stderr" + print usage2 > "/dev/stderr" + exit 1 + } + switch (ARGC) { + case 5: + delay = ARGV[4] + 0 + # fall through + case 4: + count = ARGV[3] + 0 + # fall through + case 3: + message = ARGV[2] + break + default: + if (ARGV[1] !~ /[[:digit:]]?[[:digit:]]:[[:digit:]]{2}/) { + print usage1 > "/dev/stderr" + print usage2 > "/dev/stderr" + exit 1 + } + break + } + + # set defaults for once we reach the desired time + if (delay == 0) + delay = 180 # 3 minutes + if (count == 0) + count = 5 + if (message == "") + message = sprintf("\aIt is now %s!\a", ARGV[1]) + else if (index(message, "\a") == 0) + message = "\a" message "\a" + # split up alarm time + split(ARGV[1], atime, ":") + hour = atime[1] + 0 # force numeric + minute = atime[2] + 0 # force numeric + + # get current broken down time + getlocaltime(now) + + # if time given is 12-hour hours and it's after that + # hour, e.g., `alarm 5:30' at 9 a.m. means 5:30 p.m., + # then add 12 to real hour + if (hour < 12 && now["hour"] > hour) + hour += 12 + + # set target time in seconds since midnight + target = (hour * 60 * 60) + (minute * 60) + + # get current time in seconds since midnight + current = (now["hour"] * 60 * 60) + \ + (now["minute"] * 60) + now["second"] + + # how long to sleep for + naptime = target - current + if (naptime <= 0) { + print "alarm: time is in the past!" > "/dev/stderr" + exit 1 + } + # zzzzzz..... go away if interrupted + if (system(sprintf("sleep %d", naptime)) != 0) + exit 1 + + # time to notify! + command = sprintf("sleep %d", delay) + for (i = 1; i <= count; i++) { + print message + # if sleep command interrupted, go away + if (system(command) != 0) + break + } + + exit 0 +} diff --git a/awklib/eg/prog/anagram.awk b/awklib/eg/prog/anagram.awk new file mode 100644 index 0000000..4c2ce1f --- /dev/null +++ b/awklib/eg/prog/anagram.awk @@ -0,0 +1,50 @@ +# anagram.awk --- An implementation of the anagram-finding algorithm +# from Jon Bentley's "Programming Pearls," 2nd edition. +# Addison Wesley, 2000, ISBN 0-201-65788-0. +# Column 2, Problem C, section 2.8, pp 18-20. +# +# This program requires gawk 4.0 or newer. +# Required gawk-specific features: +# - True multidimensional arrays +# - split() with "" as separator splits out individual characters +# - asort() and asorti() functions +# +# See https://savannah.gnu.org/projects/gawk. +# +# Arnold Robbins +# arnold@skeeve.com +# Public Domain +# January, 2011 + +/'s$/ { next } # Skip possessives +{ + key = word2key($1) # Build signature + data[key][$1] = $1 # Store word with signature +} +# word2key --- split word apart into letters, sort, and join back together + +function word2key(word, a, i, n, result) +{ + n = split(word, a, "") + asort(a) + + for (i = 1; i <= n; i++) + result = result a[i] + + return result +} +END { + sort = "sort" + for (key in data) { + # Sort words with same key + nwords = asorti(data[key], words) + if (nwords == 1) + continue + + # And print. Minor glitch: trailing space at end of each line + for (j = 1; j <= nwords; j++) + printf("%s ", words[j]) | sort + print "" | sort + } + close(sort) +} diff --git a/awklib/eg/prog/awksed.awk b/awklib/eg/prog/awksed.awk new file mode 100644 index 0000000..d9f1771 --- /dev/null +++ b/awklib/eg/prog/awksed.awk @@ -0,0 +1,31 @@ +# awksed.awk --- do s/foo/bar/g using just print +# Thanks to Michael Brennan for the idea +# +# Arnold Robbins, arnold@skeeve.com, Public Domain +# August 1995 + +function usage() +{ + print "usage: awksed pat repl [files...]" > "/dev/stderr" + exit 1 +} + +BEGIN { + # validate arguments + if (ARGC < 3) + usage() + + RS = ARGV[1] + ORS = ARGV[2] + + # don't use arguments as files + ARGV[1] = ARGV[2] = "" +} + +# look ma, no hands! +{ + if (RT == "") + printf "%s", $0 + else + print +} diff --git a/awklib/eg/prog/cut.awk b/awklib/eg/prog/cut.awk new file mode 100644 index 0000000..fd77910 --- /dev/null +++ b/awklib/eg/prog/cut.awk @@ -0,0 +1,137 @@ +# cut.awk --- implement cut in awk +# +# Arnold Robbins, arnold@skeeve.com, Public Domain +# May 1993 + +# Options: +# -f list Cut fields +# -d c Field delimiter character +# -c list Cut characters +# +# -s Suppress lines without the delimiter +# +# Requires getopt() and join() library functions + +function usage() +{ + print("usage: cut [-f list] [-d c] [-s] [files...]") > "/dev/stderr" + print("usage: cut [-c list] [files...]") > "/dev/stderr" + exit 1 +} +BEGIN { + FS = "\t" # default + OFS = FS + while ((c = getopt(ARGC, ARGV, "sf:c:d:")) != -1) { + if (c == "f") { + by_fields = 1 + fieldlist = Optarg + } else if (c == "c") { + by_chars = 1 + fieldlist = Optarg + OFS = "" + } else if (c == "d") { + if (length(Optarg) > 1) { + printf("cut: using first character of %s" \ + " for delimiter\n", Optarg) > "/dev/stderr" + Optarg = substr(Optarg, 1, 1) + } + fs = FS = Optarg + OFS = FS + if (FS == " ") # defeat awk semantics + FS = "[ ]" + } else if (c == "s") + suppress = 1 + else + usage() + } + + # Clear out options + for (i = 1; i < Optind; i++) + ARGV[i] = "" + if (by_fields && by_chars) + usage() + + if (by_fields == 0 && by_chars == 0) + by_fields = 1 # default + + if (fieldlist == "") { + print "cut: needs list for -c or -f" > "/dev/stderr" + exit 1 + } + + if (by_fields) + set_fieldlist() + else + set_charlist() +} +function set_fieldlist( n, m, i, j, k, f, g) +{ + n = split(fieldlist, f, ",") + j = 1 # index in flist + for (i = 1; i <= n; i++) { + if (index(f[i], "-") != 0) { # a range + m = split(f[i], g, "-") + if (m != 2 || g[1] >= g[2]) { + printf("cut: bad field list: %s\n", + f[i]) > "/dev/stderr" + exit 1 + } + for (k = g[1]; k <= g[2]; k++) + flist[j++] = k + } else + flist[j++] = f[i] + } + nfields = j - 1 +} +function set_charlist( field, i, j, f, g, n, m, t, + filler, last, len) +{ + field = 1 # count total fields + n = split(fieldlist, f, ",") + j = 1 # index in flist + for (i = 1; i <= n; i++) { + if (index(f[i], "-") != 0) { # range + m = split(f[i], g, "-") + if (m != 2 || g[1] >= g[2]) { + printf("cut: bad character list: %s\n", + f[i]) > "/dev/stderr" + exit 1 + } + len = g[2] - g[1] + 1 + if (g[1] > 1) # compute length of filler + filler = g[1] - last - 1 + else + filler = 0 + if (filler) + t[field++] = filler + t[field++] = len # length of field + last = g[2] + flist[j++] = field - 1 + } else { + if (f[i] > 1) + filler = f[i] - last - 1 + else + filler = 0 + if (filler) + t[field++] = filler + t[field++] = 1 + last = f[i] + flist[j++] = field - 1 + } + } + FIELDWIDTHS = join(t, 1, field - 1) + nfields = j - 1 +} +{ + if (by_fields && suppress && index($0, fs) == 0) + next + + for (i = 1; i <= nfields; i++) { + if ($flist[i] != "") { + printf "%s", $flist[i] + if (i < nfields && $flist[i+1] != "") + printf "%s", OFS + } + } + print "" +} diff --git a/awklib/eg/prog/dupword.awk b/awklib/eg/prog/dupword.awk new file mode 100644 index 0000000..047b99f --- /dev/null +++ b/awklib/eg/prog/dupword.awk @@ -0,0 +1,21 @@ +# dupword.awk --- find duplicate words in text +# +# Arnold Robbins, arnold@skeeve.com, Public Domain +# December 1991 +# Revised October 2000 + +{ + $0 = tolower($0) + gsub(/[^[:alnum:][:blank:]]/, " "); + $0 = $0 # re-split + if (NF == 0) + next + if ($1 == prev) + printf("%s:%d: duplicate %s\n", + FILENAME, FNR, $1) + for (i = 2; i <= NF; i++) + if ($i == $(i-1)) + printf("%s:%d: duplicate %s\n", + FILENAME, FNR, $i) + prev = $NF +} diff --git a/awklib/eg/prog/egrep.awk b/awklib/eg/prog/egrep.awk new file mode 100644 index 0000000..a4165a9 --- /dev/null +++ b/awklib/eg/prog/egrep.awk @@ -0,0 +1,99 @@ +# egrep.awk --- simulate egrep in awk +# +# Arnold Robbins, arnold@skeeve.com, Public Domain +# May 1993 + +# Options: +# -c count of lines +# -s silent - use exit value +# -v invert test, success if no match +# -i ignore case +# -l print filenames only +# -e argument is pattern +# +# Requires getopt and file transition library functions + +BEGIN { + while ((c = getopt(ARGC, ARGV, "ce:svil")) != -1) { + if (c == "c") + count_only++ + else if (c == "s") + no_print++ + else if (c == "v") + invert++ + else if (c == "i") + IGNORECASE = 1 + else if (c == "l") + filenames_only++ + else if (c == "e") + pattern = Optarg + else + usage() + } + if (pattern == "") + pattern = ARGV[Optind++] + + for (i = 1; i < Optind; i++) + ARGV[i] = "" + if (Optind >= ARGC) { + ARGV[1] = "-" + ARGC = 2 + } else if (ARGC - Optind > 1) + do_filenames++ + +# if (IGNORECASE) +# pattern = tolower(pattern) +} +#{ +# if (IGNORECASE) +# $0 = tolower($0) +#} +function beginfile(junk) +{ + fcount = 0 +} +function endfile(file) +{ + if (! no_print && count_only) { + if (do_filenames) + print file ":" fcount + else + print fcount + } + + total += fcount +} +{ + matches = ($0 ~ pattern) + if (invert) + matches = ! matches + + fcount += matches # 1 or 0 + + if (! matches) + next + + if (! count_only) { + if (no_print) + nextfile + + if (filenames_only) { + print FILENAME + nextfile + } + + if (do_filenames) + print FILENAME ":" $0 + else + print + } +} +END { + exit (total == 0) +} +function usage() +{ + print("Usage: egrep [-csvil] [-e pat] [files ...]") > "/dev/stderr" + print("\n\tegrep [-csvil] pat [files ...]") > "/dev/stderr" + exit 1 +} diff --git a/awklib/eg/prog/extract.awk b/awklib/eg/prog/extract.awk new file mode 100644 index 0000000..f5dfcf4 --- /dev/null +++ b/awklib/eg/prog/extract.awk @@ -0,0 +1,73 @@ +# extract.awk --- extract files and run programs from Texinfo files +# +# Arnold Robbins, arnold@skeeve.com, Public Domain +# May 1993 +# Revised September 2000 + +BEGIN { IGNORECASE = 1 } + +/^@c(omment)?[ \t]+system/ { + if (NF < 3) { + e = ("extract: " FILENAME ":" FNR) + e = (e ": badly formed `system' line") + print e > "/dev/stderr" + next + } + $1 = "" + $2 = "" + stat = system($0) + if (stat != 0) { + e = ("extract: " FILENAME ":" FNR) + e = (e ": warning: system returned " stat) + print e > "/dev/stderr" + } +} +/^@c(omment)?[ \t]+file/ { + if (NF != 3) { + e = ("extract: " FILENAME ":" FNR ": badly formed `file' line") + print e > "/dev/stderr" + next + } + if ($3 != curfile) { + if (curfile != "") + close(curfile) + curfile = $3 + } + + for (;;) { + if ((getline line) <= 0) + unexpected_eof() + if (line ~ /^@c(omment)?[ \t]+endfile/) + break + else if (line ~ /^@(end[ \t]+)?group/) + continue + else if (line ~ /^@c(omment+)?[ \t]+/) + continue + if (index(line, "@") == 0) { + print line > curfile + continue + } + n = split(line, a, "@") + # if a[1] == "", means leading @, + # don't add one back in. + for (i = 2; i <= n; i++) { + if (a[i] == "") { # was an @@ + a[i] = "@" + if (a[i+1] == "") + i++ + } + } + print join(a, 1, n, SUBSEP) > curfile + } +} +function unexpected_eof() +{ + printf("extract: %s:%d: unexpected EOF or error\n", + FILENAME, FNR) > "/dev/stderr" + exit 1 +} + +END { + if (curfile) + close(curfile) +} diff --git a/awklib/eg/prog/guide.awk b/awklib/eg/prog/guide.awk new file mode 100644 index 0000000..a2dea1b --- /dev/null +++ b/awklib/eg/prog/guide.awk @@ -0,0 +1,7 @@ +BEGIN { + TEXTDOMAIN = "guide" + bindtextdomain(".") # for testing + print _"Don't Panic" + print _"The Answer Is", 42 + print "Pardon me, Zaphod who?" +} diff --git a/awklib/eg/prog/histsort.awk b/awklib/eg/prog/histsort.awk new file mode 100644 index 0000000..b156f67 --- /dev/null +++ b/awklib/eg/prog/histsort.awk @@ -0,0 +1,15 @@ +# histsort.awk --- compact a shell history file +# Thanks to Byron Rakitzis for the general idea +# +# Arnold Robbins, arnold@skeeve.com, Public Domain +# May 1993 + +{ + if (data[$0]++ == 0) + lines[++count] = $0 +} + +END { + for (i = 1; i <= count; i++) + print lines[i] +} diff --git a/awklib/eg/prog/id.awk b/awklib/eg/prog/id.awk new file mode 100644 index 0000000..b6061f9 --- /dev/null +++ b/awklib/eg/prog/id.awk @@ -0,0 +1,61 @@ +# id.awk --- implement id in awk +# +# Requires user and group library functions +# +# Arnold Robbins, arnold@skeeve.com, Public Domain +# May 1993 +# Revised February 1996 +# Revised May 2014 +# Revised September 2014 + +# output is: +# uid=12(foo) euid=34(bar) gid=3(baz) \ +# egid=5(blat) groups=9(nine),2(two),1(one) + +BEGIN { + uid = PROCINFO["uid"] + euid = PROCINFO["euid"] + gid = PROCINFO["gid"] + egid = PROCINFO["egid"] + + printf("uid=%d", uid) + pw = getpwuid(uid) + pr_first_field(pw) + + if (euid != uid) { + printf(" euid=%d", euid) + pw = getpwuid(euid) + pr_first_field(pw) + } + + printf(" gid=%d", gid) + pw = getgrgid(gid) + pr_first_field(pw) + + if (egid != gid) { + printf(" egid=%d", egid) + pw = getgrgid(egid) + pr_first_field(pw) + } + + for (i = 1; ("group" i) in PROCINFO; i++) { + if (i == 1) + printf(" groups=") + group = PROCINFO["group" i] + printf("%d", group) + pw = getgrgid(group) + pr_first_field(pw) + if (("group" (i+1)) in PROCINFO) + printf(",") + } + + print "" +} + +function pr_first_field(str, a) +{ + if (str != "") { + split(str, a, ":") + printf("(%s)", a[1]) + } +} diff --git a/awklib/eg/prog/igawk.sh b/awklib/eg/prog/igawk.sh new file mode 100644 index 0000000..70edf60 --- /dev/null +++ b/awklib/eg/prog/igawk.sh @@ -0,0 +1,138 @@ +#! /bin/sh +# igawk --- like gawk but do @include processing +# +# Arnold Robbins, arnold@skeeve.com, Public Domain +# July 1993 +# December 2010, minor edits + +if [ "$1" = debug ] +then + set -x + shift +fi + +# A literal newline, so that program text is formatted correctly +n=' +' + +# Initialize variables to empty +program= +opts= + +while [ $# -ne 0 ] # loop over arguments +do + case $1 in + --) shift + break ;; + + -W) shift + # The ${x?'message here'} construct prints a + # diagnostic if $x is the null string + set -- -W"${@?'missing operand'}" + continue ;; + + -[vF]) opts="$opts $1 '${2?'missing operand'}'" + shift ;; + + -[vF]*) opts="$opts '$1'" ;; + + -f) program="$program$n@include ${2?'missing operand'}" + shift ;; + + -f*) f=$(expr "$1" : '-f\(.*\)') + program="$program$n@include $f" ;; + + -[W-]file=*) + f=$(expr "$1" : '-.file=\(.*\)') + program="$program$n@include $f" ;; + + -[W-]file) + program="$program$n@include ${2?'missing operand'}" + shift ;; + + -[W-]source=*) + t=$(expr "$1" : '-.source=\(.*\)') + program="$program$n$t" ;; + + -[W-]source) + program="$program$n${2?'missing operand'}" + shift ;; + + -[W-]version) + echo igawk: version 3.0 1>&2 + gawk --version + exit 0 ;; + + -[W-]*) opts="$opts '$1'" ;; + + *) break ;; + esac + shift +done + +if [ -z "$program" ] +then + program=${1?'missing program'} + shift +fi + +# At this point, `program' has the program. +expand_prog=' + +function pathto(file, i, t, junk) +{ + if (index(file, "/") != 0) + return file + + if (file == "-") + return file + + for (i = 1; i <= ndirs; i++) { + t = (pathlist[i] "/" file) + if ((getline junk < t) > 0) { + # found it + close(t) + return t + } + } + return "" +} +BEGIN { + path = ENVIRON["AWKPATH"] + ndirs = split(path, pathlist, ":") + for (i = 1; i <= ndirs; i++) { + if (pathlist[i] == "") + pathlist[i] = "." + } + stackptr = 0 + input[stackptr] = ARGV[1] # ARGV[1] is first file + + for (; stackptr >= 0; stackptr--) { + while ((getline < input[stackptr]) > 0) { + if (tolower($1) != "@include") { + print + continue + } + fpath = pathto($2) + if (fpath == "") { + printf("igawk: %s:%d: cannot find %s\n", + input[stackptr], FNR, $2) > "/dev/stderr" + continue + } + if (! (fpath in processed)) { + processed[fpath] = input[stackptr] + input[++stackptr] = fpath # push onto stack + } else + print $2, "included in", input[stackptr], + "already included in", + processed[fpath] > "/dev/stderr" + } + close(input[stackptr]) + } +}' # close quote ends `expand_prog' variable + +processed_program=$(gawk -- "$expand_prog" /dev/stdin << EOF +$program +EOF +) +eval gawk $opts -- '"$processed_program"' '"$@"' diff --git a/awklib/eg/prog/indirectcall.awk b/awklib/eg/prog/indirectcall.awk new file mode 100644 index 0000000..165b022 --- /dev/null +++ b/awklib/eg/prog/indirectcall.awk @@ -0,0 +1,45 @@ +# num_lt --- do a numeric less than comparison + +function num_lt(left, right) +{ + return ((left + 0) < (right + 0)) +} + +# num_ge --- do a numeric greater than or equal to comparison + +function num_ge(left, right) +{ + return ((left + 0) >= (right + 0)) +} +# do_sort --- sort the data according to `compare' +# and return it as a string + +function do_sort(first, last, compare, data, i, retval) +{ + delete data + for (i = 1; first <= last; first++) { + data[i] = $first + i++ + } + + quicksort(data, 1, i-1, compare) + + retval = data[1] + for (i = 2; i in data; i++) + retval = retval " " data[i] + + return retval +} +# sort --- sort the data in ascending order and return it as a string + +function sort(first, last) +{ + return do_sort(first, last, "num_lt") +} + +# rsort --- sort the data in descending order and return it as a string + +function rsort(first, last) +{ + return do_sort(first, last, "num_ge") +} diff --git a/awklib/eg/prog/labels.awk b/awklib/eg/prog/labels.awk new file mode 100644 index 0000000..3195809 --- /dev/null +++ b/awklib/eg/prog/labels.awk @@ -0,0 +1,53 @@ +# labels.awk --- print mailing labels +# +# Arnold Robbins, arnold@skeeve.com, Public Domain +# June 1992 +# December 2010, minor edits + +# Each label is 5 lines of data that may have blank lines. +# The label sheets have 2 blank lines at the top and 2 at +# the bottom. + +BEGIN { RS = "" ; MAXLINES = 100 } + +function printpage( i, j) +{ + if (Nlines <= 0) + return + + printf "\n\n" # header + + for (i = 1; i <= Nlines; i += 10) { + if (i == 21 || i == 61) + print "" + for (j = 0; j < 5; j++) { + if (i + j > MAXLINES) + break + printf " %-41s %s\n", line[i+j], line[i+j+5] + } + print "" + } + + printf "\n\n" # footer + + delete line +} + +# main rule +{ + if (Count >= 20) { + printpage() + Count = 0 + Nlines = 0 + } + n = split($0, a, "\n") + for (i = 1; i <= n; i++) + line[++Nlines] = a[i] + for (; i <= 5; i++) + line[++Nlines] = "" + Count++ +} + +END { + printpage() +} diff --git a/awklib/eg/prog/pi.awk b/awklib/eg/prog/pi.awk new file mode 100644 index 0000000..91060db --- /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 + intdiv0(x, d, result) + pi = result["quotient"] + pi = pi + two + } + print pi +} diff --git a/awklib/eg/prog/split.awk b/awklib/eg/prog/split.awk new file mode 100644 index 0000000..9239a6c --- /dev/null +++ b/awklib/eg/prog/split.awk @@ -0,0 +1,56 @@ +# split.awk --- do split in awk +# +# Requires ord() and chr() library functions +# +# Arnold Robbins, arnold@skeeve.com, Public Domain +# May 1993 +# Revised slightly, May 2014 + +# usage: split [-count] [file] [outname] + +BEGIN { + outfile = "x" # default + count = 1000 + if (ARGC > 4) + usage() + + i = 1 + if (i in ARGV && ARGV[i] ~ /^-[[:digit:]]+$/) { + count = -ARGV[i] + ARGV[i] = "" + i++ + } + # test argv in case reading from stdin instead of file + if (i in ARGV) + i++ # skip datafile name + if (i in ARGV) { + outfile = ARGV[i] + ARGV[i] = "" + } + s1 = s2 = "a" + out = (outfile s1 s2) +} +{ + if (++tcount > count) { + close(out) + if (s2 == "z") { + if (s1 == "z") { + printf("split: %s is too large to split\n", + FILENAME) > "/dev/stderr" + exit 1 + } + s1 = chr(ord(s1) + 1) + s2 = "a" + } + else + s2 = chr(ord(s2) + 1) + out = (outfile s1 s2) + tcount = 1 + } + print > out +} +function usage() +{ + print("usage: split [-num] [file] [outname]") > "/dev/stderr" + exit 1 +} diff --git a/awklib/eg/prog/tee.awk b/awklib/eg/prog/tee.awk new file mode 100644 index 0000000..fd9985f --- /dev/null +++ b/awklib/eg/prog/tee.awk @@ -0,0 +1,40 @@ +# tee.awk --- tee in awk +# +# Copy standard input to all named output files. +# Append content if -a option is supplied. +# +# Arnold Robbins, arnold@skeeve.com, Public Domain +# May 1993 +# Revised December 1995 + +BEGIN { + for (i = 1; i < ARGC; i++) + copy[i] = ARGV[i] + + if (ARGV[1] == "-a") { + append = 1 + delete ARGV[1] + delete copy[1] + ARGC-- + } + if (ARGC < 2) { + print "usage: tee [-a] file ..." > "/dev/stderr" + exit 1 + } + ARGV[1] = "-" + ARGC = 2 +} +{ + # moving the if outside the loop makes it run faster + if (append) + for (i in copy) + print >> copy[i] + else + for (i in copy) + print > copy[i] + print +} +END { + for (i in copy) + close(copy[i]) +} diff --git a/awklib/eg/prog/testbits.awk b/awklib/eg/prog/testbits.awk new file mode 100644 index 0000000..03cb716 --- /dev/null +++ b/awklib/eg/prog/testbits.awk @@ -0,0 +1,27 @@ +# bits2str --- turn an integer into readable ones and zeros + +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 +} +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) +} diff --git a/awklib/eg/prog/translate.awk b/awklib/eg/prog/translate.awk new file mode 100644 index 0000000..e740371 --- /dev/null +++ b/awklib/eg/prog/translate.awk @@ -0,0 +1,51 @@ +# translate.awk --- do tr-like stuff +# +# Arnold Robbins, arnold@skeeve.com, Public Domain +# August 1989 +# February 2009 - bug fix + +# Bugs: does not handle things like tr A-Z a-z; it has +# to be spelled out. However, if `to' is shorter than `from', +# the last character in `to' is used for the rest of `from'. + +function stranslate(from, to, target, lf, lt, ltarget, t_ar, i, c, + result) +{ + lf = length(from) + lt = length(to) + ltarget = length(target) + for (i = 1; i <= lt; i++) + t_ar[substr(from, i, 1)] = substr(to, i, 1) + if (lt < lf) + for (; i <= lf; i++) + t_ar[substr(from, i, 1)] = substr(to, lt, 1) + for (i = 1; i <= ltarget; i++) { + c = substr(target, i, 1) + if (c in t_ar) + c = t_ar[c] + result = result c + } + return result +} + +function translate(from, to) +{ + return $0 = stranslate(from, to, $0) +} + +# main program +BEGIN { + if (ARGC < 3) { + print "usage: translate from to" > "/dev/stderr" + exit + } + FROM = ARGV[1] + TO = ARGV[2] + ARGC = 2 + ARGV[1] = "-" +} + +{ + translate(FROM, TO) + print +} diff --git a/awklib/eg/prog/uniq.awk b/awklib/eg/prog/uniq.awk new file mode 100644 index 0000000..7dd1609 --- /dev/null +++ b/awklib/eg/prog/uniq.awk @@ -0,0 +1,118 @@ +# uniq.awk --- do uniq in awk +# +# Requires getopt() and join() library functions +# +# Arnold Robbins, arnold@skeeve.com, Public Domain +# May 1993 + +function usage() +{ + print("Usage: uniq [-udc [-n]] [+n] [ in [ out ]]") > "/dev/stderr" + exit 1 +} + +# -c count lines. overrides -d and -u +# -d only repeated lines +# -u only nonrepeated lines +# -n skip n fields +# +n skip n characters, skip fields first + +BEGIN { + count = 1 + outputfile = "/dev/stdout" + opts = "udc0:1:2:3:4:5:6:7:8:9:" + while ((c = getopt(ARGC, ARGV, opts)) != -1) { + if (c == "u") + non_repeated_only++ + else if (c == "d") + repeated_only++ + else if (c == "c") + do_count++ + else if (index("0123456789", c) != 0) { + # getopt() requires args to options + # this messes us up for things like -5 + if (Optarg ~ /^[[:digit:]]+$/) + fcount = (c Optarg) + 0 + else { + fcount = c + 0 + Optind-- + } + } else + usage() + } + + if (ARGV[Optind] ~ /^\+[[:digit:]]+$/) { + charcount = substr(ARGV[Optind], 2) + 0 + Optind++ + } + + for (i = 1; i < Optind; i++) + ARGV[i] = "" + + if (repeated_only == 0 && non_repeated_only == 0) + repeated_only = non_repeated_only = 1 + + if (ARGC - Optind == 2) { + outputfile = ARGV[ARGC - 1] + ARGV[ARGC - 1] = "" + } +} +function are_equal( n, m, clast, cline, alast, aline) +{ + if (fcount == 0 && charcount == 0) + return (last == $0) + + if (fcount > 0) { + n = split(last, alast) + m = split($0, aline) + clast = join(alast, fcount+1, n) + cline = join(aline, fcount+1, m) + } else { + clast = last + cline = $0 + } + if (charcount) { + clast = substr(clast, charcount + 1) + cline = substr(cline, charcount + 1) + } + + return (clast == cline) +} +NR == 1 { + last = $0 + next +} + +{ + equal = are_equal() + + if (do_count) { # overrides -d and -u + if (equal) + count++ + else { + printf("%4d %s\n", count, last) > outputfile + last = $0 + count = 1 # reset + } + next + } + + if (equal) + count++ + else { + if ((repeated_only && count > 1) || + (non_repeated_only && count == 1)) + print last > outputfile + last = $0 + count = 1 + } +} + +END { + if (do_count) + printf("%4d %s\n", count, last) > outputfile + else if ((repeated_only && count > 1) || + (non_repeated_only && count == 1)) + print last > outputfile + close(outputfile) +} diff --git a/awklib/eg/prog/wc.awk b/awklib/eg/prog/wc.awk new file mode 100644 index 0000000..c46d098 --- /dev/null +++ b/awklib/eg/prog/wc.awk @@ -0,0 +1,69 @@ +# wc.awk --- count lines, words, characters +# +# Arnold Robbins, arnold@skeeve.com, Public Domain +# May 1993 + +# Options: +# -l only count lines +# -w only count words +# -c only count characters +# +# Default is to count lines, words, characters +# +# Requires getopt() and file transition library functions + +BEGIN { + # let getopt() print a message about + # invalid options. we ignore them + while ((c = getopt(ARGC, ARGV, "lwc")) != -1) { + if (c == "l") + do_lines = 1 + else if (c == "w") + do_words = 1 + else if (c == "c") + do_chars = 1 + } + for (i = 1; i < Optind; i++) + ARGV[i] = "" + + # if no options, do all + if (! do_lines && ! do_words && ! do_chars) + do_lines = do_words = do_chars = 1 + + print_total = (ARGC - i > 1) +} +function beginfile(file) +{ + lines = words = chars = 0 + fname = FILENAME +} +function endfile(file) +{ + tlines += lines + twords += words + tchars += chars + if (do_lines) + printf "\t%d", lines + if (do_words) + printf "\t%d", words + if (do_chars) + printf "\t%d", chars + printf "\t%s\n", fname +} +# do per line +{ + chars += length($0) + 1 # get newline + lines++ + words += NF +} +END { + if (print_total) { + if (do_lines) + printf "\t%d", tlines + if (do_words) + printf "\t%d", twords + if (do_chars) + printf "\t%d", tchars + print "\ttotal" + } +} diff --git a/awklib/eg/prog/wordfreq.awk b/awklib/eg/prog/wordfreq.awk new file mode 100644 index 0000000..6d7195e --- /dev/null +++ b/awklib/eg/prog/wordfreq.awk @@ -0,0 +1,16 @@ +# wordfreq.awk --- print list of word frequencies + +{ + $0 = tolower($0) # remove case distinctions + # remove punctuation + gsub(/[^[:alnum:]_[:blank:]]/, "", $0) + for (i = 1; i <= NF; i++) + freq[$i]++ +} + +END { + sort = "sort -k 2nr" + for (word in freq) + printf "%s\t%d\n", word, freq[word] | sort + close(sort) +} diff --git a/awklib/extract.awk b/awklib/extract.awk new file mode 100644 index 0000000..2662574 --- /dev/null +++ b/awklib/extract.awk @@ -0,0 +1,89 @@ +# extract.awk --- extract files and run programs from Texinfo files +# +# Arnold Robbins, arnold@skeeve.com, Public Domain +# May 1993 +# Revised September 2000 + +BEGIN { IGNORECASE = 1 } + +/^@c(omment)?[ \t]+system/ { + if (NF < 3) { + e = ("extract: " FILENAME ":" FNR) + e = (e ": badly formed `system' line") + print e > "/dev/stderr" + next + } + $1 = "" + $2 = "" + stat = system($0) + if (stat != 0) { + e = ("extract: " FILENAME ":" FNR) + e = (e ": warning: system returned " stat) + print e > "/dev/stderr" + } +} +/^@c(omment)?[ \t]+file/ { + if (NF != 3) { + e = ("extract: " FILENAME ":" FNR ": badly formed `file' line") + print e > "/dev/stderr" + next + } + if ($3 != curfile) { + if (curfile != "") + close(curfile) + curfile = $3 + } + + for (;;) { + if ((getline line) <= 0) + unexpected_eof() + if (line ~ /^@c(omment)?[ \t]+endfile/) + break + else if (line ~ /^@(end[ \t]+)?group/) + continue + else if (line ~ /^@c(omment+)?[ \t]+/) + continue + if (index(line, "@") == 0) { + print line > curfile + continue + } + n = split(line, a, "@") + # if a[1] == "", means leading @, + # don't add one back in. + for (i = 2; i <= n; i++) { + if (a[i] == "") { # was an @@ + a[i] = "@" + if (a[i+1] == "") + i++ + } + } + print join(a, 1, n, SUBSEP) > curfile + } +} +function unexpected_eof() +{ + printf("extract: %s:%d: unexpected EOF or error\n", + FILENAME, FNR) > "/dev/stderr" + exit 1 +} + +END { + if (curfile) + close(curfile) +} +# join.awk --- join an array into a string +# +# Arnold Robbins, arnold@gnu.org, Public Domain +# May 1993 + +function join(array, start, end, sep, result, i) +{ + if (sep == "") + sep = " " + else if (sep == SUBSEP) # magic value + sep = "" + result = array[start] + for (i = start + 1; i <= end; i++) + result = result sep array[i] + return result +} diff --git a/awklib/stamp-eg b/awklib/stamp-eg new file mode 100644 index 0000000..241abd9 --- /dev/null +++ b/awklib/stamp-eg @@ -0,0 +1,2 @@ +some makes are stupid and will not check a directory +against a file, so this file is a place holder. gack. diff --git a/builtin.c b/builtin.c new file mode 100644 index 0000000..6927205 --- /dev/null +++ b/builtin.c @@ -0,0 +1,4185 @@ +/* + * builtin.c - Builtin functions and various utility procedures. + */ + +/* + * Copyright (C) 1986, 1988, 1989, 1991-2018 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 + */ + + +#include "awk.h" +#if defined(HAVE_FCNTL_H) +#include +#endif +#include +#include "random.h" +#include "floatmagic.h" + +#if defined(HAVE_POPEN_H) +#include "popen.h" +#endif + +#ifndef CHAR_BIT +# define CHAR_BIT 8 +#endif + +/* The extra casts work around common compiler bugs. */ +#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) +/* Note: these assume that negative integers are represented internally + via 2's complement, which is not mandated by C. They also ignore the + fact that signed integer arithmetic overflow can trigger exceptions, + unlike unsigned which is guaranteed not to do so. */ +#define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \ + ? ~ (uintmax_t) 0 << (sizeof (t) * CHAR_BIT - 1) \ + : 0)) +#define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t))) + +#ifndef INTMAX_MIN +# define INTMAX_MIN TYPE_MINIMUM (intmax_t) +#endif +#ifndef UINTMAX_MAX +# define UINTMAX_MAX TYPE_MAXIMUM (uintmax_t) +#endif + +#ifndef SIZE_MAX /* C99 constant, can't rely on it everywhere */ +#define SIZE_MAX ((size_t) -1) +#endif + +#define DEFAULT_G_PRECISION 6 + +static size_t mbc_byte_count(const char *ptr, size_t numchars); +static size_t mbc_char_count(const char *ptr, size_t numbytes); + +/* Can declare these, since we always use the random shipped with gawk */ +extern char *initstate(unsigned long seed, char *state, long n); +extern char *setstate(char *state); +extern long random(void); +extern void srandom(unsigned long seed); + +extern NODE **args_array; +extern int max_args; +extern NODE **fields_arr; +extern bool output_is_tty; +extern FILE *output_fp; + + +#define POP_TWO_SCALARS(s1, s2) \ +s2 = POP_SCALAR(); \ +s1 = POP(); \ +do { if (s1->type == Node_var_array) { \ +DEREF(s2); \ +fatal(_("attempt to use array `%s' in a scalar context"), array_vname(s1)); \ +}} while (false) + + +/* + * Since we supply the version of random(), we know what + * value to use here. + */ +#define GAWK_RANDOM_MAX 0x7fffffffL + +/* efwrite --- like fwrite, but with error checking */ + +static void +efwrite(const void *ptr, + size_t size, + size_t count, + FILE *fp, + const char *from, + struct redirect *rp, + bool flush) +{ + errno = 0; + if (rp != NULL) { + if (rp->output.gawk_fwrite(ptr, size, count, fp, rp->output.opaque) != count) + goto wrerror; + } else if (fwrite(ptr, size, count, fp) != count) + goto wrerror; + if (flush + && ((fp == stdout && output_is_tty) + || (rp != NULL && (rp->flag & RED_NOBUF) != 0))) { + if (rp != NULL) { + rp->output.gawk_fflush(fp, rp->output.opaque); + if (rp->output.gawk_ferror(fp, rp->output.opaque)) + goto wrerror; + } else { + fflush(fp); + if (ferror(fp)) + goto wrerror; + } + } + return; + +wrerror: +#ifdef __MINGW32__ + if (errno == 0 || errno == EINVAL) + w32_maybe_set_errno(); +#endif + /* for stdout, die with a real SIGPIPE, like other awks */ + if (fp == stdout && errno == EPIPE) + die_via_sigpipe(); + + /* otherwise die verbosely */ + 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 */ + +NODE * +do_exp(int nargs) +{ + NODE *tmp; + double d, res; + + tmp = POP_SCALAR(); + if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0) + lintwarn(_("exp: received non-numeric argument")); + d = force_number(tmp)->numbr; + DEREF(tmp); + errno = 0; + res = exp(d); + if (errno == ERANGE) + warning(_("exp: argument %g is out of range"), d); + return make_number((AWKNUM) res); +} + +/* stdfile --- return fp for a standard file */ + +/* + * This function allows `fflush("/dev/stdout")' to work. + * The other files will be available via getredirect(). + * /dev/stdin is not included, since fflush is only for output. + */ + +static FILE * +stdfile(const char *name, size_t len) +{ + if (len == 11) { + if (strncmp(name, "/dev/stderr", 11) == 0) + return stderr; + else if (strncmp(name, "/dev/stdout", 11) == 0) + return stdout; + } + + return NULL; +} + +/* do_fflush --- flush output, either named file or pipe or everything */ + +NODE * +do_fflush(int nargs) +{ + struct redirect *rp; + NODE *tmp; + FILE *fp; + int status = 0; + const char *file; + int len; + + /* + * November, 2012. + * It turns out that circa 2002, when BWK + * added fflush() and fflush("") to his awk, he made both of + * 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 + * with his. This should not really affect anyone, as flushing + * everything also flushes stdout. + * + * So. Once upon a time: + * fflush() --- flush stdout + * fflush("") --- flush everything + * Now, both calls flush everything. + */ + + /* fflush() */ + if (nargs == 0) { + 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(); // ERRNO updated + DEREF(tmp); + return make_number((AWKNUM) status); + } + + /* fflush("/some/path") */ + rp = getredirect(tmp->stptr, tmp->stlen); + status = -1; + 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"), + len, file); + else + 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) { + status = rp->output.gawk_fflush(fp, rp->output.opaque); + + 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 = (non_fatal_flush_std_file(fp) == false); + } else { + status = -1; + warning(_("fflush: `%.*s' is not an open file, pipe or co-process"), len, file); + } + DEREF(tmp); + return make_number((AWKNUM) status); +} + +/* strncasecmpmbs --- like strncasecmp (multibyte string version) */ + +int +strncasecmpmbs(const unsigned char *s1, const unsigned char *s2, size_t n) +{ + size_t i1, i2, mbclen1, mbclen2, gap; + wchar_t wc1, wc2; + mbstate_t mbs1, mbs2; + + memset(& mbs1, 0, sizeof(mbs1)); + memset(& mbs2, 0, sizeof(mbs2)); + + for (i1 = i2 = 0 ; i1 < n && i2 < n ;i1 += mbclen1, i2 += mbclen2) { + if (is_valid_character(s1[i1])) { + mbclen1 = 1; + wc1 = btowc_cache(s1[i1]); + } else { + mbclen1 = mbrtowc(& wc1, (const char *)s1 + i1, + n - i1, & mbs1); + if (mbclen1 == (size_t) -1 || mbclen1 == (size_t) -2 || mbclen1 == 0) { + /* We treat it as a singlebyte character. */ + mbclen1 = 1; + wc1 = btowc_cache(s1[i1]); + } + } + if (is_valid_character(s2[i2])) { + mbclen2 = 1; + wc2 = btowc_cache(s2[i2]); + } else { + mbclen2 = mbrtowc(& wc2, (const char *)s2 + i2, + n - i2, & mbs2); + if (mbclen2 == (size_t) -1 || mbclen2 == (size_t) -2 || mbclen2 == 0) { + /* We treat it as a singlebyte character. */ + mbclen2 = 1; + wc2 = btowc_cache(s2[i2]); + } + } + if ((gap = towlower(wc1) - towlower(wc2)) != 0) + /* s1 and s2 are not equivalent. */ + return gap; + } + /* s1 and s2 are equivalent. */ + return 0; +} + +/* Inspect the buffer `src' and write the index of each byte to `dest'. + Caller must allocate `dest'. + e.g. str = , , a, b, , , , c + where mb(i) means the `i'-th byte of a multibyte character. + dest = 1, 2, 1, 1, 1, 2, 3. 1 +*/ +static void +index_multibyte_buffer(char* src, char* dest, int len) +{ + int idx, prev_idx; + mbstate_t mbs, prevs; + + memset(& prevs, 0, sizeof(mbstate_t)); + for (idx = prev_idx = 0 ; idx < len ; idx++) { + size_t mbclen; + mbs = prevs; + mbclen = mbrlen(src + prev_idx, idx - prev_idx + 1, & mbs); + if (mbclen == (size_t) -1 || mbclen == 1 || mbclen == 0) { + /* singlebyte character. */ + mbclen = 1; + prev_idx = idx + 1; + } else if (mbclen == (size_t) -2) { + /* a part of a multibyte character. */ + mbclen = idx - prev_idx + 1; + } else if (mbclen > 1) { + /* the end of a multibyte character. */ + prev_idx = idx + 1; + prevs = mbs; + } else { + /* Can't reach. */ + } + dest[idx] = mbclen; + } +} + +/* do_index --- find index of a string */ + +NODE * +do_index(int nargs) +{ + NODE *s1, *s2; + const char *p1, *p2; + size_t l1, l2; + long ret; + bool do_single_byte = false; + mbstate_t mbs1, mbs2; + + if (gawk_mb_cur_max > 1) { + memset(& mbs1, 0, sizeof(mbstate_t)); + memset(& mbs2, 0, sizeof(mbstate_t)); + } + + POP_TWO_SCALARS(s1, s2); + + if (do_lint) { + if ((fixtype(s1)->flags & STRING) == 0) + lintwarn(_("index: received non-string first argument")); + if ((fixtype(s2)->flags & STRING) == 0) + lintwarn(_("index: received non-string second argument")); + } + + s1 = force_string(s1); + s2 = force_string(s2); + + p1 = s1->stptr; + p2 = s2->stptr; + l1 = s1->stlen; + l2 = s2->stlen; + ret = 0; + + /* + * Icky special case, index(foo, "") should return 1, + * since both bwk awk and mawk do, and since match("foo", "") + * returns 1. This makes index("", "") work, too, fwiw. + */ + if (l2 == 0) { + ret = 1; + goto out; + } + + if (gawk_mb_cur_max > 1) { + s1 = force_wstring(s1); + s2 = force_wstring(s2); + /* + * If we don't have valid wide character strings, use + * the real bytes. + */ + do_single_byte = ((s1->wstlen == 0 && s1->stlen > 0) + || (s2->wstlen == 0 && s2->stlen > 0)); + } + + /* IGNORECASE will already be false if posix */ + if (IGNORECASE) { + while (l1 > 0) { + if (l2 > l1) + break; + if (! do_single_byte && gawk_mb_cur_max > 1) { + const wchar_t *pos; + + pos = wcasestrstr(s1->wstptr, s1->wstlen, s2->wstptr, s2->wstlen); + if (pos == NULL) + ret = 0; + else + ret = pos - s1->wstptr + 1; /* 1-based */ + goto out; + } else { + /* + * Could use tolower(*p1) == tolower(*p2) here. + * See discussion in eval.c as to why not. + */ + if (casetable[(unsigned char)*p1] == casetable[(unsigned char)*p2] + && (l2 == 1 || strncasecmp(p1, p2, l2) == 0)) { + ret = 1 + s1->stlen - l1; + break; + } + l1--; + p1++; + } + } + } else { + while (l1 > 0) { + if (l2 > l1) + break; + if (*p1 == *p2 + && (l2 == 1 || (l2 > 0 && memcmp(p1, p2, l2) == 0))) { + ret = 1 + s1->stlen - l1; + break; + } + if (! do_single_byte && gawk_mb_cur_max > 1) { + const wchar_t *pos; + + pos = wstrstr(s1->wstptr, s1->wstlen, s2->wstptr, s2->wstlen); + if (pos == NULL) + ret = 0; + else + ret = pos - s1->wstptr + 1; /* 1-based */ + goto out; + } else { + l1--; + p1++; + } + } + } +out: + DEREF(s1); + DEREF(s2); + return make_number((AWKNUM) ret); +} + +/* double_to_int --- convert double to int, used several places */ + +double +double_to_int(double d) +{ + if (d >= 0) + d = floor(d); + else + d = ceil(d); + return d; +} + +/* do_int --- convert double to int for awk */ + +NODE * +do_int(int nargs) +{ + NODE *tmp; + double d; + + tmp = POP_SCALAR(); + if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0) + lintwarn(_("int: received non-numeric argument")); + d = force_number(tmp)->numbr; + d = double_to_int(d); + DEREF(tmp); + return make_number((AWKNUM) d); +} + +/* do_isarray --- check if argument is array */ + +NODE * +do_isarray(int nargs) +{ + NODE *tmp; + int ret = 1; + + tmp = POP(); + if (tmp->type != Node_var_array) { + ret = 0; + // could be Node_var_new + if (tmp->type == Node_val) + DEREF(tmp); + } + return make_number((AWKNUM) ret); +} + +/* do_length --- length of a string, array or $0 */ + +NODE * +do_length(int nargs) +{ + NODE *tmp; + size_t len; + + tmp = POP(); + if (tmp->type == Node_var_array) { + static bool warned = false; + unsigned long size; + + if (do_posix) + fatal(_("length: received array argument")); + if (do_lint && ! warned) { + warned = true; + lintwarn(_("`length(array)' is a gawk extension")); + } + + /* + * Support for deferred loading of array elements requires that + * 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 + * still a good idea. + */ + + size = assoc_length(tmp); + return make_number(size); + } + + assert(tmp->type == Node_val); + + if (do_lint && (fixtype(tmp)->flags & STRING) == 0) + lintwarn(_("length: received non-string argument")); + tmp = force_string(tmp); + + if (gawk_mb_cur_max > 1) { + tmp = force_wstring(tmp); + len = tmp->wstlen; + /* + * If the bytes don't make a valid wide character + * string, fall back to the bytes themselves. + */ + if (len == 0 && tmp->stlen > 0) + len = tmp->stlen; + } else + len = tmp->stlen; + + DEREF(tmp); + return make_number((AWKNUM) len); +} + +/* do_log --- the log function */ + +NODE * +do_log(int nargs) +{ + NODE *tmp; + double d, arg; + + tmp = POP_SCALAR(); + if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0) + lintwarn(_("log: received non-numeric argument")); + arg = force_number(tmp)->numbr; + if (arg < 0.0) + warning(_("log: received negative argument %g"), arg); + d = log(arg); + DEREF(tmp); + return make_number((AWKNUM) d); +} + + +#ifdef HAVE_MPFR + +/* + * mpz2mpfr --- convert an arbitrary-precision integer to a float + * without any loss of precision. The returned value is only + * good for temporary use. + */ + + +static mpfr_ptr +mpz2mpfr(mpz_ptr zi) +{ + size_t prec; + static mpfr_t mpfrval; + static bool inited = false; + int tval; + + /* estimate minimum precision for exact conversion */ + prec = mpz_sizeinbase(zi, 2); /* most significant 1 bit position starting at 1 */ + prec -= (size_t) mpz_scan1(zi, 0); /* least significant 1 bit index starting at 0 */ + if (prec < MPFR_PREC_MIN) + prec = MPFR_PREC_MIN; + else if (prec > MPFR_PREC_MAX) + prec = MPFR_PREC_MAX; + + if (! inited) { + mpfr_init2(mpfrval, prec); + inited = true; + } else + mpfr_set_prec(mpfrval, prec); + tval = mpfr_set_z(mpfrval, zi, ROUND_MODE); + IEEE_FMT(mpfrval, tval); + return mpfrval; +} +#endif + +/* + * format_tree() formats arguments of sprintf, + * and accordingly to a fmt_string providing a format like in + * printf family from C library. Returns a string node which value + * is a formatted string. Called by sprintf function. + * + * It is one of the uglier parts of gawk. Thanks to Michal Jaegermann + * for taming this beast and making it compatible with ANSI C. + */ + +NODE * +format_tree( + const char *fmt_string, + size_t n0, + NODE **the_args, + long num_args) +{ +/* copy 'l' bytes from 's' to 'obufout' checking for space in the process */ +/* difference of pointers should be of ptrdiff_t type, but let us be kind */ +#define bchunk(s, l) if (l) { \ + while ((l) > ofre) { \ + size_t olen = obufout - obuf; \ + erealloc(obuf, char *, osiz * 2, "format_tree"); \ + ofre += osiz; \ + osiz *= 2; \ + obufout = obuf + olen; \ + } \ + memcpy(obufout, s, (size_t) (l)); \ + obufout += (l); \ + ofre -= (l); \ +} + +/* copy one byte from 's' to 'obufout' checking for space in the process */ +#define bchunk_one(s) { \ + if (ofre < 1) { \ + size_t olen = obufout - obuf; \ + erealloc(obuf, char *, osiz * 2, "format_tree"); \ + ofre += osiz; \ + osiz *= 2; \ + obufout = obuf + olen; \ + } \ + *obufout++ = *s; \ + --ofre; \ +} + +/* Is there space for something L big in the buffer? */ +#define chksize(l) if ((l) >= ofre) { \ + size_t olen = obufout - obuf; \ + size_t delta = osiz+l-ofre; \ + erealloc(obuf, char *, osiz + delta, "format_tree"); \ + obufout = obuf + olen; \ + ofre += delta; \ + osiz += delta; \ +} + + size_t cur_arg = 0; + NODE *r = NULL; + int i, nc; + bool toofew = false; + char *obuf, *obufout; + size_t osiz, ofre, olen_final; + const char *chbuf; + const char *s0, *s1; + int cs1; + NODE *arg; + long fw, prec, argnum; + bool used_dollar; + bool lj, alt, big_flag, bigbig_flag, small_flag, have_prec, need_format; + long *cur = NULL; + uintmax_t uval; + bool sgn; + int base; + /* + * Although this is an array, the elements serve two different + * purposes. The first element is the general buffer meant + * to hold the entire result string. The second one is a + * temporary buffer for large floating point values. They + * could just as easily be separate variables, and the + * code might arguably be clearer. + */ + struct { + char *buf; + size_t bufsize; + char stackbuf[30]; + } cpbufs[2]; +#define cpbuf cpbufs[0].buf + char *cend = &cpbufs[0].stackbuf[sizeof(cpbufs[0].stackbuf)]; + char *cp; + const char *fill; + AWKNUM tmpval = 0.0; + char signchar = '\0'; + size_t len; + bool zero_flag = false; + bool quote_flag = false; + int ii, jj; + char *chp; + size_t copy_count, char_count; +#ifdef HAVE_MPFR + mpz_ptr zi; + mpfr_ptr mf; +#endif + enum { MP_NONE = 0, MP_INT_WITH_PREC = 1, MP_INT_WITHOUT_PREC, MP_FLOAT } fmt_type; + + static const char sp[] = " "; + static const char zero_string[] = "0"; + static const char lchbuf[] = "0123456789abcdef"; + static const char Uchbuf[] = "0123456789ABCDEF"; + +#define INITIAL_OUT_SIZE 512 + emalloc(obuf, char *, INITIAL_OUT_SIZE, "format_tree"); + obufout = obuf; + osiz = INITIAL_OUT_SIZE; + ofre = osiz - 1; + + cur_arg = 1; + + { + size_t k; + for (k = 0; k < sizeof(cpbufs)/sizeof(cpbufs[0]); k++) { + cpbufs[k].bufsize = sizeof(cpbufs[k].stackbuf); + cpbufs[k].buf = cpbufs[k].stackbuf; + } + } + + /* + * The point of this goop is to grow the buffer + * holding the converted number, so that large + * values don't overflow a fixed length buffer. + */ +#define PREPEND(CH) do { \ + if (cp == cpbufs[0].buf) { \ + char *prev = cpbufs[0].buf; \ + emalloc(cpbufs[0].buf, char *, 2*cpbufs[0].bufsize, \ + "format_tree"); \ + memcpy((cp = cpbufs[0].buf+cpbufs[0].bufsize), prev, \ + cpbufs[0].bufsize); \ + cpbufs[0].bufsize *= 2; \ + if (prev != cpbufs[0].stackbuf) \ + efree(prev); \ + cend = cpbufs[0].buf+cpbufs[0].bufsize; \ + } \ + *--cp = (CH); \ +} while(0) + + /* + * Check first for use of `count$'. + * If plain argument retrieval was used earlier, choke. + * Otherwise, return the requested argument. + * If not `count$' now, but it was used earlier, choke. + * If this format is more than total number of args, choke. + * Otherwise, return the current argument. + */ +#define parse_next_arg() { \ + if (argnum > 0) { \ + if (cur_arg > 1) { \ + msg(_("fatal: must use `count$' on all formats or none")); \ + goto out; \ + } \ + arg = the_args[argnum]; \ + } else if (used_dollar) { \ + msg(_("fatal: must use `count$' on all formats or none")); \ + arg = 0; /* shutup the compiler */ \ + goto out; \ + } else if (cur_arg >= num_args) { \ + arg = 0; /* shutup the compiler */ \ + toofew = true; \ + break; \ + } else { \ + arg = the_args[cur_arg]; \ + cur_arg++; \ + } \ +} + + need_format = false; + used_dollar = false; + + s0 = s1 = fmt_string; + while (n0-- > 0) { + if (*s1 != '%') { + s1++; + continue; + } + need_format = true; + bchunk(s0, s1 - s0); + s0 = s1; + cur = &fw; + fw = 0; + prec = 0; + base = 0; + argnum = 0; + base = 0; + have_prec = false; + signchar = '\0'; + zero_flag = false; + quote_flag = false; +#ifdef HAVE_MPFR + mf = NULL; + zi = NULL; +#endif + fmt_type = MP_NONE; + + lj = alt = big_flag = bigbig_flag = small_flag = false; + fill = sp; + cp = cend; + chbuf = lchbuf; + s1++; + +retry: + if (n0-- == 0) /* ran out early! */ + break; + + switch (cs1 = *s1++) { + case (-1): /* dummy case to allow for checking */ +check_pos: + if (cur != &fw) + break; /* reject as a valid format */ + goto retry; + case '%': + need_format = false; + /* + * 29 Oct. 2002: + * The C99 standard pages 274 and 279 seem to imply that + * since there's no arg converted, the field width doesn't + * apply. The code already was that way, but this + * comment documents it, at least in the code. + */ + if (do_lint) { + const char *msg = NULL; + + if (fw && ! have_prec) + msg = _("field width is ignored for `%%' specifier"); + else if (fw == 0 && have_prec) + msg = _("precision is ignored for `%%' specifier"); + else if (fw && have_prec) + msg = _("field width and precision are ignored for `%%' specifier"); + + if (msg != NULL) + lintwarn("%s", msg); + } + bchunk_one("%"); + s0 = s1; + break; + + case '0': + /* + * Only turn on zero_flag if we haven't seen + * the field width or precision yet. Otherwise, + * screws up floating point formatting. + */ + if (cur == & fw) + zero_flag = true; + if (lj) + goto retry; + /* FALL through */ + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (cur == NULL) + break; + if (prec >= 0) + *cur = cs1 - '0'; + /* + * with a negative precision *cur is already set + * to -1, so it will remain negative, but we have + * to "eat" precision digits in any case + */ + while (n0 > 0 && *s1 >= '0' && *s1 <= '9') { + --n0; + *cur = *cur * 10 + *s1++ - '0'; + } + if (prec < 0) /* negative precision is discarded */ + have_prec = false; + if (cur == &prec) + cur = NULL; + if (n0 == 0) /* badly formatted control string */ + continue; + goto retry; + case '$': + if (do_traditional) { + msg(_("fatal: `$' is not permitted in awk formats")); + goto out; + } + + if (cur == &fw) { + argnum = fw; + fw = 0; + used_dollar = true; + if (argnum <= 0) { + msg(_("fatal: arg count with `$' must be > 0")); + goto out; + } + if (argnum >= num_args) { + msg(_("fatal: arg count %ld greater than total number of supplied arguments"), argnum); + goto out; + } + } else { + msg(_("fatal: `$' not permitted after period in format")); + goto out; + } + + goto retry; + case '*': + if (cur == NULL) + break; + if (! do_traditional && used_dollar && ! isdigit((unsigned char) *s1)) { + fatal(_("fatal: must use `count$' on all formats or none")); + break; /* silence warnings */ + } else if (! do_traditional && isdigit((unsigned char) *s1)) { + int val = 0; + + for (; n0 > 0 && *s1 && isdigit((unsigned char) *s1); s1++, n0--) { + val *= 10; + val += *s1 - '0'; + } + if (*s1 != '$') { + msg(_("fatal: no `$' supplied for positional field width or precision")); + goto out; + } else { + s1++; + n0--; + } + if (val >= num_args) { + toofew = true; + break; + } + arg = the_args[val]; + } else { + parse_next_arg(); + } + (void) force_number(arg); + *cur = get_number_si(arg); + if (*cur < 0 && cur == &fw) { + *cur = -*cur; + lj = true; + } + if (cur == &prec) { + if (*cur >= 0) + have_prec = true; + else + have_prec = false; + cur = NULL; + } + goto retry; + case ' ': /* print ' ' or '-' */ + /* 'space' flag is ignored */ + /* if '+' already present */ + if (signchar != false) + goto check_pos; + /* FALL THROUGH */ + case '+': /* print '+' or '-' */ + signchar = cs1; + goto check_pos; + case '-': + if (prec < 0) + break; + if (cur == &prec) { + prec = -1; + goto retry; + } + fill = sp; /* if left justified then other */ + lj = true; /* filling is ignored */ + goto check_pos; + case '.': + if (cur != &fw) + break; + cur = ≺ + have_prec = true; + goto retry; + case '#': + alt = true; + goto check_pos; + case '\'': +#if defined(HAVE_LOCALE_H) + quote_flag = true; + goto check_pos; +#else + 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; + } + if (do_posix) { + msg(_("fatal: `l' is not permitted in POSIX awk formats")); + goto out; + } + } + big_flag = true; + goto retry; + case 'L': + if (bigbig_flag) + break; + else { + static bool warned = false; + + if (do_lint && ! warned) { + lintwarn(_("`L' is meaningless in awk formats; ignored")); + warned = true; + } + if (do_posix) { + msg(_("fatal: `L' is not permitted in POSIX awk formats")); + goto out; + } + } + bigbig_flag = true; + goto retry; + case 'h': + if (small_flag) + break; + else { + static bool warned = false; + + if (do_lint && ! warned) { + lintwarn(_("`h' is meaningless in awk formats; ignored")); + warned = true; + } + if (do_posix) { + msg(_("fatal: `h' is not permitted in POSIX awk formats")); + goto out; + } + } + small_flag = true; + goto retry; + case 'c': + need_format = false; + parse_next_arg(); + /* user input that looks numeric is numeric */ + fixtype(arg); + if ((arg->flags & NUMBER) != 0) { + uval = get_number_uj(arg); + if (gawk_mb_cur_max > 1) { + char buf[100]; + wchar_t wc; + mbstate_t mbs; + size_t count; + + memset(& mbs, 0, sizeof(mbs)); + + /* handle systems with too small wchar_t */ + if (sizeof(wchar_t) < 4 && uval > 0xffff) { + if (do_lint) + lintwarn( + _("[s]printf: value %g is too big for %%c format"), + arg->numbr); + + goto out0; + } + + wc = uval; + + count = wcrtomb(buf, wc, & mbs); + if (count == 0 + || count == (size_t) -1) { + if (do_lint) + lintwarn( + _("[s]printf: value %g is not a valid wide character"), + arg->numbr); + + goto out0; + } + + memcpy(cpbuf, buf, count); + prec = count; + cp = cpbuf; + goto pr_tail; + } +out0: + ; + /* else, + fall through */ + + cpbuf[0] = uval; + prec = 1; + cp = cpbuf; + goto pr_tail; + } + /* + * As per POSIX, only output first character of a + * string value. Thus, we ignore any provided + * precision, forcing it to 1. (Didn't this + * used to work? 6/2003.) + */ + cp = arg->stptr; + prec = 1; + /* + * First character can be multiple bytes if + * it's a multibyte character. Grr. + */ + if (gawk_mb_cur_max > 1) { + mbstate_t state; + size_t count; + + memset(& state, 0, sizeof(state)); + count = mbrlen(cp, arg->stlen, & state); + if (count != (size_t) -1 && count != (size_t) -2 && count > 0) { + prec = count; + /* may need to increase fw so that padding happens, see pr_tail code */ + if (fw > 0) + fw += count - 1; + } + } + goto pr_tail; + case 's': + need_format = false; + parse_next_arg(); + arg = force_string(arg); + if (fw == 0 && ! have_prec) + prec = arg->stlen; + else { + char_count = mbc_char_count(arg->stptr, arg->stlen); + if (! have_prec || prec > char_count) + prec = char_count; + } + cp = arg->stptr; + goto pr_tail; + case 'd': + case 'i': + need_format = false; + parse_next_arg(); + (void) force_number(arg); +#ifdef HAVE_MPFR + if (is_mpg_float(arg)) + goto mpf0; + else if (is_mpg_integer(arg)) + goto mpz0; + else +#endif + tmpval = arg->numbr; + + /* + * Check for Nan or Inf. + */ + if (isnan(tmpval) || isinf(tmpval)) + goto out_of_range; + else + tmpval = double_to_int(tmpval); + + /* + * ``The result of converting a zero value with a + * precision of zero is no characters.'' + */ + if (have_prec && prec == 0 && tmpval == 0) + goto pr_tail; + + if (tmpval < 0) { + tmpval = -tmpval; + sgn = true; + } else { + if (tmpval == -0.0) + /* avoid printing -0 */ + tmpval = 0.0; + sgn = false; + } + /* + * Use snprintf return value to tell if there + * is enough room in the buffer or not. + */ + while ((i = snprintf(cpbufs[1].buf, + cpbufs[1].bufsize, "%.0f", + tmpval)) >= + cpbufs[1].bufsize) { + if (cpbufs[1].buf == cpbufs[1].stackbuf) + cpbufs[1].buf = NULL; + if (i > 0) { + cpbufs[1].bufsize += ((i > cpbufs[1].bufsize) ? + i : cpbufs[1].bufsize); + } + else + cpbufs[1].bufsize *= 2; + assert(cpbufs[1].bufsize > 0); + erealloc(cpbufs[1].buf, char *, + cpbufs[1].bufsize, "format_tree"); + } + if (i < 1) + goto out_of_range; +#if defined(HAVE_LOCALE_H) + quote_flag = (quote_flag && loc.thousands_sep[0] != 0); +#endif + chp = &cpbufs[1].buf[i-1]; + ii = jj = 0; + do { + PREPEND(*chp); + chp--; i--; +#if defined(HAVE_LOCALE_H) + if (quote_flag && loc.grouping[ii] && ++jj == loc.grouping[ii]) { + if (i) { /* only add if more digits coming */ + int k; + const char *ts = loc.thousands_sep; + + for (k = strlen(ts) - 1; k >= 0; k--) { + PREPEND(ts[k]); + } + } + if (loc.grouping[ii+1] == 0) + jj = 0; /* keep using current val in loc.grouping[ii] */ + else if (loc.grouping[ii+1] == CHAR_MAX) + quote_flag = false; + else { + ii++; + jj = 0; + } + } +#endif + } while (i > 0); + + /* add more output digits to match the precision */ + if (have_prec) { + while (cend - cp < prec) + PREPEND('0'); + } + + if (sgn) + PREPEND('-'); + else if (signchar) + PREPEND(signchar); + /* + * When to fill with zeroes is of course not simple. + * First: No zero fill if left-justifying. + * Next: There seem to be two cases: + * A '0' without a precision, e.g. %06d + * A precision with no field width, e.g. %.10d + * Any other case, we don't want to fill with zeroes. + */ + if (! lj + && ((zero_flag && ! have_prec) + || (fw == 0 && have_prec))) + fill = zero_string; + if (prec > fw) + fw = prec; + prec = cend - cp; + if (fw > prec && ! lj && fill != sp + && (*cp == '-' || signchar)) { + bchunk_one(cp); + cp++; + prec--; + fw--; + } + goto pr_tail; + case 'X': + chbuf = Uchbuf; /* FALL THROUGH */ + case 'x': + base += 6; /* FALL THROUGH */ + case 'u': + base += 2; /* FALL THROUGH */ + case 'o': + base += 8; + need_format = false; + parse_next_arg(); + (void) force_number(arg); +#ifdef HAVE_MPFR + if (is_mpg_integer(arg)) { +mpz0: + zi = arg->mpg_i; + + if (cs1 != 'd' && cs1 != 'i') { + if (mpz_sgn(zi) <= 0) { + /* + * Negative value or 0 requires special handling. + * Unlike MPFR, GMP does not allow conversion + * to (u)intmax_t. So we first convert GMP type to + * a MPFR type. + */ + mf = mpz2mpfr(zi); + goto mpf1; + } + signchar = '\0'; /* Don't print '+' */ + } + + /* See comments above about when to fill with zeros */ + zero_flag = (! lj + && ((zero_flag && ! have_prec) + || (fw == 0 && have_prec))); + + fmt_type = have_prec ? MP_INT_WITH_PREC : MP_INT_WITHOUT_PREC; + goto fmt0; + + } else if (is_mpg_float(arg)) { +mpf0: + mf = arg->mpg_numbr; + if (! mpfr_number_p(mf)) { + /* inf or NaN */ + cs1 = 'g'; + fmt_type = MP_FLOAT; + goto fmt1; + } + + if (cs1 != 'd' && cs1 != 'i') { +mpf1: + /* + * The output of printf("%#.0x", 0) is 0 instead of 0x, hence <= in + * the comparison below. + */ + if (mpfr_sgn(mf) <= 0) { + if (! mpfr_fits_intmax_p(mf, ROUND_MODE)) { + /* -ve number is too large */ + cs1 = 'g'; + fmt_type = MP_FLOAT; + goto fmt1; + } + + tmpval = uval = (uintmax_t) mpfr_get_sj(mf, ROUND_MODE); + if (! alt && have_prec && prec == 0 && tmpval == 0) + goto pr_tail; /* printf("%.0x", 0) is no characters */ + goto int0; + } + signchar = '\0'; /* Don't print '+' */ + } + + /* See comments above about when to fill with zeros */ + 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; + goto fmt0; + } else +#endif + tmpval = arg->numbr; + + /* + * ``The result of converting a zero value with a + * precision of zero is no characters.'' + * + * If I remember the ANSI C standard, though, + * it says that for octal conversions + * the precision is artificially increased + * to add an extra 0 if # is supplied. + * Indeed, in C, + * printf("%#.0o\n", 0); + * prints a single 0. + */ + if (! alt && have_prec && prec == 0 && tmpval == 0) + goto pr_tail; + + if (tmpval < 0) { + uval = (uintmax_t) (intmax_t) tmpval; + if ((AWKNUM)(intmax_t)uval != double_to_int(tmpval)) + goto out_of_range; + } else { + uval = (uintmax_t) tmpval; + if ((AWKNUM)uval != double_to_int(tmpval)) + goto out_of_range; + } +#ifdef HAVE_MPFR + int0: +#endif +#if defined(HAVE_LOCALE_H) + quote_flag = (quote_flag && loc.thousands_sep[0] != 0); +#endif + /* + * When to fill with zeroes is of course not simple. + * First: No zero fill if left-justifying. + * Next: There seem to be two cases: + * A '0' without a precision, e.g. %06d + * A precision with no field width, e.g. %.10d + * Any other case, we don't want to fill with zeroes. + */ + if (! lj + && ((zero_flag && ! have_prec) + || (fw == 0 && have_prec))) + fill = zero_string; + ii = jj = 0; + do { + PREPEND(chbuf[uval % base]); + uval /= base; +#if defined(HAVE_LOCALE_H) + if (base == 10 && quote_flag && loc.grouping[ii] && ++jj == loc.grouping[ii]) { + if (uval) { /* only add if more digits coming */ + int k; + const char *ts = loc.thousands_sep; + + for (k = strlen(ts) - 1; k >= 0; k--) { + PREPEND(ts[k]); + } + } + if (loc.grouping[ii+1] == 0) + jj = 0; /* keep using current val in loc.grouping[ii] */ + else if (loc.grouping[ii+1] == CHAR_MAX) + quote_flag = false; + else { + ii++; + jj = 0; + } + } +#endif + } while (uval > 0); + + /* add more output digits to match the precision */ + if (have_prec) { + while (cend - cp < prec) + PREPEND('0'); + } + + if (alt && tmpval != 0) { + if (base == 16) { + PREPEND(cs1); + PREPEND('0'); + if (fill != sp) { + bchunk(cp, 2); + cp += 2; + fw -= 2; + } + } else if (base == 8) + PREPEND('0'); + } + base = 0; + if (prec > fw) + fw = prec; + prec = cend - cp; + pr_tail: + if (! lj) { + while (fw > prec) { + bchunk_one(fill); + fw--; + } + } + copy_count = prec; + if (fw == 0 && ! have_prec) + ; + else if (gawk_mb_cur_max > 1) { + if (cs1 == 's') { + assert(cp == arg->stptr || cp == cpbuf); + copy_count = mbc_byte_count(arg->stptr, prec); + } + /* prec was set by code for %c */ + /* else + copy_count = prec; */ + } + bchunk(cp, copy_count); + while (fw > prec) { + bchunk_one(fill); + fw--; + } + s0 = s1; + break; + + out_of_range: + /* out of range - emergency use of %g format */ + if (do_lint) + lintwarn(_("[s]printf: value %g is out of range for `%%%c' format"), + (double) tmpval, cs1); + cs1 = 'g'; + goto fmt1; + + case 'F': +#if ! defined(PRINTF_HAS_F_FORMAT) || PRINTF_HAS_F_FORMAT != 1 + cs1 = 'f'; + /* FALL THROUGH */ +#endif + case 'g': + case 'G': + case 'e': + case 'f': + case 'E': + need_format = false; + parse_next_arg(); + (void) force_number(arg); + + if (! is_mpg_number(arg)) + tmpval = arg->numbr; +#ifdef HAVE_MPFR + else if (is_mpg_float(arg)) { + mf = arg->mpg_numbr; + fmt_type = MP_FLOAT; + } else { + /* arbitrary-precision integer, convert to MPFR float */ + assert(mf == NULL); + mf = mpz2mpfr(arg->mpg_i); + fmt_type = MP_FLOAT; + } +#endif + fmt1: + if (! have_prec) + prec = DEFAULT_G_PRECISION; +#ifdef HAVE_MPFR + fmt0: +#endif + chksize(fw + prec + 11); /* 11 == slop */ + cp = cpbuf; + *cp++ = '%'; + if (lj) + *cp++ = '-'; + if (signchar) + *cp++ = signchar; + if (alt) + *cp++ = '#'; + if (zero_flag) + *cp++ = '0'; + if (quote_flag) + *cp++ = '\''; + +#if defined(LC_NUMERIC) + if (quote_flag && ! use_lc_numeric) + setlocale(LC_NUMERIC, ""); +#endif + + switch (fmt_type) { +#ifdef HAVE_MPFR + case MP_INT_WITH_PREC: + sprintf(cp, "*.*Z%c", cs1); + while ((nc = mpfr_snprintf(obufout, ofre, cpbuf, + (int) fw, (int) prec, zi)) >= ofre) + chksize(nc) + break; + case MP_INT_WITHOUT_PREC: + sprintf(cp, "*Z%c", cs1); + while ((nc = mpfr_snprintf(obufout, ofre, cpbuf, + (int) fw, zi)) >= ofre) + chksize(nc) + break; + case MP_FLOAT: + sprintf(cp, "*.*R*%c", cs1); + while ((nc = mpfr_snprintf(obufout, ofre, cpbuf, + (int) fw, (int) prec, ROUND_MODE, mf)) >= ofre) + chksize(nc) + break; +#endif + default: + sprintf(cp, "*.*%c", cs1); + while ((nc = snprintf(obufout, ofre, cpbuf, + (int) fw, (int) prec, + (double) tmpval)) >= ofre) + chksize(nc) + } + +#if defined(LC_NUMERIC) + if (quote_flag && ! use_lc_numeric) + setlocale(LC_NUMERIC, "C"); +#endif + + len = strlen(obufout); + ofre -= len; + obufout += len; + s0 = s1; + break; + default: + if (do_lint && is_alpha(cs1)) + lintwarn(_("ignoring unknown format specifier character `%c': no argument converted"), cs1); + break; + } + if (toofew) { + msg("%s\n\t`%s'\n\t%*s%s", + _("fatal: not enough arguments to satisfy format string"), + fmt_string, (int) (s1 - fmt_string - 1), "", + _("^ ran out for this one")); + goto out; + } + } + if (do_lint) { + if (need_format) + lintwarn( + _("[s]printf: format specifier does not have control letter")); + if (cur_arg < num_args) + lintwarn( + _("too many arguments supplied for format string")); + } + bchunk(s0, s1 - s0); + olen_final = obufout - obuf; + if (ofre > 0) + erealloc(obuf, char *, olen_final + 1, "format_tree"); + r = make_str_node(obuf, olen_final, ALREADY_MALLOCED); + obuf = NULL; +out: + { + size_t k; + size_t count = sizeof(cpbufs)/sizeof(cpbufs[0]); + for (k = 0; k < count; k++) { + if (cpbufs[k].buf != cpbufs[k].stackbuf) + efree(cpbufs[k].buf); + } + if (obuf != NULL) + efree(obuf); + } + + if (r == NULL) + gawk_exit(EXIT_FATAL); + return r; +} + + +/* printf_common --- common code for sprintf and printf */ + +static NODE * +printf_common(int nargs) +{ + int i; + NODE *r, *tmp; + + assert(nargs > 0 && nargs <= max_args); + for (i = 1; i <= nargs; i++) { + tmp = args_array[nargs - i] = POP(); + if (tmp->type == Node_var_array) { + while (--i > 0) + DEREF(args_array[nargs - i]); + fatal(_("attempt to use array `%s' in a scalar context"), array_vname(tmp)); + } + } + + args_array[0] = force_string(args_array[0]); + r = format_tree(args_array[0]->stptr, args_array[0]->stlen, args_array, nargs); + for (i = 0; i < nargs; i++) + DEREF(args_array[i]); + return r; +} + +/* do_sprintf --- perform sprintf */ + +NODE * +do_sprintf(int nargs) +{ + NODE *r; + + if (nargs == 0) + fatal(_("sprintf: no arguments")); + + r = printf_common(nargs); + if (r == NULL) + gawk_exit(EXIT_FATAL); + return r; +} + + +/* do_printf --- perform printf, including redirection */ + +void +do_printf(int nargs, int redirtype) +{ + FILE *fp = NULL; + NODE *tmp; + struct redirect *rp = NULL; + int errflg = 0; + NODE *redir_exp = NULL; + + if (nargs == 0) { + if (do_traditional) { + if (do_lint) + lintwarn(_("printf: no arguments")); + if (redirtype != 0) { + 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, true); + DEREF(redir_exp); + decr_sp(); + } + return; /* bwk accepts it silently */ + } + fatal(_("printf: no arguments")); + } + + if (redirtype != 0) { + 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, 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 + fp = stdout; + + tmp = printf_common(nargs); + if (redir_exp != NULL) { + DEREF(redir_exp); + decr_sp(); + } + if (tmp != NULL) { + if (fp == NULL) { + DEREF(tmp); + return; + } + efwrite(tmp->stptr, sizeof(char), tmp->stlen, fp, "printf", rp, true); + if (rp != NULL && (rp->flag & RED_TWOWAY) != 0) + rp->output.gawk_fflush(rp->output.fp, rp->output.opaque); + DEREF(tmp); + } else + gawk_exit(EXIT_FATAL); +} + +/* do_sqrt --- do the sqrt function */ + +NODE * +do_sqrt(int nargs) +{ + NODE *tmp; + double arg; + + tmp = POP_SCALAR(); + if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0) + lintwarn(_("sqrt: received non-numeric argument")); + arg = (double) force_number(tmp)->numbr; + DEREF(tmp); + if (arg < 0.0) + warning(_("sqrt: called with negative argument %g"), arg); + return make_number((AWKNUM) sqrt(arg)); +} + +/* do_substr --- do the substr function */ + +NODE * +do_substr(int nargs) +{ + NODE *t1; + NODE *r; + size_t indx; + size_t length = 0; + double d_index = 0, d_length = 0; + size_t src_len; + + if (nargs == 3) { + t1 = POP_NUMBER(); + d_length = get_number_d(t1); + DEREF(t1); + } + + t1 = POP_NUMBER(); + d_index = get_number_d(t1); + DEREF(t1); + + t1 = POP_STRING(); + + if (nargs == 3) { + if (! (d_length >= 1)) { + if (do_lint == DO_LINT_ALL) + lintwarn(_("substr: length %g is not >= 1"), d_length); + else if (do_lint == DO_LINT_INVALID && ! (d_length >= 0)) + lintwarn(_("substr: length %g is not >= 0"), d_length); + DEREF(t1); + /* + * Return explicit null string instead of doing + * dupnode(Nnull_string) so that if the result + * is checked with the combination of length() + * and lint, no error is reported about using + * an uninitialized value. Same thing later, too. + */ + return make_string("", 0); + } + if (do_lint) { + if (double_to_int(d_length) != d_length) + lintwarn( + _("substr: non-integer length %g will be truncated"), + d_length); + + if (d_length > SIZE_MAX) + lintwarn( + _("substr: length %g too big for string indexing, truncating to %g"), + d_length, (double) SIZE_MAX); + } + if (d_length < SIZE_MAX) + length = d_length; + else + length = SIZE_MAX; + } + + /* the weird `! (foo)' tests help catch NaN values. */ + if (! (d_index >= 1)) { + if (do_lint) + lintwarn(_("substr: start index %g is invalid, using 1"), + d_index); + d_index = 1; + } + if (do_lint && double_to_int(d_index) != d_index) + lintwarn(_("substr: non-integer start index %g will be truncated"), + d_index); + + /* awk indices are from 1, C's are from 0 */ + if (d_index <= SIZE_MAX) + indx = d_index - 1; + else + indx = SIZE_MAX; + + if (nargs == 2) { /* third arg. missing */ + /* use remainder of string */ + length = t1->stlen - indx; /* default to bytes */ + if (gawk_mb_cur_max > 1) { + t1 = force_wstring(t1); + if (t1->wstlen > 0) /* use length of wide char string if we have one */ + length = t1->wstlen - indx; + } + d_length = length; /* set here in case used in diagnostics, below */ + } + + if (t1->stlen == 0) { + /* substr("", 1, 0) produces a warning only if LINT_ALL */ + if (do_lint && (do_lint == DO_LINT_ALL || ((indx | length) != 0))) + lintwarn(_("substr: source string is zero length")); + DEREF(t1); + return make_string("", 0); + } + + /* get total len of input string, for following checks */ + if (gawk_mb_cur_max > 1) { + t1 = force_wstring(t1); + src_len = t1->wstlen; + } else + src_len = t1->stlen; + + if (indx >= src_len) { + if (do_lint) + lintwarn(_("substr: start index %g is past end of string"), + d_index); + DEREF(t1); + return make_string("", 0); + } + if (length > src_len - indx) { + if (do_lint) + lintwarn( + _("substr: length %g at start index %g exceeds length of first argument (%lu)"), + d_length, d_index, (unsigned long int) src_len); + length = src_len - indx; + } + + /* force_wstring() already called */ + if (gawk_mb_cur_max == 1 || t1->wstlen == t1->stlen) + /* single byte case */ + r = make_string(t1->stptr + indx, length); + else { + /* multibyte case, more work */ + size_t result; + wchar_t *wp; + mbstate_t mbs; + char *substr, *cp; + + /* + * Convert the wide chars in t1->wstptr back into m.b. chars. + * This is pretty grotty, but it's the most straightforward + * way to do things. + */ + memset(& mbs, 0, sizeof(mbs)); + 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); + if (result == (size_t) -1) /* what to do? break seems best */ + break; + cp += result; + wp++; + } + *cp = '\0'; + r = make_str_node(substr, cp - substr, ALREADY_MALLOCED); + } + + DEREF(t1); + return r; +} + +/* do_strftime --- format a time stamp */ + +NODE * +do_strftime(int nargs) +{ + NODE *t1, *t2, *t3, *ret; + struct tm *tm; + time_t fclock; + double clock_val; + char *bufp; + size_t buflen, bufsize; + char buf[BUFSIZ]; + const char *format; + int formatlen; + bool do_gmt; + NODE *val = NULL; + NODE *sub = NULL; + char save = '\0'; // initialize to avoid compiler warnings + static const time_t time_t_min = TYPE_MINIMUM(time_t); + static const time_t time_t_max = TYPE_MAXIMUM(time_t); + + /* set defaults first */ + format = def_strftime_format; /* traditional date format */ + formatlen = strlen(format); + (void) time(& fclock); /* current time of day */ + do_gmt = false; + + if (PROCINFO_node != NULL) { + sub = make_string("strftime", 8); + val = in_array(PROCINFO_node, sub); + unref(sub); + + if (val != NULL) { + 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; + formatlen = val->stlen; + } + } + + t1 = t2 = t3 = NULL; + if (nargs > 0) { /* have args */ + NODE *tmp; + + if (nargs == 3) { + t3 = POP_SCALAR(); + do_gmt = boolval(t3); + DEREF(t3); + } + + if (nargs >= 2) { + t2 = POP_SCALAR(); + 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); + fclock = (time_t) clock_val; + /* + * Protect against negative value being assigned + * to unsigned time_t. + */ + if (clock_val < 0 && fclock > 0) { + if (do_lint) + lintwarn(_("strftime: second argument less than 0 or too big for time_t")); + return make_string("", 0); + } + + /* And check that the value is in range */ + if (clock_val < time_t_min || clock_val > time_t_max) { + if (do_lint) + lintwarn(_("strftime: second argument out of range for time_t")); + return make_string("", 0); + } + + DEREF(t2); + } + + tmp = POP_SCALAR(); + 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; + if (formatlen == 0) { + if (do_lint) + lintwarn(_("strftime: received empty format string")); + DEREF(t1); + return make_string("", 0); + } + str_terminate(t1, save); + } + + if (do_gmt) + tm = gmtime(& fclock); + else + tm = localtime(& fclock); + + if (tm == NULL) { + ret = make_string("", 0); + goto done; + } + + bufp = buf; + bufsize = sizeof(buf); + for (;;) { + *bufp = '\0'; + buflen = strftime(bufp, bufsize, format, tm); + /* + * buflen can be zero EITHER because there's not enough + * room in the string, or because the control command + * goes to the empty string. Make a reasonable guess that + * if the buffer is 1024 times bigger than the length of the + * format string, it's not failing for lack of room. + * Thanks to Paul Eggert for pointing out this issue. + */ + if (buflen > 0 || bufsize >= 1024 * formatlen) + break; + bufsize *= 2; + if (bufp == buf) + emalloc(bufp, char *, bufsize, "do_strftime"); + else + erealloc(bufp, char *, bufsize, "do_strftime"); + } + ret = make_string(bufp, buflen); + if (bufp != buf) + efree(bufp); +done: + if (t1) { + str_restore(t1, save); + DEREF(t1); + } + return ret; +} + +/* do_systime --- get the time of day */ + +NODE * +do_systime(int nargs ATTRIBUTE_UNUSED) +{ + time_t lclock; + + (void) time(& lclock); + 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, *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 && (fixtype(t1)->flags & STRING) == 0) + lintwarn(_("mktime: received non-string argument")); + t1 = force_string(t1); + + save = t1->stptr[t1->stlen]; + t1->stptr[t1->stlen] = '\0'; + + count = sscanf(t1->stptr, "%ld %d %d %d %d %d %d", + & year, & month, & day, + & hour, & minute, & second, + & dst); + + if ( do_lint /* Ready? Set! Go: */ + && ( (second < 0 || second > 60) + || (minute < 0 || minute > 59) + || (hour < 0 || hour > 23) /* FIXME ISO 8601 allows 24 ? */ + || (day < 1 || day > 31) + || (month < 1 || month > 12) )) + lintwarn(_("mktime: at least one of the values is out of the default range")); + + t1->stptr[t1->stlen] = save; + DEREF(t1); + + if (count < 6 + || month == INT_MIN + || year < INT_MIN + 1900 + || year - 1900 > INT_MAX) + return make_number((AWKNUM) -1); + + memset(& then, '\0', sizeof(then)); + then.tm_sec = second; + then.tm_min = minute; + then.tm_hour = hour; + then.tm_mday = day; + then.tm_mon = month - 1; + then.tm_year = year - 1900; + then.tm_isdst = dst; + + then_stamp = (do_gmt ? mktime_tz(& then, "UTC+0") : mktime(& then)); + return make_number((AWKNUM) then_stamp); +} + +/* do_system --- run an external command */ + +NODE * +do_system(int nargs) +{ + NODE *tmp; + AWKNUM ret = 0; /* floating point on purpose, compat Unix awk */ + char *cmd; + char save; + int status; + + if (do_sandbox) + fatal(_("'system' function not allowed in sandbox mode")); + + (void) flush_io(); /* so output is synchronous with gawk's */ + tmp = POP_SCALAR(); + if (do_lint && (fixtype(tmp)->flags & STRING) == 0) + lintwarn(_("system: received non-string argument")); + cmd = force_string(tmp)->stptr; + + if (cmd && *cmd) { + /* insure arg to system is zero-terminated */ + save = cmd[tmp->stlen]; + cmd[tmp->stlen] = '\0'; + + os_restore_mode(fileno(stdin)); + set_sigpipe_to_default(); + + status = system(cmd); + /* + * 3/2016. What to do with ret? It's never simple. + * POSIX says to use the full return value. BWK awk + * divides the result by 256. That normally gives the + * exit status but gives a weird result for death-by-signal. + * So we compromise as follows: + */ + ret = status; + if (status != -1) { + if (do_posix) + ; /* leave it alone, full 16 bits */ + else if (do_traditional) +#ifdef __MINGW32__ + ret = (((unsigned)status) & ~0xC0000000); +#else + ret = (status / 256.0); +#endif + else + ret = sanitize_exit_status(status); + } + + if ((BINMODE & BINMODE_INPUT) != 0) + os_setbinmode(fileno(stdin), O_BINARY); + ignore_sigpipe(); + + cmd[tmp->stlen] = save; + } + DEREF(tmp); + return make_number((AWKNUM) ret); +} + +/* do_print --- print items, separated by OFS, terminated with ORS */ + +void +do_print(int nargs, int redirtype) +{ + struct redirect *rp = NULL; + int errflg = 0; + FILE *fp = NULL; + int i; + NODE *redir_exp = NULL; + NODE *tmp = NULL; + + assert(nargs <= max_args); + + if (redirtype != 0) { + 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, 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 + fp = stdout; + + for (i = 1; i <= nargs; i++) { + tmp = args_array[i] = POP(); + if (tmp->type == Node_var_array) { + while (--i > 0) + DEREF(args_array[i]); + fatal(_("attempt to use array `%s' in a scalar context"), array_vname(tmp)); + } + // Let force_string_ofmt handle checking if things + // are already valid. + args_array[i] = force_string_ofmt(tmp); + } + + if (redir_exp != NULL) { + DEREF(redir_exp); + decr_sp(); + } + + if (fp == NULL) { + for (i = nargs; i > 0; i--) + DEREF(args_array[i]); + return; + } + + for (i = nargs; i > 0; i--) { + efwrite(args_array[i]->stptr, sizeof(char), args_array[i]->stlen, fp, "print", rp, false); + DEREF(args_array[i]); + if (i != 1 && OFSlen > 0) + efwrite(OFS, sizeof(char), (size_t) OFSlen, + fp, "print", rp, false); + + } + if (ORSlen > 0) + efwrite(ORS, sizeof(char), (size_t) ORSlen, fp, "print", rp, true); + + if (rp != NULL && (rp->flag & RED_TWOWAY) != 0) + rp->output.gawk_fflush(rp->output.fp, rp->output.opaque); +} + +/* do_print_rec --- special case printing of $0, for speed */ + +void +do_print_rec(int nargs, int redirtype) +{ + FILE *fp = NULL; + NODE *f0; + struct redirect *rp = NULL; + int errflg = 0; + NODE *redir_exp = NULL; + + assert(nargs == 0); + if (redirtype != 0) { + redir_exp = TOP(); + 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; + } + DEREF(redir_exp); + decr_sp(); + } else + fp = output_fp; + + if (errflg) { + update_ERRNO_int(errflg); + return; + } + + if (fp == NULL) + return; + + if (! field0_valid) + (void) get_field(0L, NULL); /* rebuild record */ + + f0 = fields_arr[0]; + + if (do_lint && (f0->flags & NULL_FIELD) != 0) + lintwarn(_("reference to uninitialized field `$%d'"), 0); + + efwrite(f0->stptr, sizeof(char), f0->stlen, fp, "print", rp, false); + + if (ORSlen > 0) + efwrite(ORS, sizeof(char), (size_t) ORSlen, fp, "print", rp, true); + + if (rp != NULL && (rp->flag & RED_TWOWAY) != 0) + rp->output.gawk_fflush(rp->output.fp, rp->output.opaque); +} + + +/* is_wupper --- function version of iswupper for passing function pointers */ + +static int +is_wupper(wchar_t c) +{ + return iswupper(c); +} + +/* is_wlower --- function version of iswlower for passing function pointers */ + +static int +is_wlower(wchar_t c) +{ + return iswlower(c); +} + +/* to_wupper --- function version of towupper for passing function pointers */ + +static int +to_wlower(wchar_t c) +{ + return towlower(c); +} + +/* to_wlower --- function version of towlower for passing function pointers */ + +static int +to_wupper(wchar_t c) +{ + return towupper(c); +} + +/* wide_change_case --- generic case converter for wide characters */ + +static void +wide_change_case(wchar_t *wstr, + size_t wlen, + int (*is_x)(wchar_t c), + int (*to_y)(wchar_t c)) +{ + size_t i; + wchar_t *wcp; + + for (i = 0, wcp = wstr; i < wlen; i++, wcp++) + if (is_x(*wcp)) + *wcp = to_y(*wcp); +} + +/* wide_toupper --- map a wide string to upper case */ + +static void +wide_toupper(wchar_t *wstr, size_t wlen) +{ + wide_change_case(wstr, wlen, is_wlower, to_wupper); +} + +/* wide_tolower --- map a wide string to lower case */ + +static void +wide_tolower(wchar_t *wstr, size_t wlen) +{ + wide_change_case(wstr, wlen, is_wupper, to_wlower); +} + +/* do_tolower --- lower case a string */ + +NODE * +do_tolower(int nargs) +{ + NODE *t1, *t2; + + t1 = POP_SCALAR(); + 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); + + if (gawk_mb_cur_max == 1) { + unsigned char *cp, *cp2; + + for (cp = (unsigned char *)t2->stptr, + cp2 = (unsigned char *)(t2->stptr + t2->stlen); + cp < cp2; cp++) + if (isupper(*cp)) + *cp = tolower(*cp); + } else { + force_wstring(t2); + wide_tolower(t2->wstptr, t2->wstlen); + wstr2str(t2); + } + + DEREF(t1); + return t2; +} + +/* do_toupper --- upper case a string */ + +NODE * +do_toupper(int nargs) +{ + NODE *t1, *t2; + + t1 = POP_SCALAR(); + 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); + + if (gawk_mb_cur_max == 1) { + unsigned char *cp, *cp2; + + for (cp = (unsigned char *)t2->stptr, + cp2 = (unsigned char *)(t2->stptr + t2->stlen); + cp < cp2; cp++) + if (islower(*cp)) + *cp = toupper(*cp); + } else { + force_wstring(t2); + wide_toupper(t2->wstptr, t2->wstlen); + wstr2str(t2); + } + + DEREF(t1); + return t2; +} + +/* do_atan2 --- do the atan2 function */ + +NODE * +do_atan2(int nargs) +{ + NODE *t1, *t2; + double d1, d2; + + POP_TWO_SCALARS(t1, t2); + if (do_lint) { + if ((fixtype(t1)->flags & NUMBER) == 0) + lintwarn(_("atan2: received non-numeric first argument")); + if ((fixtype(t2)->flags & NUMBER) == 0) + lintwarn(_("atan2: received non-numeric second argument")); + } + d1 = force_number(t1)->numbr; + d2 = force_number(t2)->numbr; + DEREF(t1); + DEREF(t2); + return make_number((AWKNUM) atan2(d1, d2)); +} + +/* do_sin --- do the sin function */ + +NODE * +do_sin(int nargs) +{ + NODE *tmp; + double d; + + tmp = POP_SCALAR(); + if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0) + lintwarn(_("sin: received non-numeric argument")); + d = sin((double) force_number(tmp)->numbr); + DEREF(tmp); + return make_number((AWKNUM) d); +} + +/* do_cos --- do the cos function */ + +NODE * +do_cos(int nargs) +{ + NODE *tmp; + double d; + + tmp = POP_SCALAR(); + if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0) + lintwarn(_("cos: received non-numeric argument")); + d = cos((double) force_number(tmp)->numbr); + DEREF(tmp); + return make_number((AWKNUM) d); +} + +/* do_rand --- do the rand function */ + +static bool firstrand = true; +/* Some systems require this array to be integer aligned. Sigh. */ +#define SIZEOF_STATE 256 +static uint32_t istate[SIZEOF_STATE/sizeof(uint32_t)]; +static char *const state = (char *const) istate; + +/* ARGSUSED */ +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. */ + firstrand = false; + setstate(state); + } + /* + * Per historical practice and POSIX, return value N is + * + * 0 <= n < 1 + */ + /* + * Date: Wed, 28 Aug 2013 17:52:46 -0700 + * From: Bob Jewett + * + * 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" + * (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 */ + +NODE * +do_srand(int nargs) +{ + NODE *tmp; + static long save_seed = 1; + long ret = save_seed; /* SVR4 awk srand returns previous seed */ + + if (firstrand) { + (void) initstate((unsigned) 1, state, SIZEOF_STATE); + /* don't need to srandom(1), we're changing the seed below */ + firstrand = false; + (void) setstate(state); + } + + if (nargs == 0) + srandom((unsigned int) (save_seed = (long) time((time_t *) 0))); + else { + tmp = POP_SCALAR(); + 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); + } + return make_number((AWKNUM) ret); +} + +/* do_match --- match a regexp, set RSTART and RLENGTH, + * optional third arg is array filled with text of + * subpatterns enclosed in parens and start and len info. + */ + +NODE * +do_match(int nargs) +{ + NODE *tre, *t1, *dest, *it; + int rstart, len, ii; + int rlength; + Regexp *rp; + regoff_t s; + char *start; + char *buf = NULL; + char buff[100]; + size_t amt, oldamt = 0, ilen, slen; + char *subsepstr; + size_t subseplen; + + dest = NULL; + if (nargs == 3) { /* 3rd optional arg for the subpatterns */ + dest = POP_PARAM(); + if (dest->type != Node_var_array) + fatal(_("match: third argument is not an array")); + assoc_clear(dest); + } + 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; + + rlength = REEND(rp, t1->stptr) - RESTART(rp, t1->stptr); /* byte length */ + if (rlength > 0 && gawk_mb_cur_max > 1) { + t1 = str2wstr(t1, & wc_indices); + rlength = wc_indices[rstart + rlength - 1] - wc_indices[rstart] + 1; + rstart = wc_indices[rstart]; + } + + 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; + subseplen = SUBSEP_node->var_value->stlen; + + for (ii = 0; ii < NUMSUBPATS(rp, t1->stptr); ii++) { + /* + * Loop over all the subpats; some of them may have + * matched even if all of them did not. + */ + if ((s = SUBPATSTART(rp, t1->stptr, ii)) != -1) { + size_t subpat_start; + size_t subpat_len; + NODE **lhs; + NODE *sub; + + start = t1->stptr + s; + subpat_start = s; + subpat_len = len = SUBPATEND(rp, t1->stptr, ii) - s; + if (len > 0 && gawk_mb_cur_max > 1) { + subpat_start = wc_indices[s]; + subpat_len = wc_indices[s + len - 1] - subpat_start + 1; + } + + it = make_string(start, len); + it->flags |= USER_INPUT; + + sub = make_number((AWKNUM) (ii)); + lhs = assoc_lookup(dest, sub); + unref(*lhs); + *lhs = it; + /* execute post-assignment routine if any */ + if (dest->astore != NULL) + (*dest->astore)(dest, sub); + unref(sub); + + sprintf(buff, "%d", ii); + ilen = strlen(buff); + amt = ilen + subseplen + strlen("length") + 1; + + if (oldamt == 0) { + emalloc(buf, char *, amt, "do_match"); + } else if (amt > oldamt) { + erealloc(buf, char *, amt, "do_match"); + } + oldamt = amt; + 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); + unref(*lhs); + *lhs = it; + 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); + unref(*lhs); + *lhs = it; + if (dest->astore != NULL) + (*dest->astore)(dest, sub); + unref(sub); + } + } + + efree(buf); + } + if (wc_indices != NULL) + efree(wc_indices); + } else { /* match failed */ + rstart = 0; + rlength = -1; + } + + DEREF(t1); + unref(RSTART_node->var_value); + RSTART_node->var_value = make_number((AWKNUM) rstart); + unref(RLENGTH_node->var_value); + RLENGTH_node->var_value = make_number((AWKNUM) rlength); + return make_number((AWKNUM) rstart); +} + +/* do_sub --- do the work for sub, gsub, and gensub */ + +/* + * 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") + * print "--->", mygsub("abc", "x*", "X") + * print "--->", mygsub("abc", "b*", "X") + * print "--->", mygsub("abc", "c", "X") + * print "--->", mygsub("abc", "c+", "X") + * print "--->", mygsub("abc", "x*$", "X") + * } + * + * function mygsub(str, regex, replace, origstr, newstr, eosflag, nonzeroflag) + * { + * origstr = str; + * eosflag = nonzeroflag = false + * while (match(str, regex)) { + * if (RLENGTH > 0) { # easy case + * nonzeroflag = true + * if (RSTART == 1) { # match at front of string + * newstr = newstr replace + * } else { + * newstr = newstr substr(str, 1, RSTART-1) replace + * } + * str = substr(str, RSTART+RLENGTH) + * } else if (nonzeroflag) { + * # last match was non-zero in length, and at the + * # current character, we get a zero length match, + * # which we don't really want, so skip over it + * newstr = newstr substr(str, 1, 1) + * str = substr(str, 2) + * nonzeroflag = false + * } else { + * # 0-length match + * if (RSTART == 1) { + * newstr = newstr replace substr(str, 1, 1) + * str = substr(str, 2) + * } else { + * return newstr str replace + * } + * } + * if (length(str) == 0) + * if (eosflag) + * break + * else + * eosflag = true + * } + * if (length(str) > 0) + * newstr = newstr str # rest of string + * + * return newstr + * } + */ + +/* + * 1/2004: The gawk sub/gsub behavior dates from 1996, when we proposed it + * for POSIX. The proposal fell through the cracks, and the 2001 POSIX + * standard chose a more simple behavior. + * + * 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 + * substitutions. An ampersand ('&') appearing in the string repl shall + * be replaced by the string from in that matches the ERE. An ampersand + * preceded with a backslash ('\') shall be interpreted as the literal + * ampersand character. An occurrence of two consecutive backslashes shall + * be interpreted as just a single literal backslash character. Any other + * occurrence of a backslash (for example, preceding any other character) + * shall be treated as a literal backslash character. Note that if repl is a + * string literal (the lexical token STRING; see Grammar (on page 170)), the + * handling of the ampersand character occurs after any lexical processing, + * including any lexical backslash escape sequence processing. If in is + * specified and it is not an lvalue (see Expressions in awk (on page 156)), + * the behavior is undefined. If in is omitted, awk shall use the current + * record ($0) in its place. + * + * 11/2010: The text in the 2008 standard is the same as just quoted. + * However, POSIX behavior is now the default. This can change the behavior + * of awk programs. The old behavior is not available. + * + * 7/2011: Reverted backslash handling to what it used to be. It was in + * gawk for too long. Should have known better. + */ + +/* + * NB: `howmany' conflicts with a SunOS 4.x macro in . + */ + +NODE * +do_sub(int nargs, unsigned int flags) +{ + char *scan; + char *bp, *cp; + char *buf = NULL; + size_t buflen; + char *matchend; + size_t len; + char *matchstart; + char *text; + size_t textlen = 0; + char *repl; + char *replend; + size_t repllen; + int sofar; + int ampersands; + int matches = 0; + Regexp *rp; + 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 */ + bool global; + long current; + bool lastmatchnonzero; + char *mb_indices = NULL; + + if ((flags & GENSUB) != 0) { + double d; + NODE *glob_flag; + + tmp = PEEK(3); + rp = re_update(tmp); + + target = POP_STRING(); /* original string */ + + 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) { + (void) force_string(glob_flag); + warning(_("gensub: third argument `%.*s' treated as 1"), + (int) glob_flag->stlen, + glob_flag->stptr); + } + } + DEREF(glob_flag); + } else { + /* take care of regexp early, in case re_update is fatal */ + + tmp = PEEK(2); + rp = re_update(tmp); + + if ((flags & GSUB) != 0) + how_many = -1; + + /* original string */ + + if ((flags & LITERAL) != 0) + target = POP_STRING(); + else { + lhs = POP_ADDRESS(); + target = force_string(*lhs); + } + } + + global = (how_many == -1); + + 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, target->stptr, 0, target->stlen, RE_NEED_START) == -1 || + RESTART(rp, target->stptr) > target->stlen) + goto done; + + target->flags |= STRING; + + text = target->stptr; + textlen = target->stlen; + + repl = rep_node->stptr; + replend = repl + rep_node->stlen; + repllen = replend - repl; + + ampersands = 0; + + /* + * Some systems' malloc() can't handle being called with an + * argument of zero. Thus we have to have some special case + * code to check for `repllen == 0'. This can occur for + * something like: + * sub(/foo/, "", mystring) + * for example. + */ + if (gawk_mb_cur_max > 1 && repllen > 0) { + emalloc(mb_indices, char *, repllen * sizeof(char), "do_sub"); + 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 == '&')) { + repllen--; + ampersands++; + } else if (*scan == '\\') { + if ((flags & GENSUB) != 0) { /* gensub, behave sanely */ + if (isdigit((unsigned char) scan[1])) { + ampersands++; + scan++; + } else { /* \q for any q --> q */ + repllen--; + scan++; + } + } else if (do_posix) { + /* \& --> &, \\ --> \ */ + if (scan[1] == '&' || scan[1] == '\\') { + repllen--; + scan++; + } /* else + leave alone, it goes into the output */ + } else { + /* gawk default behavior since 1996 */ + if (strncmp(scan, "\\\\\\&", 4) == 0 + || strncmp(scan, "\\\\\\\\", 4) == 0) { /* 2016: fixed */ + /* \\\& --> \& */ + /* \\\\ --> \\ */ + repllen -= 2; + scan += 3; + } else if (strncmp(scan, "\\\\&", 3) == 0) { + /* \\& --> \ */ + ampersands++; + repllen--; + scan += 2; + } else if (scan[1] == '&') { + /* \& --> & */ + repllen--; + scan++; + } /* else + leave alone, it goes into the output */ + } + } + } + + lastmatchnonzero = false; + + /* 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'; + + bp = buf; + for (current = 1;; current++) { + matches++; + matchstart = target->stptr + RESTART(rp, target->stptr); + matchend = target->stptr + REEND(rp, target->stptr); + + /* + * create the result, copying in parts of the original + * 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 = matchend - text + repllen + + ampersands * (matchend - matchstart) + 1; + sofar = bp - buf; + while (buflen < (sofar + len + 1)) { + buflen *= 2; + erealloc(buf, char *, buflen, "sub_common"); + bp = buf + sofar; + } + for (scan = text; scan < matchstart; scan++) + *bp++ = *scan; + if (global || current == how_many) { + /* + * If the current match matched the null string, + * and the last match didn't and did a replacement, + * and the match of the null string is at the front of + * the text (meaning right after end of the previous + * replacement), then skip this one. + */ + if (matchstart == matchend + && lastmatchnonzero + && matchstart == text) { + lastmatchnonzero = false; + matches--; + goto empty; + } + /* + * If replacing all occurrences, or this is the + * match we want, copy in the replacement text, + * making substitutions as we go. + */ + for (scan = repl; scan < replend; scan++) + if (*scan == '&' + /* + * Don't test repllen here. A simple "&" could + * end up with repllen == 0. + */ + && (gawk_mb_cur_max == 1 + || mb_indices[scan - repl] == 1) + ) { + for (cp = matchstart; cp < matchend; cp++) + *bp++ = *cp; + } else if (*scan == '\\' + && (gawk_mb_cur_max == 1 + || (repllen > 0 && mb_indices[scan - repl] == 1)) + ) { + if (flags & GENSUB) { /* gensub, behave sanely */ + if (isdigit((unsigned char) scan[1])) { + int dig = scan[1] - '0'; + if (dig < NUMSUBPATS(rp, target->stptr) && SUBPATSTART(rp, tp->stptr, dig) != -1) { + char *start, *end; + + start = target->stptr + + SUBPATSTART(rp, target->stptr, dig); + end = target->stptr + + SUBPATEND(rp, target->stptr, dig); + + for (cp = start; cp < end; cp++) + *bp++ = *cp; + } + scan++; + } else /* \q for any q --> q */ + *bp++ = *++scan; + } else if (do_posix) { + /* \& --> &, \\ --> \ */ + if (scan[1] == '&' || scan[1] == '\\') + scan++; + *bp++ = *scan; + } else { + /* gawk default behavior since 1996 */ + if (strncmp(scan, "\\\\\\&", 4) == 0 + || strncmp(scan, "\\\\\\\\", 4) == 0) { /* 2016: fixed */ + /* \\\& --> \& */ + /* \\\\ --> \\ */ + *bp++ = '\\'; + *bp++ = scan[3]; + scan += 3; + } else if (strncmp(scan, "\\\\&", 3) == 0) { + /* \\& --> \ */ + *bp++ = '\\'; + for (cp = matchstart; cp < matchend; cp++) + *bp++ = *cp; + scan += 2; + } else if (scan[1] == '&') { + /* \& --> & */ + *bp++ = '&'; + scan++; + } else + *bp++ = *scan; + } + } else + *bp++ = *scan; + if (matchstart != matchend) + lastmatchnonzero = true; + } else { + /* + * don't want this match, skip over it by copying + * in current text. + */ + for (cp = matchstart; cp < matchend; cp++) + *bp++ = *cp; + } + empty: + /* catch the case of gsub(//, "blah", whatever), i.e. empty regexp */ + if (matchstart == matchend && matchend < text + textlen) { + *bp++ = *matchend; + matchend++; + } + 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, target->stptr, text - target->stptr, textlen, RE_NEED_START) == -1) + break; + + } + sofar = bp - buf; + if (buflen < (sofar + textlen + 1)) { + buflen = sofar + textlen + 1; + erealloc(buf, char *, buflen, "do_sub"); + bp = buf + sofar; + } + /* + * 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; + + if (mb_indices != NULL) + efree(mb_indices); + +done: + DEREF(rep_node); + + if ((matches == 0 || (flags & LITERAL) != 0) && buf != NULL) { + efree(buf); + buf = NULL; + } + + if (flags & GENSUB) { + if (matches > 0) { + /* return the result string */ + DEREF(target); + assert(buf != NULL); + return make_str_node(buf, textlen, ALREADY_MALLOCED); + } + + /* return the original string */ + return target; + } + + /* For a string literal, must not change the original string. */ + if ((flags & LITERAL) != 0) + DEREF(target); + else if (matches > 0) { + unref(*lhs); + *lhs = make_str_node(buf, textlen, ALREADY_MALLOCED); + } + + return make_number((AWKNUM) matches); +} + +/* call_sub --- call do_sub indirectly */ + +NODE * +call_sub(const char *name, int nargs) +{ + unsigned int flags = 0; + NODE *regex, *replace, *glob_flag; + NODE **lhs, *rhs; + NODE *zero = make_number(0.0); + NODE *result; + + if (name[0] == 'g') { + if (name[1] == 'e') + flags = GENSUB; + else + flags = GSUB; + } + + if (flags == 0 || flags == GSUB) { + /* sub or gsub */ + if (nargs != 2) + fatal(_("%s: can be called indirectly only with two arguments"), name); + + replace = POP_STRING(); + regex = POP(); /* the regex */ + /* + * push regex + * push replace + * push $0 + */ + 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); + nargs++; + PUSH_ADDRESS(lhs); + } else { + /* gensub */ + if (nargs == 4) + rhs = POP(); + else + rhs = NULL; + glob_flag = POP_STRING(); + replace = POP_STRING(); + regex = POP(); /* the regex */ + /* + * push regex + * push replace + * push glob_flag + * if (nargs = 3) { + * push $0 + * nargs++ + * } + */ + if ((regex->flags & REGEX) != 0) + regex = regex->typed_re; + else + regex = make_regnode(Node_regex, regex); + PUSH(regex); + PUSH(replace); + PUSH(glob_flag); + if (rhs == NULL) { + lhs = r_get_field(zero, (Func_ptr *) 0, true); + rhs = *lhs; + UPREF(rhs); + PUSH(rhs); + nargs++; + } + else + PUSH(rhs); + } + + unref(zero); + result = do_sub(nargs, flags); + if (flags != GENSUB) + reset_record(); + return result; +} + +/* call_match --- call do_match indirectly */ + +NODE * +call_match(int nargs) +{ + NODE *regex, *text, *array; + NODE *result; + + regex = text = array = NULL; + if (nargs == 3) + array = POP(); + regex = POP(); + + /* Don't need to pop the string just to push it back ... */ + + if ((regex->flags & REGEX) != 0) + regex = regex->typed_re; + else + regex = make_regnode(Node_regex, regex); + + PUSH(regex); + + if (array) + PUSH(array); + + result = do_match(nargs); + return result; +} + +/* call_split_func --- call do_split or do_pat_split indirectly */ + +NODE * +call_split_func(const char *name, int nargs) +{ + NODE *regex, *seps; + NODE *result; + + regex = seps = NULL; + if (nargs < 2) + fatal(_("indirect call to %s requires at least two arguments"), + name); + + if (nargs == 4) + seps = POP(); + + if (nargs >= 3) { + regex = POP_STRING(); + 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); + regex->re_flags |= FS_DFLT; + } else + regex = make_regnode(Node_regex, FPAT_node->var_value); + nargs++; + } + + /* Don't need to pop the string or the data array */ + + PUSH(regex); + + if (seps) + PUSH(seps); + + result = (name[0] == 's') ? do_split(nargs) : do_patsplit(nargs); + + return result; +} + +/* make_integer - Convert an integer to a number node. */ + +static NODE * +make_integer(uintmax_t n) +{ + n = adjust_uint(n); + + return make_number((AWKNUM) n); +} + +/* do_lshift --- perform a << operation */ + +NODE * +do_lshift(int nargs) +{ + NODE *s1, *s2; + uintmax_t uval, ushift, res; + AWKNUM val, shift; + + POP_TWO_SCALARS(s1, s2); + if (do_lint) { + if ((fixtype(s1)->flags & NUMBER) == 0) + lintwarn(_("lshift: received non-numeric first argument")); + 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 (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) + lintwarn(_("lshift(%f, %f): too large shift value will give strange results"), val, shift); + } + + DEREF(s1); + DEREF(s2); + + uval = (uintmax_t) val; + ushift = (uintmax_t) shift; + + res = uval << ushift; + return make_integer(res); +} + +/* do_rshift --- perform a >> operation */ + +NODE * +do_rshift(int nargs) +{ + NODE *s1, *s2; + uintmax_t uval, ushift, res; + AWKNUM val, shift; + + POP_TWO_SCALARS(s1, s2); + if (do_lint) { + if ((fixtype(s1)->flags & NUMBER) == 0) + lintwarn(_("rshift: received non-numeric first argument")); + 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 (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) + lintwarn(_("rshift(%f, %f): too large shift value will give strange results"), val, shift); + } + + DEREF(s1); + DEREF(s2); + + uval = (uintmax_t) val; + ushift = (uintmax_t) shift; + + res = uval >> ushift; + return make_integer(res); +} + +/* do_and --- perform an & operation */ + +NODE * +do_and(int nargs) +{ + NODE *s1; + uintmax_t res, uval; + AWKNUM val; + int i; + + res = ~0; /* start off with all ones */ + if (nargs < 2) + fatal(_("and: called with less than two arguments")); + + for (i = 1; nargs > 0; nargs--, i++) { + s1 = POP_SCALAR(); + if (do_lint && (fixtype(s1)->flags & NUMBER) == 0) + lintwarn(_("and: argument %d is non-numeric"), i); + + val = force_number(s1)->numbr; + if (val < 0) + fatal(_("and: argument %d negative value %g is not allowed"), i, val); + + uval = (uintmax_t) val; + res &= uval; + + DEREF(s1); + } + + return make_integer(res); +} + +/* do_or --- perform an | operation */ + +NODE * +do_or(int nargs) +{ + NODE *s1; + uintmax_t res, uval; + AWKNUM val; + int i; + + res = 0; + if (nargs < 2) + fatal(_("or: called with less than two arguments")); + + for (i = 1; nargs > 0; nargs--, i++) { + s1 = POP_SCALAR(); + if (do_lint && (fixtype(s1)->flags & NUMBER) == 0) + lintwarn(_("or: argument %d is non-numeric"), i); + + val = force_number(s1)->numbr; + if (val < 0) + fatal(_("or: argument %d negative value %g is not allowed"), i, val); + + uval = (uintmax_t) val; + res |= uval; + + DEREF(s1); + } + + return make_integer(res); +} + +/* do_xor --- perform an ^ operation */ + +NODE * +do_xor(int nargs) +{ + NODE *s1; + uintmax_t res, uval; + AWKNUM val; + int i; + + if (nargs < 2) + fatal(_("xor: called with less than two arguments")); + + res = 0; /* silence compiler warning */ + for (i = 1; nargs > 0; nargs--, i++) { + s1 = POP_SCALAR(); + if (do_lint && (fixtype(s1)->flags & NUMBER) == 0) + lintwarn(_("xor: argument %d is non-numeric"), i); + + val = force_number(s1)->numbr; + if (val < 0) + fatal(_("xor: argument %d negative value %g is not allowed"), i, val); + + uval = (uintmax_t) val; + if (i == 1) + res = uval; + else + res ^= uval; + + DEREF(s1); + } + + return make_integer(res); +} + +/* do_compl --- perform a ~ operation */ + +NODE * +do_compl(int nargs) +{ + NODE *tmp; + double d; + uintmax_t uval; + + tmp = POP_SCALAR(); + if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0) + lintwarn(_("compl: received non-numeric argument")); + d = force_number(tmp)->numbr; + DEREF(tmp); + + 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; + return make_integer(uval); +} + +/* do_strtonum --- the strtonum function */ + +NODE * +do_strtonum(int nargs) +{ + NODE *tmp; + AWKNUM d; + + 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; + + DEREF(tmp); + return make_number((AWKNUM) d); +} + +/* nondec2awknum --- convert octal or hex value to double */ + +/* + * Because of awk's concatenation rules and the way awk.y:yylex() + * collects a number, this routine has to be willing to stop on the + * first invalid character. + */ + +AWKNUM +nondec2awknum(char *str, size_t len, char **endptr) +{ + AWKNUM retval = 0.0; + char save; + short val; + char *start = str; + + 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 (endptr) + *endptr = start; + return (AWKNUM) 0.0; + } + + for (str += 2, len -= 2; len > 0; len--, str++) { + switch (*str) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + val = *str - '0'; + break; + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + val = *str - 'a' + 10; + break; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + val = *str - 'A' + 10; + break; + default: + if (endptr) + *endptr = str; + goto done; + } + retval = (retval * 16) + val; + } + if (endptr) + *endptr = str; + } else if (len >= 1 && *str == '0') { + for (; len > 0; len--) { + if (! isdigit((unsigned char) *str)) { + if (endptr) + *endptr = str; + goto done; + } + else if (*str == '8' || *str == '9') { + str = start; + goto decimal; + } + retval = (retval * 8) + (*str - '0'); + str++; + } + if (endptr) + *endptr = str; + } else { +decimal: + save = str[len]; + str[len] = '\0'; + retval = strtod(str, endptr); + str[len] = save; + } +done: + return retval; +} + +/* do_dcgettext, do_dcngettext --- handle i18n translations */ + +#if ENABLE_NLS && defined(LC_MESSAGES) && HAVE_DCGETTEXT + +static int +localecategory_from_argument(NODE *t) +{ + static const struct category_table { + int val; + const char *name; + } cat_tab[] = { +#ifdef LC_ALL + { LC_ALL, "LC_ALL" }, +#endif /* LC_ALL */ +#ifdef LC_COLLATE + { LC_COLLATE, "LC_COLLATE" }, +#endif /* LC_COLLATE */ +#ifdef LC_CTYPE + { LC_CTYPE, "LC_CTYPE" }, +#endif /* LC_CTYPE */ +#ifdef LC_MESSAGES + { LC_MESSAGES, "LC_MESSAGES" }, +#endif /* LC_MESSAGES */ +#ifdef LC_MONETARY + { LC_MONETARY, "LC_MONETARY" }, +#endif /* LC_MONETARY */ +#ifdef LC_NUMERIC + { LC_NUMERIC, "LC_NUMERIC" }, +#endif /* LC_NUMERIC */ +#ifdef LC_RESPONSE + { LC_RESPONSE, "LC_RESPONSE" }, +#endif /* LC_RESPONSE */ +#ifdef LC_TIME + { LC_TIME, "LC_TIME" }, +#endif /* LC_TIME */ + }; + + if (t != NULL) { + int low, high, i, mid; + char *category; + int lc_cat = -1; + + char save = t->stptr[t->stlen]; + t->stptr[t->stlen] = '\0'; + category = t->stptr; + + /* binary search the table */ + low = 0; + high = (sizeof(cat_tab) / sizeof(cat_tab[0])) - 1; + while (low <= high) { + mid = (low + high) / 2; + i = strcmp(category, cat_tab[mid].name); + + if (i < 0) /* category < mid */ + high = mid - 1; + else if (i > 0) /* category > mid */ + low = mid + 1; + else { + lc_cat = cat_tab[mid].val; + break; + } + } + t->stptr[t->stlen] = save; + if (lc_cat == -1) /* not there */ + fatal(_("dcgettext: `%s' is not a valid locale category"), category); + + return lc_cat; + } else + return LC_MESSAGES; +} + +#endif + +/* + * awk usage is + * + * str = dcgettext(string [, domain [, category]]) + * str = dcngettext(string1, string2, number [, domain [, category]]) + * + * Default domain is TEXTDOMAIN, default category is LC_MESSAGES. + */ + +NODE * +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 = '\0', save2 = '\0'; + + if (nargs == 3) { /* third argument */ + tmp = POP_STRING(); + lc_cat = localecategory_from_argument(tmp); + DEREF(tmp); + } else + lc_cat = LC_MESSAGES; + + if (nargs >= 2) { /* second argument */ + t2 = POP_STRING(); + domain = t2->stptr; + str_terminate(t2, save2); + } else + domain = TEXTDOMAIN; +#else + if (nargs == 3) { + tmp = POP_STRING(); + DEREF(tmp); + } + if (nargs >= 2) { + t2 = POP_STRING(); + DEREF(t2); + } +#endif + + t1 = POP_STRING(); /* first argument */ + string = t1->stptr; + +#if ENABLE_NLS && defined(LC_MESSAGES) && HAVE_DCGETTEXT + str_terminate(t1, save1); + the_result = dcgettext(domain, string, lc_cat); + 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, reslen); +} + + +NODE * +do_dcngettext(int nargs) +{ + NODE *tmp, *t1, *t2, *t3; + char *string1, *string2; + 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 = '\0', save1 = '\0', save2 = '\0'; + bool saved_end = false; + + if (nargs == 5) { /* fifth argument */ + tmp = POP_STRING(); + lc_cat = localecategory_from_argument(tmp); + DEREF(tmp); + } else + lc_cat = LC_MESSAGES; + + t3 = NULL; + 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 + if (nargs == 5) { + tmp = POP_STRING(); + DEREF(tmp); + } + if (nargs >= 4) { + t3 = POP_STRING(); + DEREF(t3); + } +#endif + + t2 = POP_NUMBER(); /* third argument */ + d = get_number_d(t2); + DEREF(t2); + + number = (unsigned long) double_to_int(d); + t2 = POP_STRING(); /* second argument */ + string2 = t2->stptr; + t1 = POP_STRING(); /* first argument */ + string1 = t1->stptr; + +#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 + 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, reslen); +} + +/* do_bindtextdomain --- set the directory for a text domain */ + +/* + * awk usage is + * + * binding = bindtextdomain(dir [, domain]) + * + * If dir is "", pass NULL to C version. + * Default domain is TEXTDOMAIN. + */ + +NODE * +do_bindtextdomain(int nargs) +{ + NODE *t1, *t2; + const char *directory, *domain; + const char *the_result; + + t1 = t2 = NULL; + /* set defaults */ + directory = NULL; + domain = TEXTDOMAIN; + char save = '\0', save1 = '\0'; + + 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) { + 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) { + t2->stptr[t2->stlen] = save; + DEREF(t2); + } + + return make_string(the_result, strlen(the_result)); +} + +#ifdef SUPPLY_INTDIV +/* 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); +} +#endif /* SUPPLY_INTDIV */ + +/* 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 */ + +static size_t +mbc_byte_count(const char *ptr, size_t numchars) +{ + mbstate_t cur_state; + size_t sum = 0; + int mb_len; + + memset(& cur_state, 0, sizeof(cur_state)); + + assert(gawk_mb_cur_max > 1); + mb_len = mbrlen(ptr, numchars * gawk_mb_cur_max, &cur_state); + if (mb_len <= 0) + return numchars; /* no valid m.b. char */ + + for (; numchars > 0; numchars--) { + mb_len = mbrlen(ptr, numchars * gawk_mb_cur_max, &cur_state); + if (mb_len <= 0) + break; + sum += mb_len; + ptr += mb_len; + } + + return sum; +} + +/* mbc_char_count --- return number of m.b. chars in string, up to numbytes bytes */ + +static size_t +mbc_char_count(const char *ptr, size_t numbytes) +{ + mbstate_t cur_state; + size_t sum = 0; + int mb_len; + + if (gawk_mb_cur_max == 1) + return numbytes; + + memset(& cur_state, 0, sizeof(cur_state)); + + mb_len = mbrlen(ptr, numbytes, &cur_state); + if (mb_len <= 0) + return numbytes; /* no valid m.b. char */ + + 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 new file mode 100644 index 0000000..05b9440 --- /dev/null +++ b/cint_array.c @@ -0,0 +1,1232 @@ +/* + * cint_array.c - routines for arrays of (mostly) consecutive positive integer indices. + */ + +/* + * Copyright (C) 1986, 1988, 1989, 1991-2013, 2016, 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 + */ + +#include "awk.h" + +#define INT32_BIT 32 + +extern FILE *output_fp; +extern void indent(int indent_level); +extern NODE **is_integer(NODE *symbol, NODE *subs); + +/* + * NHAT --- maximum size of a leaf array (2^NHAT). + * THRESHOLD --- Maximum capacity waste; THRESHOLD >= 2^(NHAT + 1). + */ + +static int NHAT = 10; +static long THRESHOLD; + +/* + * What is the optimium NHAT ? timing results suggest that 10 is a good choice, + * although differences aren't that significant for > 10. + */ + + +static NODE **cint_array_init(NODE *symbol, NODE *subs); +static NODE **is_uinteger(NODE *symbol, NODE *subs); +static NODE **cint_lookup(NODE *symbol, NODE *subs); +static NODE **cint_exists(NODE *symbol, NODE *subs); +static NODE **cint_clear(NODE *symbol, NODE *subs); +static NODE **cint_remove(NODE *symbol, NODE *subs); +static NODE **cint_list(NODE *symbol, NODE *t); +static NODE **cint_copy(NODE *symbol, NODE *newsymb); +static NODE **cint_dump(NODE *symbol, NODE *ndump); +#ifdef ARRAYDEBUG +static void cint_print(NODE *symbol); +#endif + +afunc_t cint_array_func[] = { + cint_array_init, + is_uinteger, + null_length, + cint_lookup, + cint_exists, + cint_clear, + cint_remove, + cint_list, + cint_copy, + cint_dump, + (afunc_t) 0, +}; + +static inline int cint_hash(long k); +static inline NODE **cint_find(NODE *symbol, long k, int h1); + +static inline NODE *make_node(NODETYPE type); + +static NODE **tree_lookup(NODE *symbol, NODE *tree, long k, int m, long base); +static NODE **tree_exists(NODE *tree, long k); +static void tree_clear(NODE *tree); +static int tree_remove(NODE *symbol, NODE *tree, long k); +static void tree_copy(NODE *newsymb, NODE *tree, NODE *newtree); +static long tree_list(NODE *tree, NODE **list, assoc_kind_t assoc_kind); +static inline NODE **tree_find(NODE *tree, long k, int i); +static void tree_info(NODE *tree, NODE *ndump, const char *aname); +static size_t tree_kilobytes(NODE *tree); +#ifdef ARRAYDEBUG +static void tree_print(NODE *tree, size_t bi, int indent_level); +#endif + +static inline NODE **leaf_lookup(NODE *symbol, NODE *array, long k, long size, long base); +static inline NODE **leaf_exists(NODE *array, long k); +static void leaf_clear(NODE *array); +static int leaf_remove(NODE *symbol, NODE *array, long k); +static void leaf_copy(NODE *newsymb, NODE *array, NODE *newarray); +static long leaf_list(NODE *array, NODE **list, assoc_kind_t assoc_kind); +static void leaf_info(NODE *array, NODE *ndump, const char *aname); +#ifdef ARRAYDEBUG +static void leaf_print(NODE *array, size_t bi, int indent_level); +#endif + +/* 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, + 8192, 16384, 32768, 65536, 131072, 262144, + 524288, 1048576, 2097152, 4194304, 8388608, 16777216, + 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824 +}; + + +#define ISUINT(a, s) ((((s)->flags & NUMINT) != 0 || is_integer(a, s) != NULL) \ + && (s)->numbr >= 0) + +/* + * 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). + * + * [0] --> [ 0 ] + * [1] --> [ 1 ] + * |2| --> [ 2 | 3 ] + * |3| --> [ 4 | 5 | 6 | 7 ] + * |.| + * |k| --> [ 2^(k - 1)| ... | 2^k - 1 ] + * ... + * + * 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. + * Bagwell, Phil (2002). + * http://infoscience.epfl.ch/record/64410/files/techlists.pdf + * + * Disadvantage: + * Worst case memory waste > 99% and will happen when each of the + * leaf arrays contains only a single element. Even with consecutive + * integers, memory waste can be as high as 50%. + * + * Solution: Hashed Array Trees (HATs). + * + */ + +/* cint_array_init --- array initialization routine */ + +static NODE ** +cint_array_init(NODE *symbol ATTRIBUTE_UNUSED, NODE *subs ATTRIBUTE_UNUSED) +{ + if (symbol == NULL) { + long newval; + size_t nelems = (sizeof(power_two_table) / sizeof(power_two_table[0])); + + /* check relevant environment variables */ + if ((newval = getenv_long("NHAT")) > 1 && newval < INT32_BIT) + NHAT = newval; + /* don't allow overflow off the end of the table */ + if (NHAT >= nelems) + NHAT = nelems - 2; + THRESHOLD = power_two_table[NHAT + 1]; + } else + null_array(symbol); + + return & success_node; +} + + +/* is_uinteger --- test if the subscript is an integer >= 0 */ + +NODE ** +is_uinteger(NODE *symbol, NODE *subs) +{ + if (is_integer(symbol, subs) != NULL && subs->numbr >= 0) + return & success_node; + return NULL; +} + + +/* cint_lookup --- Find the subscript in the array; Install it if it isn't there. */ + +static NODE ** +cint_lookup(NODE *symbol, NODE *subs) +{ + NODE **lhs; + long k; + int h1 = -1, m, li; + NODE *tn, *xn; + long cint_size, capacity; + + k = -1; + if (ISUINT(symbol, subs)) { + k = subs->numbr; /* k >= 0 */ + h1 = cint_hash(k); /* h1 >= NHAT */ + if ((lhs = cint_find(symbol, k, h1)) != NULL) + return lhs; + } + xn = symbol->xarray; + if (xn != NULL && (lhs = xn->aexists(xn, subs)) != NULL) + return lhs; + + /* It's not there, install it */ + + if (k < 0) + goto xinstall; + + m = h1 - 1; /* m >= (NHAT- 1) */ + + /* Estimate capacity upper bound. + * capacity upper bound = current capacity + leaf array size. + */ + li = m > NHAT ? m : NHAT; + while (li >= NHAT) { + /* leaf-array of a HAT */ + li = (li + 1) / 2; + } + capacity = symbol->array_capacity + power_two_table[li]; + + cint_size = (xn == NULL) ? symbol->table_size + : (symbol->table_size - xn->table_size); + assert(cint_size >= 0); + if ((capacity - cint_size) > THRESHOLD) + goto xinstall; + + if (symbol->nodes == NULL) { + symbol->array_capacity = 0; + assert(symbol->table_size == 0); + + /* nodes[0] .. nodes[NHAT- 1] not used */ + ezalloc(symbol->nodes, NODE **, INT32_BIT * sizeof(NODE *), "cint_lookup"); + } + + symbol->table_size++; /* one more element in array */ + + tn = symbol->nodes[h1]; + if (tn == NULL) { + tn = make_node(Node_array_tree); + symbol->nodes[h1] = tn; + } + + if (m < NHAT) + return tree_lookup(symbol, tn, k, NHAT, 0); + return tree_lookup(symbol, tn, k, m, power_two_table[m]); + +xinstall: + + symbol->table_size++; + if (xn == NULL) { + xn = symbol->xarray = make_array(); + xn->vname = symbol->vname; /* shallow copy */ + + /* + * Avoid using assoc_lookup(xn, subs) which may lead + * to infinite recursion. + */ + + if (is_integer(xn, subs)) + xn->array_funcs = int_array_func; + else + xn->array_funcs = str_array_func; + xn->flags |= XARRAY; + } + return xn->alookup(xn, subs); +} + + +/* cint_exists --- test whether an index is in the array or not. */ + +static NODE ** +cint_exists(NODE *symbol, NODE *subs) +{ + NODE *xn; + + if (ISUINT(symbol, subs)) { + long k = subs->numbr; + NODE **lhs; + if ((lhs = cint_find(symbol, k, cint_hash(k))) != NULL) + return lhs; + } + if ((xn = symbol->xarray) == NULL) + return NULL; + return xn->aexists(xn, subs); +} + + +/* cint_clear --- flush all the values in symbol[] */ + +static NODE ** +cint_clear(NODE *symbol, NODE *subs ATTRIBUTE_UNUSED) +{ + size_t i; + NODE *tn; + + assert(symbol->nodes != NULL); + + if (symbol->xarray != NULL) { + NODE *xn = symbol->xarray; + assoc_clear(xn); + freenode(xn); + symbol->xarray = NULL; + } + + for (i = NHAT; i < INT32_BIT; i++) { + tn = symbol->nodes[i]; + if (tn != NULL) { + tree_clear(tn); + freenode(tn); + } + } + + efree(symbol->nodes); + symbol->ainit(symbol, NULL); /* re-initialize symbol */ + return NULL; +} + + +/* cint_remove --- remove an index from the array */ + +static NODE ** +cint_remove(NODE *symbol, NODE *subs) +{ + long k; + int h1; + NODE *tn, *xn = symbol->xarray; + + if (symbol->table_size == 0) + return NULL; + + if (! ISUINT(symbol, subs)) + goto xremove; + + assert(symbol->nodes != NULL); + + k = subs->numbr; + h1 = cint_hash(k); + tn = symbol->nodes[h1]; + if (tn == NULL || ! tree_remove(symbol, tn, k)) + goto xremove; + + if (tn->table_size == 0) { + freenode(tn); + symbol->nodes[h1] = NULL; + } + + symbol->table_size--; + + if (xn == NULL && symbol->table_size == 0) { + efree(symbol->nodes); + symbol->ainit(symbol, NULL); /* re-initialize array 'symbol' */ + } else if(xn != NULL && symbol->table_size == xn->table_size) { + /* promote xn to symbol */ + + xn->flags &= ~XARRAY; + xn->parent_array = symbol->parent_array; + efree(symbol->nodes); + *symbol = *xn; + freenode(xn); + } + + return & success_node; + +xremove: + xn = symbol->xarray; + if (xn == NULL || xn->aremove(xn, subs) == NULL) + return NULL; + if (xn->table_size == 0) { + freenode(xn); + symbol->xarray = NULL; + } + symbol->table_size--; + assert(symbol->table_size > 0); + + return & success_node; +} + + +/* cint_copy --- duplicate input array "symbol" */ + +static NODE ** +cint_copy(NODE *symbol, NODE *newsymb) +{ + NODE **old, **new; + size_t i; + + assert(symbol->nodes != NULL); + + /* allocate new table */ + 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); + tree_copy(newsymb, old[i], new[i]); + } + + if (symbol->xarray != NULL) { + NODE *xn, *n; + xn = symbol->xarray; + n = make_array(); + n->vname = newsymb->vname; + (void) xn->acopy(xn, n); + newsymb->xarray = n; + } else + newsymb->xarray = NULL; + + newsymb->nodes = new; + newsymb->table_size = symbol->table_size; + newsymb->array_capacity = symbol->array_capacity; + newsymb->flags = symbol->flags; + + return NULL; +} + + +/* cint_list --- return a list of items */ + +static NODE** +cint_list(NODE *symbol, NODE *t) +{ + NODE **list = NULL; + NODE *tn, *xn; + unsigned long k = 0, num_elems, list_size; + size_t j, ja, jd; + int elem_size = 1; + assoc_kind_t assoc_kind; + + num_elems = symbol->table_size; + if (num_elems == 0) + return NULL; + assoc_kind = (assoc_kind_t) t->flags; + if ((assoc_kind & (AINDEX|AVALUE|ADELETE)) == (AINDEX|ADELETE)) + num_elems = 1; + + if ((assoc_kind & (AINDEX|AVALUE)) == (AINDEX|AVALUE)) + elem_size = 2; + list_size = num_elems * elem_size; + + if (symbol->xarray != NULL) { + xn = symbol->xarray; + list = xn->alist(xn, t); + assert(list != NULL); + assoc_kind &= ~(AASC|ADESC); + t->flags = (unsigned int) assoc_kind; + if (num_elems == 1 || num_elems == xn->table_size) + return list; + erealloc(list, NODE **, list_size * sizeof(NODE *), "cint_list"); + k = elem_size * xn->table_size; + } else + emalloc(list, NODE **, list_size * sizeof(NODE *), "cint_list"); + + if ((assoc_kind & AINUM) == 0) { + /* not sorting by "index num" */ + assoc_kind &= ~(AASC|ADESC); + t->flags = (unsigned int) assoc_kind; + } + + /* populate it with index in ascending or descending order */ + + for (ja = NHAT, jd = INT32_BIT - 1; ja < INT32_BIT && jd >= NHAT; ) { + j = (assoc_kind & ADESC) != 0 ? jd-- : ja++; + tn = symbol->nodes[j]; + if (tn == NULL) + continue; + k += tree_list(tn, list + k, assoc_kind); + if (k >= list_size) + return list; + } + return list; +} + + +/* cint_dump --- dump array info */ + +static NODE ** +cint_dump(NODE *symbol, NODE *ndump) +{ + NODE *tn, *xn = NULL; + int indent_level; + size_t i; + long cint_size = 0, xsize = 0; + AWKNUM kb = 0; + extern AWKNUM int_kilobytes(NODE *symbol); + extern AWKNUM str_kilobytes(NODE *symbol); + + indent_level = ndump->alevel; + + if (symbol->xarray != NULL) { + xn = symbol->xarray; + 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", + array_vname(symbol)); + indent_level++; + indent(indent_level); + fprintf(output_fp, "array_func: cint_array_func\n"); + if (symbol->flags != 0) { + indent(indent_level); + fprintf(output_fp, "flags: %s\n", flags2str(symbol->flags)); + } + indent(indent_level); + fprintf(output_fp, "NHAT: %d\n", NHAT); + indent(indent_level); + fprintf(output_fp, "THRESHOLD: %ld\n", THRESHOLD); + indent(indent_level); + fprintf(output_fp, "table_size: %ld (total), %ld (cint), %ld (int + str)\n", + symbol->table_size, cint_size, xsize); + indent(indent_level); + fprintf(output_fp, "array_capacity: %lu\n", (unsigned long) symbol->array_capacity); + indent(indent_level); + fprintf(output_fp, "Load Factor: %.2g\n", (AWKNUM) cint_size / symbol->array_capacity); + + for (i = NHAT; i < INT32_BIT; i++) { + tn = symbol->nodes[i]; + if (tn == NULL) + continue; + /* Node_array_tree + HAT */ + kb += (sizeof(NODE) + tree_kilobytes(tn)) / 1024.0; + } + 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) + kb += int_kilobytes(xn); + else + kb += str_kilobytes(xn); + } + + indent(indent_level); + fprintf(output_fp, "memory: %.2g kB (total)\n", kb); + + /* dump elements */ + + if (ndump->adepth >= 0) { + const char *aname; + + fprintf(output_fp, "\n"); + aname = make_aname(symbol); + for (i = NHAT; i < INT32_BIT; i++) { + tn = symbol->nodes[i]; + if (tn != NULL) + tree_info(tn, ndump, aname); + } + } + + if (xn != NULL) { + fprintf(output_fp, "\n"); + xn->adump(xn, ndump); + } + +#ifdef ARRAYDEBUG + if (ndump->adepth < -999) + cint_print(symbol); +#endif + + return NULL; +} + + +/* cint_hash --- locate the HAT for a given number 'k' */ + +static inline int +cint_hash(long k) +{ + uint32_t num, r, shift; + + assert(k >= 0); + if (k == 0) + return NHAT; + num = k; + + /* Find the Floor(log base 2 of 32-bit integer) */ + + /* + * Warren Jr., Henry S. (2002). Hacker's Delight. + * Addison Wesley. pp. pp. 215. ISBN 978-0201914658. + * + * r = 0; + * if (num >= 1<<16) { num >>= 16; r += 16; } + * if (num >= 1<< 8) { num >>= 8; r += 8; } + * if (num >= 1<< 4) { num >>= 4; r += 4; } + * if (num >= 1<< 2) { num >>= 2; r += 2; } + * if (num >= 1<< 1) { r += 1; } + */ + + + /* + * Slightly different code copied from: + * + * http://www-graphics.stanford.edu/~seander/bithacks.html + * Bit Twiddling Hacks + * 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 (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. + * + */ + + r = (num > 0xFFFF) << 4; num >>= r; + shift = (num > 0xFF) << 3; num >>= shift; r |= shift; + shift = (num > 0x0F) << 2; num >>= shift; r |= shift; + shift = (num > 0x03) << 1; num >>= shift; r |= shift; + r |= (num >> 1); + + /* We use a single HAT for 0 <= num < 2^NHAT */ + if (r < NHAT) + return NHAT; + + return (1 + r); +} + + +/* cint_find --- locate the integer subscript */ + +static inline NODE ** +cint_find(NODE *symbol, long k, int h1) +{ + NODE *tn; + + if (symbol->nodes == NULL || (tn = symbol->nodes[h1]) == NULL) + return NULL; + return tree_exists(tn, k); +} + + +#ifdef ARRAYDEBUG + +/* cint_print --- print structural info */ + +static void +cint_print(NODE *symbol) +{ + NODE *tn; + size_t i; + + fprintf(output_fp, "I[%4lu:%-4lu]\n", (unsigned long) INT32_BIT, + (unsigned long) symbol->table_size); + for (i = NHAT; i < INT32_BIT; i++) { + tn = symbol->nodes[i]; + if (tn == NULL) + continue; + tree_print(tn, i, 1); + } +} + +#endif + + +/*------------------------ Hashed Array Trees -----------------------------*/ + +/* + * HATs: Hashed Array Trees + * Fast variable-length arrays + * Edward Sitarski + * http://www.drdobbs.com/architecture-and-design/184409965 + * + * HAT has a top-level array containing a power of two + * number of leaf arrays. All leaf arrays are the same size as the + * top-level array. A full HAT can hold n^2 elements, + * where n (some power of 2) is the size of each leaf array. + * [i/n][i & (n - 1)] locates the `i th' element in a HAT. + * + */ + +/* + * 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. + * 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). + * + * IMPLEMENTATION DETAILS: + * 1. A HAT of 2^12 elements needs 2^6 house-keeping NODEs + * of Node_array_leaf. + * + * 2. A HAT of HATS of 2^12 elements needs + * 2^6 * (1 Node_array_tree + 2^3 Node_array_leaf) + * ~ 2^9 house-keeping NODEs. + * + * 3. When a leaf array (or leaf HAT) becomes empty, the memory + * is deallocated, and when there is no leaf array (or leaf HAT) left, + * the HAT is deleted. + * + * 4. A HAT stores the base (first) element, and locates the leaf array/HAT + * for the `i th' element using integer division + * (i - base)/n where n is the size of the top-level array. + * + */ + +/* make_node --- initialize a NODE */ + +static inline NODE * +make_node(NODETYPE type) +{ + NODE *n; + getnode(n); + memset(n, '\0', sizeof(NODE)); + n->type = type; + return n; +} + + +/* tree_lookup --- Find an integer subscript in a HAT; Install it if it isn't there */ + +static NODE ** +tree_lookup(NODE *symbol, NODE *tree, long k, int m, long base) +{ + NODE **lhs; + NODE *tn; + int i, n; + size_t size; + long num = k; + + /* + * HAT size (size of Top & Leaf array) = 2^n + * where n = Floor ((m + 1)/2). For an odd value of m, + * only the first half of the HAT is needed. + */ + + n = (m + 1) / 2; + + if (tree->table_size == 0) { + size_t actual_size; + NODE **table; + + assert(tree->nodes == NULL); + + /* initialize top-level array */ + size = actual_size = power_two_table[n]; + tree->array_base = base; + tree->array_size = size; + tree->table_size = 0; /* # of elements in the array */ + if (n > m/2) { + /* only first half of the array used */ + actual_size /= 2; + tree->flags |= HALFHAT; + } + ezalloc(table, NODE **, actual_size * sizeof(NODE *), "tree_lookup"); + tree->nodes = table; + } else + size = tree->array_size; + + num -= tree->array_base; + i = num / size; /* top-level array index */ + assert(i >= 0); + + if ((lhs = tree_find(tree, k, i)) != NULL) + return lhs; + + /* It's not there, install it */ + + tree->table_size++; + base += (size * i); + tn = tree->nodes[i]; + if (n > NHAT) { + if (tn == NULL) + tn = tree->nodes[i] = make_node(Node_array_tree); + return tree_lookup(symbol, tn, k, n, base); + } else { + if (tn == NULL) + tn = tree->nodes[i] = make_node(Node_array_leaf); + return leaf_lookup(symbol, tn, k, size, base); + } +} + + +/* tree_exists --- test whether integer subscript `k' exists or not */ + +static NODE ** +tree_exists(NODE *tree, long k) +{ + int i; + NODE *tn; + + i = (k - tree->array_base) / tree->array_size; + assert(i >= 0); + tn = tree->nodes[i]; + if (tn == NULL) + return NULL; + if (tn->type == Node_array_tree) + return tree_exists(tn, k); + return leaf_exists(tn, k); +} + +/* tree_clear --- flush all the values */ + +static void +tree_clear(NODE *tree) +{ + NODE *tn; + size_t j, hsize; + + hsize = tree->array_size; + if ((tree->flags & HALFHAT) != 0) + hsize /= 2; + + for (j = 0; j < hsize; j++) { + tn = tree->nodes[j]; + if (tn == NULL) + continue; + if (tn->type == Node_array_tree) + tree_clear(tn); + else + leaf_clear(tn); + freenode(tn); + } + + efree(tree->nodes); + memset(tree, '\0', sizeof(NODE)); + tree->type = Node_array_tree; +} + + +/* tree_remove --- If the integer subscript is in the HAT, remove it */ + +static int +tree_remove(NODE *symbol, NODE *tree, long k) +{ + int i; + NODE *tn; + + i = (k - tree->array_base) / tree->array_size; + assert(i >= 0); + tn = tree->nodes[i]; + if (tn == NULL) + return false; + + if (tn->type == Node_array_tree + && ! tree_remove(symbol, tn, k)) + return false; + else if (tn->type == Node_array_leaf + && ! leaf_remove(symbol, tn, k)) + return false; + + if (tn->table_size == 0) { + freenode(tn); + tree->nodes[i] = NULL; + } + + /* one less item in array */ + if (--tree->table_size == 0) { + efree(tree->nodes); + memset(tree, '\0', sizeof(NODE)); + tree->type = Node_array_tree; + } + return true; +} + + +/* tree_find --- locate an interger subscript in the HAT */ + +static inline NODE ** +tree_find(NODE *tree, long k, int i) +{ + NODE *tn; + + assert(tree->nodes != NULL); + tn = tree->nodes[i]; + if (tn != NULL) { + if (tn->type == Node_array_tree) + return tree_exists(tn, k); + return leaf_exists(tn, k); + } + return NULL; +} + + +/* tree_list --- return a list of items in the HAT */ + +static long +tree_list(NODE *tree, NODE **list, assoc_kind_t assoc_kind) +{ + NODE *tn; + size_t j, cj, hsize; + long k = 0; + + assert(list != NULL); + + hsize = tree->array_size; + if ((tree->flags & HALFHAT) != 0) + hsize /= 2; + + for (j = 0; j < hsize; j++) { + cj = (assoc_kind & ADESC) != 0 ? (hsize - 1 - j) : j; + tn = tree->nodes[cj]; + if (tn == NULL) + continue; + if (tn->type == Node_array_tree) + k += tree_list(tn, list + k, assoc_kind); + else + k += leaf_list(tn, list + k, assoc_kind); + if ((assoc_kind & ADELETE) != 0 && k >= 1) + return k; + } + return k; +} + + +/* tree_copy --- duplicate a HAT */ + +static void +tree_copy(NODE *newsymb, NODE *tree, NODE *newtree) +{ + NODE **old, **new; + size_t j, hsize; + + hsize = tree->array_size; + if ((tree->flags & HALFHAT) != 0) + hsize /= 2; + + ezalloc(new, NODE **, hsize * sizeof(NODE *), "tree_copy"); + newtree->nodes = new; + newtree->array_base = tree->array_base; + newtree->array_size = tree->array_size; + newtree->table_size = tree->table_size; + newtree->flags = tree->flags; + + old = tree->nodes; + for (j = 0; j < hsize; j++) { + if (old[j] == NULL) + continue; + if (old[j]->type == Node_array_tree) { + new[j] = make_node(Node_array_tree); + tree_copy(newsymb, old[j], new[j]); + } else { + new[j] = make_node(Node_array_leaf); + leaf_copy(newsymb, old[j], new[j]); + } + } +} + + +/* tree_info --- print index, value info */ + +static void +tree_info(NODE *tree, NODE *ndump, const char *aname) +{ + NODE *tn; + size_t j, hsize; + + hsize = tree->array_size; + if ((tree->flags & HALFHAT) != 0) + hsize /= 2; + + for (j = 0; j < hsize; j++) { + tn = tree->nodes[j]; + if (tn == NULL) + continue; + if (tn->type == Node_array_tree) + tree_info(tn, ndump, aname); + else + leaf_info(tn, ndump, aname); + } +} + + +/* tree_kilobytes --- calculate memory consumption of a HAT */ + +static size_t +tree_kilobytes(NODE *tree) +{ + NODE *tn; + size_t j, hsize; + size_t sz = 0; + + hsize = tree->array_size; + if ((tree->flags & HALFHAT) != 0) + hsize /= 2; + for (j = 0; j < hsize; j++) { + tn = tree->nodes[j]; + if (tn == NULL) + continue; + sz += sizeof(NODE); /* Node_array_tree or Node_array_leaf */ + if (tn->type == Node_array_tree) + sz += tree_kilobytes(tn); + } + sz += hsize * sizeof(NODE *); /* tree->nodes */ + return sz; +} + +#ifdef ARRAYDEBUG + +/* tree_print --- print the HAT structures */ + +static void +tree_print(NODE *tree, size_t bi, int indent_level) +{ + NODE *tn; + size_t j, hsize; + + indent(indent_level); + + hsize = tree->array_size; + if ((tree->flags & HALFHAT) != 0) + hsize /= 2; + fprintf(output_fp, "%4lu:%s[%4lu:%-4lu]\n", + (unsigned long) bi, + (tree->flags & HALFHAT) != 0 ? "HH" : "H", + (unsigned long) hsize, (unsigned long) tree->table_size); + + for (j = 0; j < hsize; j++) { + tn = tree->nodes[j]; + if (tn == NULL) + continue; + if (tn->type == Node_array_tree) + tree_print(tn, j, indent_level + 1); + else + leaf_print(tn, j, indent_level + 1); + } +} +#endif + +/*--------------------- leaf (linear 1-D) array --------------------*/ + +/* + * leaf_lookup --- find an integer subscript in the array; Install it if + * it isn't there. + */ + +static inline NODE ** +leaf_lookup(NODE *symbol, NODE *array, long k, long size, long base) +{ + NODE **lhs; + + if (array->nodes == NULL) { + array->table_size = 0; /* sanity */ + array->array_size = size; + array->array_base = base; + ezalloc(array->nodes, NODE **, size * sizeof(NODE *), "leaf_lookup"); + symbol->array_capacity += size; + } + + lhs = array->nodes + (k - base); /* leaf element */ + if (*lhs == NULL) { + array->table_size++; /* one more element in leaf array */ + *lhs = dupnode(Nnull_string); + } + return lhs; +} + + +/* 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); + return (*lhs != NULL) ? lhs : NULL; +} + + +/* leaf_clear --- flush all values in the array */ + +static void +leaf_clear(NODE *array) +{ + long i, size = array->array_size; + NODE *r; + + for (i = 0; i < size; i++) { + r = array->nodes[i]; + if (r == NULL) + continue; + if (r->type == Node_var_array) { + assoc_clear(r); /* recursively clear all sub-arrays */ + efree(r->vname); + freenode(r); + } else + unref(r); + } + efree(array->nodes); + array->nodes = NULL; + array->array_size = array->table_size = 0; +} + + +/* leaf_remove --- remove an integer subscript from the array */ + +static int +leaf_remove(NODE *symbol, NODE *array, long k) +{ + NODE **lhs; + + lhs = array->nodes + (k - array->array_base); + if (*lhs == NULL) + return false; + *lhs = NULL; + if (--array->table_size == 0) { + efree(array->nodes); + array->nodes = NULL; + symbol->array_capacity -= array->array_size; + array->array_size = 0; /* sanity */ + } + return true; +} + + +/* leaf_copy --- duplicate a leaf array */ + +static void +leaf_copy(NODE *newsymb, NODE *array, NODE *newarray) +{ + NODE **old, **new; + long size, i; + + size = array->array_size; + ezalloc(new, NODE **, size * sizeof(NODE *), "leaf_copy"); + newarray->nodes = new; + newarray->array_size = size; + newarray->array_base = array->array_base; + newarray->flags = array->flags; + newarray->table_size = array->table_size; + + old = array->nodes; + for (i = 0; i < size; i++) { + if (old[i] == NULL) + continue; + if (old[i]->type == Node_val) + new[i] = dupnode(old[i]); + else { + NODE *r; + r = make_array(); + r->vname = estrdup(old[i]->vname, strlen(old[i]->vname)); + r->parent_array = newsymb; + new[i] = assoc_copy(old[i], r); + } + } +} + + +/* leaf_list --- return a list of items */ + +static long +leaf_list(NODE *array, NODE **list, assoc_kind_t assoc_kind) +{ + NODE *r, *subs; + long num, i, ci, k = 0; + long size = array->array_size; + static char buf[100]; + + for (i = 0; i < size; i++) { + ci = (assoc_kind & ADESC) != 0 ? (size - 1 - i) : i; + r = array->nodes[ci]; + if (r == NULL) + continue; + + /* index */ + num = array->array_base + ci; + if ((assoc_kind & AISTR) != 0) { + sprintf(buf, "%ld", num); + subs = make_string(buf, strlen(buf)); + subs->numbr = num; + subs->flags |= (NUMCUR|NUMINT); + } else { + subs = make_number((AWKNUM) num); + subs->flags |= (INTIND|NUMINT); + } + list[k++] = subs; + + /* value */ + if ((assoc_kind & AVALUE) != 0) { + if (r->type == Node_val) { + if ((assoc_kind & AVNUM) != 0) + (void) force_number(r); + else if ((assoc_kind & AVSTR) != 0) + r = force_string(r); + } + list[k++] = r; + } + if ((assoc_kind & ADELETE) != 0 && k >= 1) + return k; + } + + return k; +} + + +/* leaf_info --- print index, value info */ + +static void +leaf_info(NODE *array, NODE *ndump, const char *aname) +{ + NODE *subs, *val; + size_t i, size; + + size = array->array_size; + + subs = make_number((AWKNUM) 0.0); + subs->flags |= (INTIND|NUMINT); + for (i = 0; i < size; i++) { + val = array->nodes[i]; + if (val == NULL) + continue; + subs->numbr = array->array_base + i; + assoc_info(subs, val, ndump, aname); + } + unref(subs); +} + +#ifdef ARRAYDEBUG + +/* leaf_print --- print the leaf-array structure */ + + +static void +leaf_print(NODE *array, size_t bi, int indent_level) +{ + indent(indent_level); + fprintf(output_fp, "%4lu:L[%4lu:%-4lu]\n", + (unsigned long) bi, + (unsigned long) array->array_size, + (unsigned long) array->table_size); +} +#endif diff --git a/cmd.h b/cmd.h new file mode 100644 index 0000000..375ea08 --- /dev/null +++ b/cmd.h @@ -0,0 +1,215 @@ +/* + * cmd.h - definitions for command parser + */ + +/* + * Copyright (C) 2004, 2010, 2011, 2013, 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_LIBREADLINE +#include +#include +extern char **command_completion(const char *text, int start, int end); +extern void initialize_pager(FILE *fp); /* debug.c */ +extern NODE *get_function(void); +#else +#define initialize_pager(x) /* nothing */ +#define add_history(x) /* nothing */ +#endif + +extern int gprintf(FILE *fp, const char *format, ...); +extern jmp_buf pager_quit_tag; +extern int pager_quit_tag_valid; + +extern bool output_is_tty; +extern int input_fd; +extern bool input_from_tty; +extern FILE *out_fp; +extern char *dbg_prompt; +extern char *commands_prompt; +extern char *eval_prompt; +extern char *dgawk_prompt; + +enum argtype { + D_illegal, + + /* commands */ + D_backtrace, + D_break, + D_clear, + D_commands, + D_condition, + D_continue, + D_delete, + D_disable, + D_display, + D_down, + D_dump, + D_enable, + D_end, + D_eval, + D_finish, + D_frame, + D_help, + D_ignore, + D_info, + D_list, + D_next, + D_nexti, + D_option, + D_print, + D_printf, + D_quit, + D_return, + D_run, + D_save, + D_set, + D_silent, + D_source, + D_step, + D_stepi, + D_tbreak, + D_trace, + D_undisplay, + D_until, + D_unwatch, + D_up, + D_watch, + + /* arguments */ + D_argument, + D_int, + D_string, + D_variable, + D_node, + D_field, + D_array, + D_subscript, + D_func, + D_range +}; + +/* non-number arguments to commands */ + +enum nametypeval { + A_NONE = 0, + A_ARGS, + A_BREAK, + A_DEL, + A_DISPLAY, + A_FRAME, + A_FUNCTIONS, + A_LOCALS, + A_ONCE, + A_SOURCE, + A_SOURCES, + A_TRACE_ON, + A_TRACE_OFF, + A_VARIABLES, + A_WATCH +}; + +typedef struct cmd_argument { + struct cmd_argument *next; + enum argtype type; + union { + long lval; + char *sval; + NODE *nodeval; + } value; + +#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 */ + + int a_count; /* subscript count for D_subscript and D_array */ +} CMDARG; + +typedef int (*Func_cmd)(CMDARG *, int); + +struct cmdtoken { + const char *name; + char *abbrvn; /* abbreviation */ + enum argtype type; + int class; + Func_cmd cf_ptr; + const char *help_txt; +}; + +/* command.c */ +extern void free_cmdarg(CMDARG *list); +extern Func_cmd get_command(int ctype); +extern const char *get_command_name(int ctype); + +/* debug.c */ +extern void d_error(const char *mesg, ...); + +/* command.c */ +extern int find_option(char *name); +extern void option_help(void); +extern char *(*read_a_line)(const char *prompt); +extern char *read_commands_string(const char *prompt); +extern int in_cmd_src(const char *); +extern int get_eof_status(void); +extern void push_cmd_src(int fd, bool istty, char * (*readfunc)(const char *), + int (*closefunc)(int), int cmd, int eofstatus); +extern int pop_cmd_src(void); +extern int has_break_or_watch_point(int *pnum, bool any); +extern int do_list(CMDARG *arg, int cmd); +extern int do_info(CMDARG *arg, int cmd); +extern int do_print_var(CMDARG *arg, int cmd); +extern int do_backtrace(CMDARG *arg, int cmd); +extern int do_breakpoint(CMDARG *arg, int cmd); +extern int do_tmp_breakpoint(CMDARG *arg, int cmd); +extern int do_delete_breakpoint(CMDARG *arg, int cmd); +extern int do_enable_breakpoint(CMDARG *arg, int cmd); +extern int do_disable_breakpoint(CMDARG *arg, int cmd) ; +extern int do_ignore_breakpoint(CMDARG *arg, int cmd) ; +extern int do_run(CMDARG *arg, int cmd); +extern int do_quit(CMDARG *arg, int cmd); +extern int do_continue(CMDARG *arg, int cmd); +extern int do_step(CMDARG *arg, int cmd) ; +extern int do_stepi(CMDARG *arg, int cmd) ; +extern int do_next(CMDARG *arg, int cmd); +extern int do_nexti(CMDARG *arg, int cmd); +extern int do_clear(CMDARG *arg, int cmd); +extern int do_finish(CMDARG *arg, int cmd) ; +extern int do_help(CMDARG *arg, int cmd) ; +extern int do_up(CMDARG *arg, int cmd); +extern int do_down(CMDARG *arg, int cmd); +extern int do_frame(CMDARG *arg, int cmd); +extern int do_until(CMDARG *arg, int cmd); +extern int do_set_var(CMDARG *arg, int cmd); +extern int do_return(CMDARG *arg, int cmd); +extern int do_display(CMDARG *arg, int cmd); +extern int do_undisplay(CMDARG *arg, int cmd); +extern int do_watch(CMDARG *arg, int cmd); +extern int do_unwatch(CMDARG *arg, int cmd); +extern int do_dump_instructions(CMDARG *arg, int cmd); +extern int do_trace_instruction(CMDARG *arg, int cmd); +extern int do_option(CMDARG *arg, int cmd); +extern int do_commands(CMDARG *arg, int cmd); +extern int do_print_f(CMDARG *arg, int cmd); +extern int do_source(CMDARG *arg, int cmd); +extern int do_save(CMDARG *arg, int cmd); +extern int do_eval(CMDARG *arg, int cmd); +extern int do_condition(CMDARG *arg, int cmd); diff --git a/command.c b/command.c new file mode 100644 index 0000000..0876f02 --- /dev/null +++ b/command.c @@ -0,0 +1,3483 @@ +/* A Bison parser, made by GNU Bison 3.0.4. */ + +/* Bison implementation for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015 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 . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "3.0.4" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 0 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + + +/* Substitute the variable and function names. */ +#define yyparse zzparse +#define yylex zzlex +#define yyerror zzerror +#define yydebug zzdebug +#define yynerrs zznerrs + +#define yylval zzlval +#define yychar zzchar + +/* Copy the first part of user declarations. */ +#line 28 "command.y" /* yacc.c:339 */ + +#include "awk.h" +#include "cmd.h" + +#if 0 +#define YYDEBUG 12 +int yydebug = 2; +#endif + +static int yylex(void); +static void yyerror(const char *mesg, ...); + +static int find_command(const char *token, size_t toklen); + +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 long errcount = 0; +static char *lexptr_begin = NULL; +static bool in_commands = false; +static int num_dim; + +static bool in_eval = false; +static const char start_EVAL[] = "function @eval(){"; +static const char end_EVAL[] = "}"; +static CMDARG *append_statement(CMDARG *stmt_list, char *stmt); +static NODE *concat_args(CMDARG *a, int count); + +#ifdef HAVE_LIBREADLINE +static char *next_word(char *p, int len, char **endp); +static void history_expand_line(char **line); +static char *command_generator(const char *text, int state); +static char *srcfile_generator(const char *text, int state); +static char *argument_generator(const char *text, int state); +static char *variable_generator(const char *text, int state); +extern char *option_generator(const char *text, int state); +static int this_cmd = D_illegal; +#else +#define history_expand_line(p) /* nothing */ +static int rl_inhibit_completion; /* dummy variable */ +#endif + +struct argtoken { + const char *name; + enum argtype cmd; + enum nametypeval value; +}; + +/* + * These two should be static, but there are some compilers that + * don't like the static keyword with an empty size. Therefore give + * them names that are less likely to conflict with the rest of gawk. + */ +#define argtab zz_debug_argtab +#define cmdtab zz_debug_cmdtab + +extern struct argtoken argtab[]; +extern struct cmdtoken cmdtab[]; + +static CMDARG *mk_cmdarg(enum argtype type); +static void append_cmdarg(CMDARG *arg); +static int find_argument(CMDARG *arg); +#define YYSTYPE CMDARG * + +#line 141 "command.c" /* yacc.c:339 */ + +# ifndef YY_NULLPTR +# if defined __cplusplus && 201103L <= __cplusplus +# define YY_NULLPTR nullptr +# else +# define YY_NULLPTR 0 +# endif +# endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + + +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int zzdebug; +#endif + +/* Token type. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + enum yytokentype + { + D_BACKTRACE = 258, + D_BREAK = 259, + D_CLEAR = 260, + D_CONTINUE = 261, + D_DELETE = 262, + D_DISABLE = 263, + D_DOWN = 264, + D_ENABLE = 265, + D_FINISH = 266, + D_FRAME = 267, + D_HELP = 268, + D_IGNORE = 269, + D_INFO = 270, + D_LIST = 271, + D_NEXT = 272, + D_NEXTI = 273, + D_PRINT = 274, + D_PRINTF = 275, + D_QUIT = 276, + D_RETURN = 277, + D_RUN = 278, + D_SET = 279, + D_STEP = 280, + D_STEPI = 281, + D_TBREAK = 282, + D_UP = 283, + D_UNTIL = 284, + D_DISPLAY = 285, + D_UNDISPLAY = 286, + D_WATCH = 287, + D_UNWATCH = 288, + D_DUMP = 289, + D_TRACE = 290, + D_INT = 291, + D_STRING = 292, + D_NODE = 293, + D_VARIABLE = 294, + D_OPTION = 295, + D_COMMANDS = 296, + D_END = 297, + D_SILENT = 298, + D_SOURCE = 299, + D_SAVE = 300, + D_EVAL = 301, + D_CONDITION = 302, + D_STATEMENT = 303 + }; +#endif +/* Tokens. */ +#define D_BACKTRACE 258 +#define D_BREAK 259 +#define D_CLEAR 260 +#define D_CONTINUE 261 +#define D_DELETE 262 +#define D_DISABLE 263 +#define D_DOWN 264 +#define D_ENABLE 265 +#define D_FINISH 266 +#define D_FRAME 267 +#define D_HELP 268 +#define D_IGNORE 269 +#define D_INFO 270 +#define D_LIST 271 +#define D_NEXT 272 +#define D_NEXTI 273 +#define D_PRINT 274 +#define D_PRINTF 275 +#define D_QUIT 276 +#define D_RETURN 277 +#define D_RUN 278 +#define D_SET 279 +#define D_STEP 280 +#define D_STEPI 281 +#define D_TBREAK 282 +#define D_UP 283 +#define D_UNTIL 284 +#define D_DISPLAY 285 +#define D_UNDISPLAY 286 +#define D_WATCH 287 +#define D_UNWATCH 288 +#define D_DUMP 289 +#define D_TRACE 290 +#define D_INT 291 +#define D_STRING 292 +#define D_NODE 293 +#define D_VARIABLE 294 +#define D_OPTION 295 +#define D_COMMANDS 296 +#define D_END 297 +#define D_SILENT 298 +#define D_SOURCE 299 +#define D_SAVE 300 +#define D_EVAL 301 +#define D_CONDITION 302 +#define D_STATEMENT 303 + +/* Value type. */ +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef int YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define YYSTYPE_IS_DECLARED 1 +#endif + + +extern YYSTYPE zzlval; + +int zzparse (void); + + + +/* Copy the second part of user declarations. */ + +#line 285 "command.c" /* yacc.c:358 */ + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#else +typedef signed char yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_(Msgid) dgettext ("bison-runtime", Msgid) +# endif +# endif +# ifndef YY_ +# define YY_(Msgid) Msgid +# endif +#endif + +#ifndef YY_ATTRIBUTE +# if (defined __GNUC__ \ + && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \ + || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C +# define YY_ATTRIBUTE(Spec) __attribute__(Spec) +# else +# define YY_ATTRIBUTE(Spec) /* empty */ +# endif +#endif + +#ifndef YY_ATTRIBUTE_PURE +# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__)) +#endif + +#ifndef YY_ATTRIBUTE_UNUSED +# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) +#endif + +#if !defined _Noreturn \ + && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112) +# if defined _MSC_VER && 1200 <= _MSC_VER +# define _Noreturn __declspec (noreturn) +# else +# define _Noreturn YY_ATTRIBUTE ((__noreturn__)) +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(E) ((void) (E)) +#else +# define YYUSE(E) /* empty */ +#endif + +#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ +/* Suppress an incorrect diagnostic about yylval being uninitialized. */ +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ + _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ + _Pragma ("GCC diagnostic pop") +#else +# define YY_INITIAL_VALUE(Value) Value +#endif +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_END +#endif +#ifndef YY_INITIAL_VALUE +# define YY_INITIAL_VALUE(Value) /* Nothing. */ +#endif + + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS +# include /* INFRINGES ON USER NAME SPACE */ + /* Use EXIT_SUCCESS as a witness for stdlib.h. */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's 'empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined EXIT_SUCCESS \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined EXIT_SUCCESS +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined EXIT_SUCCESS +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +# define YYCOPY_NEEDED 1 + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (0) + +#endif + +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from SRC to DST. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(Dst, Src, Count) \ + __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) +# else +# define YYCOPY(Dst, Src, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (Dst)[yyi] = (Src)[yyi]; \ + } \ + while (0) +# endif +# endif +#endif /* !YYCOPY_NEEDED */ + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 2 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 203 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 59 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 55 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 156 +/* YYNSTATES -- Number of states. */ +#define YYNSTATES 203 + +/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned + by yylex, with out-of-bounds checking. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 303 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM + as returned by yylex, without out-of-bounds checking. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 58, 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, 57, 2, 2, 2, + 2, 2, 2, 53, 50, 54, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 51, 2, + 2, 49, 2, 2, 52, 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, 55, 2, 56, 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, 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, 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, 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, + 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, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 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 +}; + +#if YYDEBUG + /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 108, 108, 110, 128, 129, 179, 186, 187, 188, + 189, 190, 194, 195, 196, 197, 201, 202, 203, 204, + 208, 209, 214, 218, 238, 245, 245, 252, 268, 282, + 283, 284, 285, 286, 287, 293, 305, 306, 307, 307, + 308, 308, 309, 310, 311, 312, 313, 313, 314, 315, + 315, 316, 316, 317, 317, 318, 319, 320, 325, 330, + 356, 366, 371, 383, 383, 391, 405, 418, 419, 425, + 426, 430, 431, 432, 433, 439, 440, 441, 446, 457, + 458, 463, 471, 488, 489, 490, 491, 492, 497, 498, + 498, 499, 500, 500, 501, 506, 507, 512, 513, 518, + 519, 522, 524, 528, 529, 544, 545, 550, 558, 559, + 560, 561, 565, 566, 570, 571, 572, 577, 578, 580, + 587, 588, 589, 590, 591, 592, 596, 609, 610, 611, + 615, 616, 617, 618, 622, 624, 626, 630, 645, 649, + 651, 656, 657, 666, 676, 678, 685, 698, 699, 705, + 706, 711, 717, 726, 728, 730, 738 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || 0 +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "D_BACKTRACE", "D_BREAK", "D_CLEAR", + "D_CONTINUE", "D_DELETE", "D_DISABLE", "D_DOWN", "D_ENABLE", "D_FINISH", + "D_FRAME", "D_HELP", "D_IGNORE", "D_INFO", "D_LIST", "D_NEXT", "D_NEXTI", + "D_PRINT", "D_PRINTF", "D_QUIT", "D_RETURN", "D_RUN", "D_SET", "D_STEP", + "D_STEPI", "D_TBREAK", "D_UP", "D_UNTIL", "D_DISPLAY", "D_UNDISPLAY", + "D_WATCH", "D_UNWATCH", "D_DUMP", "D_TRACE", "D_INT", "D_STRING", + "D_NODE", "D_VARIABLE", "D_OPTION", "D_COMMANDS", "D_END", "D_SILENT", + "D_SOURCE", "D_SAVE", "D_EVAL", "D_CONDITION", "D_STATEMENT", "'='", + "','", "':'", "'@'", "'+'", "'-'", "'['", "']'", "'$'", "'\\n'", + "$accept", "input", "line", "control_cmd", "d_cmd", "frame_cmd", + "break_cmd", "set_want_nodeval", "eval_prologue", "statement_list", "@1", + "eval_cmd", "command", "$@2", "$@3", "$@4", "$@5", "$@6", "$@7", "$@8", + "condition_exp", "commands_arg", "opt_param_list", "param_list", + "opt_string_node", "string_node", "option_args", "func_name", "location", + "break_args", "$@9", "$@10", "opt_variable", "opt_string", "opt_node", + "help_args", "enable_args", "print_exp", "print_args", "printf_exp", + "printf_args", "list_args", "integer_range", "opt_integer_list", + "integer_list", "exp_list", "subscript", "subscript_list", "variable", + "node", "opt_plus_integer", "opt_integer", "plus_integer", "integer", + "nls", YY_NULLPTR +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[NUM] -- (External) token number corresponding to the + (internal) symbol number NUM (which must be that of a token). */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 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, 61, + 44, 58, 64, 43, 45, 91, 93, 36, 10 +}; +# endif + +#define YYPACT_NINF -151 + +#define yypact_value_is_default(Yystate) \ + (!!((Yystate) == (-151))) + +#define YYTABLE_NINF -148 + +#define yytable_value_is_error(Yytable_value) \ + 0 + + /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +static const yytype_int16 yypact[] = +{ + -151, 145, -151, -34, -151, -151, 50, -151, -151, -151, + -151, 10, -151, -151, -10, 59, -9, 43, -151, -151, + -151, -151, -151, -151, -151, -151, -151, -151, -151, -151, + 50, -151, -151, -151, -151, -8, -6, 14, 12, -151, + -151, 22, 23, -151, 59, -151, -151, 59, 13, 36, + 64, -151, -151, -34, -151, -151, -151, 24, 47, -151, + -151, -151, -151, 13, -151, -151, -151, 59, 48, -151, + -151, 80, -151, 67, 47, -151, -151, -151, -151, 48, + 4, 19, 69, -20, -151, -20, -20, -151, -151, -151, + 70, -151, -151, -151, -151, -151, -151, -151, 16, -151, + -151, -151, -151, 84, 85, -151, -151, 73, -151, -151, + -151, 40, -151, 74, -151, -151, -151, 48, 59, -151, + 74, -151, 71, 89, 91, -151, 42, -151, -151, -151, + -151, 81, -151, -151, 92, 94, -151, -151, 86, -151, + -151, 6, 96, -151, -151, -151, -34, 75, -151, 6, + -151, -151, 74, 6, -151, -151, -151, -151, -151, -151, + -151, -151, 48, 31, -151, 71, 71, -151, 52, -151, + -17, -151, -151, 69, -151, -151, -151, -151, -151, -151, + -151, 95, -151, -151, -151, -151, -34, -151, 17, -151, + -151, 71, -151, -151, -151, -151, 6, -151, -151, 69, + -151, -151, -151 +}; + + /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE does not specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 2, 0, 1, 0, 18, 20, 83, 7, 15, 14, + 17, 0, 32, 19, 101, 0, 0, 117, 8, 9, + 38, 40, 30, 49, 31, 46, 10, 11, 21, 16, + 83, 51, 12, 53, 13, 97, 0, 79, 0, 60, + 61, 0, 0, 22, 0, 156, 3, 147, 0, 149, + 88, 24, 65, 0, 4, 6, 151, 82, 0, 85, + 44, 84, 129, 0, 37, 131, 103, 128, 130, 102, + 29, 0, 35, 82, 118, 119, 121, 42, 122, 120, + 0, 0, 99, 0, 43, 95, 0, 98, 56, 62, + 80, 48, 68, 59, 67, 148, 57, 58, 0, 63, + 33, 55, 153, 0, 0, 34, 150, 82, 91, 45, + 89, 0, 5, 0, 152, 104, 133, 132, 0, 36, + 0, 111, 141, 0, 0, 108, 39, 105, 116, 112, + 114, 41, 113, 144, 0, 0, 50, 100, 0, 52, + 96, 0, 0, 74, 78, 71, 0, 70, 28, 0, + 154, 155, 0, 0, 27, 25, 82, 87, 86, 126, + 124, 125, 123, 0, 139, 143, 106, 142, 0, 109, + 0, 145, 146, 0, 77, 54, 66, 76, 81, 23, + 72, 0, 64, 94, 92, 90, 0, 136, 0, 134, + 140, 107, 110, 115, 47, 73, 0, 26, 138, 0, + 137, 93, 135 +}; + + /* YYPGOTO[NTERM-NUM]. */ +static const yytype_int16 yypgoto[] = +{ + -151, -151, -151, -151, -151, -151, -151, -151, -151, -151, + -151, -151, -151, -151, -151, -151, -151, -151, -151, -151, + -119, -151, -151, -151, -151, 38, -151, -15, 108, -151, + -151, -151, -151, -151, -151, -151, -151, -90, -151, -31, + -151, -151, -14, -25, -151, -151, -150, -26, -77, -147, + 97, -151, -5, -151, -3 +}; + + /* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int16 yydefgoto[] = +{ + -1, 1, 46, 47, 48, 49, 50, 98, 51, 111, + 186, 52, 53, 80, 81, 83, 82, 85, 86, 149, + 175, 93, 146, 147, 176, 177, 91, 59, 60, 109, + 153, 196, 139, 88, 136, 70, 64, 125, 126, 130, + 131, 77, 65, 66, 67, 188, 164, 165, 127, 137, + 94, 105, 68, 106, 54 +}; + + /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule whose + number is the opposite. If YYTABLE_NINF, syntax error. */ +static const yytype_int16 yytable[] = +{ + 55, 61, 76, 78, 132, 121, 138, 174, 140, 141, + 71, 62, 79, 92, 62, 190, 189, 143, 198, 122, + 128, 129, 122, 101, 45, 61, 194, 69, 72, 87, + 182, 89, 187, 95, 185, 108, 169, 124, 115, 99, + 124, 190, 95, 122, 144, 110, 56, 63, 56, 56, + 112, 90, 202, 116, 144, 145, 123, 129, 122, 96, + 97, 124, 117, 58, -75, 58, 58, 199, -127, 133, + -147, -127, 102, 200, -69, 113, 124, 201, 192, 56, + 73, 122, 154, 114, 134, 135, 56, 57, 155, 103, + 104, 122, 168, 132, 123, 56, 74, 75, 157, 124, + 56, 107, 118, 58, 123, 160, 161, 133, 158, 124, + 56, 156, 58, 159, 180, 162, 119, 58, 120, 142, + 150, 151, 134, 135, 152, 181, 163, 58, 166, 167, + 171, 170, 172, 178, 195, 173, 148, 183, 84, 193, + 191, 0, 0, 179, 100, 2, 3, 184, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 0, 0, 197, 0, 37, 38, 39, 40, 41, + 42, 43, 44, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 45 +}; + +static const yytype_int16 yycheck[] = +{ + 3, 6, 17, 17, 81, 1, 83, 1, 85, 86, + 15, 1, 17, 1, 1, 165, 163, 1, 1, 39, + 1, 38, 39, 48, 58, 30, 173, 37, 37, 37, + 149, 37, 1, 38, 153, 50, 126, 57, 63, 44, + 57, 191, 47, 39, 38, 50, 36, 37, 36, 36, + 53, 37, 199, 67, 38, 39, 52, 38, 39, 37, + 37, 57, 67, 53, 58, 53, 53, 50, 58, 38, + 58, 58, 36, 56, 58, 51, 57, 196, 168, 36, + 37, 39, 42, 36, 53, 54, 36, 37, 48, 53, + 54, 39, 50, 170, 52, 36, 53, 54, 113, 57, + 36, 37, 54, 53, 52, 120, 120, 38, 113, 57, + 36, 37, 53, 118, 39, 120, 36, 53, 51, 49, + 36, 36, 53, 54, 51, 50, 55, 53, 39, 38, + 38, 50, 38, 37, 39, 49, 98, 152, 30, 170, + 166, -1, -1, 146, 47, 0, 1, 152, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, -1, -1, 186, -1, 40, 41, 42, 43, 44, + 45, 46, 47, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 58 +}; + + /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 60, 0, 1, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 40, 41, 42, + 43, 44, 45, 46, 47, 58, 61, 62, 63, 64, + 65, 67, 70, 71, 113, 113, 36, 37, 53, 86, + 87, 111, 1, 37, 95, 101, 102, 103, 111, 37, + 94, 111, 37, 37, 53, 54, 86, 100, 101, 111, + 72, 73, 75, 74, 87, 76, 77, 37, 92, 37, + 37, 85, 1, 80, 109, 111, 37, 37, 66, 111, + 109, 102, 36, 53, 54, 110, 112, 37, 86, 88, + 111, 68, 113, 51, 36, 102, 101, 111, 54, 36, + 51, 1, 39, 52, 57, 96, 97, 107, 1, 38, + 98, 99, 107, 38, 53, 54, 93, 108, 107, 91, + 107, 107, 49, 1, 38, 39, 81, 82, 84, 78, + 36, 36, 51, 89, 42, 48, 37, 86, 111, 111, + 86, 101, 111, 55, 105, 106, 39, 38, 50, 96, + 50, 38, 38, 49, 1, 79, 83, 84, 37, 113, + 39, 50, 79, 86, 111, 79, 69, 1, 104, 108, + 105, 106, 96, 98, 108, 39, 90, 113, 1, 50, + 56, 79, 108 +}; + + /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 59, 60, 60, 61, 61, 61, 62, 62, 62, + 62, 62, 63, 63, 63, 63, 64, 64, 64, 64, + 65, 65, 66, 67, 68, 69, 68, 70, 70, 71, + 71, 71, 71, 71, 71, 71, 71, 71, 72, 71, + 73, 71, 71, 71, 71, 71, 74, 71, 71, 75, + 71, 76, 71, 77, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 78, 71, 71, 79, 80, 80, 81, + 81, 82, 82, 82, 82, 83, 83, 83, 84, 85, + 85, 85, 86, 87, 87, 87, 87, 87, 88, 89, + 88, 88, 90, 88, 88, 91, 91, 92, 92, 93, + 93, 94, 94, 95, 95, 96, 96, 96, 97, 97, + 97, 97, 98, 98, 99, 99, 99, 100, 100, 100, + 100, 100, 100, 100, 100, 100, 101, 102, 102, 102, + 103, 103, 103, 103, 104, 104, 104, 105, 105, 106, + 106, 107, 107, 107, 108, 108, 108, 109, 109, 110, + 110, 111, 111, 112, 112, 112, 113 +}; + + /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 0, 2, 1, 2, 2, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 0, 4, 0, 0, 4, 3, 3, 2, + 1, 1, 1, 2, 2, 2, 3, 2, 0, 3, + 0, 3, 2, 2, 2, 2, 0, 5, 2, 0, + 3, 0, 3, 0, 4, 2, 2, 2, 2, 2, + 1, 1, 2, 0, 4, 1, 1, 1, 1, 0, + 1, 1, 2, 3, 1, 0, 1, 1, 1, 0, + 1, 3, 1, 0, 1, 1, 3, 3, 0, 0, + 3, 1, 0, 5, 3, 0, 1, 0, 1, 0, + 1, 0, 1, 1, 2, 1, 2, 3, 1, 2, + 3, 1, 1, 1, 1, 3, 1, 0, 1, 1, + 1, 1, 1, 3, 3, 3, 3, 0, 1, 1, + 1, 1, 2, 2, 1, 3, 1, 3, 3, 1, + 2, 1, 2, 2, 1, 2, 2, 0, 1, 0, + 1, 1, 2, 1, 2, 2, 1 +}; + + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (yylen); \ + yystate = *yyssp; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (0) + +/* Error token number */ +#define YYTERROR 1 +#define YYERRCODE 256 + + + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) + +/* This macro is provided for backward compatibility. */ +#ifndef YY_LOCATION_PRINT +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +#endif + + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (0) + + +/*----------------------------------------. +| Print this symbol's value on YYOUTPUT. | +`----------------------------------------*/ + +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +{ + FILE *yyo = yyoutput; + YYUSE (yyo); + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# endif + YYUSE (yytype); +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +{ + YYFPRINTF (yyoutput, "%s %s (", + yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (0) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +static void +yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule) +{ + unsigned long int yylno = yyrline[yyrule]; + int yynrhs = yyr2[yyrule]; + int yyi; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, + yystos[yyssp[yyi + 1 - yynrhs]], + &(yyvsp[(yyi + 1) - (yynrhs)]) + ); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyssp, yyvsp, Rule); \ +} while (0) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +static YYSIZE_T +yystrlen (const char *yystr) +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +yystpcpy (char *yydest, const char *yysrc) +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message + about the unexpected token YYTOKEN for the state stack whose top is + YYSSP. + + Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is + not large enough to hold the message. In that case, also set + *YYMSG_ALLOC to the required number of bytes. Return 2 if the + required number of bytes is too large to store. */ +static int +yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, + yytype_int16 *yyssp, int yytoken) +{ + YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); + YYSIZE_T yysize = yysize0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + /* Internationalized format string. */ + const char *yyformat = YY_NULLPTR; + /* Arguments of yyformat. */ + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + /* Number of reported tokens (one for the "unexpected", one per + "expected"). */ + int yycount = 0; + + /* There are many possibilities here to consider: + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yychar) is if + this state is a consistent state with a default action. Thus, + detecting the absence of a lookahead is sufficient to determine + that there is no unexpected or expected token to report. In that + case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is a + consistent state with a default action. There might have been a + previous inconsistent state, consistent state with a non-default + action, or user semantic action that manipulated yychar. + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state merging + (from LALR or IELR) and default reductions corrupt the expected + token list. However, the list is correct for canonical LR with + one exception: it will still contain any token that will not be + accepted due to an error action in a later state. + */ + if (yytoken != YYEMPTY) + { + int yyn = yypact[*yyssp]; + yyarg[yycount++] = yytname[yytoken]; + if (!yypact_value_is_default (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yyx; + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR + && !yytable_value_is_error (yytable[yyx + yyn])) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + break; + } + yyarg[yycount++] = yytname[yyx]; + { + YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); + if (! (yysize <= yysize1 + && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + } + } + } + + switch (yycount) + { +# define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + YYCASE_(0, YY_("syntax error")); + YYCASE_(1, YY_("syntax error, unexpected %s")); + YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +# undef YYCASE_ + } + + { + YYSIZE_T yysize1 = yysize + yystrlen (yyformat); + if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + + if (*yymsg_alloc < yysize) + { + *yymsg_alloc = 2 * yysize; + if (! (yysize <= *yymsg_alloc + && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) + *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; + return 1; + } + + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + { + char *yyp = *yymsg; + int yyi = 0; + while ((*yyp = *yyformat) != '\0') + if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyformat += 2; + } + else + { + yyp++; + yyformat++; + } + } + return 0; +} +#endif /* YYERROR_VERBOSE */ + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) +{ + YYUSE (yyvaluep); + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + YYUSE (yytype); + YY_IGNORE_MAYBE_UNINITIALIZED_END +} + + + + +/* The lookahead symbol. */ +int yychar; + +/* The semantic value of the lookahead symbol. */ +YYSTYPE yylval; +/* Number of syntax errors so far. */ +int yynerrs; + + +/*----------. +| yyparse. | +`----------*/ + +int +yyparse (void) +{ + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + 'yyss': related to states. + 'yyvs': related to semantic values. + + Refer to the stacks through separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken = 0; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yyssp = yyss = yyssa; + yyvsp = yyvs = yyvsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yypact_value_is_default (yyn)) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = yylex (); + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yytable_value_is_error (yyn)) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + '$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 3: +#line 111 "command.y" /* yacc.c:1646 */ + { + cmd_idx = -1; + want_nodeval = false; + if (lexptr_begin != NULL) { + if (input_from_tty && lexptr_begin[0] != '\0') + add_history(lexptr_begin); + efree(lexptr_begin); + lexptr_begin = NULL; + } + if (arg_list != NULL) { + free_cmdarg(arg_list); + arg_list = NULL; + } + } +#line 1546 "command.c" /* yacc.c:1646 */ + break; + + case 5: +#line 130 "command.y" /* yacc.c:1646 */ + { + if (errcount == 0 && cmd_idx >= 0) { + Func_cmd cmdfunc; + bool terminate = false; + CMDARG *args; + int ctype = 0; + + ctype = cmdtab[cmd_idx].type; + + /* a blank line repeats previous command + * (list, next, nexti, step, stepi and continue without arguments). + * save the index in the command table; used in yylex + */ + if ((ctype == D_list + || ctype == D_next + || ctype == D_step + || ctype == D_nexti + || ctype == D_stepi + || ctype == D_continue) + && arg_list == NULL + && ! in_commands + && input_from_tty + ) + repeat_idx = cmd_idx; + else + repeat_idx = -1; + + /* call the command handler; reset the globals arg_list, cmd_idx, + * since this handler could invoke yyparse again. + * call do_commands for the list of commands in `commands'; + * arg_list isn't freed on return. + */ + + cmdfunc = cmdtab[cmd_idx].cf_ptr; + if (in_commands) + cmdfunc = do_commands; + cmd_idx = -1; + want_nodeval = false; + + args = arg_list; + arg_list = NULL; + + terminate = (*cmdfunc)(args, ctype); + if (! in_commands || ctype == D_commands) + free_cmdarg(args); + if (terminate) + YYACCEPT; + } + } +#line 1600 "command.c" /* yacc.c:1646 */ + break; + + case 6: +#line 180 "command.y" /* yacc.c:1646 */ + { + yyerrok; + } +#line 1608 "command.c" /* yacc.c:1646 */ + break; + + case 22: +#line 214 "command.y" /* yacc.c:1646 */ + { want_nodeval = true; } +#line 1614 "command.c" /* yacc.c:1646 */ + break; + + case 23: +#line 219 "command.y" /* yacc.c:1646 */ + { + if (errcount == 0) { + /* don't free arg_list; passed on to statement_list + * non-terminal (empty rule action). See below. + */ + if (input_from_tty) { + dbg_prompt = eval_prompt; + fprintf(out_fp, + _("Type (g)awk statement(s). End with the command \"end\"\n")); + rl_inhibit_completion = 1; + } + cmd_idx = -1; + in_eval = true; + } + } +#line 1634 "command.c" /* yacc.c:1646 */ + break; + + case 24: +#line 238 "command.y" /* yacc.c:1646 */ + { + (yyval) = append_statement(arg_list, (char *) start_EVAL); + if (read_a_line == read_commands_string) /* unserializing 'eval' in 'commands' */ + (yyval)->a_string[0] = '\0'; + free_cmdarg(arg_list); + arg_list = NULL; + } +#line 1646 "command.c" /* yacc.c:1646 */ + break; + + case 25: +#line 245 "command.y" /* yacc.c:1646 */ + { (yyval) = append_statement((yyvsp[-1]), lexptr_begin); } +#line 1652 "command.c" /* yacc.c:1646 */ + break; + + case 26: +#line 246 "command.y" /* yacc.c:1646 */ + { + (yyval) = (yyvsp[-1]); + } +#line 1660 "command.c" /* yacc.c:1646 */ + break; + + case 27: +#line 253 "command.y" /* yacc.c:1646 */ + { + arg_list = append_statement((yyvsp[-1]), (char *) end_EVAL); + if (read_a_line == read_commands_string) { /* unserializing 'eval' in 'commands' */ + char *str = arg_list->a_string; + size_t len = strlen(str); + assert(len > 2 && str[len - 2] == '}'); + str[len - 2] = '\0'; + } + if (input_from_tty) { + dbg_prompt = in_commands ? commands_prompt : dgawk_prompt; + rl_inhibit_completion = 0; + } + cmd_idx = find_command("eval", 4); + in_eval = false; + } +#line 1680 "command.c" /* yacc.c:1646 */ + break; + + case 28: +#line 269 "command.y" /* yacc.c:1646 */ + { + NODE *n; + CMDARG *arg; + n = (yyvsp[0])->a_node; + arg = append_statement(NULL, (char *) start_EVAL); + (void) append_statement(arg, n->stptr); + (void) append_statement(arg, (char *) end_EVAL); + free_cmdarg(arg_list); + arg_list = arg; + } +#line 1695 "command.c" /* yacc.c:1646 */ + break; + + case 34: +#line 288 "command.y" /* yacc.c:1646 */ + { + if (cmdtab[cmd_idx].class == D_FRAME + && (yyvsp[0]) != NULL && (yyvsp[0])->a_int < 0) + yyerror(_("invalid frame number: %d"), (yyvsp[0])->a_int); + } +#line 1705 "command.c" /* yacc.c:1646 */ + break; + + case 35: +#line 294 "command.y" /* yacc.c:1646 */ + { + int idx = find_argument((yyvsp[0])); + if (idx < 0) + yyerror(_("info: invalid option - \"%s\""), (yyvsp[0])->a_string); + else { + efree((yyvsp[0])->a_string); + (yyvsp[0])->a_string = NULL; + (yyvsp[0])->type = D_argument; + (yyvsp[0])->a_argument = argtab[idx].value; + } + } +#line 1721 "command.c" /* yacc.c:1646 */ + break; + + case 38: +#line 307 "command.y" /* yacc.c:1646 */ + { want_nodeval = true; } +#line 1727 "command.c" /* yacc.c:1646 */ + break; + + case 40: +#line 308 "command.y" /* yacc.c:1646 */ + { want_nodeval = true; } +#line 1733 "command.c" /* yacc.c:1646 */ + break; + + case 46: +#line 313 "command.y" /* yacc.c:1646 */ + { want_nodeval = true; } +#line 1739 "command.c" /* yacc.c:1646 */ + break; + + case 49: +#line 315 "command.y" /* yacc.c:1646 */ + { want_nodeval = true; } +#line 1745 "command.c" /* yacc.c:1646 */ + break; + + case 51: +#line 316 "command.y" /* yacc.c:1646 */ + { want_nodeval = true; } +#line 1751 "command.c" /* yacc.c:1646 */ + break; + + case 53: +#line 317 "command.y" /* yacc.c:1646 */ + { want_nodeval = true; } +#line 1757 "command.c" /* yacc.c:1646 */ + break; + + case 57: +#line 321 "command.y" /* yacc.c:1646 */ + { + if (in_cmd_src((yyvsp[0])->a_string)) + yyerror(_("source \"%s\": already sourced."), (yyvsp[0])->a_string); + } +#line 1766 "command.c" /* yacc.c:1646 */ + break; + + case 58: +#line 326 "command.y" /* yacc.c:1646 */ + { + if (! input_from_tty) + yyerror(_("save \"%s\": command not permitted."), (yyvsp[0])->a_string); + } +#line 1775 "command.c" /* yacc.c:1646 */ + break; + + case 59: +#line 331 "command.y" /* yacc.c:1646 */ + { + int type = 0; + int num; + + if ((yyvsp[0]) != NULL) + num = (yyvsp[0])->a_int; + + if (errcount != 0) + ; + else if (in_commands) + yyerror(_("Can't use command `commands' for breakpoint/watchpoint commands")); + else if ((yyvsp[0]) == NULL && ! (type = has_break_or_watch_point(&num, true))) + yyerror(_("no breakpoint/watchpoint has been set yet")); + else if ((yyvsp[0]) != NULL && ! (type = has_break_or_watch_point(&num, false))) + yyerror(_("invalid breakpoint/watchpoint number")); + if (type) { + in_commands = true; + if (input_from_tty) { + 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")); + } + } + } +#line 1805 "command.c" /* yacc.c:1646 */ + break; + + case 60: +#line 357 "command.y" /* yacc.c:1646 */ + { + if (! in_commands) + yyerror(_("`end' valid only in command `commands' or `eval'")); + else { + if (input_from_tty) + dbg_prompt = dgawk_prompt; + in_commands = false; + } + } +#line 1819 "command.c" /* yacc.c:1646 */ + break; + + case 61: +#line 367 "command.y" /* yacc.c:1646 */ + { + if (! in_commands) + yyerror(_("`silent' valid only in command `commands'")); + } +#line 1828 "command.c" /* yacc.c:1646 */ + break; + + case 62: +#line 372 "command.y" /* yacc.c:1646 */ + { + int idx = find_argument((yyvsp[0])); + if (idx < 0) + yyerror(_("trace: invalid option - \"%s\""), (yyvsp[0])->a_string); + else { + efree((yyvsp[0])->a_string); + (yyvsp[0])->a_string = NULL; + (yyvsp[0])->type = D_argument; + (yyvsp[0])->a_argument = argtab[idx].value; + } + } +#line 1844 "command.c" /* yacc.c:1646 */ + break; + + case 63: +#line 383 "command.y" /* yacc.c:1646 */ + { want_nodeval = true; } +#line 1850 "command.c" /* yacc.c:1646 */ + break; + + case 64: +#line 384 "command.y" /* yacc.c:1646 */ + { + int type; + int num = (yyvsp[-2])->a_int; + type = has_break_or_watch_point(&num, false); + if (! type) + yyerror(_("condition: invalid breakpoint/watchpoint number")); + } +#line 1862 "command.c" /* yacc.c:1646 */ + break; + + case 65: +#line 392 "command.y" /* yacc.c:1646 */ + { + if (in_commands) { + /* Prepend command 'eval' to argument list */ + CMDARG *arg; + arg = mk_cmdarg(D_string); + arg->a_string = estrdup("eval", 4); + arg->next = arg_list; + arg_list = arg; + } + } +#line 1877 "command.c" /* yacc.c:1646 */ + break; + + case 66: +#line 406 "command.y" /* yacc.c:1646 */ + { + if ((yyvsp[0]) != NULL) { + NODE *n = (yyvsp[0])->a_node; + (yyvsp[0])->type = D_string; + (yyvsp[0])->a_string = n->stptr; + freenode(n); + } + (yyval) = (yyvsp[0]); + } +#line 1891 "command.c" /* yacc.c:1646 */ + break; + + case 68: +#line 420 "command.y" /* yacc.c:1646 */ + { (yyval) = NULL; } +#line 1897 "command.c" /* yacc.c:1646 */ + break; + + case 69: +#line 425 "command.y" /* yacc.c:1646 */ + { (yyval) = NULL; } +#line 1903 "command.c" /* yacc.c:1646 */ + break; + + case 74: +#line 434 "command.y" /* yacc.c:1646 */ + { (yyval) = NULL; } +#line 1909 "command.c" /* yacc.c:1646 */ + break; + + case 75: +#line 439 "command.y" /* yacc.c:1646 */ + { (yyval) = NULL; } +#line 1915 "command.c" /* yacc.c:1646 */ + break; + + case 77: +#line 442 "command.y" /* yacc.c:1646 */ + { (yyval) = NULL; } +#line 1921 "command.c" /* yacc.c:1646 */ + break; + + case 78: +#line 447 "command.y" /* yacc.c:1646 */ + { + NODE *n; + n = (yyvsp[0])->a_node; + if ((n->flags & STRING) == 0) + yyerror(_("argument not a string")); + } +#line 1932 "command.c" /* yacc.c:1646 */ + break; + + case 79: +#line 457 "command.y" /* yacc.c:1646 */ + { (yyval) = NULL; } +#line 1938 "command.c" /* yacc.c:1646 */ + break; + + case 80: +#line 459 "command.y" /* yacc.c:1646 */ + { + if (find_option((yyvsp[0])->a_string) < 0) + yyerror(_("option: invalid parameter - \"%s\""), (yyvsp[0])->a_string); + } +#line 1947 "command.c" /* yacc.c:1646 */ + break; + + case 81: +#line 464 "command.y" /* yacc.c:1646 */ + { + if (find_option((yyvsp[-2])->a_string) < 0) + yyerror(_("option: invalid parameter - \"%s\""), (yyvsp[-2])->a_string); + } +#line 1956 "command.c" /* yacc.c:1646 */ + break; + + case 82: +#line 472 "command.y" /* yacc.c:1646 */ + { + NODE *n; + n = lookup((yyvsp[0])->a_string); + if (n == NULL || n->type != Node_func) + yyerror(_("no such function - \"%s\""), (yyvsp[0])->a_string); + else { + (yyvsp[0])->type = D_func; + efree((yyvsp[0])->a_string); + (yyvsp[0])->a_string = NULL; + (yyvsp[0])->a_node = n; + } + } +#line 1973 "command.c" /* yacc.c:1646 */ + break; + + case 83: +#line 488 "command.y" /* yacc.c:1646 */ + { (yyval) = NULL; } +#line 1979 "command.c" /* yacc.c:1646 */ + break; + + case 88: +#line 497 "command.y" /* yacc.c:1646 */ + { (yyval) = NULL; } +#line 1985 "command.c" /* yacc.c:1646 */ + break; + + case 89: +#line 498 "command.y" /* yacc.c:1646 */ + { want_nodeval = true; } +#line 1991 "command.c" /* yacc.c:1646 */ + break; + + case 92: +#line 500 "command.y" /* yacc.c:1646 */ + { want_nodeval = true; } +#line 1997 "command.c" /* yacc.c:1646 */ + break; + + case 95: +#line 506 "command.y" /* yacc.c:1646 */ + { (yyval) = NULL; } +#line 2003 "command.c" /* yacc.c:1646 */ + break; + + case 97: +#line 512 "command.y" /* yacc.c:1646 */ + { (yyval) = NULL; } +#line 2009 "command.c" /* yacc.c:1646 */ + break; + + case 99: +#line 518 "command.y" /* yacc.c:1646 */ + { (yyval) = NULL; } +#line 2015 "command.c" /* yacc.c:1646 */ + break; + + case 104: +#line 530 "command.y" /* yacc.c:1646 */ + { + int idx = find_argument((yyvsp[-1])); + if (idx < 0) + yyerror(_("enable: invalid option - \"%s\""), (yyvsp[-1])->a_string); + else { + efree((yyvsp[-1])->a_string); + (yyvsp[-1])->a_string = NULL; + (yyvsp[-1])->type = D_argument; + (yyvsp[-1])->a_argument = argtab[idx].value; + } + } +#line 2031 "command.c" /* yacc.c:1646 */ + break; + + case 106: +#line 546 "command.y" /* yacc.c:1646 */ + { + (yyvsp[0])->type = D_array; /* dump all items */ + (yyvsp[0])->a_count = 0; + } +#line 2040 "command.c" /* yacc.c:1646 */ + break; + + case 107: +#line 551 "command.y" /* yacc.c:1646 */ + { + (yyvsp[-1])->type = D_array; + (yyvsp[-1])->a_count = num_dim; + } +#line 2049 "command.c" /* yacc.c:1646 */ + break; + + case 117: +#line 577 "command.y" /* yacc.c:1646 */ + { (yyval) = NULL; } +#line 2055 "command.c" /* yacc.c:1646 */ + break; + + case 118: +#line 579 "command.y" /* yacc.c:1646 */ + { (yyval) = NULL; } +#line 2061 "command.c" /* yacc.c:1646 */ + break; + + case 119: +#line 581 "command.y" /* yacc.c:1646 */ + { + CMDARG *a; + a = mk_cmdarg(D_int); + a->a_int = -1; + append_cmdarg(a); + } +#line 2072 "command.c" /* yacc.c:1646 */ + break; + + case 126: +#line 597 "command.y" /* yacc.c:1646 */ + { + if ((yyvsp[-2])->a_int > (yyvsp[0])->a_int) + yyerror(_("invalid range specification: %d - %d"), + (yyvsp[-2])->a_int, (yyvsp[0])->a_int); + else + (yyvsp[-2])->type = D_range; + (yyval) = (yyvsp[-2]); + } +#line 2085 "command.c" /* yacc.c:1646 */ + break; + + case 127: +#line 609 "command.y" /* yacc.c:1646 */ + { (yyval) = NULL; } +#line 2091 "command.c" /* yacc.c:1646 */ + break; + + case 134: +#line 623 "command.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[0]); } +#line 2097 "command.c" /* yacc.c:1646 */ + break; + + case 135: +#line 625 "command.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[-2]); } +#line 2103 "command.c" /* yacc.c:1646 */ + break; + + case 137: +#line 631 "command.y" /* yacc.c:1646 */ + { + CMDARG *a; + NODE *subs; + int count = 0; + + for (a = (yyvsp[-1]); a != NULL; a = a->next) + count++; + subs = concat_args((yyvsp[-1]), count); + free_cmdarg((yyvsp[-1])->next); + (yyvsp[-1])->next = NULL; + (yyvsp[-1])->type = D_node; + (yyvsp[-1])->a_node = subs; + (yyval) = (yyvsp[-1]); + } +#line 2122 "command.c" /* yacc.c:1646 */ + break; + + case 139: +#line 650 "command.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[0]); num_dim = 1; } +#line 2128 "command.c" /* yacc.c:1646 */ + break; + + case 140: +#line 652 "command.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[-1]); num_dim++; } +#line 2134 "command.c" /* yacc.c:1646 */ + break; + + case 142: +#line 658 "command.y" /* yacc.c:1646 */ + { + NODE *n = (yyvsp[0])->a_node; + if ((n->flags & NUMBER) == 0) + yyerror(_("non-numeric value for field number")); + else + (yyvsp[0])->type = D_field; + (yyval) = (yyvsp[0]); + } +#line 2147 "command.c" /* yacc.c:1646 */ + break; + + case 143: +#line 667 "command.y" /* yacc.c:1646 */ + { + /* a_string is array name, a_count is dimension count */ + (yyvsp[-1])->type = D_subscript; + (yyvsp[-1])->a_count = num_dim; + (yyval) = (yyvsp[-1]); + } +#line 2158 "command.c" /* yacc.c:1646 */ + break; + + case 144: +#line 677 "command.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[0]); } +#line 2164 "command.c" /* yacc.c:1646 */ + break; + + case 145: +#line 679 "command.y" /* yacc.c:1646 */ + { + NODE *n = (yyvsp[0])->a_node; + if ((n->flags & NUMBER) == 0) + yyerror(_("non-numeric value found, numeric expected")); + (yyval) = (yyvsp[0]); + } +#line 2175 "command.c" /* yacc.c:1646 */ + break; + + case 146: +#line 686 "command.y" /* yacc.c:1646 */ + { + NODE *n = (yyvsp[0])->a_node; + if ((n->flags & NUMBER) == 0) + yyerror(_("non-numeric value found, numeric expected")); + else + negate_num(n); + (yyval) = (yyvsp[0]); + } +#line 2188 "command.c" /* yacc.c:1646 */ + break; + + case 147: +#line 698 "command.y" /* yacc.c:1646 */ + { (yyval) = NULL; } +#line 2194 "command.c" /* yacc.c:1646 */ + break; + + case 148: +#line 700 "command.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[0]); } +#line 2200 "command.c" /* yacc.c:1646 */ + break; + + case 149: +#line 705 "command.y" /* yacc.c:1646 */ + { (yyval) = NULL; } +#line 2206 "command.c" /* yacc.c:1646 */ + break; + + case 150: +#line 707 "command.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[0]); } +#line 2212 "command.c" /* yacc.c:1646 */ + break; + + case 151: +#line 712 "command.y" /* yacc.c:1646 */ + { + if ((yyvsp[0])->a_int == 0) + yyerror(_("non-zero integer value")); + (yyval) = (yyvsp[0]); + } +#line 2222 "command.c" /* yacc.c:1646 */ + break; + + case 152: +#line 718 "command.y" /* yacc.c:1646 */ + { + if ((yyvsp[0])->a_int == 0) + yyerror(_("non-zero integer value")); + (yyval) = (yyvsp[0]); + } +#line 2232 "command.c" /* yacc.c:1646 */ + break; + + case 153: +#line 727 "command.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[0]); } +#line 2238 "command.c" /* yacc.c:1646 */ + break; + + case 154: +#line 729 "command.y" /* yacc.c:1646 */ + { (yyval) = (yyvsp[0]); } +#line 2244 "command.c" /* yacc.c:1646 */ + break; + + case 155: +#line 731 "command.y" /* yacc.c:1646 */ + { + (yyvsp[0])->a_int = - (yyvsp[0])->a_int; + (yyval) = (yyvsp[0]); + } +#line 2253 "command.c" /* yacc.c:1646 */ + break; + + case 156: +#line 739 "command.y" /* yacc.c:1646 */ + { + if (lexptr_begin != NULL) { + if (input_from_tty && lexptr_begin[0] != '\0') + add_history(lexptr_begin); + efree(lexptr_begin); + lexptr_begin = NULL; + } + } +#line 2266 "command.c" /* yacc.c:1646 */ + break; + + +#line 2270 "command.c" /* yacc.c:1646 */ + default: break; + } + /* User semantic actions sometimes alter yychar, and that requires + that yytoken be updated with the new translation. We take the + approach of translating immediately before every use of yytoken. + One alternative is translating here after every semantic action, + but that translation would be missed if the semantic action invokes + YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or + if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an + incorrect destructor might then be invoked immediately. In the + case of YYERROR or YYBACKUP, subsequent parser actions might lead + to an incorrect destructor call or verbose syntax error message + before the lookahead is translated. */ + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + /* Now 'shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*--------------------------------------. +| yyerrlab -- here on detecting error. | +`--------------------------------------*/ +yyerrlab: + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); + + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (YY_("syntax error")); +#else +# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ + yyssp, yytoken) + { + char const *yymsgp = YY_("syntax error"); + int yysyntax_error_status; + yysyntax_error_status = YYSYNTAX_ERROR; + if (yysyntax_error_status == 0) + yymsgp = yymsg; + else if (yysyntax_error_status == 1) + { + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); + if (!yymsg) + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + yysyntax_error_status = 2; + } + else + { + yysyntax_error_status = YYSYNTAX_ERROR; + yymsgp = yymsg; + } + } + yyerror (yymsgp); + if (yysyntax_error_status == 2) + goto yyexhaustedlab; + } +# undef YYSYNTAX_ERROR +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule whose action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (!yypact_value_is_default (yyn)) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined yyoverflow || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + { + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = YYTRANSLATE (yychar); + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); + } + /* Do not reclaim the symbols of the rule whose action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + return yyresult; +} +#line 749 "command.y" /* yacc.c:1906 */ + + + +/* append_statement --- append 'stmt' to the list of eval awk statements */ + +static CMDARG * +append_statement(CMDARG *stmt_list, char *stmt) +{ + CMDARG *a, *arg; + char *s; + int len, slen, ssize; + +#define EVALSIZE 512 + + if (stmt == start_EVAL) { + len = sizeof(start_EVAL); + for (a = stmt_list; a != NULL; a = a->next) + len += strlen(a->a_string) + 1; /* 1 for ',' */ + len += EVALSIZE; + + emalloc(s, char *, (len + 1) * sizeof(char), "append_statement"); + arg = mk_cmdarg(D_string); + arg->a_string = s; + arg->a_count = len; /* kludge */ + + slen = sizeof("function @eval(") - 1; + memcpy(s, start_EVAL, slen); + + for (a = stmt_list; a != NULL; a = a->next) { + len = strlen(a->a_string); + memcpy(s + slen, a->a_string, len); + slen += len; + if (a->next != NULL) + s[slen++] = ','; + } + s[slen++] = ')'; + s[slen++] = '{'; + 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 + 1) * sizeof(char), "append_statement"); + stmt_list->a_string = s; + stmt_list->a_count = ssize; + } + memcpy(s + slen, stmt, len); + slen += len; + if (slen >= 2 && s[slen - 2] != '\n') { + s[slen - 1] = '\n'; + s[slen] = '\0'; + } + + if (stmt == end_EVAL) + erealloc(stmt_list->a_string, char *, slen + 1, "append_statement"); + return stmt_list; + +#undef EVALSIZE +} + + +/* command names sorted in ascending order */ + +struct cmdtoken cmdtab[] = { +{ "backtrace", "bt", D_backtrace, D_BACKTRACE, do_backtrace, + gettext_noop("backtrace [N] - print trace of all or N innermost (outermost if N < 0) frames.") }, +{ "break", "b", D_break, D_BREAK, do_breakpoint, + gettext_noop("break [[filename:]N|function] - set breakpoint at the specified location.") }, +{ "clear", "", D_clear, D_CLEAR, do_clear, + gettext_noop("clear [[filename:]N|function] - delete breakpoints previously set.") }, +{ "commands", "", D_commands, D_COMMANDS, do_commands, + gettext_noop("commands [num] - starts a list of commands to be executed at a breakpoint(watchpoint) hit.") }, +{ "condition", "", D_condition, D_CONDITION, do_condition, + gettext_noop("condition num [expr] - set or clear breakpoint or watchpoint condition.") }, +{ "continue", "c", D_continue, D_CONTINUE, do_continue, + gettext_noop("continue [COUNT] - continue program being debugged.") }, +{ "delete", "d", D_delete, D_DELETE, do_delete_breakpoint, + gettext_noop("delete [breakpoints] [range] - delete specified breakpoints.") }, +{ "disable", "", D_disable, D_DISABLE, do_disable_breakpoint, + gettext_noop("disable [breakpoints] [range] - disable specified breakpoints.") }, +{ "display", "", D_display, D_DISPLAY, do_display, + gettext_noop("display [var] - print value of variable each time the program stops.") }, +{ "down", "", D_down, D_DOWN, do_down, + gettext_noop("down [N] - move N frames down the stack.") }, +{ "dump", "", D_dump, D_DUMP, do_dump_instructions, + gettext_noop("dump [filename] - dump instructions to file or stdout.") }, +{ "enable", "e", D_enable, D_ENABLE, do_enable_breakpoint, + gettext_noop("enable [once|del] [breakpoints] [range] - enable specified breakpoints.") }, +{ "end", "", D_end, D_END, do_commands, + gettext_noop("end - end a list of commands or awk statements.") }, +{ "eval", "", D_eval, D_EVAL, do_eval, + gettext_noop("eval stmt|[p1, p2, ...] - evaluate awk statement(s).") }, +{ "exit", "", D_quit, D_QUIT, do_quit, + gettext_noop("exit - (same as quit) exit debugger.") }, +{ "finish", "", D_finish, D_FINISH, do_finish, + gettext_noop("finish - execute until selected stack frame returns.") }, +{ "frame", "f", D_frame, D_FRAME, do_frame, + gettext_noop("frame [N] - select and print stack frame number N.") }, +{ "help", "h", D_help, D_HELP, do_help, + gettext_noop("help [command] - print list of commands or explanation of command.") }, +{ "ignore", "", D_ignore, D_IGNORE, do_ignore_breakpoint, + gettext_noop("ignore N COUNT - set ignore-count of breakpoint number N to COUNT.") }, +{ "info", "i", D_info, D_INFO, do_info, + gettext_noop("info topic - source|sources|variables|functions|break|frame|args|locals|display|watch.") }, +{ "list", "l", D_list, D_LIST, do_list, + gettext_noop("list [-|+|[filename:]lineno|function|range] - list specified line(s).") }, +{ "next", "n", D_next, D_NEXT, do_next, + gettext_noop("next [COUNT] - step program, proceeding through subroutine calls.") }, +{ "nexti", "ni", D_nexti, D_NEXTI, do_nexti, + gettext_noop("nexti [COUNT] - step one instruction, but proceed through subroutine calls.") }, +{ "option", "o", D_option, D_OPTION, do_option, + gettext_noop("option [name[=value]] - set or display debugger option(s).") }, +{ "print", "p", D_print, D_PRINT, do_print_var, + gettext_noop("print var [var] - print value of a variable or array.") }, +{ "printf", "", D_printf, D_PRINTF, do_print_f, + gettext_noop("printf format, [arg], ... - formatted output.") }, +{ "quit", "q", D_quit, D_QUIT, do_quit, + gettext_noop("quit - exit debugger.") }, +{ "return", "", D_return, D_RETURN, do_return, + gettext_noop("return [value] - make selected stack frame return to its caller.") }, +{ "run", "r", D_run, D_RUN, do_run, + gettext_noop("run - start or restart executing program.") }, +#ifdef HAVE_LIBREADLINE +{ "save", "", D_save, D_SAVE, do_save, + gettext_noop("save filename - save commands from the session to file.") }, +#endif +{ "set", "", D_set, D_SET, do_set_var, + gettext_noop("set var = value - assign value to a scalar variable.") }, +{ "silent", "", D_silent, D_SILENT, do_commands, + gettext_noop("silent - suspends usual message when stopped at a breakpoint/watchpoint.") }, +{ "source", "", D_source, D_SOURCE, do_source, + gettext_noop("source file - execute commands from file.") }, +{ "step", "s", D_step, D_STEP, do_step, + gettext_noop("step [COUNT] - step program until it reaches a different source line.") }, +{ "stepi", "si", D_stepi, D_STEPI, do_stepi, + gettext_noop("stepi [COUNT] - step one instruction exactly.") }, +{ "tbreak", "t", D_tbreak, D_TBREAK, do_tmp_breakpoint, + gettext_noop("tbreak [[filename:]N|function] - set a temporary breakpoint.") }, +{ "trace", "", D_trace, D_TRACE, do_trace_instruction, + gettext_noop("trace on|off - print instruction before executing.") }, +{ "undisplay", "", D_undisplay, D_UNDISPLAY, do_undisplay, + gettext_noop("undisplay [N] - remove variable(s) from automatic display list.") }, +{ "until", "u", D_until, D_UNTIL, do_until, + gettext_noop("until [[filename:]N|function] - execute until program reaches a different line or line N within current frame.") }, +{ "unwatch", "", D_unwatch, D_UNWATCH, do_unwatch, + gettext_noop("unwatch [N] - remove variable(s) from watch list.") }, +{ "up", "", D_up, D_UP, do_up, + gettext_noop("up [N] - move N frames up the stack.") }, +{ "watch", "w", D_watch, D_WATCH, do_watch, + gettext_noop("watch var - set a watchpoint for a variable.") }, +{ "where", "", D_backtrace, D_BACKTRACE, do_backtrace, + gettext_noop("where [N] - (same as backtrace) print trace of all or N innermost (outermost if N < 0) frames.") }, +{ NULL, NULL, D_illegal, 0, (Func_cmd) 0, + NULL }, +}; + +struct argtoken argtab[] = { + { "args", D_info, A_ARGS }, + { "break", D_info, A_BREAK }, + { "del", D_enable, A_DEL }, + { "display", D_info, A_DISPLAY }, + { "frame", D_info, A_FRAME }, + { "functions", D_info, A_FUNCTIONS }, + { "locals", D_info, A_LOCALS }, + { "off", D_trace, A_TRACE_OFF }, + { "on", D_trace, A_TRACE_ON }, + { "once", D_enable, A_ONCE }, + { "source", D_info, A_SOURCE }, + { "sources", D_info, A_SOURCES }, + { "variables", D_info, A_VARIABLES }, + { "watch", D_info, A_WATCH }, + { NULL, D_illegal, A_NONE }, +}; + + +/* get_command --- return command handler function */ + +Func_cmd +get_command(int ctype) +{ + int i; + for (i = 0; cmdtab[i].name != NULL; i++) { + if (cmdtab[i].type == ctype) + return cmdtab[i].cf_ptr; + } + return (Func_cmd) 0; +} + +/* get_command_name --- return command name given it's type */ + +const char * +get_command_name(int ctype) +{ + int i; + for (i = 0; cmdtab[i].name != NULL; i++) { + if (cmdtab[i].type == ctype) + return cmdtab[i].name; + } + return NULL; +} + +/* mk_cmdarg --- make an argument for command */ + +static CMDARG * +mk_cmdarg(enum argtype type) +{ + CMDARG *arg; + 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) +{ + static CMDARG *savetail; + + if (arg_list == NULL) + arg_list = arg; + else + savetail->next = arg; + savetail = arg; +} + +/* free_cmdarg --- free all arguments in LIST */ + +void +free_cmdarg(CMDARG *list) +{ + CMDARG *arg, *nexta; + + for (arg = list; arg != NULL; arg = nexta) { + nexta = arg->next; + + switch (arg->type) { + case D_variable: + case D_subscript: + case D_array: + case D_string: + if (arg->a_string != NULL) + efree(arg->a_string); + break; + case D_node: + case D_field: + unref(arg->a_node); + break; + default: + break; + } + efree(arg); + } +} + +/* yyerror --- print a syntax error message */ + +static void +yyerror(const char *mesg, ...) +{ + va_list args; + va_start(args, mesg); + fprintf(out_fp, _("error: ")); + vfprintf(out_fp, mesg, args); + fprintf(out_fp, "\n"); + va_end(args); + errcount++; + repeat_idx = -1; +} + + +/* yylex --- read a command and turn it into tokens */ + +static int +#ifdef USE_EBCDIC +yylex_ebcdic(void) +#else +yylex(void) +#endif +{ + static char *lexptr = NULL; + static char *lexend; + int c; + char *tokstart; + size_t toklen; + + yylval = (CMDARG *) NULL; + + if (errcount > 0 && lexptr_begin == NULL) { + /* fake a new line */ + errcount = 0; + return '\n'; + } + + if (lexptr_begin == NULL) { +again: + lexptr_begin = read_a_line(dbg_prompt); + if (lexptr_begin == NULL) { /* EOF or error */ + if (get_eof_status() == EXIT_FATAL) + exit(EXIT_FATAL); + if (get_eof_status() == EXIT_FAILURE) { + static int seen_eof = 0; + + /* force a quit, and let do_quit (in debug.c) exit */ + if (! seen_eof) { + if (errno != 0) { + fprintf(stderr, _("can't read command (%s)\n"), strerror(errno)); + exit_val = EXIT_FAILURE; + } /* else + exit_val = EXIT_SUCCESS; */ + + seen_eof = 1; + return '\n'; /* end current command if any */ + } else if (seen_eof++ == 1) { + cmd_idx = find_command("quit", 4); + return D_QUIT; /* 'quit' token */ + } else + return '\n'; /* end command 'quit' */ + } + if (errno != 0) + d_error(_("can't read command (%s)"), strerror(errno)); + if (pop_cmd_src() == 0) + goto again; + exit(EXIT_FATAL); /* shouldn't happen */ + } + + if (! in_commands && ! in_eval /* history expansion off in 'commands' and 'eval' */ + && input_from_tty + ) + history_expand_line(&lexptr_begin); + + lexptr = lexptr_begin; + lexend = lexptr + strlen(lexptr); + if (*lexptr == '\0' /* blank line */ + && repeat_idx >= 0 + && input_from_tty + && ! in_eval + ) { +#ifdef HAVE_LIBREADLINE + HIST_ENTRY *h; + h = previous_history(); + if (h != NULL) + add_history(h->line); +#endif + cmd_idx = repeat_idx; + return cmdtab[cmd_idx].class; /* repeat last command */ + } + repeat_idx = -1; + } + + c = *lexptr; + + while (c == ' ' || c == '\t') + c = *++lexptr; + + if (! input_from_tty && c == '#') + return '\n'; + + tokstart = lexptr; + if (lexptr >= lexend) + return '\n'; + + if (cmd_idx < 0) { /* need a command */ + if (c == '?' && tokstart[1] == '\0' && ! in_eval) { + lexptr++; + cmd_idx = find_command("help", 4); + return D_HELP; + } + + while (c != '\0' && c != ' ' && c != '\t') { + if (! is_alpha(c) && ! in_eval) { + yyerror(_("invalid character in command")); + return '\n'; + } + c = *++lexptr; + } + + toklen = lexptr - tokstart; + + if (in_eval) { + if (toklen == 3 + && tokstart[3] == '\0' + && tokstart[0] == 'e' + && tokstart[1] == 'n' + && tokstart[2] == 'd' + ) { + cmd_idx = find_command(tokstart, toklen); + return D_END; + } + lexptr = lexend; + return D_STATEMENT; + } + + cmd_idx = find_command(tokstart, toklen); + if (cmd_idx >= 0) { + if (in_commands && cmdtab[cmd_idx].type != D_eval) { + /* add the actual command string (lexptr_begin) to + * arg_list; command string for 'eval' prepended to the arg_list + * in the grammer above (see eval_cmd non-terminal). + */ + CMDARG *arg; + arg = mk_cmdarg(D_string); + arg->a_string = estrdup(lexptr_begin, lexend - lexptr_begin); + append_cmdarg(arg); + } + return cmdtab[cmd_idx].class; + } else { + yyerror(_("unknown command - \"%.*s\", try help"), toklen, tokstart); + return '\n'; + } + } + + c = *lexptr; + + if (cmdtab[cmd_idx].type == D_option) { + if (c == '=') + return *lexptr++; + } else if (c == '-' || c == '+' || c == ':' || c == '|') + return *lexptr++; + + if (c == '"') { + char *str, *p; + int flags = ALREADY_MALLOCED; + bool esc_seen = false; + + toklen = lexend - lexptr; + emalloc(str, char *, toklen + 1, "yylex"); + p = str; + + while ((c = *++lexptr) != '"') { + if (lexptr == lexend) { +err: + efree(str); + yyerror(_("unterminated string")); + return '\n'; + } + if (c == '\\') { + c = *++lexptr; + esc_seen = true; + if (want_nodeval || c != '"') + *p++ = '\\'; + } + if (lexptr == lexend) + goto err; + *p++ = c; + } + lexptr++; + *p = '\0'; + + if (! want_nodeval) { + yylval = mk_cmdarg(D_string); + yylval->a_string = str; + append_cmdarg(yylval); + return D_STRING; + } else { /* awk string */ + if (esc_seen) + flags |= SCAN; + yylval = mk_cmdarg(D_node); + yylval->a_node = make_str_node(str, p - str, flags); + append_cmdarg(yylval); + return D_NODE; + } + } + + if (! want_nodeval) { + while ((c = *++lexptr) != '\0' && c != ':' && c != '-' + && c != ' ' && c != '\t' && c != '=') + ; + + /* Is it an integer? */ + if (isdigit((unsigned char) tokstart[0]) && cmdtab[cmd_idx].type != D_option) { + char *end; + long l; + + errno = 0; + l = strtol(tokstart, &end, 0); + if (errno != 0) { + yyerror(_("%s"), strerror(errno)); + errno = 0; + return '\n'; + } + + if (lexptr == end) { + yylval = mk_cmdarg(D_int); + yylval->a_int = l; + append_cmdarg(yylval); + return D_INT; + } + } + + /* Must be string */ + yylval = mk_cmdarg(D_string); + yylval->a_string = estrdup(tokstart, lexptr - tokstart); + append_cmdarg(yylval); + return D_STRING; + } + + /* look for awk number */ + + if (isdigit((unsigned char) tokstart[0])) { + NODE *r = NULL; + + errno = 0; +#ifdef HAVE_MPFR + if (do_mpfr) { + int tval; + r = mpg_float(); + tval = mpfr_strtofr(r->mpg_numbr, tokstart, & lexptr, 0, ROUND_MODE); + IEEE_FMT(r->mpg_numbr, tval); + if (mpfr_integer_p(r->mpg_numbr)) { + /* integral value, convert to a GMP type. */ + NODE *tmp = r; + r = mpg_integer(); + mpfr_get_z(r->mpg_i, tmp->mpg_numbr, MPFR_RNDZ); + unref(tmp); + } + } else +#endif + r = make_number(strtod(tokstart, & lexptr)); + + if (errno != 0) { + yyerror(strerror(errno)); + unref(r); + errno = 0; + return '\n'; + } + yylval = mk_cmdarg(D_node); + yylval->a_node = r; + append_cmdarg(yylval); + return D_NODE; + } + + c = *lexptr; + if (c == '$' || c == '@' + || c == '[' || c == ']' + || c == ',' || c == '=') + return *lexptr++; + + if (! is_letter(c)) { + yyerror(_("invalid character")); + return '\n'; + } + + while (is_identchar(c)) + c = *++lexptr; + toklen = lexptr - tokstart; + + /* awk variable */ + yylval = mk_cmdarg(D_variable); + yylval->a_string = estrdup(tokstart, toklen); + append_cmdarg(yylval); + return D_VARIABLE; +} + +/* Convert single-character tokens coming out of yylex() from EBCDIC to + ASCII values on-the-fly so that the parse tables need not be regenerated + for EBCDIC systems. */ +#ifdef USE_EBCDIC +static int +yylex(void) +{ + static char etoa_xlate[256]; + static int do_etoa_init = 1; + int tok; + + if (do_etoa_init) + { + for (tok = 0; tok < 256; tok++) + etoa_xlate[tok] = (char) tok; +#ifdef HAVE___ETOA_L + /* IBM helpfully provides this function. */ + __etoa_l(etoa_xlate, sizeof(etoa_xlate)); +#else +# error "An EBCDIC-to-ASCII translation function is needed for this system" +#endif + do_etoa_init = 0; + } + + tok = yylex_ebcdic(); + + if (tok >= 0 && tok <= 0xFF) + tok = etoa_xlate[tok]; + + return tok; +} +#endif /* USE_EBCDIC */ + +/* find_argument --- find index in 'argtab' for a command option */ + +static int +find_argument(CMDARG *arg) +{ + /* non-number argument */ + int idx; + char *name, *p; + size_t len; + assert(cmd_idx >= 0); + name = arg->a_string; + len = strlen(name); + for (idx = 0; (p = (char *) argtab[idx].name) != NULL; idx++) { + if (cmdtab[cmd_idx].type == argtab[idx].cmd + && *p == *name + && strlen(p) == len + && strncmp(p, name, len) == 0 + ) + return idx; + } + return -1; /* invalid option */ +} + +/* concat_args --- concatenate argument strings into a single string NODE */ + +static NODE * +concat_args(CMDARG *arg, int count) +{ + NODE *n; + NODE **tmp; + char *str, *subsep, *p; + long len, subseplen; + int i; + + if (count == 1) { + 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; + len = -subseplen; + + for (i = 0; i < count; i++) { + n = force_string(arg->a_node); + len += n->stlen + subseplen; + tmp[i] = n; + arg = arg->next; + } + + emalloc(str, char *, len + 1, "concat_args"); + n = tmp[0]; + memcpy(str, n->stptr, n->stlen); + p = str + n->stlen; + for (i = 1; i < count; i++) { + if (subseplen == 1) + *p++ = *subsep; + else if (subseplen > 0) { + memcpy(p, subsep, subseplen); + p += subseplen; + } + + n = tmp[i]; + memcpy(p, n->stptr, n->stlen); + p += n->stlen; + } + str[len] = '\0'; + efree(tmp); + return make_str_node(str, len, ALREADY_MALLOCED); +} + +/* find_command --- find the index in 'cmdtab' using exact, + * abbreviation or unique partial match + */ + +static int +find_command(const char *token, size_t toklen) +{ + char *name, *abrv; + int i, k; + bool try_exact = true; + int abrv_match = -1; + int partial_match = -1; + +#if 'a' == 0x81 /* it's EBCDIC */ + /* make sure all lower case characters in token (sorting + * isn't the solution in this case) + */ + for (i = 0; i < toklen; i++) { + if (token[i] != tolower(token[i])) + return -1; + } +#endif + + k = sizeof(cmdtab)/sizeof(cmdtab[0]) - 1; + for (i = 0; i < k; i++) { + name = (char *) cmdtab[i].name; + if (try_exact && *token == *name + && toklen == strlen(name) + && strncmp(name, token, toklen) == 0 + ) + return i; + + if (*name > *token || i == (k - 1)) + try_exact = false; + + if (abrv_match < 0) { + abrv = cmdtab[i].abbrvn; + if (abrv[0] == token[0]) { + if (toklen == 1 && ! abrv[1]) + abrv_match = i; + else if (toklen == 2 && abrv[1] == token[1]) + abrv_match = i; + } + } + if (! try_exact && abrv_match >= 0) + return abrv_match; + if (partial_match < 0) { + if (*token == *name + && toklen < strlen(name) + && strncmp(name, token, toklen) == 0 + ) { + if ((i == k - 1 || strncmp(cmdtab[i + 1].name, token, toklen) != 0) + && (i == 0 || strncmp(cmdtab[i - 1].name, token, toklen) != 0) + ) + partial_match = i; + } + } + } + return partial_match; +} + +/* do_help -- help command */ + +int +do_help(CMDARG *arg, int cmd) +{ + int i; + if (arg == NULL) { + initialize_pager(out_fp); + if (setjmp(pager_quit_tag) == 0) { + for (i = 0; cmdtab[i].name != NULL; i++) { + gprintf(out_fp, "%s:\n", cmdtab[i].name); + gprintf(out_fp, "\t%s\n", _(cmdtab[i].help_txt)); + } + } + } else if (arg->type == D_string) { + char *name; + name = arg->a_string; + i = find_command(name, strlen(name)); + if (i >= 0) { + fprintf(out_fp, "%s\n", cmdtab[i].help_txt); + if (strcmp(cmdtab[i].name, "option") == 0) + option_help(); + } else + fprintf(out_fp, _("undefined command: %s\n"), name); + } + + return false; +} + + +#ifdef HAVE_LIBREADLINE + +/* 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) +{ + char *q; + int i; + + if (p == NULL || len <= 0) + return NULL; + for (i = 0; i < len; i++, p++) + if (*p != ' ' && *p != '\t') + break; + if (i == len) + return NULL; + if (endp != NULL) { + for (i++, q = p + 1; i < len; i++, q++) + if (*q == ' ' || *q == '\t') + break; + *endp = q; + } + return p; +} + +/* command_completion --- attempt to complete based on the word number in line; + * try to complete on command names if this is the first word; for the next + * word(s), the type of completion depends on the command name (first word). + */ + +#ifndef RL_READLINE_VERSION /* < 4.2a */ +#define rl_completion_matches(x, y) completion_matches((char *) (x), (y)) +#endif + + +char ** +command_completion(const char *text, int start, int end) +{ + char *cmdtok, *e; + int idx; + int len; + + rl_attempted_completion_over = true; /* no default filename completion please */ + + this_cmd = D_illegal; + len = start; + if ((cmdtok = next_word(rl_line_buffer, len, &e)) == NULL) /* no first word yet */ + return rl_completion_matches(text, command_generator); + len -= (e - rl_line_buffer); + + idx = find_command(cmdtok, e - cmdtok); + if (idx < 0) + return NULL; + this_cmd = cmdtab[idx].type; + + if (! next_word(e, len, NULL)) { + switch (this_cmd) { + case D_break: + case D_list: + case D_until: + case D_tbreak: + case D_clear: + return rl_completion_matches(text, srcfile_generator); + case D_info: + case D_enable: + case D_trace: + case D_help: + return rl_completion_matches(text, argument_generator); + case D_option: + return rl_completion_matches(text, option_generator); + case D_print: + case D_printf: + case D_set: + case D_display: + case D_watch: + return rl_completion_matches(text, variable_generator); + default: + return NULL; + } + } + + 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) +{ + static size_t textlen; + static int idx = 0; + char *name; + + if (! state) { /* first time */ + textlen = strlen(text); + idx = 0; + } + while ((name = (char *) cmdtab[idx].name) != NULL) { + idx++; + if (strncmp(name, text, textlen) == 0) + return estrdup(name, strlen(name)); + } + return NULL; +} + +/* srcfile_generator --- generator function for source file completion */ + +static char * +srcfile_generator(const char *text, int state) +{ + static size_t textlen; + static SRCFILE *s; + char *name; + extern SRCFILE *srcfiles; + + if (! state) { /* first time */ + textlen = strlen(text); + s = srcfiles->next; + } + while (s != srcfiles) { + if (s->stype != SRC_FILE && s->stype != SRC_INC) { + s = s->next; + continue; + } + name = s->src; + s = s->next; + if (strncmp(name, text, textlen) == 0) + return estrdup(name, strlen(name)); + } + return NULL; +} + +/* argument_generator --- generator function for non-number argument completion */ + +static char * +argument_generator(const char *text, int state) +{ + static size_t textlen; + static int idx; + const char *name; + + if (! state) { /* first time */ + textlen = strlen(text); + idx = 0; + } + + if (this_cmd == D_help) { + while ((name = cmdtab[idx++].name) != NULL) { + if (strncmp(name, text, textlen) == 0) + return estrdup(name, strlen(name)); + } + } else { + while ((name = argtab[idx].name) != NULL) { + if (this_cmd != argtab[idx++].cmd) + continue; + if (strncmp(name, text, textlen) == 0) + return estrdup(name, strlen(name)); + } + } + return NULL; +} + +/* variable_generator --- generator function for variable name completion */ + +static char * +variable_generator(const char *text, int state) +{ + static size_t textlen; + static int idx = 0; + static NODE *func = NULL; + static NODE **vars = NULL; + const char *name; + NODE *r; + + if (! state) { /* first time */ + textlen = strlen(text); + if (vars != NULL) + efree(vars); + vars = variable_list(); + idx = 0; + func = get_function(); /* function in current context */ + } + + /* function params */ + while (func != NULL) { + if (idx >= func->param_cnt) { + func = NULL; /* don't try to match params again */ + idx = 0; + break; + } + name = func->fparms[idx++].param; + if (strncmp(name, text, textlen) == 0) + return estrdup(name, strlen(name)); + } + + /* globals */ + while ((r = vars[idx++]) != NULL) { + name = r->vname; + if (strncmp(name, text, textlen) == 0) + return estrdup(name, strlen(name)); + } + + return NULL; +} + +/* history_expand_line --- history expand the LINE */ + +static void +history_expand_line(char **line) +{ + int ret; + char *expansion; + + if (! *line || input_fd != 0 || ! input_from_tty) + return; + using_history(); + ret = history_expand(*line, &expansion); + if (ret < 0 || ret == 2) + efree(expansion); + else { + efree(*line); + *line = expansion; + } +} + +#endif diff --git a/command.y b/command.y new file mode 100644 index 0000000..58880de --- /dev/null +++ b/command.y @@ -0,0 +1,1734 @@ +/* + * command.y - yacc/bison parser for debugger commands. + */ + +/* + * Copyright (C) 2004, 2010, 2011, 2014, 2016, 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-1335, + * USA + */ + +%{ +#include "awk.h" +#include "cmd.h" + +#if 0 +#define YYDEBUG 12 +int yydebug = 2; +#endif + +static int yylex(void); +static void yyerror(const char *mesg, ...); + +static int find_command(const char *token, size_t toklen); + +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 long errcount = 0; +static char *lexptr_begin = NULL; +static bool in_commands = false; +static int num_dim; + +static bool in_eval = false; +static const char start_EVAL[] = "function @eval(){"; +static const char end_EVAL[] = "}"; +static CMDARG *append_statement(CMDARG *stmt_list, char *stmt); +static NODE *concat_args(CMDARG *a, int count); + +#ifdef HAVE_LIBREADLINE +static char *next_word(char *p, int len, char **endp); +static void history_expand_line(char **line); +static char *command_generator(const char *text, int state); +static char *srcfile_generator(const char *text, int state); +static char *argument_generator(const char *text, int state); +static char *variable_generator(const char *text, int state); +extern char *option_generator(const char *text, int state); +static int this_cmd = D_illegal; +#else +#define history_expand_line(p) /* nothing */ +static int rl_inhibit_completion; /* dummy variable */ +#endif + +struct argtoken { + const char *name; + enum argtype cmd; + enum nametypeval value; +}; + +/* + * These two should be static, but there are some compilers that + * don't like the static keyword with an empty size. Therefore give + * them names that are less likely to conflict with the rest of gawk. + */ +#define argtab zz_debug_argtab +#define cmdtab zz_debug_cmdtab + +extern struct argtoken argtab[]; +extern struct cmdtoken cmdtab[]; + +static CMDARG *mk_cmdarg(enum argtype type); +static void append_cmdarg(CMDARG *arg); +static int find_argument(CMDARG *arg); +#define YYSTYPE CMDARG * +%} + +%token D_BACKTRACE D_BREAK D_CLEAR D_CONTINUE D_DELETE D_DISABLE D_DOWN +%token D_ENABLE D_FINISH D_FRAME D_HELP D_IGNORE D_INFO D_LIST +%token D_NEXT D_NEXTI D_PRINT D_PRINTF D_QUIT D_RETURN D_RUN D_SET +%token D_STEP D_STEPI D_TBREAK D_UP D_UNTIL +%token D_DISPLAY D_UNDISPLAY D_WATCH D_UNWATCH +%token D_DUMP D_TRACE +%token D_INT D_STRING D_NODE D_VARIABLE +%token D_OPTION D_COMMANDS D_END D_SILENT D_SOURCE +%token D_SAVE D_EVAL D_CONDITION +%token D_STATEMENT + +%% + +input + : /* empty */ + | input line + { + cmd_idx = -1; + want_nodeval = false; + if (lexptr_begin != NULL) { + if (input_from_tty && lexptr_begin[0] != '\0') + add_history(lexptr_begin); + efree(lexptr_begin); + lexptr_begin = NULL; + } + if (arg_list != NULL) { + free_cmdarg(arg_list); + arg_list = NULL; + } + } + ; + +line + : nls + | command nls + { + if (errcount == 0 && cmd_idx >= 0) { + Func_cmd cmdfunc; + bool terminate = false; + CMDARG *args; + int ctype = 0; + + ctype = cmdtab[cmd_idx].type; + + /* a blank line repeats previous command + * (list, next, nexti, step, stepi and continue without arguments). + * save the index in the command table; used in yylex + */ + if ((ctype == D_list + || ctype == D_next + || ctype == D_step + || ctype == D_nexti + || ctype == D_stepi + || ctype == D_continue) + && arg_list == NULL + && ! in_commands + && input_from_tty + ) + repeat_idx = cmd_idx; + else + repeat_idx = -1; + + /* call the command handler; reset the globals arg_list, cmd_idx, + * since this handler could invoke yyparse again. + * call do_commands for the list of commands in `commands'; + * arg_list isn't freed on return. + */ + + cmdfunc = cmdtab[cmd_idx].cf_ptr; + if (in_commands) + cmdfunc = do_commands; + cmd_idx = -1; + want_nodeval = false; + + args = arg_list; + arg_list = NULL; + + terminate = (*cmdfunc)(args, ctype); + if (! in_commands || ctype == D_commands) + free_cmdarg(args); + if (terminate) + YYACCEPT; + } + } + | error nls + { + yyerrok; + } + ; + +control_cmd + : D_CONTINUE + | D_NEXT + | D_NEXTI + | D_STEP + | D_STEPI + ; + +d_cmd + : D_UNDISPLAY + | D_UNWATCH + | D_DISABLE + | D_DELETE + ; + +frame_cmd + : D_UP + | D_DOWN + | D_BACKTRACE + | D_FRAME + ; + +break_cmd + : D_BREAK + | D_TBREAK + ; + +/* mid-rule action buried in non-terminal to avoid conflict */ +set_want_nodeval + : { want_nodeval = true; } + ; + +eval_prologue + : D_EVAL set_want_nodeval opt_param_list nls + { + if (errcount == 0) { + /* don't free arg_list; passed on to statement_list + * non-terminal (empty rule action). See below. + */ + if (input_from_tty) { + dbg_prompt = eval_prompt; + fprintf(out_fp, + _("Type (g)awk statement(s). End with the command \"end\"\n")); + rl_inhibit_completion = 1; + } + cmd_idx = -1; + in_eval = true; + } + } + ; + +statement_list + : /* empty */ + { + $$ = append_statement(arg_list, (char *) start_EVAL); + if (read_a_line == read_commands_string) /* unserializing 'eval' in 'commands' */ + $$->a_string[0] = '\0'; + free_cmdarg(arg_list); + arg_list = NULL; + } + | statement_list D_STATEMENT { $$ = append_statement($1, lexptr_begin); } nls + { + $$ = $3; + } + ; + +eval_cmd + : eval_prologue statement_list D_END + { + arg_list = append_statement($2, (char *) end_EVAL); + if (read_a_line == read_commands_string) { /* unserializing 'eval' in 'commands' */ + char *str = arg_list->a_string; + size_t len = strlen(str); + assert(len > 2 && str[len - 2] == '}'); + str[len - 2] = '\0'; + } + if (input_from_tty) { + dbg_prompt = in_commands ? commands_prompt : dgawk_prompt; + rl_inhibit_completion = 0; + } + cmd_idx = find_command("eval", 4); + in_eval = false; + } + | D_EVAL set_want_nodeval string_node + { + NODE *n; + CMDARG *arg; + n = $3->a_node; + arg = append_statement(NULL, (char *) start_EVAL); + (void) append_statement(arg, n->stptr); + (void) append_statement(arg, (char *) end_EVAL); + free_cmdarg(arg_list); + arg_list = arg; + } + ; + +command + : D_HELP help_args + | D_QUIT + | D_RUN + | D_FINISH + | control_cmd opt_plus_integer + | frame_cmd opt_integer + { + if (cmdtab[cmd_idx].class == D_FRAME + && $2 != NULL && $2->a_int < 0) + yyerror(_("invalid frame number: %d"), $2->a_int); + } + | D_INFO D_STRING + { + int idx = find_argument($2); + if (idx < 0) + yyerror(_("info: invalid option - \"%s\""), $2->a_string); + else { + efree($2->a_string); + $2->a_string = NULL; + $2->type = D_argument; + $2->a_argument = argtab[idx].value; + } + } + | D_IGNORE plus_integer D_INT + | D_ENABLE enable_args + | D_PRINT { want_nodeval = true; } print_args + | D_PRINTF { want_nodeval = true; } printf_args + | D_LIST list_args + | D_UNTIL location + | D_CLEAR location + | break_cmd break_args + | D_SET { want_nodeval = true; } variable '=' node + | D_OPTION option_args + | D_RETURN { want_nodeval = true; } opt_node + | D_DISPLAY { want_nodeval = true; } opt_variable + | D_WATCH { want_nodeval = true; } variable condition_exp + | d_cmd opt_integer_list + | D_DUMP opt_string + | D_SOURCE D_STRING + { + if (in_cmd_src($2->a_string)) + yyerror(_("source \"%s\": already sourced."), $2->a_string); + } + | D_SAVE D_STRING + { + if (! input_from_tty) + yyerror(_("save \"%s\": command not permitted."), $2->a_string); + } + | D_COMMANDS commands_arg + { + int type = 0; + int num; + + if ($2 != NULL) + num = $2->a_int; + + if (errcount != 0) + ; + else if (in_commands) + yyerror(_("Can't use command `commands' for breakpoint/watchpoint commands")); + else if ($2 == NULL && ! (type = has_break_or_watch_point(&num, true))) + yyerror(_("no breakpoint/watchpoint has been set yet")); + else if ($2 != NULL && ! (type = has_break_or_watch_point(&num, false))) + yyerror(_("invalid breakpoint/watchpoint number")); + if (type) { + in_commands = true; + if (input_from_tty) { + 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")); + } + } + } + | D_END + { + if (! in_commands) + yyerror(_("`end' valid only in command `commands' or `eval'")); + else { + if (input_from_tty) + dbg_prompt = dgawk_prompt; + in_commands = false; + } + } + | D_SILENT + { + if (! in_commands) + yyerror(_("`silent' valid only in command `commands'")); + } + | D_TRACE D_STRING + { + int idx = find_argument($2); + if (idx < 0) + yyerror(_("trace: invalid option - \"%s\""), $2->a_string); + else { + efree($2->a_string); + $2->a_string = NULL; + $2->type = D_argument; + $2->a_argument = argtab[idx].value; + } + } + | D_CONDITION plus_integer { want_nodeval = true; } condition_exp + { + int type; + int num = $2->a_int; + type = has_break_or_watch_point(&num, false); + if (! type) + yyerror(_("condition: invalid breakpoint/watchpoint number")); + } + | eval_cmd + { + if (in_commands) { + /* Prepend command 'eval' to argument list */ + CMDARG *arg; + arg = mk_cmdarg(D_string); + arg->a_string = estrdup("eval", 4); + arg->next = arg_list; + arg_list = arg; + } + } + ; + +condition_exp + : opt_string_node + { + if ($1 != NULL) { + NODE *n = $1->a_node; + $1->type = D_string; + $1->a_string = n->stptr; + freenode(n); + } + $$ = $1; + } + ; + +commands_arg + : opt_plus_integer + | error + { $$ = NULL; } + ; + +opt_param_list + : /* empty */ + { $$ = NULL; } + | param_list + ; + +param_list + : D_VARIABLE + | param_list D_VARIABLE + | param_list ',' D_VARIABLE + | error + { $$ = NULL; } + ; + +opt_string_node + : /* empty */ + { $$ = NULL; } + | string_node + | error + { $$ = NULL; } + ; + +string_node + : D_NODE + { + NODE *n; + n = $1->a_node; + if ((n->flags & STRING) == 0) + yyerror(_("argument not a string")); + } + ; + +option_args + : /* empty */ + { $$ = NULL; } + | D_STRING + { + if (find_option($1->a_string) < 0) + yyerror(_("option: invalid parameter - \"%s\""), $1->a_string); + } + | D_STRING '=' D_STRING + { + if (find_option($1->a_string) < 0) + yyerror(_("option: invalid parameter - \"%s\""), $1->a_string); + } + ; + +func_name + : D_STRING + { + NODE *n; + n = lookup($1->a_string); + if (n == NULL || n->type != Node_func) + yyerror(_("no such function - \"%s\""), $1->a_string); + else { + $1->type = D_func; + efree($1->a_string); + $1->a_string = NULL; + $1->a_node = n; + } + } + ; + +location + : /* empty */ + { $$ = NULL; } + | plus_integer + | func_name + | D_STRING ':' plus_integer + | D_STRING ':' func_name + ; + +break_args + : /* empty */ + { $$ = NULL; } + | plus_integer { want_nodeval = true; } condition_exp + | func_name + | D_STRING ':' plus_integer { want_nodeval = true; } condition_exp + | D_STRING ':' func_name + ; + +opt_variable + : /* empty */ + { $$ = NULL; } + | variable + ; + +opt_string + : /* empty */ + { $$ = NULL; } + | D_STRING + ; + +opt_node + : /* empty */ + { $$ = NULL; } + | node + ; + +help_args + : /* empty */ + | D_STRING + ; + +enable_args + : opt_integer_list + | D_STRING opt_integer_list + { + int idx = find_argument($1); + if (idx < 0) + yyerror(_("enable: invalid option - \"%s\""), $1->a_string); + else { + efree($1->a_string); + $1->a_string = NULL; + $1->type = D_argument; + $1->a_argument = argtab[idx].value; + } + } + ; + +print_exp + : variable + | '@' D_VARIABLE + { + $2->type = D_array; /* dump all items */ + $2->a_count = 0; + } + | '@' D_VARIABLE subscript_list /* dump sub-array items*/ + { + $2->type = D_array; + $2->a_count = num_dim; + } + ; + +print_args + : print_exp + | print_args print_exp + | print_args ',' print_exp + | error + ; + +printf_exp + : D_NODE + | variable + ; + +printf_args + : printf_exp + | printf_args ',' printf_exp + | error + ; + +list_args + : /* empty */ + { $$ = NULL; } + | '+' + { $$ = NULL; } + | '-' + { + CMDARG *a; + a = mk_cmdarg(D_int); + a->a_int = -1; + append_cmdarg(a); + } + | plus_integer + | func_name + | integer_range + | D_STRING ':' plus_integer + | D_STRING ':' func_name + | D_STRING ':' integer_range + ; + +integer_range + : plus_integer '-' plus_integer + { + if ($1->a_int > $3->a_int) + yyerror(_("invalid range specification: %d - %d"), + $1->a_int, $3->a_int); + else + $1->type = D_range; + $$ = $1; + } + ; + +opt_integer_list + : /* empty */ + { $$ = NULL; } + | integer_list + | error + ; + +integer_list + : plus_integer + | integer_range + | integer_list plus_integer + | integer_list integer_range + ; + +exp_list + : node + { $$ = $1; } + | exp_list ',' node + { $$ = $1; } + | error + ; + +subscript + : '[' exp_list ']' + { + CMDARG *a; + NODE *subs; + int count = 0; + + for (a = $2; a != NULL; a = a->next) + count++; + subs = concat_args($2, count); + free_cmdarg($2->next); + $2->next = NULL; + $2->type = D_node; + $2->a_node = subs; + $$ = $2; + } + | '[' exp_list error + ; + +subscript_list + : subscript + { $$ = $1; num_dim = 1; } + | subscript_list subscript + { $$ = $1; num_dim++; } + ; + +variable + : D_VARIABLE + | '$' D_NODE + { + NODE *n = $2->a_node; + if ((n->flags & NUMBER) == 0) + yyerror(_("non-numeric value for field number")); + else + $2->type = D_field; + $$ = $2; + } + | D_VARIABLE subscript_list + { + /* a_string is array name, a_count is dimension count */ + $1->type = D_subscript; + $1->a_count = num_dim; + $$ = $1; + } + ; + +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")); + else + negate_num(n); + $$ = $2; + } + ; + +opt_plus_integer + : /* empty */ + { $$ = NULL; } + | plus_integer + { $$ = $1; } + ; + +opt_integer + : /* empty */ + { $$ = NULL; } + | integer + { $$ = $1; } + ; + +plus_integer + : D_INT + { + if ($1->a_int == 0) + yyerror(_("non-zero integer value")); + $$ = $1; + } + | '+' D_INT + { + if ($2->a_int == 0) + yyerror(_("non-zero integer value")); + $$ = $2; + } + ; + +integer + : D_INT + { $$ = $1; } + | '+' D_INT + { $$ = $2; } + | '-' D_INT + { + $2->a_int = - $2->a_int; + $$ = $2; + } + ; + +nls + : '\n' + { + if (lexptr_begin != NULL) { + if (input_from_tty && lexptr_begin[0] != '\0') + add_history(lexptr_begin); + efree(lexptr_begin); + lexptr_begin = NULL; + } + } + ; + +%% + + +/* append_statement --- append 'stmt' to the list of eval awk statements */ + +static CMDARG * +append_statement(CMDARG *stmt_list, char *stmt) +{ + CMDARG *a, *arg; + char *s; + int len, slen, ssize; + +#define EVALSIZE 512 + + if (stmt == start_EVAL) { + len = sizeof(start_EVAL); + for (a = stmt_list; a != NULL; a = a->next) + len += strlen(a->a_string) + 1; /* 1 for ',' */ + len += EVALSIZE; + + emalloc(s, char *, (len + 1) * sizeof(char), "append_statement"); + arg = mk_cmdarg(D_string); + arg->a_string = s; + arg->a_count = len; /* kludge */ + + slen = sizeof("function @eval(") - 1; + memcpy(s, start_EVAL, slen); + + for (a = stmt_list; a != NULL; a = a->next) { + len = strlen(a->a_string); + memcpy(s + slen, a->a_string, len); + slen += len; + if (a->next != NULL) + s[slen++] = ','; + } + s[slen++] = ')'; + s[slen++] = '{'; + 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 + 1) * sizeof(char), "append_statement"); + stmt_list->a_string = s; + stmt_list->a_count = ssize; + } + memcpy(s + slen, stmt, len); + slen += len; + if (slen >= 2 && s[slen - 2] != '\n') { + s[slen - 1] = '\n'; + s[slen] = '\0'; + } + + if (stmt == end_EVAL) + erealloc(stmt_list->a_string, char *, slen + 1, "append_statement"); + return stmt_list; + +#undef EVALSIZE +} + + +/* command names sorted in ascending order */ + +struct cmdtoken cmdtab[] = { +{ "backtrace", "bt", D_backtrace, D_BACKTRACE, do_backtrace, + gettext_noop("backtrace [N] - print trace of all or N innermost (outermost if N < 0) frames.") }, +{ "break", "b", D_break, D_BREAK, do_breakpoint, + gettext_noop("break [[filename:]N|function] - set breakpoint at the specified location.") }, +{ "clear", "", D_clear, D_CLEAR, do_clear, + gettext_noop("clear [[filename:]N|function] - delete breakpoints previously set.") }, +{ "commands", "", D_commands, D_COMMANDS, do_commands, + gettext_noop("commands [num] - starts a list of commands to be executed at a breakpoint(watchpoint) hit.") }, +{ "condition", "", D_condition, D_CONDITION, do_condition, + gettext_noop("condition num [expr] - set or clear breakpoint or watchpoint condition.") }, +{ "continue", "c", D_continue, D_CONTINUE, do_continue, + gettext_noop("continue [COUNT] - continue program being debugged.") }, +{ "delete", "d", D_delete, D_DELETE, do_delete_breakpoint, + gettext_noop("delete [breakpoints] [range] - delete specified breakpoints.") }, +{ "disable", "", D_disable, D_DISABLE, do_disable_breakpoint, + gettext_noop("disable [breakpoints] [range] - disable specified breakpoints.") }, +{ "display", "", D_display, D_DISPLAY, do_display, + gettext_noop("display [var] - print value of variable each time the program stops.") }, +{ "down", "", D_down, D_DOWN, do_down, + gettext_noop("down [N] - move N frames down the stack.") }, +{ "dump", "", D_dump, D_DUMP, do_dump_instructions, + gettext_noop("dump [filename] - dump instructions to file or stdout.") }, +{ "enable", "e", D_enable, D_ENABLE, do_enable_breakpoint, + gettext_noop("enable [once|del] [breakpoints] [range] - enable specified breakpoints.") }, +{ "end", "", D_end, D_END, do_commands, + gettext_noop("end - end a list of commands or awk statements.") }, +{ "eval", "", D_eval, D_EVAL, do_eval, + gettext_noop("eval stmt|[p1, p2, ...] - evaluate awk statement(s).") }, +{ "exit", "", D_quit, D_QUIT, do_quit, + gettext_noop("exit - (same as quit) exit debugger.") }, +{ "finish", "", D_finish, D_FINISH, do_finish, + gettext_noop("finish - execute until selected stack frame returns.") }, +{ "frame", "f", D_frame, D_FRAME, do_frame, + gettext_noop("frame [N] - select and print stack frame number N.") }, +{ "help", "h", D_help, D_HELP, do_help, + gettext_noop("help [command] - print list of commands or explanation of command.") }, +{ "ignore", "", D_ignore, D_IGNORE, do_ignore_breakpoint, + gettext_noop("ignore N COUNT - set ignore-count of breakpoint number N to COUNT.") }, +{ "info", "i", D_info, D_INFO, do_info, + gettext_noop("info topic - source|sources|variables|functions|break|frame|args|locals|display|watch.") }, +{ "list", "l", D_list, D_LIST, do_list, + gettext_noop("list [-|+|[filename:]lineno|function|range] - list specified line(s).") }, +{ "next", "n", D_next, D_NEXT, do_next, + gettext_noop("next [COUNT] - step program, proceeding through subroutine calls.") }, +{ "nexti", "ni", D_nexti, D_NEXTI, do_nexti, + gettext_noop("nexti [COUNT] - step one instruction, but proceed through subroutine calls.") }, +{ "option", "o", D_option, D_OPTION, do_option, + gettext_noop("option [name[=value]] - set or display debugger option(s).") }, +{ "print", "p", D_print, D_PRINT, do_print_var, + gettext_noop("print var [var] - print value of a variable or array.") }, +{ "printf", "", D_printf, D_PRINTF, do_print_f, + gettext_noop("printf format, [arg], ... - formatted output.") }, +{ "quit", "q", D_quit, D_QUIT, do_quit, + gettext_noop("quit - exit debugger.") }, +{ "return", "", D_return, D_RETURN, do_return, + gettext_noop("return [value] - make selected stack frame return to its caller.") }, +{ "run", "r", D_run, D_RUN, do_run, + gettext_noop("run - start or restart executing program.") }, +#ifdef HAVE_LIBREADLINE +{ "save", "", D_save, D_SAVE, do_save, + gettext_noop("save filename - save commands from the session to file.") }, +#endif +{ "set", "", D_set, D_SET, do_set_var, + gettext_noop("set var = value - assign value to a scalar variable.") }, +{ "silent", "", D_silent, D_SILENT, do_commands, + gettext_noop("silent - suspends usual message when stopped at a breakpoint/watchpoint.") }, +{ "source", "", D_source, D_SOURCE, do_source, + gettext_noop("source file - execute commands from file.") }, +{ "step", "s", D_step, D_STEP, do_step, + gettext_noop("step [COUNT] - step program until it reaches a different source line.") }, +{ "stepi", "si", D_stepi, D_STEPI, do_stepi, + gettext_noop("stepi [COUNT] - step one instruction exactly.") }, +{ "tbreak", "t", D_tbreak, D_TBREAK, do_tmp_breakpoint, + gettext_noop("tbreak [[filename:]N|function] - set a temporary breakpoint.") }, +{ "trace", "", D_trace, D_TRACE, do_trace_instruction, + gettext_noop("trace on|off - print instruction before executing.") }, +{ "undisplay", "", D_undisplay, D_UNDISPLAY, do_undisplay, + gettext_noop("undisplay [N] - remove variable(s) from automatic display list.") }, +{ "until", "u", D_until, D_UNTIL, do_until, + gettext_noop("until [[filename:]N|function] - execute until program reaches a different line or line N within current frame.") }, +{ "unwatch", "", D_unwatch, D_UNWATCH, do_unwatch, + gettext_noop("unwatch [N] - remove variable(s) from watch list.") }, +{ "up", "", D_up, D_UP, do_up, + gettext_noop("up [N] - move N frames up the stack.") }, +{ "watch", "w", D_watch, D_WATCH, do_watch, + gettext_noop("watch var - set a watchpoint for a variable.") }, +{ "where", "", D_backtrace, D_BACKTRACE, do_backtrace, + gettext_noop("where [N] - (same as backtrace) print trace of all or N innermost (outermost if N < 0) frames.") }, +{ NULL, NULL, D_illegal, 0, (Func_cmd) 0, + NULL }, +}; + +struct argtoken argtab[] = { + { "args", D_info, A_ARGS }, + { "break", D_info, A_BREAK }, + { "del", D_enable, A_DEL }, + { "display", D_info, A_DISPLAY }, + { "frame", D_info, A_FRAME }, + { "functions", D_info, A_FUNCTIONS }, + { "locals", D_info, A_LOCALS }, + { "off", D_trace, A_TRACE_OFF }, + { "on", D_trace, A_TRACE_ON }, + { "once", D_enable, A_ONCE }, + { "source", D_info, A_SOURCE }, + { "sources", D_info, A_SOURCES }, + { "variables", D_info, A_VARIABLES }, + { "watch", D_info, A_WATCH }, + { NULL, D_illegal, A_NONE }, +}; + + +/* get_command --- return command handler function */ + +Func_cmd +get_command(int ctype) +{ + int i; + for (i = 0; cmdtab[i].name != NULL; i++) { + if (cmdtab[i].type == ctype) + return cmdtab[i].cf_ptr; + } + return (Func_cmd) 0; +} + +/* get_command_name --- return command name given it's type */ + +const char * +get_command_name(int ctype) +{ + int i; + for (i = 0; cmdtab[i].name != NULL; i++) { + if (cmdtab[i].type == ctype) + return cmdtab[i].name; + } + return NULL; +} + +/* mk_cmdarg --- make an argument for command */ + +static CMDARG * +mk_cmdarg(enum argtype type) +{ + CMDARG *arg; + 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) +{ + static CMDARG *savetail; + + if (arg_list == NULL) + arg_list = arg; + else + savetail->next = arg; + savetail = arg; +} + +/* free_cmdarg --- free all arguments in LIST */ + +void +free_cmdarg(CMDARG *list) +{ + CMDARG *arg, *nexta; + + for (arg = list; arg != NULL; arg = nexta) { + nexta = arg->next; + + switch (arg->type) { + case D_variable: + case D_subscript: + case D_array: + case D_string: + if (arg->a_string != NULL) + efree(arg->a_string); + break; + case D_node: + case D_field: + unref(arg->a_node); + break; + default: + break; + } + efree(arg); + } +} + +/* yyerror --- print a syntax error message */ + +static void +yyerror(const char *mesg, ...) +{ + va_list args; + va_start(args, mesg); + fprintf(out_fp, _("error: ")); + vfprintf(out_fp, mesg, args); + fprintf(out_fp, "\n"); + va_end(args); + errcount++; + repeat_idx = -1; +} + + +/* yylex --- read a command and turn it into tokens */ + +static int +#ifdef USE_EBCDIC +yylex_ebcdic(void) +#else +yylex(void) +#endif +{ + static char *lexptr = NULL; + static char *lexend; + int c; + char *tokstart; + size_t toklen; + + yylval = (CMDARG *) NULL; + + if (errcount > 0 && lexptr_begin == NULL) { + /* fake a new line */ + errcount = 0; + return '\n'; + } + + if (lexptr_begin == NULL) { +again: + lexptr_begin = read_a_line(dbg_prompt); + if (lexptr_begin == NULL) { /* EOF or error */ + if (get_eof_status() == EXIT_FATAL) + exit(EXIT_FATAL); + if (get_eof_status() == EXIT_FAILURE) { + static int seen_eof = 0; + + /* force a quit, and let do_quit (in debug.c) exit */ + if (! seen_eof) { + if (errno != 0) { + fprintf(stderr, _("can't read command (%s)\n"), strerror(errno)); + exit_val = EXIT_FAILURE; + } /* else + exit_val = EXIT_SUCCESS; */ + + seen_eof = 1; + return '\n'; /* end current command if any */ + } else if (seen_eof++ == 1) { + cmd_idx = find_command("quit", 4); + return D_QUIT; /* 'quit' token */ + } else + return '\n'; /* end command 'quit' */ + } + if (errno != 0) + d_error(_("can't read command (%s)"), strerror(errno)); + if (pop_cmd_src() == 0) + goto again; + exit(EXIT_FATAL); /* shouldn't happen */ + } + + if (! in_commands && ! in_eval /* history expansion off in 'commands' and 'eval' */ + && input_from_tty + ) + history_expand_line(&lexptr_begin); + + lexptr = lexptr_begin; + lexend = lexptr + strlen(lexptr); + if (*lexptr == '\0' /* blank line */ + && repeat_idx >= 0 + && input_from_tty + && ! in_eval + ) { +#ifdef HAVE_LIBREADLINE + HIST_ENTRY *h; + h = previous_history(); + if (h != NULL) + add_history(h->line); +#endif + cmd_idx = repeat_idx; + return cmdtab[cmd_idx].class; /* repeat last command */ + } + repeat_idx = -1; + } + + c = *lexptr; + + while (c == ' ' || c == '\t') + c = *++lexptr; + + if (! input_from_tty && c == '#') + return '\n'; + + tokstart = lexptr; + if (lexptr >= lexend) + return '\n'; + + if (cmd_idx < 0) { /* need a command */ + if (c == '?' && tokstart[1] == '\0' && ! in_eval) { + lexptr++; + cmd_idx = find_command("help", 4); + return D_HELP; + } + + while (c != '\0' && c != ' ' && c != '\t') { + if (! is_alpha(c) && ! in_eval) { + yyerror(_("invalid character in command")); + return '\n'; + } + c = *++lexptr; + } + + toklen = lexptr - tokstart; + + if (in_eval) { + if (toklen == 3 + && tokstart[3] == '\0' + && tokstart[0] == 'e' + && tokstart[1] == 'n' + && tokstart[2] == 'd' + ) { + cmd_idx = find_command(tokstart, toklen); + return D_END; + } + lexptr = lexend; + return D_STATEMENT; + } + + cmd_idx = find_command(tokstart, toklen); + if (cmd_idx >= 0) { + if (in_commands && cmdtab[cmd_idx].type != D_eval) { + /* add the actual command string (lexptr_begin) to + * arg_list; command string for 'eval' prepended to the arg_list + * in the grammer above (see eval_cmd non-terminal). + */ + CMDARG *arg; + arg = mk_cmdarg(D_string); + arg->a_string = estrdup(lexptr_begin, lexend - lexptr_begin); + append_cmdarg(arg); + } + return cmdtab[cmd_idx].class; + } else { + yyerror(_("unknown command - \"%.*s\", try help"), toklen, tokstart); + return '\n'; + } + } + + c = *lexptr; + + if (cmdtab[cmd_idx].type == D_option) { + if (c == '=') + return *lexptr++; + } else if (c == '-' || c == '+' || c == ':' || c == '|') + return *lexptr++; + + if (c == '"') { + char *str, *p; + int flags = ALREADY_MALLOCED; + bool esc_seen = false; + + toklen = lexend - lexptr; + emalloc(str, char *, toklen + 1, "yylex"); + p = str; + + while ((c = *++lexptr) != '"') { + if (lexptr == lexend) { +err: + efree(str); + yyerror(_("unterminated string")); + return '\n'; + } + if (c == '\\') { + c = *++lexptr; + esc_seen = true; + if (want_nodeval || c != '"') + *p++ = '\\'; + } + if (lexptr == lexend) + goto err; + *p++ = c; + } + lexptr++; + *p = '\0'; + + if (! want_nodeval) { + yylval = mk_cmdarg(D_string); + yylval->a_string = str; + append_cmdarg(yylval); + return D_STRING; + } else { /* awk string */ + if (esc_seen) + flags |= SCAN; + yylval = mk_cmdarg(D_node); + yylval->a_node = make_str_node(str, p - str, flags); + append_cmdarg(yylval); + return D_NODE; + } + } + + if (! want_nodeval) { + while ((c = *++lexptr) != '\0' && c != ':' && c != '-' + && c != ' ' && c != '\t' && c != '=') + ; + + /* Is it an integer? */ + if (isdigit((unsigned char) tokstart[0]) && cmdtab[cmd_idx].type != D_option) { + char *end; + long l; + + errno = 0; + l = strtol(tokstart, &end, 0); + if (errno != 0) { + yyerror(_("%s"), strerror(errno)); + errno = 0; + return '\n'; + } + + if (lexptr == end) { + yylval = mk_cmdarg(D_int); + yylval->a_int = l; + append_cmdarg(yylval); + return D_INT; + } + } + + /* Must be string */ + yylval = mk_cmdarg(D_string); + yylval->a_string = estrdup(tokstart, lexptr - tokstart); + append_cmdarg(yylval); + return D_STRING; + } + + /* look for awk number */ + + if (isdigit((unsigned char) tokstart[0])) { + NODE *r = NULL; + + errno = 0; +#ifdef HAVE_MPFR + if (do_mpfr) { + int tval; + r = mpg_float(); + tval = mpfr_strtofr(r->mpg_numbr, tokstart, & lexptr, 0, ROUND_MODE); + IEEE_FMT(r->mpg_numbr, tval); + if (mpfr_integer_p(r->mpg_numbr)) { + /* integral value, convert to a GMP type. */ + NODE *tmp = r; + r = mpg_integer(); + mpfr_get_z(r->mpg_i, tmp->mpg_numbr, MPFR_RNDZ); + unref(tmp); + } + } else +#endif + r = make_number(strtod(tokstart, & lexptr)); + + if (errno != 0) { + yyerror(strerror(errno)); + unref(r); + errno = 0; + return '\n'; + } + yylval = mk_cmdarg(D_node); + yylval->a_node = r; + append_cmdarg(yylval); + return D_NODE; + } + + c = *lexptr; + if (c == '$' || c == '@' + || c == '[' || c == ']' + || c == ',' || c == '=') + return *lexptr++; + + if (! is_letter(c)) { + yyerror(_("invalid character")); + return '\n'; + } + + while (is_identchar(c)) + c = *++lexptr; + toklen = lexptr - tokstart; + + /* awk variable */ + yylval = mk_cmdarg(D_variable); + yylval->a_string = estrdup(tokstart, toklen); + append_cmdarg(yylval); + return D_VARIABLE; +} + +/* Convert single-character tokens coming out of yylex() from EBCDIC to + ASCII values on-the-fly so that the parse tables need not be regenerated + for EBCDIC systems. */ +#ifdef USE_EBCDIC +static int +yylex(void) +{ + static char etoa_xlate[256]; + static int do_etoa_init = 1; + int tok; + + if (do_etoa_init) + { + for (tok = 0; tok < 256; tok++) + etoa_xlate[tok] = (char) tok; +#ifdef HAVE___ETOA_L + /* IBM helpfully provides this function. */ + __etoa_l(etoa_xlate, sizeof(etoa_xlate)); +#else +# error "An EBCDIC-to-ASCII translation function is needed for this system" +#endif + do_etoa_init = 0; + } + + tok = yylex_ebcdic(); + + if (tok >= 0 && tok <= 0xFF) + tok = etoa_xlate[tok]; + + return tok; +} +#endif /* USE_EBCDIC */ + +/* find_argument --- find index in 'argtab' for a command option */ + +static int +find_argument(CMDARG *arg) +{ + /* non-number argument */ + int idx; + char *name, *p; + size_t len; + assert(cmd_idx >= 0); + name = arg->a_string; + len = strlen(name); + for (idx = 0; (p = (char *) argtab[idx].name) != NULL; idx++) { + if (cmdtab[cmd_idx].type == argtab[idx].cmd + && *p == *name + && strlen(p) == len + && strncmp(p, name, len) == 0 + ) + return idx; + } + return -1; /* invalid option */ +} + +/* concat_args --- concatenate argument strings into a single string NODE */ + +static NODE * +concat_args(CMDARG *arg, int count) +{ + NODE *n; + NODE **tmp; + char *str, *subsep, *p; + long len, subseplen; + int i; + + if (count == 1) { + 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; + len = -subseplen; + + for (i = 0; i < count; i++) { + n = force_string(arg->a_node); + len += n->stlen + subseplen; + tmp[i] = n; + arg = arg->next; + } + + emalloc(str, char *, len + 1, "concat_args"); + n = tmp[0]; + memcpy(str, n->stptr, n->stlen); + p = str + n->stlen; + for (i = 1; i < count; i++) { + if (subseplen == 1) + *p++ = *subsep; + else if (subseplen > 0) { + memcpy(p, subsep, subseplen); + p += subseplen; + } + + n = tmp[i]; + memcpy(p, n->stptr, n->stlen); + p += n->stlen; + } + str[len] = '\0'; + efree(tmp); + return make_str_node(str, len, ALREADY_MALLOCED); +} + +/* find_command --- find the index in 'cmdtab' using exact, + * abbreviation or unique partial match + */ + +static int +find_command(const char *token, size_t toklen) +{ + char *name, *abrv; + int i, k; + bool try_exact = true; + int abrv_match = -1; + int partial_match = -1; + +#if 'a' == 0x81 /* it's EBCDIC */ + /* make sure all lower case characters in token (sorting + * isn't the solution in this case) + */ + for (i = 0; i < toklen; i++) { + if (token[i] != tolower(token[i])) + return -1; + } +#endif + + k = sizeof(cmdtab)/sizeof(cmdtab[0]) - 1; + for (i = 0; i < k; i++) { + name = (char *) cmdtab[i].name; + if (try_exact && *token == *name + && toklen == strlen(name) + && strncmp(name, token, toklen) == 0 + ) + return i; + + if (*name > *token || i == (k - 1)) + try_exact = false; + + if (abrv_match < 0) { + abrv = cmdtab[i].abbrvn; + if (abrv[0] == token[0]) { + if (toklen == 1 && ! abrv[1]) + abrv_match = i; + else if (toklen == 2 && abrv[1] == token[1]) + abrv_match = i; + } + } + if (! try_exact && abrv_match >= 0) + return abrv_match; + if (partial_match < 0) { + if (*token == *name + && toklen < strlen(name) + && strncmp(name, token, toklen) == 0 + ) { + if ((i == k - 1 || strncmp(cmdtab[i + 1].name, token, toklen) != 0) + && (i == 0 || strncmp(cmdtab[i - 1].name, token, toklen) != 0) + ) + partial_match = i; + } + } + } + return partial_match; +} + +/* do_help -- help command */ + +int +do_help(CMDARG *arg, int cmd) +{ + int i; + if (arg == NULL) { + initialize_pager(out_fp); + if (setjmp(pager_quit_tag) == 0) { + for (i = 0; cmdtab[i].name != NULL; i++) { + gprintf(out_fp, "%s:\n", cmdtab[i].name); + gprintf(out_fp, "\t%s\n", _(cmdtab[i].help_txt)); + } + } + } else if (arg->type == D_string) { + char *name; + name = arg->a_string; + i = find_command(name, strlen(name)); + if (i >= 0) { + fprintf(out_fp, "%s\n", cmdtab[i].help_txt); + if (strcmp(cmdtab[i].name, "option") == 0) + option_help(); + } else + fprintf(out_fp, _("undefined command: %s\n"), name); + } + + return false; +} + + +#ifdef HAVE_LIBREADLINE + +/* 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) +{ + char *q; + int i; + + if (p == NULL || len <= 0) + return NULL; + for (i = 0; i < len; i++, p++) + if (*p != ' ' && *p != '\t') + break; + if (i == len) + return NULL; + if (endp != NULL) { + for (i++, q = p + 1; i < len; i++, q++) + if (*q == ' ' || *q == '\t') + break; + *endp = q; + } + return p; +} + +/* command_completion --- attempt to complete based on the word number in line; + * try to complete on command names if this is the first word; for the next + * word(s), the type of completion depends on the command name (first word). + */ + +#ifndef RL_READLINE_VERSION /* < 4.2a */ +#define rl_completion_matches(x, y) completion_matches((char *) (x), (y)) +#endif + + +char ** +command_completion(const char *text, int start, int end) +{ + char *cmdtok, *e; + int idx; + int len; + + rl_attempted_completion_over = true; /* no default filename completion please */ + + this_cmd = D_illegal; + len = start; + if ((cmdtok = next_word(rl_line_buffer, len, &e)) == NULL) /* no first word yet */ + return rl_completion_matches(text, command_generator); + len -= (e - rl_line_buffer); + + idx = find_command(cmdtok, e - cmdtok); + if (idx < 0) + return NULL; + this_cmd = cmdtab[idx].type; + + if (! next_word(e, len, NULL)) { + switch (this_cmd) { + case D_break: + case D_list: + case D_until: + case D_tbreak: + case D_clear: + return rl_completion_matches(text, srcfile_generator); + case D_info: + case D_enable: + case D_trace: + case D_help: + return rl_completion_matches(text, argument_generator); + case D_option: + return rl_completion_matches(text, option_generator); + case D_print: + case D_printf: + case D_set: + case D_display: + case D_watch: + return rl_completion_matches(text, variable_generator); + default: + return NULL; + } + } + + 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) +{ + static size_t textlen; + static int idx = 0; + char *name; + + if (! state) { /* first time */ + textlen = strlen(text); + idx = 0; + } + while ((name = (char *) cmdtab[idx].name) != NULL) { + idx++; + if (strncmp(name, text, textlen) == 0) + return estrdup(name, strlen(name)); + } + return NULL; +} + +/* srcfile_generator --- generator function for source file completion */ + +static char * +srcfile_generator(const char *text, int state) +{ + static size_t textlen; + static SRCFILE *s; + char *name; + extern SRCFILE *srcfiles; + + if (! state) { /* first time */ + textlen = strlen(text); + s = srcfiles->next; + } + while (s != srcfiles) { + if (s->stype != SRC_FILE && s->stype != SRC_INC) { + s = s->next; + continue; + } + name = s->src; + s = s->next; + if (strncmp(name, text, textlen) == 0) + return estrdup(name, strlen(name)); + } + return NULL; +} + +/* argument_generator --- generator function for non-number argument completion */ + +static char * +argument_generator(const char *text, int state) +{ + static size_t textlen; + static int idx; + const char *name; + + if (! state) { /* first time */ + textlen = strlen(text); + idx = 0; + } + + if (this_cmd == D_help) { + while ((name = cmdtab[idx++].name) != NULL) { + if (strncmp(name, text, textlen) == 0) + return estrdup(name, strlen(name)); + } + } else { + while ((name = argtab[idx].name) != NULL) { + if (this_cmd != argtab[idx++].cmd) + continue; + if (strncmp(name, text, textlen) == 0) + return estrdup(name, strlen(name)); + } + } + return NULL; +} + +/* variable_generator --- generator function for variable name completion */ + +static char * +variable_generator(const char *text, int state) +{ + static size_t textlen; + static int idx = 0; + static NODE *func = NULL; + static NODE **vars = NULL; + const char *name; + NODE *r; + + if (! state) { /* first time */ + textlen = strlen(text); + if (vars != NULL) + efree(vars); + vars = variable_list(); + idx = 0; + func = get_function(); /* function in current context */ + } + + /* function params */ + while (func != NULL) { + if (idx >= func->param_cnt) { + func = NULL; /* don't try to match params again */ + idx = 0; + break; + } + name = func->fparms[idx++].param; + if (strncmp(name, text, textlen) == 0) + return estrdup(name, strlen(name)); + } + + /* globals */ + while ((r = vars[idx++]) != NULL) { + name = r->vname; + if (strncmp(name, text, textlen) == 0) + return estrdup(name, strlen(name)); + } + + return NULL; +} + +/* history_expand_line --- history expand the LINE */ + +static void +history_expand_line(char **line) +{ + int ret; + char *expansion; + + if (! *line || input_fd != 0 || ! input_from_tty) + return; + using_history(); + ret = history_expand(*line, &expansion); + if (ret < 0 || ret == 2) + efree(expansion); + else { + efree(*line); + *line = expansion; + } +} + +#endif diff --git a/compile b/compile new file mode 100755 index 0000000..0bb9d0f --- /dev/null +++ b/compile @@ -0,0 +1,348 @@ +#! /bin/sh +# Wrapper for compilers which do not understand '-c -o'. + +scriptversion=2017-09-16.17; # UTC + +# Copyright (C) 1999-2018 Free Software Foundation, Inc. +# Written by Tom Tromey . +# +# 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 2, 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 . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +nl=' +' + +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent tools from complaining about whitespace usage. +IFS=" "" $nl" + +file_conv= + +# func_file_conv build_file lazy +# Convert a $build file to $host form and store it in $file +# Currently only supports Windows hosts. If the determined conversion +# type is listed in (the comma separated) LAZY, no conversion will +# take place. +func_file_conv () +{ + file=$1 + case $file in + / | /[!/]*) # absolute file, and not a UNC file + if test -z "$file_conv"; then + # lazily determine how to convert abs files + case `uname -s` in + MINGW*) + file_conv=mingw + ;; + CYGWIN*) + file_conv=cygwin + ;; + *) + file_conv=wine + ;; + esac + fi + case $file_conv/,$2, in + *,$file_conv,*) + ;; + mingw/*) + file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` + ;; + cygwin/*) + file=`cygpath -m "$file" || echo "$file"` + ;; + wine/*) + file=`winepath -w "$file" || echo "$file"` + ;; + esac + ;; + esac +} + +# func_cl_dashL linkdir +# Make cl look for libraries in LINKDIR +func_cl_dashL () +{ + func_file_conv "$1" + if test -z "$lib_path"; then + lib_path=$file + else + lib_path="$lib_path;$file" + fi + linker_opts="$linker_opts -LIBPATH:$file" +} + +# func_cl_dashl library +# Do a library search-path lookup for cl +func_cl_dashl () +{ + lib=$1 + found=no + save_IFS=$IFS + IFS=';' + for dir in $lib_path $LIB + do + IFS=$save_IFS + if $shared && test -f "$dir/$lib.dll.lib"; then + found=yes + lib=$dir/$lib.dll.lib + break + fi + if test -f "$dir/$lib.lib"; then + found=yes + lib=$dir/$lib.lib + break + fi + if test -f "$dir/lib$lib.a"; then + found=yes + lib=$dir/lib$lib.a + break + fi + done + IFS=$save_IFS + + if test "$found" != yes; then + lib=$lib.lib + fi +} + +# func_cl_wrapper cl arg... +# Adjust compile command to suit cl +func_cl_wrapper () +{ + # Assume a capable shell + lib_path= + shared=: + linker_opts= + for arg + do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as 'compile cc -o foo foo.c'. + eat=1 + case $2 in + *.o | *.[oO][bB][jJ]) + func_file_conv "$2" + set x "$@" -Fo"$file" + shift + ;; + *) + func_file_conv "$2" + set x "$@" -Fe"$file" + shift + ;; + esac + ;; + -I) + eat=1 + func_file_conv "$2" mingw + set x "$@" -I"$file" + shift + ;; + -I*) + func_file_conv "${1#-I}" mingw + set x "$@" -I"$file" + shift + ;; + -l) + eat=1 + func_cl_dashl "$2" + set x "$@" "$lib" + shift + ;; + -l*) + func_cl_dashl "${1#-l}" + set x "$@" "$lib" + shift + ;; + -L) + eat=1 + func_cl_dashL "$2" + ;; + -L*) + func_cl_dashL "${1#-L}" + ;; + -static) + shared=false + ;; + -Wl,*) + arg=${1#-Wl,} + save_ifs="$IFS"; IFS=',' + for flag in $arg; do + IFS="$save_ifs" + linker_opts="$linker_opts $flag" + done + IFS="$save_ifs" + ;; + -Xlinker) + eat=1 + linker_opts="$linker_opts $2" + ;; + -*) + set x "$@" "$1" + shift + ;; + *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) + func_file_conv "$1" + set x "$@" -Tp"$file" + shift + ;; + *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) + func_file_conv "$1" mingw + set x "$@" "$file" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift + done + if test -n "$linker_opts"; then + linker_opts="-link$linker_opts" + fi + exec "$@" $linker_opts + exit 1 +} + +eat= + +case $1 in + '') + echo "$0: No command. Try '$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: compile [--help] [--version] PROGRAM [ARGS] + +Wrapper for compilers which do not understand '-c -o'. +Remove '-o dest.o' from ARGS, run PROGRAM with the remaining +arguments, and rename the output as expected. + +If you are trying to build a whole package this is not the +right script to run: please start by reading the file 'INSTALL'. + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "compile $scriptversion" + exit $? + ;; + cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \ + icl | *[/\\]icl | icl.exe | *[/\\]icl.exe ) + func_cl_wrapper "$@" # Doesn't return... + ;; +esac + +ofile= +cfile= + +for arg +do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as 'compile cc -o foo foo.c'. + # So we strip '-o arg' only if arg is an object. + eat=1 + case $2 in + *.o | *.obj) + ofile=$2 + ;; + *) + set x "$@" -o "$2" + shift + ;; + esac + ;; + *.c) + cfile=$1 + set x "$@" "$1" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift +done + +if test -z "$ofile" || test -z "$cfile"; then + # If no '-o' option was seen then we might have been invoked from a + # pattern rule where we don't need one. That is ok -- this is a + # normal compilation that the losing compiler can handle. If no + # '.c' file was seen then we are probably linking. That is also + # ok. + exec "$@" +fi + +# Name of file we expect compiler to create. +cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` + +# Create the lock directory. +# Note: use '[/\\:.-]' here to ensure that we don't use the same name +# that we are using for the .o file. Also, base the name on the expected +# object file name, since that is what matters with a parallel build. +lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d +while true; do + if mkdir "$lockdir" >/dev/null 2>&1; then + break + fi + sleep 1 +done +# FIXME: race condition here if user kills between mkdir and trap. +trap "rmdir '$lockdir'; exit 1" 1 2 15 + +# Run the compile. +"$@" +ret=$? + +if test -f "$cofile"; then + test "$cofile" = "$ofile" || mv "$cofile" "$ofile" +elif test -f "${cofile}bj"; then + test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" +fi + +rmdir "$lockdir" +exit $ret + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: "; # UTC" +# End: diff --git a/config.guess b/config.guess new file mode 100755 index 0000000..f50dcdb --- /dev/null +++ b/config.guess @@ -0,0 +1,1480 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright 1992-2018 Free Software Foundation, Inc. + +timestamp='2018-02-24' + +# 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 +# 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 . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). +# +# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. +# +# You can get the latest version of this script from: +# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess +# +# Please send patches to . + + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Options: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright 1992-2018 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." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > "$dummy.c" ; + for c in cc gcc c89 c99 ; do + if ($c -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +case "$UNAME_SYSTEM" in +Linux|GNU|GNU/*) + # If the system lacks a compiler, then just pick glibc. + # We could probably try harder. + LIBC=gnu + + eval "$set_cc_for_build" + cat <<-EOF > "$dummy.c" + #include + #if defined(__UCLIBC__) + LIBC=uclibc + #elif defined(__dietlibc__) + LIBC=dietlibc + #else + LIBC=gnu + #endif + EOF + eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`" + + # If ldd exists, use it to detect musl libc. + if command -v ldd >/dev/null && \ + ldd --version 2>&1 | grep -q ^musl + then + LIBC=musl + fi + ;; +esac + +# Note: order is significant - the case branches are not exclusive. + +case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ + "/sbin/$sysctl" 2>/dev/null || \ + "/usr/sbin/$sysctl" 2>/dev/null || \ + echo unknown)` + case "$UNAME_MACHINE_ARCH" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + earmv*) + arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` + machine="${arch}${endian}"-unknown + ;; + *) machine="$UNAME_MACHINE_ARCH"-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently (or will in the future) and ABI. + case "$UNAME_MACHINE_ARCH" in + earm*) + os=netbsdelf + ;; + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval "$set_cc_for_build" + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # Determine ABI tags. + case "$UNAME_MACHINE_ARCH" in + earm*) + expr='s/^earmv[0-9]/-eabi/;s/eb$//' + abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "$UNAME_VERSION" in + Debian*) + release='-gnu' + ;; + *) + release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "$machine-${os}${release}${abi}" + exit ;; + *:Bitrig:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` + echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE" + exit ;; + *:LibertyBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` + echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE" + exit ;; + *:MidnightBSD:*:*) + echo "$UNAME_MACHINE"-unknown-midnightbsd"$UNAME_RELEASE" + exit ;; + *:ekkoBSD:*:*) + echo "$UNAME_MACHINE"-unknown-ekkobsd"$UNAME_RELEASE" + exit ;; + *:SolidBSD:*:*) + echo "$UNAME_MACHINE"-unknown-solidbsd"$UNAME_RELEASE" + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd"$UNAME_RELEASE" + exit ;; + *:MirBSD:*:*) + echo "$UNAME_MACHINE"-unknown-mirbsd"$UNAME_RELEASE" + exit ;; + *:Sortix:*:*) + echo "$UNAME_MACHINE"-unknown-sortix + exit ;; + *:Redox:*:*) + echo "$UNAME_MACHINE"-unknown-redox + exit ;; + mips:OSF1:*.*) + echo mips-dec-osf1 + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE=alpha ;; + "EV4.5 (21064)") + UNAME_MACHINE=alpha ;; + "LCA4 (21066/21068)") + UNAME_MACHINE=alpha ;; + "EV5 (21164)") + UNAME_MACHINE=alphaev5 ;; + "EV5.6 (21164A)") + UNAME_MACHINE=alphaev56 ;; + "EV5.6 (21164PC)") + UNAME_MACHINE=alphapca56 ;; + "EV5.7 (21164PC)") + UNAME_MACHINE=alphapca57 ;; + "EV6 (21264)") + UNAME_MACHINE=alphaev6 ;; + "EV6.7 (21264A)") + UNAME_MACHINE=alphaev67 ;; + "EV6.8CB (21264C)") + UNAME_MACHINE=alphaev68 ;; + "EV6.8AL (21264B)") + UNAME_MACHINE=alphaev68 ;; + "EV6.8CX (21264D)") + UNAME_MACHINE=alphaev68 ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE=alphaev69 ;; + "EV7 (21364)") + UNAME_MACHINE=alphaev7 ;; + "EV7.9 (21364A)") + UNAME_MACHINE=alphaev79 ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo "$UNAME_MACHINE"-dec-osf"`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`" + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + exitcode=$? + trap '' 0 + exit $exitcode ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo "$UNAME_MACHINE"-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo "$UNAME_MACHINE"-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix"$UNAME_RELEASE" + exit ;; + arm*:riscos:*:*|arm*:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo "$UNAME_MACHINE"-ibm-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`" + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`" + exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux"$UNAME_RELEASE" + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval "$set_cc_for_build" + SUN_ARCH=i386 + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH=x86_64 + fi + fi + echo "$SUN_ARCH"-pc-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos"`echo "$UNAME_RELEASE"|sed -e 's/-/_/'`" + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos"$UNAME_RELEASE" + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos"$UNAME_RELEASE" + ;; + sun4) + echo sparc-sun-sunos"$UNAME_RELEASE" + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos"$UNAME_RELEASE" + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint"$UNAME_RELEASE" + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint"$UNAME_RELEASE" + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint"$UNAME_RELEASE" + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint"$UNAME_RELEASE" + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint"$UNAME_RELEASE" + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint"$UNAME_RELEASE" + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten"$UNAME_RELEASE" + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten"$UNAME_RELEASE" + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix"$UNAME_RELEASE" + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix"$UNAME_RELEASE" + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix"$UNAME_RELEASE" + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval "$set_cc_for_build" + sed 's/^ //' << EOF > "$dummy.c" +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o "$dummy" "$dummy.c" && + dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`"$dummy" "$dummyarg"` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos"$UNAME_RELEASE" + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ "$UNAME_PROCESSOR" = mc88100 ] || [ "$UNAME_PROCESSOR" = mc88110 ] + then + if [ "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx ] || \ + [ "$TARGET_BINARY_INTERFACE"x = x ] + then + echo m88k-dg-dgux"$UNAME_RELEASE" + else + echo m88k-dg-dguxbcs"$UNAME_RELEASE" + fi + else + echo i586-dg-dgux"$UNAME_RELEASE" + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix"`echo "$UNAME_RELEASE"|sed -e 's/-/_/g'`" + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" + fi + echo "$UNAME_MACHINE"-ibm-aix"$IBM_REV" + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval "$set_cc_for_build" + sed 's/^ //' << EOF > "$dummy.c" + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[4567]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/lslpp ] ; then + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | + awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` + else + IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" + fi + echo "$IBM_ARCH"-ibm-aix"$IBM_REV" + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd"$UNAME_RELEASE" # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'` + case "$UNAME_MACHINE" in + 9000/31?) HP_ARCH=m68000 ;; + 9000/[34]??) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "$sc_cpu_version" in + 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 + 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "$sc_kernel_bits" in + 32) HP_ARCH=hppa2.0n ;; + 64) HP_ARCH=hppa2.0w ;; + '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "$HP_ARCH" = "" ]; then + eval "$set_cc_for_build" + sed 's/^ //' << EOF > "$dummy.c" + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ "$HP_ARCH" = hppa2.0w ] + then + eval "$set_cc_for_build" + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH=hppa2.0w + else + HP_ARCH=hppa64 + fi + fi + echo "$HP_ARCH"-hp-hpux"$HPUX_REV" + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux"$HPUX_REV" + exit ;; + 3050*:HI-UX:*:*) + eval "$set_cc_for_build" + sed 's/^ //' << EOF > "$dummy.c" + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo "$UNAME_MACHINE"-unknown-osf1mk + else + echo "$UNAME_MACHINE"-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo "$UNAME_MACHINE"-pc-bsdi"$UNAME_RELEASE" + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi"$UNAME_RELEASE" + exit ;; + *:BSD/OS:*:*) + echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE" + exit ;; + *:FreeBSD:*:*) + UNAME_PROCESSOR=`/usr/bin/uname -p` + case "$UNAME_PROCESSOR" in + amd64) + 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 + exit ;; + *:MINGW64*:*) + echo "$UNAME_MACHINE"-pc-mingw64 + exit ;; + *:MINGW*:*) + echo "$UNAME_MACHINE"-pc-mingw32 + exit ;; + *:MSYS*:*) + echo "$UNAME_MACHINE"-pc-msys + exit ;; + i*:PW*:*) + echo "$UNAME_MACHINE"-pc-pw32 + exit ;; + *:Interix*:*) + case "$UNAME_MACHINE" in + x86) + echo i586-pc-interix"$UNAME_RELEASE" + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix"$UNAME_RELEASE" + exit ;; + IA64) + echo ia64-unknown-interix"$UNAME_RELEASE" + exit ;; + esac ;; + i*:UWIN*:*) + echo "$UNAME_MACHINE"-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" + exit ;; + *:GNU:*:*) + # the GNU system + echo "`echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,'`-unknown-$LIBC`echo "$UNAME_RELEASE"|sed -e 's,/.*$,,'`" + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo "$UNAME_MACHINE-unknown-`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`-$LIBC" + exit ;; + i*86:Minix:*:*) + echo "$UNAME_MACHINE"-pc-minix + exit ;; + aarch64:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC=gnulibc1 ; fi + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + arc:Linux:*:* | arceb:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + arm*:Linux:*:*) + eval "$set_cc_for_build" + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabi + else + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabihf + fi + fi + exit ;; + avr32*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + cris:Linux:*:*) + echo "$UNAME_MACHINE"-axis-linux-"$LIBC" + exit ;; + crisv32:Linux:*:*) + echo "$UNAME_MACHINE"-axis-linux-"$LIBC" + exit ;; + e2k:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + frv:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + hexagon:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + i*86:Linux:*:*) + echo "$UNAME_MACHINE"-pc-linux-"$LIBC" + exit ;; + ia64:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + k1om:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + m32r*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + m68*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval "$set_cc_for_build" + sed 's/^ //' << EOF > "$dummy.c" + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +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 ;; + or32:Linux:*:* | or1k*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-"$LIBC" + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-"$LIBC" + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;; + PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;; + *) echo hppa-unknown-linux-"$LIBC" ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-"$LIBC" + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-"$LIBC" + exit ;; + ppc64le:Linux:*:*) + echo powerpc64le-unknown-linux-"$LIBC" + exit ;; + 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 ;; + sh64*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + sh*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + tile*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + vax:Linux:*:*) + echo "$UNAME_MACHINE"-dec-linux-"$LIBC" + exit ;; + x86_64:Linux:*:*) + if objdump -f /bin/sh | grep -q elf32-x86-64; then + echo "$UNAME_MACHINE"-pc-linux-"$LIBC"x32 + else + echo "$UNAME_MACHINE"-pc-linux-"$LIBC" + fi + exit ;; + xtensa*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo "$UNAME_MACHINE"-pc-sysv4.2uw"$UNAME_VERSION" + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo "$UNAME_MACHINE"-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo "$UNAME_MACHINE"-unknown-stop + exit ;; + i*86:atheos:*:*) + echo "$UNAME_MACHINE"-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo "$UNAME_MACHINE"-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos"$UNAME_RELEASE" + exit ;; + i*86:*DOS:*:*) + echo "$UNAME_MACHINE"-pc-msdosdjgpp + exit ;; + i*86:*:4.*:*) + UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL" + else + echo "$UNAME_MACHINE"-pc-sysv"$UNAME_REL" + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo "$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}{$UNAME_VERSION}" + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo "$UNAME_MACHINE"-pc-sco"$UNAME_REL" + else + echo "$UNAME_MACHINE"-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configure will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv"$UNAME_RELEASE" # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv"$UNAME_RELEASE" # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos"$UNAME_RELEASE" + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos"$UNAME_RELEASE" + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos"$UNAME_RELEASE" + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos"$UNAME_RELEASE" + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv"$UNAME_RELEASE" + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo "$UNAME_MACHINE"-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo "$UNAME_MACHINE"-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux"$UNAME_RELEASE" + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv"$UNAME_RELEASE" + else + echo mips-unknown-sysv"$UNAME_RELEASE" + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + x86_64:Haiku:*:*) + echo x86_64-unknown-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux"$UNAME_RELEASE" + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux"$UNAME_RELEASE" + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux"$UNAME_RELEASE" + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux"$UNAME_RELEASE" + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux"$UNAME_RELEASE" + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux"$UNAME_RELEASE" + exit ;; + SX-ACE:SUPER-UX:*:*) + echo sxace-nec-superux"$UNAME_RELEASE" + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody"$UNAME_RELEASE" + exit ;; + *:Rhapsody:*:*) + echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE" + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + eval "$set_cc_for_build" + if test "$UNAME_PROCESSOR" = unknown ; then + UNAME_PROCESSOR=powerpc + fi + 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 + 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 + # that puts up a graphical alert prompting to install + # developer tools. Any system running Mac OS X 10.7 or + # later (Darwin 11 and later) is required to have a 64-bit + # processor. This is not true of the ARM version of Darwin + # that Apple uses in portable devices. + UNAME_PROCESSOR=x86_64 + fi + echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE" + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = x86; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo "$UNAME_PROCESSOR"-"$UNAME_MACHINE"-nto-qnx"$UNAME_RELEASE" + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NEO-*:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk"$UNAME_RELEASE" + exit ;; + NSE-*:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk"$UNAME_RELEASE" + exit ;; + NSR-*:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk"$UNAME_RELEASE" + exit ;; + NSV-*:NONSTOP_KERNEL:*:*) + echo nsv-tandem-nsk"$UNAME_RELEASE" + exit ;; + NSX-*:NONSTOP_KERNEL:*:*) + echo nsx-tandem-nsk"$UNAME_RELEASE" + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo "$UNAME_MACHINE"-"$UNAME_SYSTEM"-"$UNAME_RELEASE" + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = 386; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo "$UNAME_MACHINE"-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux"$UNAME_RELEASE" + exit ;; + *:DragonFly:*:*) + echo "$UNAME_MACHINE"-unknown-dragonfly"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`" + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "$UNAME_MACHINE" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo "$UNAME_MACHINE"-pc-skyos"`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`" + exit ;; + i*86:rdos:*:*) + echo "$UNAME_MACHINE"-pc-rdos + exit ;; + i*86:AROS:*:*) + echo "$UNAME_MACHINE"-pc-aros + exit ;; + x86_64:VMkernel:*:*) + echo "$UNAME_MACHINE"-unknown-esx + exit ;; + amd64:Isilon\ OneFS:*:*) + echo x86_64-unknown-onefs + exit ;; +esac + +echo "$0: unable to guess system type" >&2 + +case "$UNAME_MACHINE:$UNAME_SYSTEM" in + mips:Linux | mips64:Linux) + # If we got here on MIPS GNU/Linux, output extra information. + cat >&2 <&2 </dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = "$UNAME_MACHINE" +UNAME_RELEASE = "$UNAME_RELEASE" +UNAME_SYSTEM = "$UNAME_SYSTEM" +UNAME_VERSION = "$UNAME_VERSION" +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-functions 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/config.rpath b/config.rpath new file mode 100755 index 0000000..fc5913d --- /dev/null +++ b/config.rpath @@ -0,0 +1,684 @@ +#! /bin/sh +# Output a system dependent set of variables, describing how to set the +# run time search path of shared libraries in an executable. +# +# Copyright 1996-2018 Free Software Foundation, Inc. +# Taken from GNU libtool, 2001 +# Originally by Gordon Matzigkeit , 1996 +# +# This file 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. +# +# The first argument passed to this file is the canonical host specification, +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld +# should be set by the caller. +# +# The set of defined variables is at the end of this script. + +# Known limitations: +# - On IRIX 6.5 with CC="cc", the run time search patch must not be longer +# than 256 bytes, otherwise the compiler driver will dump core. The only +# known workaround is to choose shorter directory names for the build +# directory and/or the installation directory. + +# All known linkers require a '.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a +shrext=.so + +host="$1" +host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + +# Code taken from libtool.m4's _LT_CC_BASENAME. + +for cc_temp in $CC""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`echo "$cc_temp" | sed -e 's%^.*/%%'` + +# Code taken from libtool.m4's _LT_COMPILER_PIC. + +wl= +if test "$GCC" = yes; then + wl='-Wl,' +else + case "$host_os" in + aix*) + wl='-Wl,' + ;; + mingw* | cygwin* | pw32* | os2* | cegcc*) + ;; + hpux9* | hpux10* | hpux11*) + wl='-Wl,' + ;; + irix5* | irix6* | nonstopux*) + wl='-Wl,' + ;; + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + ecc*) + wl='-Wl,' + ;; + icc* | ifort*) + wl='-Wl,' + ;; + lf95*) + wl='-Wl,' + ;; + nagfor*) + wl='-Wl,-Wl,,' + ;; + pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) + wl='-Wl,' + ;; + ccc*) + wl='-Wl,' + ;; + xl* | bgxl* | bgf* | mpixl*) + wl='-Wl,' + ;; + como) + wl='-lopt=' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ F* | *Sun*Fortran*) + wl= + ;; + *Sun\ C*) + wl='-Wl,' + ;; + esac + ;; + esac + ;; + newsos6) + ;; + *nto* | *qnx*) + ;; + osf3* | osf4* | osf5*) + wl='-Wl,' + ;; + rdos*) + ;; + solaris*) + case $cc_basename in + f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) + wl='-Qoption ld ' + ;; + *) + wl='-Wl,' + ;; + esac + ;; + sunos4*) + wl='-Qoption ld ' + ;; + sysv4 | sysv4.2uw2* | sysv4.3*) + wl='-Wl,' + ;; + sysv4*MP*) + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + wl='-Wl,' + ;; + unicos*) + wl='-Wl,' + ;; + uts4*) + ;; + esac +fi + +# Code taken from libtool.m4's _LT_LINKER_SHLIBS. + +hardcode_libdir_flag_spec= +hardcode_libdir_separator= +hardcode_direct=no +hardcode_minus_L=no + +case "$host_os" in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; +esac + +ld_shlibs=yes +if test "$with_gnu_ld" = yes; then + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + # Unlike libtool, we use -rpath here, not --rpath, since the documented + # option of GNU ld is called -rpath, not --rpath. + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + case "$host_os" in + aix[3-9]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs=no + fi + ;; + amigaos*) + case "$host_cpu" in + powerpc) + ;; + m68k) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + cygwin* | mingw* | pw32* | cegcc*) + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + haiku*) + ;; + interix[3-9]*) + hardcode_direct=no + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + netbsd*) + ;; + solaris*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs=no + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' + else + ld_shlibs=no + fi + ;; + esac + ;; + sunos4*) + hardcode_direct=yes + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + esac + if test "$ld_shlibs" = no; then + hardcode_libdir_flag_spec= + fi +else + case "$host_os" in + aix3*) + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + aix[4-9]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + else + aix_use_runtimelinking=no + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + fi + hardcode_direct=yes + hardcode_libdir_separator=':' + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct=unsupported + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + ;; + esac + fi + # Begin _LT_AC_SYS_LIBPATH_AIX. + echo 'int main () { return 0; }' > conftest.c + ${CC} ${LDFLAGS} conftest.c -o conftest + aix_libpath=`dump -H conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` + if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` + fi + if test -z "$aix_libpath"; then + aix_libpath="/usr/lib:/lib" + fi + rm -f conftest.c conftest + # End _LT_AC_SYS_LIBPATH_AIX. + if test "$aix_use_runtimelinking" = yes; then + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + else + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + fi + fi + ;; + amigaos*) + case "$host_cpu" in + powerpc) + ;; + m68k) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + bsdi[45]*) + ;; + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec=' ' + libext=lib + ;; + darwin* | rhapsody*) + hardcode_direct=no + if { case $cc_basename in ifort*) true;; *) test "$GCC" = yes;; esac; }; then + : + else + ld_shlibs=no + fi + ;; + dgux*) + hardcode_libdir_flag_spec='-L$libdir' + ;; + freebsd2.[01]*) + hardcode_direct=yes + hardcode_minus_L=yes + ;; + freebsd* | dragonfly*) + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + ;; + hpux9*) + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + hpux10*) + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + fi + ;; + hpux11*) + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct=no + ;; + *) + hardcode_direct=yes + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + esac + fi + ;; + irix5* | irix6* | nonstopux*) + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + netbsd*) + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + ;; + newsos6) + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + *nto* | *qnx*) + ;; + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct=yes + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + else + case "$host_os" in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + else + ld_shlibs=no + fi + ;; + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + osf3*) + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + osf4* | osf5*) + if test "$GCC" = yes; then + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + # Both cc and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + hardcode_libdir_separator=: + ;; + solaris*) + hardcode_libdir_flag_spec='-R$libdir' + ;; + sunos4*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + ;; + sysv4) + case $host_vendor in + sni) + hardcode_direct=yes # is this really true??? + ;; + siemens) + hardcode_direct=no + ;; + motorola) + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + ;; + sysv4.3*) + ;; + sysv4*MP*) + if test -d /usr/nec; then + ld_shlibs=yes + fi + ;; + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + ;; + sysv5* | sco3.2v5* | sco5v6*) + hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + hardcode_libdir_separator=':' + ;; + uts4*) + hardcode_libdir_flag_spec='-L$libdir' + ;; + *) + ld_shlibs=no + ;; + esac +fi + +# Check dynamic linker characteristics +# Code taken from libtool.m4's _LT_SYS_DYNAMIC_LINKER. +# Unlike libtool.m4, here we don't care about _all_ names of the library, but +# only about the one the linker finds when passed -lNAME. This is the last +# element of library_names_spec in libtool.m4, or possibly two of them if the +# linker has special search rules. +library_names_spec= # the last element of library_names_spec in libtool.m4 +libname_spec='lib$name' +case "$host_os" in + aix3*) + library_names_spec='$libname.a' + ;; + aix[4-9]*) + library_names_spec='$libname$shrext' + ;; + amigaos*) + case "$host_cpu" in + powerpc*) + library_names_spec='$libname$shrext' ;; + m68k) + library_names_spec='$libname.a' ;; + esac + ;; + beos*) + library_names_spec='$libname$shrext' + ;; + bsdi[45]*) + library_names_spec='$libname$shrext' + ;; + cygwin* | mingw* | pw32* | cegcc*) + shrext=.dll + library_names_spec='$libname.dll.a $libname.lib' + ;; + darwin* | rhapsody*) + shrext=.dylib + library_names_spec='$libname$shrext' + ;; + dgux*) + library_names_spec='$libname$shrext' + ;; + freebsd[23].*) + library_names_spec='$libname$shrext$versuffix' + ;; + freebsd* | dragonfly*) + library_names_spec='$libname$shrext' + ;; + gnu*) + library_names_spec='$libname$shrext' + ;; + haiku*) + library_names_spec='$libname$shrext' + ;; + hpux9* | hpux10* | hpux11*) + case $host_cpu in + ia64*) + shrext=.so + ;; + hppa*64*) + shrext=.sl + ;; + *) + shrext=.sl + ;; + esac + library_names_spec='$libname$shrext' + ;; + interix[3-9]*) + library_names_spec='$libname$shrext' + ;; + irix5* | irix6* | nonstopux*) + library_names_spec='$libname$shrext' + case "$host_os" in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= ;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 ;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 ;; + *) libsuff= shlibsuff= ;; + esac + ;; + esac + ;; + linux*oldld* | linux*aout* | linux*coff*) + ;; + linux* | k*bsd*-gnu | kopensolaris*-gnu) + library_names_spec='$libname$shrext' + ;; + knetbsd*-gnu) + library_names_spec='$libname$shrext' + ;; + netbsd*) + library_names_spec='$libname$shrext' + ;; + newsos6) + library_names_spec='$libname$shrext' + ;; + *nto* | *qnx*) + library_names_spec='$libname$shrext' + ;; + openbsd*) + library_names_spec='$libname$shrext$versuffix' + ;; + os2*) + libname_spec='$name' + shrext=.dll + library_names_spec='$libname.a' + ;; + osf3* | osf4* | osf5*) + library_names_spec='$libname$shrext' + ;; + rdos*) + ;; + solaris*) + library_names_spec='$libname$shrext' + ;; + sunos4*) + library_names_spec='$libname$shrext$versuffix' + ;; + sysv4 | sysv4.3*) + library_names_spec='$libname$shrext' + ;; + sysv4*MP*) + library_names_spec='$libname$shrext' + ;; + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + library_names_spec='$libname$shrext' + ;; + tpf*) + library_names_spec='$libname$shrext' + ;; + uts4*) + library_names_spec='$libname$shrext' + ;; +esac + +sed_quote_subst='s/\(["`$\\]\)/\\\1/g' +escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"` +shlibext=`echo "$shrext" | sed -e 's,^\.,,'` +escaped_libname_spec=`echo "X$libname_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` +escaped_library_names_spec=`echo "X$library_names_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` +escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` + +LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' <. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). + + +# Please send patches to . +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS + +Canonicalize a configuration name. + +Options: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright 1992-2018 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." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo "$1" + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +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* | cloudabi*-eabi* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + android-linux) + os=-linux-android + basic_machine=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown + ;; + *) + basic_machine=`echo "$1" | sed 's/-[^-]*$//'` + if [ "$basic_machine" != "$1" ] + then os=`echo "$1" | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray | -microblaze*) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*178) + os=-lynxos178 + ;; + -lynx*5) + os=-lynxos5 + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo "$1" | sed -e 's/86-.*/86-sequent/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | aarch64 | aarch64_be \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arceb \ + | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ + | avr | avr32 \ + | ba \ + | be32 | be64 \ + | bfin \ + | c4x | c8051 | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | e2k | epiphany \ + | fido | fr30 | frv | ft32 \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | hexagon \ + | i370 | i860 | i960 | ia16 | ia64 \ + | ip2k | iq2000 \ + | k1om \ + | le32 | le64 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa32r6 | mipsisa32r6el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64r6 | mipsisa64r6el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipsr5900 | mipsr5900el \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nds32 | nds32le | nds32be \ + | nios | nios2 | nios2eb | nios2el \ + | ns16k | ns32k \ + | open8 | or1k | or1knd | or32 \ + | pdp10 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle \ + | pru \ + | pyramid \ + | riscv32 | riscv64 \ + | rl78 | rx \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu \ + | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ + | visium \ + | wasm32 \ + | x86 | xc16x | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + c54x) + basic_machine=tic54x-unknown + ;; + c55x) + basic_machine=tic55x-unknown + ;; + c6x) + basic_machine=tic6x-unknown + ;; + leon|leon[3-9]) + basic_machine=sparc-$basic_machine + ;; + m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65) + ;; + ms1) + basic_machine=mt-unknown + ;; + + strongarm | thumb | xscale) + basic_machine=arm-unknown + ;; + xgate) + basic_machine=$basic_machine-unknown + os=-none + ;; + xscaleeb) + basic_machine=armeb-unknown + ;; + + xscaleel) + basic_machine=armel-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`"$1"\': machine \`"$basic_machine"\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | aarch64-* | aarch64_be-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | ba-* \ + | be32-* | be64-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* \ + | c8051-* | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | e2k-* | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | hexagon-* \ + | i*86-* | i860-* | i960-* | ia16-* | ia64-* \ + | ip2k-* | iq2000-* \ + | k1om-* \ + | le32-* | le64-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ + | microblaze-* | microblazeel-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa32r6-* | mipsisa32r6el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64r6-* | mipsisa64r6el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipsr5900-* | mipsr5900el-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nds32-* | nds32le-* | nds32be-* \ + | nios-* | nios2-* | nios2eb-* | nios2el-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | open8-* \ + | or1k*-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ + | pru-* \ + | pyramid-* \ + | riscv32-* | riscv64-* \ + | rl78-* | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \ + | tahoe-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tile*-* \ + | tron-* \ + | ubicom32-* \ + | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ + | vax-* \ + | visium-* \ + | wasm32-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-pc + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo "$basic_machine" | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + asmjs) + basic_machine=asmjs-unknown + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo "$basic_machine" | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c54x-*) + basic_machine=tic54x-`echo "$basic_machine" | sed 's/^[^-]*-//'` + ;; + c55x-*) + basic_machine=tic55x-`echo "$basic_machine" | sed 's/^[^-]*-//'` + ;; + c6x-*) + basic_machine=tic6x-`echo "$basic_machine" | sed 's/^[^-]*-//'` + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16 | cr16-*) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2*) + basic_machine=m68k-bull + os=-sysv3 + ;; + e500v[12]) + basic_machine=powerpc-unknown + os=$os"spe" + ;; + e500v[12]-*) + basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'` + os=$os"spe" + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; + i*86v32) + basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + leon-*|leon[3-9]-*) + basic_machine=sparc-`echo "$basic_machine" | sed 's/-.*//'` + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo "$basic_machine" | sed 's/^[^-]*-//'` + os=-linux + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + microblaze*) + basic_machine=microblaze-xilinx + ;; + mingw64) + basic_machine=x86_64-pc + os=-mingw64 + ;; + mingw32) + basic_machine=i686-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo "$basic_machine" | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo "$basic_machine" | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + moxiebox) + basic_machine=moxie-unknown + os=-moxiebox + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo "$basic_machine" | sed -e 's/ms1-/mt-/'` + ;; + msys) + basic_machine=i686-pc + os=-msys + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + nacl) + basic_machine=le32-unknown + os=-nacl + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + neo-tandem) + basic_machine=neo-tandem + ;; + nse-tandem) + basic_machine=nse-tandem + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + nsv-tandem) + basic_machine=nsv-tandem + ;; + nsx-tandem) + basic_machine=nsx-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo "$basic_machine" | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo "$basic_machine" | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo "$basic_machine" | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo "$basic_machine" | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo "$basic_machine" | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo "$basic_machine" | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc | ppcbe) basic_machine=powerpc-unknown + ;; + ppc-* | ppcbe-*) + basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo "$basic_machine" | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo "$basic_machine" | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo "$basic_machine" | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos | rdos64) + basic_machine=x86_64-pc + os=-rdos + ;; + rdos32) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + strongarm-* | thumb-*) + basic_machine=arm-`echo "$basic_machine" | sed 's/^[^-]*-//'` + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tile*) + basic_machine=$basic_machine-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + x64) + basic_machine=x86_64-pc + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + xscale-* | xscalee[bl]-*) + basic_machine=`echo "$basic_machine" | sed 's/^xscale/arm/'` + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`"$1"\': machine \`"$basic_machine"\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo "$basic_machine" | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo "$basic_machine" | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases that might get confused + # with valid system types. + # -solaris* is a basic system type, with this one exception. + -auroraux) + os=-auroraux + ;; + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # es1800 is here to avoid being matched by es* (a different OS) + -es1800*) + os=-ose + ;; + # Now accept the basic system types. + # The portable systems comes first. + # Each alternative MUST end in a * to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* | -plan9* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* | -cloudabi* | -sortix* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -knetbsd* | -mirbsd* | -netbsd* \ + | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* | -glidix* \ + | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ + | -linux-newlib* | -linux-musl* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \ + | -onefs* | -tirtos* | -phoenix* | -fuchsia* | -redox* | -bme* \ + | -midnightbsd*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -xray | -os68k* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo "$os" | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo "$os" | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo "$os" | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4*) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -pikeos*) + # Until real need of OS specific support for + # particular features comes up, bare metal + # configurations are quite functional. + case $basic_machine in + arm*) + os=-eabi + ;; + *) + os=-elf + ;; + esac + ;; + -nacl*) + ;; + -ios) + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`"$1"\': system \`"$os"\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + c8051-*) + os=-elf + ;; + hexagon-*) + os=-elf + ;; + tic54x-*) + os=-coff + ;; + tic55x-*) + os=-coff + ;; + tic6x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + pru-*) + os=-elf + ;; + *-be) + os=-beos + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo "$basic_machine" | sed "s/unknown/$vendor/"` + ;; +esac + +echo "$basic_machine$os" +exit + +# Local variables: +# eval: (add-hook 'write-file-functions 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/configh.in b/configh.in new file mode 100644 index 0000000..e600005 --- /dev/null +++ b/configh.in @@ -0,0 +1,514 @@ +/* configh.in. Generated from configure.ac by autoheader. */ + +/* dynamic loading is possible */ +#undef DYNAMIC + +/* Define to 1 if translation of program messages to the user's native + language is requested. */ +#undef ENABLE_NLS + +/* Define to the type of elements in the array set by `getgroups'. Usually + this is either `int' or `gid_t'. */ +#undef GETGROUPS_T + +/* Define to 1 if the `getpgrp' function requires zero arguments. */ +#undef GETPGRP_VOID + +/* Define to 1 if you have the `alarm' function. */ +#undef HAVE_ALARM + +/* Define to 1 if you have the header file. */ +#undef HAVE_ARPA_INET_H + +/* Define to 1 if you have the `atexit' function. */ +#undef HAVE_ATEXIT + +/* Define to 1 if you have the `btowc' function. */ +#undef HAVE_BTOWC + +/* Define to 1 if you have the Mac OS X function CFLocaleCopyCurrent in the + CoreFoundation framework. */ +#undef HAVE_CFLOCALECOPYCURRENT + +/* Define to 1 if you have the Mac OS X function CFPreferencesCopyAppValue in + the CoreFoundation framework. */ +#undef HAVE_CFPREFERENCESCOPYAPPVALUE + +/* Define if the GNU dcgettext() function is already present or preinstalled. + */ +#undef HAVE_DCGETTEXT + +/* Define to 1 if you have the declaration of `tzname', and to 0 if you don't. + */ +#undef HAVE_DECL_TZNAME + +/* Define to 1 if you have the header file. */ +#undef HAVE_FCNTL_H + +/* 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 + +/* Define to 1 if you have the `gai_strerror' function. */ +#undef HAVE_GAI_STRERROR + +/* have getaddrinfo */ +#undef HAVE_GETADDRINFO + +/* Define to 1 if you have the `getgrent' function. */ +#undef HAVE_GETGRENT + +/* Define to 1 if you have the `getgroups' function. */ +#undef HAVE_GETGROUPS + +/* Define if the GNU gettext() function is already present or preinstalled. */ +#undef HAVE_GETTEXT + +/* Define to 1 if you have the `grantpt' function. */ +#undef HAVE_GRANTPT + +/* Do we have history_list? */ +#undef HAVE_HISTORY_LIST + +/* Define if you have the iconv() function and it works. */ +#undef HAVE_ICONV + +/* Define to 1 if the system has the type `intmax_t'. */ +#undef HAVE_INTMAX_T + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the `isascii' function. */ +#undef HAVE_ISASCII + +/* Define to 1 if you have the `iswctype' function. */ +#undef HAVE_ISWCTYPE + +/* Define to 1 if you have the `iswlower' function. */ +#undef HAVE_ISWLOWER + +/* Define to 1 if you have the `iswupper' function. */ +#undef HAVE_ISWUPPER + +/* Define if you have and nl_langinfo(CODESET). */ +#undef HAVE_LANGINFO_CODESET + +/* Define if your file defines LC_MESSAGES. */ +#undef HAVE_LC_MESSAGES + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIBINTL_H + +/* Define to 1 if you have a fully functional readline library. */ +#undef HAVE_LIBREADLINE + +/* Define if you have the libsigsegv library. */ +#undef HAVE_LIBSIGSEGV + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIMITS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LOCALE_H + +/* Define to 1 if the system has the type 'long long int'. */ +#undef HAVE_LONG_LONG_INT + +/* Define to 1 if you have the `mbrlen' function. */ +#undef HAVE_MBRLEN + +/* Define to 1 if mbrtowc and mbstate_t are properly declared. */ +#undef HAVE_MBRTOWC + +/* Define to 1 if you have the header file. */ +#undef HAVE_MCHECK_H + +/* Define to 1 if you have the `memcmp' function. */ +#undef HAVE_MEMCMP + +/* Define to 1 if you have the `memcpy' function. */ +#undef HAVE_MEMCPY + +/* Define to 1 if you have the `memcpy_ulong' function. */ +#undef HAVE_MEMCPY_ULONG + +/* Define to 1 if you have the `memmove' function. */ +#undef HAVE_MEMMOVE + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `memset' function. */ +#undef HAVE_MEMSET + +/* Define to 1 if you have the `memset_ulong' function. */ +#undef HAVE_MEMSET_ULONG + +/* Define to 1 if you have the `mkstemp' function. */ +#undef HAVE_MKSTEMP + +/* we have the mktime function */ +#undef HAVE_MKTIME + +/* Define to 1 if you have fully functional mpfr and gmp libraries. */ +#undef HAVE_MPFR + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETDB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_IN_H + +/* Define to 1 if you have the `posix_openpt' function. */ +#undef HAVE_POSIX_OPENPT + +/* Define to 1 if you have the `setenv' function. */ +#undef HAVE_SETENV + +/* Define to 1 if you have the `setlocale' function. */ +#undef HAVE_SETLOCALE + +/* 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 + +/* newer systems define this type here */ +#undef HAVE_SOCKADDR_STORAGE + +/* we have sockets on this system */ +#undef HAVE_SOCKETS + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDARG_H + +/* Define to 1 if stdbool.h conforms to C99. */ +#undef HAVE_STDBOOL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDDEF_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `strcasecmp' function. */ +#undef HAVE_STRCASECMP + +/* Define to 1 if you have the `strchr' function. */ +#undef HAVE_STRCHR + +/* Define to 1 if you have the `strcoll' function. */ +#undef HAVE_STRCOLL + +/* Define to 1 if you have the `strerror' function. */ +#undef HAVE_STRERROR + +/* Define to 1 if you have the `strftime' function. */ +#undef HAVE_STRFTIME + +/* Define to 1 if cpp supports the ANSI # stringizing operator. */ +#undef HAVE_STRINGIZE + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strncasecmp' function. */ +#undef HAVE_STRNCASECMP + +/* Define to 1 if you have the header file. */ +#undef HAVE_STROPTS_H + +/* Define to 1 if you have the `strtod' function. */ +#undef HAVE_STRTOD + +/* Define to 1 if you have the `strtoul' function. */ +#undef HAVE_STRTOUL + +/* Define to 1 if `gr_passwd' is a member of `struct group'. */ +#undef HAVE_STRUCT_GROUP_GR_PASSWD + +/* Define to 1 if `pw_passwd' is a member of `struct passwd'. */ +#undef HAVE_STRUCT_PASSWD_PW_PASSWD + +/* Define to 1 if `st_blksize' is a member of `struct stat'. */ +#undef HAVE_STRUCT_STAT_ST_BLKSIZE + +/* Define to 1 if `tm_zone' is a member of `struct tm'. */ +#undef HAVE_STRUCT_TM_TM_ZONE + +/* Define to 1 if you have the `system' function. */ +#undef HAVE_SYSTEM + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_IOCTL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SELECT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SOCKET_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have that is POSIX.1 compatible. */ +#undef HAVE_SYS_WAIT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_TERMIOS_H + +/* Define to 1 if you have the `tmpfile' function. */ +#undef HAVE_TMPFILE + +/* Define to 1 if your `struct tm' has `tm_zone'. Deprecated, use + `HAVE_STRUCT_TM_TM_ZONE' instead. */ +#undef HAVE_TM_ZONE + +/* Define to 1 if you have the `towlower' function. */ +#undef HAVE_TOWLOWER + +/* Define to 1 if you have the `towupper' function. */ +#undef HAVE_TOWUPPER + +/* Define to 1 if you don't have `tm_zone' but do have the external array + `tzname'. */ +#undef HAVE_TZNAME + +/* Define to 1 if you have the `tzset' function. */ +#undef HAVE_TZSET + +/* Define to 1 if the system has the type `uintmax_t'. */ +#undef HAVE_UINTMAX_T + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if the system has the type `unsigned long long int'. */ +#undef HAVE_UNSIGNED_LONG_LONG_INT + +/* 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 header file. */ +#undef HAVE_WCHAR_H + +/* Define to 1 if you have the `wcrtomb' function. */ +#undef HAVE_WCRTOMB + +/* Define to 1 if you have the `wcscoll' function. */ +#undef HAVE_WCSCOLL + +/* Define to 1 if you have the `wctype' function. */ +#undef HAVE_WCTYPE + +/* Define to 1 if you have the header file. */ +#undef HAVE_WCTYPE_H + +/* systems should define this type here */ +#undef HAVE_WCTYPE_T + +/* systems should define this type here */ +#undef HAVE_WINT_T + +/* Define to 1 if the system has the type `_Bool'. */ +#undef HAVE__BOOL + +/* Define to 1 if you have the `__etoa_l' function. */ +#undef HAVE___ETOA_L + +/* enable severe portability problems */ +#undef I_DONT_KNOW_WHAT_IM_DOING + +/* disable lint checks */ +#undef NO_LINT + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if *printf supports %F format */ +#undef PRINTF_HAS_F_FORMAT + +/* The size of `unsigned int', as computed by sizeof. */ +#undef SIZEOF_UNSIGNED_INT + +/* The size of `unsigned long', as computed by sizeof. */ +#undef SIZEOF_UNSIGNED_LONG + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* enable built-in intdiv0 function */ +#undef SUPPLY_INTDIV + +/* some systems define this type here */ +#undef TIME_T_IN_SYS_TYPES_H + +/* Define to 1 if you can safely include both and . */ +#undef TIME_WITH_SYS_TIME + +/* Define to 1 if your declares `struct tm'. */ +#undef TM_IN_SYS_TIME + +/* Define to 1 if the character set is EBCDIC */ +#undef USE_EBCDIC + +/* force use of our version of strftime */ +#undef USE_INCLUDED_STRFTIME + +/* Enable extensions on AIX 3, Interix. */ +#ifndef _ALL_SOURCE +# undef _ALL_SOURCE +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# undef _GNU_SOURCE +#endif +/* Enable threading extensions on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# undef _POSIX_PTHREAD_SEMANTICS +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# undef _TANDEM_SOURCE +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# undef __EXTENSIONS__ +#endif + + +/* Version number of package */ +#undef VERSION + +/* Enable large inode numbers on Mac OS X 10.5. */ +#ifndef _DARWIN_USE_64_BIT_INODE +# define _DARWIN_USE_64_BIT_INODE 1 +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +#undef _FILE_OFFSET_BITS + +/* Define for large files, on AIX-style hosts. */ +#undef _LARGE_FILES + +/* Define to 1 if on MINIX. */ +#undef _MINIX + +/* The _Noreturn keyword of C11. */ +#ifndef _Noreturn +# if (3 <= __GNUC__ || (__GNUC__ == 2 && 8 <= __GNUC_MINOR__) \ + || 0x5110 <= __SUNPRO_C) +# define _Noreturn __attribute__ ((__noreturn__)) +# elif defined _MSC_VER && 1200 <= _MSC_VER +# define _Noreturn __declspec (noreturn) +# else +# define _Noreturn +# endif +#endif + + +/* Define to 2 if the system does not provide POSIX.1 features except with + this defined. */ +#undef _POSIX_1_SOURCE + +/* Define to 1 if you need to in order for `stat' and other things to work. */ +#undef _POSIX_SOURCE + +/* Define to 1 if type `char' is unsigned and you are not using gcc. */ +#ifndef __CHAR_UNSIGNED__ +# undef __CHAR_UNSIGNED__ +#endif + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Define to `int' if doesn't define. */ +#undef gid_t + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +#undef inline +#endif + +/* Define to the widest signed integer type if and do + not define. */ +#undef intmax_t + +/* Define to `int' if does not define. */ +#undef pid_t + +/* Define to the equivalent of the C99 'restrict' keyword, or to + nothing if this is not supported. Do not define if restrict is + supported directly. */ +#undef restrict +/* Work around a bug in Sun C++: it does not support _Restrict or + __restrict__, even though the corresponding Sun C compiler ends up with + "#define restrict _Restrict" or "#define restrict __restrict__" in the + previous line. Perhaps some future version of Sun C++ will work with + restrict; if so, hopefully it defines __RESTRICT like Sun C does. */ +#if defined __SUNPRO_CC && !defined __RESTRICT +# define _Restrict +# define __restrict__ +#endif + +/* Define to `unsigned int' if does not define. */ +#undef size_t + +/* type to use in place of socklen_t if not defined */ +#undef socklen_t + +/* Define to `int' if does not define. */ +#undef ssize_t + +/* Define to `int' if doesn't define. */ +#undef uid_t + +/* Define to the widest unsigned integer type if and + do not define. */ +#undef uintmax_t + +#include "custom.h" diff --git a/configure b/configure new file mode 100755 index 0000000..2283f09 --- /dev/null +++ b/configure @@ -0,0 +1,12774 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.69 for GNU Awk 4.2.1. +# +# Report bugs to . +# +# +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org and bug-gawk@gnu.org +$0: about your system, including any error possibly output +$0: before this message. Then install a modern shell, or +$0: manually run the script under such a shell if you do +$0: have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +test -n "$DJDIR" || exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME='GNU Awk' +PACKAGE_TARNAME='gawk' +PACKAGE_VERSION='4.2.1' +PACKAGE_STRING='GNU Awk 4.2.1' +PACKAGE_BUGREPORT='bug-gawk@gnu.org' +PACKAGE_URL='http://www.gnu.org/software/gawk/' + +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +gt_needs= +ac_header_list= +ac_func_list= +enable_option_checking=no +ac_subst_vars='am__EXEEXT_FALSE +am__EXEEXT_TRUE +LTLIBOBJS +subdirs +GAWKLIBEXT +LIBMPFR +LIBREADLINE +SOCKET_LIBS +ENABLE_EXTENSIONS_FALSE +ENABLE_EXTENSIONS_TRUE +LIBSIGSEGV_PREFIX +LTLIBSIGSEGV +LIBSIGSEGV +HAVE_LIBSIGSEGV +LIBOBJS +TEST_CROSS_COMPILE_FALSE +TEST_CROSS_COMPILE_TRUE +POSUB +LTLIBINTL +LIBINTL +INTLLIBS +LTLIBICONV +LIBICONV +INTL_MACOSX_LIBS +XGETTEXT_EXTRA_OPTIONS +MSGMERGE +XGETTEXT_015 +XGETTEXT +GMSGFMT_015 +MSGFMT_015 +GMSGFMT +MSGFMT +GETTEXT_MACRO_VERSION +USE_NLS +SED +acl_shlibext +RANLIB +LN_S +YFLAGS +YACC +EGREP +GREP +CPP +am__fastdepCC_FALSE +am__fastdepCC_TRUE +CCDEPMODE +am__nodep +AMDEPBACKSLASH +AMDEP_FALSE +AMDEP_TRUE +am__quote +am__include +DEPDIR +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +pkgextensiondir +AM_BACKSLASH +AM_DEFAULT_VERBOSITY +AM_DEFAULT_V +AM_V +am__untar +am__tar +AMTAR +am__leading_dot +SET_MAKE +AWK +mkdir_p +MKDIR_P +INSTALL_STRIP_PROGRAM +STRIP +install_sh +MAKEINFO +AUTOHEADER +AUTOMAKE +AUTOCONF +ACLOCAL +VERSION +PACKAGE +CYGPATH_W +am__isrc +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_silent_rules +with_whiny_user_strftime +enable_lint +enable_severe_portability_problems +enable_builtin_intdiv0 +enable_mpfr +enable_versioned_extension_dir +enable_dependency_tracking +enable_largefile +enable_nls +with_gnu_ld +enable_rpath +with_libiconv_prefix +with_libintl_prefix +with_libsigsegv_prefix +enable_extensions +with_readline +with_mpfr +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CPP +YACC +YFLAGS' +ac_subdirs_all='extension' + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures GNU Awk 4.2.1 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/gawk] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of GNU Awk 4.2.1:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --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 do not compile in gawk lint checking + --enable-severe-portability-problems + allow really nasty portability problems + --enable-builtin-intdiv0 + enable built-in intdiv0 function + --disable-mpfr do not check for MPFR + --enable-versioned-extension-dir + use a versioned directory for extensions + --enable-dependency-tracking + do not reject slow dependency extractors + --disable-dependency-tracking + speeds up one-time build + --disable-largefile omit support for large files + --disable-nls do not use Native Language Support + --disable-rpath do not hardcode runtime library paths + --disable-extensions disable dynamic extensions (default is detect) + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-whiny-user-strftime + force use of included version of strftime for + deficient systems + --with-gnu-ld assume the C compiler uses GNU ld [default=no] + --with-libiconv-prefix[=DIR] search for libiconv in DIR/include and DIR/lib + --without-libiconv-prefix don't search for libiconv in includedir and libdir + --with-libintl-prefix[=DIR] search for libintl in DIR/include and DIR/lib + --without-libintl-prefix don't search for libintl in includedir and libdir + --with-libsigsegv-prefix[=DIR] search for libsigsegv in DIR/include and DIR/lib + --without-libsigsegv-prefix don't search for libsigsegv in includedir and libdir + --with-readline=DIR look for the readline library in DIR + --with-mpfr=DIR look for the mpfr and gmp libraries in DIR + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CPP C preprocessor + YACC The `Yet Another Compiler Compiler' implementation to use. + Defaults to the first program found out of: `bison -y', `byacc', + `yacc'. + YFLAGS The list of arguments that will be passed by default to $YACC. + This script will default YFLAGS to the empty string to avoid a + default value of `-d' given by some make applications. + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to . +GNU Awk home page: . +General help using GNU software: . +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +GNU Awk configure 4.2.1 +generated by GNU Autoconf 2.69 + +Copyright (C) 2012 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +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_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +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_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_c_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if eval \${$3+:} false; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.i conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} +( $as_echo "## ------------------------------- ## +## Report this to bug-gawk@gnu.org ## +## ------------------------------- ##" + ) | sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_mongrel + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +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_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { 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_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +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_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_check_type LINENO TYPE VAR INCLUDES +# ------------------------------------------- +# Tests whether TYPE exists after having included INCLUDES, setting cache +# variable VAR accordingly. +ac_fn_c_check_type () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=no" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof ($2)) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof (($2))) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + eval "$3=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 +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_type + +# ac_fn_c_compute_int LINENO EXPR VAR INCLUDES +# -------------------------------------------- +# Tries to find the compile-time value of EXPR in a program that includes +# INCLUDES, setting VAR accordingly. Returns whether the value could be +# computed +ac_fn_c_compute_int () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) >= 0)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_lo=0 ac_mid=0 + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) <= $ac_mid)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_hi=$ac_mid; break +else + as_fn_arith $ac_mid + 1 && ac_lo=$as_val + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) < 0)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_hi=-1 ac_mid=-1 + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) >= $ac_mid)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_lo=$ac_mid; break +else + as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + ac_lo= ac_hi= +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) <= $ac_mid)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_hi=$ac_mid +else + as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in #(( +?*) eval "$3=\$ac_lo"; ac_retval=0 ;; +'') ac_retval=1 ;; +esac + else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +static long int longval () { return $2; } +static unsigned long int ulongval () { return $2; } +#include +#include +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + return 1; + if (($2) < 0) + { + long int i = longval (); + if (i != ($2)) + return 1; + fprintf (f, "%ld", i); + } + else + { + unsigned long int i = ulongval (); + if (i != ($2)) + return 1; + fprintf (f, "%lu", i); + } + /* Do not output a trailing newline, as this causes \r\n confusion + on some platforms. */ + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + echo >>conftest.val; read $3 &5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_func + +# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES +# ---------------------------------------------------- +# Tries to find if the field MEMBER exists in type AGGR, after including +# INCLUDES, setting cache variable VAR accordingly. +ac_fn_c_check_member () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 +$as_echo_n "checking for $2.$3... " >&6; } +if eval \${$4+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$5 +int +main () +{ +static $2 ac_aggr; +if (ac_aggr.$3) +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$4=yes" +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$5 +int +main () +{ +static $2 ac_aggr; +if (sizeof ac_aggr.$3) +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$4=yes" +else + eval "$4=no" +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 +eval ac_res=\$$4 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_member + +# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES +# --------------------------------------------- +# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR +# accordingly. +ac_fn_c_check_decl () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + as_decl_name=`echo $2|sed 's/ *(.*//'` + as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 +$as_echo_n "checking whether $as_decl_name is declared... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +#ifndef $as_decl_name +#ifdef __cplusplus + (void) $as_decl_use; +#else + (void) $as_decl_name; +#endif +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_decl +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by GNU Awk $as_me 4.2.1, which was +generated by GNU Autoconf 2.69. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +gt_needs="$gt_needs " +as_fn_append ac_header_list " sys/time.h" +as_fn_append ac_header_list " unistd.h" +as_fn_append ac_func_list " alarm" +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +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 + + + +# This is a hack. Different versions of install on different systems +# are just too different. Chuck it and use install-sh. +# +# If the user supplies $INSTALL, figure they know what they're doing. +# +# With Autoconf 2.5x, this needs to come very early on, but *after* +# the INIT macro. Sigh. + +if test "$INSTALL" = "" +then + INSTALL="$srcdir/install-sh -c" + export INSTALL +fi + + +am__api_version='1.15' + +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if ${ac_cv_path_install+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 +$as_echo_n "checking whether build environment is sane... " >&6; } +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[\\\"\#\$\&\'\`$am_lf]*) + as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; +esac +case $srcdir in + *[\\\"\#\$\&\'\`$am_lf\ \ ]*) + as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; +esac + +# Do 'set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + am_has_slept=no + for am_try in 1 2; do + echo "timestamp, slept: $am_has_slept" > conftest.file + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + as_fn_error $? "ls -t appears to fail. Make sure there is not a broken + alias in your environment" "$LINENO" 5 + fi + if test "$2" = conftest.file || test $am_try -eq 2; then + break + fi + # Just in case. + sleep 1 + am_has_slept=yes + done + test "$2" = conftest.file + ) +then + # Ok. + : +else + as_fn_error $? "newly created file is older than distributed files! +Check your system clock" "$LINENO" 5 +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +# If we didn't sleep, we still need to ensure time stamps of config.status and +# generated files are strictly newer. +am_sleep_pid= +if grep 'slept: no' conftest.file >/dev/null 2>&1; then + ( sleep 1 ) & + am_sleep_pid=$! +fi + +rm -f conftest.file + +test "$program_prefix" != NONE && + program_transform_name="s&^&$program_prefix&;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s&\$&$program_suffix&;$program_transform_name" +# Double any \ or $. +# By default was `s,x,x', remove it if useless. +ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' +program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` + +# Expand $ac_aux_dir to an absolute path. +am_aux_dir=`cd "$ac_aux_dir" && pwd` + +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --is-lightweight"; then + am_missing_run="$MISSING " +else + am_missing_run= + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 +$as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;} +fi + +if test x"${install_sh+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi + +# Installed binaries are usually stripped using 'strip' when the user +# run "make install-strip". However 'strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the 'STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; 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_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # 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_STRIP="${ac_tool_prefix}strip" + $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 +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; 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_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # 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_STRIP="strip" + $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_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + 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 + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 +$as_echo_n "checking for a thread-safe mkdir -p... " >&6; } +if test -z "$MKDIR_P"; then + if ${ac_cv_path_mkdir+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in mkdir gmkdir; do + for ac_exec_ext in '' $ac_executable_extensions; do + as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue + case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( + 'mkdir (GNU coreutils) '* | \ + 'mkdir (coreutils) '* | \ + 'mkdir (fileutils) '4.1*) + ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext + break 3;; + esac + done + done + done +IFS=$as_save_IFS + +fi + + test -d ./--version && rmdir ./--version + if test "${ac_cv_path_mkdir+set}" = set; then + MKDIR_P="$ac_cv_path_mkdir -p" + else + # As a last resort, use the slow shell script. Don't cache a + # value for MKDIR_P within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + MKDIR_P="$ac_install_sh -d" + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 +$as_echo "$MKDIR_P" >&6; } + +for ac_prog in gawk mawk nawk awk +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_AWK+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # 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_AWK="$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 +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +$as_echo "$AWK" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AWK" && break +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering ...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + SET_MAKE= +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +# Check whether --enable-silent-rules was given. +if test "${enable_silent_rules+set}" = set; then : + enableval=$enable_silent_rules; +fi + +case $enable_silent_rules in # ((( + yes) AM_DEFAULT_VERBOSITY=0;; + no) AM_DEFAULT_VERBOSITY=1;; + *) AM_DEFAULT_VERBOSITY=1;; +esac +am_make=${MAKE-make} +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 +$as_echo_n "checking whether $am_make supports nested variables... " >&6; } +if ${am_cv_make_support_nested_variables+:} false; then : + $as_echo_n "(cached) " >&6 +else + if $as_echo 'TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 +$as_echo "$am_cv_make_support_nested_variables" >&6; } +if test $am_cv_make_support_nested_variables = yes; then + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AM_BACKSLASH='\' + +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + am__isrc=' -I$(srcdir)' + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE='gawk' + VERSION='4.2.1' + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + +# For better backward compatibility. To be removed once Automake 1.9.x +# dies out for good. For more background, see: +# +# +mkdir_p='$(MKDIR_P)' + +# We need awk for the "check" target (and possibly the TAP driver). The +# system "awk" is bad on some platforms. +# Always define AMTAR for backward compatibility. Yes, it's still used +# in the wild :-( We should find a proper way to deprecate it ... +AMTAR='$${TAR-tar}' + + +# We'll loop over all known methods to create a tar archive until one works. +_am_tools='gnutar pax cpio none' + +am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' + + + + + + +# POSIX will say in a future version that running "rm -f" with no argument +# is OK; and we want to be able to make that assumption in our Makefile +# recipes. So use an aggressive probe to check that the usage we want is +# actually supported "in the wild" to an acceptable degree. +# See automake bug#10828. +# To make any issue more visible, cause the running configure to be aborted +# by default if the 'rm' program in use doesn't match our expectations; the +# user can still override this though. +if rm -f && rm -fr && rm -rf; then : OK; else + cat >&2 <<'END' +Oops! + +Your 'rm' program seems unable to run without file operands specified +on the command line, even when the '-f' option is present. This is contrary +to the behaviour of most rm programs out there, and not conforming with +the upcoming POSIX standard: + +Please tell bug-automake@gnu.org about your system, including the value +of your $PATH and any error possibly output before this message. This +can help us improve future automake versions. + +END + if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then + echo 'Configuration will proceed anyway, since you have set the' >&2 + echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 + echo >&2 + else + cat >&2 <<'END' +Aborting the configuration process, to ensure you take notice of the issue. + +You can download and install GNU coreutils to get an 'rm' implementation +that behaves properly: . + +If you want to complete the configuration process using your problematic +'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM +to "yes", and re-run configure. + +END + as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5 + fi +fi + + + + + +# Check whether --with-whiny-user-strftime was given. +if test "${with_whiny_user_strftime+set}" = set; then : + withval=$with_whiny_user_strftime; if test "$withval" = yes + then + +$as_echo "#define USE_INCLUDED_STRFTIME 1" >>confdefs.h + + fi + +fi + +# Check whether --enable-lint was given. +if test "${enable_lint+set}" = set; then : + enableval=$enable_lint; if test "$enableval" = no + then + +$as_echo "#define NO_LINT 1" >>confdefs.h + + fi + +fi + +# Check whether --enable-severe-portability-problems was given. +if test "${enable_severe_portability_problems+set}" = set; then : + enableval=$enable_severe_portability_problems; if test "$enableval" = yes + then + +$as_echo "#define I_DONT_KNOW_WHAT_IM_DOING 1" >>confdefs.h + + fi + +fi + +# Check whether --enable-builtin-intdiv0 was given. +if test "${enable_builtin_intdiv0+set}" = set; then : + enableval=$enable_builtin_intdiv0; if test "$enableval" = yes + then + +$as_echo "#define SUPPLY_INTDIV 1" >>confdefs.h + + sed '/^@set PATCHLEVEL/a\ +@set INTDIV' < "$srcdir"/doc/gawktexi.in > foo + cp foo "$srcdir"/doc/gawktexi.in + rm foo + fi + +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 + + +EXTENSIONDIR= +# Check whether --enable-versioned-extension-dir was given. +if test "${enable_versioned_extension_dir+set}" = set; then : + enableval=$enable_versioned_extension_dir; if test "$enableval" = yes + then + MAJOR=`awk '/define gawk_api_major_version/ { print $3 }' < $srcdir/gawkapi.h` + MINOR=`awk '/define gawk_api_minor_version/ { print $3 }' < $srcdir/gawkapi.h` + + # note leading slash on the value + export EXTENSIONDIR=/ext-$MAJOR.$MINOR + fi + +fi + + +# set default shared library location +pkgextensiondir='${pkglibdir}'${EXTENSIONDIR} + + +# 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 + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if ${ac_cv_build+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if ${ac_cv_host+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + +DEPDIR="${am__leading_dot}deps" + +ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 +$as_echo_n "checking for style of include used by $am_make... " >&6; } +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from 'make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 +$as_echo "$_am_result" >&6; } +rm -f confinc confmf + +# Check whether --enable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then : + enableval=$enable_dependency_tracking; +fi + +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' + am__nodep='_no' +fi + if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +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_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 + +fi + + +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; } + +# 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 + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +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_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +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_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +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_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { 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_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if ${ac_cv_objext+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +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_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $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. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + 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 () +{ + + ; + return 0; +} +_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 : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + 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 +#include +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; +} + +/* 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]; + +/* 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]; + +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__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $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; } ;; +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 + +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 +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 how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if ${ac_cv_prog_CPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +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 + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if ${ac_cv_path_GREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_GREP" || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if ${ac_cv_path_EGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP" || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + + ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default" +if test "x$ac_cv_header_minix_config_h" = xyes; then : + MINIX=yes +else + MINIX= +fi + + + if test "$MINIX" = yes; then + +$as_echo "#define _POSIX_SOURCE 1" >>confdefs.h + + +$as_echo "#define _POSIX_1_SOURCE 2" >>confdefs.h + + +$as_echo "#define _MINIX 1" >>confdefs.h + + fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5 +$as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; } +if ${ac_cv_safe_to_define___extensions__+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +# define __EXTENSIONS__ 1 + $ac_includes_default +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_safe_to_define___extensions__=yes +else + ac_cv_safe_to_define___extensions__=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5 +$as_echo "$ac_cv_safe_to_define___extensions__" >&6; } + test $ac_cv_safe_to_define___extensions__ = yes && + $as_echo "#define __EXTENSIONS__ 1" >>confdefs.h + + $as_echo "#define _ALL_SOURCE 1" >>confdefs.h + + $as_echo "#define _GNU_SOURCE 1" >>confdefs.h + + $as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h + + $as_echo "#define _TANDEM_SOURCE 1" >>confdefs.h + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if ${ac_cv_path_EGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP" || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +for ac_prog in 'bison -y' byacc +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_YACC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$YACC"; then + ac_cv_prog_YACC="$YACC" # 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_YACC="$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 +YACC=$ac_cv_prog_YACC +if test -n "$YACC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $YACC" >&5 +$as_echo "$YACC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$YACC" && break +done +test -n "$YACC" || YACC="yacc" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 +$as_echo_n "checking whether ln -s works... " >&6; } +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 +$as_echo "no, using $LN_S" >&6; } +fi + + { $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 + ac_cv_prog_cc_c99=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include +#include + +// 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; + +struct incomplete_array +{ + int datasize; + double data[]; +}; + +struct named_init { + int number; + const wchar_t *name; + double average; +}; + +typedef const char *ccp; + +static inline int +test_restrict (ccp restrict text) +{ + // 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; +} + +// 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); + + 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); +} + +int +main () +{ + + // Check bool. + _Bool success = false; + + // Check restrict. + if (test_restrict ("String literal") == 0) + success = true; + char *restrict newvar = "Another string"; + + // Check varargs. + test_varargs ("s, d' f .", "string", 65, 34.234); + test_varargs_macros (); + + // 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; + + // Check named initializers. + struct named_init ni = { + .number = 34, + .name = L"Test wide string", + .average = 543.34343, + }; + + 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); + + ; + return 0; +} +_ACEOF +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_c99=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + 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_c99" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&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_c99" != 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 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if ${ac_cv_prog_CPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +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}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 + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering ...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + SET_MAKE= +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + + +# This is mainly for my use during testing and development. +# Yes, it's a bit of a hack. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for special development options" >&5 +$as_echo_n "checking for special development options... " >&6; } +if test -f $srcdir/.developing +then + # add other debug flags as appropriate, save GAWKDEBUG for emergencies + CFLAGS="$CFLAGS -DARRAYDEBUG -DYYDEBUG -DLOCALEDEBUG" + + # turn on compiler warnings if we're doing development + # enable debugging using macros also + if test "$GCC" = yes + then + CFLAGS="$CFLAGS -Wall -fno-builtin -g3" + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + CFLAGS="$CFLAGS -DNDEBUG" # turn off assertions +fi + + + +# shared library suffix for dynamic loading: + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for z/OS USS compilation" >&5 +$as_echo_n "checking for z/OS USS compilation... " >&6; } +if ${ac_cv_zos_uss+:} false; then : + $as_echo_n "(cached) " >&6 +else + +if test "OS/390" = "`uname`" +then + ac_cv_zos_uss=yes +else + ac_cv_zos_uss=no +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${ac_cv_zos_uss}" >&5 +$as_echo "${ac_cv_zos_uss}" >&6; } +if test "x$ac_cv_zos_uss" = "xyes" +then + ac_zos_uss_cc_id=unknown + echo " $CC " | $EGREP ' (/bin/)?c89[ |_]' >/dev/null && ac_zos_uss_cc_id=c89 + echo " $CC " | $EGREP ' (/bin/)?c99[ |_]' >/dev/null && ac_zos_uss_cc_id=xlc + echo " $CC " | $EGREP ' (/bin/)?cc[ |_]' >/dev/null && ac_zos_uss_cc_id=cc + echo " $CC " | $EGREP ' (/bin/)?xlc[ |_]' >/dev/null && ac_zos_uss_cc_id=xlc + echo " $CC " | $EGREP ' (/bin/)?xlC[ |_]' >/dev/null && ac_zos_uss_cc_id=xlc++ + echo " $CC " | $EGREP ' (/bin/)?xlc\+\+[ |_]' >/dev/null && ac_zos_uss_cc_id=xlc++ + test "x$GCC" = "xyes" && ac_zos_uss_cc_id=gcc + CPPFLAGS="$CPPFLAGS -D_ALL_SOURCE -D_OPEN_SYS_UNLOCKED_EXT" + test "$ac_zos_uss_cc_id" != xlc++ && CPPFLAGS="$CPPFLAGS -D_XOPEN_SOURCE=600" + case "$ac_zos_uss_cc_id" in + c89) + if test -n "$_C89_OPTIONS" + then + { $as_echo "$as_me:${as_lineno-$LINENO}: CC = $CC" >&5 +$as_echo "$as_me: CC = $CC" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: _C89_OPTIONS = $_C89_OPTIONS" >&5 +$as_echo "$as_me: _C89_OPTIONS = $_C89_OPTIONS" >&6;} + else + as_fn_error $? "c89-setup-required +To build GNU Awk using \"c89\", please set + + _C89_OPTIONS=\"-W c,langlvl(stdc99,libext),haltonmsg(CCN3296)\" + +in your environment, and reconfigure. (The above flags cannot be specified +in CFLAGS/CPPFLAGS, due to the parentheses.)" "$LINENO" 5 + fi + ;; + gcc) + ;; + cc) + as_fn_error $? "cc-invalid +The z/OS \"cc\" compiler does not build GNU Awk correctly. + +If the \"xlc\" or \"c89\" compiler is available, please set CC accordingly +and reconfigure. (\"xlc\" is the recommended compiler on z/OS.)" "$LINENO" 5 + ;; + xlc*) + CFLAGS="$CFLAGS -qlanglvl=stdc99:libext" + cat >zos-cc < directives) rather +# than before. +# +# This script allows the code and the build system to assume standard +# compiler behavior. +# + +PS4='zos-cc: ' +REAL_CC="$CC" + +set -x +\$REAL_CC -qhaltonmsg=CCN3296 -qnosearch "\$@" -qsearch=/usr/include +EOF + chmod +x zos-cc + { $as_echo "$as_me:${as_lineno-$LINENO}: wrapping $CC with zos-cc to obtain standard behavior" >&5 +$as_echo "$as_me: wrapping $CC with zos-cc to obtain standard behavior" >&6;} + CC="`pwd`/zos-cc" + ;; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized compiler environment" >&5 +$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 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_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char strerror (); +int +main () +{ +return strerror (); + ; + return 0; +} +_ACEOF +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 + 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 : + enableval=$enable_largefile; +fi + +if test "$enable_largefile" != no; then + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 +$as_echo_n "checking for special C compiler options needed for large files... " >&6; } +if ${ac_cv_sys_largefile_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_sys_largefile_CC=no + if test "$GCC" != yes; then + ac_save_CC=$CC + while :; do + # IRIX 6.2 and later do not support large files by default, + # so use the C compiler's -n32 option if that helps. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF + if ac_fn_c_try_compile "$LINENO"; then : + break +fi +rm -f core conftest.err conftest.$ac_objext + CC="$CC -n32" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_largefile_CC=' -n32'; break +fi +rm -f core conftest.err conftest.$ac_objext + break + done + CC=$ac_save_CC + rm -f conftest.$ac_ext + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 +$as_echo "$ac_cv_sys_largefile_CC" >&6; } + if test "$ac_cv_sys_largefile_CC" != no; then + CC=$CC$ac_cv_sys_largefile_CC + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 +$as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } +if ${ac_cv_sys_file_offset_bits+:} false; then : + $as_echo_n "(cached) " >&6 +else + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_file_offset_bits=no; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _FILE_OFFSET_BITS 64 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_file_offset_bits=64; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cv_sys_file_offset_bits=unknown + break +done +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 +$as_echo "$ac_cv_sys_file_offset_bits" >&6; } +case $ac_cv_sys_file_offset_bits in #( + no | unknown) ;; + *) +cat >>confdefs.h <<_ACEOF +#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits +_ACEOF +;; +esac +rm -rf conftest* + if test $ac_cv_sys_file_offset_bits = unknown; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 +$as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; } +if ${ac_cv_sys_large_files+:} false; then : + $as_echo_n "(cached) " >&6 +else + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_large_files=no; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _LARGE_FILES 1 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_large_files=1; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cv_sys_large_files=unknown + break +done +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 +$as_echo "$ac_cv_sys_large_files" >&6; } +case $ac_cv_sys_large_files in #( + no | unknown) ;; + *) +cat >>confdefs.h <<_ACEOF +#define _LARGE_FILES $ac_cv_sys_large_files +_ACEOF +;; +esac +rm -rf conftest* + fi + + +fi + + +{ $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 +/* end confdefs.h. */ +#if 'a' == 0x81 +gnu_gawk_in_ebcdic +#endif +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "gnu_gawk_in_ebcdic" >/dev/null 2>&1; then : + +$as_echo "#define USE_EBCDIC 1" >>confdefs.h + + use_ebcdic=yes +else + use_ebcdic=no +fi +rm -f conftest* + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $use_ebcdic" >&5 +$as_echo "$use_ebcdic" >&6; } + +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 for a sed that does not truncate output" >&5 +$as_echo_n "checking for a sed that does not truncate output... " >&6; } +if ${ac_cv_path_SED+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ + for ac_i in 1 2 3 4 5 6 7; do + ac_script="$ac_script$as_nl$ac_script" + done + echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed + { ac_script=; unset ac_script;} + if test -z "$SED"; then + ac_path_SED_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + 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_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_SED" || continue +# Check for GNU ac_path_SED and select it if it is found. + # Check for GNU $ac_path_SED +case `"$ac_path_SED" --version 2>&1` in +*GNU*) + ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo '' >> "conftest.nl" + "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_SED_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_SED="$ac_path_SED" + ac_path_SED_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_SED_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_SED"; then + as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 + fi +else + ac_cv_path_SED=$SED +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 +$as_echo "$ac_cv_path_SED" >&6; } + SED="$ac_cv_path_SED" + rm -f conftest.sed + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether NLS is requested" >&5 +$as_echo_n "checking whether NLS is requested... " >&6; } + # Check whether --enable-nls was given. +if test "${enable_nls+set}" = set; then : + enableval=$enable_nls; USE_NLS=$enableval +else + USE_NLS=yes +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_NLS" >&5 +$as_echo "$USE_NLS" >&6; } + + + + + GETTEXT_MACRO_VERSION=0.19 + + + + +# Prepare PATH_SEPARATOR. +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + # Determine PATH_SEPARATOR by trying to find /bin/sh in a PATH which + # contains only /bin. Note that ksh looks also at the FPATH variable, + # so we have to set that as well for the test. + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \ + && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \ + || PATH_SEPARATOR=';' + } +fi + +# Find out how to test for executable files. Don't use a zero-byte file, +# as systems may use methods other than mode bits to determine executability. +cat >conf$$.file <<_ASEOF +#! /bin/sh +exit 0 +_ASEOF +chmod +x conf$$.file +if test -x conf$$.file >/dev/null 2>&1; then + ac_executable_p="test -x" +else + ac_executable_p="test -f" +fi +rm -f conf$$.file + +# Extract the first word of "msgfmt", so it can be a program name with args. +set dummy msgfmt; 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_path_MSGFMT+:} false; then : + $as_echo_n "(cached) " >&6 +else + case "$MSGFMT" in + [\\/]* | ?:[\\/]*) + ac_cv_path_MSGFMT="$MSGFMT" # Let the user override the test with a path. + ;; + *) + ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$ac_save_IFS" + test -z "$ac_dir" && ac_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then + echo "$as_me: trying $ac_dir/$ac_word..." >&5 + if $ac_dir/$ac_word --statistics /dev/null >&5 2>&1 && + (if $ac_dir/$ac_word --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi); then + ac_cv_path_MSGFMT="$ac_dir/$ac_word$ac_exec_ext" + break 2 + fi + fi + done + done + IFS="$ac_save_IFS" + test -z "$ac_cv_path_MSGFMT" && ac_cv_path_MSGFMT=":" + ;; +esac +fi +MSGFMT="$ac_cv_path_MSGFMT" +if test "$MSGFMT" != ":"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MSGFMT" >&5 +$as_echo "$MSGFMT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + # Extract the first word of "gmsgfmt", so it can be a program name with args. +set dummy gmsgfmt; 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_path_GMSGFMT+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $GMSGFMT in + [\\/]* | ?:[\\/]*) + ac_cv_path_GMSGFMT="$GMSGFMT" # Let the user override the test with a path. + ;; + *) + 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_path_GMSGFMT="$as_dir/$ac_word$ac_exec_ext" + $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 + + test -z "$ac_cv_path_GMSGFMT" && ac_cv_path_GMSGFMT="$MSGFMT" + ;; +esac +fi +GMSGFMT=$ac_cv_path_GMSGFMT +if test -n "$GMSGFMT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GMSGFMT" >&5 +$as_echo "$GMSGFMT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + case `$MSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in + '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) MSGFMT_015=: ;; + *) MSGFMT_015=$MSGFMT ;; + esac + + case `$GMSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in + '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) GMSGFMT_015=: ;; + *) GMSGFMT_015=$GMSGFMT ;; + esac + + + +# Prepare PATH_SEPARATOR. +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + # Determine PATH_SEPARATOR by trying to find /bin/sh in a PATH which + # contains only /bin. Note that ksh looks also at the FPATH variable, + # so we have to set that as well for the test. + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \ + && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \ + || PATH_SEPARATOR=';' + } +fi + +# Find out how to test for executable files. Don't use a zero-byte file, +# as systems may use methods other than mode bits to determine executability. +cat >conf$$.file <<_ASEOF +#! /bin/sh +exit 0 +_ASEOF +chmod +x conf$$.file +if test -x conf$$.file >/dev/null 2>&1; then + ac_executable_p="test -x" +else + ac_executable_p="test -f" +fi +rm -f conf$$.file + +# Extract the first word of "xgettext", so it can be a program name with args. +set dummy xgettext; 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_path_XGETTEXT+:} false; then : + $as_echo_n "(cached) " >&6 +else + case "$XGETTEXT" in + [\\/]* | ?:[\\/]*) + ac_cv_path_XGETTEXT="$XGETTEXT" # Let the user override the test with a path. + ;; + *) + ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$ac_save_IFS" + test -z "$ac_dir" && ac_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then + echo "$as_me: trying $ac_dir/$ac_word..." >&5 + if $ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null >&5 2>&1 && + (if $ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi); then + ac_cv_path_XGETTEXT="$ac_dir/$ac_word$ac_exec_ext" + break 2 + fi + fi + done + done + IFS="$ac_save_IFS" + test -z "$ac_cv_path_XGETTEXT" && ac_cv_path_XGETTEXT=":" + ;; +esac +fi +XGETTEXT="$ac_cv_path_XGETTEXT" +if test "$XGETTEXT" != ":"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $XGETTEXT" >&5 +$as_echo "$XGETTEXT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + rm -f messages.po + + case `$XGETTEXT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in + '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) XGETTEXT_015=: ;; + *) XGETTEXT_015=$XGETTEXT ;; + esac + + + +# Prepare PATH_SEPARATOR. +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + # Determine PATH_SEPARATOR by trying to find /bin/sh in a PATH which + # contains only /bin. Note that ksh looks also at the FPATH variable, + # so we have to set that as well for the test. + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \ + && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \ + || PATH_SEPARATOR=';' + } +fi + +# Find out how to test for executable files. Don't use a zero-byte file, +# as systems may use methods other than mode bits to determine executability. +cat >conf$$.file <<_ASEOF +#! /bin/sh +exit 0 +_ASEOF +chmod +x conf$$.file +if test -x conf$$.file >/dev/null 2>&1; then + ac_executable_p="test -x" +else + ac_executable_p="test -f" +fi +rm -f conf$$.file + +# Extract the first word of "msgmerge", so it can be a program name with args. +set dummy msgmerge; 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_path_MSGMERGE+:} false; then : + $as_echo_n "(cached) " >&6 +else + case "$MSGMERGE" in + [\\/]* | ?:[\\/]*) + ac_cv_path_MSGMERGE="$MSGMERGE" # Let the user override the test with a path. + ;; + *) + ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$ac_save_IFS" + test -z "$ac_dir" && ac_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then + echo "$as_me: trying $ac_dir/$ac_word..." >&5 + if $ac_dir/$ac_word --update -q /dev/null /dev/null >&5 2>&1; then + ac_cv_path_MSGMERGE="$ac_dir/$ac_word$ac_exec_ext" + break 2 + fi + fi + done + done + IFS="$ac_save_IFS" + test -z "$ac_cv_path_MSGMERGE" && ac_cv_path_MSGMERGE=":" + ;; +esac +fi +MSGMERGE="$ac_cv_path_MSGMERGE" +if test "$MSGMERGE" != ":"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MSGMERGE" >&5 +$as_echo "$MSGMERGE" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$localedir" || localedir='${datadir}/locale' + + + test -n "${XGETTEXT_EXTRA_OPTIONS+set}" || XGETTEXT_EXTRA_OPTIONS= + + + ac_config_commands="$ac_config_commands po-directories" + + + + if test "X$prefix" = "XNONE"; then + acl_final_prefix="$ac_default_prefix" + else + acl_final_prefix="$prefix" + fi + if test "X$exec_prefix" = "XNONE"; then + acl_final_exec_prefix='${prefix}' + else + acl_final_exec_prefix="$exec_prefix" + fi + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" + prefix="$acl_save_prefix" + + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then : + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +# Prepare PATH_SEPARATOR. +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + # Determine PATH_SEPARATOR by trying to find /bin/sh in a PATH which + # contains only /bin. Note that ksh looks also at the FPATH variable, + # so we have to set that as well for the test. + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \ + && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \ + || PATH_SEPARATOR=';' + } +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 +$as_echo_n "checking for ld used by $CC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`echo "$ac_prog"| sed 's%\\\\%/%g'` + while echo "$ac_prog" | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if ${acl_cv_path_LD+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + acl_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$acl_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + acl_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$acl_cv_path_LD" -v 2>&1 &5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if ${acl_cv_prog_gnu_ld+:} false; then : + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 &5 +$as_echo "$acl_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$acl_cv_prog_gnu_ld + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shared library run path origin" >&5 +$as_echo_n "checking for shared library run path origin... " >&6; } +if ${acl_cv_rpath+:} false; then : + $as_echo_n "(cached) " >&6 +else + + CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ + ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh + . ./conftest.sh + rm -f ./conftest.sh + acl_cv_rpath=done + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $acl_cv_rpath" >&5 +$as_echo "$acl_cv_rpath" >&6; } + wl="$acl_cv_wl" + acl_libext="$acl_cv_libext" + acl_shlibext="$acl_cv_shlibext" + acl_libname_spec="$acl_cv_libname_spec" + acl_library_names_spec="$acl_cv_library_names_spec" + acl_hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" + acl_hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" + acl_hardcode_direct="$acl_cv_hardcode_direct" + acl_hardcode_minus_L="$acl_cv_hardcode_minus_L" + # Check whether --enable-rpath was given. +if test "${enable_rpath+set}" = set; then : + enableval=$enable_rpath; : +else + enable_rpath=yes +fi + + + + + acl_libdirstem=lib + acl_libdirstem2= + case "$host_os" in + solaris*) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 64-bit host" >&5 +$as_echo_n "checking for 64-bit host... " >&6; } +if ${gl_cv_solaris_64bit+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#ifdef _LP64 +sixtyfour bits +#endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "sixtyfour bits" >/dev/null 2>&1; then : + gl_cv_solaris_64bit=yes +else + gl_cv_solaris_64bit=no +fi +rm -f conftest* + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_solaris_64bit" >&5 +$as_echo "$gl_cv_solaris_64bit" >&6; } + if test $gl_cv_solaris_64bit = yes; then + acl_libdirstem=lib/64 + case "$host_cpu" in + sparc*) acl_libdirstem2=lib/sparcv9 ;; + i*86 | x86_64) acl_libdirstem2=lib/amd64 ;; + esac + fi + ;; + *) + searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'` + if test -n "$searchpath"; then + acl_save_IFS="${IFS= }"; IFS=":" + for searchdir in $searchpath; do + if test -d "$searchdir"; then + case "$searchdir" in + */lib64/ | */lib64 ) acl_libdirstem=lib64 ;; + */../ | */.. ) + # Better ignore directories of this form. They are misleading. + ;; + *) searchdir=`cd "$searchdir" && pwd` + case "$searchdir" in + */lib64 ) acl_libdirstem=lib64 ;; + esac ;; + esac + fi + done + IFS="$acl_save_IFS" + fi + ;; + esac + test -n "$acl_libdirstem2" || acl_libdirstem2="$acl_libdirstem" + + + + + + + + + + + + + use_additional=yes + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + +# Check whether --with-libiconv-prefix was given. +if test "${with_libiconv_prefix+set}" = set; then : + withval=$with_libiconv_prefix; + if test "X$withval" = "Xno"; then + use_additional=no + else + if test "X$withval" = "X"; then + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + else + additional_includedir="$withval/include" + additional_libdir="$withval/$acl_libdirstem" + if test "$acl_libdirstem2" != "$acl_libdirstem" \ + && ! test -d "$withval/$acl_libdirstem"; then + additional_libdir="$withval/$acl_libdirstem2" + fi + fi + fi + +fi + + LIBICONV= + LTLIBICONV= + INCICONV= + LIBICONV_PREFIX= + HAVE_LIBICONV= + rpathdirs= + ltrpathdirs= + names_already_handled= + names_next_round='iconv ' + while test -n "$names_next_round"; do + names_this_round="$names_next_round" + names_next_round= + for name in $names_this_round; do + already_handled= + for n in $names_already_handled; do + if test "$n" = "$name"; then + already_handled=yes + break + fi + done + if test -z "$already_handled"; then + names_already_handled="$names_already_handled $name" + uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./+-|ABCDEFGHIJKLMNOPQRSTUVWXYZ____|'` + eval value=\"\$HAVE_LIB$uppername\" + if test -n "$value"; then + if test "$value" = yes; then + eval value=\"\$LIB$uppername\" + test -z "$value" || LIBICONV="${LIBICONV}${LIBICONV:+ }$value" + eval value=\"\$LTLIB$uppername\" + test -z "$value" || LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }$value" + else + : + fi + else + found_dir= + found_la= + found_so= + found_a= + eval libname=\"$acl_libname_spec\" # typically: libname=lib$name + if test -n "$acl_shlibext"; then + shrext=".$acl_shlibext" # typically: shrext=.so + else + shrext= + fi + if test $use_additional = yes; then + dir="$additional_libdir" + if test -n "$acl_shlibext"; then + if test -f "$dir/$libname$shrext"; then + found_dir="$dir" + found_so="$dir/$libname$shrext" + else + if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then + ver=`(cd "$dir" && \ + for f in "$libname$shrext".*; do echo "$f"; done \ + | sed -e "s,^$libname$shrext\\\\.,," \ + | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ + | sed 1q ) 2>/dev/null` + if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then + found_dir="$dir" + found_so="$dir/$libname$shrext.$ver" + fi + else + eval library_names=\"$acl_library_names_spec\" + for f in $library_names; do + if test -f "$dir/$f"; then + found_dir="$dir" + found_so="$dir/$f" + break + fi + done + fi + fi + fi + if test "X$found_dir" = "X"; then + if test -f "$dir/$libname.$acl_libext"; then + found_dir="$dir" + found_a="$dir/$libname.$acl_libext" + fi + fi + if test "X$found_dir" != "X"; then + if test -f "$dir/$libname.la"; then + found_la="$dir/$libname.la" + fi + fi + fi + if test "X$found_dir" = "X"; then + for x in $LDFLAGS $LTLIBICONV; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + case "$x" in + -L*) + dir=`echo "X$x" | sed -e 's/^X-L//'` + if test -n "$acl_shlibext"; then + if test -f "$dir/$libname$shrext"; then + found_dir="$dir" + found_so="$dir/$libname$shrext" + else + if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then + ver=`(cd "$dir" && \ + for f in "$libname$shrext".*; do echo "$f"; done \ + | sed -e "s,^$libname$shrext\\\\.,," \ + | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ + | sed 1q ) 2>/dev/null` + if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then + found_dir="$dir" + found_so="$dir/$libname$shrext.$ver" + fi + else + eval library_names=\"$acl_library_names_spec\" + for f in $library_names; do + if test -f "$dir/$f"; then + found_dir="$dir" + found_so="$dir/$f" + break + fi + done + fi + fi + fi + if test "X$found_dir" = "X"; then + if test -f "$dir/$libname.$acl_libext"; then + found_dir="$dir" + found_a="$dir/$libname.$acl_libext" + fi + fi + if test "X$found_dir" != "X"; then + if test -f "$dir/$libname.la"; then + found_la="$dir/$libname.la" + fi + fi + ;; + esac + if test "X$found_dir" != "X"; then + break + fi + done + fi + if test "X$found_dir" != "X"; then + LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-L$found_dir -l$name" + if test "X$found_so" != "X"; then + if test "$enable_rpath" = no \ + || test "X$found_dir" = "X/usr/$acl_libdirstem" \ + || test "X$found_dir" = "X/usr/$acl_libdirstem2"; then + LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" + else + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $found_dir" + fi + if test "$acl_hardcode_direct" = yes; then + LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" + else + if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then + LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $found_dir" + fi + else + haveit= + for x in $LDFLAGS $LIBICONV; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + LIBICONV="${LIBICONV}${LIBICONV:+ }-L$found_dir" + fi + if test "$acl_hardcode_minus_L" != no; then + LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" + else + LIBICONV="${LIBICONV}${LIBICONV:+ }-l$name" + fi + fi + fi + fi + else + if test "X$found_a" != "X"; then + LIBICONV="${LIBICONV}${LIBICONV:+ }$found_a" + else + LIBICONV="${LIBICONV}${LIBICONV:+ }-L$found_dir -l$name" + fi + fi + additional_includedir= + case "$found_dir" in + */$acl_libdirstem | */$acl_libdirstem/) + basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` + if test "$name" = 'iconv'; then + LIBICONV_PREFIX="$basedir" + fi + additional_includedir="$basedir/include" + ;; + */$acl_libdirstem2 | */$acl_libdirstem2/) + basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem2/"'*$,,'` + if test "$name" = 'iconv'; then + LIBICONV_PREFIX="$basedir" + fi + additional_includedir="$basedir/include" + ;; + esac + if test "X$additional_includedir" != "X"; then + if test "X$additional_includedir" != "X/usr/include"; then + haveit= + if test "X$additional_includedir" = "X/usr/local/include"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + for x in $CPPFLAGS $INCICONV; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-I$additional_includedir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_includedir"; then + INCICONV="${INCICONV}${INCICONV:+ }-I$additional_includedir" + fi + fi + fi + fi + fi + if test -n "$found_la"; then + save_libdir="$libdir" + case "$found_la" in + */* | *\\*) . "$found_la" ;; + *) . "./$found_la" ;; + esac + libdir="$save_libdir" + for dep in $dependency_libs; do + case "$dep" in + -L*) + additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` + if test "X$additional_libdir" != "X/usr/$acl_libdirstem" \ + && test "X$additional_libdir" != "X/usr/$acl_libdirstem2"; then + haveit= + if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem" \ + || test "X$additional_libdir" = "X/usr/local/$acl_libdirstem2"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + haveit= + for x in $LDFLAGS $LIBICONV; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + LIBICONV="${LIBICONV}${LIBICONV:+ }-L$additional_libdir" + fi + fi + haveit= + for x in $LDFLAGS $LTLIBICONV; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-L$additional_libdir" + fi + fi + fi + fi + ;; + -R*) + dir=`echo "X$dep" | sed -e 's/^X-R//'` + if test "$enable_rpath" != no; then + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $dir" + fi + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $dir" + fi + fi + ;; + -l*) + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` + ;; + *.la) + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` + ;; + *) + LIBICONV="${LIBICONV}${LIBICONV:+ }$dep" + LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }$dep" + ;; + esac + done + fi + else + LIBICONV="${LIBICONV}${LIBICONV:+ }-l$name" + LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-l$name" + fi + fi + fi + done + done + if test "X$rpathdirs" != "X"; then + if test -n "$acl_hardcode_libdir_separator"; then + alldirs= + for found_dir in $rpathdirs; do + alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$found_dir" + done + acl_save_libdir="$libdir" + libdir="$alldirs" + eval flag=\"$acl_hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIBICONV="${LIBICONV}${LIBICONV:+ }$flag" + else + for found_dir in $rpathdirs; do + acl_save_libdir="$libdir" + libdir="$found_dir" + eval flag=\"$acl_hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIBICONV="${LIBICONV}${LIBICONV:+ }$flag" + done + fi + fi + if test "X$ltrpathdirs" != "X"; then + for found_dir in $ltrpathdirs; do + LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-R$found_dir" + done + fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CFPreferencesCopyAppValue" >&5 +$as_echo_n "checking for CFPreferencesCopyAppValue... " >&6; } +if ${gt_cv_func_CFPreferencesCopyAppValue+:} false; then : + $as_echo_n "(cached) " >&6 +else + gt_save_LIBS="$LIBS" + LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +CFPreferencesCopyAppValue(NULL, NULL) + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + gt_cv_func_CFPreferencesCopyAppValue=yes +else + gt_cv_func_CFPreferencesCopyAppValue=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$gt_save_LIBS" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_cv_func_CFPreferencesCopyAppValue" >&5 +$as_echo "$gt_cv_func_CFPreferencesCopyAppValue" >&6; } + if test $gt_cv_func_CFPreferencesCopyAppValue = yes; then + +$as_echo "#define HAVE_CFPREFERENCESCOPYAPPVALUE 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CFLocaleCopyCurrent" >&5 +$as_echo_n "checking for CFLocaleCopyCurrent... " >&6; } +if ${gt_cv_func_CFLocaleCopyCurrent+:} false; then : + $as_echo_n "(cached) " >&6 +else + gt_save_LIBS="$LIBS" + LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +CFLocaleCopyCurrent(); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + gt_cv_func_CFLocaleCopyCurrent=yes +else + gt_cv_func_CFLocaleCopyCurrent=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$gt_save_LIBS" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_cv_func_CFLocaleCopyCurrent" >&5 +$as_echo "$gt_cv_func_CFLocaleCopyCurrent" >&6; } + if test $gt_cv_func_CFLocaleCopyCurrent = yes; then + +$as_echo "#define HAVE_CFLOCALECOPYCURRENT 1" >>confdefs.h + + fi + INTL_MACOSX_LIBS= + if test $gt_cv_func_CFPreferencesCopyAppValue = yes || test $gt_cv_func_CFLocaleCopyCurrent = yes; then + INTL_MACOSX_LIBS="-Wl,-framework -Wl,CoreFoundation" + fi + + + + + + + LIBINTL= + LTLIBINTL= + POSUB= + + case " $gt_needs " in + *" need-formatstring-macros "*) gt_api_version=3 ;; + *" need-ngettext "*) gt_api_version=2 ;; + *) gt_api_version=1 ;; + esac + gt_func_gnugettext_libc="gt_cv_func_gnugettext${gt_api_version}_libc" + gt_func_gnugettext_libintl="gt_cv_func_gnugettext${gt_api_version}_libintl" + + if test "$USE_NLS" = "yes"; then + gt_use_preinstalled_gnugettext=no + + + if test $gt_api_version -ge 3; then + gt_revision_test_code=' +#ifndef __GNU_GETTEXT_SUPPORTED_REVISION +#define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1) +#endif +typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1]; +' + else + gt_revision_test_code= + fi + if test $gt_api_version -ge 2; then + gt_expression_test_code=' + * ngettext ("", "", 0)' + else + gt_expression_test_code= + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU gettext in libc" >&5 +$as_echo_n "checking for GNU gettext in libc... " >&6; } +if eval \${$gt_func_gnugettext_libc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +$gt_revision_test_code +extern int _nl_msg_cat_cntr; +extern int *_nl_domain_bindings; + +int +main () +{ + +bindtextdomain ("", ""); +return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_domain_bindings + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$gt_func_gnugettext_libc=yes" +else + eval "$gt_func_gnugettext_libc=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$gt_func_gnugettext_libc + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + + if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" != "yes"; }; then + + + + + + am_save_CPPFLAGS="$CPPFLAGS" + + for element in $INCICONV; do + haveit= + for x in $CPPFLAGS; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X$element"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element" + fi + done + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv" >&5 +$as_echo_n "checking for iconv... " >&6; } +if ${am_cv_func_iconv+:} false; then : + $as_echo_n "(cached) " >&6 +else + + am_cv_func_iconv="no, consider installing GNU libiconv" + am_cv_lib_iconv=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include + +int +main () +{ +iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + am_cv_func_iconv=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test "$am_cv_func_iconv" != yes; then + am_save_LIBS="$LIBS" + LIBS="$LIBS $LIBICONV" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include + +int +main () +{ +iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + am_cv_lib_iconv=yes + am_cv_func_iconv=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$am_save_LIBS" + fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_func_iconv" >&5 +$as_echo "$am_cv_func_iconv" >&6; } + if test "$am_cv_func_iconv" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working iconv" >&5 +$as_echo_n "checking for working iconv... " >&6; } +if ${am_cv_func_iconv_works+:} false; then : + $as_echo_n "(cached) " >&6 +else + + am_save_LIBS="$LIBS" + if test $am_cv_lib_iconv = yes; then + LIBS="$LIBS $LIBICONV" + fi + am_cv_func_iconv_works=no + for ac_iconv_const in '' 'const'; do + if test "$cross_compiling" = yes; then : + case "$host_os" in + aix* | hpux*) am_cv_func_iconv_works="guessing no" ;; + *) am_cv_func_iconv_works="guessing yes" ;; + esac +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include + +#ifndef ICONV_CONST +# define ICONV_CONST $ac_iconv_const +#endif + +int +main () +{ +int result = 0; + /* Test against AIX 5.1 bug: Failures are not distinguishable from successful + returns. */ + { + iconv_t cd_utf8_to_88591 = iconv_open ("ISO8859-1", "UTF-8"); + if (cd_utf8_to_88591 != (iconv_t)(-1)) + { + static ICONV_CONST char input[] = "\342\202\254"; /* EURO SIGN */ + char buf[10]; + ICONV_CONST char *inptr = input; + size_t inbytesleft = strlen (input); + char *outptr = buf; + size_t outbytesleft = sizeof (buf); + size_t res = iconv (cd_utf8_to_88591, + &inptr, &inbytesleft, + &outptr, &outbytesleft); + if (res == 0) + result |= 1; + iconv_close (cd_utf8_to_88591); + } + } + /* Test against Solaris 10 bug: Failures are not distinguishable from + successful returns. */ + { + iconv_t cd_ascii_to_88591 = iconv_open ("ISO8859-1", "646"); + if (cd_ascii_to_88591 != (iconv_t)(-1)) + { + static ICONV_CONST char input[] = "\263"; + char buf[10]; + ICONV_CONST char *inptr = input; + size_t inbytesleft = strlen (input); + char *outptr = buf; + size_t outbytesleft = sizeof (buf); + size_t res = iconv (cd_ascii_to_88591, + &inptr, &inbytesleft, + &outptr, &outbytesleft); + if (res == 0) + result |= 2; + iconv_close (cd_ascii_to_88591); + } + } + /* Test against AIX 6.1..7.1 bug: Buffer overrun. */ + { + iconv_t cd_88591_to_utf8 = iconv_open ("UTF-8", "ISO-8859-1"); + if (cd_88591_to_utf8 != (iconv_t)(-1)) + { + static ICONV_CONST char input[] = "\304"; + static char buf[2] = { (char)0xDE, (char)0xAD }; + ICONV_CONST char *inptr = input; + size_t inbytesleft = 1; + char *outptr = buf; + size_t outbytesleft = 1; + size_t res = iconv (cd_88591_to_utf8, + &inptr, &inbytesleft, + &outptr, &outbytesleft); + if (res != (size_t)(-1) || outptr - buf > 1 || buf[1] != (char)0xAD) + result |= 4; + iconv_close (cd_88591_to_utf8); + } + } +#if 0 /* This bug could be worked around by the caller. */ + /* Test against HP-UX 11.11 bug: Positive return value instead of 0. */ + { + iconv_t cd_88591_to_utf8 = iconv_open ("utf8", "iso88591"); + if (cd_88591_to_utf8 != (iconv_t)(-1)) + { + static ICONV_CONST char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337"; + char buf[50]; + ICONV_CONST char *inptr = input; + size_t inbytesleft = strlen (input); + char *outptr = buf; + size_t outbytesleft = sizeof (buf); + size_t res = iconv (cd_88591_to_utf8, + &inptr, &inbytesleft, + &outptr, &outbytesleft); + if ((int)res > 0) + result |= 8; + iconv_close (cd_88591_to_utf8); + } + } +#endif + /* Test against HP-UX 11.11 bug: No converter from EUC-JP to UTF-8 is + provided. */ + if (/* Try standardized names. */ + iconv_open ("UTF-8", "EUC-JP") == (iconv_t)(-1) + /* Try IRIX, OSF/1 names. */ + && iconv_open ("UTF-8", "eucJP") == (iconv_t)(-1) + /* Try AIX names. */ + && iconv_open ("UTF-8", "IBM-eucJP") == (iconv_t)(-1) + /* Try HP-UX names. */ + && iconv_open ("utf8", "eucJP") == (iconv_t)(-1)) + result |= 16; + return result; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + am_cv_func_iconv_works=yes +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + test "$am_cv_func_iconv_works" = no || break + done + LIBS="$am_save_LIBS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_func_iconv_works" >&5 +$as_echo "$am_cv_func_iconv_works" >&6; } + case "$am_cv_func_iconv_works" in + *no) am_func_iconv=no am_cv_lib_iconv=no ;; + *) am_func_iconv=yes ;; + esac + else + am_func_iconv=no am_cv_lib_iconv=no + fi + if test "$am_func_iconv" = yes; then + +$as_echo "#define HAVE_ICONV 1" >>confdefs.h + + fi + if test "$am_cv_lib_iconv" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libiconv" >&5 +$as_echo_n "checking how to link with libiconv... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBICONV" >&5 +$as_echo "$LIBICONV" >&6; } + else + CPPFLAGS="$am_save_CPPFLAGS" + LIBICONV= + LTLIBICONV= + fi + + + + + + + + + + + + use_additional=yes + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + +# Check whether --with-libintl-prefix was given. +if test "${with_libintl_prefix+set}" = set; then : + withval=$with_libintl_prefix; + if test "X$withval" = "Xno"; then + use_additional=no + else + if test "X$withval" = "X"; then + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + else + additional_includedir="$withval/include" + additional_libdir="$withval/$acl_libdirstem" + if test "$acl_libdirstem2" != "$acl_libdirstem" \ + && ! test -d "$withval/$acl_libdirstem"; then + additional_libdir="$withval/$acl_libdirstem2" + fi + fi + fi + +fi + + LIBINTL= + LTLIBINTL= + INCINTL= + LIBINTL_PREFIX= + HAVE_LIBINTL= + rpathdirs= + ltrpathdirs= + names_already_handled= + names_next_round='intl ' + while test -n "$names_next_round"; do + names_this_round="$names_next_round" + names_next_round= + for name in $names_this_round; do + already_handled= + for n in $names_already_handled; do + if test "$n" = "$name"; then + already_handled=yes + break + fi + done + if test -z "$already_handled"; then + names_already_handled="$names_already_handled $name" + uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./+-|ABCDEFGHIJKLMNOPQRSTUVWXYZ____|'` + eval value=\"\$HAVE_LIB$uppername\" + if test -n "$value"; then + if test "$value" = yes; then + eval value=\"\$LIB$uppername\" + test -z "$value" || LIBINTL="${LIBINTL}${LIBINTL:+ }$value" + eval value=\"\$LTLIB$uppername\" + test -z "$value" || LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }$value" + else + : + fi + else + found_dir= + found_la= + found_so= + found_a= + eval libname=\"$acl_libname_spec\" # typically: libname=lib$name + if test -n "$acl_shlibext"; then + shrext=".$acl_shlibext" # typically: shrext=.so + else + shrext= + fi + if test $use_additional = yes; then + dir="$additional_libdir" + if test -n "$acl_shlibext"; then + if test -f "$dir/$libname$shrext"; then + found_dir="$dir" + found_so="$dir/$libname$shrext" + else + if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then + ver=`(cd "$dir" && \ + for f in "$libname$shrext".*; do echo "$f"; done \ + | sed -e "s,^$libname$shrext\\\\.,," \ + | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ + | sed 1q ) 2>/dev/null` + if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then + found_dir="$dir" + found_so="$dir/$libname$shrext.$ver" + fi + else + eval library_names=\"$acl_library_names_spec\" + for f in $library_names; do + if test -f "$dir/$f"; then + found_dir="$dir" + found_so="$dir/$f" + break + fi + done + fi + fi + fi + if test "X$found_dir" = "X"; then + if test -f "$dir/$libname.$acl_libext"; then + found_dir="$dir" + found_a="$dir/$libname.$acl_libext" + fi + fi + if test "X$found_dir" != "X"; then + if test -f "$dir/$libname.la"; then + found_la="$dir/$libname.la" + fi + fi + fi + if test "X$found_dir" = "X"; then + for x in $LDFLAGS $LTLIBINTL; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + case "$x" in + -L*) + dir=`echo "X$x" | sed -e 's/^X-L//'` + if test -n "$acl_shlibext"; then + if test -f "$dir/$libname$shrext"; then + found_dir="$dir" + found_so="$dir/$libname$shrext" + else + if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then + ver=`(cd "$dir" && \ + for f in "$libname$shrext".*; do echo "$f"; done \ + | sed -e "s,^$libname$shrext\\\\.,," \ + | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ + | sed 1q ) 2>/dev/null` + if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then + found_dir="$dir" + found_so="$dir/$libname$shrext.$ver" + fi + else + eval library_names=\"$acl_library_names_spec\" + for f in $library_names; do + if test -f "$dir/$f"; then + found_dir="$dir" + found_so="$dir/$f" + break + fi + done + fi + fi + fi + if test "X$found_dir" = "X"; then + if test -f "$dir/$libname.$acl_libext"; then + found_dir="$dir" + found_a="$dir/$libname.$acl_libext" + fi + fi + if test "X$found_dir" != "X"; then + if test -f "$dir/$libname.la"; then + found_la="$dir/$libname.la" + fi + fi + ;; + esac + if test "X$found_dir" != "X"; then + break + fi + done + fi + if test "X$found_dir" != "X"; then + LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }-L$found_dir -l$name" + if test "X$found_so" != "X"; then + if test "$enable_rpath" = no \ + || test "X$found_dir" = "X/usr/$acl_libdirstem" \ + || test "X$found_dir" = "X/usr/$acl_libdirstem2"; then + LIBINTL="${LIBINTL}${LIBINTL:+ }$found_so" + else + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $found_dir" + fi + if test "$acl_hardcode_direct" = yes; then + LIBINTL="${LIBINTL}${LIBINTL:+ }$found_so" + else + if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then + LIBINTL="${LIBINTL}${LIBINTL:+ }$found_so" + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $found_dir" + fi + else + haveit= + for x in $LDFLAGS $LIBINTL; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + LIBINTL="${LIBINTL}${LIBINTL:+ }-L$found_dir" + fi + if test "$acl_hardcode_minus_L" != no; then + LIBINTL="${LIBINTL}${LIBINTL:+ }$found_so" + else + LIBINTL="${LIBINTL}${LIBINTL:+ }-l$name" + fi + fi + fi + fi + else + if test "X$found_a" != "X"; then + LIBINTL="${LIBINTL}${LIBINTL:+ }$found_a" + else + LIBINTL="${LIBINTL}${LIBINTL:+ }-L$found_dir -l$name" + fi + fi + additional_includedir= + case "$found_dir" in + */$acl_libdirstem | */$acl_libdirstem/) + basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` + if test "$name" = 'intl'; then + LIBINTL_PREFIX="$basedir" + fi + additional_includedir="$basedir/include" + ;; + */$acl_libdirstem2 | */$acl_libdirstem2/) + basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem2/"'*$,,'` + if test "$name" = 'intl'; then + LIBINTL_PREFIX="$basedir" + fi + additional_includedir="$basedir/include" + ;; + esac + if test "X$additional_includedir" != "X"; then + if test "X$additional_includedir" != "X/usr/include"; then + haveit= + if test "X$additional_includedir" = "X/usr/local/include"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + for x in $CPPFLAGS $INCINTL; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-I$additional_includedir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_includedir"; then + INCINTL="${INCINTL}${INCINTL:+ }-I$additional_includedir" + fi + fi + fi + fi + fi + if test -n "$found_la"; then + save_libdir="$libdir" + case "$found_la" in + */* | *\\*) . "$found_la" ;; + *) . "./$found_la" ;; + esac + libdir="$save_libdir" + for dep in $dependency_libs; do + case "$dep" in + -L*) + additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` + if test "X$additional_libdir" != "X/usr/$acl_libdirstem" \ + && test "X$additional_libdir" != "X/usr/$acl_libdirstem2"; then + haveit= + if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem" \ + || test "X$additional_libdir" = "X/usr/local/$acl_libdirstem2"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + haveit= + for x in $LDFLAGS $LIBINTL; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + LIBINTL="${LIBINTL}${LIBINTL:+ }-L$additional_libdir" + fi + fi + haveit= + for x in $LDFLAGS $LTLIBINTL; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }-L$additional_libdir" + fi + fi + fi + fi + ;; + -R*) + dir=`echo "X$dep" | sed -e 's/^X-R//'` + if test "$enable_rpath" != no; then + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $dir" + fi + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $dir" + fi + fi + ;; + -l*) + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` + ;; + *.la) + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` + ;; + *) + LIBINTL="${LIBINTL}${LIBINTL:+ }$dep" + LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }$dep" + ;; + esac + done + fi + else + LIBINTL="${LIBINTL}${LIBINTL:+ }-l$name" + LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }-l$name" + fi + fi + fi + done + done + if test "X$rpathdirs" != "X"; then + if test -n "$acl_hardcode_libdir_separator"; then + alldirs= + for found_dir in $rpathdirs; do + alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$found_dir" + done + acl_save_libdir="$libdir" + libdir="$alldirs" + eval flag=\"$acl_hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIBINTL="${LIBINTL}${LIBINTL:+ }$flag" + else + for found_dir in $rpathdirs; do + acl_save_libdir="$libdir" + libdir="$found_dir" + eval flag=\"$acl_hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIBINTL="${LIBINTL}${LIBINTL:+ }$flag" + done + fi + fi + if test "X$ltrpathdirs" != "X"; then + for found_dir in $ltrpathdirs; do + LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }-R$found_dir" + done + fi + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU gettext in libintl" >&5 +$as_echo_n "checking for GNU gettext in libintl... " >&6; } +if eval \${$gt_func_gnugettext_libintl+:} false; then : + $as_echo_n "(cached) " >&6 +else + gt_save_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $INCINTL" + gt_save_LIBS="$LIBS" + LIBS="$LIBS $LIBINTL" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +$gt_revision_test_code +extern int _nl_msg_cat_cntr; +extern +#ifdef __cplusplus +"C" +#endif +const char *_nl_expand_alias (const char *); + +int +main () +{ + +bindtextdomain ("", ""); +return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("") + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$gt_func_gnugettext_libintl=yes" +else + eval "$gt_func_gnugettext_libintl=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" != yes; } && test -n "$LIBICONV"; then + LIBS="$LIBS $LIBICONV" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +$gt_revision_test_code +extern int _nl_msg_cat_cntr; +extern +#ifdef __cplusplus +"C" +#endif +const char *_nl_expand_alias (const char *); + +int +main () +{ + +bindtextdomain ("", ""); +return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("") + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + LIBINTL="$LIBINTL $LIBICONV" + LTLIBINTL="$LTLIBINTL $LTLIBICONV" + eval "$gt_func_gnugettext_libintl=yes" + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + fi + CPPFLAGS="$gt_save_CPPFLAGS" + LIBS="$gt_save_LIBS" +fi +eval ac_res=\$$gt_func_gnugettext_libintl + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + fi + + if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" = "yes"; } \ + || { { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; } \ + && test "$PACKAGE" != gettext-runtime \ + && test "$PACKAGE" != gettext-tools; }; then + gt_use_preinstalled_gnugettext=yes + else + LIBINTL= + LTLIBINTL= + INCINTL= + fi + + + + if test -n "$INTL_MACOSX_LIBS"; then + if test "$gt_use_preinstalled_gnugettext" = "yes" \ + || test "$nls_cv_use_gnu_gettext" = "yes"; then + LIBINTL="$LIBINTL $INTL_MACOSX_LIBS" + LTLIBINTL="$LTLIBINTL $INTL_MACOSX_LIBS" + fi + fi + + if test "$gt_use_preinstalled_gnugettext" = "yes" \ + || test "$nls_cv_use_gnu_gettext" = "yes"; then + +$as_echo "#define ENABLE_NLS 1" >>confdefs.h + + else + USE_NLS=no + fi + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use NLS" >&5 +$as_echo_n "checking whether to use NLS... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_NLS" >&5 +$as_echo "$USE_NLS" >&6; } + if test "$USE_NLS" = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking where the gettext function comes from" >&5 +$as_echo_n "checking where the gettext function comes from... " >&6; } + if test "$gt_use_preinstalled_gnugettext" = "yes"; then + if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then + gt_source="external libintl" + else + gt_source="libc" + fi + else + gt_source="included intl directory" + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_source" >&5 +$as_echo "$gt_source" >&6; } + fi + + if test "$USE_NLS" = "yes"; then + + if test "$gt_use_preinstalled_gnugettext" = "yes"; then + if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libintl" >&5 +$as_echo_n "checking how to link with libintl... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBINTL" >&5 +$as_echo "$LIBINTL" >&6; } + + for element in $INCINTL; do + haveit= + for x in $CPPFLAGS; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X$element"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element" + fi + done + + fi + + +$as_echo "#define HAVE_GETTEXT 1" >>confdefs.h + + +$as_echo "#define HAVE_DCGETTEXT 1" >>confdefs.h + + fi + + POSUB=po + fi + + + + INTLLIBS="$LIBINTL" + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nl_langinfo and CODESET" >&5 +$as_echo_n "checking for nl_langinfo and CODESET... " >&6; } +if ${am_cv_langinfo_codeset+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +char* cs = nl_langinfo(CODESET); return !cs; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + am_cv_langinfo_codeset=yes +else + am_cv_langinfo_codeset=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_langinfo_codeset" >&5 +$as_echo "$am_cv_langinfo_codeset" >&6; } + if test $am_cv_langinfo_codeset = yes; then + +$as_echo "#define HAVE_LANGINFO_CODESET 1" >>confdefs.h + + fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for LC_MESSAGES" >&5 +$as_echo_n "checking for LC_MESSAGES... " >&6; } +if ${gt_cv_val_LC_MESSAGES+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +return LC_MESSAGES + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + gt_cv_val_LC_MESSAGES=yes +else + gt_cv_val_LC_MESSAGES=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_cv_val_LC_MESSAGES" >&5 +$as_echo "$gt_cv_val_LC_MESSAGES" >&6; } + if test $gt_cv_val_LC_MESSAGES = yes; then + +$as_echo "#define HAVE_LC_MESSAGES 1" >>confdefs.h + + fi + + +for ac_header in arpa/inet.h fcntl.h limits.h locale.h libintl.h mcheck.h \ + netdb.h netinet/in.h stdarg.h stddef.h string.h \ + sys/ioctl.h sys/param.h sys/select.h sys/socket.h sys/time.h unistd.h \ + termios.h stropts.h wchar.h wctype.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdbool.h that conforms to C99" >&5 +$as_echo_n "checking for stdbool.h that conforms to C99... " >&6; } +if ${ac_cv_header_stdbool_h+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #ifndef bool + "error: bool is not defined" + #endif + #ifndef false + "error: false is not defined" + #endif + #if false + "error: false is not 0" + #endif + #ifndef true + "error: true is not defined" + #endif + #if true != 1 + "error: true is not 1" + #endif + #ifndef __bool_true_false_are_defined + "error: __bool_true_false_are_defined is not defined" + #endif + + struct s { _Bool s: 1; _Bool t; } s; + + char a[true == 1 ? 1 : -1]; + char b[false == 0 ? 1 : -1]; + char c[__bool_true_false_are_defined == 1 ? 1 : -1]; + char d[(bool) 0.5 == true ? 1 : -1]; + /* See body of main program for 'e'. */ + char f[(_Bool) 0.0 == false ? 1 : -1]; + char g[true]; + char h[sizeof (_Bool)]; + char i[sizeof s.t]; + enum { j = false, k = true, l = false * true, m = true * 256 }; + /* The following fails for + HP aC++/ANSI C B3910B A.05.55 [Dec 04 2003]. */ + _Bool n[m]; + char o[sizeof n == m * sizeof n[0] ? 1 : -1]; + char p[-1 - (_Bool) 0 < 0 && -1 - (bool) 0 < 0 ? 1 : -1]; + /* Catch a bug in an HP-UX C compiler. See + http://gcc.gnu.org/ml/gcc-patches/2003-12/msg02303.html + http://lists.gnu.org/archive/html/bug-coreutils/2005-11/msg00161.html + */ + _Bool q = true; + _Bool *pq = &q; + +int +main () +{ + + bool e = &s; + *pq |= q; + *pq |= ! q; + /* Refer to every declared value, to avoid compiler optimizations. */ + return (!a + !b + !c + !d + !e + !f + !g + !h + !i + !!j + !k + !!l + + !m + !n + !o + !p + !q + !pq); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdbool_h=yes +else + ac_cv_header_stdbool_h=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdbool_h" >&5 +$as_echo "$ac_cv_header_stdbool_h" >&6; } + ac_fn_c_check_type "$LINENO" "_Bool" "ac_cv_type__Bool" "$ac_includes_default" +if test "x$ac_cv_type__Bool" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE__BOOL 1 +_ACEOF + + +fi + + +if test $ac_cv_header_stdbool_h = yes; then + +$as_echo "#define HAVE_STDBOOL_H 1" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that is POSIX.1 compatible" >&5 +$as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; } +if ${ac_cv_header_sys_wait_h+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#ifndef WEXITSTATUS +# define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8) +#endif +#ifndef WIFEXITED +# define WIFEXITED(stat_val) (((stat_val) & 255) == 0) +#endif + +int +main () +{ + int s; + wait (&s); + s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_sys_wait_h=yes +else + ac_cv_header_sys_wait_h=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_wait_h" >&5 +$as_echo "$ac_cv_header_sys_wait_h" >&6; } +if test $ac_cv_header_sys_wait_h = yes; then + +$as_echo "#define HAVE_SYS_WAIT_H 1" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time.h and sys/time.h may both be included" >&5 +$as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; } +if ${ac_cv_header_time+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include + +int +main () +{ +if ((struct tm *) 0) +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_time=yes +else + ac_cv_header_time=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_time" >&5 +$as_echo "$ac_cv_header_time" >&6; } +if test $ac_cv_header_time = yes; then + +$as_echo "#define TIME_WITH_SYS_TIME 1" >>confdefs.h + +fi + + +if test "$ac_cv_header_string_h" = yes +then + for ac_header in memory.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "memory.h" "ac_cv_header_memory_h" "$ac_includes_default" +if test "x$ac_cv_header_memory_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MEMORY_H 1 +_ACEOF + +fi + +done + +else + for ac_header in strings.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "strings.h" "ac_cv_header_strings_h" "$ac_includes_default" +if test "x$ac_cv_header_strings_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STRINGS_H 1 +_ACEOF + +fi + +done + +fi + + if test "$build_alias" != "$host_alias"; then + TEST_CROSS_COMPILE_TRUE= + TEST_CROSS_COMPILE_FALSE='#' +else + TEST_CROSS_COMPILE_TRUE='#' + TEST_CROSS_COMPILE_FALSE= +fi + + +ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default" +if test "x$ac_cv_type_pid_t" = xyes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define pid_t int +_ACEOF + +fi + +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 : + +else + +cat >>confdefs.h <<_ACEOF +#define size_t unsigned int +_ACEOF + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5 +$as_echo_n "checking for uid_t in sys/types.h... " >&6; } +if ${ac_cv_type_uid_t+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "uid_t" >/dev/null 2>&1; then : + ac_cv_type_uid_t=yes +else + ac_cv_type_uid_t=no +fi +rm -f conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uid_t" >&5 +$as_echo "$ac_cv_type_uid_t" >&6; } +if test $ac_cv_type_uid_t = no; then + +$as_echo "#define uid_t int" >>confdefs.h + + +$as_echo "#define gid_t int" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking type of array argument to getgroups" >&5 +$as_echo_n "checking type of array argument to getgroups... " >&6; } +if ${ac_cv_type_getgroups+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_type_getgroups=cross +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Thanks to Mike Rendell for this test. */ +$ac_includes_default +#define NGID 256 +#undef MAX +#define MAX(x, y) ((x) > (y) ? (x) : (y)) + +int +main () +{ + gid_t gidset[NGID]; + int i, n; + union { gid_t gval; long int lval; } val; + + val.lval = -1; + for (i = 0; i < NGID; i++) + gidset[i] = val.gval; + n = getgroups (sizeof (gidset) / MAX (sizeof (int), sizeof (gid_t)) - 1, + gidset); + /* Exit non-zero if getgroups seems to require an array of ints. This + happens when gid_t is short int but getgroups modifies an array + of ints. */ + return n > 0 && gidset[n] != val.gval; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_type_getgroups=gid_t +else + ac_cv_type_getgroups=int +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +if test $ac_cv_type_getgroups = cross; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "getgroups.*int.*gid_t" >/dev/null 2>&1; then : + ac_cv_type_getgroups=gid_t +else + ac_cv_type_getgroups=int +fi +rm -f conftest* + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_getgroups" >&5 +$as_echo "$ac_cv_type_getgroups" >&6; } + +cat >>confdefs.h <<_ACEOF +#define GETGROUPS_T $ac_cv_type_getgroups +_ACEOF + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for unsigned long long int" >&5 +$as_echo_n "checking for unsigned long long int... " >&6; } +if ${ac_cv_type_unsigned_long_long_int+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +unsigned long long int ull = 18446744073709551615ULL; + typedef int a[(18446744073709551615ULL <= (unsigned long long int) -1 + ? 1 : -1)]; + int i = 63; +int +main () +{ +unsigned long long int ullmax = 18446744073709551615ull; + return (ull << 63 | ull >> 63 | ull << i | ull >> i + | ullmax / ull | ullmax % ull); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_type_unsigned_long_long_int=yes +else + ac_cv_type_unsigned_long_long_int=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_unsigned_long_long_int" >&5 +$as_echo "$ac_cv_type_unsigned_long_long_int" >&6; } + if test $ac_cv_type_unsigned_long_long_int = yes; then + +$as_echo "#define HAVE_UNSIGNED_LONG_LONG_INT 1" >>confdefs.h + + fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for long long int" >&5 +$as_echo_n "checking for long long int... " >&6; } +if ${ac_cv_type_long_long_int+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_type_long_long_int=yes + if test "x${ac_cv_prog_cc_c99-no}" = xno; then + ac_cv_type_long_long_int=$ac_cv_type_unsigned_long_long_int + if test $ac_cv_type_long_long_int = yes; then + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifndef LLONG_MAX + # define HALF \ + (1LL << (sizeof (long long int) * CHAR_BIT - 2)) + # define LLONG_MAX (HALF - 1 + HALF) + #endif +int +main () +{ +long long int n = 1; + int i; + for (i = 0; ; i++) + { + long long int m = n << i; + if (m >> i != n) + return 1; + if (LLONG_MAX / 2 < m) + break; + } + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_type_long_long_int=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_long_long_int" >&5 +$as_echo "$ac_cv_type_long_long_int" >&6; } + if test $ac_cv_type_long_long_int = yes; then + +$as_echo "#define HAVE_LONG_LONG_INT 1" >>confdefs.h + + fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for unsigned long long int" >&5 +$as_echo_n "checking for unsigned long long int... " >&6; } +if ${ac_cv_type_unsigned_long_long_int+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +unsigned long long int ull = 18446744073709551615ULL; + typedef int a[(18446744073709551615ULL <= (unsigned long long int) -1 + ? 1 : -1)]; + int i = 63; +int +main () +{ +unsigned long long int ullmax = 18446744073709551615ull; + return (ull << 63 | ull >> 63 | ull << i | ull >> i + | ullmax / ull | ullmax % ull); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_type_unsigned_long_long_int=yes +else + ac_cv_type_unsigned_long_long_int=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_unsigned_long_long_int" >&5 +$as_echo "$ac_cv_type_unsigned_long_long_int" >&6; } + if test $ac_cv_type_unsigned_long_long_int = yes; then + +$as_echo "#define HAVE_UNSIGNED_LONG_LONG_INT 1" >>confdefs.h + + fi + + + + ac_fn_c_check_type "$LINENO" "intmax_t" "ac_cv_type_intmax_t" "$ac_includes_default" +if test "x$ac_cv_type_intmax_t" = xyes; then : + +$as_echo "#define HAVE_INTMAX_T 1" >>confdefs.h + +else + test $ac_cv_type_long_long_int = yes \ + && ac_type='long long int' \ + || ac_type='long int' + +cat >>confdefs.h <<_ACEOF +#define intmax_t $ac_type +_ACEOF + +fi + + + + + ac_fn_c_check_type "$LINENO" "uintmax_t" "ac_cv_type_uintmax_t" "$ac_includes_default" +if test "x$ac_cv_type_uintmax_t" = xyes; then : + +$as_echo "#define HAVE_UINTMAX_T 1" >>confdefs.h + +else + test $ac_cv_type_unsigned_long_long_int = yes \ + && ac_type='unsigned long long int' \ + || ac_type='unsigned long int' + +cat >>confdefs.h <<_ACEOF +#define uintmax_t $ac_type +_ACEOF + +fi + + +ac_fn_c_check_type "$LINENO" "ssize_t" "ac_cv_type_ssize_t" "$ac_includes_default" +if test "x$ac_cv_type_ssize_t" = xyes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define ssize_t int +_ACEOF + +fi + +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of unsigned int" >&5 +$as_echo_n "checking size of unsigned int... " >&6; } +if ${ac_cv_sizeof_unsigned_int+:} false; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (unsigned int))" "ac_cv_sizeof_unsigned_int" "$ac_includes_default"; then : + +else + if test "$ac_cv_type_unsigned_int" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (unsigned int) +See \`config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_unsigned_int=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_unsigned_int" >&5 +$as_echo "$ac_cv_sizeof_unsigned_int" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_UNSIGNED_INT $ac_cv_sizeof_unsigned_int +_ACEOF + + +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of unsigned long" >&5 +$as_echo_n "checking size of unsigned long... " >&6; } +if ${ac_cv_sizeof_unsigned_long+:} false; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (unsigned long))" "ac_cv_sizeof_unsigned_long" "$ac_includes_default"; then : + +else + if test "$ac_cv_type_unsigned_long" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (unsigned long) +See \`config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_unsigned_long=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_unsigned_long" >&5 +$as_echo "$ac_cv_sizeof_unsigned_long" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_UNSIGNED_LONG $ac_cv_sizeof_unsigned_long +_ACEOF + + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + + time_t foo; + foo = 0; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define TIME_T_IN_SYS_TYPES_H 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + + wctype_t foo; + foo = 0; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE_WCTYPE_T 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + + wint_t foo; + foo = 0; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE_WINT_T 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +int +main () +{ + + struct sockaddr_storage foo; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE_SOCKADDR_STORAGE 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + + + + + + ac_fn_c_check_type "$LINENO" "socklen_t" "ac_cv_type_socklen_t" "#include +#include +" +if test "x$ac_cv_type_socklen_t" = xyes; then : + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socklen_t equivalent" >&5 +$as_echo_n "checking for socklen_t equivalent... " >&6; } + if ${rsync_cv_socklen_t_equiv+:} false; then : + $as_echo_n "(cached) " >&6 +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 + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include + + int getpeername (int, $arg2 *, $t *); + +int +main () +{ + + $t len; + getpeername(0,0,&len); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + rsync_cv_socklen_t_equiv="$t" + break + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done + done + + if test "$rsync_cv_socklen_t_equiv" = "" + then + rsync_cv_socklen_t_equiv=int + fi + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_socklen_t_equiv" >&5 +$as_echo "$rsync_cv_socklen_t_equiv" >&6; } + +cat >>confdefs.h <<_ACEOF +#define socklen_t $rsync_cv_socklen_t_equiv +_ACEOF + +fi + + + + + + + + + + for ac_header in $ac_header_list +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + + + + + + + for ac_func in $ac_func_list +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working mktime" >&5 +$as_echo_n "checking for working mktime... " >&6; } +if ${ac_cv_func_working_mktime+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_func_working_mktime=no +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Test program from Paul Eggert and Tony Leneis. */ +#ifdef TIME_WITH_SYS_TIME +# include +# include +#else +# ifdef HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#include +#include + +#ifdef HAVE_UNISTD_H +# include +#endif + +#ifndef HAVE_ALARM +# define alarm(X) /* empty */ +#endif + +/* Work around redefinition to rpl_putenv by other config tests. */ +#undef putenv + +static time_t time_t_max; +static time_t time_t_min; + +/* Values we'll use to set the TZ environment variable. */ +static const char *tz_strings[] = { + (const char *) 0, "TZ=GMT0", "TZ=JST-9", + "TZ=EST+3EDT+2,M10.1.0/00:00:00,M2.3.0/00:00:00" +}; +#define N_STRINGS (sizeof (tz_strings) / sizeof (tz_strings[0])) + +/* Return 0 if mktime fails to convert a date in the spring-forward gap. + Based on a problem report from Andreas Jaeger. */ +static int +spring_forward_gap () +{ + /* glibc (up to about 1998-10-07) failed this test. */ + struct tm tm; + + /* Use the portable POSIX.1 specification "TZ=PST8PDT,M4.1.0,M10.5.0" + instead of "TZ=America/Vancouver" in order to detect the bug even + on systems that don't support the Olson extension, or don't have the + full zoneinfo tables installed. */ + putenv ((char*) "TZ=PST8PDT,M4.1.0,M10.5.0"); + + tm.tm_year = 98; + tm.tm_mon = 3; + tm.tm_mday = 5; + tm.tm_hour = 2; + tm.tm_min = 0; + tm.tm_sec = 0; + tm.tm_isdst = -1; + return mktime (&tm) != (time_t) -1; +} + +static int +mktime_test1 (time_t now) +{ + struct tm *lt; + return ! (lt = localtime (&now)) || mktime (lt) == now; +} + +static int +mktime_test (time_t now) +{ + return (mktime_test1 (now) + && mktime_test1 ((time_t) (time_t_max - now)) + && mktime_test1 ((time_t) (time_t_min + now))); +} + +static int +irix_6_4_bug () +{ + /* Based on code from Ariel Faigon. */ + struct tm tm; + tm.tm_year = 96; + tm.tm_mon = 3; + tm.tm_mday = 0; + tm.tm_hour = 0; + tm.tm_min = 0; + tm.tm_sec = 0; + tm.tm_isdst = -1; + mktime (&tm); + return tm.tm_mon == 2 && tm.tm_mday == 31; +} + +static int +bigtime_test (int j) +{ + struct tm tm; + time_t now; + tm.tm_year = tm.tm_mon = tm.tm_mday = tm.tm_hour = tm.tm_min = tm.tm_sec = j; + now = mktime (&tm); + if (now != (time_t) -1) + { + struct tm *lt = localtime (&now); + if (! (lt + && lt->tm_year == tm.tm_year + && lt->tm_mon == tm.tm_mon + && lt->tm_mday == tm.tm_mday + && lt->tm_hour == tm.tm_hour + && lt->tm_min == tm.tm_min + && lt->tm_sec == tm.tm_sec + && lt->tm_yday == tm.tm_yday + && lt->tm_wday == tm.tm_wday + && ((lt->tm_isdst < 0 ? -1 : 0 < lt->tm_isdst) + == (tm.tm_isdst < 0 ? -1 : 0 < tm.tm_isdst)))) + return 0; + } + return 1; +} + +static int +year_2050_test () +{ + /* The correct answer for 2050-02-01 00:00:00 in Pacific time, + ignoring leap seconds. */ + unsigned long int answer = 2527315200UL; + + struct tm tm; + time_t t; + tm.tm_year = 2050 - 1900; + tm.tm_mon = 2 - 1; + tm.tm_mday = 1; + tm.tm_hour = tm.tm_min = tm.tm_sec = 0; + tm.tm_isdst = -1; + + /* Use the portable POSIX.1 specification "TZ=PST8PDT,M4.1.0,M10.5.0" + instead of "TZ=America/Vancouver" in order to detect the bug even + on systems that don't support the Olson extension, or don't have the + full zoneinfo tables installed. */ + putenv ((char*) "TZ=PST8PDT,M4.1.0,M10.5.0"); + + t = mktime (&tm); + + /* Check that the result is either a failure, or close enough + to the correct answer that we can assume the discrepancy is + due to leap seconds. */ + return (t == (time_t) -1 + || (0 < t && answer - 120 <= t && t <= answer + 120)); +} + +int +main () +{ + time_t t, delta; + int i, j; + + /* This test makes some buggy mktime implementations loop. + Give up after 60 seconds; a mktime slower than that + isn't worth using anyway. */ + alarm (60); + + for (;;) + { + t = (time_t_max << 1) + 1; + if (t <= time_t_max) + break; + time_t_max = t; + } + time_t_min = - ((time_t) ~ (time_t) 0 == (time_t) -1) - time_t_max; + + delta = time_t_max / 997; /* a suitable prime number */ + for (i = 0; i < N_STRINGS; i++) + { + if (tz_strings[i]) + putenv ((char*) tz_strings[i]); + + for (t = 0; t <= time_t_max - delta; t += delta) + if (! mktime_test (t)) + return 1; + if (! (mktime_test ((time_t) 1) + && mktime_test ((time_t) (60 * 60)) + && mktime_test ((time_t) (60 * 60 * 24)))) + return 1; + + for (j = 1; ; j <<= 1) + if (! bigtime_test (j)) + return 1; + else if (INT_MAX / 2 < j) + break; + if (! bigtime_test (INT_MAX)) + return 1; + } + return ! (irix_6_4_bug () && spring_forward_gap () && year_2050_test ()); +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_func_working_mktime=yes +else + ac_cv_func_working_mktime=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_working_mktime" >&5 +$as_echo "$ac_cv_func_working_mktime" >&6; } +if test $ac_cv_func_working_mktime = no; then + case " $LIBOBJS " in + *" mktime.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS mktime.$ac_objext" + ;; +esac + +fi + +case "$ac_cv_func_working_mktime" in +yes) +$as_echo "#define HAVE_MKTIME 1" >>confdefs.h + + ;; +esac + +ac_fn_c_check_func "$LINENO" "getaddrinfo" "ac_cv_func_getaddrinfo" +if test "x$ac_cv_func_getaddrinfo" = xyes; then : + +$as_echo "#define HAVE_GETADDRINFO 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getaddrinfo in -lsocket" >&5 +$as_echo_n "checking for getaddrinfo in -lsocket... " >&6; } +if ${ac_cv_lib_socket_getaddrinfo+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsocket $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char getaddrinfo (); +int +main () +{ +return getaddrinfo (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_socket_getaddrinfo=yes +else + ac_cv_lib_socket_getaddrinfo=no +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_socket_getaddrinfo" >&5 +$as_echo "$ac_cv_lib_socket_getaddrinfo" >&6; } +if test "x$ac_cv_lib_socket_getaddrinfo" = xyes; then : + +$as_echo "#define HAVE_GETADDRINFO 1" >>confdefs.h + +fi + +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing fmod" >&5 +$as_echo_n "checking for library containing fmod... " >&6; } +if ${ac_cv_search_fmod+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char fmod (); +int +main () +{ +return fmod (); + ; + return 0; +} +_ACEOF +for ac_lib in '' m; 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_fmod=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_fmod+:} false; then : + break +fi +done +if ${ac_cv_search_fmod+:} false; then : + +else + ac_cv_search_fmod=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_fmod" >&5 +$as_echo "$ac_cv_search_fmod" >&6; } +ac_res=$ac_cv_search_fmod +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing isinf" >&5 +$as_echo_n "checking for library containing isinf... " >&6; } +if ${ac_cv_search_isinf+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char isinf (); +int +main () +{ +return isinf (); + ; + return 0; +} +_ACEOF +for ac_lib in '' m; 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_isinf=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_isinf+:} false; then : + break +fi +done +if ${ac_cv_search_isinf+:} false; then : + +else + ac_cv_search_isinf=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_isinf" >&5 +$as_echo "$ac_cv_search_isinf" >&6; } +ac_res=$ac_cv_search_isinf +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing ismod" >&5 +$as_echo_n "checking for library containing ismod... " >&6; } +if ${ac_cv_search_ismod+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char ismod (); +int +main () +{ +return ismod (); + ; + return 0; +} +_ACEOF +for ac_lib in '' m; 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_ismod=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_ismod+:} false; then : + break +fi +done +if ${ac_cv_search_ismod+:} false; then : + +else + ac_cv_search_ismod=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_ismod" >&5 +$as_echo "$ac_cv_search_ismod" >&6; } +ac_res=$ac_cv_search_ismod +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + +case $host_os in +osf1) : ;; +*) + + + + + + + + + + + + + + + use_additional=yes + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + +# Check whether --with-libsigsegv-prefix was given. +if test "${with_libsigsegv_prefix+set}" = set; then : + withval=$with_libsigsegv_prefix; + if test "X$withval" = "Xno"; then + use_additional=no + else + if test "X$withval" = "X"; then + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + else + additional_includedir="$withval/include" + additional_libdir="$withval/$acl_libdirstem" + if test "$acl_libdirstem2" != "$acl_libdirstem" \ + && ! test -d "$withval/$acl_libdirstem"; then + additional_libdir="$withval/$acl_libdirstem2" + fi + fi + fi + +fi + + LIBSIGSEGV= + LTLIBSIGSEGV= + INCSIGSEGV= + LIBSIGSEGV_PREFIX= + HAVE_LIBSIGSEGV= + rpathdirs= + ltrpathdirs= + names_already_handled= + names_next_round='sigsegv ' + while test -n "$names_next_round"; do + names_this_round="$names_next_round" + names_next_round= + for name in $names_this_round; do + already_handled= + for n in $names_already_handled; do + if test "$n" = "$name"; then + already_handled=yes + break + fi + done + if test -z "$already_handled"; then + names_already_handled="$names_already_handled $name" + uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./+-|ABCDEFGHIJKLMNOPQRSTUVWXYZ____|'` + eval value=\"\$HAVE_LIB$uppername\" + if test -n "$value"; then + if test "$value" = yes; then + eval value=\"\$LIB$uppername\" + test -z "$value" || LIBSIGSEGV="${LIBSIGSEGV}${LIBSIGSEGV:+ }$value" + eval value=\"\$LTLIB$uppername\" + test -z "$value" || LTLIBSIGSEGV="${LTLIBSIGSEGV}${LTLIBSIGSEGV:+ }$value" + else + : + fi + else + found_dir= + found_la= + found_so= + found_a= + eval libname=\"$acl_libname_spec\" # typically: libname=lib$name + if test -n "$acl_shlibext"; then + shrext=".$acl_shlibext" # typically: shrext=.so + else + shrext= + fi + if test $use_additional = yes; then + dir="$additional_libdir" + if test -n "$acl_shlibext"; then + if test -f "$dir/$libname$shrext"; then + found_dir="$dir" + found_so="$dir/$libname$shrext" + else + if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then + ver=`(cd "$dir" && \ + for f in "$libname$shrext".*; do echo "$f"; done \ + | sed -e "s,^$libname$shrext\\\\.,," \ + | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ + | sed 1q ) 2>/dev/null` + if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then + found_dir="$dir" + found_so="$dir/$libname$shrext.$ver" + fi + else + eval library_names=\"$acl_library_names_spec\" + for f in $library_names; do + if test -f "$dir/$f"; then + found_dir="$dir" + found_so="$dir/$f" + break + fi + done + fi + fi + fi + if test "X$found_dir" = "X"; then + if test -f "$dir/$libname.$acl_libext"; then + found_dir="$dir" + found_a="$dir/$libname.$acl_libext" + fi + fi + if test "X$found_dir" != "X"; then + if test -f "$dir/$libname.la"; then + found_la="$dir/$libname.la" + fi + fi + fi + if test "X$found_dir" = "X"; then + for x in $LDFLAGS $LTLIBSIGSEGV; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + case "$x" in + -L*) + dir=`echo "X$x" | sed -e 's/^X-L//'` + if test -n "$acl_shlibext"; then + if test -f "$dir/$libname$shrext"; then + found_dir="$dir" + found_so="$dir/$libname$shrext" + else + if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then + ver=`(cd "$dir" && \ + for f in "$libname$shrext".*; do echo "$f"; done \ + | sed -e "s,^$libname$shrext\\\\.,," \ + | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ + | sed 1q ) 2>/dev/null` + if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then + found_dir="$dir" + found_so="$dir/$libname$shrext.$ver" + fi + else + eval library_names=\"$acl_library_names_spec\" + for f in $library_names; do + if test -f "$dir/$f"; then + found_dir="$dir" + found_so="$dir/$f" + break + fi + done + fi + fi + fi + if test "X$found_dir" = "X"; then + if test -f "$dir/$libname.$acl_libext"; then + found_dir="$dir" + found_a="$dir/$libname.$acl_libext" + fi + fi + if test "X$found_dir" != "X"; then + if test -f "$dir/$libname.la"; then + found_la="$dir/$libname.la" + fi + fi + ;; + esac + if test "X$found_dir" != "X"; then + break + fi + done + fi + if test "X$found_dir" != "X"; then + LTLIBSIGSEGV="${LTLIBSIGSEGV}${LTLIBSIGSEGV:+ }-L$found_dir -l$name" + if test "X$found_so" != "X"; then + if test "$enable_rpath" = no \ + || test "X$found_dir" = "X/usr/$acl_libdirstem" \ + || test "X$found_dir" = "X/usr/$acl_libdirstem2"; then + LIBSIGSEGV="${LIBSIGSEGV}${LIBSIGSEGV:+ }$found_so" + else + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $found_dir" + fi + if test "$acl_hardcode_direct" = yes; then + LIBSIGSEGV="${LIBSIGSEGV}${LIBSIGSEGV:+ }$found_so" + else + if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then + LIBSIGSEGV="${LIBSIGSEGV}${LIBSIGSEGV:+ }$found_so" + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $found_dir" + fi + else + haveit= + for x in $LDFLAGS $LIBSIGSEGV; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + LIBSIGSEGV="${LIBSIGSEGV}${LIBSIGSEGV:+ }-L$found_dir" + fi + if test "$acl_hardcode_minus_L" != no; then + LIBSIGSEGV="${LIBSIGSEGV}${LIBSIGSEGV:+ }$found_so" + else + LIBSIGSEGV="${LIBSIGSEGV}${LIBSIGSEGV:+ }-l$name" + fi + fi + fi + fi + else + if test "X$found_a" != "X"; then + LIBSIGSEGV="${LIBSIGSEGV}${LIBSIGSEGV:+ }$found_a" + else + LIBSIGSEGV="${LIBSIGSEGV}${LIBSIGSEGV:+ }-L$found_dir -l$name" + fi + fi + additional_includedir= + case "$found_dir" in + */$acl_libdirstem | */$acl_libdirstem/) + basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` + if test "$name" = 'sigsegv'; then + LIBSIGSEGV_PREFIX="$basedir" + fi + additional_includedir="$basedir/include" + ;; + */$acl_libdirstem2 | */$acl_libdirstem2/) + basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem2/"'*$,,'` + if test "$name" = 'sigsegv'; then + LIBSIGSEGV_PREFIX="$basedir" + fi + additional_includedir="$basedir/include" + ;; + esac + if test "X$additional_includedir" != "X"; then + if test "X$additional_includedir" != "X/usr/include"; then + haveit= + if test "X$additional_includedir" = "X/usr/local/include"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + for x in $CPPFLAGS $INCSIGSEGV; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-I$additional_includedir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_includedir"; then + INCSIGSEGV="${INCSIGSEGV}${INCSIGSEGV:+ }-I$additional_includedir" + fi + fi + fi + fi + fi + if test -n "$found_la"; then + save_libdir="$libdir" + case "$found_la" in + */* | *\\*) . "$found_la" ;; + *) . "./$found_la" ;; + esac + libdir="$save_libdir" + for dep in $dependency_libs; do + case "$dep" in + -L*) + additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` + if test "X$additional_libdir" != "X/usr/$acl_libdirstem" \ + && test "X$additional_libdir" != "X/usr/$acl_libdirstem2"; then + haveit= + if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem" \ + || test "X$additional_libdir" = "X/usr/local/$acl_libdirstem2"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + haveit= + for x in $LDFLAGS $LIBSIGSEGV; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + LIBSIGSEGV="${LIBSIGSEGV}${LIBSIGSEGV:+ }-L$additional_libdir" + fi + fi + haveit= + for x in $LDFLAGS $LTLIBSIGSEGV; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + LTLIBSIGSEGV="${LTLIBSIGSEGV}${LTLIBSIGSEGV:+ }-L$additional_libdir" + fi + fi + fi + fi + ;; + -R*) + dir=`echo "X$dep" | sed -e 's/^X-R//'` + if test "$enable_rpath" != no; then + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $dir" + fi + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $dir" + fi + fi + ;; + -l*) + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` + ;; + *.la) + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` + ;; + *) + LIBSIGSEGV="${LIBSIGSEGV}${LIBSIGSEGV:+ }$dep" + LTLIBSIGSEGV="${LTLIBSIGSEGV}${LTLIBSIGSEGV:+ }$dep" + ;; + esac + done + fi + else + LIBSIGSEGV="${LIBSIGSEGV}${LIBSIGSEGV:+ }-l$name" + LTLIBSIGSEGV="${LTLIBSIGSEGV}${LTLIBSIGSEGV:+ }-l$name" + fi + fi + fi + done + done + if test "X$rpathdirs" != "X"; then + if test -n "$acl_hardcode_libdir_separator"; then + alldirs= + for found_dir in $rpathdirs; do + alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$found_dir" + done + acl_save_libdir="$libdir" + libdir="$alldirs" + eval flag=\"$acl_hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIBSIGSEGV="${LIBSIGSEGV}${LIBSIGSEGV:+ }$flag" + else + for found_dir in $rpathdirs; do + acl_save_libdir="$libdir" + libdir="$found_dir" + eval flag=\"$acl_hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIBSIGSEGV="${LIBSIGSEGV}${LIBSIGSEGV:+ }$flag" + done + fi + fi + if test "X$ltrpathdirs" != "X"; then + for found_dir in $ltrpathdirs; do + LTLIBSIGSEGV="${LTLIBSIGSEGV}${LTLIBSIGSEGV:+ }-R$found_dir" + done + fi + + + + + + + + ac_save_CPPFLAGS="$CPPFLAGS" + + for element in $INCSIGSEGV; do + haveit= + for x in $CPPFLAGS; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X$element"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element" + fi + done + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libsigsegv" >&5 +$as_echo_n "checking for libsigsegv... " >&6; } +if ${ac_cv_libsigsegv+:} false; then : + $as_echo_n "(cached) " >&6 +else + + ac_save_LIBS="$LIBS" + case " $LIBSIGSEGV" in + *" -l"*) LIBS="$LIBS $LIBSIGSEGV" ;; + *) LIBS="$LIBSIGSEGV $LIBS" ;; + esac + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +sigsegv_deinstall_handler(); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_libsigsegv=yes +else + ac_cv_libsigsegv='no, consider installing GNU libsigsegv' +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$ac_save_LIBS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libsigsegv" >&5 +$as_echo "$ac_cv_libsigsegv" >&6; } + if test "$ac_cv_libsigsegv" = yes; then + HAVE_LIBSIGSEGV=yes + +$as_echo "#define HAVE_LIBSIGSEGV 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libsigsegv" >&5 +$as_echo_n "checking how to link with libsigsegv... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBSIGSEGV" >&5 +$as_echo "$LIBSIGSEGV" >&6; } + else + HAVE_LIBSIGSEGV=no + CPPFLAGS="$ac_save_CPPFLAGS" + LIBSIGSEGV= + LTLIBSIGSEGV= + LIBSIGSEGV_PREFIX= + fi + + + + + + + + gl_cv_lib_sigsegv="$ac_cv_libsigsegv" + + ;; +esac + +# Need the check for mkstemp and tmpfile for missing_d/snprintf.c. +for ac_func in __etoa_l atexit btowc fmod gai_strerror \ + getgrent getgroups grantpt \ + fwrite_unlocked \ + isascii iswctype iswlower iswupper mbrlen \ + memcmp memcpy memcpy_ulong memmove memset \ + memset_ulong mkstemp posix_openpt setenv setlocale setsid sigprocmask \ + snprintf strchr \ + strerror strftime strcasecmp strncasecmp strcoll strtod strtoul \ + system tmpfile towlower towupper tzset usleep waitpid wcrtomb \ + wcscoll wctype +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether mbrtowc and mbstate_t are properly declared" >&5 +$as_echo_n "checking whether mbrtowc and mbstate_t are properly declared... " >&6; } +if ${ac_cv_func_mbrtowc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +wchar_t wc; + char const s[] = ""; + size_t n = 1; + mbstate_t state; + return ! (sizeof state && (mbrtowc) (&wc, s, n, &state)); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_func_mbrtowc=yes +else + ac_cv_func_mbrtowc=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_mbrtowc" >&5 +$as_echo "$ac_cv_func_mbrtowc" >&6; } + if test $ac_cv_func_mbrtowc = yes; then + +$as_echo "#define HAVE_MBRTOWC 1" >>confdefs.h + + fi + + +# Check whether --enable-extensions was given. +if test "${enable_extensions+set}" = set; then : + enableval=$enable_extensions; +fi + +if test "$enable_extensions" != "no" +then + extensions_supported=no + + case $host_os in + mirbsd* | openedition*) # OS/390 z/OS POSIX layer + ;; + *) + ac_fn_c_check_header_mongrel "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default" +if test "x$ac_cv_header_dlfcn_h" = xyes; then : + + # Check this separately. Some systems have dlopen + # in libc. Notably freebsd and cygwin. + # HP-NSK has it in zrldsrl + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing dlopen" >&5 +$as_echo_n "checking for library containing dlopen... " >&6; } +if ${ac_cv_search_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +for ac_lib in '' dl zrldsrl; 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_dlopen=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_dlopen+:} false; then : + break +fi +done +if ${ac_cv_search_dlopen+:} false; then : + +else + ac_cv_search_dlopen=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dlopen" >&5 +$as_echo "$ac_cv_search_dlopen" >&6; } +ac_res=$ac_cv_search_dlopen +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + gawk_have_dlopen=yes +else + gawk_have_dlopen=no +fi + + # Only do DYNAMIC if we have the lib. z/OS (some versions) have + # the header but not the lib, apparently + if test "$gawk_have_dlopen" = yes + then + extensions_supported=yes + +$as_echo "#define DYNAMIC 1" >>confdefs.h + + fi + +fi + + + ;; + esac + + if test "$enable_extensions$extensions_supported" = "yesno" + then + as_fn_error $? "extension support requested, but unavailable" "$LINENO" 5 + fi + enable_extensions=$extensions_supported +fi + if test "$enable_extensions" = "yes"; then + ENABLE_EXTENSIONS_TRUE= + ENABLE_EXTENSIONS_FALSE='#' +else + ENABLE_EXTENSIONS_TRUE='#' + ENABLE_EXTENSIONS_FALSE= +fi + + +case $host_os in +vms*|beos*|os2*|msdos) + +$as_echo "#define GETPGRP_VOID 1" >>confdefs.h + + ;; +*) { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether getpgrp requires zero arguments" >&5 +$as_echo_n "checking whether getpgrp requires zero arguments... " >&6; } +if ${ac_cv_func_getpgrp_void+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Use it with a single arg. +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +getpgrp (0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_func_getpgrp_void=no +else + ac_cv_func_getpgrp_void=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getpgrp_void" >&5 +$as_echo "$ac_cv_func_getpgrp_void" >&6; } +if test $ac_cv_func_getpgrp_void = yes; then + +$as_echo "#define GETPGRP_VOID 1" >>confdefs.h + +fi + + ;; +esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for printf %F format" >&5 +$as_echo_n "checking for printf %F format... " >&6; } +if test "$cross_compiling" = yes; then : + has_f_format=no +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#include + +int main() +{ + char buf[100]; + + sprintf(buf, "%F", 123.45); + + if (strcmp(buf, "123.450000") == 0) + return 0; + else + return 1; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + has_f_format=yes +else + has_f_format=no +fi +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 + +$as_echo "#define PRINTF_HAS_F_FORMAT 1" >>confdefs.h + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $has_f_format" >&5 +$as_echo "$has_f_format" >&6; } + + +gawk_have_sockets=no +# Check for system-dependent location of socket libraries + +SOCKET_LIBS= +if test "$ISC" = yes; then + SOCKET_LIBS="-lnsl_s -linet" +else + # Martyn.Johnson@cl.cam.ac.uk says this is needed for Ultrix, if the X + # libraries were built with DECnet support. And karl@cs.umb.edu says + # the Alpha needs dnet_stub (dnet does not exist). + # + # ADR: Is this needed just for sockets??? +# AC_CHECK_LIB(dnet, dnet_ntoa, [SOCKET_LIBS="$SOCKET_LIBS -ldnet"]) +# if test $ac_cv_lib_dnet_ntoa = no; then +# AC_CHECK_LIB(dnet_stub, dnet_ntoa, +# [SOCKET_LIBS="$SOCKET_LIBS -ldnet_stub"]) +# fi + + # msh@cis.ufl.edu says -lnsl (and -lsocket) are needed for his 386/AT, + # to get the SysV transport functions. + # chad@anasazi.com says the Pyramid MIS-ES running DC/OSx (SVR4) + # needs -lnsl. + # The nsl library prevents programs from opening the X display + # on Irix 5.2, according to dickey@clark.net. + ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname" +if test "x$ac_cv_func_gethostbyname" = xyes; then : + +fi + + if test $ac_cv_func_gethostbyname = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5 +$as_echo_n "checking for gethostbyname in -lnsl... " >&6; } +if ${ac_cv_lib_nsl_gethostbyname+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnsl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char gethostbyname (); +int +main () +{ +return gethostbyname (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_nsl_gethostbyname=yes +else + ac_cv_lib_nsl_gethostbyname=no +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_nsl_gethostbyname" >&5 +$as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; } +if test "x$ac_cv_lib_nsl_gethostbyname" = xyes; then : + SOCKET_LIBS="$SOCKET_LIBS -lnsl" +fi + + fi + + # lieder@skyler.mavd.honeywell.com says without -lsocket, + # socket/setsockopt and other routines are undefined under SCO ODT + # 2.0. But -lsocket is broken on IRIX 5.2 (and is not necessary + # on later versions), says simon@lia.di.epfl.ch: it contains + # gethostby* variants that don't use the nameserver (or something). + # -lsocket must be given before -lnsl if both are needed. + # We assume that if connect needs -lnsl, so does gethostbyname. + ac_fn_c_check_func "$LINENO" "connect" "ac_cv_func_connect" +if test "x$ac_cv_func_connect" = xyes; then : + +fi + + if test $ac_cv_func_connect = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for connect in -lsocket" >&5 +$as_echo_n "checking for connect in -lsocket... " >&6; } +if ${ac_cv_lib_socket_connect+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsocket $SOCKET_LIBS $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char connect (); +int +main () +{ +return connect (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_socket_connect=yes +else + ac_cv_lib_socket_connect=no +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_socket_connect" >&5 +$as_echo "$ac_cv_lib_socket_connect" >&6; } +if test "x$ac_cv_lib_socket_connect" = xyes; then : + SOCKET_LIBS="-lsocket $SOCKET_LIBS" + gawk_have_sockets=yes +fi + + else + gawk_have_sockets=yes + fi +fi + +if test "${gawk_have_sockets}" = "yes" +then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking where to find the socket library calls" >&5 +$as_echo_n "checking where to find the socket library calls... " >&6; } + case "${SOCKET_LIBS}" in + ?*) gawk_lib_loc="${SOCKET_LIBS}" ;; + *) gawk_lib_loc="the standard library" ;; + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${gawk_lib_loc}" >&5 +$as_echo "${gawk_lib_loc}" >&6; } + + +$as_echo "#define HAVE_SOCKETS 1" >>confdefs.h + +fi + + + + +# Check whether --with-readline was given. +if test "${with_readline+set}" = set; then : + withval=$with_readline; _do_readline=$withval +else + _do_readline=yes +fi + + + if test "$_do_readline" != "no" ; then + if test -d "$withval" ; then + CPPFLAGS="${CPPFLAGS} -I$withval/include" + LDFLAGS="${LDFLAGS} -L$withval/lib" + fi + + for _termcap in "" "-ltermcap" "-lcurses" "-lncurses" ; do + _readline_save_libs=$LIBS + _combo="-lreadline${_termcap:+ $_termcap}" + LIBS="$LIBS $_combo" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether readline via \"$_combo\" is present and sane" >&5 +$as_echo_n "checking whether readline via \"$_combo\" is present and sane... " >&6; } + + if test "$cross_compiling" = yes; then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +int +main () +{ + + int fd; + char *line; + + close(0); + close(1); + fd = open("/dev/null", 2); /* should get fd 0 */ + dup(fd); + line = readline("giveittome> "); + + /* some printfs don't handle NULL for %s */ + printf("got <%s>\n", line ? line : "(NULL)"); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + _found_readline=yes +else + _found_readline=no + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include + +int main(int argc, char **argv) +{ + int fd; + char *line; + + close(0); + close(1); + fd = open("/dev/null", 2); /* should get fd 0 */ + dup(fd); + line = readline("giveittome> "); + + /* some printfs don't handle NULL for %s */ + printf("got <%s>\n", line ? line : "(NULL)"); + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + _found_readline=yes +else + _found_readline=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_found_readline" >&5 +$as_echo "$_found_readline" >&6; } + + LIBS=$_readline_save_libs + + if test $_found_readline = yes ; then + case $host_os in + *bsd* ) { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tgetent in -ltermcap" >&5 +$as_echo_n "checking for tgetent in -ltermcap... " >&6; } +if ${ac_cv_lib_termcap_tgetent+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ltermcap $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char tgetent (); +int +main () +{ +return tgetent (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_termcap_tgetent=yes +else + ac_cv_lib_termcap_tgetent=no +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_termcap_tgetent" >&5 +$as_echo "$ac_cv_lib_termcap_tgetent" >&6; } +if test "x$ac_cv_lib_termcap_tgetent" = xyes; then : + _combo="$_combo -ltermcap" +fi + + ;; + esac + +$as_echo "#define HAVE_LIBREADLINE 1" >>confdefs.h + + LIBREADLINE=$_combo + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for history_list in -lreadline" >&5 +$as_echo_n "checking for history_list in -lreadline... " >&6; } +if ${ac_cv_lib_readline_history_list+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lreadline $_combo $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char history_list (); +int +main () +{ +return history_list (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_readline_history_list=yes +else + ac_cv_lib_readline_history_list=no +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_readline_history_list" >&5 +$as_echo "$ac_cv_lib_readline_history_list" >&6; } +if test "x$ac_cv_lib_readline_history_list" = xyes; then : + +$as_echo "#define HAVE_HISTORY_LIST 1" >>confdefs.h + +fi + + + break + fi + done + + unset _termcap + unset _readline_save_libs + unset _combo + unset _found_readline + 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 : + withval=$with_mpfr; _do_mpfr=$withval +else + _do_mpfr=yes +fi + + + if test "$_do_mpfr" != "no" ; then + if test -d "$withval" ; then + CPPFLAGS="${CPPFLAGS} -I$withval/include" + LDFLAGS="${LDFLAGS} -L$withval/lib" + fi + + _mpfr_save_libs=$LIBS + _combo="-lmpfr -lgmp" + LIBS="$LIBS $_combo" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether mpfr via \"$_combo\" is present and usable" >&5 +$as_echo_n "checking whether mpfr via \"$_combo\" is present and usable... " >&6; } + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#include +#include +#include + +int +main () +{ + +mpfr_t p; +mpz_t z; +mpfr_init(p); +mpz_init(z); +mpfr_printf("%Rf%Zd", p, z); +mpfr_clear(p); +mpz_clear(z); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + _found_mpfr=yes +else + _found_mpfr=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_found_mpfr" >&5 +$as_echo "$_found_mpfr" >&6; } + + LIBS=$_mpfr_save_libs + + if test $_found_mpfr = yes ; then + +$as_echo "#define HAVE_MPFR 1" >>confdefs.h + + LIBMPFR=$_combo + + break + fi + + unset _mpfr_save_libs + unset _combo + 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 : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_STAT_ST_BLKSIZE 1 +_ACEOF + + +fi + +ac_fn_c_check_member "$LINENO" "struct passwd" "pw_passwd" "ac_cv_member_struct_passwd_pw_passwd" " +#include +#include + +" +if test "x$ac_cv_member_struct_passwd_pw_passwd" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_PASSWD_PW_PASSWD 1 +_ACEOF + + +fi + +ac_fn_c_check_member "$LINENO" "struct group" "gr_passwd" "ac_cv_member_struct_group_gr_passwd" " +#include +#include + +" +if test "x$ac_cv_member_struct_group_gr_passwd" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_GROUP_GR_PASSWD 1 +_ACEOF + + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5 +$as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; } +if ${ac_cv_struct_tm+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include + +int +main () +{ +struct tm tm; + int *p = &tm.tm_sec; + return !p; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_struct_tm=time.h +else + ac_cv_struct_tm=sys/time.h +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_tm" >&5 +$as_echo "$ac_cv_struct_tm" >&6; } +if test $ac_cv_struct_tm = sys/time.h; then + +$as_echo "#define TM_IN_SYS_TIME 1" >>confdefs.h + +fi + +ac_fn_c_check_member "$LINENO" "struct tm" "tm_zone" "ac_cv_member_struct_tm_tm_zone" "#include +#include <$ac_cv_struct_tm> + +" +if test "x$ac_cv_member_struct_tm_tm_zone" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_TM_TM_ZONE 1 +_ACEOF + + +fi + +if test "$ac_cv_member_struct_tm_tm_zone" = yes; then + +$as_echo "#define HAVE_TM_ZONE 1" >>confdefs.h + +else + ac_fn_c_check_decl "$LINENO" "tzname" "ac_cv_have_decl_tzname" "#include +" +if test "x$ac_cv_have_decl_tzname" = xyes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_TZNAME $ac_have_decl +_ACEOF + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tzname" >&5 +$as_echo_n "checking for tzname... " >&6; } +if ${ac_cv_var_tzname+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#if !HAVE_DECL_TZNAME +extern char *tzname[]; +#endif + +int +main () +{ +return tzname[0][0]; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_var_tzname=yes +else + ac_cv_var_tzname=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_var_tzname" >&5 +$as_echo "$ac_cv_var_tzname" >&6; } + if test $ac_cv_var_tzname = yes; then + +$as_echo "#define HAVE_TZNAME 1" >>confdefs.h + + fi +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether char is unsigned" >&5 +$as_echo_n "checking whether char is unsigned... " >&6; } +if ${ac_cv_c_char_unsigned+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((char) -1) < 0)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_char_unsigned=no +else + ac_cv_c_char_unsigned=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_char_unsigned" >&5 +$as_echo "$ac_cv_c_char_unsigned" >&6; } +if test $ac_cv_c_char_unsigned = yes && test "$GCC" != yes; then + $as_echo "#define __CHAR_UNSIGNED__ 1" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 +$as_echo_n "checking for an ANSI C-conforming const... " >&6; } +if ${ac_cv_c_const+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + +#ifndef __cplusplus + /* Ultrix mips cc rejects this sort of thing. */ + typedef int charset[2]; + const charset cs = { 0, 0 }; + /* SunOS 4.1.1 cc rejects this. */ + char const *const *pcpcc; + char **ppc; + /* NEC SVR4.0.2 mips cc rejects this. */ + struct point {int x, y;}; + static struct point const zero = {0,0}; + /* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in + an arm of an if-expression whose if-part is not a constant + expression */ + const char *g = "string"; + pcpcc = &g + (g ? g-g : 0); + /* HPUX 7.0 cc rejects these. */ + ++pcpcc; + ppc = (char**) pcpcc; + pcpcc = (char const *const *) ppc; + { /* SCO 3.2v4 cc rejects this sort of thing. */ + char tx; + char *t = &tx; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; + if (s) return 0; + } + { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; + } + { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; + } + { /* AIX XL C 1.02.0.0 rejects this sort of thing, saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; } bx; + struct s *b = &bx; b->j = 5; + } + { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; + if (!foo) return 0; + } + return !cs[0] && !zero.x; +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_const=yes +else + ac_cv_c_const=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 +$as_echo "$ac_cv_c_const" >&6; } +if test $ac_cv_c_const = no; then + +$as_echo "#define const /**/" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C/C++ restrict keyword" >&5 +$as_echo_n "checking for C/C++ restrict keyword... " >&6; } +if ${ac_cv_c_restrict+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_c_restrict=no + # The order here caters to the fact that C++ does not require restrict. + for ac_kw in __restrict __restrict__ _Restrict restrict; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +typedef int * int_ptr; + int foo (int_ptr $ac_kw ip) { + return ip[0]; + } +int +main () +{ +int s[1]; + int * $ac_kw t = s; + t[0] = 0; + return foo(t) + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_restrict=$ac_kw +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + test "$ac_cv_c_restrict" != no && break + done + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_restrict" >&5 +$as_echo "$ac_cv_c_restrict" >&6; } + + case $ac_cv_c_restrict in + restrict) ;; + no) $as_echo "#define restrict /**/" >>confdefs.h + ;; + *) cat >>confdefs.h <<_ACEOF +#define restrict $ac_cv_c_restrict +_ACEOF + ;; + esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 +$as_echo_n "checking for inline... " >&6; } +if ${ac_cv_c_inline+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_c_inline=no +for ac_kw in inline __inline__ __inline; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifndef __cplusplus +typedef int foo_t; +static $ac_kw foo_t static_foo () {return 0; } +$ac_kw foo_t foo () {return 0; } +#endif + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_inline=$ac_kw +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + test "$ac_cv_c_inline" != no && break +done + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 +$as_echo "$ac_cv_c_inline" >&6; } + +case $ac_cv_c_inline in + inline | yes) ;; + *) + case $ac_cv_c_inline in + no) ac_val=;; + *) ac_val=$ac_cv_c_inline;; + esac + cat >>confdefs.h <<_ACEOF +#ifndef __cplusplus +#define inline $ac_val +#endif +_ACEOF + ;; +esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for preprocessor stringizing operator" >&5 +$as_echo_n "checking for preprocessor stringizing operator... " >&6; } +if ${ac_cv_c_stringize+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define x(y) #y + +char *s = x(teststring); +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "#teststring" >/dev/null 2>&1; then : + ac_cv_c_stringize=no +else + ac_cv_c_stringize=yes +fi +rm -f conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_stringize" >&5 +$as_echo "$ac_cv_c_stringize" >&6; } +if test $ac_cv_c_stringize = yes; then + +$as_echo "#define HAVE_STRINGIZE 1" >>confdefs.h + +fi + + +ac_config_headers="$ac_config_headers config.h:configh.in" + + + +case $acl_shlibext in +dylib) GAWKLIBEXT=so ;; # MacOS uses .dylib for shared libraries, but libtool uses .so for modules +*) GAWKLIBEXT=$acl_shlibext ;; +esac + + +ac_config_files="$ac_config_files Makefile support/Makefile awklib/Makefile doc/Makefile extras/Makefile po/Makefile.in test/Makefile" + +if test "$enable_extensions" = "yes" +then + + +subdirs="$subdirs extension" + +fi +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 +$as_echo_n "checking that generated files are newer than configure... " >&6; } + if test -n "$am_sleep_pid"; then + # Hide warnings about reused PIDs. + wait $am_sleep_pid 2>/dev/null + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 +$as_echo "done" >&6; } + if test -n "$EXEEXT"; then + am__EXEEXT_TRUE= + am__EXEEXT_FALSE='#' +else + am__EXEEXT_TRUE='#' + am__EXEEXT_FALSE= +fi + +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + as_fn_error $? "conditional \"AMDEP\" 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 +fi +if test -z "${ENABLE_EXTENSIONS_TRUE}" && test -z "${ENABLE_EXTENSIONS_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_EXTENSIONS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by GNU Awk $as_me 4.2.1, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" +config_commands="$ac_config_commands" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to . +GNU Awk home page: . +General help using GNU software: ." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +GNU Awk config.status 4.2.1 +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2012 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +MKDIR_P='$MKDIR_P' +AWK='$AWK' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error $? "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# +# INIT-COMMANDS +# +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" +# Capture the value of obsolete ALL_LINGUAS because we need it to compute + # POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES, CATALOGS. But hide it + # from automake < 1.5. + eval 'OBSOLETE_ALL_LINGUAS''="$ALL_LINGUAS"' + # Capture the value of LINGUAS because we need it to compute CATALOGS. + LINGUAS="${LINGUAS-%UNSET%}" + + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "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" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$ac_tmp/defines.awk" <<\_ACAWK || +BEGIN { +_ACEOF + +# Transform confdefs.h into an awk script `defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_tt=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_tt"; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' >$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$ac_tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 + fi +# Compute "$ac_file"'s index in $config_headers. +_am_arg="$ac_file" +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || +$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$_am_arg" : 'X\(//\)[^/]' \| \ + X"$_am_arg" : 'X\(//\)$' \| \ + X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$_am_arg" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'`/stamp-h$_am_stamp_count + ;; + + :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +$as_echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "depfiles":C) test x"$AMDEP_TRUE" != x"" || { + # Older Autoconf quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named 'Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`$as_dirname -- "$mf" || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running 'make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "$am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`$as_dirname -- "$file" || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir=$dirpart/$fdir; as_fn_mkdir_p + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} + ;; + "po-directories":C) + for ac_file in $CONFIG_FILES; do + # Support "outfile[:infile[:infile...]]" + case "$ac_file" in + *:*) ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + esac + # PO directories have a Makefile.in generated from Makefile.in.in. + case "$ac_file" in */Makefile.in) + # Adjust a relative srcdir. + ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` + ac_dir_suffix=/`echo "$ac_dir"|sed 's%^\./%%'` + ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` + # In autoconf-2.13 it is called $ac_given_srcdir. + # In autoconf-2.50 it is called $srcdir. + test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" + case "$ac_given_srcdir" in + .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; + /*) top_srcdir="$ac_given_srcdir" ;; + *) top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + # Treat a directory as a PO directory if and only if it has a + # POTFILES.in file. This allows packages to have multiple PO + # directories under different names or in different locations. + if test -f "$ac_given_srcdir/$ac_dir/POTFILES.in"; then + rm -f "$ac_dir/POTFILES" + test -n "$as_me" && echo "$as_me: creating $ac_dir/POTFILES" || echo "creating $ac_dir/POTFILES" + gt_tab=`printf '\t'` + cat "$ac_given_srcdir/$ac_dir/POTFILES.in" | sed -e "/^#/d" -e "/^[ ${gt_tab}]*\$/d" -e "s,.*, $top_srcdir/& \\\\," | sed -e "\$s/\(.*\) \\\\/\1/" > "$ac_dir/POTFILES" + POMAKEFILEDEPS="POTFILES.in" + # ALL_LINGUAS, POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES depend + # on $ac_dir but don't depend on user-specified configuration + # parameters. + if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then + # The LINGUAS file contains the set of available languages. + if test -n "$OBSOLETE_ALL_LINGUAS"; then + test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete" + fi + ALL_LINGUAS_=`sed -e "/^#/d" -e "s/#.*//" "$ac_given_srcdir/$ac_dir/LINGUAS"` + # Hide the ALL_LINGUAS assignment from automake < 1.5. + eval 'ALL_LINGUAS''=$ALL_LINGUAS_' + POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS" + else + # The set of available languages was given in configure.in. + # Hide the ALL_LINGUAS assignment from automake < 1.5. + eval 'ALL_LINGUAS''=$OBSOLETE_ALL_LINGUAS' + fi + # Compute POFILES + # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po) + # Compute UPDATEPOFILES + # as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) + # Compute DUMMYPOFILES + # as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) + # Compute GMOFILES + # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) + case "$ac_given_srcdir" in + .) srcdirpre= ;; + *) srcdirpre='$(srcdir)/' ;; + esac + POFILES= + UPDATEPOFILES= + DUMMYPOFILES= + GMOFILES= + for lang in $ALL_LINGUAS; do + POFILES="$POFILES $srcdirpre$lang.po" + UPDATEPOFILES="$UPDATEPOFILES $lang.po-update" + DUMMYPOFILES="$DUMMYPOFILES $lang.nop" + GMOFILES="$GMOFILES $srcdirpre$lang.gmo" + done + # CATALOGS depends on both $ac_dir and the user's LINGUAS + # environment variable. + INST_LINGUAS= + if test -n "$ALL_LINGUAS"; then + for presentlang in $ALL_LINGUAS; do + useit=no + if test "%UNSET%" != "$LINGUAS"; then + desiredlanguages="$LINGUAS" + else + desiredlanguages="$ALL_LINGUAS" + fi + for desiredlang in $desiredlanguages; do + # Use the presentlang catalog if desiredlang is + # a. equal to presentlang, or + # b. a variant of presentlang (because in this case, + # presentlang can be used as a fallback for messages + # which are not translated in the desiredlang catalog). + case "$desiredlang" in + "$presentlang"*) useit=yes;; + esac + done + if test $useit = yes; then + INST_LINGUAS="$INST_LINGUAS $presentlang" + fi + done + fi + CATALOGS= + if test -n "$INST_LINGUAS"; then + for lang in $INST_LINGUAS; do + CATALOGS="$CATALOGS $lang.gmo" + done + fi + test -n "$as_me" && echo "$as_me: creating $ac_dir/Makefile" || echo "creating $ac_dir/Makefile" + sed -e "/^POTFILES =/r $ac_dir/POTFILES" -e "/^# Makevars/r $ac_given_srcdir/$ac_dir/Makevars" -e "s|@POFILES@|$POFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" -e "s|@POMAKEFILEDEPS@|$POMAKEFILEDEPS|g" "$ac_dir/Makefile.in" > "$ac_dir/Makefile" + for f in "$ac_given_srcdir/$ac_dir"/Rules-*; do + if test -f "$f"; then + case "$f" in + *.orig | *.bak | *~) ;; + *) cat "$f" >> "$ac_dir/Makefile" ;; + esac + fi + done + fi + ;; + esac + done ;; + + esac +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi + +# +# CONFIG_SUBDIRS section. +# +if test "$no_recursion" != yes; then + + # Remove --cache-file, --srcdir, and --disable-option-checking arguments + # so they do not pile up. + ac_sub_configure_args= + ac_prev= + eval "set x $ac_configure_args" + shift + for ac_arg + do + if test -n "$ac_prev"; then + ac_prev= + continue + fi + case $ac_arg in + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* \ + | --c=*) + ;; + --config-cache | -C) + ;; + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + ;; + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + ;; + --disable-option-checking) + ;; + *) + case $ac_arg in + *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append ac_sub_configure_args " '$ac_arg'" ;; + esac + done + + # Always prepend --prefix to ensure using the same prefix + # in subdir configurations. + ac_arg="--prefix=$prefix" + case $ac_arg in + *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + ac_sub_configure_args="'$ac_arg' $ac_sub_configure_args" + + # Pass --silent + if test "$silent" = yes; then + ac_sub_configure_args="--silent $ac_sub_configure_args" + fi + + # Always prepend --disable-option-checking to silence warnings, since + # different subdirs can have different --enable and --with options. + ac_sub_configure_args="--disable-option-checking $ac_sub_configure_args" + + ac_popdir=`pwd` + for ac_dir in : $subdirs; do test "x$ac_dir" = x: && continue + + # Do not complain, so a configure script can configure whichever + # parts of a large source tree are present. + test -d "$srcdir/$ac_dir" || continue + + ac_msg="=== configuring in $ac_dir (`pwd`/$ac_dir)" + $as_echo "$as_me:${as_lineno-$LINENO}: $ac_msg" >&5 + $as_echo "$ac_msg" >&6 + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + cd "$ac_dir" + + # Check for guested configure; otherwise get Cygnus style configure. + if test -f "$ac_srcdir/configure.gnu"; then + ac_sub_configure=$ac_srcdir/configure.gnu + elif test -f "$ac_srcdir/configure"; then + ac_sub_configure=$ac_srcdir/configure + elif test -f "$ac_srcdir/configure.in"; then + # This should be Cygnus configure. + ac_sub_configure=$ac_aux_dir/configure + else + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: no configuration information is in $ac_dir" >&5 +$as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2;} + ac_sub_configure= + fi + + # The recursion is here. + if test -n "$ac_sub_configure"; then + # Make the cache file name correct relative to the subdirectory. + case $cache_file in + [\\/]* | ?:[\\/]* ) ac_sub_cache_file=$cache_file ;; + *) # Relative name. + ac_sub_cache_file=$ac_top_build_prefix$cache_file ;; + esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&5 +$as_echo "$as_me: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&6;} + # The eval makes quoting arguments work. + eval "\$SHELL \"\$ac_sub_configure\" $ac_sub_configure_args \ + --cache-file=\"\$ac_sub_cache_file\" --srcdir=\"\$ac_srcdir\"" || + as_fn_error $? "$ac_sub_configure failed for $ac_dir" "$LINENO" 5 + fi + + cd "$ac_popdir" + done +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..f45c710 --- /dev/null +++ b/configure.ac @@ -0,0 +1,459 @@ +dnl +dnl configure.ac --- autoconf input file for gawk +dnl +dnl Copyright (C) 1995-2018 the Free Software Foundation, Inc. +dnl +dnl This file is part of GAWK, the GNU implementation of the +dnl AWK Programming Language. +dnl +dnl GAWK is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 3 of the License, or +dnl (at your option) any later version. +dnl +dnl GAWK is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +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 Process this file with autoconf to produce a configure script. + +AC_INIT([GNU Awk],[4.2.1],[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. +# +# If the user supplies $INSTALL, figure they know what they're doing. +# +# With Autoconf 2.5x, this needs to come very early on, but *after* +# the INIT macro. Sigh. + +if test "$INSTALL" = "" +then + INSTALL="$srcdir/install-sh -c" + export INSTALL +fi + +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, + [AS_HELP_STRING([--with-whiny-user-strftime], [force use of included version of strftime for deficient systems])], + if test "$withval" = yes + then + AC_DEFINE(USE_INCLUDED_STRFTIME, 1, + [force use of our version of strftime]) + fi +) +AC_ARG_ENABLE([lint], + [AS_HELP_STRING([--disable-lint],[do not compile in gawk lint checking])], + if test "$enableval" = no + then + AC_DEFINE(NO_LINT, 1, [disable lint checks]) + fi +) +AC_ARG_ENABLE([severe-portability-problems], + [AS_HELP_STRING([--enable-severe-portability-problems],[allow really nasty portability problems])], + if test "$enableval" = yes + then + AC_DEFINE(I_DONT_KNOW_WHAT_IM_DOING, 1, [enable severe portability problems]) + fi +) +AC_ARG_ENABLE([builtin-intdiv0], + [AS_HELP_STRING([--enable-builtin-intdiv0],[enable built-in intdiv0 function])], + if test "$enableval" = yes + then + AC_DEFINE(SUPPLY_INTDIV, 1, [enable built-in intdiv0 function]) + sed '/^@set PATCHLEVEL/a\ +@set INTDIV' < "$srcdir"/doc/gawktexi.in > foo + cp foo "$srcdir"/doc/gawktexi.in + rm foo + 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 +) + +EXTENSIONDIR= +AC_ARG_ENABLE([versioned-extension-dir], + [AS_HELP_STRING([--enable-versioned-extension-dir], [use a versioned directory for extensions])], + if test "$enableval" = yes + then + MAJOR=`awk '/define gawk_api_major_version/ { print $3 }' < $srcdir/gawkapi.h` + MINOR=`awk '/define gawk_api_minor_version/ { print $3 }' < $srcdir/gawkapi.h` + + # note leading slash on the value + export EXTENSIONDIR=/ext-$MAJOR.$MINOR + fi +) + +# set default shared library location +AC_SUBST([pkgextensiondir], ['${pkglibdir}'${EXTENSIONDIR}]) + +AC_CANONICAL_HOST +AC_USE_SYSTEM_EXTENSIONS + +dnl checks for programs +AC_PROG_EGREP +AC_PROG_YACC +AC_PROG_LN_S +AC_PROG_CC_C99 +AC_PROG_CPP +AC_PROG_RANLIB + +AC_OBJEXT +AC_EXEEXT + +AC_PROG_INSTALL +AC_PROG_MAKE_SET + +# This is mainly for my use during testing and development. +# Yes, it's a bit of a hack. +AC_MSG_CHECKING([for special development options]) +if test -f $srcdir/.developing +then + # add other debug flags as appropriate, save GAWKDEBUG for emergencies + CFLAGS="$CFLAGS -DARRAYDEBUG -DYYDEBUG -DLOCALEDEBUG" + + # turn on compiler warnings if we're doing development + # enable debugging using macros also + if test "$GCC" = yes + then + CFLAGS="$CFLAGS -Wall -fno-builtin -g3" + fi + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) + CFLAGS="$CFLAGS -DNDEBUG" # turn off assertions +fi + +AC_SUBST(CFLAGS) + +# shared library suffix for dynamic loading: +AC_SUBST(acl_shlibext) + +dnl checks for systems +AC_ZOS_USS +AC_SEARCH_LIBS([strerror],[cposix]) +AC_SYS_LARGEFILE + +AC_MSG_CHECKING([if we are using EBCDIC]) +AC_EGREP_CPP([gnu_gawk_in_ebcdic], +[#if 'a' == 0x81 +gnu_gawk_in_ebcdic +#endif], +[AC_DEFINE(USE_EBCDIC, 1, Define to 1 if the character set is EBCDIC) + use_ebcdic=yes], +[use_ebcdic=no]) +AC_MSG_RESULT([$use_ebcdic]) + +dnl Set the programming language for checks. Fortunately, +dnl this only needs to be set once, since everything is in C. +AC_LANG([C]) + +dnl initialize GNU gettext +AM_GNU_GETTEXT([external]) +AM_GNU_GETTEXT_VERSION([0.19.7]) +AM_LANGINFO_CODESET +gt_LC_MESSAGES + +dnl checks for header files +AC_CHECK_HEADERS(arpa/inet.h fcntl.h limits.h locale.h libintl.h mcheck.h \ + netdb.h netinet/in.h stdarg.h stddef.h string.h \ + sys/ioctl.h sys/param.h sys/select.h sys/socket.h sys/time.h unistd.h \ + termios.h stropts.h wchar.h wctype.h) +AC_HEADER_STDC +AC_HEADER_STDBOOL +AC_HEADER_SYS_WAIT +AC_HEADER_TIME + +if test "$ac_cv_header_string_h" = yes +then + AC_CHECK_HEADERS(memory.h) +else + AC_CHECK_HEADERS(strings.h) +fi + +dnl Check cross compiling +AM_CONDITIONAL([TEST_CROSS_COMPILE], [test "$build_alias" != "$host_alias"]) + +dnl checks for typedefs +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_TYPE_GETGROUPS +AC_TYPE_LONG_LONG_INT +AC_TYPE_UNSIGNED_LONG_LONG_INT +AC_TYPE_INTMAX_T +AC_TYPE_UINTMAX_T +AC_CHECK_TYPE(ssize_t, int) +AC_CHECK_SIZEOF(unsigned int) +AC_CHECK_SIZEOF(unsigned long) +dnl see if time_t is defined in +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[ + time_t foo; + foo = 0; +]])],[AC_DEFINE(TIME_T_IN_SYS_TYPES_H, 1, + some systems define this type here)],[]) +dnl check for wctype_t in +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[ + wctype_t foo; + foo = 0; +]])],[AC_DEFINE(HAVE_WCTYPE_T, 1, systems should define this type here)],[]) +dnl check for wint_t in +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[ + wint_t foo; + foo = 0; +]])],[AC_DEFINE(HAVE_WINT_T, 1, systems should define this type here)],[]) +dnl check for sockaddr_storage +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include +#include ]], [[ + struct sockaddr_storage foo; +]])],[AC_DEFINE(HAVE_SOCKADDR_STORAGE, 1, newer systems define this type here)],[]) + +dnl Borrwed from rsync, thanks to to Jim Meyering. + +dnl Check for socklen_t: historically on BSD it is an int, and in +dnl POSIX 1g it is a type of its own, but some platforms use different +dnl types for the argument to getsockopt, getpeername, etc. So we +dnl have to test to find something that will work. + +dnl This is no good, because passing the wrong pointer on C compilers is +dnl likely to only generate a warning, not an error. + +AC_DEFUN([TYPE_SOCKLEN_T], +[ + AC_CHECK_TYPE([socklen_t], ,[ + AC_MSG_CHECKING([for socklen_t equivalent]) + AC_CACHE_VAL([rsync_cv_socklen_t_equiv], + [ + # 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_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include +#include + + int getpeername (int, $arg2 *, $t *); + ]], [[ + $t len; + getpeername(0,0,&len); + ]])],[ + rsync_cv_socklen_t_equiv="$t" + break + ],[]) + done + done + + if test "$rsync_cv_socklen_t_equiv" = "" + 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 + fi + ]) + AC_MSG_RESULT($rsync_cv_socklen_t_equiv) + AC_DEFINE_UNQUOTED(socklen_t, $rsync_cv_socklen_t_equiv, + [type to use in place of socklen_t if not defined])], + [#include +#include ]) +]) +TYPE_SOCKLEN_T + +dnl Check for C11 _Noreturn +GAWK_AC_NORETURN + +dnl checks for functions +AC_FUNC_MKTIME +case "$ac_cv_func_working_mktime" in +yes) AC_DEFINE(HAVE_MKTIME, 1, [we have the mktime function]) + ;; +esac + +AC_CHECK_FUNC(getaddrinfo, [AC_DEFINE(HAVE_GETADDRINFO, 1, [have getaddrinfo])], + [AC_CHECK_LIB(socket, getaddrinfo, + [AC_DEFINE(HAVE_GETADDRINFO, 1, + [have getaddrinfo])])]) + +AC_SEARCH_LIBS(fmod, m) +AC_SEARCH_LIBS(isinf, m) +AC_SEARCH_LIBS(ismod, m) +dnl Don't look for libsigsegv on OSF/1, gives us severe headaches +case $host_os in +osf1) : ;; +*) + gl_LIBSIGSEGV + ;; +esac + +# Need the check for mkstemp and tmpfile for missing_d/snprintf.c. +AC_CHECK_FUNCS(__etoa_l atexit btowc fmod gai_strerror \ + getgrent getgroups grantpt \ + fwrite_unlocked \ + isascii iswctype iswlower iswupper mbrlen \ + memcmp memcpy memcpy_ulong memmove memset \ + memset_ulong mkstemp posix_openpt setenv setlocale setsid sigprocmask \ + snprintf strchr \ + strerror strftime strcasecmp strncasecmp strcoll strtod strtoul \ + 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 + +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 "$enable_extensions" != "no" +then + extensions_supported=no + + dnl On MirBSD (and probably other systems), don't even try. + case $host_os in + mirbsd* | openedition*) # OS/390 z/OS POSIX layer + ;; + *) + AC_CHECK_HEADER(dlfcn.h, + [ + # Check this separately. Some systems have dlopen + # in libc. Notably freebsd and cygwin. + # HP-NSK has it in zrldsrl + AC_SEARCH_LIBS(dlopen, dl zrldsrl, gawk_have_dlopen=yes, gawk_have_dlopen=no) + # Only do DYNAMIC if we have the lib. z/OS (some versions) have + # the header but not the lib, apparently + if test "$gawk_have_dlopen" = yes + then + extensions_supported=yes + AC_DEFINE([DYNAMIC], 1, [dynamic loading is possible]) + fi + ]) + ;; + esac + + if test "$enable_extensions$extensions_supported" = "yesno" + then + AC_MSG_ERROR([extension support requested, but unavailable]) + fi + enable_extensions=$extensions_supported +fi +AM_CONDITIONAL([ENABLE_EXTENSIONS], [test "$enable_extensions" = "yes"]) + +dnl check for how to use getpgrp +dnl have to hardwire it for VMS POSIX. Sigh. +dnl ditto for BeOS, OS/2, and MS-DOS. +case $host_os in +vms*|beos*|os2*|msdos) + AC_DEFINE(GETPGRP_VOID, 1, + [Define to 1 if the getpgrp function requires zero arguments.]) + ;; +*) AC_FUNC_GETPGRP + ;; +esac + +dnl check for printf %F format +AC_MSG_CHECKING([for printf %F format]) +AC_RUN_IFELSE([ +AC_LANG_SOURCE([ +#include + +int main() +{ + char buf[[100]]; + + sprintf(buf, "%F", 123.45); + + if (strcmp(buf, "123.450000") == 0) + return 0; + else + return 1; +} +])], + has_f_format=yes, + has_f_format=no, + has_f_format=no dnl Cross-compiling, assuming the worst. +) +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) + +dnl check for sockets +GAWK_AC_LIB_SOCKETS + +dnl check for readline support +GAWK_CHECK_READLINE + +dnl check for mpfr support +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]) +AC_CHECK_MEMBERS([struct passwd.pw_passwd],,,[ +#include +#include +]) +AC_CHECK_MEMBERS([struct group.gr_passwd],,,[ +#include +#include +]) +AC_STRUCT_TM +AC_STRUCT_TIMEZONE + +dnl checks for compiler characteristics +AC_C_CHAR_UNSIGNED +AC_C_CONST +AC_C_RESTRICT +AC_C_INLINE +AC_C_STRINGIZE + +AC_CONFIG_HEADERS([config.h:configh.in]) +AH_BOTTOM([#include "custom.h"]) + +dnl Crude but small hack to make plug-ins work on Mac OS X +dnl We should really use the libtool value for shrext_cmds, but that +dnl is not available here, since we do not use libtool at the top level. +case $acl_shlibext in +dylib) GAWKLIBEXT=so ;; # MacOS uses .dylib for shared libraries, but libtool uses .so for modules +*) GAWKLIBEXT=$acl_shlibext ;; +esac +AC_SUBST(GAWKLIBEXT) + +AC_CONFIG_FILES(Makefile + support/Makefile + awklib/Makefile + doc/Makefile + extras/Makefile + po/Makefile.in + test/Makefile) +if test "$enable_extensions" = "yes" +then + AC_CONFIG_SUBDIRS(extension) +fi +AC_OUTPUT diff --git a/custom.h b/custom.h new file mode 100644 index 0000000..90fd1f6 --- /dev/null +++ b/custom.h @@ -0,0 +1,73 @@ +/* + * custom.h + * + * This file is for use on systems where Autoconf isn't quite able to + * get things right. It is appended to the bottom of config.h by configure, + * in order to override definitions from Autoconf that are erroneous. See + * the manual for more information. + * + * If you make additions to this file for your system, please send me + * 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 + */ + +/* for VMS POSIX, from Pat Rankin, r.pat.rankin@gmail.com */ +#ifdef VMS_POSIX +#undef VMS +#include "vms/redirect.h" +#endif + +/* For QNX, based on submission from Michael Hunter, mphunter@qnx.com */ +#ifdef __QNX__ +#define GETPGRP_VOID 1 +#endif + +/* For MacOS X, which is almost BSD Unix */ +#ifdef __APPLE__ +#define HAVE_MKTIME 1 +#endif + +/* For whiny users */ +#ifdef USE_INCLUDED_STRFTIME +#undef HAVE_STRFTIME +#endif + +/* For HP/UX with gcc */ +#if defined(hpux) || defined(_HPUX_SOURCE) +#undef HAVE_TZSET +#define HAVE_TZSET 1 +#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) +# define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__)) +#else +# define _GL_ATTRIBUTE_PURE /* empty */ +#endif diff --git a/debug.c b/debug.c new file mode 100644 index 0000000..3e76ae6 --- /dev/null +++ b/debug.c @@ -0,0 +1,5836 @@ +/* + * debug.c - gawk debugger + */ + +/* + * Copyright (C) 2004, 2010-2013, 2016-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 + */ + +#include "awk.h" +#include "cmd.h" + +#ifndef O_RDONLY +#include /* open() */ +#endif + +extern bool exiting; +extern SRCFILE *srcfiles; +extern INSTRUCTION *rule_list; +extern INSTRUCTION *code_block; +extern NODE **fcall_list; +extern long fcall_count; +extern FILE *output_fp; +extern IOBUF *curfile; +extern const char *command_file; +extern const char *get_spec_varname(Func_ptr fptr); +extern int zzparse(void); +#define read_command() (void) zzparse() + +extern const char *redir2str(int redirtype); + +static char *linebuf = NULL; /* used to print a single line of source */ +static size_t linebuf_len; + +FILE *out_fp; +char *dbg_prompt; +char *commands_prompt = "> "; /* breakpoint or watchpoint commands list */ +char *eval_prompt = "@> "; /* awk statement(s) */ + +bool input_from_tty = false; +int input_fd; + +static SRCFILE *cur_srcfile; +static long cur_frame = 0; +static INSTRUCTION *cur_pc; +int cur_rule = 0; + +static bool prog_running = false; + +struct condition { + INSTRUCTION *code; + AWK_CONTEXT *ctxt; + char *expr; +}; + +struct commands_item { + struct commands_item *next; + struct commands_item *prev; + int cmd; + char *cmd_string; + CMDARG *arg; +}; + +/* breakpoint structure */ +typedef struct break_point { + struct break_point *next; + struct break_point *prev; + int number; + + long ignore_count; + long hit_count; + char *src; + INSTRUCTION *bpi; /* Op_breakpoint */ + + struct commands_item commands; /* list of commands to run */ + bool silent; + + struct condition cndn; + + short flags; +#define BP_ENABLE 1 +#define BP_ENABLE_ONCE 2 /* enable once */ +#define BP_TEMP 4 +#define BP_IGNORE 8 + +} BREAKPOINT; + +static BREAKPOINT breakpoints = { &breakpoints, &breakpoints, 0 }; + +#ifdef HAVE_LIBREADLINE +/* do_save -- save command */ +static int sess_history_base = 0; +#endif + +#ifndef HAVE_HISTORY_LIST +#define HIST_ENTRY void +#define history_list() NULL +#endif + + +/* 'list' command */ +static int last_printed_line = 0; +static int last_print_count; /* # of lines printed */ + +/* watch or display item */ +struct list_item { + struct list_item *next; + struct list_item *prev; + int number; /* item number */ + + NODE *symbol; /* variable or function param */ + NODE **subs; /* subscripts */ + int num_subs; /* subscript(dimension) count */ + char *sname; /* symbol or param name */ + + long fcall_count; + + struct commands_item commands; + int silent; + struct condition cndn; + + /* This is for the value of the watched item */ + union { + NODE *n; + long l; + } value[2]; +#define cur_value value[0].n +#define cur_size value[0].l +#define old_value value[1].n +#define old_size value[1].l + + int flags; +#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 IS_PARAM(d) (((d)->flags & PARAM) != 0) +#define IS_SUBSCRIPT(d) (((d)->flags & SUBSCRIPT) != 0) +#define IS_FIELD(d) (((d)->flags & FIELD_NUM) != 0) +#define WATCHING_ARRAY(d) (((d)->flags & CUR_IS_ARRAY) != 0) + +static struct list_item display_list = { &display_list, &display_list, 0 }; +static struct list_item watch_list = { &watch_list, &watch_list, 0 }; + + +/* Structure to maintain data for processing debugger commands */ + +static struct { + long fcall_count; /* 'finish', 'until', 'next', 'step', 'nexti' commands */ + int sourceline; /* source line number last + * time we stopped execution, + * used by next, until and step commands + */ + char *source; /* next, until and step */ + + 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' */ + int break_point; /* non-zero (breakpoint number) if stopped at break point */ + int watch_point; /* non-zero (watchpoint number) if stopped at watch point */ + + int (*check_func)(INSTRUCTION **); /* function to decide when to suspend + * awk interpreter and return control + * to debugger command interpreter. + */ + + enum argtype command; /* command type */ +} stop; + + +/* restart related stuff */ +extern char **d_argv; /* copy of argv array */ +static bool need_restart = false; +enum { BREAK=1, WATCH, DISPLAY, HISTORY, OPTION }; +static const char *const env_variable[] = { +"", +"DGAWK_BREAK", +"DGAWK_WATCH", +"DGAWK_DISPLAY", +"DGAWK_HISTORY", +"DGAWK_OPTION", +}; +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; +#define FSEP (char)'\037' +#define RSEP (char)'\036' +#define CSEP (char)'\035' + + +/* debugger option */ +struct dbg_option { + const char *name; + int *num_val; + char **str_val; + void (*assign)(const char *); + const char *help_txt; +}; + +#define DEFAULT_HISTFILE "./.gawk_history" +#define DEFAULT_OPTFILE "./.gawkrc" +#define DEFAULT_PROMPT "gawk> " +#define DEFAULT_LISTSIZE 15 +#define DEFAULT_HISTSIZE 100 + +static void set_gawk_output(const char *file); +static void set_prompt(const char *value); +static void set_listsize(const char *value); +static void set_trace(const char *value); +static void set_save_history(const char *value); +static void set_save_options(const char *value); +static void set_history_size(const char *value); +static const char *options_file = DEFAULT_OPTFILE; +#ifdef HAVE_LIBREADLINE +static const char *history_file = DEFAULT_HISTFILE; +#endif + +/* debugger option related variables */ + +static char *output_file = "/dev/stdout"; /* gawk output redirection */ +char *dgawk_prompt = NULL; /* initialized in interpret */ +static int list_size = DEFAULT_LISTSIZE; /* # of lines that 'list' prints */ +static int do_trace = false; +static int do_save_history = true; +static int do_save_options = true; +static int history_size = DEFAULT_HISTSIZE; /* max # of lines in history file */ + +static const struct dbg_option option_list[] = { +{"history_size", &history_size, NULL, &set_history_size, + gettext_noop("set or show the number of lines to keep in history file.") }, +{"listsize", &list_size, NULL, &set_listsize, + gettext_noop("set or show the list command window size.") }, +{"outfile", NULL, &output_file, &set_gawk_output, + gettext_noop("set or show gawk output file.") }, +{"prompt", NULL, &dgawk_prompt, &set_prompt, + gettext_noop("set or show debugger prompt."), }, +{"save_history", &do_save_history, NULL, &set_save_history, + gettext_noop("(un)set or show saving of command history (value=on|off).") }, +{"save_options", &do_save_options, NULL, &set_save_options, + gettext_noop("(un)set or show saving of options (value=on|off).") }, +{"trace", &do_trace, NULL, &set_trace, + gettext_noop("(un)set or show instruction tracing (value=on|off).") }, +{0, NULL, NULL, NULL, 0}, +}; + +static void save_options(const char *file); + + +/* pager */ +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 void restart(bool run) ATTRIBUTE_NORETURN; +static void close_all(void); +static int open_readfd(const char *file); +static int find_lines(SRCFILE *s); +static SRCFILE *source_find(char *src); +static int print_lines(char *src, int start_line, int nlines); +static void print_symbol(NODE *r, bool isparam); +static NODE *find_frame(long num); +static NODE *find_param(const char *name, long num, char **pname); +static NODE *find_symbol(const char *name, char **pname); +static NODE *find_array(const char *name); +static void print_field(long field_num); +static int print_function(INSTRUCTION *pc, void *); +static void print_frame(NODE *func, char *src, int srcline); +static void print_numbered_frame(long num); +static void print_cur_frame_and_sourceline(void); +static INSTRUCTION *find_rule(char *src, long lineno); +static INSTRUCTION *mk_breakpoint(char *src, int srcline); +static int execute_commands(struct commands_item *commands); +static void delete_commands_item(struct commands_item *c); +static NODE *execute_code(volatile INSTRUCTION *code); +static int pre_execute_code(INSTRUCTION **pi); +static int parse_condition(int type, int num, char *expr); +static BREAKPOINT *add_breakpoint(INSTRUCTION *prevp, INSTRUCTION *ip, char *src, bool silent); +static BREAKPOINT *set_breakpoint_next(INSTRUCTION *rp, INSTRUCTION *ip); +static BREAKPOINT *set_breakpoint_at(INSTRUCTION *rp, int lineno, bool silent); +static void delete_breakpoint(BREAKPOINT *b); +static BREAKPOINT *find_breakpoint(long num); +static void display(struct list_item *d); +static struct list_item *find_item(struct list_item *list, long num); +static struct list_item *add_item(struct list_item *list, int type, NODE *symbol, char *pname); +static void delete_item(struct list_item *d); +static int breakpoint_triggered(BREAKPOINT *b); +static int watchpoint_triggered(struct list_item *w); +static void print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump); +static int print_code(INSTRUCTION *pc, void *x); +static void next_command(); +static void debug_post_execute(INSTRUCTION *pc); +static int debug_pre_execute(INSTRUCTION **pi); +static char *g_readline(const char *prompt); +static int prompt_yes_no(const char *, char , int , FILE *); +static struct pf_data { + Func_print print_func; + bool defn; + FILE *fp; +} pf_data; + +char * (*read_a_line)(const char *) = 0; /* reads a line of input */ + +struct command_source +{ + int fd; + int is_tty; + char * (*read_func)(const char *); + int (*close_func)(int); + int eof_status; /* see push_cmd_src */ + int cmd; /* D_source or 0 */ + char *str; /* sourced file */ + struct command_source *next; +}; + +static struct command_source *cmd_src = NULL; + + +#define CHECK_PROG_RUNNING() \ + do { \ + if (! prog_running) { \ + d_error(_("program not running.")); \ + return false; \ + } \ + } while (false) + + +/* g_readline -- read a line of text; the interface is like 'readline' but + * without any command-line editing; used when not compiled with + * readline support and/or input is not from terminal (prompt set to NULL). + */ + +static char * +g_readline(const char *prompt) +{ + char *line; + size_t line_size = 100; + static char buf[2]; + char *p, *end; + int n; + + if (input_from_tty && prompt && *prompt) + fprintf(out_fp, "%s", prompt); + + emalloc(line, char *, line_size + 1, "g_readline"); + p = line; + end = line + line_size; + while ((n = read(input_fd, buf, 1)) > 0) { + if (buf[0] == '\n') { + if (p > line && p[-1] == '\r') + p--; + break; + } + if (p == end) { + erealloc(line, char *, 2 * line_size + 1, "g_readline"); + p = line + line_size; + line_size *= 2; + end = line + line_size; + } + *p++ = buf[0]; + } + if (n == -1 || (n == 0 && p == line)) { + efree(line); + return NULL; + } + *p = '\0'; + return line; +} + + +/* d_error --- print an error message */ + +void +d_error(const char *mesg, ...) +{ + va_list args; + va_start(args, mesg); + fprintf(out_fp, _("error: ")); + vfprintf(out_fp, mesg, args); + fprintf(out_fp, "\n"); + va_end(args); +} + +/* find_lines --- find the positions of the lines in the source file. */ + +static int +find_lines(SRCFILE *s) +{ + char *buf, *p, *end; + int n; + int ofs = 0; + int *pos; + int pos_size; + int maxlen = 0; + int numlines = 0; + char lastchar = '\0'; + + emalloc(buf, char *, s->bufsize, "find_lines"); + pos_size = s->srclines; + emalloc(s->line_offset, int *, (pos_size + 2) * sizeof(int), "find_lines"); + pos = s->line_offset; + pos[0] = 0; + + while ((n = read(s->fd, buf, s->bufsize)) > 0) { + end = buf + n; + lastchar = buf[n - 1]; + p = buf; + while (p < end) { + if (*p++ == '\n') { + if (++numlines > pos_size) { + erealloc(s->line_offset, int *, (2 * pos_size + 2) * sizeof(int), "find_lines"); + pos = s->line_offset + pos_size; + pos_size *= 2; + } + *++pos = ofs + (p - buf); + if ((pos[0] - pos[-1]) > maxlen) + maxlen = pos[0] - pos[-1]; /* length including NEWLINE */ + } + } + ofs += n; + } + efree(buf); + + if (n == -1) { + d_error(_("can't read source file `%s' (%s)"), + s->src, strerror(errno)); + return -1; + } + if (ofs <= 0) { + fprintf(out_fp, _("source file `%s' is empty.\n"), s->src); + return -1; + } + + if (lastchar != '\n') { + /* fake a NEWLINE at end */ + *++pos = ofs + 1; + numlines++; + if ((pos[0] - pos[-1]) > maxlen) + maxlen = pos[0] - pos[-1]; + } + s->maxlen = maxlen; + s->srclines = numlines; + return 0; +} + +/* source_find --- return the SRCFILE struct for the source 'src' */ + +static SRCFILE * +source_find(char *src) +{ + SRCFILE *s; + struct stat sbuf; + char *path; + int errno_val = 0; + + if (src == NULL || *src == '\0') { + d_error(_("no current source file.")); + return NULL; + } + + if (cur_srcfile->src == src) /* strcmp(cur_srcfile->src, src) == 0 */ + return cur_srcfile; + + for (s = srcfiles->next; s != srcfiles; s = s->next) { + if ((s->stype == SRC_FILE || s->stype == SRC_INC) + && strcmp(s->src, src) == 0) + return s; + } + + path = find_source(src, & sbuf, & errno_val, false); + if (path != NULL) { + for (s = srcfiles->next; s != srcfiles; s = s->next) { + if ((s->stype == SRC_FILE || s->stype == SRC_INC) + && files_are_same(path, s)) { + efree(path); + return s; + } + } + efree(path); + } + + d_error(_("cannot find source file named `%s' (%s)"), src, strerror(errno_val)); + return NULL; +} + +/* print_lines --- print source lines, and update 'cur_srcfile' */ + +static int +print_lines(char *src, int start_line, int nlines) +{ + SRCFILE *s; + int *pos; + int i; + struct stat sbuf; + + s = source_find(src); + if (s == NULL) + return -1; + if (s->fd <= INVALID_HANDLE && (s->fd = srcopen(s)) <= INVALID_HANDLE) { + d_error(_("can't open source file `%s' for reading (%s)"), + src, strerror(errno)); + return -1; + } + + if (fstat(s->fd, &sbuf) == 0 && s->mtime < sbuf.st_mtime) { + fprintf(out_fp, _("WARNING: source file `%s' modified since program compilation.\n"), + src); + efree(s->line_offset); + s->line_offset = NULL; + s->mtime = sbuf.st_mtime; + + /* reopen source file */ + close(s->fd); + s->fd = INVALID_HANDLE; + if ((s->fd = srcopen(s)) <= INVALID_HANDLE) { + d_error(_("can't open source file `%s' for reading (%s)"), + src, strerror(errno)); + return -1; + } + } + + /* set binary mode so that byte offset calculations will be right */ + os_setbinmode(s->fd, O_BINARY); + + if (s->line_offset == NULL && find_lines(s) != 0) + return -1; + if (start_line < 1 || start_line > s->srclines) { + d_error(_("line number %d out of range; `%s' has %d lines"), + start_line, src, s->srclines); + return -1; + } + + assert(nlines > 0); + if ((start_line + nlines - 1) > s->srclines) + nlines = s->srclines - start_line + 1; + + pos = s->line_offset; + if (lseek(s->fd, (off_t) pos[start_line - 1], SEEK_SET) < 0) { + d_error("%s: %s", src, strerror(errno)); + return -1; + } + + if (linebuf == NULL) { + emalloc(linebuf, char *, s->maxlen + 20, "print_lines"); /* 19 for line # */ + linebuf_len = s->maxlen; + } else if (linebuf_len < s->maxlen) { + erealloc(linebuf, char *, s->maxlen + 20, "print_lines"); + linebuf_len = s->maxlen; + } + + 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 + * condition makes sure that we are in list command + */ + if (nlines > 1) { + BREAKPOINT *b; + 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; + break; + } + } + if (prog_running && src == source && i == sourceline) { + if (has_bpt) + sprintf(linebuf, "%-4d:b=>", i); + else + sprintf(linebuf, "%-4d =>", i); + } else if (has_bpt) + sprintf(linebuf, "%-4d:b ", i); + } + + p = linebuf + strlen(linebuf); + supposed_len = pos[i] - pos[i - 1]; + len = read(s->fd, p, supposed_len); + switch (len) { + case -1: + d_error(_("can't read source file `%s' (%s)"), + src, strerror(errno)); + return -1; + + case 0: + d_error(_("unexpected eof while reading file `%s', line %d"), + src, i); + return -1; + + default: + if (i == s->srclines && p[len - 1] != '\n') + p[len++] = '\n'; +#if 0 + if (len != supposed_len || p[len - 1] != '\n') { + d_error(_("source file `%s' modified since start of program execution"), + src); + return -1; + } +#endif + len += (p - linebuf); + if (fwrite(linebuf, sizeof(char), len, out_fp) != len) + return -1; + } + } + + if (cur_srcfile != s) { + if (cur_srcfile->fd != INVALID_HANDLE) { + close(cur_srcfile->fd); + cur_srcfile->fd = INVALID_HANDLE; + } + cur_srcfile = s; + } + return (i - 1); /* no of lines printed */ +} + +/* do_list --- list command */ + +int +do_list(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) +{ + long line_first, line_last; + 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; + + switch (arg->type) { + case D_int: /* list n or list - */ + if (arg->a_int < 0) { /* list - */ + line_first = last_printed_line - last_print_count - list_size + 1; + if (line_first < 1) { + if (last_printed_line != last_print_count) + line_first = 1; + else + return false; + } + } else { +line: + line_first = arg->a_int - list_size / 2; + if (line_first < 1) + line_first = 1; + } + break; + + case D_range: /* list m-n */ +range: + line_first = arg->a_int; + arg = arg->next; + assert(arg != NULL); + assert(arg->type == D_int); + count = arg->a_int - line_first + 1; + break; + + case D_string: + src = arg->a_string; + if (arg->next != NULL) { + arg = arg->next; + if (arg->type == D_int) /* list file:n */ + goto line; + else if (arg->type == D_range) /* list file:m-n */ + goto range; + else if (arg->type == D_func) /* list file:function */ + goto func; + else + line_first = 1; + } else + line_first = 1; + break; + + case D_func: /* list function */ +func: + rp = arg->a_node->code_ptr; + src = rp->source_file; + line_first = rp->source_line - list_size / 2; + if (line_first < 1) + line_first = 1; + break; + + default: + break; + } + +list: + line_last = print_lines(src, line_first, count); + if (line_last != -1) { + last_printed_line = line_last; + last_print_count = line_last - line_first + 1; + } + return false; +} + +/* do_info --- info command */ + +int +do_info(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) +{ + NODE **table; + + if (arg == NULL || arg->type != D_argument) + return false; + + switch (arg->a_argument) { + case A_SOURCE: + fprintf(out_fp, _("Current source file: %s\n"), cur_srcfile->src); + fprintf(out_fp, _("Number of lines: %d\n"), cur_srcfile->srclines); + break; + + case A_SOURCES: + { + SRCFILE *s; + for (s = srcfiles->next; s != srcfiles; s = s->next) { + fprintf(out_fp, _("Source file (lines): %s (%d)\n"), + (s->stype == SRC_FILE || s->stype == SRC_INC) ? s->src + : "cmd. line", + s->srclines); + } + } + break; + + case A_BREAK: + initialize_pager(out_fp); + if (setjmp(pager_quit_tag) == 0) { + BREAKPOINT *b; + struct commands_item *c; + + gprintf(out_fp, _("Number Disp Enabled Location\n\n")); + for (b = breakpoints.prev; b != &breakpoints; b = b->prev) { + char *disp = "keep"; + if ((b->flags & BP_ENABLE_ONCE) != 0) + disp = "dis"; + else if ((b->flags & BP_TEMP) != 0) + disp = "del"; + gprintf(out_fp, "%-6d %-4.4s %-7.7s file %s, line #%d\n", + b->number, disp, (b->flags & BP_ENABLE) != 0 ? "yes" : "no", + b->src, b->bpi->source_line); + if (b->hit_count > 0) + gprintf(out_fp, _("\tno of hits = %ld\n"), b->hit_count); + if ((b->flags & BP_IGNORE) != 0) + gprintf(out_fp, _("\tignore next %ld hit(s)\n"), b->ignore_count); + if (b->cndn.code != NULL) + gprintf(out_fp, _("\tstop condition: %s\n"), b->cndn.expr); + if (b->commands.next != &b->commands) + gprintf(out_fp, _("\tcommands:\n")); + for (c = b->commands.next; c != &b->commands; c = c->next) { + gprintf(out_fp, "\t%s\n", c->cmd_string); + if (c->cmd == D_eval) { + char *start, *end; + CMDARG *a = c->arg; + start = strchr(a->a_string, '{'); + end = strrchr(a->a_string, '}'); + if (start == NULL || end == NULL) + continue; + start++; + *end = '\0'; + gprintf(out_fp, "%s", start); /* FIXME: translate ? */ + *end = '}'; + } + } + } + } + break; + + case A_FRAME: + CHECK_PROG_RUNNING(); + fprintf(out_fp, _("Current frame: ")); + print_numbered_frame(cur_frame); + if (cur_frame < fcall_count) { + fprintf(out_fp, _("Called by frame: ")); + print_numbered_frame(cur_frame + 1); + } + if (cur_frame > 0) { + fprintf(out_fp, _("Caller of frame: ")); + print_numbered_frame(cur_frame - 1); + } + break; + + case A_ARGS: + case A_LOCALS: + { + NODE *f, *func; + INSTRUCTION *pc; + int arg_count, pcount; + int i, from, to; + + CHECK_PROG_RUNNING(); + f = find_frame(cur_frame); + func = f->func_node; + if (func == NULL) { + /* print ARGV ? */ + fprintf(out_fp, _("None in main().\n")); + return false; + } + + pcount = func->param_cnt; /* # of defined params */ + + pc = (INSTRUCTION *) f->reti; /* Op_func_call instruction */ + arg_count = (pc + 1)->expr_count; /* # of arguments supplied */ + + if (arg_count > pcount) /* extra args */ + arg_count = pcount; + if (arg->a_argument == A_ARGS) { + from = 0; + to = arg_count - 1; + } else { + from = arg_count; + to = pcount - 1; + } + + for (i = from; i <= to; i++) { + NODE *r; + r = f->stack[i]; + if (r->type == Node_array_ref) + r = r->orig_array; + fprintf(out_fp, "%s = ", func->fparms[i].param); + print_symbol(r, true); + } + if (to < from) + fprintf(out_fp, "%s", + arg->a_argument == A_ARGS ? + _("No arguments.\n") : + _("No locals.\n")); + } + break; + + case A_VARIABLES: + table = variable_list(); + initialize_pager(out_fp); + if (setjmp(pager_quit_tag) == 0) { + gprintf(out_fp, _("All defined variables:\n\n")); + print_vars(table, gprintf, out_fp); + } + efree(table); + break; + + case A_FUNCTIONS: + table = function_list(true); + initialize_pager(out_fp); + if (setjmp(pager_quit_tag) == 0) { + gprintf(out_fp, _("All defined functions:\n\n")); + pf_data.print_func = gprintf; + pf_data.fp = out_fp; + pf_data.defn = true; + (void) foreach_func(table, + (int (*)(INSTRUCTION *, void *)) print_function, + &pf_data); + } + efree(table); + break; + + case A_DISPLAY: + case A_WATCH: + initialize_pager(out_fp); + if (setjmp(pager_quit_tag) == 0) { + struct list_item *d, *list; + + if (arg->a_argument == A_DISPLAY) { + list = &display_list; + gprintf(out_fp, _("Auto-display variables:\n\n")); + } else { + list = &watch_list; + gprintf(out_fp, _("Watch variables:\n\n")); + } + for (d = list->prev; d != list; d = d->prev) { + int i; + struct commands_item *c; + NODE *symbol = d->symbol; + + if (IS_SUBSCRIPT(d)) { + gprintf(out_fp, "%d:\t%s", d->number, d->sname); + for (i = 0; i < d->num_subs; i++) { + NODE *sub; + sub = d->subs[i]; + gprintf(out_fp, "[\"%.*s\"]", (int) sub->stlen, sub->stptr); + } + gprintf(out_fp, "\n"); + } else if (IS_FIELD(d)) + gprintf(out_fp, "%d:\t$%ld\n", d->number, get_number_si(symbol)); + else + gprintf(out_fp, "%d:\t%s\n", d->number, d->sname); + if (d->cndn.code != NULL) + gprintf(out_fp, _("\tstop condition: %s\n"), d->cndn.expr); + if (d->commands.next != &d->commands) + gprintf(out_fp, _("\tcommands:\n")); + for (c = d->commands.next; c != &d->commands; c = c->next) { + gprintf(out_fp, "\t%s\n", c->cmd_string); + if (c->cmd == D_eval) { + char *start, *end; + CMDARG *a = c->arg; + start = strchr(a->a_string, '{'); + end = strrchr(a->a_string, '}'); + if (start == NULL || end == NULL) + continue; + start++; + *end = '\0'; + gprintf(out_fp, "%s", start); /* FIXME: translate ? */ + *end = '}'; + } + } + + } + } + break; + + default: + break; + } + + return false; +} + +/* print_symbol --- print a symbol table entry */ + +static void +print_symbol(NODE *r, bool isparam) +{ + switch (r->type) { + case Node_var_new: + fprintf(out_fp, "untyped variable\n"); + break; + case Node_var: + if (! isparam && r->var_update) + r->var_update(); + valinfo(r->var_value, fprintf, out_fp); + break; + case Node_var_array: + fprintf(out_fp, "array, %ld elements\n", assoc_length(r)); + break; + case Node_func: + fprintf(out_fp, "`function'\n"); + break; + default: + break; + } +} + +/* find_frame --- find frame given a frame number */ + +static NODE * +find_frame(long num) +{ + assert(num >= 0); + if (num == 0) + return frame_ptr; + + assert(prog_running == true); + assert(num <= fcall_count); + assert(fcall_list[num] != NULL); + return fcall_list[num]; +} + +/* find_param --- find a function parameter in a given frame number */ + +static NODE * +find_param(const char *name, long num, char **pname) +{ + NODE *r = NULL; + NODE *f; + char *fparam; + + if (pname) + *pname = NULL; + + if (num < 0 || num > fcall_count || name == NULL) + return NULL; + f = find_frame(num); + if (f->func_node != NULL) { /* in function */ + NODE *func; + int i, pcount; + + func = f->func_node; + pcount = func->param_cnt; + for (i = 0; i < pcount; i++) { + fparam = func->fparms[i].param; + if (strcmp(name, fparam) == 0) { + r = f->stack[i]; + if (r->type == Node_array_ref) + r = r->orig_array; + if (pname) + *pname = fparam; + break; + } + } + } + return r; +} + +/* find_symbol --- find a symbol in current context */ + +static +NODE *find_symbol(const char *name, char **pname) +{ + NODE *r = NULL; + + if (pname) + *pname = NULL; + if (prog_running) + r = find_param(name, cur_frame, pname); + if (r == NULL) + r = lookup(name); + if (r == NULL) + fprintf(out_fp, _("no symbol `%s' in current context\n"), name); + return r; +} + +/* find_array -- find an array in current context */ + +static NODE * +find_array(const char *name) +{ + NODE *r; + r = find_symbol(name, NULL); + if (r != NULL && r->type != Node_var_array) { + fprintf(out_fp, _("`%s' is not an array\n"), name); + return NULL; + } + return r; +} + +/* print_field --- print the value of $n */ + +static void +print_field(long field_num) +{ + NODE **lhs; + lhs = get_field(field_num, NULL); + if (*lhs == Null_field || *lhs == Nnull_string) + fprintf(out_fp, _("$%ld = uninitialized field\n"), field_num); + else { + fprintf(out_fp, "$%ld = ", field_num); + valinfo(*lhs, fprintf, out_fp); + } +} + +/* print_array --- print the contents of an array */ + +static int +print_array(volatile NODE *arr, char *arr_name) +{ + NODE *subs; + NODE **list; + int i; + size_t num_elems = 0; + volatile NODE *r; + volatile int ret = 0; + volatile jmp_buf pager_quit_tag_stack; + + if (assoc_empty((NODE *) arr)) { + gprintf(out_fp, _("array `%s' is empty\n"), arr_name); + return 0; + } + + num_elems = assoc_length((NODE *) arr); + + /* sort indices, sub_arrays are also sorted! */ + list = assoc_list((NODE *) arr, "@ind_str_asc", SORTED_IN); + + PUSH_BINDING(pager_quit_tag_stack, pager_quit_tag, pager_quit_tag_valid); + if (setjmp(pager_quit_tag) == 0) { + for (i = 0; ret == 0 && i < num_elems; i++) { + subs = list[i]; + r = *assoc_lookup((NODE *) arr, subs); + if (r->type == Node_var_array) + ret = print_array(r, r->vname); + else { + gprintf(out_fp, "%s[\"%.*s\"] = ", arr_name, (int) subs->stlen, subs->stptr); + valinfo((NODE *) r, gprintf, out_fp); + } + } + } else + ret = 1; + + POP_BINDING(pager_quit_tag_stack, pager_quit_tag, pager_quit_tag_valid); + + for (i = 0; i < num_elems; i++) + unref(list[i]); + efree(list); + + return ret; +} + +/* print_subscript --- print an array element */ + +static void +print_subscript(NODE *arr, char *arr_name, CMDARG *a, int count) +{ + NODE *r, *subs; + + subs = a->a_node; + r = in_array(arr, subs); + if (r == NULL) + 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); + } + } else { + fprintf(out_fp, "%s[\"%.*s\"] = ", arr_name, (int) subs->stlen, subs->stptr); + valinfo(r, fprintf, out_fp); + } +} + +/* do_print_var --- print command */ + +int +do_print_var(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) +{ + NODE *r; + CMDARG *a; + char *name, *pname; + + for (a = arg; a != NULL; a = a->next) { + switch (a->type) { + case D_variable: + name = a->a_string; + if ((r = find_symbol(name, &pname)) != NULL) { + fprintf(out_fp, "%s = ", name); + print_symbol(r, (pname != NULL)); + } + break; + + case D_subscript: + assert(a->a_count > 0); + name = a->a_string; + r = find_array(name); + if (r != NULL) + print_subscript(r, name, a->next, a->a_count); + break; + + case D_array: + name = a->a_string; + if ((r = find_array(name)) != NULL) { + int count = a->a_count; + for (; count > 0; count--) { + 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"), + (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, (int) subs->stlen, subs->stptr); + break; + } else { + r = value; + name = r->vname; + } + } + if (count == 0) { + initialize_pager(out_fp); + print_array((volatile NODE *) r, name); + } + } + break; + + case D_field: + print_field(get_number_si(a->a_node)); + break; + + default: + /* notably D_node, subscript for invalid array name; skip */ + break; + } + } + return false; +} + +/* do_set_var --- set command */ + +int +do_set_var(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) +{ + NODE *r, *val; + NODE **lhs; + char *name, *pname; + + switch (arg->type) { + case D_variable: + name = arg->a_string; + arg = arg->next; + val = arg->a_node; + + if ((r = find_symbol(name, &pname)) == NULL) + break; + + switch (r->type) { + case Node_var_new: + r->type = Node_var; + r->var_value = dupnode(Nnull_string); + /* fall through */ + case Node_var: + lhs = &r->var_value; + unref(*lhs); + *lhs = dupnode(val); + if (pname == NULL && r->var_assign != NULL) + r->var_assign(); + fprintf(out_fp, "%s = ", name); + print_symbol(r, (pname != NULL)); + break; + + default: + d_error(_("`%s' is not a scalar variable"), name); + break; + } + break; + + case D_subscript: + { + NODE *subs, *value; + int count = arg->a_count; + + assert(count > 0); + name = arg->a_string; + r = find_array(name); + if (r == NULL) + break; + for (; count > 0; count--) { + arg = arg->next; + subs = arg->a_node; + value = in_array(r, subs); + + if (count == 1) { + if (value != NULL && value->type == Node_var_array) + 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, (int) subs->stlen, subs->stptr); + valinfo(*lhs, fprintf, out_fp); + } + } else { + if (value == NULL) { + NODE *array; + array = make_array(); + array->vname = estrdup(subs->stptr, subs->stlen); + array->parent_array = r; + lhs = assoc_lookup(r, subs); + unref(*lhs); + *lhs = array; + r = array; + } else if (value->type != Node_var_array) { + d_error(_("attempt to use scalar `%s[\"%.*s\"]' as array"), + name, (int) subs->stlen, subs->stptr); + break; + } else { + r = value; + name = r->vname; + } + } + } + } + break; + + case D_field: + { + long field_num; + Func_ptr assign = NULL; + + field_num = get_number_si(arg->a_node); + assert(field_num >= 0); + arg = arg->next; + val = arg->a_node; + lhs = get_field(field_num, &assign); + if (assign) + /* call assign to copy fields before unref frees $0 */ + assign(); + unref(*lhs); + *lhs = dupnode(val); + print_field(field_num); + } + break; + + default: + break; + } + return false; +} + +/* find_item --- find an item in the watch/display list */ + +static struct list_item * +find_item(struct list_item *list, long num) +{ + struct list_item *d; + + if (num <= 0) + return NULL; + for (d = list->next; d != list; d = d->next) { + if (d->number == num) + return d; + } + return NULL; +} + +/* delete_item --- delete an item from the watch/display list */ + +static void +delete_item(struct list_item *d) +{ + struct commands_item *c; + int i; + + if (IS_SUBSCRIPT(d)) { + for (i = 0; i < d->num_subs; i++) + unref(d->subs[i]); + efree(d->subs); + } else if (IS_FIELD(d)) + unref(d->symbol); + + if ((d->flags & CUR_IS_ARRAY) == 0) + unref(d->cur_value); + if ((d->flags & OLD_IS_ARRAY) == 0) + unref(d->old_value); + + /* delete commands */ + for (c = d->commands.next; c != &d->commands; c = c->next) { + c = c->prev; + delete_commands_item(c->next); + } + + 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); +} + +/* add_item --- craete a watch/display item and add it to the list */ + +static struct list_item * +add_item(struct list_item *list, int type, NODE *symbol, char *pname) +{ + struct list_item *d; + + ezalloc(d, struct list_item *, sizeof(struct list_item), "add_item"); + d->commands.next = d->commands.prev = &d->commands; + + d->number = ++list->number; + d->sname = symbol->vname; + if (pname != NULL) { /* function param */ + d->sname = pname; + d->flags |= PARAM; + d->fcall_count = fcall_count - cur_frame; + } + + if (type == D_field) { + /* field number */ + d->symbol = symbol; + d->flags |= FIELD_NUM; + } else if (type == D_subscript) { + /* subscript */ + d->symbol = symbol; + d->flags |= SUBSCRIPT; + } else { + /* array or variable */ + d->symbol = symbol; + } + + /* add to list */ + d->next = list->next; + d->prev = list; + list->next = d; + d->next->prev = d; + return d; +} + +/* do_add_item --- add an item to the watch/display list */ + +static struct list_item * +do_add_item(struct list_item *list, CMDARG *arg) +{ + NODE *symbol = NULL; + char *name, *pname = NULL; + struct list_item *item = NULL; + + switch (arg->type) { + case D_subscript: + case D_variable: + name = arg->a_string; + if ((symbol = find_symbol(name, &pname)) == NULL) + return NULL; + if (symbol->type == Node_func) { + d_error(_("`%s' is a function"), name); + return NULL; + } + if (arg->type == D_subscript && symbol->type != Node_var_array) { + d_error(_("`%s' is not an array\n"), name); + return NULL; + } + + item = add_item(list, arg->type, symbol, pname); + if (item != NULL && arg->type == D_subscript) { + NODE **subs; + int count = arg->a_count; + int i; + + assert(count > 0); + emalloc(subs, NODE **, count * sizeof(NODE *), "do_add_item"); + for (i = 0; i < count; i++) { + arg = arg->next; + subs[i] = dupnode(arg->a_node); + subs[i] = force_string(subs[i]); + } + item->subs = subs; + item->num_subs = count; + } + break; + + case D_field: + symbol = dupnode(arg->a_node); + item = add_item(list, D_field, symbol, NULL); + break; + + default: + break; + } + + /* watch condition if any */ + if (list == &watch_list) { + arg = arg->next; + if (item != NULL && arg != NULL) { + if (parse_condition(D_watch, item->number, arg->a_string) == 0) + arg->a_string = NULL; /* don't let free_cmdarg free it */ + else + fprintf(out_fp, _("watchpoint %d is unconditional\n"), item->number); + } + } + return item; +} + +/* do_delete_item --- delete a watch/display item from list. */ + +static void +do_delete_item(struct list_item *list, CMDARG *arg) +{ + if (arg == NULL) { + while (list->next != list) + delete_item(list->next); + } + + for (; arg != NULL; arg = arg->next) { + struct list_item *d; + if (arg->type == D_range) { + long i, j; + + i = arg->a_int; + arg = arg->next; + j = arg->a_int; + if (j > list->number) + j = list->number; + for (; i <= j; i++) { + if ((d = find_item(list, i)) != NULL) + delete_item(d); + } + } else { + if ((d = find_item(list, arg->a_int)) == NULL) { + /* split into two for easier message translation */ + if (list == &display_list) + d_error(_("No display item numbered %ld"), + arg->a_int); + else + d_error(_("No watch item numbered %ld"), + arg->a_int); + } else + delete_item(d); + } + } +} + +/* display --- print an item from the auto-display list */ + +static void +display(struct list_item *d) +{ + NODE *symbol; + + symbol = d->symbol; + if (IS_PARAM(d) && (d->fcall_count != (fcall_count - cur_frame))) + return; + + if (IS_SUBSCRIPT(d)) { + NODE *sub, *r; + int i = 0, count = d->num_subs; + for (i = 0; i < count; i++) { + sub = d->subs[i]; + r = in_array(symbol, sub); + if (r == NULL) { + 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 { + if (i != count - 1) + return; /* FIXME msg and delete item ? */ + fprintf(out_fp, "%d: %s[\"%.*s\"] = ", d->number, + d->sname, (int) sub->stlen, sub->stptr); + valinfo(r, fprintf, out_fp); + } + } + } else if (IS_FIELD(d)) { + NODE *r = d->symbol; + fprintf(out_fp, "%d: ", d->number); + print_field(get_number_si(r)); + } else { +print_sym: + fprintf(out_fp, "%d: %s = ", d->number, d->sname); + print_symbol(symbol, IS_PARAM(d)); + } +} + + +/* do_display --- display command */ + +int +do_display(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) +{ + struct list_item *d; + + if (arg == NULL) { + /* display all items */ + for (d = display_list.prev; d != &display_list; d = d->prev) + display(d); + return false; + } + + if ((d = do_add_item(&display_list, arg)) != NULL) + display(d); + + return false; +} + +/* do_undisplay --- undisplay command */ + +int +do_undisplay(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) +{ + do_delete_item(&display_list, arg); + return false; +} + +/* condition_triggered --- test if a condition expression is true */ + +static int +condition_triggered(struct condition *cndn) +{ + NODE *r; + int di; + + assert(cndn != NULL); + if (cndn->code == NULL) + return true; + + push_context(cndn->ctxt); + r = execute_code((volatile INSTRUCTION *) cndn->code); + pop_context(); /* switch to prev context */ + if (r == NULL) /* fatal error */ + return false; /* not triggered */ + + force_number(r); + di = ! iszero(r); + DEREF(r); + return di; +} + + +static int +find_subscript(struct list_item *item, NODE **ptr) +{ + NODE *symbol = item->symbol; + NODE *sub, *r; + int i = 0, count = item->num_subs; + + r = *ptr = NULL; + for (i = 0; i < count; i++) { + sub = item->subs[i]; + r = in_array(symbol, sub); + if (r == NULL) + return 0; + if (r->type == Node_var_array) + symbol = r; + else if (i < count - 1) + return -1; + } + if (r != NULL) + *ptr = r; + return 0; +} + +/* cmp_val --- compare values of watched item, returns true if different; */ + +static int +cmp_val(struct list_item *w, NODE *old, NODE *new) +{ + /* + * case old new result + * ------------------------------ + * 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 + * 9: ARRAY NULL true + */ + + if (WATCHING_ARRAY(w)) { + long size = 0; + if (! new) /* 9 */ + return true; + if (new->type == Node_val) /* 7 */ + return true; + /* new->type == Node_var_array */ /* 8 */ + size = assoc_length(new); + if (w->cur_size == size) + return false; + return true; + } + + if (! old && ! new) /* 3 */ + return false; + if ((! old && new) /* 1, 2 */ + || (old && ! new)) /* 6 */ + return true; + + if (new->type == Node_var_array) /* 5 */ + return true; + return cmp_nodes(old, new, true); /* 4 */ +} + +/* watchpoint_triggered --- check if we should stop at this watchpoint; + * update old and current values accordingly. + */ + +static int +watchpoint_triggered(struct list_item *w) +{ + NODE *symbol; + NODE *t1, *t2; + + symbol = w->symbol; + if (IS_PARAM(w) && (w->fcall_count != (fcall_count - cur_frame))) + return 0; /* parameter with same name in a different function */ + if (! condition_triggered(&w->cndn)) + return 0; + + t1 = w->cur_value; + t2 = (NODE *) 0; + if (IS_SUBSCRIPT(w)) + (void) find_subscript(w, &t2); + else if (IS_FIELD(w)) { + long field_num; + field_num = get_number_si(w->symbol); + t2 = *get_field(field_num, NULL); + } else { + switch (symbol->type) { + case Node_var: + t2 = symbol->var_value; + break; + case Node_var_array: + t2 = symbol; + break; + case Node_var_new: + break; + default: + cant_happen(); + } + } + + if (! cmp_val(w, t1, t2)) + return 0; + + /* update old and current values */ + + if ((w->flags & OLD_IS_ARRAY) == 0) + unref(w->old_value); + w->flags &= ~OLD_IS_ARRAY; + if (WATCHING_ARRAY(w)) { /* 7, 8, 9 */ + w->old_size = w->cur_size; + w->flags |= OLD_IS_ARRAY; + if (! t2) { + w->flags &= ~CUR_IS_ARRAY; + w->cur_value = 0; + } else if (t2->type == Node_val) { + w->flags &= ~CUR_IS_ARRAY; + w->cur_value = dupnode(t2); + } else + w->cur_size = (t2->type == Node_var_array) ? assoc_length(t2) : 0; + } else if (! t1) { /* 1, 2 */ + w->old_value = 0; + /* new != NULL */ + if (t2->type == Node_val) + w->cur_value = dupnode(t2); + else { + w->flags |= CUR_IS_ARRAY; + w->cur_size = (t2->type == Node_var_array) ? assoc_length(t2) : 0; + } + } else /* if (t1->type == Node_val) */ { /* 4, 5, 6 */ + w->old_value = w->cur_value; + if (! t2) + w->cur_value = 0; + else if (t2->type == Node_var_array) { + w->flags |= CUR_IS_ARRAY; + w->cur_size = assoc_length(t2); + } else + w->cur_value = dupnode(t2); + } + + return w->number; +} + +/* initialize_watch_item --- initialize current value of a watched item */ + +static int +initialize_watch_item(struct list_item *w) +{ + NODE *t, *r; + NODE *symbol = w->symbol; + + if (IS_SUBSCRIPT(w)) { + if (find_subscript(w, &r) == -1) { + d_error(_("attempt to use scalar value as array")); + return -1; + } + + if (r == NULL) + w->cur_value = (NODE *) 0; + else if (r->type == Node_var_array) { /* it's a sub-array */ + w->flags |= CUR_IS_ARRAY; + w->cur_size = assoc_length(r); + } else + w->cur_value = dupnode(r); + } else if (IS_FIELD(w)) { + long field_num; + t = w->symbol; + field_num = get_number_si(t); + r = *get_field(field_num, NULL); + w->cur_value = dupnode(r); + } else { + if (symbol->type == Node_var_new) + w->cur_value = (NODE *) 0; + else if (symbol->type == Node_var) { + r = symbol->var_value; + w->cur_value = dupnode(r); + } 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 */ + } + return 0; +} + +/* do_watch --- watch command */ + +int +do_watch(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) +{ + struct list_item *w; + NODE *symbol, *sub; + int i; + + w = do_add_item(&watch_list, arg); + if (w == NULL) + return false; + + if (initialize_watch_item(w) == -1) { + delete_item(w); + return false; + } + + fprintf(out_fp, "Watchpoint %d: ", w->number); + symbol = w->symbol; + + /* FIXME: common code also in print_watch_item */ + if (IS_SUBSCRIPT(w)) { + fprintf(out_fp, "%s", w->sname); + for (i = 0; i < w->num_subs; i++) { + sub = w->subs[i]; + fprintf(out_fp, "[\"%.*s\"]", (int) sub->stlen, sub->stptr); + } + fprintf(out_fp, "\n"); + } else if (IS_FIELD(w)) + fprintf(out_fp, "$%ld\n", get_number_si(symbol)); + else + fprintf(out_fp, "%s\n", w->sname); + + return false; +} + +/* do_unwatch --- unwatch command */ + +int +do_unwatch(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) +{ + do_delete_item(&watch_list, arg); + return false; +} + +/* callback from pop_frame in eval.c */ + +void +frame_popped() +{ + struct list_item *item; + + /* delete all out of scope watchpoints */ + for (item = watch_list.next; item != &watch_list; item = item->next) { + if (IS_PARAM(item) && (item->fcall_count > fcall_count)) { + fprintf(out_fp, + _("Watchpoint %d deleted because parameter is out of scope.\n"), + item->number); + item = item->prev; + delete_item(item->next); + } + } + + /* delete all out of scope display items */ + for (item = display_list.next; item != &display_list; item = item->next) { + if (IS_PARAM(item) && (item->fcall_count > fcall_count)) { + fprintf(out_fp, + _("Display %d deleted because parameter is out of scope.\n"), + item->number); + item = item->prev; + delete_item(item->next); + } + } +} + +/* print_function --- print function name, parameters, and optionally + * file and line number. + */ + +static int +print_function(INSTRUCTION *pc, void *x) +{ + NODE *func; + int i, pcount; + struct pf_data *data = (struct pf_data *) x; + int defn = data->defn; + Func_print print_func = data->print_func; + FILE *fp = data->fp; + + func = pc->func_body; + pcount = func->param_cnt; + + print_func(fp, "%s(", func->vname); + for (i = 0; i < pcount; i++) { + print_func(fp, "%s", func->fparms[i].param); + if (i < pcount - 1) + print_func(fp, ", "); + } + print_func(fp, ")"); + if (defn) + print_func(fp, _(" in file `%s', line %d\n"), + pc->source_file, pc->source_line); + return 0; +} + +/* print_frame --- print function name, parameters, + * source and line number of where it is + * executing. + */ + +static void +print_frame(NODE *func, char *src, int srcline) +{ + if (func == NULL) + fprintf(out_fp, "main()"); + else { + pf_data.print_func = fprintf; + pf_data.fp = out_fp; + pf_data.defn = false; + (void) print_function(func->code_ptr, &pf_data); + } + fprintf(out_fp, _(" at `%s':%d"), src, srcline); +} + +/* print_numbered_frame --- print a frame given its number */ + +static void +print_numbered_frame(long num) +{ + NODE *f; + + assert(prog_running == true); + f = find_frame(num); + if (num == 0) { + fprintf(out_fp, "#%ld\t ", num); + print_frame(f->func_node, source, sourceline); + } else { + fprintf(out_fp, _("#%ld\tin "), num); + print_frame(f->func_node, f->vname, + ((INSTRUCTION *) find_frame(num - 1)->reti)->source_line); + } + fprintf(out_fp, "\n"); +} + +/* do_backtrace --- backtrace command */ + +int +do_backtrace(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) +{ + long cur = 0; + long last = fcall_count; + + CHECK_PROG_RUNNING(); + if (arg != NULL && arg->type == D_int) { + long count = arg->a_int; + + /* frame_ptr (frame #0), fcall_list[1, 2, ... fcall_count] => total count */ + if (count >= 0) { + /* toward outermost frame #fcall_count */ + last = count - 1; + if (last > fcall_count) + last = fcall_count; + } else { + /* toward innermost frame #0 */ + cur = 1 + fcall_count + count; + if (cur < 0) + cur = 0; + } + } + + for (; cur <= last; cur++) { + print_numbered_frame(cur); + } + 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() +{ + NODE *f; + int srcline; + char *src; + + assert(prog_running == true); + f = find_frame(cur_frame); + if (cur_frame == 0) { + src = source; + srcline = sourceline; + } else { + f = find_frame(cur_frame); + src = f->vname; + srcline = ((INSTRUCTION *) find_frame(cur_frame - 1)->reti)->source_line; + } + + fprintf(out_fp, (cur_frame > 0 ? _("#%ld\tin ") : "#%ld\t "), cur_frame); + print_frame(f->func_node, src, srcline); + fprintf(out_fp, "\n"); + print_lines(src, srcline, 1); + last_printed_line = srcline - list_size / 2; + if (last_printed_line < 0) + last_printed_line = 0; +} + +/* do_frame --- frame command */ + +int +do_frame(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) +{ + CHECK_PROG_RUNNING(); + if (arg && arg->type == D_int) { + if (arg->a_int < 0 || arg->a_int > fcall_count) { + d_error(_("invalid frame number")); + return false; + } + cur_frame = arg->a_int; + } + print_cur_frame_and_sourceline(); + return false; +} + +/* do_up --- up command */ + +int +do_up(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) +{ + CHECK_PROG_RUNNING(); + if (arg != NULL && arg->type == D_int) + cur_frame += arg->a_int; + else + cur_frame++; + if (cur_frame < 0) + cur_frame = 0; + else if (cur_frame > fcall_count) + cur_frame = fcall_count; + print_cur_frame_and_sourceline(); + return false; +} + +/* do_down --- down command */ + +int +do_down(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) +{ + CHECK_PROG_RUNNING(); + if (arg != NULL && arg->type == D_int) + cur_frame -= arg->a_int; + else + cur_frame--; + if (cur_frame < 0) + cur_frame = 0; + else if (cur_frame > fcall_count) + cur_frame = fcall_count; + print_cur_frame_and_sourceline(); + return false; +} + +/* find_rule --- find a rule or function in file 'src' containing + * source line 'lineno' + */ + +static INSTRUCTION * +find_rule(char *src, long lineno) +{ + INSTRUCTION *rp; + + /* + * FIXME: The check for zero and code that goes with it + * are probably fragile. A break with no arguments can + * cause this in certain cases. Try to review how this works. + */ + if (lineno == 0) { + for (rp = rule_list->nexti; rp != NULL; rp = rp->nexti) { + if ((rp - 1)->source_file == src && (rp - 1)->source_line > 0) + return (rp - 1); + } + } else { + for (rp = rule_list->nexti; rp != NULL; rp = rp->nexti) { + if ((rp - 1)->source_file == src + && lineno >= (rp + 1)->first_line + && lineno <= (rp + 1)->last_line) + return (rp - 1); + } + } + return NULL; +} + +/* mk_breakpoint --- create a breakpoint instruction and the corresponding + * breakpoint structure. + */ + +static INSTRUCTION * +mk_breakpoint(char *src, int srcline) +{ + INSTRUCTION *bp; + BREAKPOINT *b; + + bp = bcalloc(Op_breakpoint, 1, srcline); + emalloc(b, BREAKPOINT *, sizeof(BREAKPOINT), "mk_breakpoint"); + memset(&b->cndn, 0, sizeof(struct condition)); + b->commands.next = b->commands.prev = &b->commands; + b->silent = false; + + + b->number = ++watch_list.number; /* breakpoints and watchpoints use same counter */ + b->ignore_count = 0; + b->hit_count = 0; + b->flags = BP_ENABLE; + b->src = src; + bp->break_pt = b; + b->bpi = bp; + + /* prepend to list */ + b->next = breakpoints.next; + b->prev = &breakpoints; + breakpoints.next = b; + b->next->prev = b; + return bp; +} + +/* delete_breakpoint --- delete a breakpoint structure and + * disable the breakpoint instruction. + */ + +static void +delete_breakpoint(BREAKPOINT *b) +{ + INSTRUCTION *pc = b->bpi; + struct commands_item *c; + + /* N.B.: easiest thing to do is to turn Op_breakpoint into a no-op; + * 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; + + /* delete commands */ + for (c = b->commands.next; c != &b->commands; c = c->next) { + c = c->prev; + delete_commands_item(c->next); + } + + free_context(b->cndn.ctxt, false); + if (b->cndn.expr != NULL) + efree(b->cndn.expr); + + /* remove from list */ + b->next->prev = b->prev; + b->prev->next = b->next; + efree(b); +} + +/* find_breakpoint --- find the breakpoint structure from a breakpoint number */ + +static BREAKPOINT * +find_breakpoint(long num) +{ + BREAKPOINT *b; + + if (num <= 0) + return NULL; + + for (b = breakpoints.next; b != &breakpoints; b = b->next) { + if (b->number == num) + return b; + } + return NULL; +} + +/* add_breakpoint --- add a breakpoint instruction between PREVP and IP */ + +static BREAKPOINT * +add_breakpoint(INSTRUCTION *prevp, INSTRUCTION *ip, char *src, bool silent) +{ + BREAKPOINT *b; + INSTRUCTION *bp; + int lineno = ip->source_line; + + /* add new breakpoint instruction at the end of + * already set breakpoints at this line number. + */ + + while (ip->opcode == Op_breakpoint && ip->source_line == lineno) { + if (! silent) { + b = ip->break_pt; + /* + * This is more verbose that it might otherwise be, + * in order to provide easily translatable strings. + */ + if ((b->flags & BP_ENABLE) != 0) { + if ((b->flags & BP_IGNORE) != 0) + fprintf(out_fp, + _("Note: breakpoint %d (enabled, ignore next %ld hits), also set at %s:%d"), + b->number, + b->ignore_count, + b->src, + lineno); + else + fprintf(out_fp, + _("Note: breakpoint %d (enabled), also set at %s:%d"), + b->number, + b->src, + lineno); + } else { + if ((b->flags & BP_IGNORE) != 0) + fprintf(out_fp, + _("Note: breakpoint %d (disabled, ignore next %ld hits), also set at %s:%d"), + b->number, + b->ignore_count, + b->src, + lineno); + else + fprintf(out_fp, + _("Note: breakpoint %d (disabled), also set at %s:%d"), + b->number, + b->src, + lineno); + } + } + prevp = ip; + ip = ip->nexti; + } + + assert(ip->source_line == lineno); + + bp = mk_breakpoint(src, lineno); + prevp->nexti = bp; + bp->nexti = ip; + b = bp->break_pt; + if (! silent) + fprintf(out_fp, _("Breakpoint %d set at file `%s', line %d\n"), + b->number, src, lineno); + return b; +} + +/* set_breakpoint_at --- set a breakpoint at given line number*/ + +static BREAKPOINT * +set_breakpoint_at(INSTRUCTION *rp, int lineno, bool silent) +{ + INSTRUCTION *ip, *prevp; + + for (prevp = rp, ip = rp->nexti; ip; prevp = ip, ip = ip->nexti) { + if (ip->opcode == Op_K_case) { + INSTRUCTION *i1, *i2; + + /* Special case: the code line numbers for a switch do not form + * 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) + return add_breakpoint(i2, i1, rp->source_file, silent); + if (i1 == ip->stmt_end) + break; + } + } + + if (ip->source_line >= lineno) + return add_breakpoint(prevp, ip, rp->source_file, silent); + if (ip == (rp + 1)->lasti) + break; + } + return NULL; +} + +/* set_breakpoint_next --- set a breakpoint at the next instruction */ + +static BREAKPOINT * +set_breakpoint_next(INSTRUCTION *rp, INSTRUCTION *ip) +{ + INSTRUCTION *prevp; + + if (ip == (rp + 1)->lasti) + return NULL; + prevp = ip; + if (ip->opcode != Op_breakpoint) + ip = ip->nexti; + for (; ip; prevp = ip, ip = ip->nexti) { + if (ip->source_line > 0) + return add_breakpoint(prevp, ip, rp->source_file, false); + if (ip == (rp + 1)->lasti) + break; + } + return NULL; +} + +/* set_breakpoint --- set a breakpoint */ + +static int +set_breakpoint(CMDARG *arg, bool temporary) +{ + int lineno; + BREAKPOINT *b = NULL; + INSTRUCTION *rp, *ip; + NODE *func; + SRCFILE *s = cur_srcfile; + char *src = cur_srcfile->src; + + 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 +* as control returns to that frame. This is similar to the effect of a finish command +* in the frame inside the selected frame--except that finish does not leave an +* active breakpoint. If you use break without an argument in the innermost frame, +* GDB stops the next time it reaches the current location; this may be useful +* inside loops. +* GDB normally ignores breakpoints when it resumes execution, until at least +* 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. +*/ + CHECK_PROG_RUNNING(); + if (cur_frame == 0) { + src = source; + ip = cur_pc; + } else { + NODE *f; + f = find_frame(cur_frame); + src = f->vname; + ip = (INSTRUCTION *) find_frame(cur_frame - 1)->reti; /* Op_func_call */ + } + rp = find_rule(src, ip->source_line); + assert(rp != NULL); + if ((b = set_breakpoint_next(rp, ip)) == NULL) + fprintf(out_fp, _("Can't set breakpoint in file `%s'\n"), src); + else { + if (cur_frame == 0) { /* stop next time */ + b->flags |= BP_IGNORE; + b->ignore_count = 1; + } + if (temporary) + b->flags |= BP_TEMP; + } + return false; + } + + /* arg != NULL */ + + switch (arg->type) { + case D_string: /* break filename:lineno|function */ + s = source_find(arg->a_string); + arg = arg->next; + if (s == NULL || arg == NULL + || (arg->type != D_int && arg->type != D_func)) + return false; + src = s->src; + if (arg->type == D_func) /* break filename:function */ + goto func; + else + /* fall through */ + case D_int: /* break lineno */ + lineno = (int) arg->a_int; + if (lineno <= 0 || lineno > s->srclines) + d_error(_("line number %d in file `%s' out of range"), lineno, src); + else { + rp = find_rule(src, lineno); + if (rp == NULL) + fprintf(out_fp, _("Can't find rule!!!\n")); + if (rp == NULL || (b = set_breakpoint_at(rp, lineno, false)) == NULL) + fprintf(out_fp, _("Can't set breakpoint at `%s':%d\n"), + src, lineno); + if (b != NULL && temporary) + b->flags |= BP_TEMP; + } + break; + + case D_func: /* break function */ +func: + func = arg->a_node; + rp = func->code_ptr; + if ((b = set_breakpoint_at(rp, rp->source_line, false)) == NULL) + fprintf(out_fp, _("Can't set breakpoint in function `%s'\n"), + func->vname); + else if (temporary) + b->flags |= BP_TEMP; + lineno = b->bpi->source_line; + break; + + default: + return false; + } + /* condition if any */ + arg = arg->next; + if (b != NULL && arg != NULL) { + if (parse_condition(D_break, b->number, arg->a_string) == 0) + arg->a_string = NULL; /* don't let free_cmdarg free it */ + else + fprintf(out_fp, _("breakpoint %d set at file `%s', line %d is unconditional\n"), + b->number, src, lineno); + } + return false; +} + + +/* breakpoint_triggered --- check if we should stop at this breakpoint */ + +static int +breakpoint_triggered(BREAKPOINT *b) +{ + if ((b->flags & BP_ENABLE) == 0) + return 0; + if ((b->flags & BP_IGNORE) != 0) { + if (--b->ignore_count <= 0) + b->flags &= ~BP_IGNORE; + return 0; + } + + if (! condition_triggered(&b->cndn)) + return 0; + + b->hit_count++; + if ((b->flags & BP_ENABLE_ONCE) != 0) { + b->flags &= ~BP_ENABLE_ONCE; + b->flags &= ~BP_ENABLE; + } + return b->number; +} + +/* do_breakpoint --- break command */ + +int +do_breakpoint(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) +{ + return set_breakpoint(arg, false); +} + +/* do_tmp_breakpoint --- tbreak command */ + +int +do_tmp_breakpoint(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) +{ + return set_breakpoint(arg, true); +} + +/* do_clear --- clear command */ + +int +do_clear(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) +{ + int lineno; + BREAKPOINT *b; + INSTRUCTION *rp, *ip; + NODE *func; + SRCFILE *s = cur_srcfile; + char *src = cur_srcfile->src; + int bp_found = 0; + + if (arg == NULL) { /* clear */ + CHECK_PROG_RUNNING(); + if (cur_frame == 0) { + lineno = sourceline; + src = source; + } else { + NODE *f; + f = find_frame(cur_frame); + src = f->vname; + lineno = ((INSTRUCTION *) find_frame(cur_frame - 1)->reti)->source_line; + } + goto delete_bp; + } + + switch (arg->type) { + case D_string: /* clear filename:lineno|function */ + s = source_find(arg->a_string); + arg = arg->next; + if (s == NULL || arg == NULL || + (arg->type != D_int && arg->type != D_func)) + return false; + src = s->src; + if (arg->type == D_func) + goto func; + /* else + fall through */ + case D_int: /* clear lineno */ + lineno = (int) arg->a_int; + if (lineno <= 0 || lineno > s->srclines) { + d_error(_("line number %d in file `%s' out of range"), lineno, src); + return false; + } + break; + + case D_func: /* clear function */ +func: + func = arg->a_node; + rp = func->code_ptr; + for (ip = rp->nexti; ip; ip = ip->nexti) { + if (ip->source_line <= 0) + continue; + if (ip->opcode != Op_breakpoint) + break; + b = ip->break_pt; + if (++bp_found == 1) + fprintf(out_fp, _("Deleted breakpoint %d"), b->number); + else + fprintf(out_fp, ", %d", b->number); + delete_breakpoint(b); + } + if (bp_found == 0) + fprintf(out_fp, _("No breakpoint(s) at entry to function `%s'\n"), + func->vname); + else + fprintf(out_fp, "\n"); + /* fall through */ + default: + return false; + } + +delete_bp: + rp = find_rule(src, lineno); + if (rp != NULL) { + for (ip = rp->nexti; ip; ip = ip->nexti) { + if (ip->opcode == Op_breakpoint && ip->source_line == lineno) { + b = ip->break_pt; + if (++bp_found == 1) + fprintf(out_fp, _("Deleted breakpoint %d"), b->number); + else + fprintf(out_fp, ", %d", b->number); + delete_breakpoint(b); + } + if (ip == (rp + 1)->lasti) + break; + } + } + + if (bp_found == 0) + fprintf(out_fp, _("No breakpoint at file `%s', line #%d\n"), + src, (int) lineno); + else + fprintf(out_fp, "\n"); + return false; +} + +/* enable_breakpoint --- enable a breakpoint and set its disposition */ + +static inline void +enable_breakpoint(BREAKPOINT *b, short disp) +{ + b->flags &= ~(BP_ENABLE_ONCE|BP_TEMP); + b->flags |= BP_ENABLE; + if (disp) + b->flags |= disp; +} + +/* do_enable_breakpoint --- enable command */ + +int +do_enable_breakpoint(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) +{ + BREAKPOINT *b; + short disp = 0; + + if (arg != NULL && arg->type == D_argument) { + if (arg->a_argument == A_DEL) /* del */ + disp = BP_TEMP; + else /* once */ + disp = BP_ENABLE_ONCE; + arg = arg->next; + } + + if (arg == NULL) { /* enable [once|del] */ + for (b = breakpoints.next; b != &breakpoints; b = b->next) + enable_breakpoint(b, disp); + } + + for (; arg != NULL; arg = arg->next) { + if (arg->type == D_range) { + long i, j; + + i = arg->a_int; + arg = arg->next; + j = arg->a_int; + if (j > breakpoints.number) + j = breakpoints.number; + for (; i <= j; i++) { + if ((b = find_breakpoint(i)) != NULL) + enable_breakpoint(b, disp); + } + } else { + assert(arg->type == D_int); + if ((b = find_breakpoint(arg->a_int)) == NULL) + d_error(_("invalid breakpoint number")); + else + enable_breakpoint(b, disp); + } + } + return false; +} + +/* do_delete_breakpoint --- delete command */ + +int +do_delete_breakpoint(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) +{ + if (arg == NULL) { + bool delete_all = true; + 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); + } + } + + for (; arg != NULL; arg = arg->next) { + BREAKPOINT *b; + if (arg->type == D_range) { + long i, j; + + i = arg->a_int; + arg = arg->next; + j = arg->a_int; + if (j > breakpoints.number) + j = breakpoints.number; + for (; i <= j; i++) { + if ((b = find_breakpoint(i)) != NULL) + delete_breakpoint(b); + } + } else { + if ((b = find_breakpoint(arg->a_int)) == NULL) + d_error(_("invalid breakpoint number")); + else + delete_breakpoint(b); + } + } + return false; +} + +/* do_ignore_breakpoint --- ignore command */ + +int +do_ignore_breakpoint(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) +{ + BREAKPOINT *b; + + if (arg == NULL || arg->type != D_int + || arg->next == NULL || arg->next->type != D_int) + return false; + + if ((b = find_breakpoint(arg->a_int)) == NULL) + d_error(_("invalid breakpoint number")); + else { + b->ignore_count = arg->next->a_int; + if (b->ignore_count > 0) { + b->flags |= BP_IGNORE; + fprintf(out_fp, _("Will ignore next %ld crossing(s) of breakpoint %d.\n"), + b->ignore_count, b->number); + } else { + b->flags &= ~BP_IGNORE; + fprintf(out_fp, _("Will stop next time breakpoint %d is reached.\n"), + b->number); + } + } + return false; +} + +/* do_disable_breakpoint --- disable command */ + +int +do_disable_breakpoint(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) +{ + BREAKPOINT *b; + + if (arg == NULL) { + /* disable all */ + for (b = breakpoints.next; b != &breakpoints; b = b->next) + b->flags &= ~BP_ENABLE; + } + + for (; arg != NULL; arg = arg->next) { + if (arg->type == D_range) { + long i, j; + + i = arg->a_int; + arg = arg->next; + j = arg->a_int; + if (j > breakpoints.number) + j = breakpoints.number; + for (; i <= j; i++) + if ((b = find_breakpoint(i)) != NULL) + b->flags &= ~BP_ENABLE; + } else { + if ((b = find_breakpoint(arg->a_int)) == NULL) + d_error(_("invalid breakpoint number")); + else + b->flags &= ~BP_ENABLE; + } + } + return false; +} + +#ifdef HAVE_LIBREADLINE + +/* get_function --- function definition in current context */ + +NODE * +get_function() +{ + NODE *func; + + if (! prog_running) + return NULL; + func = find_frame(cur_frame)->func_node; + return func; +} + +/* initialize_readline --- initialize readline */ + +static void +initialize_readline() +{ + /* tell readline which stream to use for output, + * default input stream is stdin. + */ + rl_outstream = out_fp; + + /* allow conditional parsing of the ~/.inputrc file. */ + rl_readline_name = "gawk"; + + /* our completion function. */ + rl_attempted_completion_function = command_completion; + + read_a_line = readline; +} +#else +#define initialize_readline() /* nothing */ +#endif + + +/* init_debug --- register debugger exec hooks */ + +void +init_debug() +{ + register_exec_hook(debug_pre_execute, debug_post_execute); +} + + +/* debug_prog --- debugger entry point */ + +int +debug_prog(INSTRUCTION *pc) +{ + char *run; + + input_fd = fileno(stdin); + out_fp = stdout; + if (os_isatty(input_fd)) + input_from_tty = true; + if (input_fd == 0 && input_from_tty) + initialize_readline(); + + if (! read_a_line) + read_a_line = g_readline; + + push_cmd_src(input_fd, input_from_tty, read_a_line, 0, 0, EXIT_FATAL); + + setbuf(out_fp, (char *) NULL); + for (cur_srcfile = srcfiles->prev; cur_srcfile != srcfiles; + cur_srcfile = cur_srcfile->prev) { + if (cur_srcfile->stype == SRC_FILE + || cur_srcfile->stype == SRC_INC) + break; + } + + if (cur_srcfile == srcfiles) { + fprintf(out_fp, _("Can only debug programs provided with the `-f' option.\n")); + exit(EXIT_FAILURE); + } + + dgawk_prompt = estrdup(DEFAULT_PROMPT, strlen(DEFAULT_PROMPT)); + dbg_prompt = dgawk_prompt; + + memset(&stop, 0, sizeof(stop)); + stop.command = D_illegal; + + if ((run = getenv("DGAWK_RESTART")) != NULL) { + /* We are restarting; restore state (breakpoints, history etc.) + * passed as environment variables and optionally execute the run command. + */ + unserialize_list(BREAK); + unserialize_list(WATCH); + unserialize_list(DISPLAY); + unserialize_list(HISTORY); + unserialize_list(OPTION); + unsetenv("DGAWK_RESTART"); + fprintf(out_fp, "Restarting ...\n"); + if (strcasecmp(run, "true") == 0) + (void) do_run(NULL, 0); + + } else if (command_file != NULL) { + /* run commands from a file (--debug=file or -D file) */ + int fd; + fd = open_readfd(command_file); + if (fd == INVALID_HANDLE) { + fprintf(stderr, _("can't open source file `%s' for reading (%s)"), + command_file, strerror(errno)); + exit(EXIT_FAILURE); + } + push_cmd_src(fd, false, g_readline, close, 0, EXIT_FAILURE); + cmd_src->str = estrdup(command_file, strlen(command_file)); + + } else { + int fd; + +#ifdef HAVE_LIBREADLINE + (void) read_history(history_file); + sess_history_base = history_length; +#endif + + /* read saved options */ + fd = open_readfd(options_file); + if (fd > INVALID_HANDLE) + push_cmd_src(fd, false, g_readline, close, 0, EXIT_SUCCESS); + } + + /* start the command interpreter */ + read_command(); /* yyparse */ + return EXIT_SUCCESS; +} + + +/* N.B.: ignore breakpoints and watchpoints for return command */ + +/* check_watchpoint --- check if any watchpoint triggered */ + +static int +check_watchpoint() +{ + struct list_item *w; + + if (stop.command == D_return) + return false; + for (w = watch_list.prev; w != &watch_list; w = w->prev) { + int wnum = watchpoint_triggered(w); + if (wnum > 0) { + stop.watch_point = wnum; + stop.print_frame = true; + return true; + } + } + return false; +} + +/* check_breakpoint --- check if breakpoint triggered */ + +static int +check_breakpoint(INSTRUCTION **pi) +{ + INSTRUCTION *pc; + + pc = *pi; + if (stop.command == D_return) + return false; + if (pc->opcode == Op_breakpoint) { + int bnum; + *pi = pc->nexti; /* skip past the breakpoint instruction; + * interpreter doesn't process Op_breakpoint. + */ + bnum = breakpoint_triggered(pc->break_pt); + if (bnum > 0) { + stop.break_point = bnum; + stop.print_frame = true; + return true; + } + } + return false; +} + +/* restart --- restart the debugger */ + +static void +restart(bool run) +{ + /* save state in the environment after serialization */ + 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); + + /* close all open files */ + close_all(); + + /* start a new process replacing the current process */ +#ifdef __MINGW32__ + execvp(d_argv[0], (const char * const *)d_argv); +#else + execvp(d_argv[0], d_argv); +#endif + + /* execvp failed !!! */ + fprintf(out_fp, _("Failed to restart debugger")); + exit(EXIT_FAILURE); +} + +/* do_run --- run command */ + +int +do_run(CMDARG *arg ATTRIBUTE_UNUSED, int cmd ATTRIBUTE_UNUSED) +{ + if (prog_running) { + if (! input_from_tty) + need_restart = true; /* handled later */ + else { + need_restart = prompt_yes_no( + _("Program already running. Restart from beginning (y/n)? "), + _("y")[0], false, out_fp); + + if (! need_restart) { + fprintf(out_fp, _("Program not restarted\n")); + return false; + } + } + } + + if (need_restart) { + /* avoid endless cycles of restarting */ + if (command_file != NULL) { + /* input_from_tty = false */ + fprintf(stderr, _("error: cannot restart, operation not allowed\n")); + exit(EXIT_FAILURE); + } + + if (cmd_src->cmd == D_source) { + /* input_from_tty = false */ + fprintf(out_fp, _("error (%s): cannot restart, ignoring rest of the commands\n"), cmd_src->str); + pop_cmd_src(); + return false; + } + + restart(true); /* does not return */ + } + + fprintf(out_fp, _("Starting program: \n")); + + prog_running = true; + fatal_tag_valid = 1; + if (setjmp(fatal_tag) == 0) + (void) interpret(code_block); + + fatal_tag_valid = 0; + prog_running = false; + fprintf(out_fp, (! exiting && exit_val != EXIT_SUCCESS) + ? _("Program exited abnormally with exit value: %d\n") + : _("Program exited normally with exit value: %d\n"), + exit_val); + need_restart = true; + return false; +} + +/* do_quit --- quit command */ + +int +do_quit(CMDARG *arg ATTRIBUTE_UNUSED, int cmd ATTRIBUTE_UNUSED) +{ + bool terminate = true; + if (prog_running) + terminate = prompt_yes_no( + _("The program is running. Exit anyway (y/n)? "), + _("y")[0], true, out_fp); + if (terminate) { + close_all(); + do_trace = false; /* don't save 'trace on' */ + +#ifdef HAVE_LIBREADLINE + if (do_save_history && input_from_tty) { + int ret; + ret = write_history(history_file); + if (ret == 0 && history_length > history_size) + (void) history_truncate_file(history_file, history_size); + } +#endif + if (do_save_options && input_from_tty) + save_options(options_file); + + exit(exit_val); + } + return false; +} + +/* do_continue --- continue command */ + +int +do_continue(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) +{ + BREAKPOINT *b; + + CHECK_PROG_RUNNING(); + if (! arg || arg->type != D_int) + return true; + + /* arg is breakpoint ignore count if stopped at a breakpoint */ + if (! stop.break_point) { + fprintf(out_fp, _("Not stopped at any breakpoint; argument ignored.\n")); + return true; + } + b = find_breakpoint(stop.break_point); + if (b == NULL) { + d_error(_("invalid breakpoint number %d."), stop.break_point); + return false; + } + b->flags |= BP_IGNORE; + b->ignore_count = arg->a_int; + fprintf(out_fp, _("Will ignore next %ld crossings of breakpoint %d.\n"), + b->ignore_count, stop.break_point); + return true; +} + +/* next_step --- common code for next and step commands */ + +static int +next_step(CMDARG *arg, int cmd) +{ + CHECK_PROG_RUNNING(); + if (arg != NULL && arg->type == D_int) + stop.repeat_count = arg->a_int; + else + stop.repeat_count = 1; + stop.command = cmd; + return true; +} + +/* check_step --- process step command, return true if stopping */ + +static int +check_step(INSTRUCTION **pi) +{ + if (fcall_count != stop.fcall_count) { + stop.fcall_count = fcall_count; + stop.sourceline = sourceline; + stop.source = source; + stop.print_frame = true; + return (--stop.repeat_count == 0); + } + + if (source != stop.source) { + stop.source = source; + stop.sourceline = sourceline; + return (--stop.repeat_count == 0); + } + + if (sourceline != stop.sourceline) { + stop.sourceline = sourceline; + return (--stop.repeat_count == 0); + } + return false; +} + +/* do_step -- process step command, return true if stopping */ + +int +do_step(CMDARG *arg, int cmd) +{ + int ret; + ret = next_step(arg, cmd); + if (ret) { + stop.fcall_count = fcall_count; + stop.source = source; + stop.sourceline = sourceline; + stop.check_func = check_step; + } + return ret; +} + +/* do_stepi -- process stepi command, return true if stopping */ + +static int +check_stepi(INSTRUCTION **pi) +{ + return (--stop.repeat_count == 0); +} + +/* do_stepi -- stepi command */ + +int +do_stepi(CMDARG *arg, int cmd) +{ + int ret; + ret = next_step(arg, cmd); + if (ret) + stop.check_func = check_stepi; + return ret; +} + + +/* check_next -- process next command returning true if stopping */ + +static int +check_next(INSTRUCTION **pi) +{ + /* make sure not to step inside function calls */ + + if (fcall_count < stop.fcall_count) { + stop.fcall_count = fcall_count; + stop.sourceline = sourceline; + stop.source = source; + stop.print_frame = true; + return (--stop.repeat_count == 0); + } + + if (fcall_count == stop.fcall_count) { + if (source != stop.source) { + stop.source = source; + stop.sourceline = sourceline; + return (--stop.repeat_count == 0); + } + if (sourceline != stop.sourceline) { + stop.sourceline = sourceline; + return (--stop.repeat_count == 0); + } + } + +#if 0 + /* redundant ? */ + if (fcall_count > stop.fcall_count) { + stop.source = source; + stop.sourceline = sourceline; + } +#endif + + return false; +} + +/* do_next -- next command */ + +int +do_next(CMDARG *arg, int cmd) +{ + int ret; + + ret = next_step(arg, cmd); + if (ret) { + stop.source = source; + stop.sourceline = sourceline; + stop.fcall_count = fcall_count; + stop.check_func = check_next; + } + return ret; +} + +/* check_nexti --- process nexti command, returns true if stopping */ + +static int +check_nexti(INSTRUCTION **pi) +{ + /* make sure not to step inside function calls */ + + if (fcall_count < stop.fcall_count) { + stop.print_frame = true; + stop.fcall_count = fcall_count; + } + return (fcall_count == stop.fcall_count + && --stop.repeat_count == 0); +} + +/* do_nexti -- nexti command */ + +int +do_nexti(CMDARG *arg, int cmd) +{ + int ret; + + ret = next_step(arg, cmd); + if (ret) { + stop.fcall_count = fcall_count; + stop.check_func = check_nexti; + } + return ret; +} + +/* check_finish --- process finish command, returns true if stopping */ + +static int +check_finish(INSTRUCTION **pi) +{ + if (fcall_count == stop.fcall_count) { + stop.print_frame = true; + return true; + } + return false; +} + +/* do_finish --- finish command */ + +int +do_finish(CMDARG *arg ATTRIBUTE_UNUSED, int cmd) +{ + CHECK_PROG_RUNNING(); + if (cur_frame == fcall_count) { + fprintf(out_fp, + _("'finish' not meaningful in the outermost frame main()\n")); + return false; + } + stop.fcall_count = fcall_count - cur_frame - 1; + assert(stop.fcall_count >= 0); + fprintf(out_fp, _("Run till return from ")); + print_numbered_frame(cur_frame); + stop.check_func = check_finish; + stop.command = cmd; + stop.print_ret = true; + return true; +} + +/* check_return --- process return, returns true if stopping */ + +static int +check_return(INSTRUCTION **pi) +{ + assert(fcall_count >= stop.fcall_count); + + if (fcall_count == stop.fcall_count) { + stop.print_frame = true; + return true; + } + + if (fcall_count > stop.fcall_count) { /* innermost frame just returned */ + /* force this one to return too */ + NODE *func; + + func = find_frame(cur_frame)->func_node; + assert(func != NULL); + *pi = (func->code_ptr + 1)->lasti; + /* assert((*pi)->opcode == Op_K_return); */ + } + + return false; +} + +/* do_return --- return command */ + +int +do_return(CMDARG *arg, int cmd) +{ + NODE *func, *n; + + CHECK_PROG_RUNNING(); + func = find_frame(cur_frame)->func_node; + if (func == NULL) { + fprintf(out_fp, _("'return' not meaningful in the outermost frame main()\n")); + return false; + } + + stop.fcall_count = fcall_count - cur_frame - 1; + assert(stop.fcall_count >= 0); + stop.pc = (func->code_ptr + 1)->lasti; + assert(stop.pc->opcode == Op_K_return); + stop.command = cmd; + + stop.check_func = check_return; + + if (arg != NULL && arg->type == D_node) /* optional return value */ + n = dupnode(arg->a_node); + else + n = dupnode(Nnull_string); + PUSH(n); + + return true; +} + +/* check_until --- process until, returns true if stopping */ + +int +check_until(INSTRUCTION **pi) +{ + if (fcall_count < stop.fcall_count) { /* current stack frame returned */ + stop.print_frame = true; + return true; + } else if (fcall_count == stop.fcall_count) { + if (stop.pc && *pi == stop.pc) /* until location */ + return true; + if (stop.sourceline > 0 /* until */ + && source == stop.source + && sourceline > stop.sourceline) + return true; + } + return false; +} + +/* do_until --- until command */ + +int +do_until(CMDARG *arg, int cmd) +{ + SRCFILE *s = cur_srcfile; + char *src = cur_srcfile->src; + int lineno; + INSTRUCTION *rp, *ip; + NODE *func; + + CHECK_PROG_RUNNING(); + stop.pc = NULL; + stop.sourceline = 0; + + if (arg == NULL) { /* until without argument */ + + /* GDB doc.: continue running until a source line past the current line, + * in the current stack frame, is reached. Is used to avoid single + * stepping through a loop more than once. ... + * This means that when you reach the end of a loop after single + * stepping though it, until makes your program continue execution + * until it exits the loop. In contrast, a next command at the end + * of a loop simply steps back to the beginning of the loop, which + * forces you to step through the next iteration. + */ + + stop.source = source; + stop.sourceline = sourceline; + stop.fcall_count = fcall_count - cur_frame; + stop.check_func = check_until; + stop.command = cmd; + return true; + } + + /* GDB: until location - continue running program until + * either the specified location is reached, or the + * current stack frame returns. + */ + + switch (arg->type) { + case D_string: /* until filename : lineno|function */ + s = source_find(arg->a_string); + arg = arg->next; + if (s == NULL || arg == NULL + || (arg->type != D_int && arg->type != D_func)) + return false; + src = s->src; + if (arg->type == D_func) + goto func; + /* else + fall through */ + case D_int: /* until lineno */ + lineno = arg->a_int; + if (lineno <= 0 || lineno > s->srclines) { + d_error(_("line number %d in file `%s' out of range"), + lineno, src); + return false; + } + break; + + case D_func: /* until function */ +func: + func = arg->a_node; + rp = func->code_ptr; + for (ip = rp->nexti; ip; ip = ip->nexti) { + if (ip->opcode != Op_breakpoint && ip->source_line > 0) { + stop.pc = ip; + stop.fcall_count = fcall_count - cur_frame; + stop.check_func = check_until; + stop.command = cmd; + return true; + } + } + fprintf(out_fp, _("Can't find specified location in function `%s'\n"), + func->vname); + /* fall through */ + default: + return false; + } + + if ((rp = find_rule(src, lineno)) == NULL) { + d_error(_("invalid source line %d in file `%s'"), lineno, src); + return false; + } + + for (ip = rp->nexti; ip; ip = ip->nexti) { + if (ip->opcode != Op_breakpoint && ip->source_line >= lineno) { + stop.pc = ip; + stop.fcall_count = fcall_count - cur_frame; + stop.check_func = check_until; + stop.command = cmd; + return true; + } + if (ip == (rp + 1)->lasti) + break; + } + fprintf(out_fp, _("Can't find specified location %d in file `%s'\n"), + lineno, src); + return false; +} + +/* print_watch_item --- print watched item name, old and current values */ + +static void +print_watch_item(struct list_item *w) +{ + NODE *symbol, *sub; + int i; + + symbol = w->symbol; + if (IS_SUBSCRIPT(w)) { + fprintf(out_fp, "%s", w->sname); + for (i = 0; i < w->num_subs; i++) { + sub = w->subs[i]; + fprintf(out_fp, "[\"%.*s\"]", (int) sub->stlen, sub->stptr); + } + fprintf(out_fp, "\n"); + } else if (IS_FIELD(w)) + fprintf(out_fp, "$%ld\n", get_number_si(symbol)); + else + fprintf(out_fp, "%s\n", w->sname); + + +#define print_value(X, S, V) \ +if (X) \ + fprintf(out_fp, "array, %ld elements\n", w->S); \ +else if (! w->V) \ + fprintf(out_fp, IS_SUBSCRIPT(w) ? \ + _("element not in array\n") : _("untyped variable\n")); \ +else \ + valinfo(w->V, fprintf, out_fp); + + fprintf(out_fp, " Old value: "); + print_value((w->flags & OLD_IS_ARRAY) != 0, old_size, old_value); + fprintf(out_fp, " New value: "); + print_value((w->flags & CUR_IS_ARRAY) != 0, cur_size, cur_value); + +#undef print_value +} + +/* next_command --- (optionally) print stoppage location and reason; + * also fetch next debug command from the user. + */ + +static void +next_command() +{ + static int last_rule = 0; + struct list_item *d = NULL, *w = NULL; + BREAKPOINT *b = NULL; + SRCFILE *s; + + if (source == NULL) { + stop.command = D_illegal; + stop.check_func = NULL; + return; + } + + if (stop.break_point) { + b = find_breakpoint(stop.break_point); + assert(b != NULL); + if (b->silent) + goto no_output; + } else if (stop.watch_point) { + w = find_item(&watch_list, stop.watch_point); + if (w->silent) + goto no_output; + } + + if (cur_rule != last_rule) { + fprintf(out_fp, _("Stopping in %s ...\n"), ruletab[cur_rule]); + last_rule = cur_rule; + } + + if (b != NULL) + fprintf(out_fp, "Breakpoint %d, ", b->number); + else if (w != NULL) { + fprintf(out_fp, "Watchpoint %d: ", w->number); + print_watch_item(w); + } + + /* 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); + + /* automatic display of variables */ + for (d = display_list.prev; d != &display_list; d = d->prev) + display(d); + +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 */ + s = source_find(source); + if (cur_srcfile != s) { + if (cur_srcfile->fd != INVALID_HANDLE) { + close(cur_srcfile->fd); + cur_srcfile->fd = INVALID_HANDLE; + } + cur_srcfile = s; + } + + stop.command = D_illegal; + stop.check_func = NULL; + + if (b != NULL) { + int ret; + ret = execute_commands(&b->commands); + if ((b->flags & BP_TEMP) != 0) + delete_breakpoint(b); + if (ret) /* resume execution */ + return; + } else if (w != NULL && execute_commands(&w->commands)) + return; + + read_command(); /* zzparse */ +} + +/* debug_post_execute --- post_hook in the interpreter */ + +static void +debug_post_execute(INSTRUCTION *pc) +{ + if (! in_main_context()) + return; + + switch (pc->opcode) { + case Op_K_next: + case Op_K_nextfile: + case Op_K_exit: + if (stop.command == D_finish) { + /* cancel finish command */ + stop.print_ret = false; + stop.print_frame = false; + stop.command = D_illegal; + stop.check_func = NULL; + fprintf(out_fp, _("'finish' not meaningful with non-local jump '%s'\n"), + 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)); + } + break; + + case Op_K_return: + if (stop.command == D_finish + && fcall_count == stop.fcall_count + && stop.print_ret + ) { + NODE *r; + /* print the returned value before it disappears. */ + r = TOP(); + fprintf(out_fp, "Returned value = "); + valinfo(r, fprintf, out_fp); + stop.print_ret = false; + } + break; + + case Op_newfile: + case Op_get_record: + return; + + default: + break; + } +} + +/* debug_pre_execute --- pre_hook, called by the interpreter before execution; + * checks if execution needs to be suspended and control + * transferred to the debugger. + */ + +static int +debug_pre_execute(INSTRUCTION **pi) +{ + static bool cant_stop = false; + NODE *m; + + if (! in_main_context()) + return pre_execute_code(pi); + + cur_pc = *pi; + stop.break_point = 0; + stop.watch_point = 0; + cur_frame = 0; + + if (do_trace + && cur_pc->opcode != Op_breakpoint + && stop.command != D_return + ) + print_instruction(cur_pc, fprintf, out_fp, false); + +/* N.B.: For Op_field_spec_lhs must execute instructions upto Op_field_assign + * as a group before stopping. Otherwise, watch/print of field variables + * 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; + break; + + case Op_field_assign: + cant_stop = false; + return true; /* may stop at next instruction */ + + case Op_push_lhs: + m = cur_pc->memory; + if (m->type == Node_var && m->var_assign) + cant_stop = true; + break; + + case Op_arrayfor_incr: /* can have special var as array variable !!! */ + m = cur_pc->array_var; + if (m->type == Node_var && m->var_assign) + cant_stop = true; + break; + + case Op_var_assign: + cant_stop = false; + return true; /* may stop at next instruction */ + + case Op_rule: + cur_rule = cur_pc->in_rule; + return true; + + case Op_func: + case Op_var_update: + return true; + + case Op_breakpoint: + break; /* processed later in check_breakpoint() */ + + default: + if (cur_pc->source_line <= 0) + return true; + break; + } + + if (cant_stop) + return true; + + assert(sourceline > 0); + + /* + * 11/2015: This used to check breakpoints first, but that could + * produce strange behavior, where a watchpoint doesn't print until + * some time after the data changed. This reworks things so that + * watchpoints are checked first. It's a bit of a hack, but + * the behavior for the user is more logical. + */ + if (check_watchpoint()) { + next_command(); /* return to debugger interface */ + if (stop.command == D_return) + *pi = stop.pc; /* jump to this instruction */ + else if (cur_pc->opcode == Op_breakpoint) + cur_pc = cur_pc->nexti; /* skip past the breakpoint instruction */ + } else if (check_breakpoint(pi) + || (stop.check_func && stop.check_func(pi))) { + next_command(); /* return to debugger interface */ + if (stop.command == D_return) + *pi = stop.pc; /* jump to this instruction */ + } + + /* if cur_pc == *pi, interpreter executes cur_pc; + * Otherwise, jumps to instruction *pi. + */ + return (cur_pc == *pi); +} + +/* print_memory --- print a scalar value */ + +static void +print_memory(NODE *m, NODE *func, Func_print print_func, FILE *fp) +{ + switch (m->type) { + case Node_val: + if (m == Nnull_string) + print_func(fp, "Nnull_string"); + else if ((m->flags & NUMBER) != 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 & STRING) != 0) + pp_string_fp(print_func, fp, m->stptr, m->stlen, '"', false); + 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; + + case Node_regex: + pp_string_fp(print_func, fp, m->re_exp->stptr, m->re_exp->stlen, '/', false); + break; + + case Node_dynregex: + break; + + case Node_param_list: + assert(func != NULL); + print_func(fp, "%s", func->fparms[m->param_cnt].param); + break; + + case Node_var: + case Node_var_new: + case Node_var_array: + print_func(fp, "%s", m->vname); + break; + + default: + print_func(fp, "?"); /* can't happen */ + } +} + +/* print_instruction --- print a bytecode */ + +static void +print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump) +{ + int pcount = 0; + static NODE *func = NULL; + static int noffset = 0; + + if (noffset == 0) { + static char buf[50]; + /* offset for 2nd to last lines in a multi-line output */ + noffset = sprintf(buf, "[ :%p] %-20.20s: ", (void *) pc, + opcode2str(pc->opcode)); + } + + if (pc->opcode == Op_func) { + func = pc->func_body; + pcount = func->param_cnt; + if (in_dump) { + int j; + print_func(fp, "\n\t# Function: %s (", func->vname); + for (j = 0; j < pcount; j++) { + print_func(fp, "%s", func->fparms[j].param); + if (j < pcount - 1) + print_func(fp, ", "); + } + print_func(fp, ")\n\n"); + } + } else if (pc->opcode == Op_rule) { + if (in_dump) + print_func(fp, "\n\t# %s\n\n", ruletab[pc->in_rule]); + } + + if (pc->opcode == Op_newfile) + print_func(fp, "\n"); + + if (pc->source_line <= 0) + print_func(fp, "[ :%p] %-20.20s: ", pc, opcode2str(pc->opcode)); + else + print_func(fp, "[%6d:%p] %-20.20s: ", + pc->source_line, pc, opcode2str(pc->opcode)); + + if (prog_running && ! in_dump) { + /* find Node_func if in function */ + 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", + pc->branch_if, pc->branch_else, pc->branch_else->lasti); + break; + + case Op_K_else: + print_func(fp, "[branch_end = %p]\n", pc->branch_end); + break; + + case Op_K_while: + print_func(fp, "[while_body = %p] [target_break = %p]\n", (pc+1)->while_body, pc->target_break); + break; + + case Op_K_do: + print_func(fp, "[doloop_cond = %p] [target_break = %p]\n", (pc+1)->doloop_cond, pc->target_break); + break; + + case Op_K_for: + print_func(fp, "[forloop_cond = %p] ", (pc+1)->forloop_cond); + /* fall through */ + case Op_K_arrayfor: + print_func(fp, "[forloop_body = %p] ", (pc+1)->forloop_body); + print_func(fp, "[target_break = %p] [target_continue = %p]\n", pc->target_break, pc->target_continue); + break; + + case Op_K_switch: + print_func(fp, "[switch_start = %p] [switch_end = %p]\n", (pc+1)->switch_start, (pc+1)->switch_end); + break; + + case Op_K_default: + print_func(fp, "[stmt_start = %p] [stmt_end = %p]\n", pc->stmt_start, pc->stmt_end); + break; + + case Op_var_update: + print_func(fp, "[update_%s()]\n", get_spec_varname(pc->update_var)); + break; + + case Op_var_assign: + print_func(fp, "[set_%s()]", get_spec_varname(pc->assign_var)); + if (pc->assign_ctxt != 0) + print_func(fp, " [assign_ctxt = %s]", opcode2str(pc->assign_ctxt)); + print_func(fp, "\n"); + break; + + case Op_field_assign: + print_func(fp, "[%s]\n", pc->field_assign == reset_record ? + "reset_record()" : "invalidate_field0()"); + break; + + case Op_field_spec_lhs: + print_func(fp, "[target_assign = %p] [do_reference = %s]\n", + pc->target_assign, pc->do_reference ? "true" : "false"); + break; + + case Op_func: + print_func(fp, "[param_cnt = %d] [source_file = %s]\n", pcount, + pc->source_file ? pc->source_file : "cmd. line"); + break; + + case Op_K_getline_redir: + print_func(fp, "[into_var = %s] [redir_type = \"%s\"]\n", + pc->into_var ? "true" : "false", + redir2str(pc->redir_type)); + break; + + case Op_K_getline: + print_func(fp, "[into_var = %s]\n", pc->into_var ? "true" : "false"); + print_func(fp, "%*s[target_beginfile = %p] [target_endfile = %p]\n", + noffset, "", + (pc + 1)->target_beginfile, (pc + 1)->target_endfile); + break; + + case Op_K_print_rec: + print_func(fp, "[redir_type = \"%s\"]\n", redir2str(pc->redir_type)); + break; + + case Op_K_print: + case Op_K_printf: + print_func(fp, "[expr_count = %ld] [redir_type = \"%s\"]\n", + pc->expr_count, redir2str(pc->redir_type)); + break; + + case Op_indirect_func_call: + case Op_func_call: + print_func(fp, "[func_name = %s] [arg_count = %ld]\n", + pc->func_name, (pc + 1)->expr_count); + break; + + case Op_K_nextfile: + print_func(fp, "[target_newfile = %p] [target_endfile = %p]\n", + pc->target_newfile, pc->target_endfile); + break; + + case Op_newfile: + print_func(fp, "[target_jmp = %p] [target_endfile = %p]\n", + pc->target_jmp, pc->target_endfile); + print_func(fp, "%*s[target_get_record = %p]\n", + noffset, "", (pc + 1)->target_get_record); + break; + + case Op_get_record: + print_func(fp, "[target_newfile = %p]\n", pc->target_newfile); + break; + + case Op_jmp: + case Op_jmp_false: + case Op_jmp_true: + case Op_and: + case Op_or: + case Op_K_next: + case Op_arrayfor_init: + case Op_K_break: + case Op_K_continue: + print_func(fp, "[target_jmp = %p]\n", pc->target_jmp); + break; + + case Op_K_exit: + print_func(fp, "[target_end = %p] [target_atexit = %p]\n", + pc->target_end, pc->target_atexit); + break; + + case Op_K_case: + print_func(fp, "[target_jmp = %p] [match_exp = %s]\n", + pc->target_jmp, (pc + 1)->match_exp ? "true" : "false"); + break; + + case Op_arrayfor_incr: + print_func(fp, "[array_var = %s] [target_jmp = %p]\n", + pc->array_var->type == Node_param_list ? + func->fparms[pc->array_var->param_cnt].param : pc->array_var->vname, + pc->target_jmp); + break; + + case Op_line_range: + print_func(fp, "[triggered = %ld] [target_jmp = %p]\n", + pc->triggered, pc->target_jmp); + break; + + case Op_cond_pair: + print_func(fp, "[line_range = %p] [target_jmp = %p]\n", + pc->line_range, pc->target_jmp); + break; + + case Op_sub_builtin: + { + const char *fname = "sub"; + static const struct flagtab values[] = { + { GSUB, "GSUB" }, + { GENSUB, "GENSUB" }, + { LITERAL, "LITERAL" }, + { 0, NULL } + }; + + if ((pc->sub_flags & GSUB) != 0) + fname = "gsub"; + else if ((pc->sub_flags & GENSUB) != 0) + fname = "gensub"; + print_func(fp, "%s [arg_count = %ld] [sub_flags = %s]\n", + fname, pc->expr_count, + genflags2str(pc->sub_flags, values)); + } + break; + + case Op_builtin: + print_func(fp, "%s [arg_count = %ld]\n", getfname(pc->builtin), + pc->expr_count); + break; + + case Op_ext_builtin: + print_func(fp, "%s [arg_count = %ld]\n", (pc + 1)->func_name, + pc->expr_count); + break; + + case Op_subscript: + case Op_sub_array: + print_func(fp, "[sub_count = %ld]\n", pc->sub_count); + break; + + case Op_store_sub: + print_memory(pc->memory, func, print_func, fp); + print_func(fp, " [sub_count = %ld]\n", pc->expr_count); + break; + + case Op_subscript_lhs: + print_func(fp, "[sub_count = %ld] [do_reference = %s]\n", + pc->sub_count, + pc->do_reference ? "true" : "false"); + break; + + case Op_K_delete: + case Op_in_array: + print_func(fp, "[expr_count = %ld]\n", pc->expr_count); + break; + + case Op_concat: + /* 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"); + break; + + case Op_rule: + print_func(fp, "[in_rule = %s] [source_file = %s]\n", + ruletab[pc->in_rule], + pc->source_file ? pc->source_file : "cmd. line"); + break; + + case Op_lint: + { + static const char *const linttypetab[] = { + "LINT_illegal", + "LINT_assign_in_cond", + "LINT_no_effect" + }; + print_func(fp, "[lint_type = %s]\n", linttypetab[pc->lint_type]); + } + break; + + case Op_exec_count: + print_func(fp, "[exec_count = %ld]\n", pc->exec_count); + break; + + case Op_store_var: + print_memory(pc->memory, func, print_func, fp); + if (pc->initval != NULL) { + print_func(fp, " = "); + print_memory(pc->initval, func, print_func, fp); + } + print_func(fp, "\n"); + break; + + case Op_push_lhs: + print_memory(pc->memory, func, print_func, fp); + 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: + case Op_match_rec: + case Op_match: + case Op_nomatch: + case Op_plus_i: + case Op_minus_i: + case Op_times_i: + case Op_exp_i: + case Op_quotient_i: + case Op_mod_i: + case Op_assign_concat: + print_memory(pc->memory, func, print_func, fp); + /* fall through */ + default: + print_func(fp, "\n"); + break; + } +} + +/* do_trace_instruction --- trace command */ + +int +do_trace_instruction(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) +{ + if (arg != NULL && arg->type == D_argument + && arg->a_argument == A_TRACE_ON) + do_trace = true; + else + do_trace = false; + return false; +} + +/* print_code --- print a list of instructions */ + +static int +print_code(INSTRUCTION *pc, void *x) +{ + struct pf_data *data = (struct pf_data *) x; + for (; pc != NULL; pc = pc->nexti) + print_instruction(pc, data->print_func, data->fp, data->defn /* in_dump */); + return 0; +} + +/* do_dump_instructions --- dump command */ + +int +do_dump_instructions(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) +{ + FILE *fp; + NODE **funcs; + + if (arg != NULL && arg->type == D_string) { + /* dump to a file */ + if ((fp = fopen(arg->a_string, "w")) == NULL) { + d_error(_("could not open `%s' for writing (%s)"), + arg->a_string, strerror(errno)); + return false; + } + pf_data.print_func = fprintf; + pf_data.fp = fp; + pf_data.defn = true; /* in_dump = true */ + (void) print_code(code_block, &pf_data); + funcs = function_list(true); + (void) foreach_func(funcs, + (int (*)(INSTRUCTION *, void *)) print_code, + &pf_data); + efree(funcs); + fclose(fp); + return false; + } + + funcs = function_list(true); + initialize_pager(out_fp); + if (setjmp(pager_quit_tag) == 0) { + pf_data.print_func = gprintf; + pf_data.fp = out_fp; + pf_data.defn = true; /* in_dump = true */ + (void) print_code(code_block, &pf_data); + (void) foreach_func(funcs, + (int (*)(INSTRUCTION *, void *)) print_code, + &pf_data); + } + efree(funcs); + return false; +} + +/* do_save --- save command */ + +int +do_save(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) +{ +#if defined(HAVE_LIBREADLINE) && defined(HAVE_HISTORY_LIST) + FILE *fp; + HIST_ENTRY **hist_list; + int i; + + if ((fp = fopen(arg->a_string, "w")) == NULL) { + d_error(_("could not open `%s' for writing (%s)"), + arg->a_string, strerror(errno)); + return false; + } + + hist_list = history_list(); + if (hist_list && history_length > sess_history_base) { + for (i = sess_history_base; hist_list[i] != NULL; i++) { + char *line; + line = hist_list[i]->line; + + /* exclude save commands; + * N.B.: this test may fail if there is another + * command with the same first 2 letters. + */ + + if (strlen(line) > 1 + && strncmp(line, "sa", 2) == 0) + continue; + + fprintf(fp, "%s\n", line); + } + } + fclose(fp); +#endif + return false; +} + +/* do_option --- option command */ + +int +do_option(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) +{ + 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) + fprintf(out_fp, "%s = \"%s\"\n", opt->name, *(opt->str_val)); + else + fprintf(out_fp, "%s = %d\n", opt->name, *(opt->num_val)); + } + return false; + } + + name = arg->a_string; + arg = arg->next; + value = arg ? arg->a_string : NULL; + + for (opt = option_list; opt->name; opt++) { /* linear search */ + if (strcmp(name, opt->name) == 0) + break; + } + if (! opt->name) + return false; + + if (value == NULL) { /* display current setting */ + if (opt->str_val != NULL) + fprintf(out_fp, "%s = \"%s\"\n", opt->name, *(opt->str_val)); + else + fprintf(out_fp, "%s = %d\n", opt->name, *(opt->num_val)); + } else + (*(opt->assign))(value); + return false; +} + + +#ifdef HAVE_LIBREADLINE + +/* initialize_pager --- initialize our idea of the terminal size */ + +void +initialize_pager(FILE *fp) +{ + if (! os_isatty(fileno(fp)) || ! input_from_tty || input_fd != 0) { + screen_width = INT_MAX; + screen_height = INT_MAX; + } else { + /* get the terminal size from readline. */ + + rl_reset_terminal(NULL); /* N.B.: NULL argument means + * "use TERM env variable for terminal name". + */ + rl_get_screen_size(&screen_height, &screen_width); + if (screen_height <= 1) + screen_height = INT_MAX; + if (screen_width <= 1) + screen_width = INT_MAX; + } + pager_lines_printed = 0; +} +#endif + +static void +prompt_continue(FILE *fp) +{ + bool quit_pager = false; + + if (os_isatty(fileno(fp)) && input_fd == 0) + quit_pager = prompt_yes_no( + _("\t------[Enter] to continue or q [Enter] to quit------"), + _("q")[0], false, fp); + if (quit_pager) + longjmp(pager_quit_tag, 1); + pager_lines_printed = 0; +} + +/* gprintf --- like fprintf but allows paging */ + +int +gprintf(FILE *fp, const char *format, ...) +{ + va_list args; + static char *buf = NULL; + static size_t buflen = 0; + static int bl = 0; + char *p, *q; + int nchar; + +#define GPRINTF_BUFSIZ 512 + if (buf == NULL) { + buflen = GPRINTF_BUFSIZ; + emalloc(buf, char *, buflen * sizeof(char), "gprintf"); + } else if (buflen - bl < GPRINTF_BUFSIZ/2) { + buflen += GPRINTF_BUFSIZ; + erealloc(buf, char *, buflen * sizeof(char), "gprintf"); + } +#undef GPRINTF_BUFSIZ + + while (true) { + va_start(args, format); + nchar = vsnprintf(buf + bl, buflen - bl, format, args); + va_end(args); + if (nchar == 0) + return 0; + if (nchar > 0 && nchar < buflen - bl) { + bl += nchar; + if (buf[bl-1] != '\n') /* buffer output until see a newline at end */ + return nchar; + break; + } + + /* enlarge buffer, and try again */ + buflen *= 2; + 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); + + while (sz > 0) { + int cnt; + cnt = sz > screen_width ? screen_width : sz; + + /* do not print partial line before scrolling */ + if (cnt < sz && (pager_lines_printed == (screen_height - 2))) + prompt_continue(fp); + + if (fwrite(p, sizeof(char), cnt, fp) != cnt) + return -1; + if (cnt == sz) + break; + else { + if (++pager_lines_printed == (screen_height - 1)) + prompt_continue(fp); + sz -= screen_width; + assert(sz > 0); + p += cnt; + } + } + + fprintf(fp, "\n"); + if (++pager_lines_printed == (screen_height - 1)) + prompt_continue(fp); + p++; + } + return nchar; +} + + +static int +serialize_subscript(char *buf, int buflen, struct list_item *item) +{ + int bl, nchar, i; + NODE *sub; + + nchar = snprintf(buf, buflen, "%d%c%d%c%s%c%d%c", + item->number, FSEP, D_subscript, FSEP, item->sname, FSEP, + item->num_subs, FSEP); + if (nchar <= 0) + return 0; + else if (nchar >= buflen) /* need larger buffer */ + return 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, + (int) sub->stlen, sub->stptr, FSEP); + if (nchar <= 0) + return 0; + bl += nchar; + if (bl >= buflen) /* need larger buffer */ + return bl; + } + return bl; +} + + + +/* serialize_list--- convert a list structure to a byte stream and + * save in environment. + */ + +static void +serialize_list(int type) +{ + static char *buf = NULL; + static int buflen = 0; + int bl; + BREAKPOINT *b = NULL; + struct list_item *wd = NULL; + HIST_ENTRY **hist_list = NULL; + int hist_index = 0; + struct dbg_option *opt = NULL; + struct commands_item *commands = NULL, *c; + int cnum = 0; + struct condition *cndn = NULL; + void *ptr, *end_ptr; +#ifdef HAVE_LIBREADLINE + HIST_ENTRY *h = NULL; +#endif + + switch (type) { + case BREAK: + end_ptr = (void *) &breakpoints; + ptr = (void *) breakpoints.prev; + break; + case WATCH: + end_ptr = (void *) &watch_list; + ptr = (void *) watch_list.prev; + break; + case DISPLAY: + end_ptr = (void *) &display_list; + ptr = (void *) display_list.prev; + break; + case HISTORY: + hist_list = history_list(); + if (hist_list == NULL) /* empty history list */ + return; + end_ptr = NULL; + ptr = (void *) hist_list[0]; + break; + case OPTION: + { + int n; + n = sizeof(option_list)/sizeof(option_list[0]); + end_ptr = (void *) &option_list[n - 1]; + ptr = (void *) option_list; + } + break; + + default: + return; + } + + if (type != HISTORY && ptr == end_ptr) /* empty list */ + return; + +#define SERIALIZE_BUFSIZ 512 + + if (buf == NULL) { /* first time */ + buflen = SERIALIZE_BUFSIZ; + emalloc(buf, char *, buflen + 1, "serialize"); + } + bl = 0; + + while (ptr != end_ptr) { + int nchar = 0; + if (buflen - bl < SERIALIZE_BUFSIZ/2) { +enlarge_buffer: + buflen *= 2; + erealloc(buf, char *, buflen + 1, "serialize"); + } + +#undef SERIALIZE_BUFSIZ + + /* field seperator is FSEP ('\037'), and the record separator is RSEP ('\036') */ + + switch (type) { + case BREAK: + b = (BREAKPOINT *) ptr; + + /* src source_line flags ignore_count hit_count number; + * commands and condition processed later in the end switch + */ + + nchar = snprintf(buf + bl, buflen - bl, + "%s%c%d%c%d%c%d%c%d%c%d%c", + b->src, FSEP, b->bpi->source_line, FSEP, b->flags, FSEP, + (int) b->ignore_count, FSEP, + (int) b->hit_count, FSEP, b->number, FSEP); + cnum = b->number; + commands = &b->commands; + cndn = &b->cndn; + break; + case DISPLAY: + case WATCH: + wd = (struct list_item *) ptr; + + /* subscript -- number type sname num_subs subs(stlen + stptr) [commands [condition]] + * variable -- number type sname [commands [condition]] + * field -- number type symbol(numbr) [commands [condition]] + */ + + if (IS_PARAM(wd)) /* exclude parameters */ + nchar = 0; + else if (IS_SUBSCRIPT(wd)) + nchar = serialize_subscript(buf + bl, buflen - bl, wd); + else if (IS_FIELD(wd)) + nchar = snprintf(buf + bl, buflen - bl, "%d%c%d%c%d%c", + wd->number, FSEP, D_field, FSEP, (int) get_number_si(wd->symbol), FSEP); + 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; + commands = &wd->commands; + cndn = &wd->cndn; + break; + case HISTORY: +#if defined(HAVE_LIBREADLINE) && defined(HAVE_HISTORY_LIST) + h = (HIST_ENTRY *) ptr; + nchar = strlen(h->line); + if (nchar >= buflen - bl) + goto enlarge_buffer; + strcpy(buf + bl, h->line); +#endif + break; + case OPTION: + opt = (struct dbg_option *) ptr; + if (opt->num_val != NULL) + nchar = snprintf(buf + bl, buflen - bl, + "%s%c%d%c", opt->name, FSEP, *(opt->num_val), FSEP); + else + nchar = snprintf(buf + bl, buflen - bl, + "%s%c%s%c", opt->name, FSEP, *(opt->str_val), FSEP); + break; + default: + break; + } + + if (nchar == 0) /* skip empty history lines etc.*/ + ; + else if (nchar > 0 && nchar < buflen - bl) { + bl += nchar; + buf[bl] = RSEP; /* record */ + buf[++bl] = '\0'; + } else + goto enlarge_buffer; + + switch (type) { + case BREAK: + case WATCH: + /* recreate the `commands' command strings including the `commands' + * and `end' commands; command seperator is '\034'. + * re-parsed in unserialize_list to recover the commands list. + * Alternatively, one could encode(serialize) each command and it's arguments. + */ + + bl--; /* undo RSEP from above */ + + /* compute required room in buffer */ + nchar = 0; + for (c = commands->next; c != commands; c = c->next) { + nchar += (strlen(c->cmd_string) + 1); + if (c->cmd == D_eval) { + CMDARG *a = c->arg; + nchar += (strlen(a->a_string) + 1); /* awk statements */ + nchar += (strlen("end") + 1); + } + } + + if (nchar > 0) { /* non-empty commands list */ + 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_list"); + } + nchar = sprintf(buf + bl, "commands %d", cnum); + bl += nchar; + buf[bl++] = CSEP; + for (c = commands->next; c != commands; c = c->next) { + nchar = strlen(c->cmd_string); + memcpy(buf + bl, c->cmd_string, nchar); + bl += nchar; + buf[bl++] = CSEP; + + if (c->cmd == D_eval) { + CMDARG *a = c->arg; + nchar = strlen(a->a_string); /* statements */ + memcpy(buf + bl, a->a_string, nchar); + bl += nchar; + buf[bl++] = CSEP; + nchar = strlen("end"); /* end of 'eval' */ + memcpy(buf + bl, "end", nchar); + bl += nchar; + buf[bl++] = CSEP; + } + } + nchar = strlen("end"); /* end of 'commands' */ + memcpy(buf + bl, "end", nchar); + bl += nchar; + } + buf[bl++] = FSEP; /* field */ + buf[bl++] = RSEP; /* record */ + buf[bl] = '\0'; + + /* 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_list"); + } + memcpy(buf + bl, cndn->expr, nchar); + bl += nchar; + buf[bl++] = FSEP; /* field */ + buf[bl++] = RSEP; /* record */ + buf[bl] = '\0'; + } + + ptr = (type == BREAK) ? (void *) b->prev : (void *) wd->prev; + break; + case DISPLAY: + ptr = (void *) wd->prev; + break; + case HISTORY: + ptr = (void *) hist_list[++hist_index]; + break; + case OPTION: + ptr = (void *) (++opt); + break; + default: + break; + } + } + + if (bl > 0) /* non-empty list */ + setenv(env_variable[type], buf, 1); +} + + +static void +unserialize_commands(char *str, int str_len) +{ + if (str_len <= 0 || str == NULL) + return; + commands_string = str; + commands_string_len = str_len; + push_cmd_src(INVALID_HANDLE, false, read_commands_string, 0, 0, EXIT_FATAL); + line_sep = CSEP; + read_command(); /* forced to return in do_commands */ + pop_cmd_src(); +} + + +/* 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) +{ + int num, type, i; + struct list_item *l; + NODE *symbol = NULL; + int sub_cnt = 0, cnt; + NODE **subs = NULL; + + /* subscript -- number type sname num_subs subs [commands [condition]] + * variable -- number type sname [commands [condition]] + * field -- number type symbol(numbr) commands [commands [condition]] + */ + + num = strtol(pstr[0], NULL, 0); + type = strtol(pstr[1], NULL, 0); + + if (type == D_field) { + int field_num; + field_num = strtol(pstr[2], NULL, 0); + symbol = make_number((AWKNUM) field_num); + cnt = 3; + } else { + char *name; + name = estrdup(pstr[2], pstr_len[2]); + symbol = find_symbol(name, NULL); + efree(name); + if (symbol == NULL) + return NULL; + cnt = 3; + if (type == D_subscript) { + int sub_len; + sub_cnt = strtol(pstr[3], NULL, 0); + emalloc(subs, NODE **, sub_cnt * sizeof(NODE *), "unserialize_list_item"); + cnt++; + for (i = 0; i < sub_cnt; i++) { + sub_len = strtol(pstr[cnt], NULL, 0); + subs[i] = make_string(pstr[cnt + 1], sub_len); + cnt += 2; + } + } + } + + l = add_item(list, type, symbol, NULL); + if (type == D_subscript) { + l->num_subs = sub_cnt; + l->subs = subs; + } + l->number = num; /* keep same item number across executions */ + + if (list == &watch_list) { + initialize_watch_item(l); + /* unserialize watchpoint `commands' */ + unserialize_commands(pstr[cnt], pstr_len[cnt]); + cnt++; + if (field_cnt > cnt) { + char *expr; + expr = estrdup(pstr[cnt], pstr_len[cnt]); + if (parse_condition(D_watch, l->number, expr) != 0) + efree(expr); + } + if (num > list->number) /* update list number counter */ + list->number = num; + } else + list->number = num; + + return l; +} + +/* unserialize_breakpoint --- create a breakpoint structure from unserialized data */ + +static BREAKPOINT * +unserialize_breakpoint(char **pstr, int *pstr_len, int field_cnt) +{ + char *src; + int lineno; + BREAKPOINT *b = NULL; + INSTRUCTION *rp; + SRCFILE *s; + + /* src source_line flags ignore_count hit_count number commands [condition] */ + + src = estrdup(pstr[0], pstr_len[0]); + s = source_find(src); + efree(src); + if (s == NULL) + return NULL; + src = s->src; + lineno = strtol(pstr[1], NULL, 0); + if (lineno <= 0 || lineno > s->srclines) + return NULL; + rp = find_rule(src, lineno); + if (rp == NULL + || (b = set_breakpoint_at(rp, lineno, true)) == NULL + ) + return NULL; + + b->flags = strtol(pstr[2], NULL, 0); + b->ignore_count = strtol(pstr[3], NULL, 0); + b->hit_count = strtol(pstr[4], NULL, 0); + b->number = strtol(pstr[5], NULL, 0); /* same number as previous run */ + + if (field_cnt > 6) /* unserialize breakpoint `commands' */ + unserialize_commands(pstr[6], pstr_len[6]); + + if (field_cnt > 7) { /* condition expression */ + char *expr; + expr = estrdup(pstr[7], pstr_len[7]); + if (parse_condition(D_break, b->number, expr) != 0) + efree(expr); + } + + if (b->number > watch_list.number) /* watch and break has same number counter */ + watch_list.number = b->number; /* update counter */ + return b; +} + +/* unserialize_option --- set a debugger option from unserialized data. */ + +static struct dbg_option * +unserialize_option(char **pstr, int *pstr_len, int field_cnt ATTRIBUTE_UNUSED) +{ + const struct dbg_option *opt; + + for (opt = option_list; opt->name; opt++) { + if (strncmp(pstr[0], opt->name, pstr_len[0]) == 0) { + char *value; + + value = estrdup(pstr[1], pstr_len[1]); + (*(opt->assign))(value); + efree(value); + return ((struct dbg_option *) opt); + } + } + return NULL; +} + +/* unserialize_list -- reconstruct list from serialized data stored in + * environment variable. + */ + +static void +unserialize_list(int type) +{ + char *val; + char *p, *q, *r, *s; +#define MAX_FIELD 30 + static char *pstr[MAX_FIELD]; + static int pstr_len[MAX_FIELD]; + + val = getenv(env_variable[type]); + if (val == NULL) + return; + + for (p = val; (q = strchr(p, RSEP)) != NULL; p = q + 1) { + int field_cnt = 0; + if (type == HISTORY) { + *q = '\0'; + add_history(p); + *q = RSEP; + continue; + } + + r = p; + while ((s = strchr(r, FSEP)) != NULL && s < q) { + pstr[field_cnt] = r; + pstr_len[field_cnt] = (int) (s - r); + r = s + 1; + field_cnt++; + if (field_cnt == MAX_FIELD) +#ifdef GAWKDEBUG + fatal("Increase MAX_FIELD and recompile.\n"); +#else + return; +#endif + } + + switch (type) { + case BREAK: + (void) unserialize_breakpoint(pstr, pstr_len, field_cnt); + break; + case DISPLAY: + (void) unserialize_list_item(&display_list, pstr, pstr_len, field_cnt); + break; + case WATCH: + (void) unserialize_list_item(&watch_list, pstr, pstr_len, field_cnt); + break; + case OPTION: + (void) unserialize_option(pstr, pstr_len, field_cnt); + break; + case HISTORY: + /* processed at the beginning of for loop */ + break; + default: + break; + } + } + +#ifdef HAVE_LIBREADLINE + if (type == HISTORY) + sess_history_base = history_length; +#endif + + unsetenv(env_variable[type]); +#undef MAX_FIELD +} + +static int +prompt_yes_no(const char *mesg, char res_true, int res_default, FILE *fp) +{ + char *in_str; + int ret = res_default; /* default */ + + if (input_from_tty) { + fprintf(fp, "%s", _(mesg)); + in_str = read_a_line(NULL); + if (in_str == NULL) /* EOF */ + exit(EXIT_FAILURE); + ret = (*in_str == res_true); + efree(in_str); + } + return ret; +} + +/* has_break_or_watch_point --- check if given breakpoint or watchpoint + * number exists. When flag any is true, + * check if any breakpoint/watchpoint + * has been set (ignores num). Returns + * type (breakpoint or watchpoint) or 0. + */ + +int +has_break_or_watch_point(int *pnum, bool any) +{ + BREAKPOINT *b = NULL; + struct list_item *w = NULL; + + if (any) { + if (breakpoints.next != &breakpoints) + b = breakpoints.next; + if (watch_list.next != &watch_list) + w = watch_list.next; + + if (! b && ! w) + return 0; + if (b && ! w) { + *pnum = b->number; + return D_break; + } + if (w && ! b) { + *pnum = w->number; + return D_watch; + } + if (w->number > b->number) { + *pnum = w->number; + return D_watch; + } + *pnum = b->number; + return D_break; + } + + /* 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) + return D_break; + } + for (w = watch_list.next; w != &watch_list; w = w->next) { + if (w->number == *pnum) + return D_watch; + } + + return 0; +} + +/* delete_commands_item --- delete item(command) from `commands' list. */ + +static void +delete_commands_item(struct commands_item *c) +{ + efree(c->cmd_string); + free_cmdarg(c->arg); + c->next->prev = c->prev; + c->prev->next = c->next; + efree(c); +} + +/* do_commands --- commands command */ + +int +do_commands(CMDARG *arg, int cmd) +{ + static BREAKPOINT *b; + 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) + type = has_break_or_watch_point(&num, true); + else { + num = arg->a_int; + type = has_break_or_watch_point(&num, false); + } + b = NULL; + w = NULL; + if (type == D_break) + b = find_breakpoint(num); + else if (type == D_watch) + w = find_item(&watch_list, num); + assert((b != NULL) || (w != NULL)); + commands = (b != NULL) ? &b->commands : &w->commands; + + /* delete current commands */ + for (c = commands->next; c != commands; c = c->next) { + c = c->prev; + delete_commands_item(c->next); + } + return false; + + } else if (cmd == D_end) { + commands = NULL; + if (read_a_line == read_commands_string) /* unserializig commands */ + return true; /* done unserializing, terminate zzparse() */ + return false; + + } else if (cmd == D_silent) { + if (b != NULL) + b->silent = true; + else if (w != NULL) + w->silent = true; + /* we also append silent command to the list for use + * in `info break(watch)', and to simplify + * serialization/unserialization of commands. + */ + } + + assert(commands != NULL); + + emalloc(c, struct commands_item *, sizeof(struct commands_item), "do_commands"); + c->next = NULL; + c->cmd = cmd; + + /* 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); + + /* append to the list */ + c->prev = commands->prev; + c->next = commands; + commands->prev = c; + c->prev->next = c; + return false; +} + +/* execute_commands --- execute breakpoint/watchpoint commands, the first + * command that resumes execution terminates + * commands processing. + */ + +static int +execute_commands(struct commands_item *commands) +{ + struct commands_item *c; + Func_cmd cmd_ptr; + bool ret = false; + + for (c = commands->next; c != commands; c = c->next) { + if (c->cmd == D_silent) + continue; + cmd_ptr = get_command(c->cmd); /* command handler */ + ret = (*cmd_ptr)(c->arg, c->cmd); + if (ret) /* resume execution (continue, next etc.) */ + break; + } + return ret; +} + +/* do_print_f --- printf command */ + +int +do_print_f(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) +{ + int count = 0; + int i; + CMDARG *a; + NODE **tmp; + char *name; + NODE *r; + volatile jmp_buf fatal_tag_stack; + + /* count maximum required size for tmp */ + for (a = arg; a != NULL ; a = a->next) + count++; + emalloc(tmp, NODE **, count * sizeof(NODE *), "do_print_f"); + + for (i = 0, a = arg; a != NULL ; i++, a = a->next) { + switch (a->type) { + case D_variable: + name = a->a_string; + r = find_symbol(name, NULL); + if (r == NULL) + goto done; + if (r->type == Node_var_new) + tmp[i] = Nnull_string; + else if (r->type != Node_var) { + d_error(_("`%s' is not a scalar variable"), name); + goto done; + } else + tmp[i] = r->var_value; + break; + case D_field: + { + long field_num; + r = a->a_node; + field_num = get_number_si(r); + tmp[i] = *get_field(field_num, NULL); + } + break; + case D_subscript: + { + int cnt = a->a_count; + name = a->a_string; + r = find_array(name); + if (r == NULL) + goto done; + + for (; cnt > 0; cnt--) { + NODE *value, *subs; + a = a->next; + subs = a->a_node; + value = in_array(r, subs); + if (cnt == 1) { + 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, (int) subs->stlen, subs->stptr); + goto done; + } else + tmp[i] = value; + } else { + if (value == NULL) { + 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, (int) subs->stlen, subs->stptr); + goto done; + } else { + r = value; + name = r->vname; + } + } + } + } + break; + case D_node: + tmp[i] = a->a_node; + break; + default: + break; + } + } + + tmp[0] = force_string(tmp[0]); + + PUSH_BINDING(fatal_tag_stack, fatal_tag, fatal_tag_valid); + if (setjmp(fatal_tag) == 0) + r = format_tree(tmp[0]->stptr, tmp[0]->stlen, tmp, i); + else { + /* fatal error, restore exit_val of program */ + exit_val = EXIT_SUCCESS; + r = NULL; + } + POP_BINDING(fatal_tag_stack, fatal_tag, fatal_tag_valid); + + if (r != NULL) { + (void) fwrite(r->stptr, sizeof(char), r->stlen, out_fp); + unref(r); + } +done: + efree(tmp); + return false; +} + +/* do_source --- source command */ + +int +do_source(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) +{ + int fd; + char *file = arg->a_string; + + fd = open_readfd(file); + if (fd <= INVALID_HANDLE) { + d_error(_("can't open source file `%s' for reading (%s)"), + file, strerror(errno)); + return false; + } + + push_cmd_src(fd, false, g_readline, close, D_source, EXIT_SUCCESS); + cmd_src->str = estrdup(file, strlen(file)); + return false; +} + +/* open_readfd --- open a file for reading */ + +static int +open_readfd(const char *file) +{ + int fd; + + fd = open(file, O_RDONLY); + if (fd <= INVALID_HANDLE) + return INVALID_HANDLE; + else if (os_isdir(fd)) { + (void) close(fd); + errno = EISDIR; + return INVALID_HANDLE; + } + return fd; +} + +/* find_option --- check if option name is valid */ + +int +find_option(char *name) +{ + const char *p; + int idx; + + for (idx = 0; (p = option_list[idx].name); idx++) { + if (strcmp(p, name) == 0) + return idx; + } + return -1; +} + +/* option_help --- display help text for debugger options */ + +void +option_help() +{ + 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 * +option_generator(const char *text, int state) +{ + static size_t textlen; + static int idx; + const char *name; + + if (! state) { /* first time */ + textlen = strlen(text); + idx = 0; + } + + while ((name = option_list[idx++].name)) { + if (strncmp(name, text, textlen) == 0) + return estrdup(name, strlen(name)); + } + return NULL; +} + +#endif + +/* set_gawk_output --- redirect gawk (normal) output */ + +static void +set_gawk_output(const char *file) +{ + int fd = INVALID_HANDLE; + FILE *fp = NULL; + + if (output_fp != stdout) { + if (output_fp != stderr) { + fclose(output_fp); + efree(output_file); + } + output_fp = stdout; + output_is_tty = os_isatty(fileno(stdout)); + output_file = "/dev/stdout"; + } + + if (file == NULL || file[0] == '\0') + return; + + errno = 0; + if ((fd = os_devopen(file, O_WRONLY)) != INVALID_HANDLE) { + fp = fdopen(fd, "w"); + if (fp == NULL) + close(fd); + + } else if (strncmp(file, "/dev/", 5) == 0) { + char *cp = (char *) file + 5; + + if (strcmp(cp, "stdout") == 0) + return; + if (strcmp(cp, "stderr") == 0) { + output_fp = stderr; + output_file = "/dev/stderr"; + output_is_tty = os_isatty(fileno(stderr)); + return; + } + + if (strncmp(cp, "fd/", 3) == 0) { + cp += 3; + fd = (int) strtoul(cp, NULL, 10); + if (errno == 0 && fd > INVALID_HANDLE) { + fp = fdopen(fd, "w"); + if (fp == NULL) + fd = INVALID_HANDLE; + } else + fd = INVALID_HANDLE; + } else { + /* /dev/ttyN, /dev/pts/N, /dev/null etc. */ + fd = open(file, O_WRONLY); + } + + if (fd > INVALID_HANDLE && fp == NULL) { + fp = fdopen(fd, "w"); + if (fp == NULL) + close(fd); + } + + } else { + /* regular file */ + fp = fopen(file, "w"); + } + + if (fp != NULL) { + output_fp = fp; + output_file = estrdup(file, strlen(file)); + setbuf(fp, (char *) NULL); + output_is_tty = os_isatty(fileno(fp)); + } else { + d_error(_("could not open `%s' for writing (%s)"), + file, + errno != 0 ? strerror(errno) : _("reason unknown")); + fprintf(out_fp, _("sending output to stdout\n")); + } +} + +/* set_prompt --- set debugger prompt */ + +static void +set_prompt(const char *value) +{ + efree(dgawk_prompt); + dgawk_prompt = estrdup(value, strlen(value)); + dbg_prompt = dgawk_prompt; +} + +/* set_option_flag --- convert option string to flag value */ + +static int +set_option_flag(const char *value) +{ + long n; + if (strcmp(value, "on") == 0) + return true; + if (strcmp(value, "off") == 0) + return false; + errno = 0; + n = strtol(value, NULL, 0); + return (errno == 0 && n != 0); +} + +/* set_option_num --- set integer option value from string */ + +static void +set_option_num(int *pnum, const char *value) +{ + long n; + errno = 0; + n = strtol(value, NULL, 0); + if (errno == 0 && n > 0) + *pnum = n; + else + d_error(_("invalid number")); +} + +/* set_listsize --- set list output window size */ + +static void +set_listsize(const char *value) +{ + set_option_num(&list_size, value); +} + +/* set_trace --- set instruction tracing on or off */ + +static void +set_trace(const char *value) +{ + do_trace = set_option_flag(value); +} + +/* set_save_history --- save history on exit */ + +static void +set_save_history(const char *value) +{ + do_save_history = set_option_flag(value); +} + +/* set_save_options --- save options on exit */ + +static void +set_save_options(const char *value) +{ + do_save_options = set_option_flag(value); +} + +/* set_history_size --- maximum entries in history file */ + +static void +set_history_size(const char *value) +{ + set_option_num(&history_size, value); +} + + +/* read_commands_string --- one of the many ways zzlex fetches a line to parse; + * this one is used to parse `commands' string during + * unserialization. + */ + +char * +read_commands_string(const char *prompt ATTRIBUTE_UNUSED) +{ + char *p, *end, *line; + + if (commands_string == NULL) + return NULL; + + p = (char *) commands_string; + end = (char *) commands_string + commands_string_len; + for (; p < end; p++) { + if (*p == line_sep) { + line = estrdup(commands_string, p - commands_string); + commands_string = p + 1; + commands_string_len = end - commands_string; + return line; + } + } + + line = estrdup(commands_string, commands_string_len); + commands_string = NULL; + commands_string_len = 0; + return line; +} + +/* save_options --- save current options to file */ + +static void +save_options(const char *file) +{ + FILE *fp; + const struct dbg_option *opt; + + fp = fopen(file, "w"); + if (fp == NULL) + return; + + for (opt = option_list; opt->name; opt++) { + if (opt->str_val != NULL) + fprintf(fp, "option %s = \"%s\"\n", opt->name, *(opt->str_val)); + else + fprintf(fp, "option %s = %d\n", opt->name, *(opt->num_val)); + } + fclose(fp); + chmod(file, 0600); +} + +/* close_all --- close all open files */ + +static void +close_all() +{ + bool stdio_problem; + struct command_source *cs; + + (void) nextfile(& curfile, true); /* close input data file */ + (void) close_io(& stdio_problem); + if (cur_srcfile->fd != INVALID_HANDLE) { + close(cur_srcfile->fd); + cur_srcfile->fd = INVALID_HANDLE; + } + for (cs = cmd_src; cs != NULL; cs = cs->next) { + if (cs->close_func && cs->fd != INVALID_HANDLE) { + cs->close_func(cs->fd); + cs->fd = INVALID_HANDLE; + } + } + + close_extensions(); + + set_gawk_output(NULL); /* closes output_fp if not stdout */ +} + +/* pre_execute_code --- pre_hook for execute_code, called by pre_execute */ + +static int +pre_execute_code(INSTRUCTION **pi) +{ + INSTRUCTION *ei = *pi; + + switch (ei->opcode) { + case Op_K_exit: + case Op_K_next: + case Op_K_nextfile: + case Op_K_getline: /* getline without redirection */ + d_error(_("`%s' not allowed in current context;" + " statement ignored"), + op2str(ei->opcode)); + *pi = ei->nexti; + break; + case Op_K_return: + if (ei->nexti != NULL) { /* not an implicit return */ + NODE *r; + d_error(_("`return' not allowed in current context;" + " statement ignored")); + /* throw away return value already pushed onto stack */ + r = POP_SCALAR(); + DEREF(r); + *pi = ei->nexti; + } + break; + default: + break; + } + return (ei == *pi); +} + +extern INSTRUCTION *unwind_stack(long n); + +static NODE * +execute_code(volatile INSTRUCTION *code) +{ + volatile NODE *r = NULL; + volatile jmp_buf fatal_tag_stack; + long save_stack_size; + int save_flags = do_flags; + + /* 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; + + PUSH_BINDING(fatal_tag_stack, fatal_tag, fatal_tag_valid); + if (setjmp(fatal_tag) == 0) { + (void) interpret((INSTRUCTION *) code); + r = POP_SCALAR(); + } else /* fatal error */ + (void) unwind_stack(save_stack_size); + + POP_BINDING(fatal_tag_stack, fatal_tag, fatal_tag_valid); + do_flags = save_flags; + if (exit_val != EXIT_SUCCESS) { /* must be EXIT_FATAL? */ + exit_val = EXIT_SUCCESS; + return NULL; + } + return (NODE *) r; +} + +/* do_eval --- eval command */ + +int +do_eval(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) +{ + NODE *r, *ret_val; + NODE *f = NULL; + NODE *this_frame = NULL, *this_func = NULL; + NODE **sp; + INSTRUCTION *eval, *code = NULL; + AWK_CONTEXT *ctxt; + int ecount = 0, pcount = 0; + 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 */ + ctxt = new_context(); + ctxt->install_func = append_symbol; /* keep track of newly installed globals */ + push_context(ctxt); + the_source = add_srcfile(SRC_CMDLINE, arg->a_string, srcfiles, NULL, NULL); + do_flags = false; + ret = parse_program(&code); + do_flags = save_flags; + remove_params(this_func); + if (ret != 0) { + pop_context(); /* switch to prev context */ + free_context(ctxt, false /* keep_globals */); + return false; + } + + f = lookup("@eval"); + assert(f != NULL); + if (this_func == NULL) { /* in main */ + /* do a function call */ + eval = bcalloc(Op_func_call, 2, 0); + eval->source_file = cur_srcfile->src; + eval->func_body = f; + 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 */ + int i; + INSTRUCTION *t; + + eval = f->code_ptr; /* Op_func */ + eval->source_file = cur_srcfile->src; + /* turn implicit Op_K_return into Op_stop */ + t = (eval + 1)->lasti; /* Op_K_return */ + t->opcode = Op_stop; + + /* 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"); + else + erealloc(this_frame->stack, NODE **, (pcount + ecount) * sizeof(NODE *), "do_eval"); + + sp = this_frame->stack + pcount; + for (i = 0; i < ecount; i++) { + NODE *np; + + np = f->fparms + i; + np->param_cnt += pcount; /* appending eval locals: fixup param_cnt */ + + getnode(r); + memset(r, 0, sizeof(NODE)); + *sp++ = r; + /* local variable */ + r->type = Node_var_new; + r->vname = np->param; + } + + this_func->param_cnt += ecount; + } + } + +#if 0 + pf_data.print_func = fprintf; + pf_data.fp = out_fp; + pf_data.defn = false; /* in_dump = false */ + (void) print_code(f->code_ptr, &pf_data); +#endif + + ret_val = execute_code((volatile INSTRUCTION *) eval); + + if (ret_val != NULL) + DEREF(ret_val); /* throw away return value */ + /* else + fatal error */ + + if (this_func != NULL && ecount > 0) { + int i; + + /* undo frame manipulation from above */ + + /* free eval locals */ + sp = this_frame->stack + pcount; + for (i = ecount; i > 0; i--) { + r = *sp; + if (r->type == Node_var) /* eval local variable */ + DEREF(r->var_value); + else if (r->type == Node_var_array) /* eval local array */ + assoc_clear(r); + freenode(r); + *sp++ = (NODE *) 0; + } + if (pcount == 0) { + efree(this_frame->stack); + this_frame->stack = NULL; + } /* else + restore_frame() will free it */ + + this_func->param_cnt -= ecount; + } + + /* + * Always destroy symbol "@eval", however destroy all newly installed + * globals only if fatal error (execute_code() returing NULL). + */ + + pop_context(); /* switch to prev context */ + free_context(ctxt, (ret_val != NULL)); /* free all instructions and optionally symbols */ + + if (ret_val != NULL) { + /* + * Remove @eval from FUNCTAB, so that above code + * will work the next time around. + */ + NODE *s = make_string("@eval", 5); + + (void) assoc_remove(func_table, s); + unref(s); + } + + free_srcfile(the_source); + + return false; +} + +/* +GDB Documentation: + ... When you use condition, GDB checks expression +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: + + No symbol "foo" in current context. +*/ + +static int invalid_symbol = 0; + +static void +check_symbol(NODE *r) +{ + invalid_symbol++; + d_error(_("No symbol `%s' in current context"), r->vname); + /* install anyway, but keep track of it */ + append_symbol(r); +} + +/* parse_condition --- compile a condition expression */ + +static int +parse_condition(int type, int num, char *expr) +{ + INSTRUCTION *code = NULL; + AWK_CONTEXT *ctxt = NULL; + int ret; + BREAKPOINT *b; + struct list_item *w; + NODE *this_func = NULL; + INSTRUCTION *it, *stop, *rule; + struct condition *cndn = NULL; + int save_flags = do_flags; + + if (type == D_break && (b = find_breakpoint(num)) != NULL) { + INSTRUCTION *rp; + cndn = &b->cndn; + rp = find_rule(b->src, b->bpi->source_line); + if (rp != NULL && rp->opcode == Op_func) + 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; + } + + if (cndn == NULL) + return -1; + if (expr == NULL) + goto out; /* delete condition */ + + install_params(this_func); + ctxt = new_context(); + invalid_symbol = 0; + ctxt->install_func = check_symbol; + push_context(ctxt); + (void) add_srcfile(SRC_CMDLINE, expr, srcfiles, NULL, NULL); + do_flags = false; + ret = parse_program(&code); + do_flags = save_flags; + remove_params(this_func); + pop_context(); + + if (ret != 0 || invalid_symbol) { + free_context(ctxt, false /* keep_globals */); + return -1; + } + + /* condition expression is parsed as awk pattern without + * any action. The code is then modified to end up with + * a `1.0' on stack when the expression is true, `0.0' otherwise. + */ + + assert(code != NULL); + rule = ctxt->rule_list.nexti; + stop = bcalloc(Op_stop, 1, 0); + + it = rule->firsti; /* Op_K_print_rec */ + assert(it->opcode == Op_K_print_rec); + it->opcode = Op_push_i; + it->memory = make_number(1.0); + 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; + it->memory = make_number(0.0); + it->nexti = stop; + +out: + if (cndn->expr != NULL) + efree(cndn->expr); + free_context(cndn->ctxt, false); + cndn->code = code; + cndn->expr = expr; + cndn->ctxt = ctxt; + + return 0; +} + +/* do_condition --- condition command */ + +int +do_condition(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) +{ + int type, num; + char *expr = NULL; + + num = arg->a_int; + type = has_break_or_watch_point(&num, false); + if (! type) + return false; + arg = arg->next; /* condition expression */ + if (arg != NULL) + expr = arg->a_string; + if (parse_condition(type, num, expr) == 0 && arg != NULL) + arg->a_string = NULL; /* don't let free_cmdarg free it */ + return false; +} + +/* in_cmd_src --- check if filename already in cmd_src */ + +int +in_cmd_src(const char *filename) +{ + struct command_source *cs; + for (cs = cmd_src; cs != NULL; cs = cs->next) { + if (cs->str != NULL && strcmp(cs->str, filename) == 0) + return true; + } + return false; +} + +int +get_eof_status() +{ + if (cmd_src == NULL) + return EXIT_FATAL; + return cmd_src->eof_status; +} + +void +push_cmd_src( + int fd, + bool istty, + char * (*readfunc)(const char *), + int (*closefunc)(int), + int ctype, + int eofstatus) +{ + struct command_source *cs; + emalloc(cs, struct command_source *, sizeof(struct command_source), "push_cmd_src"); + cs->fd = fd; + cs->is_tty = istty; + cs->read_func = readfunc; + cs->close_func = closefunc; + cs->cmd = ctype; + + /* 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. + */ + 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; +} + +int +pop_cmd_src() +{ + struct command_source *cs; + + if (cmd_src->next == NULL) + return -1; + + cs = cmd_src; + cmd_src = cs->next; + if (cs->close_func && cs->fd != INVALID_HANDLE) + cs->close_func(cs->fd); + if (cs->str != NULL) + efree(cs->str); + efree(cs); + + input_fd = cmd_src->fd; + input_from_tty = cmd_src->is_tty; + read_a_line = cmd_src->read_func; + return 0; +} diff --git a/depcomp b/depcomp new file mode 100755 index 0000000..49eb4bf --- /dev/null +++ b/depcomp @@ -0,0 +1,791 @@ +#! /bin/sh +# depcomp - compile a program generating dependencies as side-effects + +scriptversion=2017-09-16.17; # UTC + +# Copyright (C) 1999-2018 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 2, 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 . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Alexandre Oliva . + +case $1 in + '') + echo "$0: No command. Try '$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: depcomp [--help] [--version] PROGRAM [ARGS] + +Run PROGRAMS ARGS to compile a file, generating dependencies +as side-effects. + +Environment variables: + depmode Dependency tracking mode. + source Source file read by 'PROGRAMS ARGS'. + object Object file output by 'PROGRAMS ARGS'. + DEPDIR directory where to store dependencies. + depfile Dependency file to output. + tmpdepfile Temporary file to use when outputting dependencies. + libtool Whether libtool is used (yes/no). + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "depcomp $scriptversion" + exit $? + ;; +esac + +# Get the directory component of the given path, and save it in the +# global variables '$dir'. Note that this directory component will +# be either empty or ending with a '/' character. This is deliberate. +set_dir_from () +{ + case $1 in + */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; + *) dir=;; + esac +} + +# Get the suffix-stripped basename of the given path, and save it the +# global variable '$base'. +set_base_from () +{ + base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` +} + +# If no dependency file was actually created by the compiler invocation, +# we still have to create a dummy depfile, to avoid errors with the +# Makefile "include basename.Plo" scheme. +make_dummy_depfile () +{ + echo "#dummy" > "$depfile" +} + +# Factor out some common post-processing of the generated depfile. +# Requires the auxiliary global variable '$tmpdepfile' to be set. +aix_post_process_depfile () +{ + # If the compiler actually managed to produce a dependency file, + # post-process it. + if test -f "$tmpdepfile"; then + # Each line is of the form 'foo.o: dependency.h'. + # Do two passes, one to just change these to + # $object: dependency.h + # and one to simply output + # dependency.h: + # which is needed to avoid the deleted-header problem. + { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" + sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" + } > "$depfile" + rm -f "$tmpdepfile" + else + make_dummy_depfile + fi +} + +# A tabulation character. +tab=' ' +# A newline character. +nl=' +' +# Character ranges might be problematic outside the C locale. +# These definitions help. +upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ +lower=abcdefghijklmnopqrstuvwxyz +digits=0123456789 +alpha=${upper}${lower} + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi + +# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. +depfile=${depfile-`echo "$object" | + sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Avoid interferences from the environment. +gccflag= dashmflag= + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +cygpath_u="cygpath -u -f -" +if test "$depmode" = msvcmsys; then + # This is just like msvisualcpp but w/o cygpath translation. + # Just convert the backslash-escaped backslashes to single forward + # slashes to satisfy depend.m4 + cygpath_u='sed s,\\\\,/,g' + depmode=msvisualcpp +fi + +if test "$depmode" = msvc7msys; then + # This is just like msvc7 but w/o cygpath translation. + # Just convert the backslash-escaped backslashes to single forward + # slashes to satisfy depend.m4 + cygpath_u='sed s,\\\\,/,g' + depmode=msvc7 +fi + +if test "$depmode" = xlc; then + # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. + gccflag=-qmakedep=gcc,-MF + depmode=gcc +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. +## Unfortunately, FreeBSD c89 acceptance of flags depends upon +## the command line argument order; so add the flags where they +## appear in depend2.am. Note that the slowdown incurred here +## affects only configure: in makefiles, %FASTDEP% shortcuts this. + for arg + do + case $arg in + -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; + *) set fnord "$@" "$arg" ;; + esac + shift # fnord + shift # $arg + done + "$@" + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. +## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. +## (see the conditional assignment to $gccflag above). +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). Also, it might not be +## supported by the other compilers which use the 'gcc' depmode. +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + # The second -e expression handles DOS-style file names with drive + # letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the "deleted header file" problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. +## Some versions of gcc put a space before the ':'. On the theory +## that the space means something, we add a space to the output as +## well. hp depmode also adds that space, but also prefixes the VPATH +## to the object. Take care to not repeat it in the output. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + tr ' ' "$nl" < "$tmpdepfile" \ + | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ + | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # 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, + # since it is checked for above. + 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, + # since it is checked for above. + exit 1 + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. In older versions, this file always lives in the + # current directory. Also, the AIX compiler puts '$object:' at the + # start of each line; $object doesn't have directory information. + # Version 6 uses the directory in both cases. + set_dir_from "$object" + set_base_from "$object" + if test "$libtool" = yes; then + tmpdepfile1=$dir$base.u + tmpdepfile2=$base.u + tmpdepfile3=$dir.libs/$base.u + "$@" -Wc,-M + else + tmpdepfile1=$dir$base.u + tmpdepfile2=$dir$base.u + tmpdepfile3=$dir$base.u + "$@" -M + fi + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + do + test -f "$tmpdepfile" && break + done + aix_post_process_depfile + ;; + +tcc) + # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 + # FIXME: That version still under development at the moment of writing. + # Make that this statement remains true also for stable, released + # versions. + # It will wrap lines (doesn't matter whether long or short) with a + # trailing '\', as in: + # + # foo.o : \ + # foo.c \ + # foo.h \ + # + # It will put a trailing '\' even on the last line, and will use leading + # spaces rather than leading tabs (at least since its commit 0394caf7 + # "Emit spaces for -MD"). + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. + # We have to change lines of the first kind to '$object: \'. + sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" + # And for each line of the second kind, we have to emit a 'dep.h:' + # dummy dependency, to avoid the deleted-header problem. + sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" + rm -f "$tmpdepfile" + ;; + +## The order of this option in the case statement is important, since the +## shell code in configure will try each of these formats in the order +## listed in this file. A plain '-MD' option would be understood by many +## compilers, so we must ensure this comes after the gcc and icc options. +pgcc) + # Portland's C compiler understands '-MD'. + # Will always output deps to 'file.d' where file is the root name of the + # source file under compilation, even if file resides in a subdirectory. + # The object file name does not affect the name of the '.d' file. + # pgcc 10.2 will output + # foo.o: sub/foo.c sub/foo.h + # and will wrap long lines using '\' : + # foo.o: sub/foo.c ... \ + # sub/foo.h ... \ + # ... + set_dir_from "$object" + # Use the source, not the object, to determine the base name, since + # that's sadly what pgcc will do too. + set_base_from "$source" + tmpdepfile=$base.d + + # For projects that build the same source file twice into different object + # files, the pgcc approach of using the *source* file root name can cause + # problems in parallel builds. Use a locking strategy to avoid stomping on + # the same $tmpdepfile. + lockdir=$base.d-lock + trap " + echo '$0: caught signal, cleaning up...' >&2 + rmdir '$lockdir' + exit 1 + " 1 2 13 15 + numtries=100 + i=$numtries + while test $i -gt 0; do + # mkdir is a portable test-and-set. + if mkdir "$lockdir" 2>/dev/null; then + # This process acquired the lock. + "$@" -MD + stat=$? + # Release the lock. + rmdir "$lockdir" + break + else + # If the lock is being held by a different process, wait + # until the winning process is done or we timeout. + while test -d "$lockdir" && test $i -gt 0; do + sleep 1 + i=`expr $i - 1` + done + fi + i=`expr $i - 1` + done + trap - 1 2 13 15 + if test $i -le 0; then + echo "$0: failed to acquire lock after $numtries attempts" >&2 + echo "$0: check lockdir '$lockdir'" >&2 + exit 1 + fi + + if test $stat -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each line is of the form `foo.o: dependent.h', + # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \ + | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp2) + # The "hp" stanza above does not work with aCC (C++) and HP's ia64 + # compilers, which have integrated preprocessors. The correct option + # to use with these is +Maked; it writes dependencies to a file named + # 'foo.d', which lands next to the object file, wherever that + # happens to be. + # Much of this is similar to the tru64 case; see comments there. + set_dir_from "$object" + set_base_from "$object" + if test "$libtool" = yes; then + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir.libs/$base.d + "$@" -Wc,+Maked + else + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir$base.d + "$@" +Maked + fi + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile1" "$tmpdepfile2" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" + # Add 'dependent.h:' lines. + sed -ne '2,${ + s/^ *// + s/ \\*$// + s/$/:/ + p + }' "$tmpdepfile" >> "$depfile" + else + make_dummy_depfile + fi + rm -f "$tmpdepfile" "$tmpdepfile2" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in 'foo.d' instead, so we check for that too. + # Subdirectories are respected. + set_dir_from "$object" + set_base_from "$object" + + if test "$libtool" = yes; then + # Libtool generates 2 separate objects for the 2 libraries. These + # two compilations output dependencies in $dir.libs/$base.o.d and + # in $dir$base.o.d. We have to check for both files, because + # one of the two compilations can be disabled. We should prefer + # $dir$base.o.d over $dir.libs/$base.o.d because the latter is + # automatically cleaned when .libs/ is deleted, while ignoring + # the former would cause a distcleancheck panic. + tmpdepfile1=$dir$base.o.d # libtool 1.5 + tmpdepfile2=$dir.libs/$base.o.d # Likewise. + tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 + "$@" -Wc,-MD + else + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir$base.d + tmpdepfile3=$dir$base.d + "$@" -MD + fi + + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + do + test -f "$tmpdepfile" && break + done + # Same post-processing that is required for AIX mode. + aix_post_process_depfile + ;; + +msvc7) + if test "$libtool" = yes; then + showIncludes=-Wc,-showIncludes + else + showIncludes=-showIncludes + fi + "$@" $showIncludes > "$tmpdepfile" + stat=$? + grep -v '^Note: including file: ' "$tmpdepfile" + if test $stat -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + # The first sed program below extracts the file names and escapes + # backslashes for cygpath. The second sed program outputs the file + # name when reading, but also accumulates all include files in the + # hold buffer in order to output them again at the end. This only + # works with sed implementations that can handle large buffers. + sed < "$tmpdepfile" -n ' +/^Note: including file: *\(.*\)/ { + s//\1/ + s/\\/\\\\/g + p +}' | $cygpath_u | sort -u | sed -n ' +s/ /\\ /g +s/\(.*\)/'"$tab"'\1 \\/p +s/.\(.*\) \\/\1:/ +H +$ { + s/.*/'"$tab"'/ + G + p +}' >> "$depfile" + echo >> "$depfile" # make sure the fragment doesn't end with a backslash + rm -f "$tmpdepfile" + ;; + +msvc7msys) + # 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, + # since it is checked for above. + exit 1 + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + # Remove '-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + # Require at least two characters before searching for ':' + # in the target name. This is to cope with DOS-style filenames: + # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. + "$@" $dashmflag | + sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this sed invocation + # correctly. Breaking it into two sed invocations is a workaround. + tr ' ' "$nl" < "$tmpdepfile" \ + | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ + | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # Remove any Libtool call + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + # X makedepend + shift + cleared=no eat=no + for arg + do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + if test $eat = yes; then + eat=no + continue + fi + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + # Strip any option that makedepend may not understand. Remove + # the object too, otherwise makedepend will parse it as a source file. + -arch) + eat=yes ;; + -*|$object) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix=`echo "$object" | sed 's/^.*\././'` + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + # makedepend may prepend the VPATH from the source file name to the object. + # No need to regex-escape $object, excess matching of '.' is harmless. + sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process the last invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed '1,2d' "$tmpdepfile" \ + | tr ' ' "$nl" \ + | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ + | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + # Remove '-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E \ + | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ + -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ + | sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + IFS=" " + for arg + do + case "$arg" in + -o) + shift + ;; + $object) + shift + ;; + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E 2>/dev/null | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" + echo "$tab" >> "$depfile" + sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvcmsys) + # 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, + # since it is checked for above. + exit 1 + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: "; # UTC" +# End: diff --git a/doc/ChangeLog b/doc/ChangeLog new file mode 100644 index 0000000..45c61dd --- /dev/null +++ b/doc/ChangeLog @@ -0,0 +1,2425 @@ +2018-02-25 Arnold D. Robbins + + * 4.2.1: Release tar ball made. + +2018-02-25 Arnold D. Robbins + + * gawktexi.in: Update UPDATE-MONTH. + * awkcard.in: Update tar ball version and copyright year. + +2018-02-25 Arnold D. Robbins + + * texinfo.tex: Updated. + +2018-02-17 Arnold D. Robbins + + * gawktexi.in: Further fix to NONFATAL stuff. Thanks to + Antonio Giovanni Colombo for the report. + +2018-02-16 Arnold D. Robbins + + * gawktexi.in: Fix NONFATAL stuff to cover input redirections too. + +2018-02-15 Arnold D. Robbins + + * gawk.1: Fix NONFATAL stuff to cover input redirections too. + +2018-02-08 Arnold D. Robbins + + * gawktexi.in: Clarify binary mode is default on Cygwin, + improve section on using on PCs to refer to MinGW and DJGPP. + Thanks for the report to a contributor who wishes to + remain anonymous. + +2018-01-28 Arnold D. Robbins + + * wordlist: Updated. + +2018-01-25 Arnold D. Robbins + + * gawktexi.in (AWKLIBPATH Variable): Add note that changing + ENVIRON["AWKLIBPATH"] won't affect the running program. Thanks to + Neil R. Ormos for the suggestion. + +2018-01-25 Arnold D. Robbins + + * gawktexi.in (gawkextlib): Update discussion of gawkextlib. + Add not about json extension, and just present the list as + describing some of the extensions, since there are now too + many to try to keep up with all of them. + +2018-01-15 Arnold D. Robbins + + * gawktexi.in: Update gnu.org and fsf.org URLs to https. OK'd + by the FSF. + +2018-01-11 Arnold D. Robbins + + * gawktexi.in: Remove incorrect '*' on some declarations of + ext_id in sample extension code. Thanks to Panos Papadopoulos + for the report. + * texinfo.tex: Updated from GNULIB. + +2018-01-08 Andrew J. Schorr + + * gawktexi.in (Checking for MPFR): Add warnings about exit's processing + of END rules. + +2018-01-03 Arnold D. Robbins + + * gawktexi.in: Update copryight year, and some small cleanups. + +2018-01-02 Arnold D. Robbins + + * gawktexi.in (Setting the rounding mode): Add a sidebar + with sample code (courtesy of ) to + demonstrate how ROUNDMODE affects number to string conversion. + +2017-12-28 Arnold D. Robbins + + * texinfo.tex: Updated. + * gawktexi.in (How To Contribute): Update to point to + awklang.org. + +2017-12-22 Arnold D. Robbins + + * texinfo.tex: Updated. + +2017-12-20 Arnold D. Robbins + + * gawktexi.in (Additional Configuration Options): Add + description of the --enable-versioned-extension-dir option. + +2017-12-01 Sergey Tselikh + + * gawktexi.in: Several small changes to gawktexi.in, + mainly related to fixing typos, small text polishing + and adding @group/@end group in @example and @example-like + constructs to clean PDF version (formatted for Letter paper, + which is the default) of orphaned single lines of source code + or example output in higher and lower parts of pages (such + lines were with just a "}", or with a single line of code or + a comment). Hyphenated words "single-precision", + "double-precision" and alike left untouched. + +2017-12-14 Arnold D. Robbins + + * gawktexi.in: Add a note to add a section on recursion. + Thanks to Bill Duncan for the + suggestion. + * gawktexi.in: Add a missing DARKCORNER indicator and + a few missing dark corner index entries. Remove the note + at the end to check that all dark corners are indexed and + instead make it part of the list of consistency checks. + +2017-11-24 Arnold D. Robbins + + * gawkworkflow.texi (General practices): Use correct option + --delete for deleting a branch upstream, instead of -d. + +2017-11-21 Andrew J. Schorr + + * gawktexi.in (Setting the Rounding Mode): Fix the description + of ROUNDMODE "A": it uses MPFR_RNDA mode, which rounds away from zero, + not "Round to nearest, ties away from zero". + * gawk.1 (ROUNDMODE): Fix description of "A". + +2017-11-17 Arnold D. Robbins + + * gawktexi.in (Changes from API V1): Give a list of things + that changed, with xrefs. Thanks to Andrew Schorr for the push. + +2017-11-09 Arnold D. Robbins + + * gawktexi.in (For Statement): Small clarification in the text. + +2017-11-08 Arnold D. Robbins + + * gawktexi.in (General Data Types): Move AWK_NUMBER_TYPE + enum out to top level, corresponding to code change. + +2017-10-19 Arnold D. Robbins + + * 4.2.0: Release tar ball made. + +2017-10-17 Arnold D. Robbins + + * gawktexi.in (EDITION): Update to 4.2. Also, remove all visible + references to http://awk.info; that site no longer exists. + +2017-10-17 Andrew J. Schorr + + Update docs to indicate that isarray is not deprected in this release. + + * awkcard.in: Remove "Deprecated" notice under isarray. + * gawk.1: Remove deprecated warning under isarray documentation. + * gawkexti.in: Remove sentence indicating that isarray is deprecated + and recommending typeof instead. + +2017-10-10 Arnold D. Robbins + + * gawktexi.in (Readfile Function): Fix the code for the naive + function to be syntactically and semantically correct. Thanks to + Jaromir Obr for the report. + (POSIX String Comparison): Add some URL references in @ignore. + +2017-10-08 Andrew J. Schorr + + * gawktexi.in: Fix discussion of AWKPATH in section on @include. + +2017-10-04 Arnold D. Robbins + + * gawktexi.in: Update the update month to October. + +2017-10-02 Antonio Giovanni Colombo + + * gawktexi.in: Two typo fixes. + +2017-10-01 Arnold D. Robbins + + * gawktexi.in: Add pointer to mawk 2.0 GitHub page. + +2017-10-01 Antonio Giovanni Colombo + + * gawktexi.in: Update many URLs to https. Some other small fixes. + +2017-10-01 Arnold D. Robbins + + * awkcard.in: One more small change. + * gawk.1: Brought up to date and polished a bit. + * gawktexi.in: Some small additional fixes. + +2017-09-29 Arnold D. Robbins + + * awkcard.in: Finish changes (we hope) for next release. + +2017-09-28 Arnold D. Robbins + + * ad.block: Change FSF URL to https. + * awkcard.in: First round of changes for next release. + +2017-09-18 Arnold D. Robbins + + * gawktexi.in: Change GNU URLs to use `https://...'. + Revise UPDATE_MONTH. + * texinfo.tex: Updated. + +2017-09-17 Arnold D. Robbins + + * gawktexi.in: Change 'namespace' to 'name_space' where it matters + for C++ compatibility. + +2017-09-13 David Kaspar + + * gawktexi.in: Fix the dir entry. + * gawkinet.texi: Allow calling as `info awktexi'. + +2017-09-12 Arnold D. Robbins + + * gawktexi.in (Installation summary): Note OS/2 exists for PCs + in a comment. + +2017-08-28 Arnold D. Robbins + + * gawktexi.in (Contributors): Update entry for Steven Davies. + +2017-08-24 Arnold D. Robbins + + * texinfo.tex: Updated. Fixes table of contents issue + with very long title. + * gawktexi.in: Slight rearranging of order of things that + happened in 4.2. Minor cleanups related to Scott Deifik. + +2017-08-21 Arnold D. Robbins + + * texinfo.tex: Updated. Fixes table of contents issue + with Part header. + +2017-08-17 Arnold D. Robbins + + * gawktexi.in: Document Marco Curreli's contribution of + the Italian translation, along with Antonio Colombo. + +2017-08-16 Arnold D. Robbins + + * gawktexi.in: Update history of features appendix section. + * wordlist, worldlist2: Add more words. + +2017-08-13 Arnold D. Robbins + + * gawktexi.in, gawk.1, awkcard.in: Update versions and + copyright years, prepatory to starting a release spiral. + +2017-08-13 Arnold D. Robbins + + * gawktexi.in: Update API chapter with info about additions + for accessing and/or creating MPZ and MPFR values. + +2017-08-04 Arnold D. Robbins + + * texinfo.tex: Updated. + +2017-08-01 Arnold D. Robbins + + * gawktexi.in: Update with info about DJGPP port now + being supported. + +2017-07-28 Arnold D. Robbins + + * gawktexi.in (Type Functions): Improve the example + for untyped variables. + +2017-07-28 Arnold D. Robbins + + * gawktexi.in (Extension Sample Inplace): Apply GPL to + inplace.awk; should have done that when it was first + added. Oops. + +2017-07-21 Arnold D. Robbins + + * gawktexi.in: Fix a spelling error. + * wordlist: Update with more words. + +2017-07-02 Arnold D. Robbins + + * texinfo.tex: Pull in latest from Texinfo SVN. + +2017-06-19 Andrew J. Schorr + + * gawktexi.in (Memory Allocation Functions and Convenience Macros): + Document new ezalloc API macro. + +2017-06-18 Andrew J. Schorr + + * gawkworkflow.texi: Fix typo. + +2017-06-15 Arnold D. Robbins + + * gawktexi.in: Expand tab characters. + +2017-06-05 Andrew J. Schorr + + * gawktexi.in (Checking for MPFR): Fix typo. + +2017-05-30 Arnold D. Robbins + + * gawktexi.in: Document PROCINFO["argv"]. + +2017-05-29 Arnold D. Robbins + + * gawktexi.in (Checking for MPFR): New node on checking if + gawk was invoked with -M. + +2017-05-22 Arnold D. Robbins + + * 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 + + * gawktexi.in: Improve documentation of --source option. + +2017-04-20 Arnold D. Robbins + + * gawktexi.in: Document --disable-mpfr configure option. + +2017-04-16 Arnold D. Robbins + + * awkcard.in: Comment out description of intdiv(). + * gawk.1: Ditto. + * gawktexi.in: References to intdiv changed to intdiv0 and + bracketed inside @ifset INTDIV. Not set by default. + +2017-04-16 Arnold D. Robbins + + * gawktexi.in: Improve documentation of the intdiv() function. + +2017-04-12 Arnold D. Robbins + + * it: New directory with Italian translation of the manual. + * Makefile.am (EXTRA_DIST): Add `it' and wordlist2. + +2017-04-12 Manuel Collado + + * gawktexi.in, gawk.1: Small clarification of the patsplit behavior. + +2017-04-11 Arnold D. Robbins + + * gawktexi.in: Minor style edits. + +2017-04-10 Andrew J. Schorr + + * 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 + + * 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 + + * gawk.1: Document new PROCINFO["FS"] value "API". + +2017-03-22 Andrew J. Schorr + + * awkcard.in: Document FIELDWIDTHS enhancement to support an optional + field skip prefix. + * gawk.1: Ditto. + +2017-03-17 Arnold D. Robbins + + * gawktexi.in: Improve the discussion of quoting on + MS-Windows. Original text contributed by + Vincent Belaiche . + +2017-03-03 Arnold D. Robbins + + * gawktexi.in: Additional small writing tip in the notes + after the @bye. + +2017-03-02 Arnold D. Robbins + + * gawktexi.in: Edits preparatory to release. + +2017-02-23 Arnold D. Robbins + + * gawk.1: "timezone" --> "time zone". + * awkcard.in: Update copyright year. + +2017-02-21 Andrew J. Schorr + + * gawk.1: Document new mktime optional 2nd utc-flag argument. + * gawktex.in: Ditto. + * awkcard.in: Ditto. + +2017-02-13 Arnold D. Robbins + + * gawktexi.in: Fix two typos. + * wordlist.txt: Update. + + Related: + + * gawktexi.in: Fix more typos. + * wordlist.txt: Update again. + +2017-01-27 Arnold D. Robbins + + * gawktexi.in: Update UPDATE-MONTH and copyright years. + +2017-01-25 Arnold D. Robbins + + * gawktexi.in: Comment out stuff about awk.info, since that + domain is now gone. + +2016-12-05 Andrew J. Schorr + + * 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 + + * gawktexi.in: Update API table of type requested / type returned. + +2016-12-22 Arnold D. Robbins + + * gawktexi.in: Minor edits after merging branches and some + additional work in the code. + +2016-12-17 Arnold D. Robbins + + * gawktexi.in: Further API clarifications and edits, add a + section on backwards compatibility. + +2016-12-16 Arnold D. Robbins + + * gawktexi.in: Update description of awk_ext_func_t structure, + again. + +2016-12-14 Arnold D. Robbins + + * gawktexi.in: Update description of awk_ext_func_t structure. + +2016-12-05 Andrew J. Schorr + + * 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 + + * gawktexi.in: Remove make_regex and replace it with make_const_regex + and make_malloced_regex. + +2016-12-04 Andrew J. Schorr + + * 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 + + * gawktexi.in: Document typed regex changes as relates to API. + Still stuff left to do. + +2016-11-21 Arnold D. Robbins + + * 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 + + * 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 + + * gawktexi.in: Fix example use of dcngettext. + Thanks to Sergey Tselikh + for the report. + +2016-11-08 Arnold D. Robbins + + * gawktexi.in, wordlist: Typo fix. ECBDIC --> EBCDIC. + Thanks to Sergey Tselikh for the report. + (bitwise-ops): Put table in @verbatim instead of @display. + Works better for Info, text, and HTML. Thanks to + Marco Curreli for the report. + +2016-11-04 Arnold D. Robbins + + * gawktexi.in: Fix a spelling error. + * wordlist: Update. + +2016-10-25 Arnold D. Robbins + + * 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 + + * gawktexi.in: Remove references to MS-DOS and OS/2, + simplify the whole section on PC operating systems. + +2016-10-02 Arnold D. Robbins + + * gawktexi.in (Bugs): Rework this section and break into + subsections, mainly to emphasize that I no longer + read comp.lang.awk. + +2016-09-20 Arnold D. Robbins + + * gawktexi.in (Group Functions): Typo fix. Reported + by Jaromir Obr . + (Time Functions): Slightly enhance description of ISO 8601 + definition of first and last weeks. Thanks to + Michel de Ruiter for the note. + +2016-08-25 Arnold D. Robbins + + * 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 + + * 4.1.4: Release tar ball made. + +2016-08-24 Arnold D. Robbins + + * wordlist: Add more words. + * gawktexi.in: Fix more typos. + +2016-08-23 Arnold D. Robbins + + * Makefile.am (EXTRA_DIST): Add new file, wordlist. + (spell): New target. + * wordlist: New file. + * gawktexi.in: Fix typos, adjust update date. + * awkcard.in: Update copyright years. + +2016-08-03 Arnold D. Robbins + + Restored doc on typed regexes. + + * gawk.1, gawktexi.in: Updated. + +2016-08-03 Arnold D. Robbins + + Remove typed regexes until they can be done properly. + + * gawk.1, gawktexi.in: Updated. + +2016-08-01 Arnold D. Robbins + + * gawktexi.in: Mark DJGPP port as unsupported. + +2016-07-24 Arnold D. Robbins + + * gawktexi.in: Fix a typo. Thanks to Marco Curreli for reporting. + +2016-07-23 Arnold D. Robbins + + * 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 + + * gawktexi.in: Fix a typo. Thanks to Antonio Colombo for reporting. + +2016-07-17 Arnold D. Robbins + + * gawktexi.in: Document GAWK_LOCALE_DIR env var and also to not + use LANGUAGE env var. + +2016-07-12 Arnold D. Robbins + + * gawktexi.in (Auto-set): Add example use of multiply function. + +2016-06-30 Arnold D. Robbins + + * gawk.1: Typo fix. Thanks to Antonio Giovanni Colombo + for noticing. + +2016-06-15 Arnold D. Robbins + + * gawk.1: Document typeof(), update modified date. + * awkcard.in: Document typeof(). + +2016-06-10 Arnold D. Robbins + + * gawktexi.in: Fix a typo, and replace hard-coded "section" with + @value{SECTION} where appropriate. Thanks to Antonio + Giovanni Colombo for the reports. + (UPDATE-MONTH, PATCHLEVEL): Update to current before release. + * awkcard.in: Update version. + +2016-05-30 Andrew J. Schorr + + * gawktexi.in: Replace num_expected_args with max_expected_args. + Explain what it's used for. + +2016-05-25 Manuel Collado . + + * gawktexi.in: Document new 'nonfatal' API function. + +2016-05-25 Arnold D. Robbins + + * gawktexi.in: Typo fix in extension section, thanks to + Manuel Collado . + +2016-05-02 Andrew J. Schorr + + * gawktexi.in: Document new CPP defines gawk_api_major_version and + gawk_api_minor_version. + +2016-04-13 Arnold D. Robbins + + * gawkinet.texi: Some general cleanups. Remove stuff commented + out since 2001, index RFCs, change function name convention to + match main gawktexi.in. Update the update month. + +2016-04-06 Arnold D. Robbins + + * 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 + + * gawktexi.in, gawkinet.texi: Enable use of braces in + indexes. Requires Texinfo 6.0 or later. + +2016-04-02 Arnold D. Robbins + + * 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 + + * gawkinet.texi: Small update about end of line vs full + comments when pretty printing. + +2016-03-21 Arnold D. Robbins + + * gawkinet.texi: Update UDP client and discussion, update + modification dates and gawk versions. + +2016-03-11 Arnold D. Robbins + + * gawktexi.in: Improve system() return values documentation. + +2016-03-07 Arnold D. Robbins + + * gawktexi.in: Document system() return values. + * gawk.1: Add a pointer to the manual about same. + +2016-02-23 Arnold D. Robbins + + * sidebar.awk: Globally replace [[:space:]] with [ \t] so that + it will work with old versions of mawk (as found, boo!, on many + Debian-based distributions). Thanks to Yehezkel Bernat for + discovering and reporting the issue. + +2016-02-20 Arnold D. Robbins + + * gawktexi.in (Bracket Expressions): Add a small note about + Unicode in bracket expressions. + +2016-02-18 Arnold D. Robbins + + * gawktexi.in: Fixes in wc.awk and in cut.awk. Thanks to David Ward, + 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 + + * gawktexi.in: Revise for use with Texinfo 6.1. + Remove ` @c' at the end of inline docbook constructs. + Remove special @DB*REF macros, not needed anymore. + Use @sup for superscripts where possible. + * texinfo.tex: Updated. + +2016-02-05 Arnold D. Robbins + + * 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 + + * gawktexi.in (Command-Line Options): Change wording of -M description + to say "Select" instead of "Force". + (Arbitrary-Precision Arithmetic Features): Tweak the wording to make + it clear that MPFR is not used unless the -M option is supplied. + +2016-02-03 Arnold D. Robbins + + * gawktexi.in (VMS Running): Improve the Texinfo usage. + +2016-01-31 John E. Malmberg + + * gawktexi.in (VMS Running): Add instructions on how to redirect + gawk data to a VMS command. + +2016-01-18 Arnold D. Robbins + + * gawktexi.in (Bracket Expressions): Document that '[', '.' and + '*' are literal inside bracket expressions. + (Two-way I/O): Add stuff about stdbuf and deadlocks. + +2016-01-15 Arnold D. Robbins + + * gawktexi.in (Array Sorting Functions): Clean up the code some, + per suggestion from Michal Jaegermann. Tighten up the prose + a bit too. + +2016-01-14 Arnold D. Robbins + + * 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 + + * gawktexi.in (Array Sorting Functions): Add an example of + using a function name with asort(). Response to bug report + Stephane Goujet . + +2016-01-06 Arnold D. Robbins + + * 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 + + * gawktexi.in: Document that GNU/Linux on Alpha is no + longer supported. + +2015-12-27 Arnold D. Robbins + + * gawktexi.in: Fix some @c endfile. Thanks to Antonio + Giovanni Colombo for the report and patch. + +2015-12-20 Arnold D. Robbins + + * gawktexi.in: Add PROCINFO["NONFATAL"] to the list for PROCINFO. + * gawk.1: Ditto. + +2015-12-18 Arnold D. Robbins + + * gawk.1: Update description of PROCINFO, and sort it properly. + * gawktexi.in: Ditto. + +2015-11-26 Arnold D. Robbins + + * gawktexi.in: Add "exit" as synonym for "quit" in the + debugger. Suggested by Joep van Delft . + +2015-11-15 Arnold D. Robbins + + * gawktexi.in: Minor edits. + * gawk.1: Revise \x to maximum of two digits. + +2015-11-04 Arnold D. Robbins + + * Makefile.am (pdf-local): Remove igawk.1.pdf. Ooops. + +2015-10-30 Arnold D. Robbins + + * Makefile.am (awkcard.ps): Add options to force paper size + to letter. This makes the cut marks come out correctly even + if groff's default paper size is a4. + +2015-10-26 Arnold D. Robbins + + * gawk.1: Put commas outside quoting in regexps to avoid + confusion. Thanks to Mike Frysinger . + +2015-10-16 Arnold D. Robbins + + * awkcard.in: Fix tbl complaint. + +2015-10-07 Arnold D. Robbins + + * texinfo.tex: Updated to a working version. + +2015-10-04 Arnold D. Robbins + + * texinfo.tex: Revert update. It stopped working. I should learn + to test these things. Thanks to Antonio Giovanni Colombo for + the report. + +2015-10-02 Arnold D. Robbins + + * gawktexi.in: Note that there is no support for SSL. + +2015-09-25 Arnold D. Robbins + + * texinfo.tex: Update to latest. + +2015-08-28 Daniel Richard G. + + * doc/gawktexi.in: Check for the "struct passwd.pw_passwd" and + "struct group.gr_passwd" fields and conditionalize their use, as + they don't exist on z/OS. + * Makefile.am (pdf-local): Renamed from "pdf", as Automake already + defines "pdf" and warns us as much. + +2015-08-14 Arnold D. Robbins + + * gawktexi.in: Typo fixes in Appendix A. + Thanks to Antonio Colombo. + +2015-07-30 Arnold D. Robbins + + * gawktexi.in: Small typo fix; thanks to Antonio Colombo + for noticing. + +2015-07-01 Arnold D. Robbins + + * gawktexi.in: Update info on Quiktrim awk; thanks to + Antonio Colombo for the pointer. + +2015-06-30 Arnold D. Robbins + + * 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 + + * gawktexi.in: Update description of values returned by typeof. + +2015-06-19 Arnold D. Robbins + + * gawkinet.info: Fix an old arnold@gnu.org. + +2015-06-17 Andrew J. Schorr + + * gawktexi.in: Document inplace shortcomings -- it does not preserve + ACLs, and it may leave temporary files behind if killed by a signal. + +2015-06-17 Andrew J. Schorr + + * gawktexi.in: Document new inplace variable to control whether + inplace editing is active. + +2015-06-13 Arnold D. Robbins + + * gawktexi.in: Comment out exercise 10.3, since the answer + is included in the text. Thanks to Antonio Colombo + for pointing this out. + +2015-06-12 Arnold D. Robbins + + * gawktexi.in: Add another pithy quote from Chet Ramey. Currently + commented out. + +2015-05-31 Arnold D. Robbins + + * gawktexi.in: Revised description of default field parsing + for POSIX. Newline is now a separator also. Thanks to + Michael Klement for pointing this out. + * gawk.1: Updated too. + +2015-05-30 Arnold D. Robbins + + * gawktexi.in (Bitwise Functions): Update results of testbits.awk. + +2015-05-19 Arnold D. Robbins + + * 4.1.3: Release tar ball made. + +2015-05-19 Arnold D. Robbins + + * gawktexi.in: Bump patch level and modified date. + Move to modern version of @image. + * texinfo.tex: Update to latest. + * array-elements.txt: Remove texinfo commands. + +2015-05-18 Arnold D. Robbins + + * gawktexi.in: Add a pithy quote from Chet Ramey. Currently + commented out. + +2015-05-16 Arnold D. Robbins + + * gawktexi.in: Fix description of nextfile within a function. Sigh. + +2015-05-15 Andrew J. Schorr + + * gawktexi.in (Undocumented): Describe the new PROCINFO["argv"] array. + +2015-05-14 Arnold D. Robbins + + * gawktexi.in (Bugs): Add that email should be in plain + text and not in HTML. Sigh. + +2015-05-11 Arnold D. Robbins + + * gawktexi.in: Add doc on conversions for strongly typed + regexp variables. + +2015-05-03 Arnold D. Robbins + + * gawktexi.in: Add initial documentation for strongly typed + regexps and for `typeof'. + +2015-04-29 Arnold D. Robbins + + * 4.1.2: Release tar ball made. + +2015-04-16 Arnold D. Robbins + + * gawktexi.in (Undocumented): More info added. + +2015-04-08 Arnold D. Robbins + + * gawktexi.in: Update feature history section. + +2015-04-07 Arnold D. Robbins + + * gawktexi.in: Add a minor note to revisit FPAT pattern for CSV + files at some point. + +2015-04-05 Andrew J. Schorr + + * gawktexi.in: Replace http://gawkextlib.sourceforge.net with + http://sourceforge.net/projects/gawkextlib, since the former link + contains obsolete info. Update the gawkextlib build instructions + to point to http://sourceforge.net/projects/gawkextlib/files for the + current info. + +2015-04-05 Arnold D. Robbins + + * 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 + + * gawktexi.in, gawk.1, awkcard.in: Name change: div() --> intdiv(). + +2015-03-31 Arnold D. Robbins + + * gawktexi.in: Update discussion of calling built-in functions + indirectly. Small additional fix relating to rand(). Thanks + to Antonio Colombo. + +2015-03-27 Arnold D. Robbins + + * gawktexi.in: Minor edits. + +2015-03-24 Arnold D. Robbins + + * 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 + + * gawktexi.in: Modify inplace.awk to call inplace_end in BEGINFILE + and END instead of in ENDFILE. This way, actions in ENDFILE rules + will be redirected as expected. + +2015-03-17 Arnold D. Robbins + + * gawktexi.in: Turn "positive" into non-negative as appropriate. + Thanks to Nicholas Mills for pointing out + the issue. + +2015-03-08 Arnold D. Robbins + + * 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 + + * gawktexi.in: Change quotes to @dfn for pseudorandom. + A last-minute O'Reilly fix. + +2015-02-27 Arnold D. Robbins + + * gawktexi.in: Update UPDATE-MONTH and copyright year. + Note that "the guide is definitive" quote is really + from "The Restaurant at the End of the Universe". Thanks + to Antonio Colombo for pointing this out. + +2015-02-24 Arnold D. Robbins + + * texinfo.tex: Update to most current version. + * gawktexi.in: Minor edit to match an O'Reilly fix. + Add some FIXMEs to one day use @sup. + +2015-02-22 Arnold D. Robbins + + * gawktexi.in: Change 'div' to 'divisor' in some examples. + This future-proofs against a new function in master. + Thanks to Antonio Giovanni Colombo for the report. + +2015-02-20 Arnold D. Robbins + + * gawktexi.in: More O'Reilly fixes. I think it's done! + +2015-02-19 Arnold D. Robbins + + * gawktexi.in: More O'Reilly fixes. + +2015-02-17 Arnold D. Robbins + + * gawktexi.in: A few minor formatting fixes to sync with O'Reilly + version. + +2015-02-13 Arnold D. Robbins + + * gawktexi.in: O'Reilly fixes. Through QC1 review. + +2015-02-11 Arnold D. Robbins + + * gawktexi.in: O'Reilly fixes. + +2015-02-10 Arnold D. Robbins + + * gawktexi.in: Minor fixes, O'Reilly fixes. + +2015-02-09 Arnold D. Robbins + + * gawktexi.in: Restore a lost sentence. O'Reilly fixes. + +2015-02-08 Arnold D. Robbins + + * gawktexi.in: O'Reilly fixes. + Make non-fatal i/o use "NONFATAL". + +2015-02-06 Arnold D. Robbins + + * gawktexi.in: O'Reilly fixes. + +2015-02-04 Arnold D. Robbins + + * gawktexi.in: O'Reilly fixes. + * gawktexi.in: Update various version-related bits of info. + +2015-02-02 Arnold D. Robbins + + * gawktexi.in: O'Reilly fixes. + +2015-02-01 Arnold D. Robbins + + * gawktexi.in: POSIX requirement that function parameters cannot + have the same name as a function is now --posix. + Restore indirectcall example. + + More O'Reilly fixes. + +2015-01-30 Arnold D. Robbins + + * gawktexi.in: Document POSIX requirement that function parameters + cannot have the same name as a function. Fix indirectcall example. + +2015-01-27 Arnold D. Robbins + + * gawktexi.in: O'Reilly fixes. + And still more. Also, fix @code --> @command in a number of places. + +2015-01-26 Arnold D. Robbins + + * gawktexi.in: O'Reilly fixes. + +2015-01-25 Arnold D. Robbins + + * gawktexi.in: Fix a bad URL. And another one. + More O'Reilly fixes. + +2015-01-23 Arnold D. Robbins + + * gawktexi.in: O'Reilly fixes. + (Glossary): Many new entries from Antonio Giovanni Colombo. + +2015-01-21 Arnold D. Robbins + + * gawktexi.in: O'Reilly fixes. + Remove obsolete start/end of range indexing comments. + +2015-01-20 Arnold D. Robbins + + * gawktexi.in: O'Reilly fixes. + +2015-01-19 Arnold D. Robbins + + * 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 + + * 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 + + * gawktexi.in: Improve get_file documentation. + +2015-01-05 Andrew J. Schorr + + * gawktexi.in: Replace "Retrying I/O" with "Retrying Input", since this + feature pertains to input, not output. + +2015-01-04 Andrew J. Schorr + + * gawktexi.in: Document the get_file API function. + +2015-01-04 Andrew J. Schorr + + * 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 + + * gawktexi.in (Glossary): Really sort the items. + +2014-12-24 Arnold D. Robbins + + * gawktexi.in: Start documenting nonfatal output. + +2014-12-24 Arnold D. Robbins + + * 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. + + * texinfo.tex: Updated. + +2014-12-12 Arnold D. Robbins + + * gawktexi.in: Minor fix. + Thanks to Teri Price . + +2014-12-10 Arnold D. Robbins + + * gawktexi.in: More minor fixes. + +2014-12-09 Arnold D. Robbins + + * gawktexi.in: More minor fixes. + +2014-12-07 Arnold D. Robbins + + * gawktexi.in: Minor fixes. + +2014-12-06 Arnold D. Robbins + + * gawktexi.in: A minor fix. + +2014-12-05 Arnold D. Robbins + + * gawktexi.in: Various minor fixes and updates. + +2014-11-23 Arnold D. Robbins + + * gawktexi.in: Update that TZ env. var can influence mktime + in running program. Thanks to Hermann Peifer. + +2014-11-19 Arnold D. Robbins + + * gawktexi.in: Update that RFC 4180 documents CSV data. + +2014-11-17 Arnold D. Robbins + + * gawktexi.in: Copyedits applied. + +2014-11-02 Arnold D. Robbins + + * 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 + + * gawktexi.in: Document new extras directory containing shell startup + files to manipulate AWKPATH and AWKLIBPATH environment variables. + +2014-10-28 Arnold D. Robbins + + * gawk.1: Clarification that debugger reads stdin. + * gawktexi.in: Ditto, and correctly place the "Braces" entry in + the Glossary. Thanks to Antonio Colombo for that. + + Unrelated: + + * gawktexi.in: Restore use of @sc. Karl fixed makeinfo. :-) + +2014-10-25 Arnold D. Robbins + + * gawktexi.in: Minor typo fixes. + Fix discussion of \x, per note from Antonio Colombo. + +2014-10-17 Arnold D. Robbins + + * gawktexi.in: Fix date in docbook attribution for new Foreword; + thanks to Antonio Colombo for the catch. Update latest version + of gettext. + +2014-10-15 Arnold D. Robbins + + * gawk.1: Fix default value for AWKLIBPATH. + * gawktexi.in: Revised text for AWKPATH and AWKLIBPATH. + +2014-10-14 Arnold D. Robbins + + * gawktexi.in: Add new Foreword from Mike Brennan. + +2014-10-13 Arnold D. Robbins + + * gawktexi.in: Fix example outputs in chapter 2. + Improve description of SYMTAB. + +2014-10-12 Arnold D. Robbins + + * gawktexi.in: Revise doc for {INT,STR}_CHAIN_MAX. Remove Pat + Rankin from VMS duties (per his request). Add a small TeX fix + for the table in ch 16 for requesting values. + +2014-10-05 Arnold D. Robbins + + * gawktexi.in: Finished changes! + +2014-10-03 Arnold D. Robbins + + * gawktexi.in (EMRED): Renamed from EMISTERED to match original. + Thanks to Warren Toomey at TUHS for access to archives recording + the text. + +2014-10-02 Arnold D. Robbins + + * 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 + + * 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 + + * gawktexi.in: More fixes after reading through the MS. + +2014-09-29 Arnold D. Robbins + + * gawktexi.in: More fixes after reading through the MS. + And still more fixes. + +2014-09-28 Arnold D. Robbins + + * gawktexi.in: More fixes after reading through the MS. + Document the debugger's "where" command. + +2014-09-27 Arnold D. Robbins + + * gawktexi.in: Lots more fixes after reading through the MS. + +2014-09-23 Arnold D. Robbins + + * gawktexi.in: Rework the documentation of special files in + Chapter 5; some reordering as well as rewriting. + +2014-09-22 Arnold D. Robbins + + * gawktex.in: Continue fixes after reading through the MS. + +2014-09-21 Arnold D. Robbins + + * gawktex.in: Start on fixes after reading through the MS. + +2014-09-18 Arnold D. Robbins + + * gawktexi.in: Fix italics in quotations. Some docbook special + cases. + +2014-09-15 Arnold D. Robbins + + * gawktexi.in: Document that identifiers must use the English + letters. + +2014-09-14 Arnold D. Robbins + + * gawktexi.in: More edits during review, minor addition. + +2014-09-08 Arnold D. Robbins + + * gawktexi.in: Remove text that won't get used. + +2014-09-07 Arnold D. Robbins + + * gawktexi.in: Minor cleanups. + +2014-09-05 Arnold D. Robbins + + * gawktexi.in: Document builtin functions in FUNCTAB and in + PROCINFO["identifiers"]. + * gawk.1: Ditto. + + Unrelated: + + * gawktexi.in: More stuff from reviewer comments. + +2014-09-04 Arnold D. Robbins + + * gawktexi.in: Document that indirect calls now work on built-in + and extension functions. + * gawk.1: Same. + +2014-09-03 Arnold D. Robbins + + * gawktexi.in: Further fixes from reviews and bug reports. + +2014-09-02 Arnold D. Robbins + + * gawktexi.in: Corrections to walkthrough in debugger chapter. + Thanks to David Ward for the problem report. + +2014-09-01 Arnold D. Robbins + + * gawktexi.in: Add index entry for @ - @load, @include, + and indirect function calls. Thanks to "Kenny McKormack" in + comp.lang.awk. + +2014-08-29 Arnold D. Robbins + + * gawktexi.in: Continuing on reviewer comments, and other + bug fixes, miscellaneous improvements. + +2014-08-26 Arnold D. Robbins + + * gawktexi.in: Use a different mechanism to exclude + exercises. Remove use of LC_ALL in an example; doesn't seem + to be needed anymore. + + Unrelated: + + * gawktexi.in: Document that MirBSD is no longer supported. + +2014-08-25 Arnold D. Robbins + + * gawktexi.in: Exercises are excluded from print edition. + +2014-08-24 Arnold D. Robbins + + * gawktexi.in: Continuing on reviewer comments. + +2014-08-23 Arnold D. Robbins + + * gawktexi.in: Continuing on reviewer comments. + +2014-08-22 Arnold D. Robbins + + * gawktexi.in: Continuing on reviewer comments. + +2014-08-20 Arnold D. Robbins + + * gawktexi.in: Continuing on reviewer comments. + +2014-08-16 Arnold D. Robbins + + * gawktexi.in: Continuing on reviewer comments. + +2014-08-15 Arnold D. Robbins + + * gawktexi.in: Continuing on reviewer comments. + +2014-08-13 Arnold D. Robbins + + * gawktexi.in: Starting on reviewer comments. + Update acknowledgements. + +2014-08-12 Arnold D. Robbins + + * gawktexi.in: Cause div.awk to get into the example files. + +2014-08-06 Arnold D. Robbins + + * gawktexi.in: Misc minor additions. + +2014-08-03 Arnold D. Robbins + + * gawktexi.in: For sprintf %c document that if value is a valid + wide character, gawk uses the low 8 bits of the value. + + Unrelated: + + * gawktexi.in: Fix doc for API get_record - errcode needs to + be greater than zero. + +2014-07-24 Arnold D. Robbins + + * 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 + + * 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 + + * gawktexi.in (Bracket Expressions): Add a note about how to + match ASCII characters. Thanks to Hermann Peifer. + +2014-06-25 Arnold D. Robbins + + * gawktexi.in: Update permissions on copyright page per + latest maintain.texi. Add GPL to print version of book. + +2014-06-24 Arnold D. Robbins + + * 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 + + * gawktexi.in: Typo fixes and minor corrections. + +2014-06-19 Arnold D. Robbins + + * gawktexi.in: Add thanks to Patrice Dumas and to Karl Berry. + Per request from Hermann Peifer, try to clarify how local variables + in functions are initialized. + +2014-06-18 Arnold D. Robbins + + * gawktexi.in: Split 6.1.4 into subsections. Other minor fixes. + +2014-06-17 Arnold D. Robbins + + * gawktexi.in: Finish adding exercises. + Rework chapter 15 on floating point and MPFR. + Spell check. Fix menues. + +2014-06-16 Arnold D. Robbins + + * gawktexi.in: Start adding exercises. + +2014-06-15 Arnold D. Robbins + + * gawktexi.in: Finish up summaries. Improvements in mystrtonum(). + +2014-06-13 Arnold D. Robbins + + * gawktexi.in: Fix typos from changes of 3 June when macros were + added for filename, data file, etc. Ooops. + +2014-06-12 Arnold D. Robbins + + * gawktexi.in: More "Summary" sections. Through chapter 14. + +2014-06-11 Arnold D. Robbins + + * gawktexi.in: More "Summary" sections. Through chapter 10. + +2014-06-10 Arnold D. Robbins + + * gawktexi.in: Update docbook figure markup. + +2014-06-09 Arnold D. Robbins + + * gawktexi.in: More "Summary" sections. + Judiciously arrange for full xrefs in docbook in a few spots. + +2014-06-08 Arnold D. Robbins + + * gawktexi.in: Start adding "Summary" sections. + +2014-06-03 Arnold D. Robbins + + * gawktexi.in: Restore macros for file name vs. filename etc. + Go through @if... and @ifnot... and fix them up too. Other misc. + cleanup. + +2014-05-29 Arnold D. Robbins + + * gawktexi.in: Remove some obsolete bits, fix up some other + minor stuff. + +2014-05-27 Arnold D. Robbins + + * gawktexi.in: Edits through the end! + +2014-05-25 Arnold D. Robbins + + * gawktexi.in: Edits through Appendix A. + * gawktexi.in: Tweak nested lists for docbook. + +2014-05-24 Arnold D. Robbins + + * gawktexi.in (Staying current): New section. + +2014-05-22 Andrew J. Schorr + + * gawktexi.in (BEGINFILE/ENDFILE): Update doc for getline - any + redirected form is allowed inside BEGINFILE/ENDFILE. + +2014-05-21 Arnold D. Robbins + + * gawktexi.in: Add comments for where we need full xrefs in + docbook. + +2014-05-20 Arnold D. Robbins + + * gawktexi.in: Misc improvements for docbook, consistency + in table and figure captions. + +2014-05-17 Arnold D. Robbins + + * gawktexi.in: Edits through Chapter 16. + +2014-05-16 Arnold D. Robbins + + * gawktexi.in: Edits through Chapter 14. + +2014-05-15 Arnold D. Robbins + + * gawktexi.in: Fix displays for docbook, edits through Chapter 11. + +2014-05-14 Arnold D. Robbins + + * gawktexi.in: Fix real preface for docbook. + +2014-05-13 Arnold D. Robbins + + * gawktexi.in: Complete formatting for FOR_PRINT and not FOR_PRINT. + +2014-05-07 Arnold D. Robbins + + * gawktexi.in: Docbook edits for preface and parts. + Document AWKBUFSIZE. + +2014-05-05 Arnold D. Robbins + + * gawktexi.in: Editing progress. Through Chapter 9. + +2014-05-05 Michal Jaegermann + + * array-elements.fig: Fix subscripts to be aligned + horizontally. Regenerate the other files. + +2014-05-02 Arnold D. Robbins + + * gawktexi.in: Editing progress. Through Chapter 8. + * array-elements.eps, array-elements.fig, array-elements.pdf, + array-elements.png array-elements.txt: New files. + * Makefile.am (EXTRA_DIST): Add them. + +2014-04-30 Arnold D. Robbins + + * gawktexi.in: Editing progress. Through Chapter 5. + * gawktexi.in: Editing progress. Through Chapter 6 and into + Chapter 7. + +2014-04-29 Arnold D. Robbins + + * gawktexi.in: Editing progress. Through Chapter 3. + +2014-04-24 Arnold D. Robbins + + * gawktexi.in: Start on revisions. + +2014-04-17 Arnold D. Robbins + + * gawk.1: Remove the bit about single character programs overflowing + the parse stack. It doesn't seem to be true anymore. + +2014-04-08 Arnold D. Robbins + + * 4.1.1: Release tar ball made. + +2014-04-08 Arnold D. Robbins + + * texinfo.tex: Update to latest. + * awkcard.in: Update copyright, patchlevel in download. + * gawktexi.in: Update patchlevel, update month, spell check. + +2014-03-30 Arnold D. Robbins + + * gawktexi.in: Cleanups to docbook, finish math stuff. + +2014-03-28 Arnold D. Robbins + + * gawktexi.in: Minor cleanups to the indexing. + + Unrelated: + + * gawktexi.in: Merge in changes needed for creating valid + DocBook XML. Works with post-5.2 Texinfo and dblatex! + +2014-03-27 Arnold D. Robbins + + * gawktexi.in: Finish the massive indexing improvements such that + functions are indexed the way I want in TeX and the way Eli + wants in Info. + + Unrelated: + + * gawktexi.in: Add a note in extension chapter that lookup of + PROCINFO can fail. + +2014-03-27 Eli Zaretskii + + * gawktexi.in: First round of massive indexing improvements. + +2014-03-27 Antonio Giovanni Colombo + + * gawktexi.in: Redo all the examples using BBS-list to a different + file that doesn't use out-of-date concepts. + +2014-03-10 Arnold D. Robbins + + * gawktexi.in: Finish indexing improvements. (For now, anyway.) + + Unrelated: + + * gawk.1: Document the quote flag! (Better late than never.) + * awkcard.in: Update documentation of quote flag. + +2014-03-08 Arnold D. Robbins + + * gawktexi.in: Minor edits to the discussion of the memory allocation + functions. + +2014-03-08 Andrew J. Schorr + + * gawktexi.in: Document new extension API functions api_malloc, + api_calloc, api_realloc, and api_free. + +2014-03-07 Arnold D. Robbins + + * gawktexi.in: Indexing improvements. + +2014-03-02 John E. Malmberg + + * gawktexi.in: Remove paragraph about obsolete VMS + compilers. Update reference about building PCSI kit. + +2014-02-27 Arnold D. Robbins + + * gawktexi.in: Lots of small fixes throughout, update of + profiling output. Finished fixes needed before a release. + +2014-02-20 Arnold D. Robbins + + * gawktexi.in: Add a quote to the alarm clock program. + +2014-02-15 Arnold D. Robbins + + * texinfo.tex: Update to latest. + +2014-02-14 Arnold D. Robbins + + * gawktexi.in: Lots of small edits. + +2014-02-07 Arnold D. Robbins + + * gawktexi.in: More minor fixes, update UPDATE_MONTH. + +2014-02-03 Arnold D. Robbins + + * gawktexi.in: More minor fixes, in indexing. + +2014-02-03 Arnold D. Robbins + + * gawktexi.in, gawkinet.texi: Minor fixes, mostly in indexing. + * texinfo.tex: Update to latest. + +2014-01-31 Arnold D. Robbins + + * gawktexi.in: Add `()' to names of extension functions in indexing + commands and in one place in the text. Consistency, don'tcha know. + +2014-01-30 Arnold D. Robbins + + * gawktexi.in: Add a few missing STARTOFRANGE comments. + * gawk.1: Note that `(i, j) in array' doesn't work in for loops. + Update the copyright year. + +2014-01-28 Arnold D. Robbins + + * gawktexi.in: Update info for Anders Wallin. + +2014-01-25 Arnold D. Robbins + + * texinfo.tex: Updated to current version. + * gawktexi.in: Add magic stuff so that PDFs have "dark red" + links like before. + +2014-01-23 Arnold D. Robbins + + * gawktexi.in (Feature History): New node. + (Common Extensions): Update features now in mawk, too. + +2014-12-14 John E. Malmberg + + * gawktexi.in: Add information on building VMS PCSI kit. + +2014-01-03 Arnold D. Robbins + + * gawktexi.in (Full Line Fields): New node. + Update copyright year. + +2013-12-29 John E. Malmberg + + * gawktexi.in: VMS dynamic extensions. + +2013-12-26 Arnold D. Robbins + + * gawktexi.in: More minor additions / fixes. + (Bugs): Add John Malmberg for VMS. Other minor edits. + +2013-12-25 Arnold D. Robbins + + * gawktexi.in: Minor additions / fixes. + +2013-12-23 John E. Malmberg + + * gawktexi.in: Document the VMS exit status encoding. + +2013-12-21 Arnold D. Robbins + + * gawktexi.in (Additional Configuration Options): Document + the --disable-extensions option. + +2013-12-16 John E. Malmberg + + * gawktexi.in: Updates to VMS sections. + +2013-12-12 Arnold D. Robbins + + * gawktexi.in: Fix the presentation of asort() and asorti(). + Thanks to Andy Schorr for pointing out the problems. + +2013-11-28 Arnold D. Robbins + + * gawktexi.in: Update quotations to use @author, fix a few + placements of footnotes. + +2013-11-08 Arnold D. Robbins + + * gawktexi.in: Update the list of files included in the gawk + distribution and fix a few typos. + +2013-11-03 Arnold D. Robbins + + * gawktexi.in: Fix the section and subsection headings in + the Preface. Also change the short title page to just + "GNU Awk". + +2013-10-31 Arnold D. Robbins + + * gawktexi.in: Add @shorttitlepage command. + +2013-10-25 Arnold D. Robbins + + * gawktexi.in (Contributors): Update with more info. + (Distribution contents): Ditto. + General: Remove all hyphens when used with "multi" prefix. + +2013-10-22 Arnold D. Robbins + + * gawktexi.in (Other Environment Variables): Document GAWK_MSG_SRC + variable and fix documentation of *_CHAIN_MAX variables. + +2013-10-11 Arnold D. Robbins + + * gawktexi.in (Conversion, Printf Ordering): Better wording for + descriptions of CONVFMT. Thanks to Hermann Peifer. + +2013-09-29 Arnold D. Robbins + + * gawktexi.in (Other Versions): Updated info on MKS awk and + some other links. + +2013-09-24 Arnold D. Robbins + + * gawktexi.in (Readfile function): New node. + +2013-09-22 Arnold D. Robbins + + * 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 + + * gawk.1: Document that ENVIRON updates affect the environment. + * gawktexi.in: Ditto. + +2013-06-27 Arnold D. Robbins + + * texinfo.tex: Update from Karl, fixes a formatting problem. + * gawktexi.in (Conversions): Undo @w{} around @option{--posix}. + +2013-06-22 Arnold D. Robbins + + * gawktexi.in (Type Functions): Add more explanation to isarray(), + including that it makes no sense to call it at the global level. + +2013-06-03 Arnold D. Robbins + + * gawktexi.in: Make it crystal clear not to use delete with FUNCTAB, + or attempt to assign to it. + +2013-05-29 Arnold D. Robbins + + * gawktexi.in (Internal File Description): Add "devbsize" element + to stat data array. + +2013-05-27 Arnold D. Robbins + + * gawktexi.in: Sample filefuncs.c extension code: Change test from + ifdef HAVE_ST_BLKSIZE to HAVE_STRUCT_STAT_ST_BLKSIZE. + +2013-05-21 Arnold D. Robbins + + * gawktexi.in (Quick Installation): Add a paragraph advising to + run `make install'. Thanks to Hermann Peifer. + +2013-05-16 Arnold D. Robbins + + * gawktexi.in (gawkextlib): Add a note to use make install on + gawkextlib itself. Thanks to Hermann Peifer. + (Cut program): Fix test for skipping lines if -s was supplied. + Thanks to David Ward for the bug report. + +2013-05-09 Arnold D. Robbins + + * 4.1.0: Release tar ball made. + +2013-05-09 Arnold D. Robbins + + * gawktexi.in, gawk.1: Document that a regexp constant as the second + argument to index() produces a fatal error. + * gawktexi.in: More cleanups. Particularly, cleanup the index. + +2013-04-27 Arnold D. Robbins + + * gawktexi.in: Renamed from gawkman.texi. + Add a reference to Overton's IEEE Math book in MPFR chapter. + Thanks to Nelson Beebe for the recommendation. + * Makefile.am, sidebar.awk: Adjusted. + +2013-04-26 Arnold D. Robbins + + * gawkman.texi: Cleanup in MPFR and API chapters. + Also minor cleanup in design decisions. Add vim modeline. + * api-figure2.fig: Minor fix. + * api-figure2.eps, api-figure2.pdf, api-figure2.png: Regenerated. + +2013-04-24 Arnold D. Robbins + + * gawk.1: Finish cleanup pass. + * awkcard.in: Document that getline sets RT. + * gawkman.texi: Ditto. + +2013-04-23 Arnold D. Robbins + + * gawk.1: Start cleanup pass. + * awkcard.in: Minor addition. + * gawkman.texi: Minor fixes. + + * gawk.1, gawkman.texi: Document PROCINFO entries for API + major and minor versions. + +2013-04-21 Arnold D. Robbins + + * gawkman.texi: Update all the menus. Fix spelling errors. Remove + some unneeded fakenodes. + +2013-04-20 Arnold D. Robbins + + * awkcard.in: Clean up and bring up to date. + +2013-04-17 Arnold D. Robbins + + * Makefile.am (gawk.ps, gawkinet.ps): Set TEXINPUTS to point + at $(srcdir) to be able to include various figures if doing a + build not in the source directory. + +2013-04-16 Arnold D. Robbins + + * gawkman.texi: New file. This is now the real source for the + manual and gawk.texi is generated from it. + * sidebar.awk: New file to DTRT for sidebars in the manual. + * Makefile.am (EXTRA_DIST): Update. + (gawk.texi): Add new rule to create / update it if necessary. + +2013-04-16 Arnold D. Robbins + + * gawk.texi: Pretty much finish cleanup. Move i18n chapter to + after advanced features chapter. + * texinfo.tex: Updated to current in texinfo SVN. + +2013-04-15 Arnold D. Robbins + + * gawk.texi: Continue cleanup. + +2013-04-14 Arnold D. Robbins + + * gawk.texi: Add link to 'pawk' - awk for python. + Further cleanups. + +2013-04-12 Arnold D. Robbins + + * gawk.texi: Continue cleanup. + +2013-04-11 Arnold D. Robbins + + * gawk.texi: Continue cleanup. + +2013-04-04 Arnold D. Robbins + + * gawk.texi: Continue cleanup. + +2013-04-03 Arnold D. Robbins + + * gawk.texi: Continue cleanup. + +2013-04-02 Arnold D. Robbins + + * gawk.texi: Start a simple cleanup pass before the release. + +2013-03-15 Arnold D. Robbins + + * gawk.texi: Update URL for texinfo, fix a typo. + +2013-03-04 Arnold D. Robbins + + * gawk.texi (Getline/Pipe): Add a nice quote from BWK. + +2013-02-08 Arnold D. Robbins + + * gawk.texi: Restore centering of text images. + +2013-02-07 Arnold D. Robbins + + * gawk.texi (Other Versions): Remove the description of xmlgawk. + +2013-02-06 Arnold D. Robbins + + * gawk.texi: For Info output, don't use @center on text images + since the new makeinfo doesn't yet center the file as a block. + Thanks to Karl Berry for the diagnostic. + * gawk.1: Remove commented out doc for -m option which was for + compatibility with BWK awk. His awk dropped it back in 2007. + +2013-01-31 Arnold D. Robbins + + * api-figure2.txt, api-figure3.txt: Convert tabs to spaces. + * gawk.texi (Gory Details): Fix a command that new makeinfo doesn't + recognize. + (Conversion): Update example to be in POSIX mode. Thanks to + Hermann Peifer. + +2013-01-27 Arnold D. Robbins + + * gawk.texi (Dynamic Typing): Clarify that gawk dies after the + first fatal error on the test program. Thanks to Hermann Peifer. + +2013-01-21 Arnold D. Robbins + + * gawk.texi (Setting Precision): Fix a typo. 3.322 instead + of 3.332. Thanks to Hermann Peifer. + +2013-01-09 Arnold D. Robbins + + * gawk.texi: Minor edits to documentation for new inplace extension. + +2013-01-08 Andrew J. Schorr + + * gawk.texi: Add documentation for new inplace extension. + +2013-01-08 Arnold D. Robbins + + * gawk.texi, awkcard.in: Sync what mawk has. Main point of + interest is that mawk supports the three time functions. + +2013-01-06 Arnold D. Robbins + + * gawk.texi, awkcard.in: Add Git Hub info for BWK awk. + Update copyrights. + * gawk.texi: Add Software Tools quote in chapter on library functions. + +2012-12-25 Arnold D. Robbins + + * gawk.texi: Remove doc sym_constant() API function. + +2012-12-24 Arnold D. Robbins + + * 4.0.2: Release tar ball made. + +2012-12-23 Arnold D. Robbins + + * gawk.texi: Remove an incorrect comment. + * awkcard.in: Bump patch level. + +2012-12-18 Arnold D. Robbins + + * gawk.texi (Input Parsers): Add info on read_func. + +2012-12-16 Arnold D. Robbins + + * gawk.texi: Move design decisions on new API to appendix C. + Move section on old extensions to last in the same appendix. + +2012-12-15 Arnold D. Robbins + + * macros: Update to GPL Version 3 and add copyright year. + * texinfo.tex: Updated, from automake 1.12.6. + * gawk.texi (Derived Files): A few minor fixes. + +2012-12-09 Arnold D. Robbins + + * awkforai.txt: Changed content to be pointers to the article + to avoid copyright issues. + * gawk.texi: Updated description of awkforai.txt. + +2012-12-07 Arnold D. Robbins + + * gawk.texi (I/O Functions): Document that fflush() is now part + of POSIX. Fix in a few other places as well. + * awkcard.in: Update for fflush(). + +2012-12-03 Arnold D. Robbins + + * gawk.texi: Fix all @tex ... @end tex tables to use a different + control character than @ so that the new makeinfo won't + complain about them. Thanks to Karl Berry for the guidance. + (Old Extension Mechanism): New node. + +2012-12-01 Arnold D. Robbins + + * gawk.texi: API chapter. Sync with gawkapi.h + +2012-11-27 Arnold D. Robbins + + * gawk.texi: API chapter. Change command for making shared libs + to use gcc, not ld. Thanks to Nelson Beebe. + (I/O Functions): Document new behavior for fflush(). + * gawk.1: Update for fflush(). + * awkcard.in: Ditto. And some general cleanup. + +2012-11-24 Arnold D. Robbins + + * gawk.texi (Future Extensions): Point to TODO file in the + gawk dist. + (Implementation Limitations): New node, from old LIMITATIONS file. + +2012-11-22 Arnold D. Robbins + + * gawk.texi: In API chapter, document the full list of include + files that need to be included. + +2012-11-21 Arnold D. Robbins + + * gawk.texi: In API chapter, update behavior of stat function + in the filefuncs extension. Update the code example and prose + to match the current code. + +2012-11-19 Arnold D. Robbins + + * gawk.texi: In API chapter, update behavior of readdir extension. + +2012-11-16 Arnold D. Robbins + + * gawk.texi: Minor edits in API chapter. + Thanks to Nelson Beebe. + +2012-11-14 Arnold D. Robbins + + * gawk.texi: Minor edits in API chapter. + Thanks to Andrew Schorr. + +2012-11-06 Arnold D. Robbins + + * gawk.texi: Rearrange chapter order and separate into parts + using @part for TeX. Fix capitalization in @caption text. + (Variable Scope): Document that arrays can be local also. + Thanks to Denis Shirokov , for pointing out + the lack. + +2012-11-05 Arnold D. Robbins + + * gawk.texi: Semi-rationalize invocations of @image. + +2012-11-04 Arnold D. Robbins + + * gawk.texi: New chapter on extension API. + * api-figure1.pdf, api-figure2.pdf, api-figure3.pdf, + general-program.pdf, process-flow.pdf: New files. Again. + * Makefile.am (EXTRA_DIST): Update. Again. + +2012-11-03 Arnold D. Robbins + + * api-figure1.pdf, api-figure2.pdf, api-figure3.pdf: Removed. + * api-figure1.txt, api-figure2.txt, api-figure3.txt, + api-figure1.png, api-figure2.png, api-figure3.png: New files. + * Makefile.am (EXTRA_DIST): Update. + + * gawk.texi: Fix up images. + * general-program.pdf, process-flow.pdf: Removed. + * general-program.png, process-flow.png, + general-program.txt, process-flow.txt: New files. + * Makefile.am (EXTRA_DIST): Update. + +2012-10-31 Arnold D. Robbins + + * api-figure1.eps, api-figure1.fig, api-figure1.pdf, + api-figure2.eps, api-figure2.fig, api-figure2.pdf, + api-figure3.eps, api-figure3.fig, api-figure3.pdf: New files. + * Makefile.am (EXTRA_DIST): Add the above. + +2012-10-28 Arnold D. Robbins + + * gawk.texi (Glossary): Document cookie, some cleanup of + notes at the end. + +2012-10-19 Arnold D. Robbins + + * gawk.texi: More doc on SYMTAB. + +2012-10-05 Arnold D. Robbins + + * Makefile.am (LN, install-data-hook, uninstall-hook): Removed. No + longer needed since dgawk and pgawk are gone. + +2012-10-13 Arnold D. Robbins + + * Makefile.am: Add dgawk.1 to man page links created / removed + on install / uninstall. (On stable branch.) + +2012-10-02 Arnold D. Robbins + + * gawk.texi (Glossary). Correct the full name for `ISO' per + bug report from William Bresler . Add a link + to the ISO website. + + * gawk.texi, gawk.1, awkcard.in: Document FUNCTAB, SYMTAB, and + PROCINFO["identifiers"]. Including that delete does not work + on FUNCTAB and SYMTAB. + +2012-09-23 Arnold D. Robbins + + * gawk.texi (Nextfile Statement): Document that it's now part of POSIX + and update the title. + (Delete): Document that `delete array' is now part of POSIX. + * awkcard.in: Adjust coloring for nextfile and delete array. + +2012-09-07 Arnold D. Robbins + + * texinfo.tex: Updated to version 2012-09-05.06. + +2012-08-27 Arnold D. Robbins + + * gawk.texi: Minor edits, fix some spelling mistakes. + +2012-08-26 Arnold D. Robbins + + * gawk.texi: More edits to chapter on arithmetic. + Primarily English changes. + +2012-08-24 Arnold D. Robbins + + * gawk.texi: Emphasize more that floating point behavior is + not a language issue. Add a pointer to POSIX bc. + Move arithmetic chapter to later in the book, before chapter + on dynamic extensions. + +2012-08-17 Arnold D. Robbins + + * texinfo.tex: Update infrastructure to Automake 1.12.3. + +2012-08-14 Arnold D. Robbins + + * gawk.texi: Fixed a math bug in the chapter on multiple + precision floating point. Thanks to John Haque. + +2012-08-12 Arnold D. Robbins + + * gawk.texi: Merged discussion of numbers from Appendix C into + the chapter on arbitrary precision arithmetic. Did some surgery + on that chapter to organize it a little better. + +2012-08-10 Arnold D. Robbins + + * awkcard.in, gawk.1, gawk.texi: Updated. Mostly for new API stuff + but also some other things. + * gawk.texi (Derived Files): New node. + +2012-08-01 Arnold D. Robbins + + * Makefile.am (install-data-hook): Install a dgawk.1 link to the + man page also. Remove it on uninstall. + +2012-07-29 Andrew J. Schorr + + * gawk.texi: Document that RT is set by getline. + +2012-07-04 Arnold D. Robbins + + * gawk.texi, gawk.1, awkcard.in: Document that and(), or(), and + xor() can all take any number of arguments, with a minimum of two. + +2012-06-10 Andrew J. Schorr + + * gawk.texi: Rename gettimeofday function to getlocaltime, since + the new time extension will provide gettimeofday. + +2012-05-24 Andrew J. Schorr + + * gawk.texi, gawk.1: Replace references to dlload with dl_load. + But much more work needs to be done on the docs. + +2012-05-19 Andrew J. Schorr + + * gawk.texi, gawk.1: Document new -i option, and describe new default + .awk suffix behavior. + +2012-04-01 Andrew J. Schorr + + * gawk.texi: Replace documentation of removed functions update_ERRNO and + update_ERRNO_saved with descriptions new functions update_ERRNO_int, + update_ERRNO_string and unset_ERRNO. And fix a couple of examples + to use update_ERRNO_int instead of update_ERRNO. + +2012-03-26 Arnold D. Robbins + + * gawk.texi: Minor style edits. + +2012-03-21 Andrew J. Schorr + + * gawk.texi, gawk.1: Document new @load keyword. + +2012-03-20 Andrew J. Schorr + + * gawk.texi, gawk.1: Add AWKLIBPATH. + +2012-08-12 Arnold D. Robbins + + * gawk.texi (Ranges and Locales): Clarified ranges and + locales. Again. + +2012-08-05 Arnold D. Robbins + + * gawk.texi (PC Binary Installation): Document Eli Zaretskii's + site. + (Records): Update case of RS = "a". It only prints 1 if in + POSIX mode. Thanks to Jeroen Schot who first reported it. + +2012-07-20 Arnold D. Robbins + + * gawk.texi (Ranges and Locales): Clarified ranges and + locales. + +2012-07-13 Arnold D. Robbins + + * gawk.texi (Getline Notes): Discuss side effects in + argument expression. + +2012-06-29 Arnold D. Robbins + + * gawk.texi, awkcard.in: Latest mawk understands /dev/stdin. + +2012-04-27 Arnold D. Robbins + + * gawk.texi: Add that -b affects output. + +2012-04-27 Arnold D. Robbins + + * texinfo.tex: Update to latest from automake 1.12. + +2012-04-09 Arnold D. Robbins + + * texinfo.tex: Update to latest from automake 1.11.4. + +2012-04-11 John Haque + + * gawk.texi: Change RNDMODE to ROUNDMODE. + * gawk.1, awkcard.in: Ditto. + +2012-04-11 Arnold D. Robbins + + * gawk.texi: Change --arbitrary-precision to --bignum. + * gawk.1: Ditto. + * awkcard.in: Add --bignum, RNDMODE, PREC. + +2012-04-08 Arnold D. Robbins + + * gawk.texi: Editing on new chapter on arbitrary precision numbers. + +2012-03-31 John Haque + + * gawk.texi, gawk.1: Add text on support for arbitrary precision + numbers. + +2012-02-06 Arnold D. Robbins + + * gawk.texi, gawk.1: And some minor edits thereunto. + +2012-02-03 John Haque + + * gawk.texi, gawk.1: Add text on read timeout. + +2011-12-28 Arnold D. Robbins + + * awkcard.in, gawk.1: Minor edits after merge of executables. + +2011-12-21 John Haque + + * gawk.texi: Updated sections on profiling and debugging + after merging the exes. Document new options --debug and + --load, and add a sub-section on loading extension library. + * gawk.1: Same. + * awkcard.in: Same. + +2012-03-28 Arnold D. Robbins + + * 4.0.1: Release tar ball made. + +2012-02-10 Arnold D. Robbins + + * gawk.texi, awkcard.in: Bump patch level. + * texinfo.tex: Updated from Texinfo CVS. + +2011-12-06 Arnold D. Robbins + + * gawk.texi: Various typo fixes from mailing list. + +2011-11-10 Arnold D. Robbins + + * gawk.1: Fix some .BR to be .B. + +2011-11-08 Arnold D. Robbins + + * gawk.texi: Further improvement in the discussion of sorted array + traversal. Some sections reordered and text edited to suit. + +2011-11-06 Arnold D. Robbins + + * gawk.texi: Try to improve discussion of sorted array + traversal. + +2011-09-24 Arnold D. Robbins + + * gawk.1: Fix some spelling errors. Thanks to + Jeroen Schot . + * gawk.texi: Some minor fixes. + +2011-08-31 John Haque + + * gawk.texi: Updated gawk dynamic extension doc. + +2011-07-28 Arnold D. Robbins + + * gawk.texi (Gory Details): Restore text on historical behavior + etc. and add explanation on gawk 4.0.x. + +2011-07-17 Arnold D. Robbins + + * gawk.texi: Add reference in node Expressions to node Precedence, + based on suggestion from Dan Jacobson dated 4 Jun 2001. + +2011-07-17 Paul Eggert + + * gawk.texi: Warn up-front (indirectly) that plain gawk is not + compatible with SVR4 awk and with POSIX awk. Describe how + gawk differs from the GNU standard in its interpretation of + POSIXLY_CORRECT. (From mail dated 15 May 2001). + +2011-06-24 Arnold D. Robbins + + * Makefile.am (EXTRA_DIST): Add ChangeLog.0. + * 4.0.0: Remake the tar ball. + +2011-06-23 Arnold D. Robbins + + * ChangeLog.0: Rotated ChangeLog into this file. + * ChangeLog: Created anew for gawk 4.0.0 and on. + * 4.0.0: Release tar ball made. diff --git a/doc/ChangeLog.0 b/doc/ChangeLog.0 new file mode 100644 index 0000000..8b32325 --- /dev/null +++ b/doc/ChangeLog.0 @@ -0,0 +1,1032 @@ +Mon Jun 13 22:28:02 2011 Arnold D. Robbins + + * gawk.texi: Document that POSIX now says [a-z] is undefined outside + the C and POSIX locales, so gawk treats it as the Good Lord intended + in all cases. Thanks to Paul Eggert for letting me know about this + and providing URLs to cite. + +Fri May 27 09:59:38 2011 Arnold D. Robbins + + * gawk.1, gawk.texi: Minor edits w.r.t. the bug reporting address. + +Wed May 25 22:03:53 2011 Arnold D. Robbins + + * gawk.1, gawk.texi: Straighten out owners of the different + Windows ports. + +Thu May 19 17:52:46 2011 Arnold D. Robbins + + * gawk.texi: Igawk, have pathto check for "-". + Thanks to Steffen Schuler , + from email dated 27, December 2008. + +Thu May 19 16:57:28 2011 Arnold D. Robbins + + * gawk.texi, gawk.1, awkcard.in: Revised to reflect the reality + that -d and -p don't allow a space before the file name. + Thanks to Pat Rankin. + +Mon May 16 16:40:50 2011 Arnold D. Robbins + + * gawk.texi: Remove last vestiges of old PROCINFO sorting + description. + +Mon May 9 15:58:33 2011 Arnold D. Robbins + + * gawk.texi: Finish array sorting and do a spell check. + +Fri May 6 13:21:20 2011 Arnold D. Robbins + + * gawk.texi: Finish edits after full read through. + * gawk.1: Update array sorting information. + +Wed May 4 23:39:09 2011 Arnold D. Robbins + + * gawk.texi: Start at revamping array sorting doc. Still + needs work. + +Wed Apr 27 21:49:23 2011 Arnold D. Robbins + + * gawk.1: Minor edit. + * awkcard.in: Document third arg to asort and asorti. + +Thu Apr 7 21:55:27 2011 Arnold D. Robbins + + * gawk.texi (Nextfile Function): Removed, along with all references, + since only gawk and MKS awk allow next from a function, so this + function was useless for most people. Strange that noone noticed. + I wonder who really reads the doc? + + Lots of other fixes have been going in too. + +Sun Mar 27 21:10:55 2011 Pat Rankin + + * gawk.texi (Builit-in Variables: PROCINFO array, Scanning All + Elements of an Array: `for' statement): Update the documentation + for PROCINFO["sorted_in"]; add "ascending index number", + "descending index string", "ascending value", and "descending + value" as supported sort orderings. + * gawk.1 (PROCINFO array): Update PROCINFO["sorted_in"] to + reflect that the value matters, and list the supported sort orders. + +Tue Feb 15 17:11:26 2011 Pat Rankin + + * gawk.texi (Builit-in Variables: PROCINFO array, Scanning All + Elements of an Array: `for' statement): Document that the value + of PROCINFO["sorted_in"] matters; sort orders "ascending index + string", "descending index string", and "unsorted" are supported. + +Sun Feb 13 19:58:35 2011 Arnold D. Robbins + + * awkcard.in, gawk.1, gawk.texi, gawkinet.texi: Fix typos + and spelling errors. + +Thu Feb 10 21:48:18 2011 Pat Rankin + + * gawk.texi: Update VMS section. + +Thu Feb 10 21:31:36 2011 Andreas Buening + + * gawk.texi: Update OS/2 information. + +Thu Feb 10 21:06:14 2011 Arnold D. Robbins + + * lflashlight-small.xpic: Renamed from lflashlight.small.xpic. + * rflashlight-small.xpic: Renamed from rflashlight.small.xpic. + * Makefile.am (EXTRA_DIST): Adjusted. + +Tue Feb 1 10:21:22 2011 Arnold D. Robbins + + * gawk.texi, awkcard.in, gawk.1: Document isarray function, + magic string in PROCINFO for array sorting. Needs a little + more work in gawk.texi. + +Mon Jan 10 21:52:21 2011 Arnold D. Robbins + + * lflashlight.small.xpic, rflashlight.small.xpic: Original + source files for flashlight files from xpic tool. + It only took over 10 years to put them into the dist. + * Makefile.am (EXTRA_DIST): Add the new files. + +Thu Jan 6 22:13:11 2011 Arnold D. Robbins + + * gawk.texi: Replace xpic figures in Appendix D with figures + from xfig. + * general-program.eps, general-program.fig, general-program.pdf, + process-flow.eps, process-flow.fig, process-flow.pdf: New files. + * Makefile.am (EXTRA_DIST): Add the new files. + +Wed Jan 5 14:33:51 2011 Arnold D. Robbins + + * Makefile.am: Sanitize making of different PDF files. + +Sun Jan 2 20:30:37 2011 Arnold D. Robbins + + * texinfo.tex: Update to latest from texinfo CVS repository. + +Tue Dec 28 21:46:21 2010 Arnold D. Robbins + + * README.DGAWK: Removed, since there is now a chapter on the + debugger. + * Makefile.am (EXTRA_DIST): Remove README.DGAWK. + +Tue Dec 28 07:13:20 2010 John Haque + + * gawk.texi: Update dgawk examples. Document condition command + without an expression. Fix a typo. + +Tue Dec 21 10:06:05 2010 Arnold D. Robbins + + * Makefile.am (pdf): Renamed from `all-pdf'. Much more logical + and easier to remember. + +Sat Dec 18 20:14:58 2010 Eli Zaretskii + + * gawk.texi (DOS Quoting): Fix a typo. + (Top, PC Installation): Remove "PC Dynamic" from the menus. + (PC Installation, PC Compiling, PC Using): Remove obsolete stuff. + Fix whitespace between sentences. Add indexing. + (PC Testing): New node, stuff moved from "PC Compiling". + (PC Dynamic): Node removed. + (Cygwin): Fix wording. + (MSYS): Fix whitespace between sentences. + +Thu Dec 9 22:27:53 2010 Arnold D. Robbins + + * awkcard.in, gawk.1, gawk.texi, gawkinet.texi: Remove discussion + of raw option in making sockets, since it was never implemented. + +Wed Dec 1 21:39:15 2010 Arnold D. Robbins + + * awkcard.in, gawk.1: Document arrays of arrays. + * gawk.texi: General progress. + +Mon Nov 8 22:24:21 2010 Arnold D. Robbins + + * gawk.1: Minor fix from Jari Aalto + to help Emacs fontification. + +Tue Nov 2 12:15:56 2010 Arnold D. Robbins + + * awkcard.in, gawk.1, gawk.texi: --lint --> -L, + --lint-old --> -t. + +Mon Nov 1 22:01:26 2010 Arnold D. Robbins + + * awkcard.in, gawk.1, gawk.texi: -l renamed -t. + +Sat Oct 30 05:53:25 2010 John Haque + + * gawk.texi: Added section on Array of Arrays. + +Sat Oct 23 20:36:58 2010 Arnold D. Robbins + + * awkcard.in: Updated, cleaned up. + * gawk.1: Updated, some clean up. + +Wed Sep 22 05:29:43 2010 Arnold D. Robbins + + * gawk.texi: Added section on @include files. + +Wed Aug 18 22:14:19 2010 Arnold D. Robbins + + * gawk.texi: Minor edits. + * Makefile.am (LN): Use `ln -f' when installing link for + pgawk.1. Thanks to Peter Breitenlohner . + +Thu Jul 1 21:29:25 2010 Arnold D. Robbins + + * gawk.texi, gawk.1, awkcard.in: Document `/inet4' and `/inet6'. + +Sun Jun 27 21:58:47 2010 Arnold D. Robbins + + * gawk.texi, gawk.1, awkcard.in: Document all short options. + +Wed Jun 2 22:06:22 2010 Arnold D. Robbins + + * gawk.texi, gawk.1, awkcard.in: Document FPAT variable and patsplit + function. + +Fri Jun 12 13:28:24 2009 Arnold D. Robbins + + * gawk.texi, gawk.1: Remove --disable-directories-fatal configuration + option. + +Thu Feb 26 20:36:18 2009 Arnold D. Robbins + + * gawk.texi, gawk.1, awkcard.in: Document BEGINFILE and ENDFILE. + +Mon Feb 16 21:53:22 2009 Arnold D. Robbins + + * gawk.texi: Document switch statements as always available. + * gawk.1: Ditto. + * awkcard.in: Ditto. + +Thu Feb 12 22:36:32 2009 Arnold D. Robbins + + * gawk.texi: Document that interval expressions are now on by default. + Also that --gen-po is now --gen-pot. + * gawk.1: Ditto. + * awkcard.in: Ditto. + +Sat Jan 17 20:03:43 2009 Arnold D. Robbins + + * gawk.texi: Document indirect function calls. + * gawk.1: Ditto. + * awkcard.in: Ditto. + +Tue Dec 30 22:22:04 2008 Assaf Gordon + + * gawk.texi: Document new --sandbox option. + * gawk.1: Ditto. + * awkcard.in: Ditto. + +Tue Dec 30 22:21:11 2008 Arnold D. Robbins + + * gawk.texi: Change --binary to --characters-as-bytes, per Karl Berry. + * gawk.1: Ditto. + * awkcard.in: Ditto. + +Thu Dec 18 05:30:13 2008 Steffen Schuler + + * gawk.texi: Documented fourth parameter of split(). + * gawk.1: Ditto. + * awkcard.in: Ditto. + +Thu Dec 18 05:16:48 2008 Arnold D. Robbins + + * gawk.texi: Minimally document `-b' / --binary. + * gawk.1: Ditto. + * awkcard.in: Ditto. + +Sun Nov 16 22:03:50 2008 Arnold D. Robbins + + * gawk.texi: Fully documented `-r' as synonym for --re-interval. + * gawk.1: Ditto. + * awkcard.in: Ditto. + +Tue Aug 3 13:35:15 2004 Arnold D. Robbins + + * gawk.texi: Document that gawk now uses the 2001 POSIX + rules for `sub' and `gsub'. + +Wed Dec 26 22:15:05 2001 Arnold D. Robbins + + * gawk.texi: Documented that process special files are gone. + * gawk.1: Ditto. + * awkcard.in: Ditto. + +Thu May 6 20:55:14 2010 Arnold D. Robbins + + * Release 3.1.8: Release tar file made. + +Tue Apr 20 11:48:31 2010 Arnold D. Robbins + + * texinfo.tex: Update to latest from texinfo git repository. + * gawk.texi, gawk.1, awkcard.in: Update version and copyright dates. + +Thu Mar 25 21:51:58 2010 Arnold D. Robbins + + * gawk.1: Clarify the socket timeout environment variables. + +Wed Mar 10 21:28:12 2010 Arnold D. Robbins + + * gawk.texi: Reworded 'index in array' so that there's no chance of + someone using 'index' as a real subscript. Thanks to Hermann + Peifer for the push. + +Thu Feb 4 20:54:48 2010 Arnold D. Robbins + + * gawk.texi: Multiple cleanups and bringing of things up to date. + * gawk.1: Ditto, only not as much. + * Makefile.am: New `all-pdf' target to make PDF files of manpage + and reference card. + +Tue Aug 4 06:07:35 2009 Arnold D. Robbins + + * gawk.texi, gawk.1, awkcard.in: Document that 0 flag in + printf applies only to the numeric formats. + +Tue Aug 4 05:58:52 2009 Arnold D. Robbins + + * texinfo.tex: Updated to current version. + +Tue Jul 21 22:28:56 2009 Arnold D. Robbins + + * Release 3.1.7: Release tar file made. + +Tue Jul 21 22:20:25 2009 Arnold D. Robbins + + * gawk.texi, awkcard.in: Update mawk site information now + that Thomas Dickey is maintaining it. + +Mon Jul 13 07:53:32 2009 Arnold D. Robbins + + * Makefile.am (SEDME2): New macro, used in making awkcard.ps, + removes last empty page. Finally! + +Fri Jul 10 10:35:29 2009 Arnold D. Robbins + + * awkcard.in: Rearrange items for better formatting and + organization. + * gawk.texi (Exit Status): New node to document exit values. + (Exit Statement): Give portability advice about exit value. + +Wed Jul 8 08:55:50 2009 Arnold D. Robbins + + * awkcard.in: Really fix table option for --verbose. Other + fixes and improvements, including document %'d flag. + +Tue Jul 7 09:13:02 2009 Arnold D. Robbins + + * awkcard.in: Fix table option for --verbose. + +Mon Jun 8 00:40:26 2009 Tommi Vainikainen + + * gawk.1: Bug fix to restore space between paragraphs at + entry for "--". + +Thu May 21 21:09:59 2009 Arnold D. Robbins + + * gawk.1, awkcard.in: Document new -O / --optimize option. + * gawk.texi (Options): Likewise. + +Fri May 15 14:34:37 2009 Arnold D. Robbins + + * gawk.texi (User-defined): Document that you can't use + the name of a built-in variable as a function parameter. + +Sat May 2 23:36:10 2009 Arnold D. Robbins + + * gawk.texi (Other Versions): Add Quiktrim awk. + (How to Contribute): Change things to point to awk.info. + +Mon Apr 6 22:29:47 2009 Arnold D. Robbins + + * awkcard.in: Bell Labs awk also supports fflush() + and fflush(""). Thanks to Steffen Schuler + . + +Mon Mar 30 21:26:04 2009 Arnold D. Robbins + + * gawk.texi (Simple Server): Fix bug since 3.1.0 where error + message from typo was in the middle of the HandleGet function. + Thanks to Tim Menzies for catching this. + +Mon Feb 9 22:11:16 2009 Arnold D. Robbins + + * gawk.texi (Translate Program): Bug fix in stranslate + function from Steffen Schuler . + +Tue Feb 3 22:06:10 2009 Arnold D. Robbins + + * gawk.texi (Regexp Field Splitting): Documented dark corner + of ^ in FS. + +Sat Jan 17 20:37:12 2009 Arnold D. Robbins + + * gawk.texi (Plain Getline): Bug fix in code. Thanks to + Steffen Schuler . + +Mon Jan 5 22:47:42 2009 Arnold D. Robbins + + * gawk.1, awkcard.in: Document that getline returns 1 + on sucess. Thanks to Paolo for + the report. + +Fri Dec 26 14:45:39 2008 Arnold D. Robbins + + * gawk.texi, gawkinet.texi: Update to FDL 1.3. + +Mon Dec 1 21:20:39 2008 Arnold D. Robbins + + * gawk.texi (File Checking): Correct the text at the end; getline + isn't fatal, period, not related to POSIX. Thanks to + Seb for pointing this out. + (Round-Function): Change initial return when equal to return ival, + which lops off any digits, e.g. if given 121.0. Thanks to + Timothy J. Stefanski . + +Fri Aug 1 17:34:55 2008 Arnold D. Robbins + + * gawk.texi (Signature Program): Added new subsection. + +Thu Jul 31 21:38:08 2008 Arnold D. Robbins + + * gawk.texi (Variable Typing): Document that array elements created + by `match' also get strnum attribute. + +Mon Jun 2 22:47:08 2008 Arnold D. Robbins + + * gawk.texi (Control Letters): Add a note about %c only + taking values from 0 to 255. + (DOS Quoting): New node. + +Thu Jan 31 16:17:27 2008 Arnold D. Robbins + + * gawk.texi, gawkinet.texi: Updated the Back-Cover text per + latest from the FSF. + +Fri Jan 25 12:13:39 2008 Dave Pitts + + * gawk.texi (pwcat.c, grcat.c): Added ZOS_USS changes. + +Mon Jan 14 05:30:16 2008 Arnold D. Robbins + + * gawk.texi: Add maintainer contact info for z/OS. + +Mon Oct 22 08:49:05 2007 Arnold D. Robbins + + * Release 3.1.6: Release tar file made. + +Fri Oct 19 04:13:33 2007 Arnold D. Robbins + + * gawk.1: Add length(array) to list of extensions at end. + Revise date. + +Thu Oct 18 08:40:59 2007 Arnold D. Robbins + + * texinfo.tex: Updated to version from Texinfo 4.11. + +Sun Oct 14 20:37:59 2007 Arnold D. Robbins + + * awkcard.in: Fix version numbers and copyright info, minor + cleanups to format nicely. + +Sun Sep 30 22:30:05 2007 Arnold D. Robbins + + * gawk.texi (Conversion): Add table describing locale decimal + point versus period. + +Sat Sep 8 23:53:46 2007 Arnold D. Robbins + + * gawk.texi: A number of minor fixes based on suggestions + from Jack Kelley . + +Sat Aug 11 22:46:14 2007 Arnold D. Robbins + + * gawk.texi (Copying): Move to GPL 3. + +Wed May 30 17:11:19 2007 Arnold D. Robbins + + * Makefile.am (CLEANFILES): Added, so that even "make distclean" + will do the right thing. + (clean): Removed, let automake to do it. + +Tue May 29 22:49:16 2007 Arnold D. Robbins + + * gawk.texi: Document --use-lc-numeric. Document that some + VMS systems come with an old version of gawk. + +Mon May 28 08:21:51 2007 Arnold D. Robbins + + * gawk.1, awkcard.in: Document --use-lc-numeric. + +Tue May 15 13:27:38 2007 Arnold D. Robbins + + * gawk.texi, gawk.1: Documented --disable-directories-fatal + configure option. + +Wed May 9 21:50:44 2007 Arnold D. Robbins + + * gawk.1: Reviewed and updated, minor typos fixed. + * awkcard.in: Added mention of %F. + +Wed May 2 19:55:02 2007 Arnold D. Robbins + + * gawk.texi: Cleaned up discussion of string concatenation + where needed, including a note about the mixed treatment + of `"echo " "date" | getline'. Sigh. + +Sun Apr 29 13:33:27 2007 Arnold D. Robbins + + * gawk.texi (Time Functions): Update description of strftime + for third utc-flag argument. Other minor fixes. + * gawk.1, awkcard.in: Same. + +Tue Apr 3 22:47:40 2007 Arnold D. Robbins + + * gawk.texi (New Ports): Update list of files for all of + regex that should not be messed with lightly. + +Wed Mar 21 09:02:53 2007 Arnold D. Robbins + + * gawk.texi: Removed last vestiges of arnold@gnu.org + email address. + +Wed Mar 7 13:06:31 2007 Arnold D. Robbins + + * gawk.texi (Getopt Function): Add a note that user level + code must clear out ARGV from 1 to Optind. + Thanks to Matthew.Hall1@VerizonWireless.com, from mail + dated Tue, 02 Aug 2005 09:04:37 -0700. + +Wed Mar 7 08:48:02 2007 Arnold D. Robbins + + * gawk.texi: Fix my personal email address. Sheesh. + Thanks again to Sahak Petrosyan . + +Tue Mar 6 09:13:38 2007 Arnold D. Robbins + + * gawk.texi: Fix link to online version of the manual. + Thanks to Sahak Petrosyan . + +Wed Feb 14 19:40:33 2007 Arnold D. Robbins + + * gawk.texi: Add discussion of magic values for Inf, NaN, + and hexadecimal floating point in appendix on numbers. + Other minor updates for date, trademarks, etc. + +Sun Jan 21 12:59:33 2007 "Ennio-(Sr)" + + * gawk.1: Add note that locale settings can influence the + choice of decimal point character. + +Sat Jan 13 22:43:39 2007 Ralf Wildenhues + + * gawk.texi: Fix some typos. + * gawkinet.texi: Likewise. + +Sat Jan 13 21:25:28 2007 Ralf Wildenhues + + * awkcard.in: next is POSIX. + * gawk.texi: V7/SVR3.1: Mention assignable `$0', `var in index' + as expression. Specify `FS' limitation. + +Fri Jan 12 12:28:51 2007 Arnold D. Robbins + + * texinfo.tex: Updated upon move to current autotools. + +Thu Jan 4 19:56:45 2007 Arnold D. Robbins + + * gawk.1: Applied patch from Eric Raymond to stop his stupid + automated email kvetching about the wonders of docbook. + +2006-07-29 Paul Eggert + + * gawk.texi: Document that `$$0++--' isn't valid even though it + is unambiguous according to the Awk grammar. This is in response + to Open Group XCU ERN 86 + . + +Fri Oct 21 12:50:19 2005 Arnold D. Robbins + + Better support for PDF, thanks to Marty Leisner + for the prodding. + + * Makefile.am: Add lflashlight.pdf, rflashlight.pdf, statist.pdf + to EXTRADIST and add gawk.pdf and gawkinet.pdf to list of files + to remove for `clean'. + * lflashlight.pdf, rflashlight.pdf, statist.pdf: New files, created + with `epstopdf foo.eps > foo.pdf'. + +Tue Jul 26 21:46:16 2005 Arnold D. Robbins + + * Release 3.1.5: Release tar file made. + +Sun Jun 26 16:24:07 2005 Arnold D. Robbins + + * gawk.texi: Document `length(array)'. + * gawk.1: Ditto. + * awkcard.in: Ditto. + +Mon May 23 20:56:32 2005 Arnold D. Robbins + + * gawk.texi: Removed references to `--with-included-gettext'. + +Fri Apr 1 06:25:30 2005 Arnold D. Robbins + + * texinfo.tex: Updated to version 2005-01-30.17. + +Wed Feb 9 11:39:38 2005 Arnold D. Robbins + + * Makefile.am: Per Stepan Kasal, removed html rules, since + Automake does it for us. + +Tue Jan 4 18:47:34 2005 Arnold D. Robbins + + * texinfo.tex: Updated to version 2004-11-25.16. + +Mon Jan 3 14:09:57 2005 Arnold D. Robbins + + * texinfo.tex: Updated to version 2004-10-31.06. + +Wed Sep 22 11:40:06 2004 Arnold D. Robbins + + * gawk.1, gawk.texi, awkcard.in: Documented new --exec option. + +Mon Aug 2 12:18:15 2004 Arnold D. Robbins + + * Release 3.1.4: Release tar file made. + +Wed Jul 28 17:03:16 2004 Arnold D. Robbins + + * Makefile.am (TROFF): Add -U flag to invocation. Makes it + possible to format ref card from a build directory that isn't + the source directory. + (distclean): Removed target. Let automake handle it. + +Tue Jun 15 12:21:09 2004 Arnold D. Robbins + + * texinfo.tex: Updated to version 2004-06-14.14. + * gawk.texi (Dynamic Extensions): Text revised to follow + current implementation: new APIs, info on `n->param_cnt' + fixed. + + Also in all index entries where comma does not separate + primary, secondary or tertiary terms, replaced the comma + with @comma{} and removed the corresponding comments. + +Mon May 31 09:11:01 2004 Arnold D. Robbins + + * ad.block, awkcard.in, cardfonts, colors, no.colors: Change + old email address to current one. + +Mon May 3 09:54:46 2004 Arnold D. Robbins + + * texinfo.tex: Updated to version from Automake 1.8.4. + +Mon Mar 22 10:53:13 2004 Arnold D. Robbins + + * texinfo.tex: Updated. + +Tue Jan 6 17:38:40 2004 Arnold D. Robbins + + * texinfo.tex: Updated. + * gawk.texi: All @strong{Note:} changed to `@quotation NOTE'. + +Mon Jul 7 11:01:43 2003 Arnold D. Robbins + + * Release 3.1.3: Release tar file made. + +Mon Jun 9 16:06:30 2003 Arnold D. Robbins + + * gawk.texi: Set automatic-xref-title and change all cross + references to be of the single-argument type. Made all + @node lines have just the node name. + + Should have done both of these years ago. + +Sun May 11 16:08:58 2003 Arnold D. Robbins + + * Makefile.am (html, gawk.html, gawkinet.html): New targets. + +Mon Mar 31 17:15:23 2003 Arnold D. Robbins + + * Makefile.am (install-data-hook, uninstall-hook): Added code to + hard link gawk.1 to pgawk.1 upon install and remove pgawk.1 upon + uninstall. Avoids MANPATH search problems, etc. etc. + (man_MANS): Removed pgawk.1 from the list. + * pgawk.1: Removed. + +Wed Mar 19 14:10:31 2003 Arnold D. Robbins + + This time for sure. + -- Bullwinkle + + * Release 3.1.2: Release tar file made. + +Tue Mar 11 11:22:36 2003 Arnold D. Robbins + + * Makefile.am (man_MANS): Add pgawk.1. + * pgawk.1: New file, does `.so gawk.1' so that `man pgawk' will work. + Thanks to Nelson Beebe for pointing the need for this. + +Sun Feb 9 09:45:06 2003 Arnold D. Robbins + + * gawk.texi, gawkinet.texi: Per Karl Berry, change dircategory + to follow current standards. In gawkinet.texi, remove + bracketing ifinfo. + +Thu Feb 6 12:06:22 2003 Arnold D. Robbins + + * texinfo.tex: Updated to version 2003-02-03.16 from Texinfo 4.5. + +Tue Feb 4 15:21:46 2003 Arnold D. Robbins + + * awkcard.in: Redid the page-breaking. + +Tue Feb 4 14:28:06 2003 Arnold D. Robbins + + All relevant files: Copyright year updated to 2003. + +Sun Jan 26 11:13:01 2003 Arnold D. Robbins + + * texinfo.tex: Updated to version 2003-01-24.17 from prep. + * gawk.texi: Documented asorti(), new elements in match() 3rd arg, + misc cleanups. Updated to FDL 1.2. + * awkcard.in, gawk.1: Ditto for asorti(), match(). + * gawkinet.texi: Updated to FDL 1.2. + +Thu Jan 16 18:34:54 2003 Arnold D. Robbins + + * texinfo.tex: Updated to version 2003-01-12.11 from prep. + +Sun Nov 24 17:55:23 2002 Arnold D. Robbins + + * texinfo.tex: Updated to version 2002-11-05.11 from Texinfo 4.3. + +Sun Nov 17 21:34:35 2002 Arnold D. Robbins + + * texinfo.tex: Updated to version 2002-10-13.14 from automake 1.7.1. + +Fri Nov 1 11:25:00 2002 Arnold D. Robbins + + From Kaveh Ghazi: + + * gawk.texi (grcat.c): Include stdlib.h. + (main): Fix format specifier warnings. + * gawk.texi (pwcat.c): Include config.h/stdlib.h. + (main): Fix format specifier warnings. + +Tue Jun 11 23:08:04 2002 Arnold D. Robbins + + * gawk.texi: Fix grcat code ifdef for HAVE_GETGRENT. + +2002-05-09 Paul Eggert + + [ ADR: Some minor post-patch editing was required. ] + + * gawk.texi (igawk): Do not put temporary files in /tmp, as that + has some security problems. This fixes a problem originally + reported by Jarno Huuskonen via solar@openwall.com. + + Fix the following problems with igawk while we're at it. + + * Report missing operands of options; this fixes e.g. an + infinite loop with "igawk -W". + + * Check for --source and -Wsource only, not -.source (which matches + errors). Similarly for other multichar options. + + * Do not use 'echo', as that mishandles backslashes. + +Mon May 13 01:25:40 2002 Arnold D. Robbins + + * gawkinet.texi: Change `ifinfo' to `ifnottex' around + the Top node. Thanks to Eli Zaretskii. + +Wed May 1 16:41:32 2002 Arnold D. Robbins + + * Release 3.1.1: Release tar file made. + +Tue Apr 16 13:26:13 2002 Arnold D. Robbins + + * gawk.texi: FINALLY. All O'Reilly production and + indexing changes integrated. Index reviewed and + cleaned up. + * gawkinet.texi: Ditto. + * awkcard.in: Redid page breaking. + * Makefile.am (clean): Add `awkcard.tr' to list of files + that are removed. + (distclean): Depend on clean to REALLY GET `awkcard.tr'. + Sheesh. + +Mon Apr 15 14:43:51 2002 Arnold D. Robbins + + * texinfo.tex: Updated to version from Texinfo 4.2. + * gawk.texi: Modified to use new @copying command. + * gawkinet.texi: Ditto. + +Wed Mar 20 17:07:50 2002 Arnold D. Robbins + + * texinfo.tex: Updated to version from Texinfo 4.1. + +2002-02-10 Paul Eggert + + * gawk.texi (Word Sorting): Don't use sort +1, as POSIX 1003.1-2001 + no longer allows it. Use sort -k instead. + +2002-01-27 Bruno Haible + + * gawk.texi: Document the dcngettext function. + * awkcard.in: Likewise. + * gawk.1: Likewise. + +Mon Jan 28 18:41:02 2002 Arnold D. Robbins + + * gawkinet.texi, Makefile.am: Removed User Friendly cartoon. + Sigh. + +Wed Dec 19 16:00:39 2001 Eli Zaretskii + + * gawk.texi (Profiling): Describe the signals used for profile + dumping in the DJGPP version. + +Mon Sep 3 18:30:13 2001 Arnold D. Robbins + + * gawk.texi (Top): Put in @ifnottex so that makeinfo + --html is now happy. + +Sun Jun 3 13:04:44 2001 Arnold D. Robbins + + * Release 3.1.0: Release tar file made. And there was + rejoicing. + +Mon May 14 19:57:31 2001 Arnold D. Robbins + + * gawk.texi, gawkinet.texi: Versions for distribution + put in place. + * gawk.1, awkcard.in: Minor edits for consistency of + usage, formatting. + +Wed Nov 22 14:57:59 2000 Arnold D. Robbins + + * gawk.texi, gawk.1, awkcard.in: Removed all documentation + of abort. + +Sun Aug 13 11:23:50 2000 Arnold D. Robbins + + * gawk.texi, gawk.1, awkcard.in: documented sort function + and optional third argument to match. + +Sun Aug 13 00:40:41 2000 Arnold D. Robbins + + * gawk.texi: hardwired publisher info. + * publisher.texi: Removed. Not needed any more. + * gawkinet.texi: Added title page stuff. + +Thu Jul 5 21:05:57 2000 Arnold D. Robbins + + * gawk.texi: moved to use of @command, @option everywhere + appropriate. Removed all @page and @group in anticipation + of re-page breaking. Updated stuff for install-info. + Added FDL. + +Tue Nov 10 11:42:26 1998 Arnold D. Robbins + + * publisher.texi: new file with publisher related info. + * Makefile.in: updated dvi and postscript targets to make + them lots smarter about not reformatting if need be. + +Mon Aug 7 15:23:00 2000 Arnold D. Robbins + + * Release 3.0.6: Release tar file made. + +Sun Jun 25 15:08:19 2000 Arnold D. Robbins + + * Release 3.0.5: Release tar file made. + +Wed May 17 19:04:54 2000 Arnold D. Robbins + + * gawk.texi, gawk.1, awkcard.in: Documented %u. Ooops. + +Tue May 2 11:44:13 2000 Arnold D. Robbins + + * texinfo.tex: Updated to version 1999-10-01.07. + * gawk.texi: Redid page breaking for new texinfo.tex. + +Thu Apr 6 12:32:49 2000 Arnold D. Robbins + + * gawk.texi: Change info dir file entry to `(gawk)' from + `(gawk.info)'. + * Makefile.in [$(infodir)/gawk.info]: Fix grep test is + accordance with above. + +Sun Feb 13 15:36:32 2000 Paul Eggert + + * gawk.texi: Mention that arithmetic is done in double + precision floating point, and point to Goldberg's paper for + people who want to know more. Fix some other minor floating + point discussion issues. + +Wed Nov 3 17:04:35 1999 Arnold D. Robbins + + * gawk.1: Lots of troff ``lint'' from Paul Eggert. Not all + of his changes, just the ones I thought worth doing. + +Mon Oct 11 16:53:54 1999 Arnold D. Robbins + + * Makefile.in (gawk.dvi): Put $(srcdir) first in TEXINPUTS, + and also just use texi2dvi, don't run texindex and tex + manually. Doing so is no longer necessary. + +Mon Aug 9 13:06:01 1999 Arnold D. Robbins + + * gawk.texi: New node `Array Efficiency' on the best use + of subscripting to avoid memory bloat. + +Thu Jul 29 23:15:34 1999 Arnold D. Robbins + + * Makefile.in ($(infodir)/gawk.info): Removed loop around + $(INSTALL_DATA), since there's only one Info file to install, + install it directly. + +Wed Jun 30 16:14:36 1999 Arnold D. Robbins + + * Release 3.0.4: Release tar file made. This time for sure. + +Wed Oct 7 21:59:33 1998 Arnold D. Robbins + + * texinfo.tex: Updated to version 2.227, from Texinfo 3.12. + +Sun Oct 19 12:26:08 1997 Arnold D. Robbins + + * ALL: change references to arnold@gnu.ai.mit.edu to arnold@gnu.org. + +Tue Sep 23 10:31:17 1997 Arnold D. Robbins + + * texinfo.tex: Updated to version 2.218, from Texinfo 3.11. + +Fri Jul 4 08:19:00 1997 Arnold D. Robbins + + * Makefile.in ($(infodir)/gawk.info): Don't make dependent upon + gawk.info, in case installed one is newer. Instead, check that + an installed gawk.info exists and is identical to current one. + If so, just exit; otherwise do the install. + +Wed Jul 2 14:55:12 1997 Arnold D. Robbins + + * Makefile.in ($(infodir)/gawk.info): typo fix. + +Thu May 15 12:49:08 1997 Arnold D. Robbins + + * Release 3.0.3: Release tar file made. + +Fri Apr 18 07:55:47 1997 Arnold D. Robbins + + * BETA Release 3.0.34: Release tar file made. + +Sun Apr 13 15:39:20 1997 Arnold D. Robbins + + * Makefile.in ($(infodir)/gawk.info): exit 0 in case install-info + fails. + +Thu Jan 2 23:17:53 1997 Fred Fish + + * Makefile.in (awkcard.tr): Use ':' chars to separate parts of + sed command, since $(srcdir) may expand to something with '/' + characters in it, which confuses sed terribly. + * gawk.texi (Amiga Installation): Note change of configuration + from "m68k-cbm-amigados" to "m68k-amigaos". Point ftp users + towards current ADE distribution and not obsolete Aminet + "gcc" distribution. Change "FreshFish" to "Geek Gadgets". + +Wed Dec 25 11:25:22 1996 Arnold D. Robbins + + * Release 3.0.2: Release tar file made. + +Wed Dec 25 11:17:32 1996 Arnold D. Robbins + + * Makefile.in ($(mandir)/igawk$(manext),$(mandir)/gawk$(manext)): + remove chmod command; let $(INSTALL_DATA) use -m. + +Tue Dec 17 22:38:28 1996 Arnold D. Robbins + + * Makefile.in (gawk.info,gawk.dvi,postscript): run makeinfo, TeX, + and/or troff against files in $(srcdir). Thanks to Ulrich Drepper. + ($(infodir)/gawk.info): use --info-dir to install-info, not + --infodir. + +Tue Dec 10 23:09:26 1996 Arnold D. Robbins + + * Release 3.0.1: Release tar file made. + +Mon Dec 9 12:48:54 1996 Arnold D. Robbins + + * no.colors: new file from Michal for old troffs. + * Makefile.in [AWKCARD]: changes to parameterize old/new troff. + +Sun Dec 1 15:04:56 1996 Arnold D. Robbins + + * texinfo.tex: Updated to version 2.193, from Karl Berry. + +Tue Nov 26 22:57:15 1996 Arnold D. Robbins + + * Makefile.in ($(infodir)/gawk.info): Change option in call + to `install-info' to `--info-dir' from `--infodir'. + +Mon Nov 4 13:30:39 1996 Arnold D. Robbins + + * Makefile.in: updates for reference card. + (ad.block, awkcard.in, cardfonts, colors, macros, setter.outline): + new files for reference card. + +Wed Oct 16 12:43:02 1996 Arnold D. Robbins + + * texinfo.tex: Updated to version 2.185, from texinfo-3.9 dist. + +Sun Aug 11 23:12:08 1996 Arnold D. Robbins + + * Makefile.in ($(infodir)/gawk.info): correct use of + $(INSTALL_DATA) and remove chmod command. + +Thu Jul 11 22:06:50 1996 Arnold D. Robbins + + * Makefile.in ($(mandir)/gawk.$(ext), $(mandir)/igawk.$(ext)): + made dependant on files in $(srcdir). + +Fri Mar 15 06:45:35 1996 Arnold D. Robbins + + * Makefile.in (clean): add `*~' to list of files to be removed. + +Thu Jan 25 23:40:15 1996 Arnold D. Robbins + + * Makefile.in (dvi): run texindex and tex an extra time. + This gets the cross references right. Sigh. + +Wed Jan 24 11:51:54 1996 Arnold D. Robbins + + * Makefile.in (maintainer-clean): + Depend on distclean, not the other way around. + Output warning message as per GNU standards. diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 0000000..0b9316b --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,122 @@ +# +# doc/Makefile.am --- automake input file for gawk +# +# 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 +# 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 + +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 \ + api-figure1.png api-figure1.txt \ + api-figure2.eps api-figure2.fig api-figure2.pdf \ + api-figure2.png api-figure2.txt \ + api-figure3.eps api-figure3.fig api-figure3.pdf \ + api-figure3.png api-figure3.txt \ + array-elements.eps array-elements.fig array-elements.pdf \ + array-elements.png array-elements.txt \ + 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 wordlist2 \ + bc_notes + +# Get rid of generated files when cleaning +CLEANFILES = *.ps *.html *.dvi *~ awkcard.nc awkcard.tr gawk.pdf gawkinet.pdf gawkworkflow.pdf awkcard.pdf gawk.1.pdf + +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' + +CARDSRC = $(srcdir)/macros $(srcdir)/cardfonts $(srcdir)/colors awkcard.tr +CARDSRC_N = $(srcdir)/macros $(srcdir)/cardfonts $(srcdir)/no.colors awkcard.tr +CARDFILES= $(CARDSRC) ad.block awkcard.in setter.outline +PAPEROPTS= -dpaper=letter -P-pletter + +# Use this if your troff can correctly handle macros from 'colors' file +AWKCARD = awkcard.ps + +# Uncomment the following definition of AWKCARD if your troff can produce +# Postscript but still has troubles with macros from 'colors'. As this +# is not groff you will have to change TROFF macro as well. Do not forget +# to ensure that awkcard.tr is processed by tbl. +#AWKCARD = awkcard.nc + +gawk.texi: $(srcdir)/gawktexi.in $(srcdir)/sidebar.awk + awk -f $(srcdir)/sidebar.awk < $(srcdir)/gawktexi.in > gawk.texi + +postscript: gawk.ps gawkinet.ps gawkworkflow.ps gawk.1.ps $(AWKCARD) + +pdf-local: postscript gawk.pdf gawkinet.pdf awkcard.pdf gawk.1.pdf + +gawk.ps: gawk.dvi + TEXINPUTS=$(srcdir): dvips -o 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 + +awkcard.tr: awkcard.in + sed 's:SRCDIR:$(srcdir):' < $(srcdir)/awkcard.in > awkcard.tr + +awkcard.ps: $(CARDFILES) + $(TROFF) $(PAPEROPTS) $(CARDSRC) | $(SEDME) | cat $(srcdir)/setter.outline - | $(SEDME2) > awkcard.ps + +awkcard.nc: $(CARDFILES) + $(TROFF) $(PAPEROPTS) $(CARDSRC_N) | $(SEDME) | cat $(srcdir)/setter.outline - | $(SEDME2) > awkcard.ps && touch awkcard.nc + +awkcard.pdf: awkcard.ps + ps2pdf awkcard.ps awkcard.pdf + +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 new file mode 100644 index 0000000..078a006 --- /dev/null +++ b/doc/Makefile.in @@ -0,0 +1,940 @@ +# 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@ + +# +# doc/Makefile.am --- automake input file for gawk +# +# 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 +# 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 = doc +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_V_DVIPS = $(am__v_DVIPS_@AM_V@) +am__v_DVIPS_ = $(am__v_DVIPS_@AM_DEFAULT_V@) +am__v_DVIPS_0 = @echo " DVIPS " $@; +am__v_DVIPS_1 = +AM_V_MAKEINFO = $(am__v_MAKEINFO_@AM_V@) +am__v_MAKEINFO_ = $(am__v_MAKEINFO_@AM_DEFAULT_V@) +am__v_MAKEINFO_0 = @echo " MAKEINFO" $@; +am__v_MAKEINFO_1 = +AM_V_INFOHTML = $(am__v_INFOHTML_@AM_V@) +am__v_INFOHTML_ = $(am__v_INFOHTML_@AM_DEFAULT_V@) +am__v_INFOHTML_0 = @echo " INFOHTML" $@; +am__v_INFOHTML_1 = +AM_V_TEXI2DVI = $(am__v_TEXI2DVI_@AM_V@) +am__v_TEXI2DVI_ = $(am__v_TEXI2DVI_@AM_DEFAULT_V@) +am__v_TEXI2DVI_0 = @echo " TEXI2DVI" $@; +am__v_TEXI2DVI_1 = +AM_V_TEXI2PDF = $(am__v_TEXI2PDF_@AM_V@) +am__v_TEXI2PDF_ = $(am__v_TEXI2PDF_@AM_DEFAULT_V@) +am__v_TEXI2PDF_0 = @echo " TEXI2PDF" $@; +am__v_TEXI2PDF_1 = +AM_V_texinfo = $(am__v_texinfo_@AM_V@) +am__v_texinfo_ = $(am__v_texinfo_@AM_DEFAULT_V@) +am__v_texinfo_0 = -q +am__v_texinfo_1 = +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 \ + $(srcdir)/gawkworkflow.info +am__TEXINFO_TEX_DIR = $(srcdir) +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 +AM_MAKEINFOHTMLFLAGS = $(AM_MAKEINFOFLAGS) +DVIPS = dvips +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__installdirs = "$(DESTDIR)$(infodir)" "$(DESTDIR)$(man1dir)" +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; }; \ + } +man1dir = $(mandir)/man1 +NROFF = nroff +MANS = $(man_MANS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/mkinstalldirs \ + ChangeLog texinfo.tex +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@ --no-split --force +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@ +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 \ + api-figure1.png api-figure1.txt \ + api-figure2.eps api-figure2.fig api-figure2.pdf \ + api-figure2.png api-figure2.txt \ + api-figure3.eps api-figure3.fig api-figure3.pdf \ + api-figure3.png api-figure3.txt \ + array-elements.eps array-elements.fig array-elements.pdf \ + array-elements.png array-elements.txt \ + 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 wordlist2 \ + bc_notes + + +# Get rid of generated files when cleaning +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/" + +SEDME2 = sed '/%%Page: 10 10/,/0 Cg EP/d' +CARDSRC = $(srcdir)/macros $(srcdir)/cardfonts $(srcdir)/colors awkcard.tr +CARDSRC_N = $(srcdir)/macros $(srcdir)/cardfonts $(srcdir)/no.colors awkcard.tr +CARDFILES = $(CARDSRC) ad.block awkcard.in setter.outline +PAPEROPTS = -dpaper=letter -P-pletter + +# Use this if your troff can correctly handle macros from 'colors' file +AWKCARD = awkcard.ps +all: all-am + +.SUFFIXES: +.SUFFIXES: .dvi .html .info .pdf .ps .texi +$(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 doc/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu doc/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): + +.texi.info: + $(AM_V_MAKEINFO)restore=: && backupdir="$(am__leading_dot)am$$$$" && \ + am__cwd=`pwd` && $(am__cd) $(srcdir) && \ + rm -rf $$backupdir && mkdir $$backupdir && \ + if ($(MAKEINFO) --version) >/dev/null 2>&1; then \ + for f in $@ $@-[0-9] $@-[0-9][0-9] $(@:.info=).i[0-9] $(@:.info=).i[0-9][0-9]; do \ + if test -f $$f; then mv $$f $$backupdir; restore=mv; else :; fi; \ + done; \ + else :; fi && \ + cd "$$am__cwd"; \ + if $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \ + -o $@ $<; \ + then \ + rc=0; \ + $(am__cd) $(srcdir); \ + else \ + rc=$$?; \ + $(am__cd) $(srcdir) && \ + $$restore $$backupdir/* `echo "./$@" | sed 's|[^/]*$$||'`; \ + fi; \ + rm -rf $$backupdir; exit $$rc + +.texi.dvi: + $(AM_V_TEXI2DVI)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ + MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \ + $(TEXI2DVI) $(AM_V_texinfo) --build-dir=$(@:.dvi=.t2d) -o $@ $(AM_V_texidevnull) \ + $< + +.texi.pdf: + $(AM_V_TEXI2PDF)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ + MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \ + $(TEXI2PDF) $(AM_V_texinfo) --build-dir=$(@:.pdf=.t2p) -o $@ $(AM_V_texidevnull) \ + $< + +.texi.html: + $(AM_V_MAKEINFO)rm -rf $(@:.html=.htp) + $(AM_V_at)if $(MAKEINFOHTML) $(AM_MAKEINFOHTMLFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \ + -o $(@:.html=.htp) $<; \ + then \ + rm -rf $@ && mv $(@:.html=.htp) $@; \ + else \ + rm -rf $(@:.html=.htp); exit 1; \ + fi +$(srcdir)/gawk.info: gawk.texi +gawk.dvi: gawk.texi +gawk.pdf: gawk.texi +gawk.html: gawk.texi +$(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 $@ $< + +uninstall-dvi-am: + @$(NORMAL_UNINSTALL) + @list='$(DVIS)'; test -n "$(dvidir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(dvidir)/$$f'"; \ + rm -f "$(DESTDIR)$(dvidir)/$$f"; \ + done + +uninstall-html-am: + @$(NORMAL_UNINSTALL) + @list='$(HTMLS)'; test -n "$(htmldir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " rm -rf '$(DESTDIR)$(htmldir)/$$f'"; \ + rm -rf "$(DESTDIR)$(htmldir)/$$f"; \ + done + +uninstall-info-am: + @$(PRE_UNINSTALL) + @if test -d '$(DESTDIR)$(infodir)' && $(am__can_run_installinfo); then \ + list='$(INFO_DEPS)'; \ + for file in $$list; do \ + relfile=`echo "$$file" | sed 's|^.*/||'`; \ + echo " install-info --info-dir='$(DESTDIR)$(infodir)' --remove '$(DESTDIR)$(infodir)/$$relfile'"; \ + if install-info --info-dir="$(DESTDIR)$(infodir)" --remove "$(DESTDIR)$(infodir)/$$relfile"; \ + then :; else test ! -f "$(DESTDIR)$(infodir)/$$relfile" || exit 1; fi; \ + done; \ + else :; fi + @$(NORMAL_UNINSTALL) + @list='$(INFO_DEPS)'; \ + for file in $$list; do \ + relfile=`echo "$$file" | sed 's|^.*/||'`; \ + relfile_i=`echo "$$relfile" | sed 's|\.info$$||;s|$$|.i|'`; \ + (if test -d "$(DESTDIR)$(infodir)" && cd "$(DESTDIR)$(infodir)"; then \ + echo " cd '$(DESTDIR)$(infodir)' && rm -f $$relfile $$relfile-[0-9] $$relfile-[0-9][0-9] $$relfile_i[0-9] $$relfile_i[0-9][0-9]"; \ + rm -f $$relfile $$relfile-[0-9] $$relfile-[0-9][0-9] $$relfile_i[0-9] $$relfile_i[0-9][0-9]; \ + else :; fi); \ + done + +uninstall-pdf-am: + @$(NORMAL_UNINSTALL) + @list='$(PDFS)'; test -n "$(pdfdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(pdfdir)/$$f'"; \ + rm -f "$(DESTDIR)$(pdfdir)/$$f"; \ + done + +uninstall-ps-am: + @$(NORMAL_UNINSTALL) + @list='$(PSS)'; test -n "$(psdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(psdir)/$$f'"; \ + rm -f "$(DESTDIR)$(psdir)/$$f"; \ + done + +dist-info: $(INFO_DEPS) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + list='$(INFO_DEPS)'; \ + for base in $$list; do \ + case $$base in \ + $(srcdir)/*) base=`echo "$$base" | sed "s|^$$srcdirstrip/||"`;; \ + esac; \ + if test -f $$base; then d=.; else d=$(srcdir); fi; \ + base_i=`echo "$$base" | sed 's|\.info$$||;s|$$|.i|'`; \ + for file in $$d/$$base $$d/$$base-[0-9] $$d/$$base-[0-9][0-9] $$d/$$base_i[0-9] $$d/$$base_i[0-9][0-9]; do \ + if test -f $$file; then \ + relfile=`expr "$$file" : "$$d/\(.*\)"`; \ + test -f "$(distdir)/$$relfile" || \ + cp -p $$file "$(distdir)/$$relfile"; \ + else :; fi; \ + done; \ + done + +mostlyclean-aminfo: + -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 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 gawkworkflow.dvi gawkworkflow.pdf \ + gawkworkflow.ps gawkworkflow.html + +maintainer-clean-aminfo: + @list='$(INFO_DEPS)'; for i in $$list; do \ + i_i=`echo "$$i" | sed 's|\.info$$||;s|$$|.i|'`; \ + echo " rm -f $$i $$i-[0-9] $$i-[0-9][0-9] $$i_i[0-9] $$i_i[0-9][0-9]"; \ + rm -f $$i $$i-[0-9] $$i-[0-9][0-9] $$i_i[0-9] $$i_i[0-9][0-9]; \ + done +install-man1: $(man_MANS) + @$(NORMAL_INSTALL) + @list1=''; \ + list2='$(man_MANS)'; \ + test -n "$(man1dir)" \ + && test -n "`echo $$list1$$list2`" \ + || exit 0; \ + echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \ + { for i in $$list1; do echo "$$i"; done; \ + if test -n "$$list2"; then \ + for i in $$list2; do echo "$$i"; done \ + | sed -n '/\.1[a-z]*$$/p'; \ + fi; \ + } | while read p; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; echo "$$p"; \ + done | \ + sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ + sed 'N;N;s,\n, ,g' | { \ + list=; while read file base inst; do \ + if test "$$base" = "$$inst"; then list="$$list $$file"; else \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ + fi; \ + done; \ + for i in $$list; do echo "$$i"; done | $(am__base_list) | \ + while read files; do \ + test -z "$$files" || { \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ + done; } + +uninstall-man1: + @$(NORMAL_UNINSTALL) + @list=''; test -n "$(man1dir)" || exit 0; \ + files=`{ for i in $$list; do echo "$$i"; done; \ + l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ + sed -n '/\.1[a-z]*$$/p'; \ + } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ + dir='$(DESTDIR)$(man1dir)'; $(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 + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$(top_distdir)" distdir="$(distdir)" \ + dist-info +check-am: all-am +check: check-am +all-am: Makefile $(INFO_DEPS) $(MANS) +installdirs: + for dir in "$(DESTDIR)$(infodir)" "$(DESTDIR)$(man1dir)"; 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: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +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-aminfo clean-generic mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: $(DVIS) + +html: html-am + +html-am: $(HTMLS) + +info: info-am + +info-am: $(INFO_DEPS) + +install-data-am: install-info-am install-man + +install-dvi: install-dvi-am + +install-dvi-am: $(DVIS) + @$(NORMAL_INSTALL) + @list='$(DVIS)'; test -n "$(dvidir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(dvidir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(dvidir)" || 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)$(dvidir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(dvidir)" || exit $$?; \ + done +install-exec-am: + +install-html: install-html-am + +install-html-am: $(HTMLS) + @$(NORMAL_INSTALL) + @list='$(HTMLS)'; list2=; test -n "$(htmldir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(htmldir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p" || test -d "$$p"; then d=; else d="$(srcdir)/"; fi; \ + $(am__strip_dir) \ + d2=$$d$$p; \ + if test -d "$$d2"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)/$$f'"; \ + $(MKDIR_P) "$(DESTDIR)$(htmldir)/$$f" || exit 1; \ + echo " $(INSTALL_DATA) '$$d2'/* '$(DESTDIR)$(htmldir)/$$f'"; \ + $(INSTALL_DATA) "$$d2"/* "$(DESTDIR)$(htmldir)/$$f" || exit $$?; \ + else \ + list2="$$list2 $$d2"; \ + fi; \ + done; \ + test -z "$$list2" || { echo "$$list2" | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(htmldir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(htmldir)" || exit $$?; \ + done; } +install-info: install-info-am + +install-info-am: $(INFO_DEPS) + @$(NORMAL_INSTALL) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + list='$(INFO_DEPS)'; test -n "$(infodir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(infodir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(infodir)" || exit 1; \ + fi; \ + for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + esac; \ + if test -f $$file; then d=.; else d=$(srcdir); fi; \ + file_i=`echo "$$file" | sed 's|\.info$$||;s|$$|.i|'`; \ + for ifile in $$d/$$file $$d/$$file-[0-9] $$d/$$file-[0-9][0-9] \ + $$d/$$file_i[0-9] $$d/$$file_i[0-9][0-9] ; do \ + if test -f $$ifile; then \ + echo "$$ifile"; \ + else : ; fi; \ + done; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(infodir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(infodir)" || exit $$?; done + @$(POST_INSTALL) + @if $(am__can_run_installinfo); then \ + list='$(INFO_DEPS)'; test -n "$(infodir)" || list=; \ + for file in $$list; do \ + relfile=`echo "$$file" | sed 's|^.*/||'`; \ + echo " install-info --info-dir='$(DESTDIR)$(infodir)' '$(DESTDIR)$(infodir)/$$relfile'";\ + install-info --info-dir="$(DESTDIR)$(infodir)" "$(DESTDIR)$(infodir)/$$relfile" || :;\ + done; \ + else : ; fi +install-man: install-man1 + +install-pdf: install-pdf-am + +install-pdf-am: $(PDFS) + @$(NORMAL_INSTALL) + @list='$(PDFS)'; test -n "$(pdfdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(pdfdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(pdfdir)" || 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)$(pdfdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pdfdir)" || exit $$?; done +install-ps: install-ps-am + +install-ps-am: $(PSS) + @$(NORMAL_INSTALL) + @list='$(PSS)'; test -n "$(psdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(psdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(psdir)" || 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)$(psdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(psdir)" || exit $$?; done +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-aminfo \ + maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-aminfo mostlyclean-generic + +pdf: pdf-am + +pdf-am: $(PDFS) pdf-local + +ps: ps-am + +ps-am: $(PSS) + +uninstall-am: uninstall-dvi-am uninstall-html-am uninstall-info-am \ + uninstall-man uninstall-pdf-am uninstall-ps-am + +uninstall-man: uninstall-man1 + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-aminfo clean-generic \ + cscopelist-am ctags-am dist-info 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-man1 install-pdf install-pdf-am install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-aminfo \ + maintainer-clean-generic mostlyclean mostlyclean-aminfo \ + mostlyclean-generic pdf pdf-am pdf-local ps ps-am tags-am \ + uninstall uninstall-am uninstall-dvi-am uninstall-html-am \ + uninstall-info-am uninstall-man uninstall-man1 \ + uninstall-pdf-am uninstall-ps-am + +.PRECIOUS: Makefile + + +# Uncomment the following definition of AWKCARD if your troff can produce +# Postscript but still has troubles with macros from 'colors'. As this +# is not groff you will have to change TROFF macro as well. Do not forget +# to ensure that awkcard.tr is processed by tbl. +#AWKCARD = awkcard.nc + +gawk.texi: $(srcdir)/gawktexi.in $(srcdir)/sidebar.awk + awk -f $(srcdir)/sidebar.awk < $(srcdir)/gawktexi.in > gawk.texi + +postscript: gawk.ps gawkinet.ps gawkworkflow.ps gawk.1.ps $(AWKCARD) + +pdf-local: postscript gawk.pdf gawkinet.pdf awkcard.pdf gawk.1.pdf + +gawk.ps: gawk.dvi + TEXINPUTS=$(srcdir): dvips -o 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 + +awkcard.tr: awkcard.in + sed 's:SRCDIR:$(srcdir):' < $(srcdir)/awkcard.in > awkcard.tr + +awkcard.ps: $(CARDFILES) + $(TROFF) $(PAPEROPTS) $(CARDSRC) | $(SEDME) | cat $(srcdir)/setter.outline - | $(SEDME2) > awkcard.ps + +awkcard.nc: $(CARDFILES) + $(TROFF) $(PAPEROPTS) $(CARDSRC_N) | $(SEDME) | cat $(srcdir)/setter.outline - | $(SEDME2) > awkcard.ps && touch awkcard.nc + +awkcard.pdf: awkcard.ps + ps2pdf awkcard.ps awkcard.pdf + +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/README.card b/doc/README.card new file mode 100644 index 0000000..ef77cda --- /dev/null +++ b/doc/README.card @@ -0,0 +1,19 @@ +Mon Dec 9 12:45:48 EST 1996 + +The AWK reference card included here requires a modern version of troff +(ditroff). GNU Troff (groff) is known to work. + +If your troff is able to produce Postscript but does not know how to +properly use the macros from `colors' file then try to uncomment in +Makefile the defintion which sets AWKCARD to awkcard.nc (no colors). +This will definitely require changes to the TROFF macro and you have to +ensure that the tbl preprocessor is called. For example, the following +modifications on NeXT: + +TROFF = tbl +SEDME = ptroff -t | sed -e \ + "s/^level0 restore/level0 restore flashme 100 72 moveto\ + (Copyright `date`, FSF, Inc. (all)) show/" \ + -e "s/^\/level0 save def/\/level0 save def 30 -48 translate/" + +will produce a correctly formatted, albeit monochromatic, reference card. diff --git a/doc/ad.block b/doc/ad.block new file mode 100644 index 0000000..54a0f31 --- /dev/null +++ b/doc/ad.block @@ -0,0 +1,49 @@ +.\" AWK Reference Card --- Arnold Robbins, arnold@skeeve.com +.\" This file is the Ad block (included in cover) +.\" +.\" Copyright (C) 1996, 1998, 2000, 2001, 2003, 2017 +.\" Free Software Foundation, Inc. +.\" +.\" Permission is granted to make and distribute verbatim copies of +.\" this reference card provided the copyright notice and this permission +.\" notice are preserved on all copies. +.\" +.\" Permission is granted to process this file through troff and print the +.\" results, provided the printed document carries copying permission +.\" notice identical to this one except for the removal of this paragraph +.\" (this paragraph not being relevant to the printed reference card). +.\" +.\" Permission is granted to copy and distribute modified versions of this +.\" reference card under the conditions for verbatim copying, provided that +.\" the entire resulting derived work is distributed under the terms of a +.\" permission notice identical to this one. +.\" +.\" Permission is granted to copy and distribute translations of this +.\" reference card into another language, under the above conditions for +.\" modified versions, except that this permission notice may be stated in +.\" a translation approved by the Foundation. +.\" +.ft HB +.ps 10 +.vs 12 +.ES +.nf +.ce 7 +\*(CBFree Software Foundation, Inc. +.ft H +51 Franklin Street, Fifth Floor +Boston, MA 02110-1301 USA +Phone: +1-617-542-5942 +Fax (including Japan): +1-617-542-2652 +E-mail: gnu@gnu.org +URL: https://www.gnu.org + +.ce 5 +.ft HB +\*(CGSource Distributions on CD-ROM +.\" Deluxe Distributions +Emacs, Make and GDB Manuals +Emacs and GDB References\*(CX +.EB "\f(HBOTHER FSF PRODUCTS:\*(FR" +.ps +.vs diff --git a/doc/api-figure1.eps b/doc/api-figure1.eps new file mode 100644 index 0000000..7af094c --- /dev/null +++ b/doc/api-figure1.eps @@ -0,0 +1,536 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Title: api-figure1.fig +%%Creator: fig2dev Version 3.2 Patchlevel 5d +%%CreationDate: Wed Oct 31 20:16:08 2012 +%%BoundingBox: 0 0 399 227 +%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 227 moveto 0 0 lineto 399 0 lineto 399 227 lineto closepath clip newpath +-194.8 350.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 180.00 scf sf +3510 5490 m +gs 1 -1 sc (gawk Main Program Address Space) col0 sh gr +/Times-Roman ff 180.00 scf sf +7290 5490 m +gs 1 -1 sc (Extension) col0 sh gr +/Times-Roman ff 180.00 scf sf +5985 2115 m +gs 1 -1 sc (API) col0 sh gr +/Times-Roman ff 180.00 scf sf +5895 2340 m +gs 1 -1 sc (Struct) col0 sh gr +/Courier-Bold ff 180.00 scf sf +7065 2655 m +gs 1 -1 sc (dl_load\(api_p, id\);) col0 sh gr +% here ends figure; +pagefooter +showpage +%%Trailer +end +%EOF diff --git a/doc/api-figure1.fig b/doc/api-figure1.fig new file mode 100644 index 0000000..7bc4784 --- /dev/null +++ b/doc/api-figure1.fig @@ -0,0 +1,40 @@ +#FIG 3.2 Produced by xfig version 3.2.5b +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 180 2850 3510 5490 gawk Main Program Address Space\001 +4 0 0 50 -1 0 12 0.0000 4 135 825 7290 5490 Extension\001 +4 0 0 50 -1 0 12 0.0000 4 135 300 5985 2115 API\001 +4 0 0 50 -1 0 12 0.0000 4 135 480 5895 2340 Struct\001 +4 0 0 50 -1 14 12 0.0000 4 165 2280 7065 2655 dl_load(api_p, id);\001 diff --git a/doc/api-figure1.pdf b/doc/api-figure1.pdf new file mode 100644 index 0000000..0c24b67 Binary files /dev/null and b/doc/api-figure1.pdf differ diff --git a/doc/api-figure1.png b/doc/api-figure1.png new file mode 100644 index 0000000..72d552c Binary files /dev/null and b/doc/api-figure1.png differ diff --git a/doc/api-figure1.txt b/doc/api-figure1.txt new file mode 100644 index 0000000..686b853 --- /dev/null +++ b/doc/api-figure1.txt @@ -0,0 +1,24 @@ + API + Struct + +---+ + | | + +---+ + +---------------| | + | +---+ dl_load(api_p, id); + | | | ___________________ + | +---+ | + | +---------| | __________________ | + | | +---+ || + | | | | || + | | +---+ || + | | +---| | || + | | | +---+ \ || / + | | | \ / + v v v \/ ++-------+-+---+-+---+-+------------------+--------------------+ +| |x| |x| |x| |OOOOOOOOOOOOOOOOOOOO| +| |x| |x| |x| |OOOOOOOOOOOOOOOOOOOO| +| |x| |x| |x| |OOOOOOOOOOOOOOOOOOOO| ++-------+-+---+-+---+-+------------------+--------------------+ + + gawk Main Program Address Space Extension diff --git a/doc/api-figure2.eps b/doc/api-figure2.eps new file mode 100644 index 0000000..caf5c34 --- /dev/null +++ b/doc/api-figure2.eps @@ -0,0 +1,517 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Title: api-figure2.fig +%%Creator: fig2dev Version 3.2 Patchlevel 5d +%%CreationDate: Thu Apr 25 22:22:07 2013 +%%BoundingBox: 0 0 363 179 +%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 179 moveto 0 0 lineto 363 0 lineto 363 179 lineto closepath clip newpath +-194.8 350.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 +/Times-Roman ff 180.00 scf sf +3510 5490 m +gs 1 -1 sc (gawk Main Program Address Space) col0 sh gr +/Times-Roman ff 180.00 scf sf +7290 5490 m +gs 1 -1 sc (Extension) col0 sh gr +/Courier-Bold ff 180.00 scf sf +3420 2880 m +gs 1 -1 sc (register_ext_func\({ "chdir", do_chdir, 1 }\);) col0 sh gr +% here ends figure; +pagefooter +showpage +%%Trailer +end +%EOF diff --git a/doc/api-figure2.fig b/doc/api-figure2.fig new file mode 100644 index 0000000..2ae6085 --- /dev/null +++ b/doc/api-figure2.fig @@ -0,0 +1,26 @@ +#FIG 3.2 Produced by xfig version 3.2.5b +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 0 12 0.0000 4 180 2850 3510 5490 gawk Main Program Address Space\001 +4 0 0 50 -1 0 12 0.0000 4 135 825 7290 5490 Extension\001 +4 0 0 50 -1 14 12 0.0000 4 165 5280 3420 2880 register_ext_func({ "chdir", do_chdir, 1 });\001 diff --git a/doc/api-figure2.pdf b/doc/api-figure2.pdf new file mode 100644 index 0000000..2046285 Binary files /dev/null and b/doc/api-figure2.pdf differ diff --git a/doc/api-figure2.png b/doc/api-figure2.png new file mode 100644 index 0000000..a6e28c9 Binary files /dev/null and b/doc/api-figure2.png differ diff --git a/doc/api-figure2.txt b/doc/api-figure2.txt new file mode 100644 index 0000000..5ed8e2a --- /dev/null +++ b/doc/api-figure2.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| ++-------+-+---+-+---+-+------------------+--------------+-+---+ + + gawk Main Program Address Space Extension diff --git a/doc/api-figure3.eps b/doc/api-figure3.eps new file mode 100644 index 0000000..d713575 --- /dev/null +++ b/doc/api-figure3.eps @@ -0,0 +1,526 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Title: api-figure3.fig +%%Creator: fig2dev Version 3.2 Patchlevel 5d +%%CreationDate: Wed Oct 31 20:16:08 2012 +%%BoundingBox: 0 0 356 175 +%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 175 moveto 0 0 lineto 356 0 lineto 356 175 lineto closepath clip newpath +-194.8 350.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 +/Times-Roman ff 180.00 scf sf +3510 5490 m +gs 1 -1 sc (gawk Main Program Address Space) col0 sh gr +/Times-Roman ff 180.00 scf sf +7290 5490 m +gs 1 -1 sc (Extension) col0 sh gr +/Courier-Bold ff 180.00 scf sf +3240 3150 m +gs 1 -1 sc ( chdir\("/path"\)) col0 sh gr +/Courier-Bold ff 180.00 scf sf +3330 3375 m +gs 1 -1 sc (}) col0 sh gr +/Courier-Bold ff 180.00 scf sf +3375 2925 m +gs 1 -1 sc (BEGIN {) col0 sh gr +/Courier-Bold ff 180.00 scf sf +6660 3150 m +gs 1 -1 sc (\(*fnptr\)\(1\);) col0 sh gr +% here ends figure; +pagefooter +showpage +%%Trailer +end +%EOF diff --git a/doc/api-figure3.fig b/doc/api-figure3.fig new file mode 100644 index 0000000..5c7fdd9 --- /dev/null +++ b/doc/api-figure3.fig @@ -0,0 +1,29 @@ +#FIG 3.2 Produced by xfig version 3.2.5b +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 0 12 0.0000 4 180 2850 3510 5490 gawk Main Program Address Space\001 +4 0 0 50 -1 0 12 0.0000 4 135 825 7290 5490 Extension\001 +4 0 0 50 -1 14 12 0.0000 4 180 2160 3240 3150 chdir("/path")\001 +4 0 0 50 -1 14 12 0.0000 4 150 120 3330 3375 }\001 +4 0 0 50 -1 14 12 0.0000 4 150 840 3375 2925 BEGIN {\001 +4 0 0 50 -1 14 12 0.0000 4 165 1440 6660 3150 (*fnptr)(1);\001 diff --git a/doc/api-figure3.pdf b/doc/api-figure3.pdf new file mode 100644 index 0000000..517b2ec Binary files /dev/null and b/doc/api-figure3.pdf differ diff --git a/doc/api-figure3.png b/doc/api-figure3.png new file mode 100644 index 0000000..f7db079 Binary files /dev/null and b/doc/api-figure3.png differ diff --git a/doc/api-figure3.txt b/doc/api-figure3.txt new file mode 100644 index 0000000..a601ce9 --- /dev/null +++ b/doc/api-figure3.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| ++-------+-+---+-+---+-+------------------+--------------+-+---+ + + gawk Main Program Address Space Extension diff --git a/doc/array-elements.eps b/doc/array-elements.eps new file mode 100644 index 0000000..041c0b3 --- /dev/null +++ b/doc/array-elements.eps @@ -0,0 +1,158 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Title: array-elements.fig +%%Creator: fig2dev Version 3.2 Patchlevel 5d +%%CreationDate: Sun May 4 22:46:26 2014 +%%BoundingBox: 0 0 379 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 379 0 lineto 379 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 180.00 scf sf +3735 2340 m +gs 1 -1 sc (8) col0 sh gr +/Courier-Bold ff 180.00 scf sf +5175 2340 m +gs 1 -1 sc ("foo") col0 sh gr +/Courier-Bold ff 180.00 scf sf +6795 2340 m +gs 1 -1 sc ("") col0 sh gr +/Courier-Bold ff 180.00 scf sf +7875 2340 m +gs 1 -1 sc (30) col0 sh gr +/Times-Roman ff 180.00 scf sf +3735 3150 m +gs 1 -1 sc (0) col0 sh gr +/Times-Roman ff 180.00 scf sf +5175 3150 m +gs 1 -1 sc (1) col0 sh gr +/Times-Roman ff 180.00 scf sf +6795 3150 m +gs 1 -1 sc (2) col0 sh gr +/Times-Roman ff 180.00 scf sf +7875 3150 m +gs 1 -1 sc (3) col0 sh gr +/Times-Roman ff 180.00 scf sf +8730 2340 m +gs 1 -1 sc (Value) col0 sh gr +/Times-Roman ff 180.00 scf sf +8730 3150 m +gs 1 -1 sc (Index) 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/array-elements.fig b/doc/array-elements.fig new file mode 100644 index 0000000..63b5ffb --- /dev/null +++ b/doc/array-elements.fig @@ -0,0 +1,27 @@ +#FIG 3.2 Produced by xfig version 3.2.5b +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 120 120 3735 2340 8\001 +4 0 0 50 -1 14 12 0.0000 4 120 600 5175 2340 "foo"\001 +4 0 0 50 -1 14 12 0.0000 4 60 240 6795 2340 ""\001 +4 0 0 50 -1 14 12 0.0000 4 120 240 7875 2340 30\001 +4 0 0 50 -1 0 12 0.0000 4 135 105 3735 3150 0\001 +4 0 0 50 -1 0 12 0.0000 4 135 105 5175 3150 1\001 +4 0 0 50 -1 0 12 0.0000 4 135 105 6795 3150 2\001 +4 0 0 50 -1 0 12 0.0000 4 135 105 7875 3150 3\001 +4 0 0 50 -1 0 12 0.0000 4 135 480 8730 2340 Value\001 +4 0 0 50 -1 0 12 0.0000 4 135 465 8730 3150 Index\001 diff --git a/doc/array-elements.pdf b/doc/array-elements.pdf new file mode 100644 index 0000000..328cbd1 Binary files /dev/null and b/doc/array-elements.pdf differ diff --git a/doc/array-elements.png b/doc/array-elements.png new file mode 100644 index 0000000..b57d66b Binary files /dev/null and b/doc/array-elements.png differ diff --git a/doc/array-elements.txt b/doc/array-elements.txt new file mode 100644 index 0000000..424c170 --- /dev/null +++ b/doc/array-elements.txt @@ -0,0 +1,4 @@ ++---------+---------+--------+---------+ +| 8 | "foo" | "" | 30 | Value ++---------+---------+--------+---------+ + 0 1 2 3 Index diff --git a/doc/awkcard.in b/doc/awkcard.in new file mode 100644 index 0000000..1148294 --- /dev/null +++ b/doc/awkcard.in @@ -0,0 +1,2016 @@ +.\" 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, 2017, 2018 +.\" Free Software Foundation, Inc. +.\" +.\" Permission is granted to make and distribute verbatim copies of +.\" this reference card provided the copyright notice and this permission +.\" notice are preserved on all copies. +.\" +.\" Permission is granted to process this file through troff and print the +.\" results, provided the printed document carries copying permission +.\" notice identical to this one except for the removal of this paragraph +.\" (this paragraph not being relevant to the printed reference card). +.\" +.\" Permission is granted to copy and distribute modified versions of this +.\" reference card under the conditions for verbatim copying, provided that +.\" the entire resulting derived work is distributed under the terms of a +.\" permission notice identical to this one. +.\" +.\" Permission is granted to copy and distribute translations of this +.\" reference card into another language, under the above conditions for +.\" modified versions, except that this permission notice may be stated in +.\" a translation approved by the Foundation. +.\" +.\" Strings to save typing +.ds AK \*(FCawk\*(FR +.ds GK \*(FCgawk\*(FR +.ds NK Brian Kernighan's \*(FCawk\*(FR +.ds MK \*(FCmawk\*(FR +.\" +.\" +.de TD\" tab defaults +.ta .2i .78i 1i 1.2i 1.4i 1.7i +.. +.de TE +.TD +.. + +.sp +.ce +\*(CD\f(HB\s+8AWK REFERENCE\s0\*(FR +.sp +.\" --- Table Of Contents +.ta 2.4i 2.6iR +.lc . +.ES +.in +.2i +.nf +\*(FRAction Statements 9 +Arrays 7 +Awk Program Execution 5 +Bit Manipulation Functions (\*(GK) 17 +Bug Reports 2 +Closing Redirections 13 +Command Line Arguments (standard) 2 +Command Line Arguments (\*(GK) 3 +Command Line Arguments (\*(MK) 4 +Conversions And Comparisons 8 +Copying Permissions 18 +Definitions 2 +Dynamic Extensions (\*(GK) 17 +Environment Variables (\*(GK) 11 +Escape Sequences 9 +Expressions 7 +Fields 10 +FTP/HTTP/GIT Information 18 +Historical Features (\*(GK) 10 +Input Control 13 +Internationalization (\*(GK) 18 +Lines And Statements 4 +Localization (\*(GK) 12 +Numeric Functions 15 +Output Control 13 +Pattern Elements 8 +Printf Formats 14 +Records 10 +Regular Expressions 11 +Signals (\*(GK \*(FC\-\^\-profile\*(FR) 4 +Special Filenames 12 +String Functions 16 +Time Functions 17 +Type Functions (\*(GK) 18 +User-defined Functions 15 +Variables 5\*(CX +.in -.2i +.EB "\s+2\f(HBCONTENTS\*(FR\s0" +.sp .4 +.TD +.fi +\*(CD\*(FRArnold Robbins wrote this reference card. +We thank +Brian Kernighan and Michael Brennan who reviewed it. +.sp .4 +.SL +.sp .4 +.so SRCDIR/ad.block +.\" a subtlety here; this line changes color. We rely on it +.\" also to provide a empty line. +\*(CD +.SL +.nf +\*(FRCopyright \(co 1996\(en2005, 2007, 2009\(en2018 +Free Software Foundation, Inc. +.nf +.BT + + +.\" +.\" +.\" --- Definitions +.fi +.ES +\*(CDThis card describes POSIX AWK, as well as three +freely available \*(AK implementations +(see \fHFTP/HTTP/GIT Information\fP). +\*(CLCommon extensions (in two or more versions) are printed in light blue. +\*(CBFeatures specific to just one version\(emusually GNU AWK (\*(GK)\(emare +printed in dark blue. +\*(CRExceptions and deprecated features are printed in red. +\*(CDFeatures mandated by POSIX are printed in black. +.sp .5 +Several type faces are used to clarify the meaning: +.br +.nr IN \w'\(bu ' +\(bu \*(FC\*(CN\fP is used for computer input. +.br +.fi +.in +\n(INu +.ti -\n(INu +\(bu\|\^\*(FI\*(IN\fP is used for emphasis, to indicate user input and for syntactic +placeholders, such as \*(FIvariable\fP or \*(FIaction\fP. +.in -\n(INu +.br +\(bu \*(RN is used for explanatory text. +.sp .5 +\*(FInumber\fP \- a floating point number as in ANSI C, such as +\*(FC3\*(FR, +\*(FC2.3\*(FR, +\*(FC.4\*(FR, +\*(FC1.4e2\*(FR +or +\*(FC4.1E5\*(FR. +\*(CBNumbers may also be given in octal or hexadecimal: e.g., +\*(FC011\*(FR or \*(FC0x11\*(FR.\*(CD +.sp .5 +\*(FIescape sequences\fP \- a special sequence of characters beginning +with a backslash, used to describe otherwise unprintable characters. +(See \fHEscape Sequences\fP.) +.sp .5 +\*(FIstring\fP \- a group of characters enclosed in double quotes. +Strings may contain \*(FIescape sequences\*(FR. +.sp .5 +\*(FIregexp\fP \- a regular expression, either a regexp constant +enclosed in forward slashes, or a dynamic regexp computed at run-time. +Regexp constants may contain \*(FIescape sequences\*(FR. +.sp .5 +\*(CB\*(FIstrongly typed regexp\fP \- a regular expression constant with +a leading \*(FC@\*(FR. E.g., \*(FC@/stuff/\*(FR. Such constants may +be assigned to variables and passed to user-defined functions.\*(CD +.sp .5 +\*(FIname\fP \- a variable, array or function name. +.sp .5 +\*(FIentry\fP(\*(FIN\fP) \- entry \*(FIentry\fP in section \*(FIN\fP of the +Unix reference manual. +.sp .5 +\*(FIpattern\fP \- an expression describing an input record to be matched. +.sp .5 +\*(FIaction\fP \- statements to execute when an input record is matched. +.sp .5 +\*(FIrule\fP \- a pattern-action pair, where the pattern or action may +be missing.\*(CX +.EB "\s+2\f(HBDEFINITIONS\*(FR\s0" + +.\" +.\" +.\" --- Command Line Arguments +.ES +.fi +\*(CDCommand line arguments control setting the field separator, +setting variables before the \*(FCBEGIN\fP rule runs, and +the location of AWK program source code. +Implementation-specific command line arguments change +the behavior of the running interpreter. +.sp .5 +.TS +expand; +l lw(2.0i). +\*(FC\-F \*(FIfs\*(FR Use \*(FIfs\fP for the input field separator. +\*(FC\-v\*(FI var\*(FC\^=\^\*(FIval\*(FR T{ +Assign the value \*(FIval\*(FR to the variable \*(FIvar\*(FR +before execution of the program begins. Such +variable values are available to the \*(FCBEGIN\fP rule. +T} +\*(FC\-f \*(FIprog-file\*(FR T{ +Read the AWK program source from the file +\*(FIprog-file\*(FR, instead of from the first command +line argument. Multiple \*(FC\-f\*(FR options may be used. +T} +\*(FC\-\^\-\*(FR Signal the end of options.\*(CX +.TE +.EB "\s+2\f(HBCOMMAND LINE ARGUMENTS (standard)\*(FR\s0" + +.\" --- Bug Reports +.ES +.fi +\*(CDIf you find a bug in this reference card, please report it via electronic +mail to \*(FCbug-gawk@gnu.org\*(FR.\*(CX +.EB "\s+2\f(HBBUG REPORTS\*(FR\s0" + +.BT + +.\" +.\" +.\" --- Command Line Arguments (gawk) +.ES +.fi +\*(CDLong options may abbreviated as long as the abbreviation +remains unique. +You may use ``\*(FC\-W \*(FIoption\*(FR'' +for full POSIX compliance. +.sp .5 +.ig +.\" This option is left undocumented, on purpose. +\*(FC\-\^\-nostalgia\*(FR%T{ +provide a moment of nostalgia for +long time \*(AK users. +T} +.. +.de TI \" table item +.ti -4n +\\$1 +.br +.. +.TS +expand, tab(%); +l lw(1.3i). +\*(FC\-\^\-assign \*(FIvar\*(FC\^=\^\*(FIval\*(FR%Same as \*(FC\-v\fP. +\*(FC\-\^\-field-separator \*(FIfs\*(FR%Same as \*(FC\-F\fP. +\*(FC\-\^\-file \*(FIprog-file%\*(FRSame as \*(FC\-f\fP. +.TE +.in +4n +.TI "\*(FC\-b\*(FR, \*(FC\-\^\-characters\-as\-bytes\*(FR +Treat all input data as single-byte characters. +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 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, +their types and final values to +\*(FIfile\*(FR (default: \*(FCawkvars.out\*(FR). +.TI "\*(FC\-D\*(FR[\*(FC\*(FIfile\*(FR], \*(FC\-\^\-debug\*(FR[\*(FC=\*(FIfile\*(FR] +Enable debugging of program. Optionally read stored commands +from \*(FIfile\*(FR. +.TI "\*(FC-e '\*(FItext\*(FC'\*(FR, \*(FC\-\^\-source '\*(FItext\*(FC'\*(FR +Use \*(FItext\*(FR as AWK program source code. +.TI "\*(FC\-E \*(FIfile\*(FR, \*(FC\-\^\-exec \*(FIfile\*(FR +Read program text from \*(FIfile\fP. No other +options are processed. +Also disable command-line variable assignments. +Useful with \*(FC#!\fP. +.TI "\*(FC\-g\*(FR, \*(FC\-\^\-gen\-pot\*(FR +Process the program and print a GNU \*(FCgettext\*(FR +format \*(FC\&.pot\*(FR file on \*(FCstdout\*(FR, +containing the text of all strings that were marked +for localization. +.TI "\*(FC\-h\*(FR, \*(FC\-\^\-help\*(FR +Print a short summary of the available +options on \*(FCstdout\*(FR, then exit zero. +.TI "\*(FC\-i \*(FIfile\*(FR, \*(FC\-\^\-include \*(FIfile\*(FR +Include library AWK code in \*(FIfile\*(FR. +See \fHAwk Program Execution\*(FR. +.TI "\*(FC\-l \*(FIlib\*(FR, \*(FC\-\^\-load \*(FIlib\*(FR +Load dynamic extension \*(FIlib\fP. +See \fHDynamic Extensions\*(FR. +.TI "\*(FC\-L \*(FR[\*(FC\*(FIvalue\*(FR], \*(FC\-\^\-lint\*(FR[\*(FC=\*(FIvalue\*(FR] +Warn about dubious or non-portable constructs. +If \*(FIvalue\*(FR is +\*(FCfatal\*(FR, +lint warnings become fatal errors. +If \*(FIvalue\*(FR is +\*(FCinvalid\*(FR, +only issue warnings about things that are +actually invalid (not fully implemented yet). +.TI "\*(FC\-M\*(FR, \*(FC\-\^\-bignum\*(FR +Enable arbitrary-precision arithmetic. +.TI "\*(FC\-n\*(FR, \*(FC\-\^\-non\-decimal\-data\*(FR +Recognize octal and hexadecimal values in input data. +\*(FIUse this option with great caution!\*(FR +.TI "\*(FC\-N\*(FR, \*(FC\-\^\-use\-lc\-numeric\*(FR +Force use of the locale's decimal point character when parsing input data. +.TI "\*(FC\-o\*(FR[\*(FC\*(FIfile\*(FR], \*(FC\-\^\-pretty-print\*(FR[\*(FC=\*(FIfile\*(FR] +Output a pretty printed version of the program to \*(FIfile\*(FR +(default: \*(FCawkprof.out\*(FR). +.TI "\*(FC\-O\*(FR, \*(FC\-\^\-optimize\*(FR +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). +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. +.TI "\*(FC\-r\*(FR, \*(FC\-\^\-re\-interval\*(FR +Enable \*(FIinterval expressions\*(FR. +(Needed with \*(FC\-c\*(FR.)\*(CB +.in -4n +.EB "\s+2\f(HBCOMMAND LINE ARGUMENTS (\*(GK\f(HB)\*(FR\s0" + +.BT + +.\" +.\" +.\" --- Command Line Arguments (gawk) continued +.ES +.fi +.in +4n +.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, +output redirection with \*(FCprint\*(FR and \*(FCprintf\*(FR, +and loading dynamic extensions. +.TI "\*(FC-t\*(FR, \*(FC\-\^\-lint\-old\*(FR +Warn about constructs that are not +portable to the original version of +Unix \*(AK. +.TI "\*(FC\-V\*(FR, \*(FC\-\^\-version\*(FR +Print version \" information +info +on \*(FCstdout\fP +and exit zero. +.in -4n +.sp .5 +.fi +Normally, if there is program text, unknown +options are passed on to the AWK program in +\*(FCARGV\*(FR +for processing. +In compatibility mode, +unknown options are flagged as invalid, but are otherwise ignored.\*(CB +.EB "\s+2\f(HBCOMMAND LINE ARGUMENTS (\*(GK\f(HB)\*(FR\s0" +.sp .4 +.\" +.\" +.\" --- Command Line Arguments (mawk) +.ES +.fi +\*(CDThe following options are specific to \*(MK. +.sp .5 +.fi +.TS +expand; +l lw(1.8i). +\*(FC\-W dump\*(FR T{ +Print an assembly listing of the program to +\*(FCstdout\fP and exit zero. +T} +\*(FC\-W exec \*(FIfile\*(FR T{ +Read program text from \*(FIfile\fP. No other +options are processed. Useful with \*(FC#!\fP. +T} +\*(FC\-W interactive\*(FR T{ +Unbuffer \*(FCstdout\fP and line buffer \*(FCstdin\fP. +Lines are always records, ignoring \*(FCRS\fP. +T} +\*(FC\-W posix_space\*(FR T{ +\*(FC\en\*(FR separates fields when \*(FCRS = "\^"\fP. +T} +\*(FC\-W sprintf=\*(FInum\*(FR T{ +Adjust the size of \*(MK's internal +\*(FCsprintf\*(FR buffer. +T} +\*(FC\-W version\*(FR T{ +Print version and copyright on +\*(FCstdout\fP, limit information on \*(FCstderr\fP, +and exit zero. +T} +.TE +.sp .5 +.fi +The options may be abbreviated using just the first letter, e.g., +\*(FC\-We\*(FR, +\*(FC\-Wv\*(FR +and so on.\*(CB +.EB "\s+2\f(HBCOMMAND LINE ARGUMENTS (\*(MK\f(HB)\*(FR\s0" +.sp .7 +.\" --- Signals (gawk --profile) +.ES +.fi +\*(CD\*(GK accepts two signals while profiling. +\*(FCSIGUSR1\fP dumps a profile and function call stack to the +profile file. It then continues to run. +\*(FCSIGHUP\fP is similar, but exits.\*(CB +.EB "\s+2\f(HBSIGNALS (\*(GK \f(HB\-\^\-profile)\*(FR\s0" + +.\" --- Lines And Statements +.ES +.fi +\*(CDAWK is a line-oriented language. The pattern comes first, and then the +action. Action statements are enclosed in \*(FC{\fP and \*(FC}\*(FR. +Either the pattern or the action may be missing, but +not both. If the pattern is missing, the action is +executed for every input record. +A missing action is equivalent to +.sp .5 + \*(FC{ print }\fP +.sp .5 +which prints the entire record. +.sp .5 +Comments begin with the \*(FC#\*(FR character, and continue until the +end of the line. +Normally, statements end with a newline, but lines ending in +a ``,'', +\*(FC{\*(FR, +\*(CB\*(FC?\*(FR, +\*(FC:\*(FR,\*(CD +\*(FC&&\*(FR, +or +\*(FC||\*(FR, +are automatically continued. +Lines ending in \*(FCdo\fP or \*(FCelse\fP +also have their statements automatically continued on the following line. +In other cases, a line can be continued by ending it with a ``\e'', +in which case the newline is ignored. However, a ``\e'' after a +\*(FC#\*(FR is not special. +.sp .5 +Multiple statements may be put on one line by separating them with a ``;''. +This applies to both the statements within the action part of a +pattern-action pair (the usual case) +and to the pattern-action statements themselves.\*(CX +.EB "\s+2\f(HBLINES AND STATEMENTS\*(FR\s0" +.BT + +.\" --- Awk Program Execution +.ES +.fi +\*(CDAWK programs are a sequence of +\*(CBoptional directives,\*(CD +pattern-action statements +and optional function definitions. +.sp .5 + \*(CB\*(FC@include "\*(FIfilename\*(FC" +.br + \*(FC@load "\*(FIfilename\*(FC"\*(CD +.br + \*(FIpattern\*(FC { \*(FIaction statements\*(FC }\*(FR +.br + \*(FCfunction \*(FIname\*(FC(\*(FIparameter list\*(FC) { \*(FIstatements\*(FC }\*(FR +.sp .5 +\*(AK first reads the program source from the +\*(FIprog-file\*(FR(s), if specified, +\*(CBfrom arguments to \*(FC\-\^\-source\*(FR,\*(CD +or from the first non-option argument on the command line. +The program text is read as if all the \*(FIprog-file\*(FR(s) +\*(CBand command line +source texts\*(CD had been concatenated. +.sp +\*(CB\*(GK includes files named on \*(FC@include\*(FR lines. +Nested includes are allowed. +\*(GK loads extensions named on \*(FC@load\*(FR lines; +see \fHDynamic Extensions\*(FR.\*(CD +.sp .5 +AWK programs execute in the following order. +First, all variable assignments specified via the \*(FC\-v\fP +option are performed. +Next, \*(AK executes the code in the +\*(FCBEGIN\fP rules(s), if any, and then proceeds to read +the files \*(FC1\fP through \*(FCARGC \- 1\fP in the \*(FCARGV\fP array. +If there are no files named on the command line, +\*(AK reads the standard input. +.sp .5 +A command line argument of the form +\*(FIvar\*(FC=\*(FIval\*(FR, +is treated as a variable assignment. The variable +\*(FIvar\fP is assigned the value \*(FIval\*(FR. +(This happens after any \*(FCBEGIN\fP rule(s) have been run.) +.sp .5 +If the value of a particular element of \*(FCARGV\fP is empty +(\*(FC"\^"\*(FR), \*(AK skips over it. +.sp .5 +\*(CBFor each input file, +if a \*(FCBEGINFILE\fP rule exists, \*(GK executes the associated code +before processing the contents of the file. Similarly, \*(GK executes +the code associated with \*(FCENDFILE\fP after processing the file.\*(CD +.sp .5 +For each record in the input, \*(AK tests to see if it matches any +\*(FIpattern\fP in the AWK program. +For each pattern that the record matches, +it executes the associated \*(FIaction\fP. +The patterns are tested in the order they occur in the program. +.sp .5 +Finally, after all the input is exhausted, +\*(AK executes the code in the \*(FCEND\fP rule(s), if any. +.sp .5 +If a program only has a \*(FCBEGIN\fP rule, no input files are processed. +If a program only has an \*(FCEND\fP rule, the input is read. +\*(CX +.EB "\s+2\f(HBAWK PROGRAM EXECUTION\*(FR\s0" +.sp .5 +.\" --- Variables +.ES +.fi +.TS +expand; +l lw(2.3i). +\*(CD\*(FCARGC\fP T{ +Number of command line arguments. +T} +\*(CB\*(FCARGIND\fP T{ +Index in \*(FCARGV\fP of current data file.\*(CD +T} +\*(FCARGV\fP T{ +Array of command line arguments. Indexed from +zero to \*(FCARGC\fP \- 1. Dynamically changing the +contents of \*(FCARGV\fP can control the files used +for data. +T} +\*(CL\*(FCBINMODE\fP T{ +Controls ``binary'' mode for all file I/O. Values of 1, 2, or 3, +indicate input, output, or all files, respectively, should use binary +I/O. \*(CR(Not \*(NK.) \*(CLApplies only to non-POSIX systems. +\*(CBFor \*(GK, string values of \*(FC"r"\fP, or \*(FC"w"\fP specify +that input files, or output files, respectively, should use binary I/O. +Use \*(FC"rw"\fP or \*(FC"wr"\fP for all files.\*(CX +T} +.TE +.EB "\s+2\f(HBVARIABLES\*(FR\s0" +.BT + +.\" --- Variables (continued) +.ES +.fi +.TS +expand; +l lw(2i). +\*(FCCONVFMT\fP T{ +Conversion format for numbers, default value +is \*(FC"%.6g"\*(FR. +T} +\*(FCENVIRON\fP T{ +Array containing the current environment. +It is indexed by the environment +variable names, each element being the value of +that variable. +T} +\*(CB\*(FCERRNO\fP T{ +String error value if a +\*(FCgetline\*(FR +redirection or read +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, +instead of the value of \*(FCFS\fP. +See \fHFields\*(FR.\*(CD +T} +\*(FCFILENAME\fP T{ +Name of the current input file. If no files given +on the command line, \*(FCFILENAME\fP is ``\-''. +\*(FCFILENAME\fP is undefined inside the \*(FCBEGIN\fP rule +(unless set by \*(FCgetline\fP). +T} +\*(FCFNR\fP T{ +Record number in current input file. +T} +\*(CB\*(FCFPAT\fP T{ +Regular expression describing field contents. +Used to parse the input based on the fields +instead of the field separator.\*(CD +T} +\*(FCFS\fP T{ +Input field separator, a space by default +(see \fHFields\fP). +T} +\*(CB\*(FCFUNCTAB\fP T{ +An array indexed by the names of all user-defined +and extension functions.\*(CD +T} +\*(CB\*(FCIGNORECASE\fP T{ +If non-zero, all regular expression and string +operations ignore case. +Array subscripting +is \*(FInot\*(FR affected. +However, the +\*(FCasort()\*(FR +and +\*(FCasorti()\*(FR +function are affected. +T} +\*(CB\*(FCLINT\fP T{ +Provides dynamic control of the \*(FC\-\^\-lint\fP +option from within an AWK program. +T} +\*(CD\*(FCNF\fP T{ +Number of fields in the current input record. +T} +\*(FCNR\fP T{ +Total number of input records seen so far.\*(CX +T} +\*(CD\*(FCOFMT\fP T{ +Output format for numbers, \*(FC"%.6g"\*(FR, by default. +T} +\*(FCOFS\fP T{ +Output field separator, a space by default. +T} +\*(FCORS\fP T{ +Output record separator, a newline by default. +T} +\*(CB\*(FCPREC\fP T{ +The working precision of arbitrary precision floating-point +numbers, 53 by default. +T} +\*(FCPROCINFO\fP T{ +Elements of this array provide access to information +about the running AWK program. See +\*(AM for details.\*(CD +T} +\*(FCRLENGTH\fP T{ +Length of the string matched by \*(FCmatch()\*(FR; +\-1 if no match. +T} +\*(CB\*(FCROUNDMODE\fP T{ +The rounding mode to use for arbitrary precision arithmetic, +by default \*(FC"N"\fP.\*(CD +T} +\*(FCRS\fP T{ +Input record separator, a newline by default +(see \fHRecords\fP). +T} +\*(FCRSTART\fP T{ +Index of the first character matched by +\*(FCmatch()\*(FR; zero if no match. +T} +\*(CB\*(FCRT\fP T{ +Record terminator. \*(GK sets \*(FCRT\fP to the input +text that matched the character or regular +expression specified by \*(FCRS\*(FR.\*(CD +T} +\*(FCSUBSEP\fP T{ +Character(s) used to separate multiple subscripts +in array elements, by default \*(FC"\e034"\*(FR. (See +\fHArrays\fP). +T} +\*(CB\*(FCSYMTAB\fP T{ +An array indexed by the names of all global +variables and arrays. May be used to indirectly +set variable and array values.\*(CD +T} +\*(CB\*(FCTEXTDOMAIN\fP T{ +The internationalization text domain, +for finding the localized +translations of the program's strings.\*(CX +T} +.TE +.EB "\s+2\f(HBVARIABLES (continued)\*(FR\s0" + +.BT + +.\" --- Arrays +.ES +.fi +\*(CDAn array subscript is an expression between square brackets +(\*(FC[ \*(FRand \*(FC]\*(FR). +If the expression is a list +(\*(FIexpr\*(FC, \*(FIexpr \*(FR...), +then the subscript is a string consisting of the +concatenation of the (string) value of each expression, +separated by the value of \*(FCSUBSEP\fP. +This simulates multi-dimensional +arrays. For example: +.nf +.sp .5 + \*(FCi = "A";\^ j = "B";\^ k = "C" + x[i, j, k] = "hello, world\en"\*(FR +.sp .5 +.fi +assigns \*(FC"hello, world\en"\*(FR to the element of the array +\*(FCx\fP +indexed by the string \*(FC"A\e034B\e034C"\*(FR. All arrays in AWK +are associative, i.e., indexed by string values. +.sp .5 +Use the special operator \*(FCin\fP in an \*(FCif\fP +or \*(FCwhile\fP statement to see if a particular value is +an array index. +.sp .5 +.nf + \*(FCif (val in array) + print array[val]\*(FR +.sp .5 +.fi +If the array has multiple subscripts, use +\*(FC(i, j) in array\*(FR. +.sp .5 +Use the \*(FCin\fP construct in a \*(FCfor\fP +loop to iterate over all the elements of an array. +.sp .5 +Use the \*(FCdelete\fP statement to delete an +element from an array. +Specifying just the array name without a subscript in +the \*(FCdelete\fP +statement deletes the entire contents of an array. +\*(CBYou cannot use \*(FCdelete\fP with \*(FCFUNCTAB\fP +or \*(FCSYMTAB\fP.\*(CD +.sp .5 +\*(CB\*(GK provides true multidimensional arrays. +Such arrays need not be ``rectangular'' as in C or C++. For example: +.sp .5 +.nf + \*(FCa[1] = 5; a[2][1] = 6; a[2][2] = 7\*(FR\*(CX +.fi +.EB "\s+2\f(HBARRAYS\*(FR\s0" + +.\" --- Expressions +.ES +.fi +\*(CDExpressions are used as patterns, for controlling conditional action +statements, and to produce parameter values when calling functions. +Expressions may also be used as simple statements, +particularly if they have side-effects such as assignment. +Expressions mix \*(FIoperands\fP and \*(FIoperators\fP. Operands are +constants, fields, variables, array elements, and the return +values from function calls (both built-in and user-defined). +.sp .5 +Regexp constants (\*(FC/\*(FIpat\*(FC/\*(FR), when used as simple expressions, +i.e., not used on the right-hand side of +\*(FC~\fP and \*(FC!~\fP, or as arguments to the +\*(CB\*(FCgensub()\fP,\*(CD +\*(FCgsub()\fP, +\*(FCmatch()\fP, +\*(CB\*(FCpatsplit()\fP,\*(CD +\*(FCsplit()\fP, +and +\*(FCsub()\fP, +functions, mean \*(FC$0 ~ /\*(FIpat\*(FC/\*(FR. +.sp .5 +The AWK operators, in order of decreasing precedence, are: +.sp .5 +.fi +.TS +expand; +l lw(1.8i). +\*(FC(\&...)\*(FR Grouping +\*(FC$\fP Field reference +\*(FC++ \-\^\-\fP T{ +Increment and decrement, +prefix and postfix +T} +\*(FC^\fP \*(CL\*(FC**\*(FR\*(CD Exponentiation +\*(FC+ \- !\fP Unary plus, unary minus, and logical negation +\*(FC* / %\fP Multiplication, division, and modulus +\*(FC+ \-\fP Addition and subtraction +\*(FIspace\fP String concatenation +\*(FC< >\fP Less than, greater than +\*(FC<= >=\fP Less than or equal, greater than or equal +\*(FC== !=\fP Equal, not equal +\*(FC~ !~\fP Regular expression match, negated match +\*(FCin\fP Array membership +\*(FC&&\fP Logical AND, short circuit +\*(FC||\fP Logical OR, short circuit +\*(FC?\^:\fP In-line conditional expression +.T& +l s +l lw(1.8i). +\*(FC=\0+=\0\-=\0*=\0/=\0%=\0^=\0\*(CL**=\*(CD\fP + Assignment operators\*(CX +.TE +.EB "\s+2\f(HBEXPRESSIONS\*(FR\s0" + +.BT + +.\" --- Conversions and Comparisons +.ES +.fi +\*(CDVariables and fields may be (floating point) numbers, strings or both. +Context determines how a variable's value is interpreted. If used in +a numeric expression, it will be treated as a number, if used as a string +it will be treated as a string. +\*(CBAssigning a strongly typed regexp constant to a scalar makes it +a regexp.\*(CD +.sp .5 +To force a variable to be treated as a number, add zero to it; to force it +to be treated as a string, concatenate it with the null string. +.sp .5 +Uninitialized variables have the numeric value zero and the string value +\*(FC"\^"\fP +(the null, or empty, string). +.sp .5 +When a string must be converted to a number, the conversion is accomplished +using \*(FIstrtod\*(FR(3). +A number is converted to a string by using the value of \*(FCCONVFMT\fP +as a format string for \*(FIsprintf\*(FR(3), +with the numeric value of the variable as the argument. +However, even though all numbers in AWK are floating-point, +integral values are \*(FIalways\fP converted as integers. +.sp .5 +Comparisons are performed as follows: +If two variables are numeric, they are compared numerically. +If one value is numeric and the other has a string value that is a +``numeric string,'' then comparisons are also done numerically. +Otherwise, the numeric value is converted to a string, and a string +comparison is performed. +Two strings are compared, of course, as strings. +.sp .5 +Note that string constants, such as \*(FC"57"\fP, are \*(FInot\fP +numeric strings, they are string constants. The idea of ``numeric string'' +only applies to fields, \*(FCgetline\fP input, +\*(FCFILENAME\*(FR, \*(FCARGV\fP elements, \*(FCENVIRON\fP +elements and the elements of an array created by \*(FCsplit()\fP +\*(CBor \*(FCpatsplit()\fP\*(CD that are numeric strings. +The basic idea is that \*(FIuser input\*(FR, +and only user input, that looks numeric, +should be treated that way.\*(CX +.EB "\s+2\f(HBCONVERSIONS AND COMPARISONS\*(FR\s0" + +.\" --- Pattern Elements +.ES +.fi +\*(CDAWK patterns may be one of the following. +.sp .5 +.nf + \*(FCBEGIN + END + \*(CBBEGINFILE + ENDFILE\*(CD + \*(FIexpression + pat1\*(FC,\*(FIpat2\*(FR +.sp .5 +.fi +\*(FCBEGIN\fP and \*(FCEND\fP are special patterns that provide start-up +and clean-up actions respectively. They must have actions. There can +be multiple \*(FCBEGIN\fP and \*(FCEND\fP rules; they are merged and +executed as if there had just been one large rule. They may occur anywhere +in a program, including different source files. +.sp .5 +\*(CB\*(FCBEGINFILE\*(FR and \*(FCENDFILE\*(FR are special patterns that +execute before the first record of each file and after the last record +of each file, respectively. In the \*(FCBEGINFILE\*(FR rule, the \*(FCERRNO\*(FR +variable is non-null if there is a problem with the file; the rule should use +\*(FCnextfile\*(FR to skip the file if desired. Otherwise \*(GK exits with +its usual fatal error. The actions for multiple +\*(FCBEGINFILE\*(FR and \*(FCENDFILE\*(FR patterns are merged.\*(CD +.sp .5 +Expression patterns can be any expression, as described +under \fHExpressions\fP. +.sp .5 +The \*(FIpat1\*(FC,\*(FIpat2\*(FR pattern +is called a \*(FIrange pattern\*(FR. +It matches all input records starting with a record that matches +\*(FIpat1\*(FR, and continuing until a record that matches +\*(FIpat2\*(FR, inclusive. +It does not combine with any other pattern expression.\*(CX +.EB "\s+2\f(HBPATTERN ELEMENTS\*(FR\s0" + +.BT + +.\" --- Action Statements +.ES +.fi +.in +.2i +.ti -.2i +\*(CD\*(FCbreak\*(FR +.br +Break out of the nearest enclosing +\*(CB\*(FCswitch\fP statement, or\*(CD +\*(FCdo\*(FR, \*(FCfor\*(FR, or \*(FCwhile\*(FR loop. +.ti -.2i +\*(FCcontinue\*(FR +.br +Skip the rest of the loop body. +Evaluate the \*(FIcondition\*(FR +part of the nearest enclosing \*(FCdo\*(FR or \*(FCwhile\*(FR loop, +or go to the \*(FIincr\*(FR part of a \*(FCfor\*(FR loop. +.ti -.2i +\*(FCdelete \*(FIarray\^\*(FC[\^\*(FIindex\^\*(FC]\*(FR +.br +Delete element \*(FIindex\*(FR from array \*(FIarray\*(FR. +.ti -.2i +\*(FCdelete \*(FIarray\^\*(FR +.br +Delete all elements from array \*(FIarray\*(FR. +.ti -.2i +\*(FCdo \*(FIstatement \*(FCwhile (\*(FIcondition\*(FC)\*(FR +.br +Execute \*(FIstatement\*(FR while \*(FIcondition\*(FR is true. +The \*(FIstatement\*(FR is always executed at least once. +.ti -.2i +\*(FCexit\*(FR [ \*(FIexpression\*(FR ] +.br +Terminate input record processing. +Execute the \*(FCEND\*(FR rule(s) if present. +If present, \*(FIexpression\*(FR becomes \*(AK's return value. +.ti -.2i +\*(FCfor (\*(FIinit\*(FC; \*(FIcond\*(FC; \*(FIincr\*(FC) \*(FIstatement\*(FR +.br +Execute \*(FIinit\*(FR. +Evaluate \*(FIcond\*(FR. +If it is true, execute \*(FIstatement\*(FR. +Execute \*(FIincr\*(FR before going back to the top to +re-evaluate \*(FIcond\*(FR. +Any of the three may be omitted. +A missing \*(FIcond\*(FR is considered to be true. +.ti -.2i +\*(FCfor (\*(FIvar \*(FCin\*(FI array\*(FC) \*(FIstatement\*(FR +.br +Execute \*(FIstatement\*(FR once for each subscript in \*(FIarray\*(FR, +with \*(FIvar\*(FR set to a different subscript each time through +the loop. +.ti -.2i +\*(CD\*(FCif (\*(FIcondition\*(FC) \*(FIstatement1\*(FR [ \*(FCelse\*(FI statement2\*(FR ] +.br +If \*(FIcondition\*(FR is true, execute \*(FIstatement1\*(FR, +otherwise execute \*(FIstatement2\*(FR. Each \*(FCelse\*(FR +matches the closest \*(FCif\*(FR. +.ti -.2i +\*(FCnext\*(FR See \fHInput Control.\fP +.ti -.2i +\*(FCnextfile\*(FR See \fHInput Control.\fP +.in -.2i +.\" --- Start switch statement +\*(CB\*(FCswitch (\*(FIexpression\*(FC) { +.br +case \*(FIconstant\*(FC|\*(FIregular expression\*(FC: \*(FIstatement(s) +.br +\*(FCdefault: \*(FIstatement(s) +.br +\*(FC}\*(FR +.in +.2i +.br +Switch on \*(FIexpression\*(FR, +execute \*(FIcase\*(FR if matched, default if not. +The \*(FCdefault\fP label and associated statements are optional.\*(CD +.ti -.2i +.\" --- End switch statement +\*(FCwhile (\*(FIcondition\*(FC) \*(FIstatement \*(FR +.br +While \*(FIcondition\*(FR is true, execute \*(FIstatement\*(FR. +.ti -.2i +\*(FC{ \*(FIstatements \*(FC}\*(FR .br +A list of statements enclosed in braces can be used anywhere +that a single statement would otherwise be used.\*(CX +.in -.2i +.EB "\s+2\f(HBACTION STATEMENTS\*(FR\s0" + +.\" --- Escape Sequences +.ES +.fi +\*(CDWithin strings constants (\*(FC"..."\fP) and regexp +constants (\*(FC/.../\fP), escape sequences may be used to +generate otherwise unprintable characters. This table lists +the available escape sequences. +.sp .5 +.TS +center, tab(~); +lp8 lp8 lp8 lp8. +\*(FC\ea\fP~alert (bell)~\*(FC\er\fP~carriage return +\*(FC\eb\fP~backspace~\*(FC\et\fP~horizontal tab +\*(FC\ef\fP~form feed~\*(FC\ev\fP~vertical tab +\*(FC\en\fP~newline~\*(FC\e\e\fP~backslash +\*(FC\e\*(FIddd\*(FR~octal value \*(FIddd\fP~\*(CL\*(FC\ex\*(FIhh\*(FR~hex value \*(FIhh\fP\*(CD +\*(FC\e"\fP~double quote~\*(FC\e/\fP~forward slash\*(CX +.TE +.EB "\s+2\f(HBESCAPE SEQUENCES\*(FR\s0" +.BT + +.\" --- Records +.ES +.fi +\*(CDNormally, records are separated by newline characters. +Assigning values to the built-in variable \*(FCRS\*(FR +controls how records are separated. +If \*(FCRS\fP is any single character, that character separates records. +\*(CLOtherwise, \*(FCRS\fP is a regular expression. +\*(CR(Not \*(NK.)\*(CL +Text in the input that matches this +regular expression separates the record. +\*(CB\*(GK sets \*(FCRT\*(FR to the value of the +input text that matched the regular expression. +The value of \*(FCIGNORECASE\fP +also affects how records are separated when +\*(FCRS\fP is a regular expression.\*(CD +If \*(FCRS\fP is set to the null string, +then records are separated by one or more empty lines. +When \*(FCRS\fP is set to the null string, +the newline character always acts as +a field separator, in addition to whatever value +\*(FCFS\fP may have. +\*(CB\*(MK does not apply exceptional rules to \*(FCFS\fP +when \*(FCRS\fP is set to \*(FC"\^"\fP.\*(CX +.EB "\s+2\f(HBRECORDS\*(FR\s0" + +.\" --- Fields +.ES +.fi +\*(CDAs each input record is read, \*(AK splits the record into +\*(FIfields\*(FR, using the value of the \*(FCFS\fP +variable as the field separator. +If \*(FCFS\fP is a single character, +fields are separated by that character. +\*(CLIf \*(FCFS\fP is the null string, +then each individual character becomes a separate field.\*(CD +Otherwise, \*(FCFS\fP is expected to be a full regular expression. +In the special case that \*(FCFS\fP +is a single space, fields are separated +by runs of spaces and/or tabs +and/or newlines. +Leading and trailing whitespace are ignored. +\*(CBThe value of \*(FCIGNORECASE\fP +also affects how fields are split when +\*(FCFS\fP is a regular expression.\*(CD +.sp .5 +\*(CBIf the \*(FCFIELDWIDTHS\fP +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. +and restores the default behavior. +.sp .5 +Similarly, if the +\*(FCFPAT\fP +variable is set to a string representing a regular expression, +each field is made up of text that matches that regular expression. In +this case, the regular expression describes the fields themselves, +instead of the text that separates the fields. +Assigning a new value to +\*(FCFS\fP +or +\*(FCFIELDWIDTHS\fP +overrides the use of +\*(FCFPAT\fP.\*(CD +.sp .5 +Each field in the input record may be referenced by its position: +\*(FC$1\*(FR, \*(FC$2\*(FR and so on. +\*(FC$0\fP is the whole record. +Fields may also be assigned new values. +.sp .5 +The variable \*(FCNF\fP +is set to the total number of fields in the input record. +.sp .5 +References to non-existent fields (i.e., fields after \*(FC$NF\*(FR) +produce the null string. However, assigning to a non-existent field +(e.g., \*(FC$(NF+2) = 5\*(FR) increases the value of +\*(FCNF\*(FR, creates any intervening fields with the null string as their value, +and causes the value of \*(FC$0\fP +to be recomputed with the fields being separated by the +value of \*(FCOFS\*(FR. +References to negative numbered fields cause a fatal error. +Decreasing the value of \*(FCNF\fP causes the trailing fields to be lost +\*(CR(not \*(NK)\*(CD.\*(CX +.EB "\s+2\f(HBFIELDS\*(FR\s0" + +.\" --- Historical Features +.ES +.fi +\*(CDIt is possible to call the \*(FClength()\fP +built-in function not only with no argument, but even without parentheses. +Doing so, however, is poor practice, +and \*(GK +issues a warning about its use if \*(FC\-\^\-lint\fP +is specified on the command line.\*(CB +.EB "\s+2\f(HBHISTORICAL FEATURES (\*(GK\f(HB)\*(FR\s0" +.BT + +.\" --- Regular Expressions +.ES +.fi +\*(CDRegular expressions are the extended kind originally defined by +\*(FCegrep\fP. +\*(CB\*(GK supports additional GNU operators. +A \*(FIword-constituent\fP character is a letter, digit, or +underscore (\*(FC_\fP).\*(CD +.sp .5 +.TS +center, tab(~); +cp8 sp8 +cp8 sp8 +lp8|lp8. +.\" .vs 10 +_ +Summary of Regular Expressions +In Decreasing Precedence +_ +\*(FC(\^\*(FIr\*(FC)\*(FR~regular expression (for grouping) +\*(FIc\*(FR~if non-special character, matches itself +\*(FC\e\*(FI\^c\*(FR~turn off special meaning of \*(FIc\fP +\*(FC^\*(FR~beginning of string (note: \*(FInot\fP line) +\*(FC$\*(FR~end of string (note: \*(FInot\fP line) +\*(FC.\*(FR~any single character, including newline +\*(FC[\*(FR...\*(FC]\*(FR~any one character in ... or range +\*(FC[^\*(FR...\*(FC]\*(FR~any one character not in ... or range +\*(CB\*(FC\ey\*(FR~word boundary +\*(FC\eB\*(FR~middle of a word +\*(FC\e<\*(FR~beginning of a word +\*(FC\e>\*(FR~end of a word +\*(FC\es\*(FR~any whitespace character +\*(FC\eS\*(FR~any non-whitespace character +\*(FC\ew\*(FR~any word-constituent character +\*(FC\eW\*(FR~any non-word-constituent character +\*(FC\e`\*(FR~beginning of a string +\*(FC\e'\*(FR~end of a string\*(CD +\*(FIr\*(FC*\*(FR~zero or more occurrences of \*(FIr\*(FR +\*(FIr\*(FC+\*(FR~one or more occurrences of \*(FIr\*(FR +\*(FIr\*(FC?\*(FR~zero or one occurrences of \*(FIr\*(FR +\*(FIr\*(FC{\*(FIn\*(FC,\*(FIm\*(FC}\*(FR~\*(FIn\fP to \*(FIm\fP occurrences of \*(FIr\*(FR \*(CR(POSIX: see note below)\*(CD +\*(FIr1\*(FC|\|\*(FIr2\*(FR~\*(FIr1\*(FR or \*(FIr2\*(FR +.TE +.sp .5 +.fi +The \*(FIr\*(FC{\*(FIn\*(FC,\*(FIm\*(FC}\*(FR notation is called an +\*(FIinterval expression\fP. +\*(CRNot supported by +\*(MK or \*(NK.\*(CX +.sp .5 +\*(CDIn regular expressions, within character ranges +(\*(FC[\*(FR...\*(FC]\*(FR), +the notation \*(FC[[:\*(FIclass\*(FC:]]\*(FR defines character classes\*(CD: +.sp .5 +.TS +center, tab(~); +lp8 lp8 lp8 lp8. +\*(FCalnum\*(FR~alphanumeric~\*(FClower\*(FR~lowercase +\*(FCalpha\*(FR~alphabetic~\*(FCprint\*(FR~printable +\*(FCblank\*(FR~space or tab~\*(FCpunct\*(FR~punctuation +\*(FCcntrl\*(FR~control~\*(FCspace\*(FR~whitespace +\*(FCdigit\*(FR~decimal~\*(FCupper\*(FR~uppercase +\*(FCgraph\*(FR~non-spaces~\*(FCxdigit\*(FR~hexadecimal\*(CX +.TE +.fi +.EB "\s+2\f(HBREGULAR EXPRESSIONS\*(FR\s0" + +.\" --- Environment Variables +.ES +.fi +\*(CDThe environment variable \*(FCAWKPATH\fP specifies a search path to use +when finding source files named with the \*(FC\-f\fP +option. +The default path is +\*(FC".:/usr/local/share/awk"\*(FR. +.\" if this variable does not exist. +.\" (The actual directory may vary, +.\" depending upon how \*(GK was built and installed.) +If a file name given to the \*(FC\-f\fP option contains a ``/'' character, +no path search is performed. +.sp .5 +The variable \*(FCAWKLIBPATH\fP +specifies the search path for dynamic extensions to use +with \*(FC@load\fP and the \*(FC\-l\fP option. +.sp .5 +For socket communication, +\*(FCGAWK_SOCK_RETRIES\fP +controls the number of connection retries, and +\*(FCGAWK_MSEC_SLEEP\fP controls +the interval between retries. +The interval is in milliseconds. On systems that do not support +\*(FIusleep\fP(3), +the value is rounded up to an integral number of seconds. +.sp .5 +The value of \*(FCGAWK_READ_TIMEOUT\fP specifies the time, in milliseconds, +for \*(GK to +wait for input before returning with an error. +.sp .5 +If \*(FCPOSIXLY_CORRECT\fP exists +.\" in the environment, +then \*(GK +behaves exactly as if the \*(FC\-\^\-posix\fP option had been given.\*(CB +.EB "\s+2\f(HBENVIRONMENT VARIABLES (\*(GK\f(HB)\*(FR\s0" +.BT + +.\" --- Localization +.ES +.fi +\*(CDThere are several steps involved in producing and running a localizable +\*(AK program. +.sp .5 +1. Add a \*(FCBEGIN\*(FR action to assign a value to the +\*(FCTEXTDOMAIN\*(FR variable to set the text domain for +your program. +.sp .3 +.ti +5n +\*(FCBEGIN { TEXTDOMAIN = "myprog" }\*(FR +.sp .3 +This allows \*(GK to find the \*(FC\&.gmo\*(FR +file associated with your program. +Without this step, \*(GK uses the \*(FCmessages\*(FR text domain, +which probably won't work. +.sp .5 +2. Mark all strings that should be translated with leading underscores. +.sp .5 +3. Use the +\*(FCbindtextdomain()\*(FR, +\*(FCdcgettext()\*(FR, +and/or +\*(FCdcngettext()\*(FR +functions in your program, as appropriate. +.sp .5 +4. Run +.sp .3 +.ti +3n +\*(FCgawk\0\-\^\-gen\-pot\0\-f\0myprog.awk\0>\0myprog.pot\*(FR +.sp .3 +to generate a \*(FC\&.pot\*(FR +file for your program. +.sp .5 +5. Provide appropriate translations, and build and install a corresponding +\*(FC\&.gmo\*(FR file. +.sp .5 +The internationalization features are described in full detail in \*(AM.\*(CB +.EB "\s+2\f(HBLOCALIZATION (\*(GK\f(HB)\*(FR\s0" + +.\" --- Special Filenames +.ES +.fi +\*(CDAll three \*(FCawk\fP implementations +recognize certain special filenames internally +when doing I/O redirection from either \*(FCprint\fP +or \*(FCprintf\fP into a file or via \*(FCgetline\fP +from a file. +These filenames +provide access to open file descriptors inherited from the +parent process. They +may also be used on the command line to name data files. +The filenames are: +.sp .5 +.TS +expand; +l lw(2i). +\*(FC"\-"\fP standard input +\*(FC/dev/stdin\fP standard input +\*(FC/dev/stdout\fP standard output +\*(FC/dev/stderr\fP standard error output +.TE +.sp .5 +.fi +\*(CBThe following names are specific to \*(GK. +.sp .5 +.in +.2i +.ti -.2i +\*(FC/dev/fd/\^\*(FIn\*(FR +.br +File associated with the open file descriptor \*(FIn\*(FR. +.ti -.2i +\*(FC/inet/tcp/\*(FIlport\*(FC/\*(FIrhost\*(FC/\*(FIrport\*(FR +.br +.ti -.2i +\*(FC/inet4/tcp/\*(FIlport\*(FC/\*(FIrhost\*(FC/\*(FIrport\*(FR +.br +.ti -.2i +\*(FC/inet6/tcp/\*(FIlport\*(FC/\*(FIrhost\*(FC/\*(FIrport\*(FR +.br +Files for TCP/IP connections on local port \*(FIlport\*(FR to +remote host \*(FIrhost\*(FR on remote port \*(FIrport\*(FR. +Use a port of \*(FC0\*(FR to have the system pick a port. +Use \*(FC/inet4\fP to force an IPv4 connection, +and \*(FC/inet6\fP to force an IPv6 connection. +Plain \*(FC/inet\fP uses the system default (probably IPv4). +Usable only with the \*(FC|&\*(FR two-way I/O operator. +.ti -.2i +\*(FC/inet/udp/\*(FIlport\*(FC/\*(FIrhost\*(FC/\*(FIrport\*(FR +.br +.ti -.2i +\*(FC/inet4/udp/\*(FIlport\*(FC/\*(FIrhost\*(FC/\*(FIrport\*(FR +.br +.ti -.2i +\*(FC/inet6/udp/\*(FIlport\*(FC/\*(FIrhost\*(FC/\*(FIrport\*(FR +.br +Similar, but use UDP/IP instead of TCP/IP.\*(CL +.in -.2i +.EB "\s+2\f(HBSPECIAL FILENAMES\*(FR\s0" + +.BT + +.\" --- Input Control +.ES +.fi +.TS +expand; +l lw(1.8i). +\*(FCgetline\fP T{ +Set \*(FC$0\fP from next record; +set \*(FCNF\*(FR, \*(FCNR\*(FR, \*(FCFNR\*(FR. +T} +\*(FCgetline < \*(FIfile\*(FR Set \*(FC$0\fP from next record of \*(FIfile\*(FR; set \*(FCNF\*(FR. +\*(FCgetline \*(FIv\*(FR T{ +Set \*(FIv\fP from next input record; +set \*(FCNR\*(FR, \*(FCFNR\*(FR. +T} +\*(FCgetline \*(FIv \*(FC< \*(FIfile\*(FR Set \*(FIv\fP from next record of \*(FIfile\*(FR. +\*(FIcmd \*(FC| getline\*(FR Pipe into \*(FCgetline\*(FR; set \*(FC$0\*(FR, \*(FCNF\*(FR. +\*(FIcmd \*(FC| getline \*(FIv\*(FR Pipe into \*(FCgetline\*(FR; set \*(FIv\*(FR. +.\" \*(CB\*(FIcmd \*(FC|& getline\*(FR Coprocess pipe into \*(FCgetline\*(FR; set \*(FC$0\*(FR, \*(FCNF\*(FR. +.TE +.fi +.in +.2i +.ti -.2i +\*(CB\*(FIcmd \*(FC|& getline\*(FR +.br +Coprocess pipe into \*(FCgetline\*(FR; set \*(FC$0\*(FR, \*(FCNF\*(FR. +.br +.ti -.2i +\*(FIcmd \*(FC|& getline \*(FIv\*(FR +.br +Coprocess pipe into \*(FCgetline\*(FR; set \*(FIv\*(FR. +.ti -.2i +\*(CD\*(FCnext\fP +.br +Stop processing the current input +record. Read next input record and +start over with the first pattern in the +program. Upon end of the input data, +execute any \*(FCEND\fP rule(s). +.br +.ti -.2i +\*(FCnextfile\fP +.br +Stop processing the current input file. +The next input record comes from the +next input file. Update \*(FCFILENAME\fP \*(CBand +\*(FCARGIND\fP\*(CD, reset \*(FCFNR\fP to 1, +and start over with the first +pattern. At end +of file, execute any \*(CB\*(FCENDFILE\fP and\*(CD \*(FCEND\fP rule(s). +.in -.2i +.sp .5 +.fi +\*(FCgetline\*(FR returns 1 on success, zero on end of file, +and \-1 on an error. +\*(CBFor retryable I/O, \*(FCgetline\*(FR returns \-2. +All versions set \*(FCRT\fP. +Upon an error, \*(FCERRNO\*(FR describes +the problem.\*(CX +.EB "\s+2\f(HBINPUT CONTROL\*(FR\s0" +.sp .6 +.\" --- Output Control +.ES +.fi +.in +.2i +.ti -.2i +\*(CD\*(FCfflush(\*(FR[\*(FIfile\^\*(FR]\*(FC)\*(FR +.br +Flush any buffers associated +with the open output file or pipe \*(FIfile\*(FR. +If no \*(FIfile\fP, or if +\*(FIfile\fP is null, then flush all open output files and pipes. +.ti -.2i +\*(FCprint\fP +.br +Print the current record. Terminate output record +with \*(FCORS\fP. +.ti -.2i +\*(FCprint \*(FIexpr-list\*(FR +.br +Print expressions. Each expression is separated +by the value of \*(FCOFS\fP. Terminate the output record +with \*(FCORS\fP. +.ti -.2i +\*(FCprintf \*(FIfmt\*(FC, \*(FIexpr-list\*(FR +.br +Format and print (see \fHPrintf Formats\fP). +.ti -.2i +\*(FCsystem(\*(FIcmd\*(FC)\*(FR +.br +Execute the command \*(FIcmd\*(FR, +and return the exit status +\*(CR(may not be available on non-POSIX systems)\*(CD. +.sp .5 +.in -.2i +I/O redirections may be used with both \*(FCprint\fP and \*(FCprintf\fP. +.sp .5 +.in +.2i +.ti -.2i +\*(CD\*(FCprint "hello" > \*(FIfile\*(FR +.br +Print data to \*(FIfile\fP. The first time the file is written to, it +is truncated. Subsequent commands append data. +.ti -.2i +\*(FCprint "hello" >> \*(FIfile\*(FR +.br +Append data to \*(FIfile\fP. The previous contents of \*(FIfile\*(FR are not lost. +.ti -.2i +\*(FCprint "hello" | \*(FIcmd\*(FR +.br +Print data down a pipeline to \*(FIcmd\*(FR. +.ti -.2i +\*(CB\*(FCprint "hello" |& \*(FIcmd\*(FR +.br +Print data down a pipeline to coprocess \*(FIcmd\*(FR.\*(CX +.in -.2i +.EB "\s+2\f(HBOUTPUT CONTROL\*(FR\s0" +.sp .6 +.\" --- Closing Redirections +.ES +.fi +.in +.2i +.ti -.2i +\*(CD\*(FCclose(\*(FIfile\*(FC)\*(FR +.br +Close input or output file, pipe \*(CBor coprocess.\*(CD +.ti -.2i +\*(CB\*(FCclose(\*(FIcommand\*(FC, \*(FIhow\*(FC)\*(FR +.br +Close one end of coprocess pipe. +Use \*(FC"to"\*(FR for the write end, or +\*(FC"from"\*(FR for the read end.\*(CD +.in -.2i +.sp .5 +On success, \*(FCclose()\*(FR returns zero for a file, or the exit status for a process. +It returns \-1 if \*(FIfile\*(FR +was never opened, or +if there was a system problem. +\*(CB\*(FCERRNO\*(FR describes +the error.\*(CX +.EB "\s+2\f(HBCLOSING REDIRECTIONS\*(FR\s0" + +.BT + +.\" --- Printf Formats +.ES +.fi +\*(CDThe \*(FCprintf\fP statement and +\*(FCsprintf()\fP function +accept the following conversion specification formats: +.sp .5 +.nf +\*(FC%c\fP An \s-1ASCII\s+1 character +\*(FC%d\fP, \*(FC%i\fP A decimal number (the integer part) +\*(FC%e\fP A floating point number of the form + \*(FC[\-]d.dddddde[+\^\-]dd\*(FR +\*(FC%E\fP Like \*(FC%e\fP, but use \*(FCE\fP instead of \*(FCe\*(FR +\*(FC%f\fP A floating point number of the form + \*(FC[\-]ddd.dddddd\*(FR +\*(FC%F\fP Like \*(FC%f\fP, but use capital letters for infinity and + not-a-number values. +\*(FC%g\fP Use \*(FC%e\fP or \*(FC%f\fP, whichever is shorter, with + nonsignificant zeros suppressed +\*(FC%G\fP Like \*(FC%g\fP, but use \*(FC%E\fP instead of \*(FC%e\*(FR +\*(FC%o\fP An unsigned octal integer +\*(FC%u\fP An unsigned decimal integer +\*(FC%s\fP A character string +\*(FC%x\fP An unsigned hexadecimal integer +\*(FC%X\fP Like \*(FC%x\fP, but use \*(FCABCDEF\fP for 10\(en15 +\*(FC%%\fP A literal \*(FC%\fP; no argument is converted +.sp .5 +.fi +Optional, additional parameters may lie between the \*(FC%\fP +and the control letter: +.sp .5 +.TS +expand; +l lw(2.2i). +\*(CB\*(FIcount\*(FC$\*(FR T{ +Use the +\*(FIcount\*(FR'th +argument at this point in the formatting +(a \*(FIpositional specifier\*(FR). +For use in translated versions of +format strings, not in the original text of an AWK program.\*(CD +T} +\*(FC\-\fP T{ +Left-justify the expression within its field. +T} +\*(FIspace\fP T{ +For numeric conversions, prefix positive values +with a space and negative values with a +minus sign. +T} +\*(FC+\fP T{ +Use before the \*(FIwidth\fP modifier to always +supply a sign for numeric conversions, even if +the data to be formatted is positive. The \*(FC+\fP +overrides the space modifier. +T} +\*(FC#\fP T{ +Use an ``alternate form'' for some control letters: +T} + \*(FC%o\*(FR T{ +Supply a leading zero. +T} + \*(FC%x\*(FR, \*(FC%X\*(FR T{ +Supply a leading \*(FC0x\*(FR or \*(FC0X\*(FR for a nonzero result. +T} + \*(FC%e\*(FR, \*(FC%E\*(FR, \*(FC%f\*(FR T{ +The result always has a decimal point. +T} + \*(FC%g\*(FR, \*(FC%G\*(FR T{ +Trailing zeros are not removed. +T} +\*(FC0\fP T{ +Pad output with zeros instead of spaces. +This applies only to the numeric output formats. +Only has an effect when the field width is wider +than the value to be printed. +T} +\*(CB\*(FC'\*(FR T{ +Use the locale's thousands separator and decimal +point characters.\*(CD +T} +\*(FIwidth\fP T{ +Pad the field to this width. The field is normally +padded with spaces. If the \*(FC0\fP flag has been used, +pad with zeros. +T} +\*(FC.\*(FIprec\*(FR T{ +Precision. +The meaning of the \*(FIprec\*(FR varies by control letter: +T} + \*(FC%d\*(FR,\|\*(FC%o\*(FR,\|\*(FC%i\fP, \0 + \*(FC%u\*(FR,\|\*(FC%x\*(FR,\|\*(FC%X\fP T{ +The minimum number of digits to print. +T} + \*(FC%e\*(FR, \*(FC%E\*(FR, \*(FC%f\*(FR T{ +The number of digits to print to the right of the decimal point. +T} + \*(FC%g\*(FR, \*(FC%G\fP T{ +The maximum number of significant digits. +T} + \*(FC%s\fP T{ +The maximum number of characters to print. +T} +.TE +.sp .5 +.fi +Use a +\*(FC*\fP in place of either the \*(FIwidth\fP or \*(FIprec\fP +specifications to take their values from +the \*(FCprintf\fP or \*(FCsprintf()\*(FR argument list. +\*(CBUse \*(FC*\*(FIn\*(FC$\*(FR to use positional specifiers +with a dynamic width or precision.\*(CX +.EB "\s+2\f(HBPRINTF FORMATS\*(FR\s0" + + +.BT + +.\" --- User-defined Functions +.ES +.fi +\*(CDFunctions in AWK are defined as follows: +.sp .5 +.nf + \*(FCfunction \*(FIname\*(FC(\*(FIparameter list\*(FC) + { + \*(FIstatements + \*(FC}\*(FR +.sp .5 +.fi +Functions execute when they are called from within expressions +in either patterns or actions. Actual parameters supplied in the function +call instantiate the formal parameters declared in the function. +Arrays are passed by reference, other variables are passed by value. +.sp .5 +Declare local variables as extra parameters +in the parameter list. The convention is to separate local variables from +real parameters by extra spaces in the parameter list. For example: +.sp .5 +.nf + \*(FC# a and b are local + function f(p, q, a, b) + { + \&..... + } +.sp .3 + /abc/ { ... ; f(1, 2) ; ... }\*(FR +.fi +.sp .5 +The left parenthesis in a function call is required +to immediately follow the function name +without any intervening whitespace. +This is to avoid a syntactic ambiguity with the concatenation operator. +This restriction does not apply to the built-in functions. +.sp .5 +Functions may call each other and may be recursive. +Function parameters used as local variables are initialized +to the null string and the number zero upon function invocation. +.sp .5 +\*(CBFunctions may be called indirectly. To do this, assign +the name of the function to be called, as a string, to a variable. +Then use the variable as if it were the name of a function, prefixed with +an ``at'' sign, like so:\*(FC +.nf +.sp .5 + function myfunc() + { + print "myfunc called" + } +.sp .3 + { + the_func = "myfunc" + @the_func() + } +.fi +.sp .5 +\*(FR\*(CDUse \*(FCreturn\fP to return a value from a function. The return value +is undefined if no value is provided, or if the function returns by +``falling off'' the end. +.sp .5 +\*(CLThe word +\*(FCfunc\fP +may be used in place of +\*(FCfunction\*(FR. +\*(CRThis usage is deprecated.\*(CX +.EB "\s+2\f(HBUSER-DEFINED FUNCTIONS\*(FR\s0" +.sp .6 +.\" --- Built-in Numeric Functions +.ES +.fi +.TS +expand; +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. +\*(FCsqrt(\*(FIexpr\*(FC)\*(FR The square root of \*(FIexpr\fP. +\&\*(FCsrand(\*(FR[\*(FIexpr\^\*(FR]\*(FC)\*(FR T{ +Use \*(FIexpr\fP as the new seed for the random number +generator. If no \*(FIexpr\fP, use the time of day. +Return the \" random number generator's +previous seed.\*(CX +T} +.TE +.EB "\s+2\f(HBNUMERIC FUNCTIONS\*(FR\s0" +.BT + +.\" --- Built-in String Functions +.ES +.fi +.in +.2i +.ti -.2i +\*(CB\*(FCasort(\*(FIs \*(FR[\*(FC,\*(FI d \*(FR[\*(FC,\*(FI comp\*(FR]]\*(FC)\*(FR +.br +Sort the source array \*(FIs\*(FR, replacing the indices with numeric +values 1 through \*(FIn\*(FR (the number of elements in the array), +and return the number of elements. +If destination \*(FId\*(FR is supplied, copy \*(FIs\*(FR to \*(FId\*(FR, +sort \*(FId\*(FR, and leave \*(FIs\*(FR unchanged. +Use \*(FIcomp\*(FR to compare indices and elements.\*(CD +.ti -.2i +\*(CB\*(FCasorti(\*(FIs \*(FR[\*(FC,\*(FI d \*(FR[\*(FC,\*(FI comp\*(FR]]\*(FC)\*(FR +.br +Like \*(FCasort()\*(FR, but sort on the indices, not +the values. The original values are thrown array, so provide a +second array to preserve the first.\*(CD +.ti -.2i +\*(CB\*(FCgensub(\*(FIr\*(FC, \*(FIs\*(FC, \*(FIh \*(FR[\*(FC, \*(FIt\*(FR]\*(FC)\*(FR +.br +Search the target string +\*(FIt\fP for matches of the regular expression \*(FIr\*(FR. If +\*(FIh\fP is a string beginning with \*(FCg\fP or \*(FCG\*(FR, +replace all matches of \*(FIr\fP with \*(FIs\*(FR. Otherwise, \*(FIh\fP +is a number indicating which match of \*(FIr\fP to replace. +If \*(FIt\fP is not supplied, use \*(FC$0\fP instead. Within the +replacement text \*(FIs\*(FR, the sequence \*(FC\e\*(FIn\*(FR, +where \*(FIn\fP is a digit from 1 to 9, indicates just +the text that matched the \*(FIn\*(FRth parenthesized subexpression. +The sequence \*(FC\e0\fP represents the entire matched text, as does +the character \*(FC&\*(FR. Unlike \*(FCsub()\fP and \*(FCgsub()\*(FR, +the function returns the modified string; +the original target string is \*(FInot\fP changed.\*(CD +.ti -.2i +\*(FCgsub(\*(FIr\*(FC, \*(FIs \*(FR[\*(FC, \*(FIt\*(FR]\*(FC)\*(FR +.br +For each substring matching the +regular expression \*(FIr\fP in the string \*(FIt\*(FR, substitute the +string \*(FIs\*(FR, and return the number of substitutions. If +\*(FIt\fP is not supplied, use \*(FC$0\*(FR. An \*(FC&\fP in the +replacement text is replaced with the text that was actually matched. +Use \*(FC\e&\fP to get a literal \*(FC&\*(FR. See \*(AM +for a fuller discussion of the rules for \*(FC&\*(FR's and backslashes +in the replacement text of \*(CB\*(FCgensub()\*(FR,\*(CD \*(FCsub()\*(FR +and \*(FCgsub().\*(FR +.ti -.2i +\*(FCindex(\*(FIs\*(FC, \*(FIt\*(FC)\*(FR +.br +Return the index of the string +\*(FIt\fP in the string \*(FIs\*(FR, or zero if \*(FIt\fP is not present. +.ti -.2i +\*(FClength(\*(FR[\*(FIs\*(FR]\*(FC)\*(FR +.br +Return the length of the string +\*(FIs\*(FR, or the length of \*(FC$0\fP if \*(FIs\fP is not supplied. +\*(CLWith an array argument, return the number of elements +in the array.\*(CD +.ti -.2i +\*(FCmatch(\*(FIs\*(FC, \*(FIr \*(CB\*(FR[\*(FC, \*(FIa\*(FR]\*(CD\*(FC)\*(FR +.br +Return the position in +\*(FIs\fP where the regular expression \*(FIr\fP occurs, or zero if +\*(FIr\fP is not present, and set the values of variables +\*(FCRSTART\fP +and \*(FCRLENGTH\*(FR. +\*(CBIf \*(FIa\*(FR is supplied, the text matching all of \*(FIr\*(FR +is placed in \*(FIa\*(FC[0]\*(FR. If there were parenthesized +subexpressions, the matching texts are placed +in \*(FIa\*(FC[1]\*(FR, \*(FIa\*(FC[2]\*(FR, and so on. +Subscripts +\*(FCa[\*(FIn\^\*(FC, "start"]\*(FR, +and +\*(FCa[\*(FIn\^\*(FC, "length"]\*(FR +provide the starting index in the string and length, +respectively, of each matching substring.\*(CD +.ti -.2i +\*(CB\*(FCpatsplit(\*(FIs\*(FC, \*(FIa \*(FR[\*(FC, \*(FIr \*(CB\*(FR[\*(FC, \*(FIseps \*(FR] \*(FR] \*(FC)\*(FR +.br +Split the string +\*(FIs\fP into the array \*(FIa\fP +and the array \*(FIseps\fP of separator strings +using the regular expression \*(FIr\*(FR, +and return the number of fields. +Element values are the portions of \*(FIs\fP that matched \*(FIr\fP. +The value of \*(FIseps\fP[\*(FIi\fP] is the separator that appeared in +front of \*(FIa\fP[\*(FIi\fP+1]. +If \*(FIr\fP is omitted, use \*(FCFPAT\fP instead. +Clear the arrays \*(FIa\fP and \*(FIseps\fP first. +Splitting behaves identically to field splitting with \*(FCFPAT\fP.\*(CD +.ti -.2i +\*(FCsplit(\*(FIs\*(FC, \*(FIa \*(FR[\*(FC, \*(FIr \*(CB\*(FR[\*(FC, \*(FIseps \*(FR]\*(CD \*(FR] \*(FC)\*(FR +.br +Split the string +\*(FIs\fP into the array \*(FIa\fP \*(CBand the array \*(FIseps\fP of separator strings\*(CD +using the regular expression \*(FIr\*(FR, +and return the number of fields. If \*(FIr\fP is omitted, use \*(FCFS\fP +instead. +Clear the arrays \*(FIa\fP \*(CBand \*(FIseps\fP\*(CD first. +Splitting behaves identically to field splitting. +(See \fHFields\fP.) +.ti -.2i +\*(FCsprintf(\*(FIfmt\*(FC, \*(FIexpr-list\*(FC)\*(FR +.br +Print \*(FIexpr-list\fP +according to \*(FIfmt\*(FR, and return the result.\*(CX +.in -.2i +.EB "\s+2\f(HBSTRING FUNCTIONS\*(FR\s0" + +.BT + +.\" --- Built-in String Functions +.ES +.fi +.in +.2i +.ti -.2i +\*(CB\*(FCstrtonum(\*(FIs\*(FC)\*(FR +.br +Examine \*(FIs\*(FR, and return its numeric value. +If \*(FIs\*(FR begins with a leading \*(FC0\*(FR, +treat it as an octal number. +If \*(FIs\*(FR begins with a leading \*(FC0x\*(FR +or \*(FC0X\*(FR, treat +\*(FIs\*(FR as a hexadecimal number. Otherwise, +treat the number as decimal.\*(CD +.ti -.2i +\*(FCsub(\*(FIr\*(FC, \*(FIs \*(FR[\*(FC, \*(FIt\*(FR]\*(FC)\*(FR +.br +Just like +\*(FCgsub()\*(FR, but replace only the first matching substring.\*(CX +.ti -.2i +\*(CD\*(FCsubstr(\*(FIs\*(FC, \*(FIi \*(FR[\*(FC, \*(FIn\*(FR]\*(FC)\*(FR +.br +Return the at most +\*(FIn\*(FR-character substring of \*(FIs\fP starting at \*(FIi\*(FR. +If \*(FIn\fP is omitted, use the rest of \*(FIs\fP. +.ti -.2i +\*(FCtolower(\*(FIstr\*(FC)\*(FR +.br +Return a copy of the string \*(FIstr\*(FR, +with all the uppercase characters in \*(FIstr\fP translated to their +corresponding lowercase counterparts. Non-alphabetic characters are +left unchanged. +.ti -.2i +\*(FCtoupper(\*(FIstr\*(FC)\*(FR +.br +Return a copy of the string \*(FIstr\*(FR, +with all the lowercase characters in \*(FIstr\fP translated to their +corresponding uppercase counterparts. Non-alphabetic characters are +left unchanged.\*(CX +.in -.2i +.EB "\s+2\f(HBSTRING FUNCTIONS (continued)\*(FR\s0" +.sp .6 +.\" --- Built-in Time Functions +.ES +.fi +\*(CD\*(GK and \*(MK +provide the following functions for obtaining time stamps and +formatting them. +.sp .5 +.fi +.in +.2i +.ti -.2i +\*(FCmktime(\*(FIdatespec \*(CB\*(FR[\*(FC, \*(FIutc-flag\*(FR]\*(FC\*(CD)\*(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. +\*(CBIf \*(FIutc-flag\*(FR +is present and is non-zero or non-null, the result +is in UTC, otherwise it is in local time.\*(CD +.ti -.2i +\*(FCstrftime(\*(FR[\*(FIformat \*(FR[\*(FC, \*(FItimestamp\*(FR[\*(FC, \*(FIutc-flag\*(FR]]]\*(FC)\*(FR +.br +Format \*(FItimestamp\fP +according to the specification in \*(FIformat\*(FR. The +\*(FItimestamp\fP should be of the same form as returned by +\*(FCsystime()\*(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. +If \*(FItimestamp\fP is missing, use the current time of day. If +\*(FIformat\fP is missing, use \*(FCPROCINFO["strftime"]\fP. +The default value is +equivalent to the output +of \*(FIdate\*(FR\^(1). +.ti -.2i +\*(FCsystime()\fP +.br +Return the current time of day as the number of +seconds since the Epoch.\*(CL +.in -.2i +.EB "\s+2\f(HBTIME FUNCTIONS\*(FR\s0" +.sp .6 +.\" --- Built-in Bit Manipulation Functions +.ES +.fi +\*(CD\*(GK +provides the following bit manipulation functions. +.sp .5 +.fi +.in +.2i +.ti -.2i +\*(FCand(\*(FIv1\*(FC, \*(FIv2\*(FR [\*(FC,\*(FR ... ]\*(FC)\*(FR +.br +Return the bitwise AND of the arguments. +.ti -.2i +\*(FCcompl(\*(FIval\*(FC)\*(FR +.br +Return the bitwise complement of +\*(FIval\*(FR. +.ti -.2i +\*(FClshift(\*(FIval\*(FC, \*(FIcount\*(FC)\*(FR +.br +Return the value of \*(FIval\*(FR, +shifted left by \*(FIcount\*(FR bits. +.ti -.2i +\*(FCor(\*(FIv1\*(FC, \*(FIv2\*(FR [\*(FC,\*(FR ... ]\*(FC)\*(FR +.br +Return the bitwise OR of the arguments. +.ti -.2i +\*(FCrshift(\*(FIval\*(FC, \*(FIcount\*(FC)\*(FR +.br +Return the value of \*(FIval\*(FR, +shifted right by \*(FIcount\*(FR bits. +.ti -.2i +\*(FCxor(\*(FIv1\*(FC, \*(FIv2\*(FR [\*(FC,\*(FR ... ]\*(FC)\*(FR +.br +Return the bitwise XOR of the arguments.\*(CB +.in -.2i +.EB "\s+2\f(HBBIT MANIPULATION FUNCTIONS (\*(GK\f(HB)\*(FR\s0" +.sp .6 +.\" --- Extensions +.ES +.fi +.in +.2i +.ti -.2i +\*(CD\*(FC@load "\*(FIextension\*(FC"\*(FR +.br +Dynamically load the named \*(FIextension\*(FR. +This adds new built-in functions to \*(GK. +.\" The extension should use the API defined by the +.\" \*(FCgawkapi.h\*(FR header file, as documented in +.\" the full manual. +The extension is loaded during the parsing of the program. +See the manual for details.\*(CB +.in -.2i +.EB "\s+2\f(HBDYNAMIC EXTENSIONS (\*(GK\f(HB)\*(FR\s0" +.BT + +.\" --- Type Functions +.ES +.fi +.in +.2i +.ti -.2i +\*(CD\*(FCisarray(\*(FIx\*(FC)\*(FR +.br +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 +.\" --- Built-in Internationalization Functions +.ES +.fi +\*(CD\*(GK +provides the following functions for runtime message translation. +.in +.2i +.sp .5 +.ti -.2i +\*(FCbindtextdomain(\*(FIdirectory \*(FR[\*(FC, \*(FIdomain\*(FR]\*(FC)\*(FR +.br +Specify the directory where \*(GK looks for the \*(FC\&.gmo\*(FR +files, in case they +will not or cannot be placed in the ``standard'' locations +(e.g., during testing). +Return the directory where \*(FIdomain\*(FR is ``bound.'' +.sp .5 +The default \*(FIdomain\*(FR is the value of \*(FCTEXTDOMAIN\*(FR. +When \*(FIdirectory\*(FR is the null string (\*(FC"\^"\*(FR), +\*(FCbindtextdomain()\*(FR returns the current binding for the +given \*(FIdomain\*(FR. +.ti -.2i +\*(FCdcgettext(\*(FIstring \*(FR[\*(FC, \*(FIdomain \*(FR[\*(FC, \*(FIcategory\*(FR]]\*(FC)\*(FR +.br +Return the translation of \*(FIstring\*(FR in text domain +\*(FIdomain\*(FR for locale category \*(FIcategory\*(FR. +The default value for \*(FIdomain\*(FR is the current value of \*(FCTEXTDOMAIN\*(FR. +The default value for \*(FIcategory\*(FR is \*(FC"LC_MESSAGES"\*(FR. +.sp .5 +If you supply a value for \*(FIcategory\*(FR, it must be a string equal to +one of the known locale categories. +You must also supply a text domain. Use \*(FCTEXTDOMAIN\*(FR +to use the current domain. +.ti -.2i +\*(FCdcngettext(\*(FIstring1\*(FC, \*(FIstring2\*(FC, \*(FInumber\*(FR [\*(FC, \*(FIdom \*(FR[\*(FC, \*(FIcat\*(FR]]\*(FC)\*(FR +.br +Return the plural form used for \*(FInumber\*(FR of the translation of +\*(FIstring1\*(FR and \*(FIstring2\*(FR in text domain +\*(FIdom\*(FR for locale category \*(FIcat\*(FR. +The default value for \*(FIdom\*(FR is the current value of \*(FCTEXTDOMAIN\*(FR. +The default for \*(FIcat\*(FR is \*(FC"LC_MESSAGES"\*(FR. +.sp .5 +If you supply a value for \*(FIcat\*(FR, it must be a string equal to +one of the known locale categories. +You must also supply a text domain. Use \*(FCTEXTDOMAIN\*(FR +to use the current domain.\*(CB +.in -.2i +.EB "\s+2\f(HBINTERNATIONALIZATION (\*(GK\f(HB)\*(FR\s0" +.sp .5 +.\" --- FTP/HTTP/GIT Information +.ES +.nf +\*(CDHost: \*(FCftp.gnu.org\*(FR +File: \*(FC/gnu/gawk/gawk-4.2.1.tar.gz\fP +.in +.2i +.fi +GNU \*(AK (\*(GK). There may be a later version. +.in -.2i +.nf +.sp .4 +.\" http://www.cs.princeton.edu/~bwk/btl.mirror/ +.\" awk.tar.gz +.\" .br +\*(FCgit clone git://github.com/onetrueawk/awk\fP +.in +.2i +.fi +\*(NK. This version requires an ANSI C compiler; +GCC (the GNU Compiler Collection) works well. +.in -.2i +.nf +.sp .4 +Host: \*(FCinvisible-island.net\*(FR +File: \*(FC/mawk/mawk.tar.gz\fP +.in +.2i +.fi +Michael Brennan's \*(MK. Thomas Dickey now +maintains it.\*(CX +.in -.2i +.EB "\s+2\f(HBFTP/HTTP/GIT INFORMATION\*(FR\s0" +.sp .5 +.\" --- Copying Permissions +.ES +.fi +\*(CDCopyright \(co 1996\(en2005, +2007, 2009\(en2018 Free Software Foundation, Inc. +.sp .5 +Permission is granted to make and distribute verbatim copies of this +reference card provided the copyright notice and this permission notice +are preserved on all copies. +.sp .5 +Permission is granted to copy and distribute modified versions of this +reference card under the conditions for verbatim copying, provided that +the entire resulting derived work is distributed under the terms of a +permission notice identical to this one. +.sp .5 +Permission is granted to copy and distribute translations of this +reference card into another language, under the above conditions for +modified versions, except that this permission notice may be stated in a +translation approved by the Foundation.\*(CX +.EB "\s+2\f(HBCOPYING PERMISSIONS\*(FR\s0" +.\" Need the BT here to get the final page number + +.ig +.ES +\*(CX +.sp 10 +.EB "\s+2\f(HBNOTES\*(FR\s0" +.. + +.BT diff --git a/doc/awkforai.txt b/doc/awkforai.txt new file mode 100644 index 0000000..2908da5 --- /dev/null +++ b/doc/awkforai.txt @@ -0,0 +1,18 @@ +Sun Dec 9 11:58:23 IST 2012 +============================ + +The original of this file was a draft of an article written in 1996 by +Ronald P. Lui for an ACM Sigplan publication, explaining why he used +gawk for teaching introductory Artificial Intelligence courses. + +Since it was not clear as to copying permissions and so on, it has been +removed from the gawk distribution. + +A quick web search shows that this same draft is available at +http://www.cs.wustl.edu/~loui/sigplan and the final article is available +from the ACM: http://dl.acm.org/citation.cfm?id=242908 + +The article itself is recommended reading. + +Arnold Robbins +arnold@skeeve.com diff --git a/doc/bc_notes b/doc/bc_notes new file mode 100644 index 0000000..b548cec --- /dev/null +++ b/doc/bc_notes @@ -0,0 +1,323 @@ +Op Codes +======== + Op_illegal, /* illegal entry == 0 */ + + /* binary operators */ + Op_times, + Op_times_i, all _i operators here are used to optimise arithmetic + Op_quotient, by converting push, push , op to just push, op_i + Op_quotient_i, + Op_mod, + Op_mod_i, + Op_plus, + Op_plus_i, + Op_minus, + Op_minus_i, + Op_exp, + Op_exp_i, + Op_concat, + + /* line range instruction pairs */ + Op_line_range, /* flags for Op_cond_pair */ + Op_cond_pair, /* conditional pair */ + + Op_subscript, calculate array subscript + + /* unary operators */ + Op_preincrement, + Op_predecrement, + Op_postincrement, + Op_postdecrement, + Op_unary_minus, + Op_field_spec, usage: push #, field_spec -> $# + + /* unary relationals */ + Op_not, + + /* assignments */ + Op_assign, simple assign + Op_assign_times, *= etc + Op_assign_quotient, + Op_assign_mod, + Op_assign_plus, + Op_assign_minus, + Op_assign_exp, + Op_assign_concat, optimised concatenation + + /* boolean binaries */ + Op_and, /* a left subexpression in && */ + Op_and_final, /* right subexpression of && */ + Op_or, + Op_or_final, + + /* binary relationals */ + Op_equal, + Op_notequal, + Op_less, + Op_greater, + Op_leq, + Op_geq, + Op_match, + Op_match_rec, /* match $0 */ + Op_nomatch, + + Op_rule, + + /* keywords */ + Op_K_case, + Op_K_default, + Op_K_break, + Op_K_continue, + Op_K_print, + Op_K_print_rec, + Op_K_printf, + Op_K_next, + Op_K_exit, + Op_K_return, + Op_K_delete, + Op_K_delete_loop, + Op_K_getline, + Op_K_nextfile, + + Op_builtin, + Op_in_array, /* boolean test of membership in array */ + + /* function call instruction pairs */ + Op_func_call, + + Op_push, /* variable */ + Op_push_i, /* number, string */ + Op_push_re, /* regex */ + Op_push_array, + Op_push_param, + Op_push_lhs, var assignment + Op_subscript_lhs, array assignment + Op_field_spec_lhs, field assignment + Op_no_op, /* jump target */ + Op_pop, /* pop an item from the runtime stack */ + Op_jmp, + Op_jmp_true, + Op_jmp_false, + Op_push_loop, /* break (continue) target for loop */ + Op_pop_loop, end of loop + Op_get_record, read next input line + Op_newfile, open next input file + Op_arrayfor_init, initialise array for loop + Op_arrayfor_incr, next in array for loop + Op_arrayfor_final, end of array loop + + Op_var_update, /* update value of NR, NF or FNR */ + Op_var_assign, + Op_field_assign, + + Op_ext_func, + Op_func, + + Op_exec_count, debugging etc + Op_breakpoint, + Op_lint, + Op_exit, /* end of instructions, contains final exit value */ + + /*--------- end proper opcodes -------*/ + + /* program structures */ + Op_K_do, + Op_K_for, + Op_K_arrayfor, + Op_K_while, + Op_K_switch, + Op_K_if, + Op_K_else, + Op_K_function, + Op_cond_exp, + Op_list, + Op_case_list, + + /* I/O redirection for print statements */ + Op_redirect_output, + Op_redirect_append, + Op_redirect_pipe, + Op_redirect_pipein, + Op_redirect_input, + Op_redirect_twoway, + + Op_final /* sentry value, not legal */ + + +INSTRUCTIONs +============ + +typedef struct exp_instruction { + struct exp_instruction *nexti; + union { + NODE *dn; + struct exp_instruction *di; + NODE *(*fptr) P((int)); + long dl; + char *name; + } d; + + union { + long xl; + NODE *xn; + void (*aptr) P((void)); + struct exp_instruction *xi; + struct break_point *bpt; + } x; + + short source_line; + OPCODE opcode; +} INSTRUCTION; + +#define lextok d.name +#define func_name d.name + +#define memory d.dn +#define builtin d.fptr +#define builtin_idx d.dl + +#define expr_count x.xl + +#define target_continue d.di +#define target_jmp d.di +#define target_break x.xi + +/* Op_rule */ +#define in_rule x.xl +#define source_file d.name + +/* Op_K_case, Op_K_default */ +#define target_stmt x.xi + +/* Op_case_list, Op_K_switch */ +#define case_val d.di +#define case_stmt x.xi +#define switch_dflt x.xi +#define switch_body d.di /* pretty printing and profiling */ + +/* Op_K_exit */ +#define target_exit x.xi + +/* Op_exit */ +#define exit_value d.dl + +/* Op_K_getline */ +#define into_var x.xl + +/* Op_K_getline, Op_K_print, Op_K_print_rec, Op_K_printf */ +#define redir_type d.dl + +/* Op_arrayfor_incr */ +#define array_var x.xn + +/* Op_line_range */ +#define triggered x.xl + +/* Op_cond_pair */ +#define line_range x.xi + +/* Op_func_call, Op_func */ +#define func_body x.xn + +/* Op_subscript */ +#define sub_count d.dl + +/* Op_push_lhs, Op_subscript_lhs, Op_field_spec_lhs */ +#define do_reference x.xl + +/* Op_list, Op_rule, Op_func */ +#define lasti d.di +#define firsti x.xi + +/* Op_rule, Op_func */ +#define last_line x.xl +#define first_line source_line + +/* Op_lint */ +#define lint_type d.dl + +/* Op_field_spec_lhs */ +#define target_assign d.di + +/* Op_field_assign */ +#define field_assign x.aptr + +/* Op_concat */ +#define var_concat d.dl + +/* Op_breakpoint */ +#define break_pt x.bpt + +/*------------------ pretty printing/profiling --------*/ + +/* Op_exec_count */ +#define exec_count d.dl + +/* Op_K_while */ +#define while_body d.di + +/* Op_K_do */ +#define doloop_cond d.di + +/* Op_K_for */ +#define forloop_cond d.di +#define forloop_body x.xi + +/* Op_K_if */ +#define branch_if d.di +#define branch_else x.xi + +/* Op_K_else */ +#define branch_end x.xi + +/* Op_line_range */ +#define condpair_left d.di +#define condpair_right x.xi + +Programs consist of a list of INSTRUCTIONs linked by nexti pointers. +Each source statement generates a list of INSTRUCTIONs which are then in turn linked to create the program list. + +The list for a given source statement is delimited by the lasti (last INSTRUCTION) pointer. +(The first INSTRUCTION in any rule is identified by the firsti pointer. This is only used in profiling (I think).) + +Each INSTRUCTION can be linked to a NODE via the d.dn (memory) pointer. + +The BEGIN rule(s) are prepended to the program list and the END rule(s) are appended to complete the program build process. + +At run-time, the "virtual machine" walks the program list using the nexti pointers. + +The list_xxx functions are used to create and manipulate these INSTRUCTION lists. + +list_create creates an INSTRUCTION with opcode Op_list and nexti and lasti pointers pointing to itself (an empty list). + +list_append adds a single INSTRUCTION to the end of an existing list and list_prepend does the same at the start of an existing list. +list_merge adds one list to the end of another (and frees the "header" INSTRUCTION of the added list); + +The list_append, list_prepend and list_merge functions reset the nexti and lasti pointers as needed. + + + +Run-time Stack +============== + +Stack is allocated in eval.c line 1040 with an initial 256 (NODE) entries. +If this stack fills, additional blocks of 256 entries are added. + +The various push operators add NODE entries to the stack for processing by subsequent operators. +Once a stack variable is used and no longer required, it is popped off and (if temporary) freed. +Current stack position is in stack_ptr. + +Most operators (eg builtin functions) expect all of their "arguments" to be on the stack. +Some operators (eg Op_plus_i etc) expect one operand on the stack and another in the NODE linked to the +operator via the d.dn (memory) pointer. + + +Debugger +======== +The dgawk debugger usage is described in README.DGAWK. I suggest that we make -DBCDEBUG a default setting (or remove the ifdefs) +so that the dump and trace commands are always available. + +dgawk operates in exactly the same way as gawk except that it offers the ability to dump the program list, to step through the program list, to set breakpoints and to view variables etc. + +dgawk uses exactly the same "virtual machine" as gawk so the results are identical. The only difference is that dgawk checks to see if any debug action is required before executing each INSTRUCTION. + diff --git a/doc/cardfonts b/doc/cardfonts new file mode 100644 index 0000000..0f528e1 --- /dev/null +++ b/doc/cardfonts @@ -0,0 +1,37 @@ +.\" AWK Reference Card --- Arnold Robbins, arnold@skeeve.com +.\" cardfonts --- this file sets the fonts to use for the reference card +.\" +.\" Copyright (C) 1996 Free Software Foundation, Inc. +.\" +.\" Permission is granted to make and distribute verbatim copies of +.\" this reference card provided the copyright notice and this permission +.\" notice are preserved on all copies. +.\" +.\" Permission is granted to process this file through troff and print the +.\" results, provided the printed document carries copying permission +.\" notice identical to this one except for the removal of this paragraph +.\" (this paragraph not being relevant to the printed reference card). +.\" +.\" Permission is granted to copy and distribute modified versions of this +.\" reference card under the conditions for verbatim copying, provided that +.\" the entire resulting derived work is distributed under the terms of a +.\" permission notice identical to this one. +.\" +.\" Permission is granted to copy and distribute translations of this +.\" reference card into another language, under the above conditions for +.\" modified versions, except that this permission notice may be stated in +.\" a translation approved by the Foundation. +.\" +.ig +Strings for inline font change. +FR - font roman +FI - font italic +FC - font courier +.. +.ds FR \fR +.ds FI \fI +.ds FC \f(CB +.ds RN Times Roman +.ds IN Times Italic +.ds CN Courier Bold +.ds AM \fIGAWK: Effective AWK Programming\fP diff --git a/doc/colors b/doc/colors new file mode 100644 index 0000000..97dbff7 --- /dev/null +++ b/doc/colors @@ -0,0 +1,39 @@ +.\" AWK Reference Card --- Arnold Robbins, arnold@skeeve.com +.\" This file sets the colors to use. +.\" +.\" Copyright (C) 1996,97,99 Free Software Foundation, Inc. +.\" +.\" Permission is granted to make and distribute verbatim copies of +.\" this reference card provided the copyright notice and this permission +.\" notice are preserved on all copies. +.\" +.\" Permission is granted to process this file through troff and print the +.\" results, provided the printed document carries copying permission +.\" notice identical to this one except for the removal of this paragraph +.\" (this paragraph not being relevant to the printed reference card). +.\" +.\" Permission is granted to copy and distribute modified versions of this +.\" reference card under the conditions for verbatim copying, provided that +.\" the entire resulting derived work is distributed under the terms of a +.\" permission notice identical to this one. +.\" +.\" Permission is granted to copy and distribute translations of this +.\" reference card into another language, under the above conditions for +.\" modified versions, except that this permission notice may be stated in +.\" a translation approved by the Foundation. +.\" +.ig +Strings for inline color change. +CR - color red +CG - color green +CL - color light blue +CB - color blue +CD - color dark, i.e. black +CX - color boX, i.e. for the surrounding boxes (red for now) +.. +.ds CR \X'ps: exec 0 .96 .65 0 setcmykcolor' +.ds CG \X'ps: exec 1.0 0 .51 .43 setcmykcolor' +.ds CL \X'ps: exec .69 .34 0 0 setcmykcolor' +.ds CB \X'ps: exec 1 .72 0 .06 setcmykcolor' +.ds CD \X'ps: exec 1 1 1 1 setcmykcolor' +.ds CX \*(CG diff --git a/doc/gawk.1 b/doc/gawk.1 new file mode 100644 index 0000000..16762a8 --- /dev/null +++ b/doc/gawk.1 @@ -0,0 +1,4183 @@ +.ds PX \s-1POSIX\s+1 +.ds UX \s-1UNIX\s+1 +.ds GN \s-1GNU\s+1 +.ds AK \s-1AWK\s+1 +.ds EP \fIGAWK: Effective AWK Programming\fP +.if !\n(.g \{\ +. if !\w|\*(lq| \{\ +. ds lq `` +. if \w'\(lq' .ds lq "\(lq +. \} +. if !\w|\*(rq| \{\ +. ds rq '' +. if \w'\(rq' .ds rq "\(rq +. \} +.\} +.TH GAWK 1 "Feb 15 2018" "Free Software Foundation" "Utility Commands" +.SH NAME +gawk \- pattern scanning and processing language +.SH SYNOPSIS +.B gawk +[ \*(PX or \*(GN style options ] +.B \-f +.I program-file +[ +.B \-\^\- +] file .\|.\|. +.br +.B gawk +[ \*(PX or \*(GN style options ] +[ +.B \-\^\- +] +.I program-text +file .\|.\|. +.SH DESCRIPTION +.I Gawk +is the \*(GN Project's implementation of the \*(AK programming language. +It conforms to the definition of the language in +the \*(PX 1003.1 standard. +This version in turn is based on the description in +.IR "The AWK Programming Language" , +by Aho, Kernighan, and Weinberger. +.I Gawk +provides the additional features found in the current version +of Brian Kernighan's +.I awk +and numerous \*(GN-specific extensions. +.PP +The command line consists of options to +.I gawk +itself, the \*(AK program text (if not supplied via the +.B \-f +or +.B \-i +options), and values to be made +available in the +.B ARGC +and +.B ARGV +pre-defined \*(AK variables. +.PP +When +.I gawk +is invoked with the +.B \-\^\-profile +option, it starts gathering profiling statistics +from the execution of the program. +.I Gawk +runs more slowly in this mode, and automatically produces an execution +profile in the file +.B awkprof.out +when done. +See the +.B \-\^\-profile +option, below. +.PP +.I Gawk +also has an integrated debugger. An interactive debugging session can +be started by supplying the +.B \-\^\-debug +option to the command line. In this mode of execution, +.I gawk +loads the +AWK source code and then prompts for debugging commands. +.I Gawk +can only debug AWK program source provided with the +.B \-f +option. +The debugger is documented in \*(EP. +.SH OPTION FORMAT +.PP +.I Gawk +options may be either traditional \*(PX-style one letter options, +or \*(GN-style long options. \*(PX options start with a single \*(lq\-\*(rq, +while long options start with \*(lq\-\^\-\*(rq. +Long options are provided for both \*(GN-specific features and +for \*(PX-mandated features. +.PP +.IR Gawk -specific +options are typically used in long-option form. +Arguments to long options are either joined with the option +by an +.B = +sign, with no intervening spaces, or they may be provided in the +next command line argument. +Long options may be abbreviated, as long as the abbreviation +remains unique. +.PP +Additionally, every long option has a corresponding short +option, so that the option's functionality may be used from +within +.B #! +executable scripts. +.SH OPTIONS +.PP +.I Gawk +accepts the following options. +Standard options are listed first, followed by options for +.I gawk +extensions, listed alphabetically by short option. +.TP +.PD 0 +.BI \-f " program-file" +.TP +.PD +.BI \-\^\-file " program-file" +Read the \*(AK program source from the file +.IR program-file , +instead of from the first command line argument. +Multiple +.B \-f +(or +.BR \-\^\-file ) +options may be used. +.TP +.PD 0 +.BI \-F " fs" +.TP +.PD +.BI \-\^\-field-separator " fs" +Use +.I fs +for the input field separator (the value of the +.B FS +predefined +variable). +.TP +.PD 0 +\fB\-v\fI var\fB\^=\^\fIval\fR +.TP +.PD +\fB\-\^\-assign \fIvar\fB\^=\^\fIval\fR +Assign the value +.I val +to the variable +.IR var , +before execution of the program begins. +Such variable values are available to the +.B BEGIN +rule of an \*(AK program. +.TP +.PD 0 +.B \-b +.TP +.PD +.B \-\^\-characters\-as\-bytes +Treat all input data as single-byte characters. In other words, +don't pay any attention to the locale information when attempting to +process strings as multibyte characters. +The +.B "\-\^\-posix" +option overrides this one. +.bp +.TP +.PD 0 +.B \-c +.TP +.PD +.B \-\^\-traditional +Run in +.I compatibility +mode. In compatibility mode, +.I gawk +behaves identically to Brian Kernighan's +.IR awk ; +none of the \*(GN-specific extensions are recognized. +.\" The use of +.\" .B \-\^\-traditional +.\" is preferred over the other forms of this option. +See +.BR "GNU EXTENSIONS" , +below, for more information. +.TP +.PD 0 +.B \-C +.TP +.PD +.B \-\^\-copyright +Print the short version of the \*(GN copyright information message on +the standard output and exit successfully. +.TP +.PD 0 +\fB\-d\fR[\fIfile\fR] +.TP +.PD +\fB\-\^\-dump-variables\fR[\fB=\fIfile\fR] +Print a sorted list of global variables, their types and final values to +.IR file . +If no +.I file +is provided, +.I gawk +uses a file named +.B awkvars.out +in the current directory. +.sp .5 +Having a list of all the global variables is a good way to look for +typographical errors in your programs. +You would also use this option if you have a large program with a lot of +functions, and you want to be sure that your functions don't +inadvertently use global variables that you meant to be local. +(This is a particularly easy mistake to make with simple variable +names like +.BR i , +.BR j , +and so on.) +.TP +.PD 0 +\fB\-D\fR[\fIfile\fR] +.TP +.PD +\fB\-\^\-debug\fR[\fB=\fIfile\fR] +Enable debugging of \*(AK programs. +By default, the debugger reads commands interactively from the keyboard +(standard input). +The optional +.IR file +argument specifies a file with a list +of commands for the debugger to execute non-interactively. +.TP +.PD 0 +.BI "\-e " program-text +.TP +.PD +.BI \-\^\-source " program-text" +Use +.I program-text +as \*(AK program source code. +This option allows the easy intermixing of library functions (used via the +.B \-f +and +.B \-i +options) with source code entered on the command line. +It is intended primarily for medium to large \*(AK programs used +in shell scripts. +.TP +.PD 0 +.BI "\-E " file +.TP +.PD +.BI \-\^\-exec " file" +Similar to +.BR \-f , +however, this is option is the last one processed. +This should be used with +.B #! +scripts, particularly for CGI applications, to avoid +passing in options or source code (!) on the command line +from a URL. +This option disables command-line variable assignments. +.TP +.PD 0 +.B \-g +.TP +.PD +.B \-\^\-gen\-pot +Scan and parse the \*(AK program, and generate a \*(GN +.B \&.pot +(Portable Object Template) +format file on standard output with entries for all localizable +strings in the program. The program itself is not executed. +See the \*(GN +.I gettext +distribution for more information on +.B \&.pot +files. +.TP +.PD 0 +.B \-h +.TP +.PD +.B \-\^\-help +Print a relatively short summary of the available options on +the standard output. +(Per the +.IR "GNU Coding Standards" , +these options cause an immediate, successful exit.) +.TP +.PD 0 +.BI "\-i " include-file +.TP +.PD +.BI \-\^\-include " include-file" +Load an awk source library. +This searches for the library using the +.B AWKPATH +environment variable. If the initial search fails, another attempt will +be made after appending the +.B \&.awk +suffix. The file will be loaded only +once (i.e., duplicates are eliminated), and the code does not constitute +the main program source. +.TP +.PD 0 +.BI "\-l " lib +.TP +.PD +.BI \-\^\-load " lib" +Load a +.I gawk +extension from the shared library +.IR lib . +This searches for the library using the +.B AWKLIBPATH +environment variable. If the initial search fails, another attempt will +be made after appending the default shared library suffix for the platform. +The library initialization routine is expected to be named +.BR dl_load() . +.TP +.PD 0 +.BR "\-L " [ \fIvalue\fR ] +.TP +.PD +.BR \-\^\-lint [ =\fIvalue\fR ] +Provide warnings about constructs that are +dubious or non-portable to other \*(AK implementations. +With an optional argument of +.BR fatal , +lint warnings become fatal errors. +This may be drastic, but its use will certainly encourage the +development of cleaner \*(AK programs. +With an optional argument of +.BR invalid , +only warnings about things that are +actually invalid are issued. (This is not fully implemented yet.) +.TP +.PD 0 +.B \-M +.TP +.PD +.B \-\^\-bignum +Force arbitrary precision arithmetic on numbers. This option has +no effect if +.I gawk +is not compiled to use the GNU MPFR and MP libraries. +(In such a case, +.I gawk +issues a warning.) +.TP +.PD 0 +.B \-n +.TP +.PD +.B "\-\^\-non\-decimal\-data" +Recognize octal and hexadecimal values in input data. +.I "Use this option with great caution!" +.TP +.PD 0 +.B \-N +.TP +.PD +.B \-\^\-use\-lc\-numeric +Force +.I gawk +to use the locale's decimal point character when parsing input data. +Although the POSIX standard requires this behavior, and +.I gawk +does so when +.B \-\^\-posix +is in effect, the default is to follow traditional behavior and use a +period as the decimal point, even in locales where the period is not the +decimal point character. This option overrides the default behavior, +without the full draconian strictness of the +.B \-\^\-posix +option. +.ig +.\" This option is left undocumented, on purpose. +.TP +.PD 0 +.B "\-W nostalgia" +.TP +.PD +.B \-\^\-nostalgia +Provide a moment of nostalgia for long time +.I awk +users. +.. +.TP +.PD 0 +\fB\-o\fR[\fIfile\fR] +.TP +.PD +\fB\-\^\-pretty-print\fR[\fB=\fIfile\fR] +Output a pretty printed version of the program to +.IR file . +If no +.I file +is provided, +.I gawk +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 +.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. +This option is on by default. +.TP +.PD 0 +\fB\-p\fR[\fIprof-file\fR] +.TP +.PD +\fB\-\^\-profile\fR[\fB=\fIprof-file\fR] +Start a profiling session, and send the profiling data to +.IR prof-file . +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 +.TP +.PD +.B \-\^\-posix +This turns on +.I compatibility +mode, with the following additional restrictions: +.RS +.TP "\w'\(bu'u+1n" +\(bu +.B \ex +escape sequences are not recognized. +.TP +\(bu +You cannot continue lines after +.B ? +and +.BR : . +.TP +\(bu +The synonym +.B func +for the keyword +.B function +is not recognized. +.TP +\(bu +The operators +.B ** +and +.B **= +cannot be used in place of +.B ^ +and +.BR ^= . +.RE +.TP +.PD 0 +.B \-r +.TP +.PD +.B \-\^\-re\-interval +Enable the use of +.I "interval expressions" +in regular expression matching +(see +.BR "Regular Expressions" , +below). +Interval expressions were not traditionally available in the +\*(AK language. The \*(PX standard added them, to make +.I awk +and +.I egrep +consistent with each other. +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 +.BI \-\^\-sandbox +Run +.I gawk +in sandbox mode, disabling the +.B system() +function, input redirection with +.BR getline , +output redirection with +.BR print " and " printf , +and loading dynamic extensions. +Command execution (through pipelines) is also disabled. +This effectively blocks a script from accessing local resources, +except for the files specified on the command line. +.TP +.PD 0 +.B \-t +.TP +.PD +.B \-\^\-lint\-old +Provide warnings about constructs that are +not portable to the original version of \*(UX +.IR awk . +.TP +.PD 0 +.B \-V +.TP +.PD +.B \-\^\-version +Print version information for this particular copy of +.I gawk +on the standard output. +This is useful mainly for knowing if the current copy of +.I gawk +on your system +is up to date with respect to whatever the Free Software Foundation +is distributing. +This is also useful when reporting bugs. +(Per the +.IR "GNU Coding Standards" , +these options cause an immediate, successful exit.) +.TP +.B \-\^\- +Signal the end of options. This is useful to allow further arguments to the +\*(AK program itself to start with a \*(lq\-\*(rq. +This provides consistency with the argument parsing convention used +by most other \*(PX programs. +.PP +In compatibility mode, +any other options are flagged as invalid, but are otherwise ignored. +In normal operation, as long as program text has been supplied, unknown +options are passed on to the \*(AK program in the +.B ARGV +array for processing. This is particularly useful for running \*(AK +programs via the +.B #! +executable interpreter mechanism. +.PP +For \*(PX compatibility, the +.B \-W +option may be used, followed by the name of a long option. +.SH AWK PROGRAM EXECUTION +.PP +An \*(AK program consists of a sequence of +optional directives, +pattern-action statements, +and optional function definitions. +.RS +.PP +\fB@include "\fIfilename\fB" +.br +\fB@load "\fIfilename\fB" +.br +\fIpattern\fB { \fIaction statements\fB }\fR +.br +\fBfunction \fIname\fB(\fIparameter list\fB) { \fIstatements\fB }\fR +.RE +.PP +.I Gawk +first reads the program source from the +.IR program-file (s) +if specified, +from arguments to +.BR \-\^\-source , +or from the first non-option argument on the command line. +The +.B \-f +and +.B \-\^\-source +options may be used multiple times on the command line. +.I Gawk +reads the program text as if all the +.IR program-file s +and command line source texts +had been concatenated together. This is useful for building libraries +of \*(AK functions, without having to include them in each new \*(AK +program that uses them. It also provides the ability to mix library +functions with command line programs. +.PP +In addition, lines beginning with +.B @include +may be used to include other source files into your program, +making library use even easier. This is equivalent +to using the +.B \-i +option. +.PP +Lines beginning with +.B @load +may be used to load extension functions into your program. This is equivalent +to using the +.B \-l +option. +.PP +The environment variable +.B AWKPATH +specifies a search path to use when finding source files named with +the +.B \-f +and +.B \-i +options. If this variable does not exist, the default path is +\fB".:/usr/local/share/awk"\fR. +(The actual directory may vary, depending upon how +.I gawk +was built and installed.) +If a file name given to the +.B \-f +option contains a \*(lq/\*(rq character, no path search is performed. +.PP +The environment variable +.B AWKLIBPATH +specifies a search path to use when finding source files named with +the +.B \-l +option. If this variable does not exist, the default path is +\fB"/usr/local/lib/gawk"\fR. +(The actual directory may vary, depending upon how +.I gawk +was built and installed.) +.PP +.I Gawk +executes \*(AK programs in the following order. +First, +all variable assignments specified via the +.B \-v +option are performed. +Next, +.I gawk +compiles the program into an internal form. +Then, +.I gawk +executes the code in the +.B BEGIN +rule(s) (if any), +and then proceeds to read +each file named in the +.B ARGV +array (up to +.BR ARGV[ARGC\-1] ). +If there are no files named on the command line, +.I gawk +reads the standard input. +.PP +If a filename on the command line has the form +.IB var = val +it is treated as a variable assignment. The variable +.I var +will be assigned the value +.IR val . +(This happens after any +.B BEGIN +rule(s) have been run.) +Command line variable assignment +is most useful for dynamically assigning values to the variables +\*(AK uses to control how input is broken into fields and records. +It is also useful for controlling state if multiple passes are needed over +a single data file. +.PP +If the value of a particular element of +.B ARGV +is empty (\fB""\fR), +.I gawk +skips over it. +.PP +For each input file, +if a +.B BEGINFILE +rule exists, +.I gawk +executes the associated code +before processing the contents of the file. Similarly, +.I gawk +executes +the code associated with +.B ENDFILE +after processing the file. +.PP +For each record in the input, +.I gawk +tests to see if it matches any +.I pattern +in the \*(AK program. +For each pattern that the record matches, +.I gawk +executes the associated +.IR action . +The patterns are tested in the order they occur in the program. +.PP +Finally, after all the input is exhausted, +.I gawk +executes the code in the +.B END +rule(s) (if any). +.SS Command Line Directories +.PP +According to POSIX, files named on the +.I awk +command line must be +text files. The behavior is ``undefined'' if they are not. Most versions +of +.I awk +treat a directory on the command line as a fatal error. +.PP +Starting with version 4.0 of +.IR gawk , +a directory on the command line +produces a warning, but is otherwise skipped. If either of the +.B \-\^\-posix +or +.B \-\^\-traditional +options is given, then +.I gawk +reverts to +treating directories on the command line as a fatal error. +.SH VARIABLES, RECORDS AND FIELDS +\*(AK variables are dynamic; they come into existence when they are +first used. Their values are either floating-point numbers or strings, +or both, +depending upon how they are used. +Additionally, +.I gawk +allows variables to have regular-expression type. +\*(AK also has one dimensional +arrays; arrays with multiple dimensions may be simulated. +.I Gawk +provides true arrays of arrays; see +.BR Arrays , +below. +Several pre-defined variables are set as a program +runs; these are described as needed and summarized below. +.SS Records +Normally, records are separated by newline characters. You can control how +records are separated by assigning values to the built-in variable +.BR RS . +If +.B RS +is any single character, that character separates records. +Otherwise, +.B RS +is a regular expression. Text in the input that matches this +regular expression separates the record. +However, in compatibility mode, +only the first character of its string +value is used for separating records. +If +.B RS +is set to the null string, then records are separated by +empty lines. +When +.B RS +is set to the null string, the newline character always acts as +a field separator, in addition to whatever value +.B FS +may have. +.SS Fields +.PP +As each input record is read, +.I gawk +splits the record into +.IR fields , +using the value of the +.B FS +variable as the field separator. +If +.B FS +is a single character, fields are separated by that character. +If +.B FS +is the null string, then each individual character becomes a +separate field. +Otherwise, +.B FS +is expected to be a full regular expression. +In the special case that +.B FS +is a single space, fields are separated +by runs of spaces and/or tabs and/or newlines. +.BR NOTE : +The value of +.B IGNORECASE +(see below) also affects how fields are split when +.B FS +is a regular expression, and how records are separated when +.B RS +is a regular expression. +.PP +If the +.B FIELDWIDTHS +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. +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 +.B FS +or +.B FPAT +overrides the use of +.BR FIELDWIDTHS . +.PP +Similarly, if the +.B FPAT +variable is set to a string representing a regular expression, +each field is made up of text that matches that regular expression. In +this case, the regular expression describes the fields themselves, +instead of the text that separates the fields. +Assigning a new value to +.B FS +or +.B FIELDWIDTHS +overrides the use of +.BR FPAT . +.PP +Each field in the input record may be referenced by its position: +.BR $1 , +.BR $2 , +and so on. +.B $0 +is the whole record. +Fields need not be referenced by constants: +.RS +.PP +.ft B +n = 5 +.br +print $n +.ft R +.RE +.PP +prints the fifth field in the input record. +.PP +The variable +.B NF +is set to the total number of fields in the input record. +.PP +References to non-existent fields (i.e., fields after +.BR $NF ) +produce the null-string. However, assigning to a non-existent field +(e.g., +.BR "$(NF+2) = 5" ) +increases the value of +.BR NF , +creates any intervening fields with the null string as their values, and +causes the value of +.B $0 +to be recomputed, with the fields being separated by the value of +.BR OFS . +References to negative numbered fields cause a fatal error. +Decrementing +.B NF +causes the values of fields past the new value to be lost, and the value of +.B $0 +to be recomputed, with the fields being separated by the value of +.BR OFS . +.PP +Assigning a value to an existing field +causes the whole record to be rebuilt when +.B $0 +is referenced. +Similarly, assigning a value to +.B $0 +causes the record to be resplit, creating new +values for the fields. +.SS Built-in Variables +.PP +.IR Gawk\^ "'s" +built-in variables are: +.PP +.TP "\w'\fBFIELDWIDTHS\fR'u+1n" +.B ARGC +The number of command line arguments (does not include options to +.IR gawk , +or the program source). +.TP +.B ARGIND +The index in +.B ARGV +of the current file being processed. +.TP +.B ARGV +Array of command line arguments. The array is indexed from +0 to +.B ARGC +\- 1. +Dynamically changing the contents of +.B ARGV +can control the files used for data. +.TP +.B BINMODE +On non-POSIX systems, specifies use of \*(lqbinary\*(rq mode for all file I/O. +Numeric values of 1, 2, or 3, specify that input files, output files, or +all files, respectively, should use binary I/O. +String values of \fB"r"\fR, or \fB"w"\fR specify that input files, or output files, +respectively, should use binary I/O. +String values of \fB"rw"\fR or \fB"wr"\fR specify that all files +should use binary I/O. +Any other string value is treated as \fB"rw"\fR, but generates a warning message. +.TP +.B CONVFMT +The conversion format for numbers, \fB"%.6g"\fR, by default. +.TP +.B ENVIRON +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). +.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 +.BR getline , +during a read for +.BR getline , +or during a +.BR close() , +then +.B ERRNO +is set to +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, +.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. +.TP +.B FILENAME +The name of the current input file. +If no files are specified on the command line, the value of +.B FILENAME +is \*(lq\-\*(rq. +However, +.B FILENAME +is undefined inside the +.B BEGIN +rule +(unless set by +.BR getline ). +.TP +.B FNR +The input record number in the current input file. +.TP +.B FPAT +A regular expression describing the contents of the +fields in a record. +When set, +.I gawk +parses the input into fields, where the fields match the +regular expression, instead of using the +value of the +.B FS +variable as the field separator. +See +.BR Fields , +above. +.TP +.B FS +The input field separator, a space by default. See +.BR Fields , +above. +.TP +.B FUNCTAB +An array whose indices and corresponding values +are the names of all the user-defined +or extension functions in the program. +.BR NOTE : +You may not use the +.B delete +statement with the +.B FUNCTAB +array. +.TP +.B IGNORECASE +Controls the case-sensitivity of all regular expression +and string operations. If +.B IGNORECASE +has a non-zero value, then string comparisons and +pattern matching in rules, +field splitting with +.B FS +and +.BR FPAT , +record separating with +.BR RS , +regular expression +matching with +.B ~ +and +.BR !~ , +and the +.BR gensub() , +.BR gsub() , +.BR index() , +.BR match() , +.BR patsplit() , +.BR split() , +and +.B sub() +built-in functions all ignore case when doing regular expression +operations. +.BR NOTE : +Array subscripting is +.I not +affected. +However, the +.B asort() +and +.B asorti() +functions are affected. +.sp .5 +Thus, if +.B IGNORECASE +is not equal to zero, +.B /aB/ +matches all of the strings \fB"ab"\fP, \fB"aB"\fP, \fB"Ab"\fP, +and \fB"AB"\fP. +As with all \*(AK variables, the initial value of +.B IGNORECASE +is zero, so all regular expression and string +operations are normally case-sensitive. +.TP +.B LINT +Provides dynamic control of the +.B \-\^\-lint +option from within an \*(AK program. +When true, +.I gawk +prints lint warnings. When false, it does not. +When assigned the string value \fB"fatal"\fP, +lint warnings become fatal errors, exactly like +.BR \-\^\-lint=fatal . +Any other true value just prints warnings. +.TP +.B NF +The number of fields in the current input record. +.TP +.B NR +The total number of input records seen so far. +.TP +.B OFMT +The output format for numbers, \fB"%.6g"\fR, by default. +.TP +.B OFS +The output field separator, a space by default. +.TP +.B ORS +The output record separator, by default a newline. +.TP +.B PREC +The working precision of arbitrary precision floating-point +numbers, 53 by default. +.TP +.B PROCINFO +The elements of this array provide access to information about the +running \*(AK program. +On some systems, +there may be elements in the array, \fB"group1"\fP through +\fB"group\fIn\fB"\fR for some +.IR n , +which is the number of supplementary groups that the process has. +Use the +.B in +operator to test for these elements. +The following elements are guaranteed to be available: +.RS +.TP \w'\fBPROCINFO["strftime"]\fR'u+1n +\fBPROCINFO["argv"]\fP +The command line arguments as received by +.I gawk +at the C-language level. +The subscripts start from zero. +.TP +\fBPROCINFO["egid"]\fP +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) +system call. +.TP +\fBPROCINFO["FS"]\fP +\fB"FS"\fP if field splitting with +.B FS +is in effect, +\fB"FPAT"\fP if field splitting with +.B FPAT +is in effect, +\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 +The value of the +.IR getgid (2) +system call. +.TP +\fBPROCINFO["identifiers"]\fP +A subarray, indexed by the names of all identifiers used in the +text of the AWK program. +The values indicate what +.I gawk +knows about the identifiers after it has finished parsing the program; they are +.I not +updated while the program runs. +For each identifier, the value of the element is one of the following: +.RS +.TP \w'\fB"extension"\fR'u+1n +\fB"array"\fR +The identifier is an array. +.TP +\fB"builtin"\fR +The identifier is a built-in function. +.TP +\fB"extension"\fR +The identifier is an extension function loaded via +.B @load +or +.BR \-l . +.TP +\fB"scalar"\fR +The identifier is a scalar. +.TP +\fB"untyped"\fR +The identifier is untyped (could be used as a scalar or array, +.I gawk +doesn't know yet). +.TP +\fB"user"\fR +The identifier is a user-defined function. +.RE +.TP +\fBPROCINFO["pgrpid"]\fP +The process group ID of the current process. +.TP +\fBPROCINFO["pid"]\fP +The process ID of the current process. +.TP +\fBPROCINFO["ppid"]\fP +The parent process ID of the current process. +.TP +\fBPROCINFO["strftime"]\fP +The default time format string for +.BR strftime() . +.TP +\fBPROCINFO["uid"]\fP +The value of the +.IR getuid (2) +system call. +.TP +\fBPROCINFO["version"]\fP +the version of +.IR gawk . +.PP +The following elements are present if loading dynamic +extensions is available: +.TP +\fBPROCINFO["api_major"]\fP +The major version of the extension API. +.TP +\fBPROCINFO["api_minor"]\fP +The minor version of the extension API. +.PP +The following elements are available if MPFR support is +compiled into +.IR gawk\^ : +.TP +\fBPROCINFO["gmp_version"]\fP +The version of the GNU MP library used for arbitrary precision +number support in +.IR gawk . +.TP +\fBPROCINFO["mpfr_version"]\fP +The version of the GNU MPFR library used for arbitrary precision +number support in +.IR gawk . +.TP +\fBPROCINFO["prec_max"]\fP +The maximum precision supported by the GNU MPFR library for +arbitrary precision floating-point numbers. +.TP +\fBPROCINFO["prec_min"]\fP +The minimum precision allowed by the GNU MPFR library for +arbitrary precision floating-point numbers. +.PP +The following elements may set by a program to +change +.IR gawk 's +behavior: +.TP +\fBPROCINFO["NONFATAL"]\fR +If this exists, then I/O errors for all redirections become nonfatal. +.TP +\fBPROCINFO["\fname\fB", "NONFATAL"]\fR +Make I/O errors for +.I name +be nonfatal. +.TP +\fBPROCINFO["\fIcommand\fB", "pty"]\fR +Use a pseudo-tty for two-way communication with +.I command +instead of setting up two one-way pipes. +.TP +\fBPROCINFO["\fIinput\fB", "READ_TIMEOUT"]\fR +The timeout in milliseconds for reading data from +.IR input , +where +.I input +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 +returns \-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 , +then its value controls the order in which array elements +are traversed in +.B for +loops. +Supported values are +\fB"@ind_str_asc"\fR, +\fB"@ind_num_asc"\fR, +\fB"@val_type_asc"\fR, +\fB"@val_str_asc"\fR, +\fB"@val_num_asc"\fR, +\fB"@ind_str_desc"\fR, +\fB"@ind_num_desc"\fR, +\fB"@val_type_desc"\fR, +\fB"@val_str_desc"\fR, +\fB"@val_num_desc"\fR, +and +\fB"@unsorted"\fR. +The value can also be the name (as a +.IR string ) +of any comparison function defined +as follows: +.sp +.in +5m +\fBfunction cmp_func(i1, v1, i2, v2)\fR +.in -5m +.sp +where +.I i1 +and +.I i2 +are the indices, and +.I v1 +and +.I v2 +are the +corresponding values of the two elements being compared. +It should return a number less than, equal to, or greater than 0, +depending on how the elements of the array are to be ordered. +.RE +.TP +.B ROUNDMODE +The rounding mode to use for arbitrary precision arithmetic on +numbers, by default \fB"N"\fR (IEEE-754 roundTiesToEven mode). +The accepted values are +\fB"N"\fR or \fB"n"\fR for roundTiesToEven, +\fB"U"\fR or \fB"u"\fR for roundTowardPositive, +\fB"D"\fR or \fB"d"\fR for roundTowardNegative, +\fB"Z"\fR or \fB"z"\fR for roundTowardZero, +and if your version of GNU MPFR library supports it, +\fB"A"\fR or \fB"a"\fR for rounding away from zero. +.TP +.B RS +The input record separator, by default a newline. +.TP +.B RT +The record terminator. +.I Gawk +sets +.B RT +to the input text that matched the character or regular expression +specified by +.BR RS . +.TP +.B RSTART +The index of the first character matched by +.BR match() ; +0 if no match. +(This implies that character indices start at one.) +.TP +.B RLENGTH +The length of the string matched by +.BR match() ; +\-1 if no match. +.TP +.B SUBSEP +The character used to separate multiple subscripts in array +elements, by default \fB"\e034"\fR. +.TP +.B SYMTAB +An array whose indices are the names of all currently defined +global variables and arrays in the program. The array may be used +for indirect access to read or write the value of a variable: +.sp +.ft B +.nf +.in +5m +foo = 5 +SYMTAB["foo"] = 4 +print foo # prints 4 +.fi +.ft R +.in -5m +.sp +The +.B typeof() +function may be used to test if an element in +.B SYMTAB +is an array. +You may not use the +.B delete +statement with the +.B SYMTAB +array. +.TP +.B TEXTDOMAIN +The text domain of the \*(AK program; used to find the localized +translations for the program's strings. +.SS Arrays +.PP +Arrays are subscripted with an expression between square brackets +.RB ( [ " and " ] ). +If the expression is an expression list +.RI ( expr ", " expr " .\|.\|.)" +then the array subscript is a string consisting of the +concatenation of the (string) value of each expression, +separated by the value of the +.B SUBSEP +variable. +This facility is used to simulate multiply dimensioned +arrays. For example: +.PP +.RS +.ft B +i = "A";\^ j = "B";\^ k = "C" +.br +x[i, j, k] = "hello, world\en" +.ft R +.RE +.PP +assigns the string \fB"hello,\ world\en"\fR to the element of the array +.B x +which is indexed by the string \fB"A\e034B\e034C"\fR. All arrays in \*(AK +are associative, i.e., indexed by string values. +.PP +The special operator +.B in +may be used to test if an array has an index consisting of a particular +value: +.PP +.RS +.ft B +.nf +if (val in array) + print array[val] +.fi +.ft +.RE +.PP +If the array has multiple subscripts, use +.BR "(i, j) in array" . +.PP +The +.B in +construct may also be used in a +.B for +loop to iterate over all the elements of an array. +However, the +.B "(i, j) in array" +construct only works in tests, not in +.B for +loops. +.PP +An element may be deleted from an array using the +.B delete +statement. +The +.B delete +statement may also be used to delete the entire contents of an array, +just by specifying the array name without a subscript. +.PP +.I gawk +supports true multidimensional arrays. It does not require that +such arrays be ``rectangular'' as in C or C++. +For example: +.sp +.RS +.ft B +.nf +a[1] = 5 +a[2][1] = 6 +a[2][2] = 7 +.fi +.ft +.RE +.PP +.BR NOTE : +You may need to tell +.I gawk +that an array element is really a subarray in order to use it where +.I gawk +expects an array (such as in the second argument to +.BR split() ). +You can do this by creating an element in the subarray and then +deleting it with the +.B delete +statement. +.SS Variable Typing And Conversion +.PP +Variables and fields +may be (floating point) numbers, or strings, or both. +They may also be regular expressions. How the +value of a variable is interpreted depends upon its context. If used in +a numeric expression, it will be treated as a number; if used as a string +it will be treated as a string. +.PP +To force a variable to be treated as a number, add zero to it; to force it +to be treated as a string, concatenate it with the null string. +.PP +Uninitialized variables have the numeric value zero and the string value "" +(the null, or empty, string). +.PP +When a string must be converted to a number, the conversion is accomplished +using +.IR strtod (3). +A number is converted to a string by using the value of +.B CONVFMT +as a format string for +.IR sprintf (3), +with the numeric value of the variable as the argument. +However, even though all numbers in \*(AK are floating-point, +integral values are +.I always +converted as integers. Thus, given +.PP +.RS +.ft B +.nf +CONVFMT = "%2.2f" +a = 12 +b = a "" +.fi +.ft R +.RE +.PP +the variable +.B b +has a string value of \fB"12"\fR and not \fB"12.00"\fR. +.PP +.BR NOTE : +When operating in POSIX mode (such as with the +.B \-\^\-posix +option), +beware that locale settings may interfere with the way +decimal numbers are treated: the decimal separator of the numbers you +are feeding to +.I gawk +must conform to what your locale would expect, be it +a comma (,) or a period (.). +.PP +.I Gawk +performs comparisons as follows: +If two variables are numeric, they are compared numerically. +If one value is numeric and the other has a string value that is a +\*(lqnumeric string,\*(rq then comparisons are also done numerically. +Otherwise, the numeric value is converted to a string and a string +comparison is performed. +Two strings are compared, of course, as strings. +.PP +Note that string constants, such as \fB"57"\fP, are +.I not +numeric strings, they are string constants. +The idea of \*(lqnumeric string\*(rq +only applies to fields, +.B getline +input, +.BR FILENAME , +.B ARGV +elements, +.B ENVIRON +elements and the elements of an array created by +.B split() +or +.B patsplit() +that are numeric strings. +The basic idea is that +.IR "user input" , +and only user input, that looks numeric, +should be treated that way. +.SS Octal and Hexadecimal Constants +You may use C-style octal and hexadecimal constants in your AWK +program source code. +For example, the octal value +.B 011 +is equal to decimal +.BR 9 , +and the hexadecimal value +.B 0x11 +is equal to decimal 17. +.SS String Constants +.PP +String constants in \*(AK are sequences of characters enclosed +between double quotes (like \fB"value"\fR). Within strings, certain +.I "escape sequences" +are recognized, as in C. These are: +.PP +.TP "\w'\fB\e\^\fIddd\fR'u+1n" +.B \e\e +A literal backslash. +.TP +.B \ea +The \*(lqalert\*(rq character; usually the \s-1ASCII\s+1 \s-1BEL\s+1 character. +.TP +.B \eb +Backspace. +.TP +.B \ef +Form-feed. +.TP +.B \en +Newline. +.TP +.B \er +Carriage return. +.TP +.B \et +Horizontal tab. +.TP +.B \ev +Vertical tab. +.TP +.BI \ex "\^hex digits" +The character represented by the string of hexadecimal digits following +the +.BR \ex . +Up to two +following hexadecimal digits are considered part of +the escape sequence. +E.g., \fB"\ex1B"\fR is the \s-1ASCII\s+1 \s-1ESC\s+1 (escape) character. +.TP +.BI \e ddd +The character represented by the 1-, 2-, or 3-digit sequence of octal +digits. +E.g., \fB"\e033"\fR is the \s-1ASCII\s+1 \s-1ESC\s+1 (escape) character. +.TP +.BI \e c +The literal character +.IR c\^ . +.PP +In compatibility mode, the characters represented by octal and +hexadecimal escape sequences are treated literally when used in +regular expression constants. Thus, +.B /a\e52b/ +is equivalent to +.BR /a\e*b/ . +.SS "Regexp Constants" +A regular expression constant is a sequence of characters enclosed +between forward slashes (like +.BR /value/ ). +Regular expression matching is described more fully below; see +.BR "Regular Expressions" . +.PP +The escape sequences described earlier may also be used inside +constant regular expressions +(e.g., +.B "/[\ \et\ef\en\er\ev]/" +matches whitespace characters). +.TP +.I Gawk +provides +.I "strongly typed" +regular expression constants. These are written with a leading +.B @ +symbol (like so: +.BR @/value/ ). +Such constants may be assigned to scalars (variables, array elements) +and passed to user-defined functions. Variables that have been so +assigned have regular expression type. +.SH PATTERNS AND ACTIONS +\*(AK is a line-oriented language. The pattern comes first, and then the +action. Action statements are enclosed in +.B { +and +.BR } . +Either the pattern may be missing, or the action may be missing, but, +of course, not both. If the pattern is missing, the action +executes for every single record of input. +A missing action is equivalent to +.RS +.PP +.B "{ print }" +.RE +.PP +which prints the entire record. +.PP +Comments begin with the +.B # +character, and continue until the +end of the line. +Empty lines may be used to separate statements. +Normally, a statement ends with a newline, however, this is not the +case for lines ending in +a comma, +.BR { , +.BR ? , +.BR : , +.BR && , +or +.BR || . +Lines ending in +.B do +or +.B else +also have their statements automatically continued on the following line. +In other cases, a line can be continued by ending it with a \*(lq\e\*(rq, +in which case the newline is ignored. +.PP +Multiple statements may +be put on one line by separating them with a \*(lq;\*(rq. +This applies to both the statements within the action part of a +pattern-action pair (the usual case), +and to the pattern-action statements themselves. +.SS Patterns +\*(AK patterns may be one of the following: +.PP +.RS +.nf +.B BEGIN +.B END +.B BEGINFILE +.B ENDFILE +.BI / "regular expression" / +.I "relational expression" +.IB pattern " && " pattern +.IB pattern " || " pattern +.IB pattern " ? " pattern " : " pattern +.BI ( pattern ) +.BI ! " pattern" +.IB pattern1 ", " pattern2 +.fi +.RE +.PP +.B BEGIN +and +.B END +are two special kinds of patterns which are not tested against +the input. +The action parts of all +.B BEGIN +patterns are merged as if all the statements had +been written in a single +.B BEGIN +rule. They are executed before any +of the input is read. Similarly, all the +.B END +rules are merged, +and executed when all the input is exhausted (or when an +.B exit +statement is executed). +.B BEGIN +and +.B END +patterns cannot be combined with other patterns in pattern expressions. +.B BEGIN +and +.B END +patterns cannot have missing action parts. +.PP +.B BEGINFILE +and +.B ENDFILE +are additional special patterns whose bodies are executed +before reading the first record of each command line input file +and after reading the last record of each file. +Inside the +.B BEGINFILE +rule, the value of +.B ERRNO +is the empty string if the file was opened successfully. +Otherwise, there is some problem with the file and the code should +use +.B nextfile +to skip it. If that is not done, +.I gawk +produces its usual fatal error for files that cannot be opened. +.PP +For +.BI / "regular expression" / +patterns, the associated statement is executed for each input record that matches +the regular expression. +Regular expressions are the same as those in +.IR egrep (1), +and are summarized below. +.PP +A +.I "relational expression" +may use any of the operators defined below in the section on actions. +These generally test whether certain fields match certain regular expressions. +.PP +The +.BR && , +.BR || , +and +.B ! +operators are logical AND, logical OR, and logical NOT, respectively, as in C. +They do short-circuit evaluation, also as in C, and are used for combining +more primitive pattern expressions. As in most languages, parentheses +may be used to change the order of evaluation. +.PP +The +.B ?\^: +operator is like the same operator in C. If the first pattern is true +then the pattern used for testing is the second pattern, otherwise it is +the third. Only one of the second and third patterns is evaluated. +.PP +The +.IB pattern1 ", " pattern2 +form of an expression is called a +.IR "range pattern" . +It matches all input records starting with a record that matches +.IR pattern1 , +and continuing until a record that matches +.IR pattern2 , +inclusive. It does not combine with any other sort of pattern expression. +.SS Regular Expressions +Regular expressions are the extended kind found in +.IR egrep . +They are composed of characters as follows: +.TP "\w'\fB[^\fIabc.\|.\|.\fB]\fR'u+2n" +.I c +Matches the non-metacharacter +.IR c . +.TP +.I \ec +Matches the literal character +.IR c . +.TP +.B . +Matches any character +.I including +newline. +.TP +.B ^ +Matches the beginning of a string. +.TP +.B $ +Matches the end of a string. +.TP +.BI [ abc.\|.\|. ] +A character list: matches any of the characters +.IR abc.\|.\|. . +You may include a range of characters by separating them with a dash. +.TP +\fB[^\fIabc.\|.\|.\fB]\fR +A negated character list: matches any character except +.IR abc.\|.\|. . +.TP +.IB r1 | r2 +Alternation: matches either +.I r1 +or +.IR r2 . +.TP +.I r1r2 +Concatenation: matches +.IR r1 , +and then +.IR r2 . +.TP +.IB r\^ + +Matches one or more +.IR r\^ "'s." +.TP +.IB r * +Matches zero or more +.IR r\^ "'s." +.TP +.IB r\^ ? +Matches zero or one +.IR r\^ "'s." +.TP +.BI ( r ) +Grouping: matches +.IR r . +.TP +.PD 0 +.IB r { n } +.TP +.PD 0 +.IB r { n ,} +.TP +.PD +.IB r { n , m } +One or two numbers inside braces denote an +.IR "interval expression" . +If there is one number in the braces, the preceding regular expression +.I r +is repeated +.I n +times. If there are two numbers separated by a comma, +.I r +is repeated +.I n +to +.I m +times. +If there is one number followed by a comma, then +.I r +is repeated at least +.I n +times. +.TP +.B \ey +Matches the empty string at either the beginning or the +end of a word. +.TP +.B \eB +Matches the empty string within a word. +.TP +.B \e< +Matches the empty string at the beginning of a word. +.TP +.B \e> +Matches the empty string at the end of a word. +.TP +.B \es +Matches any whitespace character. +.TP +.B \eS +Matches any nonwhitespace character. +.TP +.B \ew +Matches any word-constituent character (letter, digit, or underscore). +.TP +.B \eW +Matches any character that is not word-constituent. +.TP +.B \e` +Matches the empty string at the beginning of a buffer (string). +.TP +.B \e' +Matches the empty string at the end of a buffer. +.PP +The escape sequences that are valid in string constants (see +.BR "String Constants" ) +are also valid in regular expressions. +.PP +.I "Character classes" +are a feature introduced in the \*(PX standard. +A character class is a special notation for describing +lists of characters that have a specific attribute, but where the +actual characters themselves can vary from country to country and/or +from character set to character set. For example, the notion of what +is an alphabetic character differs in the USA and in France. +.PP +A character class is only valid in a regular expression +.I inside +the brackets of a character list. Character classes consist of +.BR [: , +a keyword denoting the class, and +.BR :] . +The character +classes defined by the \*(PX standard are: +.TP "\w'\fB[:alnum:]\fR'u+2n" +.B [:alnum:] +Alphanumeric characters. +.TP +.B [:alpha:] +Alphabetic characters. +.TP +.B [:blank:] +Space or tab characters. +.TP +.B [:cntrl:] +Control characters. +.TP +.B [:digit:] +Numeric characters. +.TP +.B [:graph:] +Characters that are both printable and visible. +(A space is printable, but not visible, while an +.B a +is both.) +.TP +.B [:lower:] +Lowercase alphabetic characters. +.TP +.B [:print:] +Printable characters (characters that are not control characters.) +.TP +.B [:punct:] +Punctuation characters (characters that are not letter, digits, +control characters, or space characters). +.TP +.B [:space:] +Space characters (such as space, tab, and formfeed, to name a few). +.TP +.B [:upper:] +Uppercase alphabetic characters. +.TP +.B [:xdigit:] +Characters that are hexadecimal digits. +.PP +For example, before the \*(PX standard, to match alphanumeric +characters, you would have had to write +.BR /[A\-Za\-z0\-9]/ . +If your character set had other alphabetic characters in it, this would not +match them, and if your character set collated differently from +\s-1ASCII\s+1, this might not even match the +\s-1ASCII\s+1 alphanumeric characters. +With the \*(PX character classes, you can write +.BR /[[:alnum:]]/ , +and this matches +the alphabetic and numeric characters in your character set, +no matter what it is. +.PP +Two additional special sequences can appear in character lists. +These apply to non-\s-1ASCII\s+1 character sets, which can have single symbols +(called +.IR "collating elements" ) +that are represented with more than one +character, as well as several characters that are equivalent for +.IR collating , +or sorting, purposes. (E.g., in French, a plain \*(lqe\*(rq +and a grave-accented \*(lqe\h'-\w:e:u'\`\*(rq are equivalent.) +.TP +Collating Symbols +A collating symbol is a multi-character collating element enclosed in +.B [. +and +.BR .] . +For example, if +.B ch +is a collating element, then +.B [[.ch.]] +is a regular expression that matches this collating element, while +.B [ch] +is a regular expression that matches either +.B c +or +.BR h . +.TP +Equivalence Classes +An equivalence class is a locale-specific name for a list of +characters that are equivalent. The name is enclosed in +.B [= +and +.BR =] . +For example, the name +.B e +might be used to represent all of +\*(lqe\*(rq, \*(lqe\h'-\w:e:u'\'\*(rq, and \*(lqe\h'-\w:e:u'\`\*(rq. +In this case, +.B [[=e=]] +is a regular expression +that matches any of +.BR e , +.BR "e\h'-\w:e:u'\'" , +or +.BR "e\h'-\w:e:u'\`" . +.PP +These features are very valuable in non-English speaking locales. +The library functions that +.I gawk +uses for regular expression matching +currently only recognize \*(PX character classes; they do not recognize +collating symbols or equivalence classes. +.PP +The +.BR \ey , +.BR \eB , +.BR \e< , +.BR \e> , +.BR \es , +.BR \eS , +.BR \ew , +.BR \eW , +.BR \e` , +and +.B \e' +operators are specific to +.IR gawk ; +they are extensions based on facilities in the \*(GN regular expression libraries. +.PP +The various command line options +control how +.I gawk +interprets characters in regular expressions. +.TP +No options +In the default case, +.I gawk +provides all the facilities of +\*(PX regular expressions and the \*(GN regular expression operators described above. +.TP +.B \-\^\-posix +Only \*(PX regular expressions are supported, the \*(GN operators are not special. +(E.g., +.B \ew +matches a literal +.BR w ). +.TP +.B \-\^\-traditional +Traditional \*(UX +.I awk +regular expressions are matched. The \*(GN operators +are not special, and interval expressions are not available. +Characters described by octal and hexadecimal escape sequences are +treated literally, even if they represent regular expression metacharacters. +.TP +.B \-\^\-re\-interval +Allow interval expressions in regular expressions, even if +.B \-\^\-traditional +has been provided. +.SS Actions +Action statements are enclosed in braces, +.B { +and +.BR } . +Action statements consist of the usual assignment, conditional, and looping +statements found in most languages. The operators, control statements, +and input/output statements +available are patterned after those in C. +.SS Operators +.PP +The operators in \*(AK, in order of decreasing precedence, are: +.PP +.TP "\w'\fB*= /= %= ^=\fR'u+1n" +.BR ( \&.\|.\|. ) +Grouping +.TP +.B $ +Field reference. +.TP +.B "++ \-\^\-" +Increment and decrement, both prefix and postfix. +.TP +.B ^ +Exponentiation (\fB**\fR may also be used, and \fB**=\fR for +the assignment operator). +.TP +.B "+ \- !" +Unary plus, unary minus, and logical negation. +.TP +.B "* / %" +Multiplication, division, and modulus. +.TP +.B "+ \-" +Addition and subtraction. +.TP +.I space +String concatenation. +.TP +.B "| |&" +Piped I/O for +.BR getline , +.BR print , +and +.BR printf . +.TP +.B "< > <= >= == !=" +The regular relational operators. +.TP +.B "~ !~" +Regular expression match, negated match. +.BR NOTE : +Do not use a constant regular expression +.RB ( /foo/ ) +on the left-hand side of a +.B ~ +or +.BR !~ . +Only use one on the right-hand side. The expression +.BI "/foo/ ~ " exp +has the same meaning as \fB(($0 ~ /foo/) ~ \fIexp\fB)\fR. +This is usually +.I not +what you want. +.TP +.B in +Array membership. +.TP +.B && +Logical AND. +.TP +.B || +Logical OR. +.TP +.B ?: +The C conditional expression. This has the form +.IB expr1 " ? " expr2 " : " expr3\c +\&. +If +.I expr1 +is true, the value of the expression is +.IR expr2 , +otherwise it is +.IR expr3 . +Only one of +.I expr2 +and +.I expr3 +is evaluated. +.TP +.B "= += \-= *= /= %= ^=" +Assignment. Both absolute assignment +.BI ( var " = " value ) +and operator-assignment (the other forms) are supported. +.SS Control Statements +.PP +The control statements are +as follows: +.PP +.RS +.nf +\fBif (\fIcondition\fB) \fIstatement\fR [ \fBelse\fI statement \fR] +\fBwhile (\fIcondition\fB) \fIstatement \fR +\fBdo \fIstatement \fBwhile (\fIcondition\fB)\fR +\fBfor (\fIexpr1\fB; \fIexpr2\fB; \fIexpr3\fB) \fIstatement\fR +\fBfor (\fIvar \fBin\fI array\fB) \fIstatement\fR +\fBbreak\fR +\fBcontinue\fR +\fBdelete \fIarray\^\fB[\^\fIindex\^\fB]\fR +\fBdelete \fIarray\^\fR +\fBexit\fR [ \fIexpression\fR ] +\fB{ \fIstatements \fB}\fR +\fBswitch (\fIexpression\fB) { +\fBcase \fIvalue\fB|\fIregex\fB : \fIstatement +\&.\^.\^. +\fR[ \fBdefault: \fIstatement \fR] +\fB}\fR +.fi +.RE +.SS "I/O Statements" +.PP +The input/output statements are as follows: +.PP +.TP "\w'\fBprintf \fIfmt, expr-list\fR'u+1n" +\fBclose(\fIfile \fR[\fB, \fIhow\fR]\fB)\fR +Close file, pipe or coprocess. +The optional +.I how +should only be used when closing one end of a +two-way pipe to a coprocess. +It must be a string value, either +\fB"to"\fR or \fB"from"\fR. +.TP +.B getline +Set +.B $0 +from next input record; set +.BR NF , +.BR NR , +.BR FNR , +.BR RT . +.TP +.BI "getline <" file +Set +.B $0 +from next record of +.IR file ; +set +.BR NF , +.BR RT . +.TP +.BI getline " var" +Set +.I var +from next input record; set +.BR NR , +.BR FNR , +.BR RT . +.TP +.BI getline " var" " <" file +Set +.I var +from next record of +.IR file , +.BR RT . +.TP +\fIcommand\fB | getline \fR[\fIvar\fR] +Run +.I command +piping the output either into +.B $0 +or +.IR var , +as above, and +.BR RT . +.TP +\fIcommand\fB |& getline \fR[\fIvar\fR] +Run +.I command +as a coprocess +piping the output either into +.B $0 +or +.IR var , +as above, and +.BR RT . +Coprocesses are a +.I gawk +extension. +.RI ( command +can also be a socket. See the subsection +.BR "Special File Names" , +below.) +.TP +.B next +Stop processing the current input record. The next input record +is read and processing starts over with the first pattern in the +\*(AK program. +Upon reaching the end of the input data, +.I gawk +executes any +.B END +rule(s). +.TP +.B "nextfile" +Stop processing the current input file. The next input record read +comes from the next input file. +.B FILENAME +and +.B ARGIND +are updated, +.B FNR +is reset to 1, and processing starts over with the first pattern in the +\*(AK program. +Upon reaching the end of the input data, +.I gawk +executes any +.B ENDFILE +and +.B END +rule(s). +.TP +.B print +Print the current record. +The output record is terminated with the value of +.BR ORS . +.TP +.BI print " expr-list" +Print expressions. +Each expression is separated by the value of +.BR OFS . +The output record is terminated with the value of +.BR ORS . +.TP +.BI print " expr-list" " >" file +Print expressions on +.IR file . +Each expression is separated by the value of +.BR OFS . +The output record is terminated with the value of +.BR ORS . +.TP +.BI printf " fmt, expr-list" +Format and print. +See \fBThe \fIprintf \fBStatement\fR, below. +.TP +.BI printf " fmt, expr-list" " >" file +Format and print on +.IR file . +.TP +.BI system( cmd-line ) +Execute the command +.IR cmd-line , +and return the exit status. +(This may not be available on non-\*(PX systems.) +See \*(EP for the full details on the exit status. +.TP +\&\fBfflush(\fR[\fIfile\^\fR]\fB)\fR +Flush any buffers associated with the open output file or pipe +.IR file . +If +.I file +is missing or if it +is the null string, +then flush all open output files and pipes. +.PP +Additional output redirections are allowed for +.B print +and +.BR printf . +.TP +.BI "print .\|.\|. >>" " file" +Appends output to the +.IR file . +.TP +.BI "print .\|.\|. |" " command" +Writes on a pipe. +.TP +.BI "print .\|.\|. |&" " command" +Sends data to a coprocess or socket. +(See also the subsection +.BR "Special File Names" , +below.) +.PP +The +.B getline +command returns 1 on success, zero 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 is 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. +.PP +.BR NOTE : +Failure in opening a two-way socket results in a non-fatal error being +returned to the calling function. If using a pipe, coprocess, or socket to +.BR getline , +or from +.B print +or +.B printf +within a loop, you +.I must +use +.B close() +to create new instances of the command or socket. +\*(AK does not automatically close pipes, sockets, or coprocesses when +they return EOF. +.SS The \fIprintf\fP\^ Statement +.PP +The \*(AK versions of the +.B printf +statement and +.B sprintf() +function +(see below) +accept the following conversion specification formats: +.TP "\w'\fB%g\fR, \fB%G\fR'u+2n" +.B %c +A single character. +If the argument used for +.B %c +is numeric, it is treated as a character and printed. +Otherwise, the argument is assumed to be a string, and the only first +character of that string is printed. +.TP +.BR "%d" "," " %i" +A decimal number (the integer part). +.TP +.BR %e , " %E" +A floating point number of the form +[\fB\-\fP]\fId\fB.\fIdddddd\^\fBe\fR[\fB+\-\fR]\fIdd\fR. +The +.B %E +format uses +.B E +instead of +.BR e . +.TP +.BR %f , " %F" +A floating point number of the form +[\fB\-\fP]\fIddd\fB.\fIdddddd\fR. +If the system library supports it, +.B %F +is available as well. This is like +.BR %f , +but uses capital letters for special \*(lqnot a number\*(rq +and \*(lqinfinity\*(rq values. If +.B %F +is not available, +.I gawk +uses +.BR %f . +.TP +.BR %g , " %G" +Use +.B %e +or +.B %f +conversion, whichever is shorter, with nonsignificant zeros suppressed. +The +.B %G +format uses +.B %E +instead of +.BR %e . +.TP +.B %o +An unsigned octal number (also an integer). +.TP +.PD +.B %u +An unsigned decimal number (again, an integer). +.TP +.B %s +A character string. +.TP +.BR %x , " %X" +An unsigned hexadecimal number (an integer). +The +.B %X +format uses +.B ABCDEF +instead of +.BR abcdef . +.TP +.B %% +A single +.B % +character; no argument is converted. +.PP +Optional, additional parameters may lie between the +.B % +and the control letter: +.TP +.IB count $ +Use the +.IR count "'th" +argument at this point in the formatting. +This is called a +.I "positional specifier" +and +is intended primarily for use in translated versions of +format strings, not in the original text of an AWK program. +It is a +.I gawk +extension. +.TP +.B \- +The expression should be left-justified within its field. +.TP +.I space +For numeric conversions, prefix positive values with a space, and +negative values with a minus sign. +.TP +.B + +The plus sign, used before the width modifier (see below), +says to always supply a sign for numeric conversions, even if the data +to be formatted is positive. The +.B + +overrides the space modifier. +.TP +.B # +Use an \*(lqalternate form\*(rq for certain control letters. +For +.BR %o , +supply a leading zero. +For +.BR %x , +and +.BR %X , +supply a leading +.B 0x +or +.B 0X +for +a nonzero result. +For +.BR %e , +.BR %E , +.B %f +and +.BR %F , +the result always contains a +decimal point. +For +.BR %g , +and +.BR %G , +trailing zeros are not removed from the result. +.TP +.B 0 +A leading +.B 0 +(zero) acts as a flag, indicating that output should be +padded with zeroes instead of spaces. +This applies only to the numeric output formats. +This flag only has an effect when the field width is wider than the +value to be printed. +.TP +.B ' +A single quote character instructs +.I gawk +to insert the locale's thousands-separator character +into decimal numbers, and to also use the locale's +decimal point character with floating point formats. +This requires correct locale support in the C library +and in the definition of the current locale. +.TP +.I width +The field should be padded to this width. The field is normally padded +with spaces. With the +.B 0 +flag, it is padded with zeroes. +.TP +.BI \&. prec +A number that specifies the precision to use when printing. +For the +.BR %e , +.BR %E , +.B %f +and +.BR %F , +formats, this specifies the +number of digits you want printed to the right of the decimal point. +For the +.BR %g , +and +.B %G +formats, it specifies the maximum number +of significant digits. For the +.BR %d , +.BR %i , +.BR %o , +.BR %u , +.BR %x , +and +.B %X +formats, it specifies the minimum number of +digits to print. For +.BR %s , +it specifies the maximum number of +characters from the string that should be printed. +.PP +The dynamic +.I width +and +.I prec +capabilities of the ISO C +.B printf() +routines are supported. +A +.B * +in place of either the +.I width +or +.I prec +specifications causes their values to be taken from +the argument list to +.B printf +or +.BR sprintf() . +To use a positional specifier with a dynamic width or precision, +supply the +.IB count $ +after the +.B * +in the format string. +For example, \fB"%3$*2$.*1$s"\fP. +.SS Special File Names +.PP +When doing I/O redirection from either +.B print +or +.B printf +into a file, +or via +.B getline +from a file, +.I gawk +recognizes certain special filenames internally. These filenames +allow access to open file descriptors inherited from +.IR gawk\^ "'s" +parent process (usually the shell). +These file names may also be used on the command line to name data files. +The filenames are: +.TP "\w'\fB/dev/stdout\fR'u+1n" +.B \- +The standard input. +.TP +.B /dev/stdin +The standard input. +.TP +.B /dev/stdout +The standard output. +.TP +.B /dev/stderr +The standard error output. +.TP +.BI /dev/fd/\^ n +The file associated with the open file descriptor +.IR n . +.PP +These are particularly useful for error messages. For example: +.PP +.RS +.ft B +print "You blew it!" > "/dev/stderr" +.ft R +.RE +.PP +whereas you would otherwise have to use +.PP +.RS +.ft B +print "You blew it!" | "cat 1>&2" +.ft R +.RE +.PP +The following special filenames may be used with the +.B |& +coprocess operator for creating TCP/IP network connections: +.TP +.PD 0 +.BI /inet/tcp/ lport / rhost / rport +.TP +.PD 0 +.BI /inet4/tcp/ lport / rhost / rport +.TP +.PD +.BI /inet6/tcp/ lport / rhost / rport +Files for a TCP/IP connection on local port +.I lport +to +remote host +.I rhost +on remote port +.IR rport . +Use a port of +.B 0 +to have the system pick a port. +Use +.B /inet4 +to force an IPv4 connection, +and +.B /inet6 +to force an IPv6 connection. +Plain +.B /inet +uses the system default (most likely IPv4). +.TP +.PD 0 +.BI /inet/udp/ lport / rhost / rport +.TP +.PD 0 +.BI /inet4/udp/ lport / rhost / rport +.TP +.PD +.BI /inet6/udp/ lport / rhost / rport +Similar, but use UDP/IP instead of TCP/IP. +.SS Numeric Functions +.PP +\*(AK has the following built-in arithmetic functions: +.PP +.TP "\w'\fBsrand(\fR[\fIexpr\^\fR]\fB)\fR'u+1n" +.BI atan2( y , " x" ) +Return the arctangent of +.I y/x +in radians. +.TP +.BI cos( expr ) +Return the cosine of +.IR expr , +which is in radians. +.TP +.BI exp( expr ) +The exponential function. +.TP +.BI int( expr ) +Truncate to integer. +.ig +.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 +.B rand() +Return a random number +.IR N , +between zero and one, +such that 0 \(<= \fIN\fP < 1. +.TP +.BI sin( expr ) +Return the sine of +.IR expr , +which is in radians. +.TP +.BI sqrt( expr ) +Return the square root of +.IR expr . +.TP +\&\fBsrand(\fR[\fIexpr\^\fR]\fB)\fR +Use +.I expr +as the new seed for the random number generator. If no +.I expr +is provided, use the time of day. +Return the previous seed for the random +number generator. +.SS String Functions +.PP +.I Gawk +has the following built-in string functions: +.PP +.TP "\w'\fBsprintf(\^\fIfmt\fB\^, \fIexpr-list\^\fB)\fR'u+1n" +\fBasort(\fIs \fR[\fB, \fId\fR [\fB, \fIhow\fR] ]\fB)\fR +Return the number of elements in the source +array +.IR s . +Sort +the contents of +.I s +using +.IR gawk\^ "'s" +normal rules for +comparing values, and replace the indices of the +sorted values +.I s +with sequential +integers starting with 1. If the optional +destination array +.I d +is specified, +first duplicate +.I s +into +.IR d , +and then sort +.IR d , +leaving the indices of the +source array +.I s +unchanged. The optional string +.I how +controls the direction and the comparison mode. +Valid values for +.I how +are +any of the strings valid for +\fBPROCINFO["sorted_in"]\fR. +It can also be the name of a user-defined +comparison function as described in +\fBPROCINFO["sorted_in"]\fR. +.TP "\w'\fBsprintf(\^\fIfmt\fB\^, \fIexpr-list\^\fB)\fR'u+1n" +\fBasorti(\fIs \fR[\fB, \fId\fR [\fB, \fIhow\fR] ]\fB)\fR +Return the number of elements in the source +array +.IR s . +The behavior is the same as that of +.BR asort() , +except that the array +.I indices +are used for sorting, not the array values. +When done, the array is indexed numerically, and +the values are those of the original indices. +The original values are lost; thus provide +a second array if you wish to preserve the original. +The purpose of the optional string +.I how +is the same as described +previously for +.BR asort() . +.TP +\fBgensub(\fIr\fB, \fIs\fB, \fIh \fR[\fB, \fIt\fR]\fB)\fR +Search the target string +.I t +for matches of the regular expression +.IR r . +If +.I h +is a string beginning with +.B g +or +.BR G , +then replace all matches of +.I r +with +.IR s . +Otherwise, +.I h +is a number indicating which match of +.I r +to replace. +If +.I t +is not supplied, use +.B $0 +instead. +Within the replacement text +.IR s , +the sequence +.BI \e n\fR, +where +.I n +is a digit from 1 to 9, may be used to indicate just the text that +matched the +.IR n 'th +parenthesized subexpression. The sequence +.B \e0 +represents the entire matched text, as does the character +.BR & . +Unlike +.B sub() +and +.BR gsub() , +the modified string is returned as the result of the function, +and the original target string is +.I not +changed. +.TP "\w'\fBsprintf(\^\fIfmt\fB\^, \fIexpr-list\^\fB)\fR'u+1n" +\fBgsub(\fIr\fB, \fIs \fR[\fB, \fIt\fR]\fB)\fR +For each substring matching the regular expression +.I r +in the string +.IR t , +substitute the string +.IR s , +and return the number of substitutions. +If +.I t +is not supplied, use +.BR $0 . +An +.B & +in the replacement text is replaced with the text that was actually matched. +Use +.B \e& +to get a literal +.BR & . +(This must be typed as \fB"\e\e&"\fP; +see \*(EP +for a fuller discussion of the rules for ampersands +and backslashes in the replacement text of +.BR sub() , +.BR gsub() , +and +.BR gensub() .) +.TP +.BI index( s , " t" ) +Return the index of the string +.I t +in the string +.IR s , +or zero if +.I t +is not present. +(This implies that character indices start at one.) +It is a fatal error to use a regexp constant for +.IR t . +.TP +\fBlength(\fR[\fIs\fR]\fB) +Return the length of the string +.IR s , +or the length of +.B $0 +if +.I s +is not supplied. +As a non-standard extension, with an array argument, +.B length() +returns the number of elements in the array. +.TP +\fBmatch(\fIs\fB, \fIr \fR[\fB, \fIa\fR]\fB)\fR +Return the position in +.I s +where the regular expression +.I r +occurs, or zero if +.I r +is not present, and set the values of +.B RSTART +and +.BR RLENGTH . +Note that the argument order is the same as for the +.B ~ +operator: +.IB str " ~" +.IR re . +.ft R +If array +.I a +is provided, +.I a +is cleared and then elements 1 through +.I n +are filled with the portions of +.I s +that match the corresponding parenthesized +subexpression in +.IR r . +The zero'th element of +.I a +contains the portion +of +.I s +matched by the entire regular expression +.IR r . +Subscripts +\fBa[\fIn\^\fB, "start"]\fR, +and +\fBa[\fIn\^\fB, "length"]\fR +provide the starting index in the string and length +respectively, of each matching substring. +.TP +\fBpatsplit(\fIs\fB, \fIa \fR[\fB, \fIr\fR [\fB, \fIseps\fR] ]\fB)\fR +Split the string +.I s +into the array +.I a +and the separators array +.I seps +on the regular expression +.IR r , +and return the number of fields. +Element values are the portions of +.I s +that matched +.IR r . +The value of +.BI seps[ i ] +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, +.B FPAT +is used instead. +The arrays +.I a +and +.I seps +are cleared first. +Splitting behaves identically to field splitting with +.BR FPAT , +described above. +.TP +\fBsplit(\fIs\fB, \fIa \fR[\fB, \fIr\fR [\fB, \fIseps\fR] ]\fB)\fR +Split the string +.I s +into the array +.I a +and the separators array +.I seps +on the regular expression +.IR r , +and return the number of fields. If +.I r +is omitted, +.B FS +is used instead. +The arrays +.I a +and +.I seps +are cleared first. +.BI seps[ i ] +is the field separator matched by +.I r +between +.BI a[ i ] +and +.BI a[ i +1]\fR. +\&\fRIf +.I r +is a single space, then leading whitespace in +.I s +goes into the extra array element +.B seps[0] +and trailing whitespace goes into the extra array element +.BI seps[ n ]\fR, +where +.I n +is the return value of +.BI split( s ", " a ", " r ", " seps )\fR. +Splitting behaves identically to field splitting, described above. +.TP +.BI sprintf( fmt , " expr-list" ) +Print +.I expr-list +according to +.IR fmt , +and return the resulting string. +.TP +.BI strtonum( str ) +Examine +.IR str , +and return its numeric value. +If +.I str +begins +with a leading +.BR 0 , +treat it +as an octal number. +If +.I str +begins +with a leading +.B 0x +or +.BR 0X , +treat it +as a hexadecimal number. +Otherwise, assume it is a decimal number. +.TP +\fBsub(\fIr\fB, \fIs \fR[\fB, \fIt\fR]\fB)\fR +Just like +.BR gsub() , +but replace only the first matching substring. +Return either zero or one. +.TP +\fBsubstr(\fIs\fB, \fIi \fR[\fB, \fIn\fR]\fB)\fR +Return the at most +.IR n -character +substring of +.I s +starting at +.IR i . +If +.I n +is omitted, use the rest of +.IR s . +.TP +.BI tolower( str ) +Return a copy of the string +.IR str , +with all the uppercase characters in +.I str +translated to their corresponding lowercase counterparts. +Non-alphabetic characters are left unchanged. +.TP +.BI toupper( str ) +Return a copy of the string +.IR str , +with all the lowercase characters in +.I str +translated to their corresponding uppercase counterparts. +Non-alphabetic characters are left unchanged. +.PP +.I Gawk +is multibyte aware. This means that +.BR index() , +.BR length() , +.B substr() +and +.B match() +all work in terms of characters, not bytes. +.SS Time Functions +Since one of the primary uses of \*(AK programs is processing log files +that contain time stamp information, +.I gawk +provides the following functions for obtaining time stamps and +formatting them. +.PP +.TP "\w'\fBsystime()\fR'u+1n" +\fBmktime(\fIdatespec\fR [\fB, \fIutc-flag\fR]\fB)\fR +Turn +.I datespec +into a time stamp of the same form as returned by +.BR systime() , +and return the result. +The +.I datespec +is a string of the form +.IR "YYYY MM DD HH MM SS[ DST]" . +The contents of the string are six or seven numbers representing respectively +the full year including century, +the month from 1 to 12, +the day of the month from 1 to 31, +the hour of the day from 0 to 23, +the minute from 0 to 59, +the second from 0 to 60, +and an optional daylight saving flag. +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. +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 +.I DST +daylight saving flag is positive, +the time is assumed to be daylight saving time; +if zero, the time is assumed to be standard time; +and if negative (the default), +.B mktime() +attempts to determine whether daylight saving time is in effect +for the specified time. +If +.I datespec +does not contain enough elements or if the resulting time +is out of range, +.B mktime() +returns \-1. +.TP +\fBstrftime(\fR[\fIformat \fR[\fB, \fItimestamp\fR[\fB, \fIutc-flag\fR]]]\fB)\fR +Format +.I timestamp +according to the specification in +.IR format . +If +.I utc-flag +is present and is non-zero or non-null, the result +is in UTC, otherwise the result is in local time. +The +.I timestamp +should be of the same form as returned by +.BR systime() . +If +.I timestamp +is missing, the current time of day is used. +If +.I format +is missing, a default format equivalent to the output of +.IR date (1) +is used. +The default format is available in +.BR PROCINFO["strftime"] . +See the specification for the +.B strftime() +function in ISO C for the format conversions that are +guaranteed to be available. +.TP +.B systime() +Return the current time of day as the number of seconds since the Epoch +(1970-01-01 00:00:00 UTC on \*(PX systems). +.SS Bit Manipulations Functions +.I Gawk +supplies the following bit manipulation functions. +They work by converting double-precision floating point +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 +Return the bitwise AND of the values provided in the argument list. +There must be at least two. +.TP +\fBcompl(\fIval\fB)\fR +Return the bitwise complement of +.IR val . +.TP +\fBlshift(\fIval\fB, \fIcount\fB)\fR +Return the value of +.IR val , +shifted left by +.I count +bits. +.TP +\fBor(\fIv1\fB, \fIv2 \fR[, ...]\fB)\fR +Return the bitwise OR of the values provided in the argument list. +There must be at least two. +.TP +\fBrshift(\fIval\fB, \fIcount\fB)\fR +Return the value of +.IR val , +shifted right by +.I count +bits. +.TP +\fBxor(\fIv1\fB, \fIv2 \fR[, ...]\fB)\fR +Return the bitwise XOR of the values provided in the argument list. +There must be at least two. +.PP +.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. +For full details, see \*(EP. +.TP +\fBbindtextdomain(\fIdirectory \fR[\fB, \fIdomain\fR]\fB)\fR +Specify the directory where +.I gawk +looks for the +.B \&.gmo +files, in case they +will not or cannot be placed in the ``standard'' locations +(e.g., during testing). +It returns the directory where +.I domain +is ``bound.'' +.sp .5 +The default +.I domain +is the value of +.BR TEXTDOMAIN . +If +.I directory +is the null string (\fB""\fR), then +.B bindtextdomain() +returns the current binding for the +given +.IR domain . +.TP +\fBdcgettext(\fIstring \fR[\fB, \fIdomain \fR[\fB, \fIcategory\fR]]\fB)\fR +Return the translation of +.I string +in text domain +.I domain +for locale category +.IR category . +The default value for +.I domain +is the current value of +.BR TEXTDOMAIN . +The default value for +.I category +is \fB"LC_MESSAGES"\fR. +.sp .5 +If you supply a value for +.IR category , +it must be a string equal to +one of the known locale categories described +in \*(EP. +You must also supply a text domain. Use +.B TEXTDOMAIN +if you want to use the current domain. +.TP +\fBdcngettext(\fIstring1\fB, \fIstring2\fB, \fInumber \fR[\fB, \fIdomain \fR[\fB, \fIcategory\fR]]\fB)\fR +Return the plural form used for +.I number +of the translation of +.I string1 +and +.I string2 +in +text domain +.I domain +for locale category +.IR category . +The default value for +.I domain +is the current value of +.BR TEXTDOMAIN . +The default value for +.I category +is \fB"LC_MESSAGES"\fR. +.sp .5 +If you supply a value for +.IR category , +it must be a string equal to +one of the known locale categories described +in \*(EP. +You must also supply a text domain. Use +.B TEXTDOMAIN +if you want to use the current domain. +.SH USER-DEFINED FUNCTIONS +Functions in \*(AK are defined as follows: +.PP +.RS +\fBfunction \fIname\fB(\fIparameter list\fB) { \fIstatements \fB}\fR +.RE +.PP +Functions execute when they are called from within expressions +in either patterns or actions. Actual parameters supplied in the function +call are used to instantiate the formal parameters declared in the function. +Arrays are passed by reference, other variables are passed by value. +.PP +Since functions were not originally part of the \*(AK language, the provision +for local variables is rather clumsy: They are declared as extra parameters +in the parameter list. The convention is to separate local variables from +real parameters by extra spaces in the parameter list. For example: +.PP +.RS +.ft B +.nf +function f(p, q, a, b) # a and b are local +{ + \&.\|.\|. +} + +/abc/ { .\|.\|. ; f(1, 2) ; .\|.\|. } +.fi +.ft R +.RE +.PP +The left parenthesis in a function call is required +to immediately follow the function name, +without any intervening whitespace. +This avoids a syntactic ambiguity with the concatenation operator. +This restriction does not apply to the built-in functions listed above. +.PP +Functions may call each other and may be recursive. +Function parameters used as local variables are initialized +to the null string and the number zero upon function invocation. +.PP +Use +.BI return " expr" +to return a value from a function. The return value is undefined if no +value is provided, or if the function returns by \*(lqfalling off\*(rq the +end. +.PP +As a +.I gawk +extension, functions may be called indirectly. To do this, assign +the name of the function to be called, as a string, to a variable. +Then use the variable as if it were the name of a function, prefixed with an +.B @ +sign, like so: +.RS +.ft B +.nf +function myfunc() +{ + print "myfunc called" + \&.\|.\|. +} + +{ .\|.\|. + the_func = "myfunc" + @the_func() # call through the_func to myfunc + .\|.\|. +} +.fi +.ft R +.RE +As of version 4.1.2, this works with user-defined functions, +built-in functions, and extension functions. +.PP +If +.B \-\^\-lint +has been provided, +.I gawk +warns about calls to undefined functions at parse time, +instead of at run time. +Calling an undefined function at run time is a fatal error. +.PP +The word +.B func +may be used in place of +.BR function , +although this is deprecated. +.SH DYNAMICALLY LOADING NEW FUNCTIONS +You can dynamically add new built-in functions to the running +.I gawk +interpreter with the +.B @load +statement. +The full details are beyond the scope of this manual page; +see \*(EP. +.SH SIGNALS +The +.I gawk +profiler accepts two signals. +.B SIGUSR1 +causes it to dump a profile and function call stack to the +profile file, which is either +.BR awkprof.out , +or whatever file was named with the +.B \-\^\-profile +option. It then continues to run. +.B SIGHUP +causes +.I gawk +to dump the profile and function call stack and then exit. +.SH INTERNATIONALIZATION +.PP +String constants are sequences of characters enclosed in double +quotes. In non-English speaking environments, it is possible to mark +strings in the \*(AK program as requiring translation to the local +natural language. Such strings are marked in the \*(AK program with +a leading underscore (\*(lq_\*(rq). For example, +.sp +.RS +.ft B +gawk 'BEGIN { print "hello, world" }' +.RE +.sp +.ft R +always prints +.BR "hello, world" . +But, +.sp +.RS +.ft B +gawk 'BEGIN { print _"hello, world" }' +.RE +.sp +.ft R +might print +.B "bonjour, monde" +in France. +.PP +There are several steps involved in producing and running a localizable +\*(AK program. +.TP "\w'4.'u+2n" +1. +Add a +.B BEGIN +action to assign a value to the +.B TEXTDOMAIN +variable to set the text domain to a name associated with your program: +.sp +.in +5m +.ft B +BEGIN { TEXTDOMAIN = "myprog" } +.ft R +.in -5m +.sp +This allows +.I gawk +to find the +.B \&.gmo +file associated with your program. +Without this step, +.I gawk +uses the +.B messages +text domain, +which likely does not contain translations for your program. +.TP +2. +Mark all strings that should be translated with leading underscores. +.TP +3. +If necessary, use the +.B dcgettext() +and/or +.B bindtextdomain() +functions in your program, as appropriate. +.TP +4. +Run +.B "gawk \-\^\-gen\-pot \-f myprog.awk > myprog.pot" +to generate a +.B \&.pot +file for your program. +.TP +5. +Provide appropriate translations, and build and install the corresponding +.B \&.gmo +files. +.PP +The internationalization features are described in full detail in \*(EP. +.SH POSIX COMPATIBILITY +A primary goal for +.I gawk +is compatibility with the \*(PX standard, as well as with the +latest version of Brian Kernighan's +.IR awk . +To this end, +.I gawk +incorporates the following user visible +features which are not described in the \*(AK book, +but are part of the Brian Kernighan's version of +.IR awk , +and are in the \*(PX standard. +.PP +The book indicates that command line variable assignment happens when +.I awk +would otherwise open the argument as a file, which is after the +.B BEGIN +rule is executed. However, in earlier implementations, when such an +assignment appeared before any file names, the assignment would happen +.I before +the +.B BEGIN +rule was run. Applications came to depend on this \*(lqfeature.\*(rq +When +.I awk +was changed to match its documentation, the +.B \-v +option for assigning variables before program execution was added to +accommodate applications that depended upon the old behavior. +(This feature was agreed upon by both the Bell Laboratories +and the \*(GN developers.) +.PP +When processing arguments, +.I gawk +uses the special option \*(lq\-\^\-\*(rq to signal the end of +arguments. +In compatibility mode, it warns about but otherwise ignores +undefined options. +In normal operation, such arguments are passed on to the \*(AK program for +it to process. +.PP +The \*(AK book does not define the return value of +.BR srand() . +The \*(PX standard +has it return the seed it was using, to allow keeping track +of random number sequences. Therefore +.B srand() +in +.I gawk +also returns its current seed. +.PP +Other features are: +The use of multiple +.B \-f +options (from MKS +.IR awk ); +the +.B ENVIRON +array; the +.BR \ea , +and +.B \ev +escape sequences (done originally in +.I gawk +and fed back into the Bell Laboratories version); the +.B tolower() +and +.B toupper() +built-in functions (from the Bell Laboratories version); and the ISO C conversion specifications in +.B printf +(done first in the Bell Laboratories version). +.SH HISTORICAL FEATURES +There is one feature of historical \*(AK implementations that +.I gawk +supports: +It is possible to call the +.B length() +built-in function not only with no argument, but even without parentheses! +Thus, +.RS +.PP +.ft B +a = length # Holy Algol 60, Batman! +.ft R +.RE +.PP +is the same as either of +.RS +.PP +.ft B +a = length() +.br +a = length($0) +.ft R +.RE +.PP +Using this feature is poor practice, and +.I gawk +issues a warning about its use if +.B \-\^\-lint +is specified on the command line. +.SH GNU EXTENSIONS +.I Gawk +has a too-large number of extensions to \*(PX +.IR awk . +They are described in this section. All the extensions described here +can be disabled by +invoking +.I gawk +with the +.B \-\^\-traditional +or +.B \-\^\-posix +options. +.PP +The following features of +.I gawk +are not available in +\*(PX +.IR awk . +.\" Environment vars and startup stuff +.TP "\w'\(bu'u+1n" +\(bu +No path search is performed for files named via the +.B \-f +option. Therefore the +.B AWKPATH +environment variable is not special. +.\" POSIX and language recognition issues +.TP +\(bu +There is no facility for doing file inclusion +.RI ( gawk 's +.B @include +mechanism). +.TP +\(bu +There is no facility for dynamically adding new functions +written in C +.RI ( gawk 's +.B @load +mechanism). +.TP +\(bu +The +.B \ex +escape sequence. +.TP +\(bu +The ability to continue lines after +.B ? +and +.BR : . +.TP +\(bu +Octal and hexadecimal constants in AWK programs. +.\" Special variables +.TP +\(bu +The +.BR ARGIND , +.BR BINMODE , +.BR ERRNO , +.BR LINT , +.BR PREC , +.BR ROUNDMODE , +.B RT +and +.B TEXTDOMAIN +variables are not special. +.TP +\(bu +The +.B IGNORECASE +variable and its side-effects are not available. +.TP +\(bu +The +.B FIELDWIDTHS +variable and fixed-width field splitting. +.TP +\(bu +The +.B FPAT +variable and field splitting based on field values. +.TP +\(bu +The +.BR FUNCTAB , +.BR SYMTAB , +and +.B PROCINFO +arrays are not available. +.\" I/O stuff +.TP +\(bu +The use of +.B RS +as a regular expression. +.TP +\(bu +The special file names available for I/O redirection are not recognized. +.TP +\(bu +The +.B |& +operator for creating coprocesses. +.TP +\(bu +The +.B BEGINFILE +and +.B ENDFILE +special patterns are not available. +.\" Changes to standard awk functions +.TP +\(bu +The ability to split out individual characters using the null string +as the value of +.BR FS , +and as the third argument to +.BR split() . +.TP +\(bu +An optional fourth argument to +.B split() +to receive the separator texts. +.TP +\(bu +The optional second argument to the +.B close() +function. +.TP +\(bu +The optional third argument to the +.B match() +function. +.TP +\(bu +The ability to use positional specifiers with +.B printf +and +.BR sprintf() . +.TP +\(bu +The ability to pass an array to +.BR length() . +.\" New keywords or changes to keywords +.\" (As of 2012, these are in POSIX) +.\" .TP +.\" \(bu +.\" The use of +.\" .BI delete " array" +.\" to delete the entire contents of an array. +.\" .TP +.\" \(bu +.\" The use of +.\" .B "nextfile" +.\" to abandon processing of the current input file. +.\" New functions +.TP +\(bu +The +.BR and() , +.BR asort() , +.BR asorti() , +.BR bindtextdomain() , +.BR compl() , +.BR dcgettext() , +.BR dcngettext() , +.BR gensub() , +.BR lshift() , +.BR mktime() , +.BR or() , +.BR patsplit() , +.BR rshift() , +.BR strftime() , +.BR strtonum() , +.B systime() +and +.B xor() +functions. +.\" I18N stuff +.TP +\(bu +Localizable strings. +.TP +\(bu +Non-fatal I/O. +.TP +\(bu +Retryable I/O. +.PP +The \*(AK book does not define the return value of the +.B close() +function. +.IR Gawk\^ "'s" +.B close() +returns the value from +.IR fclose (3), +or +.IR pclose (3), +when closing an output file or pipe, respectively. +It returns the process's exit status when closing an input pipe. +The return value is \-1 if the named file, pipe +or coprocess was not opened with a redirection. +.PP +When +.I gawk +is invoked with the +.B \-\^\-traditional +option, +if the +.I fs +argument to the +.B \-F +option is \*(lqt\*(rq, then +.B FS +is set to the tab character. +Note that typing +.B "gawk \-F\et \&.\|.\|." +simply causes the shell to quote the \*(lqt,\*(rq and does not pass +\*(lq\et\*(rq to the +.B \-F +option. +Since this is a rather ugly special case, it is not the default behavior. +This behavior also does not occur if +.B \-\^\-posix +has been specified. +To really get a tab character as the field separator, it is best to use +single quotes: +.BR "gawk \-F'\et' \&.\|.\|." . +.ig +.PP +If +.I gawk +was compiled for debugging, it +accepts the following additional options: +.TP +.PD 0 +.B \-Y +.TP +.PD +.B \-\^\-parsedebug +Turn on +.IR yacc (1) +or +.IR bison (1) +debugging output during program parsing. +This option should only be of interest to the +.I gawk +maintainers, and may not even be compiled into +.IR gawk . +.. +.SH ENVIRONMENT VARIABLES +The +.B AWKPATH +environment variable can be used to provide a list of directories that +.I gawk +searches when looking for files named via the +.BR \-f , +.RB \-\^\-file , +.B \-i +and +.B \-\^\-include +options, and the +.B @include +directive. If the initial search fails, the path is searched again after +appending +.B \&.awk +to the filename. +.PP +The +.B AWKLIBPATH +environment variable can be used to provide a list of directories that +.I gawk +searches when looking for files named via the +.B \-l +and +.B \-\^\-load +options. +.PP +The +.B GAWK_READ_TIMEOUT +environment variable can be used to specify a timeout +in milliseconds for reading input from a terminal, pipe +or two-way communication including sockets. +.PP +For connection to a remote host via socket, +.B GAWK_SOCK_RETRIES +controls the number of retries, and +.B GAWK_MSEC_SLEEP +and the interval between retries. +The interval is in milliseconds. On systems that do not support +.IR usleep (3), +the value is rounded up to an integral number of seconds. +.PP +If +.B POSIXLY_CORRECT +exists in the environment, then +.I gawk +behaves exactly as if +.B \-\^\-posix +had been specified on the command line. +If +.B \-\^\-lint +has been specified, +.I gawk +issues a warning message to this effect. +.SH EXIT STATUS +If the +.B exit +statement is used with a value, +then +.I gawk +exits with +the numeric value given to it. +.PP +Otherwise, if there were no problems during execution, +.I gawk +exits with the value of the C constant +.BR EXIT_SUCCESS . +This is usually zero. +.PP +If an error occurs, +.I gawk +exits with the value of +the C constant +.BR EXIT_FAILURE . +This is usually one. +.PP +If +.I gawk +exits because of a fatal error, the exit +status is 2. On non-POSIX systems, this value may be mapped to +.BR EXIT_FAILURE . +.SH VERSION INFORMATION +This man page documents +.IR gawk , +version 4.2. +.SH AUTHORS +The original version of \*(UX +.I awk +was designed and implemented by Alfred Aho, +Peter Weinberger, and Brian Kernighan of Bell Laboratories. Brian Kernighan +continues to maintain and enhance it. +.PP +Paul Rubin and Jay Fenlason, +of the Free Software Foundation, wrote +.IR gawk , +to be compatible with the original version of +.I awk +distributed in Seventh Edition \*(UX. +John Woods contributed a number of bug fixes. +David Trueman, with contributions +from Arnold Robbins, made +.I gawk +compatible with the new version of \*(UX +.IR awk . +Arnold Robbins is the current maintainer. +.PP +See \*(EP for a full list of the contributors to +.I gawk +and its documentation. +.PP +See the +.B README +file in the +.I gawk +distribution for up-to-date information about maintainers +and which ports are currently supported. +.SH BUG REPORTS +If you find a bug in +.IR gawk , +please send electronic mail to +.BR bug-gawk@gnu.org . +Please include your operating system and its revision, the version of +.I gawk +(from +.BR "gawk \-\^\-version" ), +which C compiler you used to compile it, and a test program +and data that are as small as possible for reproducing the problem. +.PP +Before sending a bug report, please do the following things. First, verify that +you have the latest version of +.IR gawk . +Many bugs (usually subtle ones) are fixed at each release, and if +yours is out of date, the problem may already have been solved. +Second, please see if setting the environment variable +.B LC_ALL +to +.B LC_ALL=C +causes things to behave as you expect. If so, it's a locale issue, +and may or may not really be a bug. +Finally, please read this man page and the reference manual carefully to +be sure that what you think is a bug really is, instead of just a quirk +in the language. +.PP +Whatever you do, do +.B NOT +post a bug report in +.BR comp.lang.awk . +While the +.I gawk +developers occasionally read this newsgroup, posting bug reports there +is an unreliable way to report bugs. Instead, please use the electronic mail +addresses given above. +Really. +.PP +If you're using a GNU/Linux or BSD-based system, +you may wish to submit a bug report to the vendor of your distribution. +That's fine, but please send a copy to the official email address as well, +since there's no guarantee that the bug report will be forwarded to the +.I gawk +maintainer. +.SH BUGS +The +.B \-F +option is not necessary given the command line variable assignment feature; +it remains only for backwards compatibility. +.SH SEE ALSO +.IR egrep (1), +.IR sed (1), +.IR getpid (2), +.IR getppid (2), +.IR getpgrp (2), +.IR getuid (2), +.IR geteuid (2), +.IR getgid (2), +.IR getegid (2), +.IR getgroups (2), +.IR printf (3), +.IR strftime (3), +.IR usleep (3) +.PP +.IR "The AWK Programming Language" , +Alfred V. Aho, Brian W. Kernighan, Peter J. Weinberger, +Addison-Wesley, 1988. ISBN 0-201-07981-X. +.PP +\*(EP, +Edition 4.2, shipped with the +.I gawk +source. +The current version of this document is available online at +.BR https://www.gnu.org/software/gawk/manual . +.PP +The GNU +.B gettext +documentation, available online at +.BR https://www.gnu.org/software/gettext . +.SH EXAMPLES +.nf +Print and sort the login names of all users: + +.ft B + BEGIN { FS = ":" } + { print $1 | "sort" } + +.ft R +Count lines in a file: + +.ft B + { nlines++ } + END { print nlines } + +.ft R +Precede each line by its number in the file: + +.ft B + { print FNR, $0 } + +.ft R +Concatenate and line number (a variation on a theme): + +.ft B + { print NR, $0 } + +.ft R +Run an external command for particular lines of data: + +.ft B + tail \-f access_log | + awk '/myhome.html/ { system("nmap " $1 ">> logdir/myhome.html") }' +.ft R +.fi +.SH ACKNOWLEDGEMENTS +Brian Kernighan +provided valuable assistance during testing and debugging. +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, 2015, 2016, 2017, 2018 +Free Software Foundation, Inc. +.PP +Permission is granted to make and distribute verbatim copies of +this manual page provided the copyright notice and this permission +notice are preserved on all copies. +.ig +Permission is granted to process this file through troff and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual page). +.. +.PP +Permission is granted to copy and distribute modified versions of this +manual page under the conditions for verbatim copying, provided that +the entire resulting derived work is distributed under the terms of a +permission notice identical to this one. +.PP +Permission is granted to copy and distribute translations of this +manual page into another language, under the above conditions for +modified versions, except that this permission notice may be stated in +a translation approved by the Foundation. diff --git a/doc/gawk.info b/doc/gawk.info new file mode 100644 index 0000000..738de09 --- /dev/null +++ b/doc/gawk.info @@ -0,0 +1,36584 @@ +This is gawk.info, produced by makeinfo version 6.1 from gawk.texi. + +Copyright (C) 1989, 1991, 1992, 1993, 1996-2005, 2007, 2009-2018 +Free Software Foundation, Inc. + + + This is Edition 4.2 of 'GAWK: Effective AWK Programming: A User's +Guide for GNU Awk', for the 4.2.1 (or later) version of the GNU +implementation of AWK. + + 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: (gawk). A text scanning and processing language. +END-INFO-DIR-ENTRY + +INFO-DIR-SECTION Individual utilities +START-INFO-DIR-ENTRY +* awk: (gawk)Invoking Gawk. Text scanning and processing. +END-INFO-DIR-ENTRY + + +File: gawk.info, Node: Top, Next: Foreword3, Up: (dir) + +General Introduction +******************** + +This file documents 'awk', a program that you can use to select +particular records in a file and perform operations upon them. + + Copyright (C) 1989, 1991, 1992, 1993, 1996-2005, 2007, 2009-2018 +Free Software Foundation, Inc. + + + This is Edition 4.2 of 'GAWK: Effective AWK Programming: A User's +Guide for GNU Awk', for the 4.2.1 (or later) version of the GNU +implementation of AWK. + + 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: + +* Foreword3:: Some nice words about this + Info file. +* Foreword4:: More nice words. +* Preface:: What this Info file is about; brief + history and acknowledgments. +* Getting Started:: A basic introduction to using + 'awk'. How to run an 'awk' + program. Command-line syntax. +* Invoking Gawk:: How to run 'gawk'. +* Regexp:: All about matching things using regular + expressions. +* Reading Files:: How to read files and manipulate fields. +* Printing:: How to print using 'awk'. Describes + the 'print' and 'printf' + statements. Also describes redirection of + output. +* Expressions:: Expressions are the basic building blocks + of statements. +* Patterns and Actions:: Overviews of patterns and actions. +* Arrays:: The description and use of arrays. Also + includes array-oriented control statements. +* Functions:: Built-in and user-defined functions. +* Library Functions:: A Library of 'awk' Functions. +* Sample Programs:: Many 'awk' programs with complete + explanations. +* Advanced Features:: Stuff for advanced users, specific to + 'gawk'. +* Internationalization:: Getting 'gawk' to speak your + language. +* Debugger:: The 'gawk' debugger. +* Arbitrary Precision Arithmetic:: Arbitrary precision arithmetic with + 'gawk'. +* Dynamic Extensions:: Adding new built-in functions to + 'gawk'. +* Language History:: The evolution of the 'awk' + language. +* Installation:: Installing 'gawk' under various + operating systems. +* Notes:: Notes about adding things to 'gawk' + and possible future work. +* Basic Concepts:: A very quick introduction to programming + concepts. +* Glossary:: An explanation of some unfamiliar terms. +* Copying:: Your right to copy and distribute + 'gawk'. +* GNU Free Documentation License:: The license for this Info file. +* Index:: Concept and Variable Index. + +* History:: The history of 'gawk' and + 'awk'. +* Names:: What name to use to find + 'awk'. +* This Manual:: Using this Info file. Includes + sample input files that you can use. +* Conventions:: Typographical Conventions. +* Manual History:: Brief history of the GNU project and + this Info file. +* How To Contribute:: Helping to save the world. +* Acknowledgments:: Acknowledgments. +* Running gawk:: How to run 'gawk' programs; + includes command-line syntax. +* One-shot:: Running a short throwaway + 'awk' program. +* Read Terminal:: Using no input files (input from the + keyboard instead). +* Long:: Putting permanent 'awk' + programs in files. +* Executable Scripts:: Making self-contained 'awk' + programs. +* Comments:: Adding documentation to 'gawk' + programs. +* Quoting:: More discussion of shell quoting + issues. +* DOS Quoting:: Quoting in Windows Batch Files. +* Sample Data Files:: Sample data files for use in the + 'awk' programs illustrated in + this Info file. +* Very Simple:: A very simple example. +* Two Rules:: A less simple one-line example using + two rules. +* More Complex:: A more complex example. +* Statements/Lines:: Subdividing or combining statements + into lines. +* Other Features:: Other Features of 'awk'. +* When:: When to use 'gawk' and when to + use other things. +* Intro Summary:: Summary of the introduction. +* Command Line:: How to run 'awk'. +* Options:: Command-line options and their + meanings. +* Other Arguments:: Input file names and variable + assignments. +* Naming Standard Input:: How to specify standard input with + other files. +* Environment Variables:: The environment variables + 'gawk' uses. +* AWKPATH Variable:: Searching directories for + 'awk' programs. +* AWKLIBPATH Variable:: Searching directories for + 'awk' shared libraries. +* Other Environment Variables:: The environment variables. +* Exit Status:: 'gawk''s exit status. +* Include Files:: Including other files into your + program. +* Loading Shared Libraries:: Loading shared libraries into your + program. +* Obsolete:: Obsolete Options and/or features. +* Undocumented:: Undocumented Options and Features. +* Invoking Summary:: Invocation summary. +* Regexp Usage:: How to Use Regular Expressions. +* Escape Sequences:: How to write nonprinting characters. +* Regexp Operators:: Regular Expression Operators. +* Bracket Expressions:: What can go between '[...]'. +* Leftmost Longest:: How much text matches. +* Computed Regexps:: Using Dynamic Regexps. +* GNU Regexp Operators:: Operators specific to GNU software. +* Case-sensitivity:: How to do case-insensitive matching. +* Regexp Summary:: Regular expressions summary. +* Records:: Controlling how data is split into + records. +* awk split records:: How standard 'awk' splits + records. +* gawk split records:: How 'gawk' splits records. +* Fields:: An introduction to fields. +* Nonconstant Fields:: Nonconstant Field Numbers. +* Changing Fields:: Changing the Contents of a Field. +* Field Separators:: The field separator and how to change + it. +* Default Field Splitting:: How fields are normally separated. +* Regexp Field Splitting:: Using regexps as the field separator. +* Single Character Fields:: Making each character a separate + field. +* Command Line Field Separator:: Setting 'FS' from the command + line. +* Full Line Fields:: Making the full line be a single + 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' + function. +* Plain Getline:: Using 'getline' with no + arguments. +* Getline/Variable:: Using 'getline' into a variable. +* Getline/File:: Using 'getline' from a file. +* Getline/Variable/File:: Using 'getline' into a variable + from a file. +* Getline/Pipe:: Using 'getline' from a pipe. +* Getline/Variable/Pipe:: Using 'getline' into a variable + from a pipe. +* Getline/Coprocess:: Using 'getline' from a coprocess. +* Getline/Variable/Coprocess:: Using 'getline' into a variable + from a coprocess. +* Getline Notes:: Important things to know about + '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. +* Input Exercises:: Exercises. +* Print:: The 'print' statement. +* Print Examples:: Simple examples of 'print' + statements. +* Output Separators:: The output separators and how to + change them. +* OFMT:: Controlling Numeric Output With + 'print'. +* Printf:: The 'printf' statement. +* Basic Printf:: Syntax of the 'printf' statement. +* Control Letters:: Format-control letters. +* Format Modifiers:: Format-specification modifiers. +* Printf Examples:: Several examples. +* Redirection:: How to redirect output to multiple + files and pipes. +* Special FD:: Special files for I/O. +* Special Files:: File name interpretation in + 'gawk'. 'gawk' allows + access to inherited file descriptors. +* Other Inherited Files:: Accessing other open files with + 'gawk'. +* Special Network:: Special files for network + communications. +* 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 + Expressions. +* Constants:: String, numeric and regexp constants. +* Scalar Constants:: Numeric and string constants. +* 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. +* Assignment Options:: Setting variables on the command line + and a summary of command-line syntax. + This is an advanced method of input. +* Conversion:: The conversion of strings to numbers + and vice versa. +* Strings And Numbers:: How 'awk' Converts Between + Strings And Numbers. +* Locale influences conversions:: How the locale may affect conversions. +* All Operators:: 'gawk''s operators. +* Arithmetic Ops:: Arithmetic operations ('+', + '-', etc.) +* Concatenation:: Concatenating strings. +* Assignment Ops:: Changing the value of a variable or a + field. +* Increment Ops:: Incrementing the numeric value of a + variable. +* Truth Values and Conditions:: Testing for true and false. +* Truth Values:: What is "true" and what is + "false". +* Typing and Comparison:: How variables acquire types and how + this affects comparison of numbers and + strings with '<', etc. +* Variable Typing:: String type versus numeric type. +* Comparison Operators:: The comparison operators. +* POSIX String Comparison:: String comparison with POSIX rules. +* Boolean Ops:: Combining comparison expressions using + boolean operators '||' ("or"), + '&&' ("and") and '!' + ("not"). +* Conditional Exp:: Conditional expressions select between + two subexpressions under control of a + third subexpression. +* Function Calls:: A function call is an expression. +* Precedence:: How various operators nest. +* Locales:: How the locale affects things. +* Expressions Summary:: Expressions summary. +* Pattern Overview:: What goes into a pattern. +* Regexp Patterns:: Using regexps as patterns. +* Expression Patterns:: Any expression can be used as a + pattern. +* Ranges:: Pairs of patterns specify record + ranges. +* BEGIN/END:: Specifying initialization and cleanup + rules. +* Using BEGIN/END:: How and why to use BEGIN/END rules. +* I/O And BEGIN/END:: I/O issues in BEGIN/END rules. +* BEGINFILE/ENDFILE:: Two special patterns for advanced + control. +* Empty:: The empty pattern, which matches every + record. +* Using Shell Variables:: How to use shell variables with + 'awk'. +* Action Overview:: What goes into an action. +* Statements:: Describes the various control + statements in detail. +* If Statement:: Conditionally execute some + 'awk' statements. +* While Statement:: Loop until some condition is + satisfied. +* Do Statement:: Do specified action while looping + until some condition is satisfied. +* For Statement:: Another looping statement, that + provides initialization and increment + clauses. +* Switch Statement:: Switch/case evaluation for conditional + execution of statements based on a + value. +* Break Statement:: Immediately exit the innermost + enclosing loop. +* Continue Statement:: Skip to the end of the innermost + enclosing loop. +* Next Statement:: Stop processing the current input + record. +* Nextfile Statement:: Stop processing the current file. +* Exit Statement:: Stop execution of 'awk'. +* Built-in Variables:: Summarizes the predefined variables. +* User-modified:: Built-in variables that you change to + control 'awk'. +* Auto-set:: Built-in variables where 'awk' + gives you information. +* ARGC and ARGV:: Ways to use 'ARGC' and + 'ARGV'. +* Pattern Action Summary:: Patterns and Actions summary. +* Array Basics:: The basics of arrays. +* Array Intro:: Introduction to Arrays +* Reference to Elements:: How to examine one element of an + array. +* Assigning Elements:: How to change an element of an array. +* Array Example:: Basic Example of an Array +* Scanning an Array:: A variation of the 'for' + statement. It loops through the + indices of an array's existing + elements. +* Controlling Scanning:: Controlling the order in which arrays + are scanned. +* Numeric Array Subscripts:: How to use numbers as subscripts in + 'awk'. +* Uninitialized Subscripts:: Using Uninitialized variables as + subscripts. +* Delete:: The 'delete' statement removes an + element from an array. +* Multidimensional:: Emulating multidimensional arrays in + 'awk'. +* Multiscanning:: Scanning multidimensional arrays. +* Arrays of Arrays:: True multidimensional arrays. +* Arrays Summary:: Summary of arrays. +* Built-in:: Summarizes the built-in functions. +* Calling Built-in:: How to call built-in functions. +* Numeric Functions:: Functions that work with numbers, + including 'int()', 'sin()' + and 'rand()'. +* String Functions:: Functions for string manipulation, + such as 'split()', 'match()' + and 'sprintf()'. +* Gory Details:: More than you want to know about + '\' and '&' with + 'sub()', 'gsub()', and + 'gensub()'. +* I/O Functions:: Functions for files and shell + commands. +* Time Functions:: Functions for dealing with timestamps. +* Bitwise Functions:: Functions for bitwise operations. +* Type Functions:: Functions for type information. +* I18N Functions:: Functions for string translation. +* User-defined:: Describes User-defined functions in + detail. +* Definition Syntax:: How to write definitions and what they + mean. +* Function Example:: An example function definition and + what it does. +* Function Caveats:: Things to watch out for. +* Calling A Function:: Don't use spaces. +* Variable Scope:: Controlling variable scope. +* Pass By Value/Reference:: Passing parameters. +* Return Statement:: Specifying the value a function + returns. +* Dynamic Typing:: How variable types can change at + runtime. +* Indirect Calls:: Choosing the function to call at + runtime. +* Functions Summary:: Summary of functions. +* Library Names:: How to best name private global + variables in library functions. +* General Functions:: Functions that are of general use. +* Strtonum Function:: A replacement for the built-in + 'strtonum()' function. +* Assert Function:: A function for assertions in + 'awk' programs. +* Round Function:: A function for rounding if + 'sprintf()' does not do it + correctly. +* Cliff Random Function:: The Cliff Random Number Generator. +* Ordinal Functions:: Functions for using characters as + numbers and vice versa. +* Join Function:: A function to join an array into a + string. +* Getlocaltime Function:: A function to get formatted times. +* Readfile Function:: A function to read an entire file at + once. +* Shell Quoting:: A function to quote strings for the + shell. +* Data File Management:: Functions for managing command-line + data files. +* Filetrans Function:: A function for handling data file + transitions. +* Rewind Function:: A function for rereading the current + file. +* File Checking:: Checking that data files are readable. +* Empty Files:: Checking for zero-length files. +* Ignoring Assigns:: Treating assignments as file names. +* Getopt Function:: A function for processing command-line + arguments. +* Passwd Functions:: Functions for getting user + information. +* Group Functions:: Functions for getting group + information. +* Walking Arrays:: A function to walk arrays of arrays. +* Library Functions Summary:: Summary of library functions. +* Library Exercises:: Exercises. +* Running Examples:: How to run these examples. +* Clones:: Clones of common utilities. +* Cut Program:: The 'cut' utility. +* Egrep Program:: The 'egrep' utility. +* Id Program:: The 'id' utility. +* Split Program:: The 'split' utility. +* Tee Program:: The 'tee' utility. +* Uniq Program:: The 'uniq' utility. +* Wc Program:: The 'wc' utility. +* Miscellaneous Programs:: Some interesting 'awk' + programs. +* Dupword Program:: Finding duplicated words in a + document. +* Alarm Program:: An alarm clock. +* Translate Program:: A program similar to the 'tr' + utility. +* Labels Program:: Printing mailing labels. +* Word Sorting:: A program to produce a word usage + count. +* History Sorting:: Eliminating duplicate entries from a + history file. +* Extract Program:: Pulling out programs from Texinfo + source files. +* Simple Sed:: A Simple Stream Editor. +* Igawk Program:: A wrapper for 'awk' that + includes files. +* Anagram Program:: Finding anagrams from a dictionary. +* Signature Program:: People do amazing things with too much + time on their hands. +* Programs Summary:: Summary of programs. +* Programs Exercises:: Exercises. +* Nondecimal Data:: Allowing nondecimal input data. +* Array Sorting:: Facilities for controlling array + traversal and sorting arrays. +* Controlling Array Traversal:: How to use PROCINFO["sorted_in"]. +* Array Sorting Functions:: How to use 'asort()' and + 'asorti()'. +* Two-way I/O:: Two-way communications with another + process. +* TCP/IP Networking:: Using 'gawk' for network + programming. +* Profiling:: Profiling your 'awk' programs. +* Advanced Features Summary:: Summary of advanced features. +* I18N and L10N:: Internationalization and Localization. +* Explaining gettext:: How GNU 'gettext' works. +* Programmer i18n:: Features for the programmer. +* Translator i18n:: Features for the translator. +* String Extraction:: Extracting marked strings. +* Printf Ordering:: Rearranging 'printf' arguments. +* I18N Portability:: 'awk'-level portability + issues. +* I18N Example:: A simple i18n example. +* Gawk I18N:: 'gawk' is also + internationalized. +* I18N Summary:: Summary of I18N stuff. +* Debugging:: Introduction to 'gawk' + debugger. +* Debugging Concepts:: Debugging in General. +* Debugging Terms:: Additional Debugging Concepts. +* Awk Debugging:: Awk Debugging. +* Sample Debugging Session:: Sample debugging session. +* Debugger Invocation:: How to Start the Debugger. +* Finding The Bug:: Finding the Bug. +* List of Debugger Commands:: Main debugger commands. +* Breakpoint Control:: Control of Breakpoints. +* Debugger Execution Control:: Control of Execution. +* Viewing And Changing Data:: Viewing and Changing Data. +* Execution Stack:: Dealing with the Stack. +* Debugger Info:: Obtaining Information about the + Program and the Debugger State. +* Miscellaneous Debugger Commands:: Miscellaneous Commands. +* Readline Support:: Readline support. +* Limitations:: Limitations and future plans. +* Debugging Summary:: Debugging summary. +* Computer Arithmetic:: A quick intro to computer math. +* Math Definitions:: Defining terms used. +* MPFR features:: The MPFR features in 'gawk'. +* FP Math Caution:: Things to know. +* Inexactness of computations:: Floating point math is not exact. +* Inexact representation:: Numbers are not exactly represented. +* Comparing FP Values:: How to compare floating point values. +* Errors accumulate:: Errors get bigger as they go. +* Getting Accuracy:: Getting more accuracy takes some work. +* Try To Round:: Add digits and round. +* Setting precision:: How to set the precision. +* 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. +* Plugin License:: A note about licensing. +* Extension Mechanism Outline:: An outline of how it works. +* Extension API Description:: A full description of the API. +* Extension API Functions Introduction:: Introduction to the API functions. +* General Data Types:: The data types. +* Memory Allocation Functions:: Functions for allocating memory. +* Constructor Functions:: Functions for creating values. +* Registration Functions:: Functions to register things with + 'gawk'. +* Extension Functions:: Registering extension functions. +* Exit Callback Functions:: Registering an exit callback. +* Extension Version String:: Registering a version string. +* Input Parsers:: Registering an input parser. +* Output Wrappers:: Registering an output wrapper. +* Two-way processors:: Registering a two-way processor. +* Printing Messages:: Functions for printing messages. +* Updating ERRNO:: Functions for updating 'ERRNO'. +* Requesting Values:: How to get a value. +* Accessing Parameters:: Functions for accessing parameters. +* Symbol Table Access:: Functions for accessing global + variables. +* Symbol table by name:: Accessing variables by name. +* Symbol table by cookie:: Accessing variables by "cookie". +* Cached values:: Creating and using cached values. +* Array Manipulation:: Functions for working with arrays. +* Array Data Types:: Data types for working with arrays. +* 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 GMP/MPFR Versioning:: Version information about GMP and + MPFR. +* 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. +* Internal File Description:: What the new functions will do. +* Internal File Ops:: The code for internal file operations. +* Using Internal File Ops:: How to use an external extension. +* Extension Samples:: The sample extensions that ship with + 'gawk'. +* Extension Sample File Functions:: The file functions sample. +* Extension Sample Fnmatch:: An interface to 'fnmatch()'. +* Extension Sample Fork:: An interface to 'fork()' and + other process functions. +* Extension Sample Inplace:: Enabling in-place file editing. +* Extension Sample Ord:: Character to value to character + conversions. +* Extension Sample Readdir:: An interface to 'readdir()'. +* Extension Sample Revout:: Reversing output sample output + wrapper. +* Extension Sample Rev2way:: Reversing data sample two-way + processor. +* Extension Sample Read write array:: Serializing an array to a file. +* Extension Sample Readfile:: Reading an entire file into a string. +* Extension Sample Time:: An interface to 'gettimeofday()' + and 'sleep()'. +* Extension Sample API Tests:: Tests for the API. +* gawkextlib:: The 'gawkextlib' project. +* Extension summary:: Extension summary. +* Extension Exercises:: Exercises. +* V7/SVR3.1:: The major changes between V7 and + System V Release 3.1. +* SVR4:: Minor changes between System V + Releases 3.1 and 4. +* POSIX:: New features from the POSIX standard. +* BTL:: New features from Brian Kernighan's + version of 'awk'. +* POSIX/GNU:: The extensions in 'gawk' not + in POSIX 'awk'. +* Feature History:: The history of the features in + 'gawk'. +* Common Extensions:: Common Extensions Summary. +* Ranges and Locales:: How locales used to affect regexp + ranges. +* Contributors:: The major contributors to + 'gawk'. +* History summary:: History summary. +* Gawk Distribution:: What is in the 'gawk' + distribution. +* Getting:: How to get the distribution. +* Extracting:: How to extract the distribution. +* Distribution contents:: What is in the distribution. +* 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 Binary Installation:: Installing a prepared distribution. +* PC Compiling:: Compiling 'gawk' for + Windows32. +* PC Using:: Running 'gawk' on Windows32. +* Cygwin:: Building and running 'gawk' + for Cygwin. +* MSYS:: Using 'gawk' In The MSYS + Environment. +* VMS Installation:: Installing 'gawk' on VMS. +* VMS Compilation:: How to compile 'gawk' under + VMS. +* VMS Dynamic Extensions:: Compiling 'gawk' dynamic + extensions on VMS. +* VMS Installation Details:: How to install 'gawk' under + VMS. +* VMS Running:: How to run 'gawk' under VMS. +* VMS GNV:: The VMS GNV Project. +* VMS Old Gawk:: An old version comes with some VMS + systems. +* Bugs:: Reporting Problems and Bugs. +* Bug address:: Where to send reports to. +* Usenet:: Where not to send reports to. +* Maintainers:: Maintainers of non-*nix ports. +* Other Versions:: Other freely available 'awk' + implementations. +* Installation summary:: Summary of installation. +* Compatibility Mode:: How to disable certain 'gawk' + extensions. +* Additions:: Making Additions To 'gawk'. +* Accessing The Source:: Accessing the Git repository. +* Adding Code:: Adding code to the main body of + 'gawk'. +* New Ports:: Porting 'gawk' to a new + operating system. +* Derived Files:: Why derived files are kept in the Git + repository. +* Future Extensions:: New features that may be implemented + one day. +* Implementation Limitations:: Some limitations of the + implementation. +* Extension Design:: Design notes about the extension API. +* Old Extension Problems:: Problems with the old mechanism. +* Extension New Mechanism Goals:: Goals for the new mechanism. +* Extension Other Design Decisions:: Some other design decisions. +* Extension Future Growth:: Some room for future growth. +* Old Extension Mechanism:: Some compatibility for old extensions. +* Notes summary:: Summary of implementation notes. +* Basic High Level:: The high level view. +* Basic Data Typing:: A very quick intro to data types. + + To my parents, for their love, and for the wonderful example they set +for me. + + To my wife Miriam, for making me complete. Thank you for building +your life together with me. + + To our children Chana, Rivka, Nachum and Malka, for enrichening our +lives in innumerable ways. + + +File: gawk.info, Node: Foreword3, Next: Foreword4, Prev: Top, Up: Top + +Foreword to the Third Edition +***************************** + +Arnold Robbins and I are good friends. We were introduced in 1990 by +circumstances--and our favorite programming language, AWK. The +circumstances started a couple of years earlier. I was working at a new +job and noticed an unplugged Unix computer sitting in the corner. No +one knew how to use it, and neither did I. However, a couple of days +later, it was running, and I was 'root' and the one-and-only user. That +day, I began the transition from statistician to Unix programmer. + + On one of many trips to the library or bookstore in search of books +on Unix, I found the gray AWK book, a.k.a. Alfred V. Aho, Brian W. +Kernighan, and Peter J. Weinberger's 'The AWK Programming Language' +(Addison-Wesley, 1988). 'awk''s simple programming paradigm--find a +pattern in the input and then perform an action--often reduced complex +or tedious data manipulations to a few lines of code. I was excited to +try my hand at programming in AWK. + + Alas, the 'awk' on my computer was a limited version of the language +described in the gray book. I discovered that my computer had "old +'awk'" and the book described "new 'awk'." I learned that this was +typical; the old version refused to step aside or relinquish its name. +If a system had a new 'awk', it was invariably called 'nawk', and few +systems had it. The best way to get a new 'awk' was to 'ftp' the source +code for 'gawk' from 'prep.ai.mit.edu'. 'gawk' was a version of new +'awk' written by David Trueman and Arnold, and available under the GNU +General Public License. + + (Incidentally, it's no longer difficult to find a new 'awk'. 'gawk' +ships with GNU/Linux, and you can download binaries or source code for +almost any system; my wife uses 'gawk' on her VMS box.) + + My Unix system started out unplugged from the wall; it certainly was +not plugged into a network. So, oblivious to the existence of 'gawk' +and the Unix community in general, and desiring a new 'awk', I wrote my +own, called 'mawk'. Before I was finished, I knew about 'gawk', but it +was too late to stop, so I eventually posted to a 'comp.sources' +newsgroup. + + A few days after my posting, I got a friendly email from Arnold +introducing himself. He suggested we share design and algorithms and +attached a draft of the POSIX standard so that I could update 'mawk' to +support language extensions added after publication of 'The AWK +Programming Language'. + + Frankly, if our roles had been reversed, I would not have been so +open and we probably would have never met. I'm glad we did meet. He is +an AWK expert's AWK expert and a genuinely nice person. Arnold +contributes significant amounts of his expertise and time to the Free +Software Foundation. + + This book is the 'gawk' reference manual, but at its core it is a +book about AWK programming that will appeal to a wide audience. It is a +definitive reference to the AWK language as defined by the 1987 Bell +Laboratories release and codified in the 1992 POSIX Utilities standard. + + On the other hand, the novice AWK programmer can study a wealth of +practical programs that emphasize the power of AWK's basic idioms: +data-driven control flow, pattern matching with regular expressions, and +associative arrays. Those looking for something new can try out +'gawk''s interface to network protocols via special '/inet' files. + + The programs in this book make clear that an AWK program is typically +much smaller and faster to develop than a counterpart written in C. +Consequently, there is often a payoff to prototyping an algorithm or +design in AWK to get it running quickly and expose problems early. +Often, the interpreted performance is adequate and the AWK prototype +becomes the product. + + The new 'pgawk' (profiling 'gawk'), produces program execution +counts. I recently experimented with an algorithm that for n lines of +input, exhibited ~ C n^2 performance, while theory predicted ~ C n log n +behavior. A few minutes poring over the 'awkprof.out' profile +pinpointed the problem to a single line of code. 'pgawk' is a welcome +addition to my programmer's toolbox. + + Arnold has distilled over a decade of experience writing and using +AWK programs, and developing 'gawk', into this book. If you use AWK or +want to learn how, then read this book. + + Michael Brennan + Author of 'mawk' + March 2001 + + +File: gawk.info, Node: Foreword4, Next: Preface, Prev: Foreword3, Up: Top + +Foreword to the Fourth Edition +****************************** + +Some things don't change. Thirteen years ago I wrote: "If you use AWK +or want to learn how, then read this book." True then, and still true +today. + + Learning to use a programming language is about more than mastering +the syntax. One needs to acquire an understanding of how to use the +features of the language to solve practical programming problems. A +focus of this book is many examples that show how to use AWK. + + Some things do change. Our computers are much faster and have more +memory. Consequently, speed and storage inefficiencies of a high-level +language matter less. Prototyping in AWK and then rewriting in C for +performance reasons happens less, because more often the prototype is +fast enough. + + Of course, there are computing operations that are best done in C or +C++. With 'gawk' 4.1 and later, you do not have to choose between +writing your program in AWK or in C/C++. You can write most of your +program in AWK and the aspects that require C/C++ capabilities can be +written in C/C++, and then the pieces glued together when the 'gawk' +module loads the C/C++ module as a dynamic plug-in. *note Dynamic +Extensions::, has all the details, and, as expected, many examples to +help you learn the ins and outs. + + I enjoy programming in AWK and had fun (re)reading this book. I +think you will too. + + Michael Brennan + Author of 'mawk' + October 2014 + + +File: gawk.info, Node: Preface, Next: Getting Started, Prev: Foreword4, Up: Top + +Preface +******* + +Several kinds of tasks occur repeatedly when working with text files. +You might want to extract certain lines and discard the rest. Or you +may need to make changes wherever certain patterns appear, but leave the +rest of the file alone. Such jobs are often easy with 'awk'. The 'awk' +utility interprets a special-purpose programming language that makes it +easy to handle simple data-reformatting jobs. + + The GNU implementation of 'awk' is called 'gawk'; if you invoke it +with the proper options or environment variables, it is fully compatible +with the POSIX(1) specification of the 'awk' language and with the Unix +version of 'awk' maintained by Brian Kernighan. This means that all +properly written 'awk' programs should work with 'gawk'. So most of the +time, we don't distinguish between 'gawk' and other 'awk' +implementations. + + Using 'awk' you can: + + * Manage small, personal databases + + * Generate reports + + * Validate data + + * Produce indexes and perform other document-preparation tasks + + * Experiment with algorithms that you can adapt later to other + computer languages + + In addition, 'gawk' provides facilities that make it easy to: + + * Extract bits and pieces of data for processing + + * Sort data + + * Perform simple network communications + + * Profile and debug 'awk' programs + + * Extend the language with functions written in C or C++ + + This Info file teaches you about the 'awk' language and how you can +use it effectively. You should already be familiar with basic system +commands, such as 'cat' and 'ls',(2) as well as basic shell facilities, +such as input/output (I/O) redirection and pipes. + + Implementations of the 'awk' language are available for many +different computing environments. This Info file, while describing the +'awk' language in general, also describes the particular implementation +of 'awk' called 'gawk' (which stands for "GNU 'awk'"). 'gawk' runs on a +broad range of Unix systems, ranging from Intel-architecture PC-based +computers up through large-scale systems. 'gawk' has also been ported +to Mac OS X, Microsoft Windows (all versions), and OpenVMS.(3) + +* Menu: + +* History:: The history of 'gawk' and + 'awk'. +* Names:: What name to use to find 'awk'. +* This Manual:: Using this Info file. Includes sample + input files that you can use. +* Conventions:: Typographical Conventions. +* Manual History:: Brief history of the GNU project and this + Info file. +* How To Contribute:: Helping to save the world. +* Acknowledgments:: Acknowledgments. + + ---------- Footnotes ---------- + + (1) The 2008 POSIX standard is accessible online at +. + + (2) These utilities are available on POSIX-compliant systems, as well +as on traditional Unix-based systems. If you are using some other +operating system, you still need to be familiar with the ideas of I/O +redirection and pipes. + + (3) Some other, obsolete systems to which 'gawk' was once ported are +no longer supported and the code for those systems has been removed. + + +File: gawk.info, Node: History, Next: Names, Up: Preface + +History of 'awk' and 'gawk' +=========================== + + Recipe for a Programming Language + + 1 part 'egrep' 1 part 'snobol' + 2 parts 'ed' 3 parts C + + Blend all parts well using 'lex' and 'yacc'. Document minimally and +release. + + After eight years, add another part 'egrep' and two more parts C. +Document very well and release. + + The name 'awk' comes from the initials of its designers: Alfred V. +Aho, Peter J. Weinberger, and Brian W. Kernighan. The original version +of 'awk' was written in 1977 at AT&T Bell Laboratories. In 1985, a new +version made the programming language more powerful, introducing +user-defined functions, multiple input streams, and computed regular +expressions. This new version became widely available with Unix System +V Release 3.1 (1987). The version in System V Release 4 (1989) added +some new features and cleaned up the behavior in some of the "dark +corners" of the language. The specification for 'awk' in the POSIX +Command Language and Utilities standard further clarified the language. +Both the 'gawk' designers and the original 'awk' designers at Bell +Laboratories provided feedback for the POSIX specification. + + Paul Rubin wrote 'gawk' in 1986. Jay Fenlason completed it, with +advice from Richard Stallman. John Woods contributed parts of the code +as well. In 1988 and 1989, David Trueman, with help from me, thoroughly +reworked 'gawk' for compatibility with the newer 'awk'. Circa 1994, I +became the primary maintainer. Current development focuses on bug +fixes, performance improvements, standards compliance, and, +occasionally, new features. + + In May 1997, Ju"rgen Kahrs felt the need for network access from +'awk', and with a little help from me, set about adding features to do +this for 'gawk'. At that time, he also wrote the bulk of 'TCP/IP +Internetworking with 'gawk'' (a separate document, available as part of +the 'gawk' distribution). His code finally became part of the main +'gawk' distribution with 'gawk' version 3.1. + + John Haque rewrote the 'gawk' internals, in the process providing an +'awk'-level debugger. This version became available as 'gawk' version +4.0 in 2011. + + *Note Contributors:: for a full list of those who have made important +contributions to 'gawk'. + + +File: gawk.info, Node: Names, Next: This Manual, Prev: History, Up: Preface + +A Rose by Any Other Name +======================== + +The 'awk' language has evolved over the years. Full details are +provided in *note Language History::. The language described in this +Info file is often referred to as "new 'awk'." By analogy, the original +version of 'awk' is referred to as "old 'awk'." + + On most current systems, when you run the 'awk' utility you get some +version of new 'awk'.(1) If your system's standard 'awk' is the old +one, you will see something like this if you try the test program: + + $ awk 1 /dev/null + error-> awk: syntax error near line 1 + error-> awk: bailing out near line 1 + +In this case, you should find a version of new 'awk', or just install +'gawk'! + + Throughout this Info file, whenever we refer to a language feature +that should be available in any complete implementation of POSIX 'awk', +we simply use the term 'awk'. When referring to a feature that is +specific to the GNU implementation, we use the term 'gawk'. + + ---------- Footnotes ---------- + + (1) Only Solaris systems still use an old 'awk' for the default 'awk' +utility. A more modern 'awk' lives in '/usr/xpg6/bin' on these systems. + + +File: gawk.info, Node: This Manual, Next: Conventions, Prev: Names, Up: Preface + +Using This Book +=============== + +The term 'awk' refers to a particular program as well as to the language +you use to tell this program what to do. When we need to be careful, we +call the language "the 'awk' language," and the program "the 'awk' +utility." This Info file explains both how to write programs in the +'awk' language and how to run the 'awk' utility. The term "'awk' +program" refers to a program written by you in the 'awk' programming +language. + + Primarily, this Info file explains the features of 'awk' as defined +in the POSIX standard. It does so in the context of the 'gawk' +implementation. While doing so, it also attempts to describe important +differences between 'gawk' and other 'awk' implementations.(1) Finally, +it notes any 'gawk' features that are not in the POSIX standard for +'awk'. + + There are sidebars scattered throughout the Info file. They add a +more complete explanation of points that are relevant, but not likely to +be of interest on first reading. All appear in the index, under the +heading "sidebar." + + Most of the time, the examples use complete 'awk' programs. Some of +the more advanced minor nodes show only the part of the 'awk' program +that illustrates the concept being described. + + Although this Info file is aimed principally at people who have not +been exposed to 'awk', there is a lot of information here that even the +'awk' expert should find useful. In particular, the description of +POSIX 'awk' and the example programs in *note Library Functions::, and +in *note Sample Programs::, should be of interest. + + This Info file is split into several parts, as follows: + + * Part I describes the 'awk' language and the 'gawk' program in + detail. It starts with the basics, and continues through all of + the features of 'awk'. It contains the following chapters: + + - *note Getting Started::, provides the essentials you need to + know to begin using 'awk'. + + - *note Invoking Gawk::, describes how to run 'gawk', the + meaning of its command-line options, and how it finds 'awk' + program source files. + + - *note Regexp::, introduces regular expressions in general, and + in particular the flavors supported by POSIX 'awk' and 'gawk'. + + - *note Reading Files::, describes how 'awk' reads your data. + It introduces the concepts of records and fields, as well as + the 'getline' command. I/O redirection is first described + here. Network I/O is also briefly introduced here. + + - *note Printing::, describes how 'awk' programs can produce + output with 'print' and 'printf'. + + - *note Expressions::, describes expressions, which are the + basic building blocks for getting most things done in a + program. + + - *note Patterns and Actions::, describes how to write patterns + for matching records, actions for doing something when a + record is matched, and the predefined variables 'awk' and + 'gawk' use. + + - *note Arrays::, covers 'awk''s one-and-only data structure: + the associative array. Deleting array elements and whole + arrays is described, as well as sorting arrays in 'gawk'. The + major node also describes how 'gawk' provides arrays of + arrays. + + - *note Functions::, describes the built-in functions 'awk' and + 'gawk' provide, as well as how to define your own functions. + It also discusses how 'gawk' lets you call functions + indirectly. + + * Part II shows how to use 'awk' and 'gawk' for problem solving. + There is lots of code here for you to read and learn from. This + part contains the following chapters: + + - *note Library Functions::, provides a number of functions + meant to be used from main 'awk' programs. + + - *note Sample Programs::, provides many sample 'awk' programs. + + Reading these two chapters allows you to see 'awk' solving real + problems. + + * Part III focuses on features specific to 'gawk'. It contains the + following chapters: + + - *note Advanced Features::, describes a number of advanced + features. Of particular note are the abilities to control the + order of array traversal, have two-way communications with + another process, perform TCP/IP networking, and profile your + 'awk' programs. + + - *note Internationalization::, describes special features for + translating program messages into different languages at + runtime. + + - *note Debugger::, describes the 'gawk' debugger. + + - *note Arbitrary Precision Arithmetic::, describes advanced + arithmetic facilities. + + - *note Dynamic Extensions::, describes how to add new variables + and functions to 'gawk' by writing extensions in C or C++. + + * Part IV provides the appendices, the Glossary, and two licenses + that cover the 'gawk' source code and this Info file, respectively. + It contains the following appendices: + + - *note Language History::, describes how the 'awk' language has + evolved since its first release to the present. It also + describes how 'gawk' has acquired features over time. + + - *note Installation::, describes how to get 'gawk', how to + compile it on POSIX-compatible systems, and how to compile and + use it on different non-POSIX systems. It also describes how + to report bugs in 'gawk' and where to get other freely + available 'awk' implementations. + + - *note Notes::, describes how to disable 'gawk''s extensions, + as well as how to contribute new code to 'gawk', and some + possible future directions for 'gawk' development. + + - *note Basic Concepts::, provides some very cursory background + material for those who are completely unfamiliar with computer + programming. + + The *note Glossary::, defines most, if not all, of the + significant terms used throughout the Info file. If you find + terms that you aren't familiar with, try looking them up here. + + - *note Copying::, and *note GNU Free Documentation License::, + present the licenses that cover the 'gawk' source code and + this Info file, respectively. + + ---------- Footnotes ---------- + + (1) All such differences appear in the index under the entry +"differences in 'awk' and 'gawk'." + + +File: gawk.info, Node: Conventions, Next: Manual History, Prev: This Manual, Up: Preface + +Typographical Conventions +========================= + +This Info file is written in Texinfo +(https://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. + + For the sake of brevity, throughout this Info file, we refer to Brian +Kernighan's version of 'awk' as "BWK 'awk'." (*Note Other Versions:: +for information on his and other versions.) + +Dark Corners +------------ + + Dark corners are basically fractal--no matter how much you + illuminate, there's always a smaller but darker one. + -- _Brian Kernighan_ + + Until the POSIX standard (and 'GAWK: Effective AWK Programming'), +many features of 'awk' were either poorly documented or not documented +at all. Descriptions of such features (often called "dark corners") are +noted in this Info file with "(d.c.)." They also appear in the index +under the heading "dark corner." + + But, as noted by the opening quote, any coverage of dark corners is +by definition incomplete. + + Extensions to the standard 'awk' language that are supported by more +than one 'awk' implementation are marked "(c.e.)," and listed in the +index under "common extensions" and "extensions, common." + + +File: gawk.info, Node: Manual History, Next: How To Contribute, Prev: Conventions, Up: Preface + +The GNU Project and This Book +============================= + +The Free Software Foundation (FSF) is a nonprofit organization dedicated +to the production and distribution of freely distributable software. It +was founded by Richard M. Stallman, the author of the original Emacs +editor. GNU Emacs is the most widely used version of Emacs today. + + The GNU(1) Project is an ongoing effort on the part of the Free +Software Foundation to create a complete, freely distributable, +POSIX-compliant computing environment. The FSF uses the GNU General +Public License (GPL) to ensure that its software's source code is always +available to the end user. A copy of the GPL is included for your +reference (*note Copying::). The GPL applies to the C language source +code for 'gawk'. To find out more about the FSF and the GNU Project +online, see the GNU Project's home page (https://www.gnu.org). This +Info file may also be read from GNU's website +(https://www.gnu.org/software/gawk/manual/). + + A shell, an editor (Emacs), highly portable optimizing C, C++, and +Objective-C compilers, a symbolic debugger and dozens of large and small +utilities (such as 'gawk'), have all been completed and are freely +available. The GNU operating system kernel (the HURD), has been +released but remains in an early stage of development. + + Until the GNU operating system is more fully developed, you should +consider using GNU/Linux, a freely distributable, Unix-like operating +system for Intel, Power Architecture, Sun SPARC, IBM S/390, and other +systems.(2) Many GNU/Linux distributions are available for download +from the Internet. + + The Info file itself has gone through multiple previous editions. +Paul Rubin wrote the very first draft of 'The GAWK Manual'; it was +around 40 pages long. Diane Close and Richard Stallman improved it, +yielding a version that was around 90 pages and barely described the +original, "old" version of 'awk'. + + I started working with that version in the fall of 1988. As work on +it progressed, the FSF published several preliminary versions (numbered +0.X). In 1996, edition 1.0 was released with 'gawk' 3.0.0. The FSF +published the first two editions under the title 'The GNU Awk User's +Guide'. + + This edition maintains the basic structure of the previous editions. +For FSF edition 4.0, the content was thoroughly reviewed and updated. +All references to 'gawk' versions prior to 4.0 were removed. Of +significant note for that edition was the addition of *note Debugger::. + + For FSF edition 4.2, the content has been reorganized into parts, and +the major new additions are *note Arbitrary Precision Arithmetic::, and +*note Dynamic Extensions::. + + This Info file will undoubtedly continue to evolve. If you find an +error in the Info file, please report it! *Note Bugs:: for information +on submitting problem reports electronically. + + ---------- Footnotes ---------- + + (1) GNU stands for "GNU's Not Unix." + + (2) The terminology "GNU/Linux" is explained in the *note Glossary::. + + +File: gawk.info, Node: How To Contribute, Next: Acknowledgments, Prev: Manual History, Up: Preface + +How to Contribute +================= + +As the maintainer of GNU 'awk', I once thought that I would be able to +manage a collection of publicly available 'awk' programs and I even +solicited contributions. Making things available on the Internet helps +keep the 'gawk' distribution down to manageable size. + + The initial collection of material, such as it is, is still available +at . + + In the hopes of doing something more broad, I acquired the +'awklang.org' domain. Late in 2017, a volunteer took on the task of +managing it. + + If you have written an interesting 'awk' program, that you would like +to share with the rest of the world, please see +and use the "Contact" link. + + If you have written a 'gawk' extension, please see *note +gawkextlib::. + + +File: gawk.info, Node: Acknowledgments, Prev: How To Contribute, Up: Preface + +Acknowledgments +=============== + +The initial draft of 'The GAWK Manual' had the following +acknowledgments: + + Many people need to be thanked for their assistance in producing + this manual. Jay Fenlason contributed many ideas and sample + programs. Richard Mlynarik and Robert Chassell gave helpful + comments on drafts of this manual. The paper 'A Supplemental + Document for AWK' by John W. Pierce of the Chemistry Department at + UC San Diego, pinpointed several issues relevant both to 'awk' + implementation and to this manual, that would otherwise have + escaped us. + + I would like to acknowledge Richard M. Stallman, for his vision of a +better world and for his courage in founding the FSF and starting the +GNU Project. + + Earlier editions of this Info file had the following +acknowledgements: + + The following people (in alphabetical order) provided helpful + comments on various versions of this book: 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, and Chuck Toporek. + + Robert J. Chassell provided much valuable advice on the use of + Texinfo. He also deserves special thanks for convincing me _not_ + to title this Info file 'How to Gawk Politely'. Karl Berry helped + significantly with the TeX part of Texinfo. + + I would like to thank Marshall and Elaine Hartholz of Seattle and + Dr. Bert and Rita Schreiber of Detroit for large amounts of quiet + vacation time in their homes, which allowed me to make significant + progress on this Info file and on 'gawk' itself. + + Phil Hughes of SSC contributed in a very important way by loaning + me his laptop GNU/Linux system, not once, but twice, which allowed + me to do a lot of work while away from home. + + David Trueman deserves special credit; he has done a yeoman job of + evolving 'gawk' so that it performs well and without bugs. + Although he is no longer involved with 'gawk', working with him on + this project was a significant pleasure. + + The intrepid members of the GNITS mailing list, and most notably + Ulrich Drepper, provided invaluable help and feedback for the + design of the internationalization features. + + Chuck Toporek, Mary Sheehan, and Claire Cloutier of O'Reilly & + Associates contributed significant editorial help for this Info + file for the 3.1 release of 'gawk'. + + Dr. Nelson Beebe, Andreas Buening, Dr. Manuel Collado, Antonio +Colombo, Stephen Davies, Scott Deifik, Akim Demaille, Daniel Richard G., +Juan Manuel Guerrero, Darrel Hankerson, Michal Jaegermann, Ju"rgen +Kahrs, Stepan Kasal, John Malmberg, Dave Pitts, Chet Ramey, Pat Rankin, +Andrew Schorr, Corinna Vinschen, and Eli Zaretskii (in alphabetical +order) make up the current 'gawk' "crack portability team." Without +their hard work and help, 'gawk' would not be nearly the robust, +portable program it is today. It has been and continues to be a +pleasure working with this team of fine people. + + Notable code and documentation contributions were made by a number of +people. *Note Contributors:: for the full list. + + Thanks to Michael Brennan for the Forewords. + + Thanks to Patrice Dumas for the new 'makeinfo' program. Thanks to +Karl Berry, who continues to work to keep the Texinfo markup language +sane. + + Robert P.J. Day, Michael Brennan, and Brian Kernighan kindly acted as +reviewers for the 2015 edition of this Info file. Their feedback helped +improve the final work. + + I would also like to thank Brian Kernighan for his invaluable +assistance during the testing and debugging of 'gawk', and for his +ongoing help and advice in clarifying numerous points about the +language. We could not have done nearly as good a job on either 'gawk' +or its documentation without his help. + + Brian is in a class by himself as a programmer and technical author. +I have to thank him (yet again) for his ongoing friendship and for being +a role model to me for close to 30 years! Having him as a reviewer is +an exciting privilege. It has also been extremely humbling... + + I must thank my wonderful wife, Miriam, for her patience through the +many versions of this project, for her proofreading, and for sharing me +with the computer. I would like to thank my parents for their love, and +for the grace with which they raised and educated me. Finally, I also +must acknowledge my gratitude to G-d, for the many opportunities He has +sent my way, as well as for the gifts He has given me with which to take +advantage of those opportunities. + + +Arnold Robbins +Nof Ayalon +Israel +February 2015 + + +File: gawk.info, Node: Getting Started, Next: Invoking Gawk, Prev: Preface, Up: Top + +1 Getting Started with 'awk' +**************************** + +The basic function of 'awk' is to search files for lines (or other units +of text) that contain certain patterns. When a line matches one of the +patterns, 'awk' performs specified actions on that line. 'awk' +continues to process input lines in this way until it reaches the end of +the input files. + + Programs in 'awk' are different from programs in most other +languages, because 'awk' programs are "data driven" (i.e., you describe +the data you want to work with and then what to do when you find it). +Most other languages are "procedural"; you have to describe, in great +detail, every step the program should take. When working with +procedural languages, it is usually much harder to clearly describe the +data your program will process. For this reason, 'awk' programs are +often refreshingly easy to read and write. + + When you run 'awk', you specify an 'awk' "program" that tells 'awk' +what to do. The program consists of a series of "rules" (it may also +contain "function definitions", an advanced feature that we will ignore +for now; *note User-defined::). Each rule specifies one pattern to +search for and one action to perform upon finding the pattern. + + Syntactically, a rule consists of a "pattern" followed by an +"action". The action is enclosed in braces to separate it from the +pattern. Newlines usually separate rules. Therefore, an 'awk' program +looks like this: + + PATTERN { ACTION } + PATTERN { ACTION } + ... + +* Menu: + +* Running gawk:: How to run 'gawk' programs; includes + command-line syntax. +* Sample Data Files:: Sample data files for use in the 'awk' + programs illustrated in this Info file. +* Very Simple:: A very simple example. +* Two Rules:: A less simple one-line example using two + rules. +* More Complex:: A more complex example. +* Statements/Lines:: Subdividing or combining statements into + lines. +* Other Features:: Other Features of 'awk'. +* When:: When to use 'gawk' and when to use + other things. +* Intro Summary:: Summary of the introduction. + + +File: gawk.info, Node: Running gawk, Next: Sample Data Files, Up: Getting Started + +1.1 How to Run 'awk' Programs +============================= + +There are several ways to run an 'awk' program. If the program is +short, it is easiest to include it in the command that runs 'awk', like +this: + + awk 'PROGRAM' INPUT-FILE1 INPUT-FILE2 ... + + When the program is long, it is usually more convenient to put it in +a file and run it with a command like this: + + awk -f PROGRAM-FILE INPUT-FILE1 INPUT-FILE2 ... + + This minor node discusses both mechanisms, along with several +variations of each. + +* Menu: + +* One-shot:: Running a short throwaway 'awk' + program. +* Read Terminal:: Using no input files (input from the keyboard + instead). +* Long:: Putting permanent 'awk' programs in + files. +* Executable Scripts:: Making self-contained 'awk' programs. +* Comments:: Adding documentation to 'gawk' + programs. +* Quoting:: More discussion of shell quoting issues. + + +File: gawk.info, Node: One-shot, Next: Read Terminal, Up: Running gawk + +1.1.1 One-Shot Throwaway 'awk' Programs +--------------------------------------- + +Once you are familiar with 'awk', you will often type in simple programs +the moment you want to use them. Then you can write the program as the +first argument of the 'awk' command, like this: + + awk 'PROGRAM' INPUT-FILE1 INPUT-FILE2 ... + +where PROGRAM consists of a series of patterns and actions, as described +earlier. + + This command format instructs the "shell", or command interpreter, to +start 'awk' and use the PROGRAM to process records in the input file(s). +There are single quotes around PROGRAM so the shell won't interpret any +'awk' characters as special shell characters. The quotes also cause the +shell to treat all of PROGRAM as a single argument for 'awk', and allow +PROGRAM to be more than one line long. + + This format is also useful for running short or medium-sized 'awk' +programs from shell scripts, because it avoids the need for a separate +file for the 'awk' program. A self-contained shell script is more +reliable because there are no other files to misplace. + + Later in this chapter, in *note Very Simple::, we'll see examples of +several short, self-contained programs. + + +File: gawk.info, Node: Read Terminal, Next: Long, Prev: One-shot, Up: Running gawk + +1.1.2 Running 'awk' Without Input Files +--------------------------------------- + +You can also run 'awk' without any input files. If you type the +following command line: + + awk 'PROGRAM' + +'awk' applies the PROGRAM to the "standard input", which usually means +whatever you type on the keyboard. This continues until you indicate +end-of-file by typing 'Ctrl-d'. (On non-POSIX operating systems, the +end-of-file character may be different.) + + As an example, the following program prints a friendly piece of +advice (from Douglas Adams's 'The Hitchhiker's Guide to the Galaxy'), to +keep you from worrying about the complexities of computer programming: + + $ awk 'BEGIN { print "Don\47t Panic!" }' + -| Don't Panic! + + 'awk' executes statements associated with 'BEGIN' before reading any +input. If there are no other statements in your program, as is the case +here, 'awk' just stops, instead of trying to read input it doesn't know +how to process. The '\47' is a magic way (explained later) of getting a +single quote into the program, without having to engage in ugly shell +quoting tricks. + + NOTE: If you use Bash as your shell, you should execute the command + 'set +H' before running this program interactively, to disable the + C shell-style command history, which treats '!' as a special + character. We recommend putting this command into your personal + startup file. + + This next simple 'awk' program emulates the 'cat' utility; it copies +whatever you type on the keyboard to its standard output (why this works +is explained shortly): + + $ awk '{ print }' + Now is the time for all good men + -| Now is the time for all good men + to come to the aid of their country. + -| to come to the aid of their country. + Four score and seven years ago, ... + -| Four score and seven years ago, ... + What, me worry? + -| What, me worry? + Ctrl-d + + +File: gawk.info, Node: Long, Next: Executable Scripts, Prev: Read Terminal, Up: Running gawk + +1.1.3 Running Long Programs +--------------------------- + +Sometimes 'awk' programs are very long. In these cases, it is more +convenient to put the program into a separate file. In order to tell +'awk' to use that file for its program, you type: + + awk -f SOURCE-FILE INPUT-FILE1 INPUT-FILE2 ... + + The '-f' instructs the 'awk' utility to get the 'awk' program from +the file SOURCE-FILE (*note Options::). Any file name can be used for +SOURCE-FILE. For example, you could put the program: + + BEGIN { print "Don't Panic!" } + +into the file 'advice'. Then this command: + + awk -f advice + +does the same thing as this one: + + awk 'BEGIN { print "Don\47t Panic!" }' + +This was explained earlier (*note Read Terminal::). Note that you don't +usually need single quotes around the file name that you specify with +'-f', because most file names don't contain any of the shell's special +characters. Notice that in 'advice', the 'awk' program did not have +single quotes around it. The quotes are only needed for programs that +are provided on the 'awk' command line. (Also, placing the program in a +file allows us to use a literal single quote in the program text, +instead of the magic '\47'.) + + If you want to clearly identify an 'awk' program file as such, you +can add the extension '.awk' to the file name. This doesn't affect the +execution of the 'awk' program but it does make "housekeeping" easier. + + +File: gawk.info, Node: Executable Scripts, Next: Comments, Prev: Long, Up: Running gawk + +1.1.4 Executable 'awk' Programs +------------------------------- + +Once you have learned 'awk', you may want to write self-contained 'awk' +scripts, using the '#!' script mechanism. You can do this on many +systems.(1) For example, you could update the file 'advice' to look +like this: + + #! /bin/awk -f + + BEGIN { print "Don't Panic!" } + +After making this file executable (with the 'chmod' utility), simply +type 'advice' at the shell and the system arranges to run 'awk' as if +you had typed 'awk -f advice': + + $ chmod +x advice + $ advice + -| Don't Panic! + +(We assume you have the current directory in your shell's search path +variable [typically '$PATH']. If not, you may need to type './advice' +at the shell.) + + Self-contained 'awk' scripts are useful when you want to write a +program that users can invoke without their having to know that the +program is written in 'awk'. + + Understanding '#!' + + 'awk' is an "interpreted" language. This means that the 'awk' +utility reads your program and then processes your data according to the +instructions in your program. (This is different from a "compiled" +language such as C, where your program is first compiled into machine +code that is executed directly by your system's processor.) The 'awk' +utility is thus termed an "interpreter". Many modern languages are +interpreted. + + The line beginning with '#!' lists the full file name of an +interpreter to run and a single optional initial command-line argument +to pass to that interpreter. The operating system then runs the +interpreter with the given argument and the full argument list of the +executed program. The first argument in the list is the full file name +of the 'awk' program. The rest of the argument list contains either +options to 'awk', or data files, or both. (Note that on many systems +'awk' may be found in '/usr/bin' instead of in '/bin'.) + + Some systems limit the length of the interpreter name to 32 +characters. Often, this can be dealt with by using a symbolic link. + + You should not put more than one argument on the '#!' line after the +path to 'awk'. It does not work. The operating system treats the rest +of the line as a single argument and passes it to 'awk'. Doing this +leads to confusing behavior--most likely a usage diagnostic of some sort +from 'awk'. + + Finally, the value of 'ARGV[0]' (*note Built-in Variables::) varies +depending upon your operating system. Some systems put 'awk' there, +some put the full pathname of 'awk' (such as '/bin/awk'), and some put +the name of your script ('advice'). (d.c.) Don't rely on the value of +'ARGV[0]' to provide your script name. + + ---------- Footnotes ---------- + + (1) The '#!' mechanism works on GNU/Linux systems, BSD-based systems, +and commercial Unix systems. + + +File: gawk.info, Node: Comments, Next: Quoting, Prev: Executable Scripts, Up: Running gawk + +1.1.5 Comments in 'awk' Programs +-------------------------------- + +A "comment" is some text that is included in a program for the sake of +human readers; it is not really an executable part of the program. +Comments can explain what the program does and how it works. Nearly all +programming languages have provisions for comments, as programs are +typically hard to understand without them. + + In the 'awk' language, a comment starts with the number sign +character ('#') and continues to the end of the line. The '#' does not +have to be the first character on the line. The 'awk' language ignores +the rest of a line following a number sign. For example, we could have +put the following into 'advice': + + # This program prints a nice, friendly message. It helps + # keep novice users from being afraid of the computer. + BEGIN { print "Don't Panic!" } + + You can put comment lines into keyboard-composed throwaway 'awk' +programs, but this usually isn't very useful; the purpose of a comment +is to help you or another person understand the program when reading it +at a later time. + + CAUTION: As mentioned in *note One-shot::, you can enclose short to + medium-sized programs in single quotes, in order to keep your shell + scripts self-contained. When doing so, _don't_ put an apostrophe + (i.e., a single quote) into a comment (or anywhere else in your + program). The shell interprets the quote as the closing quote for + the entire program. As a result, usually the shell prints a + message about mismatched quotes, and if 'awk' actually runs, it + will probably print strange messages about syntax errors. For + example, look at the following: + + $ awk 'BEGIN { print "hello" } # let's be cute' + > + + The shell sees that the first two quotes match, and that a new + quoted object begins at the end of the command line. It therefore + prompts with the secondary prompt, waiting for more input. With + Unix 'awk', closing the quoted string produces this result: + + $ awk '{ print "hello" } # let's be cute' + > ' + error-> awk: can't open file be + error-> source line number 1 + + Putting a backslash before the single quote in 'let's' wouldn't + help, because backslashes are not special inside single quotes. + The next node describes the shell's quoting rules. + + +File: gawk.info, Node: Quoting, Prev: Comments, Up: Running gawk + +1.1.6 Shell Quoting Issues +-------------------------- + +* Menu: + +* DOS Quoting:: Quoting in Windows Batch Files. + +For short to medium-length 'awk' programs, it is most convenient to +enter the program on the 'awk' command line. This is best done by +enclosing the entire program in single quotes. This is true whether you +are entering the program interactively at the shell prompt, or writing +it as part of a larger shell script: + + awk 'PROGRAM TEXT' INPUT-FILE1 INPUT-FILE2 ... + + Once you are working with the shell, it is helpful to have a basic +knowledge of shell quoting rules. The following rules apply only to +POSIX-compliant, Bourne-style shells (such as Bash, the GNU Bourne-Again +Shell). If you use the C shell, you're on your own. + + Before diving into the rules, we introduce a concept that appears +throughout this Info file, which is that of the "null", or empty, +string. + + The null string is character data that has no value. In other words, +it is empty. It is written in 'awk' programs like this: '""'. In the +shell, it can be written using single or double quotes: '""' or ''''. +Although the null string has no characters in it, it does exist. For +example, consider this command: + + $ echo "" + +Here, the 'echo' utility receives a single argument, even though that +argument has no characters in it. In the rest of this Info file, we use +the terms "null string" and "empty string" interchangeably. Now, on to +the quoting rules: + + * Quoted items can be concatenated with nonquoted items as well as + with other quoted items. The shell turns everything into one + argument for the command. + + * Preceding any single character with a backslash ('\') quotes that + character. The shell removes the backslash and passes the quoted + character on to the command. + + * Single quotes protect everything between the opening and closing + quotes. The shell does no interpretation of the quoted text, + passing it on verbatim to the command. It is _impossible_ to embed + a single quote inside single-quoted text. Refer back to *note + Comments:: for an example of what happens if you try. + + * Double quotes protect most things between the opening and closing + quotes. The shell does at least variable and command substitution + on the quoted text. Different shells may do additional kinds of + processing on double-quoted text. + + Because certain characters within double-quoted text are processed + by the shell, they must be "escaped" within the text. Of note are + the characters '$', '`', '\', and '"', all of which must be + preceded by a backslash within double-quoted text if they are to be + passed on literally to the program. (The leading backslash is + stripped first.) Thus, the example seen in *note Read Terminal::: + + awk 'BEGIN { print "Don\47t Panic!" }' + + could instead be written this way: + + $ awk "BEGIN { print \"Don't Panic!\" }" + -| Don't Panic! + + Note that the single quote is not special within double quotes. + + * Null strings are removed when they occur as part of a non-null + command-line argument, while explicit null objects are kept. For + example, to specify that the field separator 'FS' should be set to + the null string, use: + + awk -F "" 'PROGRAM' FILES # correct + + Don't use this: + + awk -F"" 'PROGRAM' FILES # wrong! + + In the second case, 'awk' attempts to use the text of the program + as the value of 'FS', and the first file name as the text of the + program! This results in syntax errors at best, and confusing + behavior at worst. + + Mixing single and double quotes is difficult. You have to resort to +shell quoting tricks, like this: + + $ awk 'BEGIN { print "Here is a single quote <'"'"'>" }' + -| Here is a single quote <'> + +This program consists of three concatenated quoted strings. The first +and the third are single-quoted, and the second is double-quoted. + + This can be "simplified" to: + + $ awk 'BEGIN { print "Here is a single quote <'\''>" }' + -| Here is a single quote <'> + +Judge for yourself which of these two is the more readable. + + Another option is to use double quotes, escaping the embedded, +'awk'-level double quotes: + + $ awk "BEGIN { print \"Here is a single quote <'>\" }" + -| Here is a single quote <'> + +This option is also painful, because double quotes, backslashes, and +dollar signs are very common in more advanced 'awk' programs. + + A third option is to use the octal escape sequence equivalents (*note +Escape Sequences::) for the single- and double-quote characters, like +so: + + $ awk 'BEGIN { print "Here is a single quote <\47>" }' + -| Here is a single quote <'> + $ awk 'BEGIN { print "Here is a double quote <\42>" }' + -| Here is a double quote <"> + +This works nicely, but you should comment clearly what the escapes mean. + + A fourth option is to use command-line variable assignment, like +this: + + $ awk -v sq="'" 'BEGIN { print "Here is a single quote <" sq ">" }' + -| Here is a single quote <'> + + (Here, the two string constants and the value of 'sq' are +concatenated into a single string that is printed by 'print'.) + + If you really need both single and double quotes in your 'awk' +program, it is probably best to move it into a separate file, where the +shell won't be part of the picture and you can say what you mean. + + +File: gawk.info, Node: DOS Quoting, Up: Quoting + +1.1.6.1 Quoting in MS-Windows Batch Files +......................................... + +Although this Info file generally only worries about POSIX systems and +the POSIX shell, the following issue arises often enough for many users +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 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 original 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 + +1.2 Data files for the Examples +=============================== + +Many of the examples in this Info file take their input from two sample +data files. The first, 'mail-list', represents a list of peoples' names +together with their email addresses and information about those people. +The second data file, called 'inventory-shipped', contains information +about monthly shipments. In both files, each line is considered to be +one "record". + + In 'mail-list', each record contains the name of a person, his/her +phone number, his/her email address, and a code for his/her relationship +with the author of the list. The columns are aligned using spaces. An +'A' in the last column means that the person is an acquaintance. An 'F' +in the last column means that the person is a friend. An 'R' means that +the person is a relative: + + Amelia 555-5553 amelia.zodiacusque@gmail.com F + Anthony 555-3412 anthony.asserturo@hotmail.com A + 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 + + The data file 'inventory-shipped' represents information about +shipments during the year. Each record contains the month, the number +of green crates shipped, the number of red boxes shipped, the number of +orange bags shipped, and the number of blue packages shipped, +respectively. There are 16 entries, covering the 12 months of last year +and the first four months of the current year. An empty line separates +the data for the two years: + + 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 + + The sample files are included in the 'gawk' distribution, in the +directory 'awklib/eg/data'. + + +File: gawk.info, Node: Very Simple, Next: Two Rules, Prev: Sample Data Files, Up: Getting Started + +1.3 Some Simple Examples +======================== + +The following command runs a simple 'awk' program that searches the +input file 'mail-list' for the character string 'li' (a grouping of +characters is usually called a "string"; the term "string" is based on +similar usage in English, such as "a string of pearls" or "a string of +cars in a train"): + + awk '/li/ { print $0 }' mail-list + +When lines containing 'li' are found, they are printed because +'print $0' means print the current line. (Just 'print' by itself means +the same thing, so we could have written that instead.) + + You will notice that slashes ('/') surround the string 'li' in the +'awk' program. The slashes indicate that 'li' is the pattern to search +for. This type of pattern is called a "regular expression", which is +covered in more detail later (*note Regexp::). The pattern is allowed +to match parts of words. There are single quotes around the 'awk' +program so that the shell won't interpret any of it as special shell +characters. + + Here is what this program prints: + + $ awk '/li/ { print $0 }' mail-list + -| Amelia 555-5553 amelia.zodiacusque@gmail.com F + -| Broderick 555-0542 broderick.aliquotiens@yahoo.com R + -| Julie 555-6699 julie.perscrutabor@skeeve.com F + -| Samuel 555-3430 samuel.lanceolis@shu.edu A + + In an 'awk' rule, either the pattern or the action can be omitted, +but not both. If the pattern is omitted, then the action is performed +for _every_ input line. If the action is omitted, the default action is +to print all lines that match the pattern. + + Thus, we could leave out the action (the 'print' statement and the +braces) in the previous example and the result would be the same: 'awk' +prints all lines matching the pattern 'li'. By comparison, omitting the +'print' statement but retaining the braces makes an empty action that +does nothing (i.e., no lines are printed). + + Many practical 'awk' programs are just a line or two long. Following +is a collection of useful, short programs to get you started. Some of +these programs contain constructs that haven't been covered yet. (The +description of the program will give you a good idea of what is going +on, but you'll need to read the rest of the Info file to become an 'awk' +expert!) Most of the examples use a data file named 'data'. This is +just a placeholder; if you use these programs yourself, substitute your +own file names for 'data'. For future reference, note that there is +often more than one way to do things in 'awk'. At some point, you may +want to look back at these examples and see if you can come up with +different ways to do the same things shown here: + + * Print every line that is longer than 80 characters: + + awk 'length($0) > 80' data + + The sole rule has a relational expression as its pattern and has no + action--so it uses the default action, printing the record. + + * Print the length of the longest input line: + + awk '{ if (length($0) > max) max = length($0) } + END { print max }' data + + The code associated with 'END' executes after all input has been + read; it's the other side of the coin to 'BEGIN'. + + * Print the length of the longest line in 'data': + + expand data | awk '{ if (x < length($0)) x = length($0) } + END { print "maximum line length is " x }' + + This example differs slightly from the previous one: the input is + processed by the 'expand' utility to change TABs into spaces, so + the widths compared are actually the right-margin columns, as + opposed to the number of input characters on each line. + + * Print every line that has at least one field: + + awk 'NF > 0' data + + This is an easy way to delete blank lines from a file (or rather, + to create a new file similar to the old file but from which the + blank lines have been removed). + + * Print seven random numbers from 0 to 100, inclusive: + + awk 'BEGIN { for (i = 1; i <= 7; i++) + print int(101 * rand()) }' + + * Print the total number of bytes used by FILES: + + ls -l FILES | awk '{ x += $5 } + END { print "total bytes: " x }' + + * Print the total number of kilobytes used by FILES: + + ls -l FILES | awk '{ x += $5 } + END { print "total K-bytes:", x / 1024 }' + + * Print a sorted list of the login names of all users: + + awk -F: '{ print $1 }' /etc/passwd | sort + + * Count the lines in a file: + + awk 'END { print NR }' data + + * Print the even-numbered lines in the data file: + + awk 'NR % 2 == 0' data + + If you used the expression 'NR % 2 == 1' instead, the program would + print the odd-numbered lines. + + +File: gawk.info, Node: Two Rules, Next: More Complex, Prev: Very Simple, Up: Getting Started + +1.4 An Example with Two Rules +============================= + +The 'awk' utility reads the input files one line at a time. For each +line, 'awk' tries the patterns of each rule. If several patterns match, +then several actions execute in the order in which they appear in the +'awk' program. If no patterns match, then no actions run. + + After processing all the rules that match the line (and perhaps there +are none), 'awk' reads the next line. (However, *note Next Statement:: +and also *note Nextfile Statement::.) This continues until the program +reaches the end of the file. For example, the following 'awk' program +contains two rules: + + /12/ { print $0 } + /21/ { print $0 } + +The first rule has the string '12' as the pattern and 'print $0' as the +action. The second rule has the string '21' as the pattern and also has +'print $0' as the action. Each rule's action is enclosed in its own +pair of braces. + + This program prints every line that contains the string '12' _or_ the +string '21'. If a line contains both strings, it is printed twice, once +by each rule. + + This is what happens if we run this program on our two sample data +files, 'mail-list' and 'inventory-shipped': + + $ awk '/12/ { print $0 } + > /21/ { print $0 }' mail-list inventory-shipped + -| Anthony 555-3412 anthony.asserturo@hotmail.com A + -| Camilla 555-2912 camilla.infusarum@skynet.be R + -| Fabius 555-1234 fabius.undevicesimus@ucb.edu F + -| Jean-Paul 555-2127 jeanpaul.campanorum@nyu.edu R + -| Jean-Paul 555-2127 jeanpaul.campanorum@nyu.edu R + -| Jan 21 36 64 620 + -| Apr 21 70 74 514 + +Note how the line beginning with 'Jean-Paul' in 'mail-list' was printed +twice, once for each rule. + + +File: gawk.info, Node: More Complex, Next: Statements/Lines, Prev: Two Rules, Up: Getting Started + +1.5 A More Complex Example +========================== + +Now that we've mastered some simple tasks, let's look at what typical +'awk' programs do. This example shows how 'awk' can be used to +summarize, select, and rearrange the output of another utility. It uses +features that haven't been covered yet, so don't worry if you don't +understand all the details: + + ls -l | awk '$6 == "Nov" { sum += $5 } + END { print sum }' + + This command prints the total number of bytes in all the files in the +current directory that were last modified in November (of any year). +The 'ls -l' part of this example is a system command that gives you a +listing of the files in a directory, including each file's size and the +date the file was last modified. Its output looks like this: + + -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 + +The first field contains read-write permissions, the second field +contains the number of links to the file, and the third field identifies +the file's owner. The fourth field identifies the file's group. The +fifth field contains the file's size in bytes. The sixth, seventh, and +eighth fields contain the month, day, and time, respectively, that the +file was last modified. Finally, the ninth field contains the file +name. + + The '$6 == "Nov"' in our 'awk' program is an expression that tests +whether the sixth field of the output from 'ls -l' matches the string +'Nov'. Each time a line has the string 'Nov' for its sixth field, 'awk' +performs the action 'sum += $5'. This adds the fifth field (the file's +size) to the variable 'sum'. As a result, when 'awk' has finished +reading all the input lines, 'sum' is the total of the sizes of the +files whose lines matched the pattern. (This works because 'awk' +variables are automatically initialized to zero.) + + After the last line of output from 'ls' has been processed, the 'END' +rule executes and prints the value of 'sum'. In this example, the value +of 'sum' is 80600. + + These more advanced 'awk' techniques are covered in later minor nodes +(*note Action Overview::). Before you can move on to more advanced +'awk' programming, you have to know how 'awk' interprets your input and +displays your output. By manipulating fields and using 'print' +statements, you can produce some very useful and impressive-looking +reports. + + +File: gawk.info, Node: Statements/Lines, Next: Other Features, Prev: More Complex, Up: Getting Started + +1.6 'awk' Statements Versus Lines +================================= + +Most often, each line in an 'awk' program is a separate statement or +separate rule, like this: + + awk '/12/ { print $0 } + /21/ { print $0 }' mail-list inventory-shipped + + However, 'gawk' ignores newlines after any of the following symbols +and keywords: + + , { ? : || && do else + +A newline at any other point is considered the end of the statement.(1) + + If you would like to split a single statement into two lines at a +point where a newline would terminate it, you can "continue" it by +ending the first line with a backslash character ('\'). The backslash +must be the final character on the line in order to be recognized as a +continuation character. A backslash is allowed anywhere in the +statement, even in the middle of a string or regular expression. For +example: + + awk '/This regular expression is too long, so continue it\ + on the next line/ { print $1 }' + +We have generally not used backslash continuation in our sample +programs. 'gawk' places no limit on the length of a line, so backslash +continuation is never strictly necessary; it just makes programs more +readable. For this same reason, as well as for clarity, we have kept +most statements short in the programs presented throughout the Info +file. Backslash continuation is most useful when your 'awk' program is +in a separate source file instead of entered from the command line. You +should also note that many 'awk' implementations are more particular +about where you may use backslash continuation. For example, they may +not allow you to split a string constant using backslash continuation. +Thus, for maximum portability of your 'awk' programs, it is best not to +split your lines in the middle of a regular expression or a string. + + CAUTION: _Backslash continuation does not work as described with + the C shell._ It works for 'awk' programs in files and for + one-shot programs, _provided_ you are using a POSIX-compliant + shell, such as the Unix Bourne shell or Bash. But the C shell + behaves differently! There you must use two backslashes in a row, + followed by a newline. Note also that when using the C shell, + _every_ newline in your 'awk' program must be escaped with a + backslash. To illustrate: + + % awk 'BEGIN { \ + ? print \\ + ? "hello, world" \ + ? }' + -| hello, world + + Here, the '%' and '?' are the C shell's primary and secondary + prompts, analogous to the standard shell's '$' and '>'. + + Compare the previous example to how it is done with a + POSIX-compliant shell: + + $ awk 'BEGIN { + > print \ + > "hello, world" + > }' + -| hello, world + + 'awk' is a line-oriented language. Each rule's action has to begin +on the same line as the pattern. To have the pattern and action on +separate lines, you _must_ use backslash continuation; there is no other +option. + + Another thing to keep in mind is that backslash continuation and +comments do not mix. As soon as 'awk' sees the '#' that starts a +comment, it ignores _everything_ on the rest of the line. For example: + + $ gawk 'BEGIN { print "dont panic" # a friendly \ + > BEGIN rule + > }' + error-> gawk: cmd. line:2: BEGIN rule + error-> gawk: cmd. line:2: ^ syntax error + +In this case, it looks like the backslash would continue the comment +onto the next line. However, the backslash-newline combination is never +even noticed because it is "hidden" inside the comment. Thus, the +'BEGIN' is noted as a syntax error. + + When 'awk' statements within one rule are short, you might want to +put more than one of them on a line. This is accomplished by separating +the statements with a semicolon (';'). This also applies to the rules +themselves. Thus, the program shown at the start of this minor node +could also be written this way: + + /12/ { print $0 } ; /21/ { print $0 } + + NOTE: The requirement that states that rules on the same line must + be separated with a semicolon was not in the original 'awk' + language; it was added for consistency with the treatment of + statements within an action. + + ---------- Footnotes ---------- + + (1) The '?' and ':' referred to here is the three-operand conditional +expression described in *note Conditional Exp::. Splitting lines after +'?' and ':' is a minor 'gawk' extension; if '--posix' is specified +(*note Options::), then this extension is disabled. + + +File: gawk.info, Node: Other Features, Next: When, Prev: Statements/Lines, Up: Getting Started + +1.7 Other Features of 'awk' +=========================== + +The 'awk' language provides a number of predefined, or "built-in", +variables that your programs can use to get information from 'awk'. +There are other variables your program can set as well to control how +'awk' processes your data. + + In addition, 'awk' provides a number of built-in functions for doing +common computational and string-related operations. 'gawk' provides +built-in functions for working with timestamps, performing bit +manipulation, for runtime string translation (internationalization), +determining the type of a variable, and array sorting. + + As we develop our presentation of the 'awk' language, we will +introduce most of the variables and many of the functions. They are +described systematically in *note Built-in Variables:: and in *note +Built-in::. + + +File: gawk.info, Node: When, Next: Intro Summary, Prev: Other Features, Up: Getting Started + +1.8 When to Use 'awk' +===================== + +Now that you've seen some of what 'awk' can do, you might wonder how +'awk' could be useful for you. By using utility programs, advanced +patterns, field separators, arithmetic statements, and other selection +criteria, you can produce much more complex output. The 'awk' language +is very useful for producing reports from large amounts of raw data, +such as summarizing information from the output of other utility +programs like 'ls'. (*Note More Complex::.) + + Programs written with 'awk' are usually much smaller than they would +be in other languages. This makes 'awk' programs easy to compose and +use. Often, 'awk' programs can be quickly composed at your keyboard, +used once, and thrown away. Because 'awk' programs are interpreted, you +can avoid the (usually lengthy) compilation part of the typical +edit-compile-test-debug cycle of software development. + + Complex programs have been written in 'awk', including a complete +retargetable assembler for eight-bit microprocessors (*note Glossary::, +for more information), and a microcode assembler for a special-purpose +Prolog computer. The original 'awk''s capabilities were strained by +tasks of such complexity, but modern versions are more capable. + + If you find yourself writing 'awk' scripts of more than, say, a few +hundred lines, you might consider using a different programming +language. The shell is good at string and pattern matching; in +addition, it allows powerful use of the system utilities. Python offers +a nice balance between high-level ease of programming and access to +system facilities.(1) + + ---------- Footnotes ---------- + + (1) Other popular scripting languages include Ruby and Perl. + + +File: gawk.info, Node: Intro Summary, Prev: When, Up: Getting Started + +1.9 Summary +=========== + + * Programs in 'awk' consist of PATTERN-ACTION pairs. + + * An ACTION without a PATTERN always runs. The default ACTION for a + pattern without one is '{ print $0 }'. + + * Use either 'awk 'PROGRAM' FILES' or 'awk -f PROGRAM-FILE FILES' to + run 'awk'. + + * You may use the special '#!' header line to create 'awk' programs + that are directly executable. + + * Comments in 'awk' programs start with '#' and continue to the end + of the same line. + + * Be aware of quoting issues when writing 'awk' programs as part of a + larger shell script (or MS-Windows batch file). + + * You may use backslash continuation to continue a source line. + Lines are automatically continued after a comma, open brace, + question mark, colon, '||', '&&', 'do', and 'else'. + + +File: gawk.info, Node: Invoking Gawk, Next: Regexp, Prev: Getting Started, Up: Top + +2 Running 'awk' and 'gawk' +************************** + +This major node covers how to run 'awk', both POSIX-standard and +'gawk'-specific command-line options, and what 'awk' and 'gawk' do with +nonoption arguments. It then proceeds to cover how 'gawk' searches for +source files, reading standard input along with other files, 'gawk''s +environment variables, 'gawk''s exit status, using include files, and +obsolete and undocumented options and/or features. + + Many of the options and features described here are discussed in more +detail later in the Info file; feel free to skip over things in this +major node that don't interest you right now. + +* Menu: + +* Command Line:: How to run 'awk'. +* Options:: Command-line options and their meanings. +* Other Arguments:: Input file names and variable assignments. +* Naming Standard Input:: How to specify standard input with other + files. +* Environment Variables:: The environment variables 'gawk' uses. +* Exit Status:: 'gawk''s exit status. +* Include Files:: Including other files into your program. +* Loading Shared Libraries:: Loading shared libraries into your program. +* Obsolete:: Obsolete Options and/or features. +* Undocumented:: Undocumented Options and Features. +* Invoking Summary:: Invocation summary. + + +File: gawk.info, Node: Command Line, Next: Options, Up: Invoking Gawk + +2.1 Invoking 'awk' +================== + +There are two ways to run 'awk'--with an explicit program or with one or +more program files. Here are templates for both of them; items enclosed +in [...] in these templates are optional: + + 'awk' [OPTIONS] '-f' PROGFILE ['--'] FILE ... + 'awk' [OPTIONS] ['--'] ''PROGRAM'' FILE ... + + In addition to traditional one-letter POSIX-style options, 'gawk' +also supports GNU long options. + + It is possible to invoke 'awk' with an empty program: + + awk '' datafile1 datafile2 + +Doing so makes little sense, though; 'awk' exits silently when given an +empty program. (d.c.) If '--lint' has been specified on the command +line, 'gawk' issues a warning that the program is empty. + + +File: gawk.info, Node: Options, Next: Other Arguments, Prev: Command Line, Up: Invoking Gawk + +2.2 Command-Line Options +======================== + +Options begin with a dash and consist of a single character. GNU-style +long options consist of two dashes and a keyword. The keyword can be +abbreviated, as long as the abbreviation allows the option to be +uniquely identified. If the option takes an argument, either the +keyword is immediately followed by an equals sign ('=') and the +argument's value, or the keyword and the argument's value are separated +by whitespace. If a particular option with a value is given more than +once, it is the last value that counts. + + Each long option for 'gawk' has a corresponding POSIX-style short +option. The long and short options are interchangeable in all contexts. +The following list describes options mandated by the POSIX standard: + +'-F FS' +'--field-separator FS' + Set the 'FS' variable to FS (*note Field Separators::). + +'-f SOURCE-FILE' +'--file SOURCE-FILE' + Read the 'awk' program source from SOURCE-FILE instead of in the + first nonoption argument. This option may be given multiple times; + the 'awk' program consists of the concatenation of the contents of + each specified SOURCE-FILE. + +'-v VAR=VAL' +'--assign VAR=VAL' + Set the variable VAR to the value VAL _before_ execution of the + program begins. Such variable values are available inside the + 'BEGIN' rule (*note Other Arguments::). + + The '-v' option can only set one variable, but it can be used more + than once, setting another variable each time, like this: 'awk + -v foo=1 -v bar=2 ...'. + + CAUTION: Using '-v' to set the values of the built-in + variables may lead to surprising results. 'awk' will reset + the values of those variables as it needs to, possibly + ignoring any initial value you may have given. + +'-W GAWK-OPT' + Provide an implementation-specific option. This is the POSIX + convention for providing implementation-specific options. These + options also have corresponding GNU-style long options. Note that + the long options may be abbreviated, as long as the abbreviations + remain unique. The full list of 'gawk'-specific options is + provided next. + +'--' + Signal the end of the command-line options. The following + arguments are not treated as options even if they begin with '-'. + This interpretation of '--' follows the POSIX argument parsing + conventions. + + This is useful if you have file names that start with '-', or in + shell scripts, if you have file names that will be specified by the + user that could start with '-'. It is also useful for passing + options on to the 'awk' program; see *note Getopt Function::. + + The following list describes 'gawk'-specific options: + +'-b' +'--characters-as-bytes' + Cause 'gawk' to treat all input data as single-byte characters. In + addition, all output written with 'print' or 'printf' is treated as + single-byte characters. + + Normally, 'gawk' follows the POSIX standard and attempts to process + its input data according to the current locale (*note Locales::). + This can often involve converting multibyte characters into wide + characters (internally), and can lead to problems or confusion if + the input data does not contain valid multibyte characters. This + option is an easy way to tell 'gawk', "Hands off my data!" + +'-c' +'--traditional' + Specify "compatibility mode", in which the GNU extensions to the + 'awk' language are disabled, so that 'gawk' behaves just like BWK + 'awk'. *Note POSIX/GNU::, which summarizes the extensions. Also + see *note Compatibility Mode::. + +'-C' +'--copyright' + Print the short version of the General Public License and then + exit. + +'-d'[FILE] +'--dump-variables'['='FILE] + Print a sorted list of global variables, their types, and final + values to FILE. If no FILE is provided, print this list to a file + named 'awkvars.out' in the current directory. No space is allowed + between the '-d' and FILE, if FILE is supplied. + + Having a list of all global variables is a good way to look for + typographical errors in your programs. You would also use this + option if you have a large program with a lot of functions, and you + want to be sure that your functions don't inadvertently use global + variables that you meant to be local. (This is a particularly easy + mistake to make with simple variable names like 'i', 'j', etc.) + +'-D'[FILE] +'--debug'['='FILE] + Enable debugging of 'awk' programs (*note Debugging::). By + default, the debugger reads commands interactively from the + keyboard (standard input). The optional FILE argument allows you + to specify a file with a list of commands for the debugger to + execute noninteractively. No space is allowed between the '-D' and + FILE, if FILE is supplied. + +'-e' PROGRAM-TEXT +'--source' PROGRAM-TEXT + Provide program source code in the PROGRAM-TEXT. This option + allows you to mix source code in files with source code that you + enter on the command line. This is particularly useful when you + 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 + differences from '-f': + + * This option terminates option processing; anything else on the + command line is passed on directly to the 'awk' program. + + * Command-line variable assignments of the form 'VAR=VALUE' are + disallowed. + + This option is particularly necessary for World Wide Web CGI + applications that pass arguments through the URL; using this option + prevents a malicious (or other) user from passing in options, + assignments, or 'awk' source code (via '-e') to the CGI + application.(1) This option should be used with '#!' scripts + (*note Executable Scripts::), like so: + + #! /usr/local/bin/gawk -E + + AWK PROGRAM HERE ... + +'-g' +'--gen-pot' + Analyze the source program and generate a GNU 'gettext' portable + object template file on standard output for all string constants + that have been marked for translation. *Note + Internationalization::, for information about this option. + +'-h' +'--help' + Print a "usage" message summarizing the short- and long-style + options that 'gawk' accepts and then exit. + +'-i' SOURCE-FILE +'--include' SOURCE-FILE + Read an 'awk' source library from SOURCE-FILE. This option is + completely equivalent to using the '@include' directive inside your + program. It is very similar to the '-f' option, but there are two + important differences. First, when '-i' is used, the program + source is not loaded if it has been previously loaded, whereas with + '-f', 'gawk' always loads the file. Second, because this option is + intended to be used with code libraries, 'gawk' does not recognize + such files as constituting main program input. Thus, after + processing an '-i' argument, 'gawk' still expects to find the main + source code via the '-f' option or on the command line. + +'-l' EXT +'--load' EXT + Load a dynamic extension named EXT. Extensions are stored as + system shared libraries. This option searches for the library + using the 'AWKLIBPATH' environment variable. The correct library + suffix for your platform will be supplied by default, so it need + not be specified in the extension name. The extension + initialization routine should be named 'dl_load()'. An alternative + is to use the '@load' keyword inside the program to load a shared + library. This advanced feature is described in detail in *note + Dynamic Extensions::. + +'-L'[VALUE] +'--lint'['='VALUE] + Warn about constructs that are dubious or nonportable to other + 'awk' implementations. No space is allowed between the '-L' and + VALUE, if VALUE is supplied. Some warnings are issued when 'gawk' + first reads your program. Others are issued at runtime, as your + program executes. With an optional argument of 'fatal', lint + warnings become fatal errors. This may be drastic, but its use + will certainly encourage the development of cleaner 'awk' programs. + With an optional argument of 'invalid', only warnings about things + that are actually invalid are issued. (This is not fully + implemented yet.) + + Some warnings are only printed once, even if the dubious constructs + they warn about occur multiple times in your 'awk' program. Thus, + when eliminating problems pointed out by '--lint', you should take + care to search for all occurrences of each inappropriate construct. + As 'awk' programs are usually short, doing so is not burdensome. + +'-M' +'--bignum' + Select arbitrary-precision arithmetic on numbers. This option has + no effect if 'gawk' is not compiled to use the GNU MPFR and MP + libraries (*note Arbitrary Precision Arithmetic::). + +'-n' +'--non-decimal-data' + Enable automatic interpretation of octal and hexadecimal values in + input data (*note Nondecimal Data::). + + CAUTION: This option can severely break old programs. Use + with care. Also note that this option may disappear in a + future version of 'gawk'. + +'-N' +'--use-lc-numeric' + Force the use of the locale's decimal point character when parsing + numeric input data (*note Locales::). + +'-o'[FILE] +'--pretty-print'['='FILE] + 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: In the past, this option would also execute your + program. This is no longer the case. + +'-O' +'--optimize' + 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::). 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 + function. + +'-P' +'--posix' + Operate in strict POSIX mode. This disables all 'gawk' extensions + (just like '--traditional') and disables all extensions not allowed + by POSIX. *Note Common Extensions:: for a summary of the extensions + in 'gawk' that are disabled by this option. Also, the following + additional restrictions apply: + + * Newlines are not allowed after '?' or ':' (*note Conditional + Exp::). + + * Specifying '-Ft' on the command line does not set the value of + 'FS' to be a single TAB character (*note Field Separators::). + + * The locale's decimal point character is used for parsing input + data (*note Locales::). + + If you supply both '--traditional' and '--posix' on the command + line, '--posix' takes precedence. 'gawk' issues a warning if both + options are supplied. + +'-r' +'--re-interval' + Allow interval expressions (*note Regexp Operators::) in regexps. + This is now 'gawk''s default behavior. Nevertheless, this option + 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', + output redirections with 'print' and 'printf', and dynamic + extensions. This is particularly useful when you want to run 'awk' + scripts from questionable sources and need to make sure the scripts + can't access your system (other than the specified input data + file). + +'-t' +'--lint-old' + Warn about constructs that are not available in the original + version of 'awk' from Version 7 Unix (*note V7/SVR3.1::). + +'-V' +'--version' + Print version information for this particular copy of 'gawk'. This + allows you to determine if your copy of 'gawk' is up to date with + respect to whatever the Free Software Foundation is currently + distributing. It is also useful for bug reports (*note Bugs::). + + As long as program text has been supplied, any other options are +flagged as invalid with a warning message but are otherwise ignored. + + In compatibility mode, as a special case, if the value of FS supplied +to the '-F' option is 't', then 'FS' is set to the TAB character +('"\t"'). This is true only for '--traditional' and not for '--posix' +(*note Field Separators::). + + The '-f' option may be used more than once on the command line. If +it is, 'awk' reads its program source from all of the named files, as if +they had been concatenated together into one big file. This is useful +for creating libraries of 'awk' functions. These functions can be +written once and then retrieved from a standard place, instead of having +to be included in each individual program. The '-i' option is similar +in this regard. (As mentioned in *note Definition Syntax::, function +names must be unique.) + + With standard 'awk', library functions can still be used, even if the +program is entered at the keyboard, by specifying '-f /dev/tty'. After +typing your program, type 'Ctrl-d' (the end-of-file character) to +terminate it. (You may also use '-f -' to read program source from the +standard input, but then you will not be able to also use the standard +input as a source of data.) + + Because it is clumsy using the standard 'awk' mechanisms to mix +source file and command-line 'awk' programs, 'gawk' provides the '-e' +option. This does not require you to preempt the standard input for +your source code; it allows you to easily mix command-line and library +source code (*note AWKPATH Variable::). As with '-f', the '-e' and '-i' +options may also be used multiple times on the command line. + + If no '-f' or '-e' option is specified, then 'gawk' uses the first +nonoption command-line argument as the text of the program source code. + + If the environment variable 'POSIXLY_CORRECT' exists, then 'gawk' +behaves in strict POSIX mode, exactly as if you had supplied '--posix'. +Many GNU programs look for this environment variable to suppress +extensions that conflict with POSIX, but 'gawk' behaves differently: it +suppresses all extensions, even those that do not conflict with POSIX, +and behaves in strict POSIX mode. If '--lint' is supplied on the +command line and 'gawk' turns on POSIX mode because of +'POSIXLY_CORRECT', then it issues a warning message indicating that +POSIX mode is in effect. You would typically set this variable in your +shell's startup file. For a Bourne-compatible shell (such as Bash), you +would add these lines to the '.profile' file in your home directory: + + POSIXLY_CORRECT=true + export POSIXLY_CORRECT + + For a C shell-compatible shell,(2) you would add this line to the +'.login' file in your home directory: + + setenv POSIXLY_CORRECT true + + Having 'POSIXLY_CORRECT' set is not recommended for daily use, but it +is good for testing the portability of your programs to other +environments. + + ---------- Footnotes ---------- + + (1) For more detail, please see Section 4.4 of RFC 3875 +(http://www.ietf.org/rfc/rfc3875). Also see the explanatory note sent +to the 'gawk' bug mailing list +(https://lists.gnu.org/archive/html/bug-gawk/2014-11/msg00022.html). + + (2) Not recommended. + + +File: gawk.info, Node: Other Arguments, Next: Naming Standard Input, Prev: Options, Up: Invoking Gawk + +2.3 Other Command-Line Arguments +================================ + +Any additional arguments on the command line are normally treated as +input files to be processed in the order specified. However, an +argument that has the form 'VAR=VALUE', assigns the value VALUE to the +variable VAR--it does not specify a file at all. (See *note Assignment +Options::.) In the following example, COUNT=1 is a variable assignment, +not a file name: + + awk -f program.awk file1 count=1 file2 + + All the command-line arguments are made available to your 'awk' +program in the 'ARGV' array (*note Built-in Variables::). Command-line +options and the program text (if present) are omitted from 'ARGV'. All +other arguments, including variable assignments, are included. As each +element of 'ARGV' is processed, 'gawk' sets 'ARGIND' to the index in +'ARGV' of the current element. + + Changing 'ARGC' and 'ARGV' in your 'awk' program lets you control how +'awk' processes the input files; this is described in more detail in +*note ARGC and ARGV::. + + The distinction between file name arguments and variable-assignment +arguments is made when 'awk' is about to open the next input file. At +that point in execution, it checks the file name to see whether it is +really a variable assignment; if so, 'awk' sets the variable instead of +reading a file. + + Therefore, the variables actually receive the given values after all +previously specified files have been read. In particular, the values of +variables assigned in this fashion are _not_ available inside a 'BEGIN' +rule (*note BEGIN/END::), because such rules are run before 'awk' begins +scanning the argument list. + + The variable values given on the command line are processed for +escape sequences (*note Escape Sequences::). (d.c.) + + In some very early implementations of 'awk', when a variable +assignment occurred before any file names, the assignment would happen +_before_ the 'BEGIN' rule was executed. 'awk''s behavior was thus +inconsistent; some command-line assignments were available inside the +'BEGIN' rule, while others were not. Unfortunately, some applications +came to depend upon this "feature." When 'awk' was changed to be more +consistent, the '-v' option was added to accommodate applications that +depended upon the old behavior. + + The variable assignment feature is most useful for assigning to +variables such as 'RS', 'OFS', and 'ORS', which control input and output +formats, before scanning the data files. It is also useful for +controlling state if multiple passes are needed over a data file. For +example: + + awk 'pass == 1 { PASS 1 STUFF } + pass == 2 { PASS 2 STUFF }' pass=1 mydata pass=2 mydata + + Given the variable assignment feature, the '-F' option for setting +the value of 'FS' is not strictly necessary. It remains for historical +compatibility. + + +File: gawk.info, Node: Naming Standard Input, Next: Environment Variables, Prev: Other Arguments, Up: Invoking Gawk + +2.4 Naming Standard Input +========================= + +Often, you may wish to read standard input together with other files. +For example, you may wish to read one file, read standard input coming +from a pipe, and then read another file. + + The way to name the standard input, with all versions of 'awk', is to +use a single, standalone minus sign or dash, '-'. For example: + + SOME_COMMAND | awk -f myprog.awk file1 - file2 + +Here, 'awk' first reads 'file1', then it reads the output of +SOME_COMMAND, and finally it reads 'file2'. + + You may also use '"-"' to name standard input when reading files with +'getline' (*note Getline/File::). + + In addition, 'gawk' allows you to specify the special file name +'/dev/stdin', both on the command line and with 'getline'. Some other +versions of 'awk' also support this, but it is not standard. (Some +operating systems provide a '/dev/stdin' file in the filesystem; +however, 'gawk' always processes this file name itself.) + + +File: gawk.info, Node: Environment Variables, Next: Exit Status, Prev: Naming Standard Input, Up: Invoking Gawk + +2.5 The Environment Variables 'gawk' Uses +========================================= + +A number of environment variables influence how 'gawk' behaves. + +* Menu: + +* AWKPATH Variable:: Searching directories for 'awk' + programs. +* AWKLIBPATH Variable:: Searching directories for 'awk' shared + libraries. +* Other Environment Variables:: The environment variables. + + +File: gawk.info, Node: AWKPATH Variable, Next: AWKLIBPATH Variable, Up: Environment Variables + +2.5.1 The 'AWKPATH' Environment Variable +---------------------------------------- + +The previous minor node described how 'awk' program files can be named +on the command line with the '-f' option. In most 'awk' +implementations, you must supply a precise pathname for each program +file, unless the file is in the current directory. But with 'gawk', if +the file name supplied to the '-f' or '-i' options does not contain a +directory separator '/', then 'gawk' searches a list of directories +(called the "search path") one by one, looking for a file with the +specified name. + + The search path is a string consisting of directory names separated +by colons.(1) 'gawk' gets its search path from the 'AWKPATH' +environment variable. If that variable does not exist, or if it has an +empty value, 'gawk' uses a default path (described shortly). + + The search path feature is particularly helpful for building +libraries of useful 'awk' functions. The library files can be placed in +a standard directory in the default path and then specified on the +command line with a short file name. Otherwise, you would have to type +the full file name for each file. + + By using the '-i' or '-f' options, your command-line 'awk' programs +can use facilities in 'awk' library files (*note Library Functions::). +Path searching is not done if 'gawk' is in compatibility mode. This is +true for both '--traditional' and '--posix'. *Note Options::. + + If the source code file is not found after the initial search, the +path is searched again after adding the suffix '.awk' to the file name. + + 'gawk''s path search mechanism is similar to the shell's. (See 'The +Bourne-Again SHell manual' (https://www.gnu.org/software/bash/manual/).) +It treats a null entry in the path as indicating the current directory. +(A null entry is indicated by starting or ending the path with a colon +or by placing two colons next to each other ['::'].) + + NOTE: To include the current directory in the path, either place + '.' as an entry in the path or write a null entry in the path. + + Different past versions of 'gawk' would also look explicitly in the + current directory, either before or after the path search. As of + version 4.1.2, this no longer happens; if you wish to look in the + current directory, you must include '.' either as a separate entry + or as a null entry in the search path. + + The default value for 'AWKPATH' is '.:/usr/local/share/awk'.(2) +Since '.' is included at the beginning, 'gawk' searches first in the +current directory and then in '/usr/local/share/awk'. In practice, this +means that you will rarely need to change the value of 'AWKPATH'. + + *Note Shell Startup Files::, for information on functions that help +to manipulate the 'AWKPATH' variable. + + 'gawk' places the value of the search path that it used into +'ENVIRON["AWKPATH"]'. This provides access to the actual search path +value from within an 'awk' program. + + Although you can change 'ENVIRON["AWKPATH"]' within your 'awk' +program, this has no effect on the running program's behavior. This +makes sense: the 'AWKPATH' environment variable is used to find the +program source files. Once your program is running, all the files have +been found, and 'gawk' no longer needs to use 'AWKPATH'. + + ---------- Footnotes ---------- + + (1) Semicolons on MS-Windows. + + (2) Your version of 'gawk' may use a different directory; it will +depend upon how 'gawk' was built and installed. The actual directory is +the value of '$(datadir)' generated when 'gawk' was configured. You +probably don't need to worry about this, though. + + +File: gawk.info, Node: AWKLIBPATH Variable, Next: Other Environment Variables, Prev: AWKPATH Variable, Up: Environment Variables + +2.5.2 The 'AWKLIBPATH' Environment Variable +------------------------------------------- + +The 'AWKLIBPATH' environment variable is similar to the 'AWKPATH' +variable, but it is used to search for loadable extensions (stored as +system shared libraries) specified with the '-l' option rather than for +source files. If the extension is not found, the path is searched again +after adding the appropriate shared library suffix for the platform. +For example, on GNU/Linux systems, the suffix '.so' is used. The search +path specified is also used for extensions loaded via the '@load' +keyword (*note Loading Shared Libraries::). + + If 'AWKLIBPATH' does not exist in the environment, or if it has an +empty value, 'gawk' uses a default path; this is typically +'/usr/local/lib/gawk', although it can vary depending upon how 'gawk' +was built. + + *Note Shell Startup Files::, for information on functions that help +to manipulate the 'AWKLIBPATH' variable. + + 'gawk' places the value of the search path that it used into +'ENVIRON["AWKLIBPATH"]'. This provides access to the actual search path +value from within an 'awk' program. + + Although you can change 'ENVIRON["AWKLIBPATH"]' within your 'awk' +program, this has no effect on the running program's behavior. This +makes sense: the 'AWKLIBPATH' environment variable is used to find any +requested extensions, and they are loaded before the program starts to +run. Once your program is running, all the extensions have been found, +and 'gawk' no longer needs to use 'AWKLIBPATH'. + + +File: gawk.info, Node: Other Environment Variables, Prev: AWKLIBPATH Variable, Up: Environment Variables + +2.5.3 Other Environment Variables +--------------------------------- + +A number of other environment variables affect 'gawk''s behavior, but +they are more specialized. Those in the following list are meant to be +used by regular users: + +'GAWK_MSEC_SLEEP' + Specifies the interval between connection retries, in milliseconds. + On systems that do not support the 'usleep()' system call, the + value is rounded up to an integral number of seconds. + +'GAWK_READ_TIMEOUT' + Specifies the time, in milliseconds, for 'gawk' to wait for input + before returning with an error. *Note Read Timeout::. + +'GAWK_SOCK_RETRIES' + Controls the number of times 'gawk' attempts to retry a two-way + TCP/IP (socket) connection before giving up. *Note TCP/IP + Networking::. 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 + traditional and GNU extensions. *Note Options::. + + The environment variables in the following list are meant for use by +the 'gawk' developers for testing and tuning. They are subject to +change. The variables are: + +'AWKBUFSIZE' + This variable only affects 'gawk' on POSIX-compliant systems. With + a value of 'exact', 'gawk' uses the size of each input file as the + size of the memory buffer to allocate for I/O. Otherwise, the value + should be a number, and 'gawk' uses that number as the size of the + buffer to allocate. (When this variable is not set, 'gawk' uses + the smaller of the file's size and the "default" blocksize, which + is usually the filesystem's I/O blocksize.) + +'AWK_HASH' + If this variable exists with a value of 'gst', 'gawk' switches to + using the hash function from GNU Smalltalk for managing arrays. + This function may be marginally faster than the standard function. + +'AWKREADFUNC' + If this variable exists, 'gawk' switches to reading source files + one line at a time, instead of reading in blocks. This exists for + debugging problems on filesystems on non-POSIX operating systems + where I/O is performed in records, not in blocks. + +'GAWK_MSG_SRC' + If this variable exists, 'gawk' includes the file name and line + number within the 'gawk' source code from which warning and/or + fatal messages are generated. Its purpose is to help isolate the + source of a message, as there are multiple places that produce the + same warning or error message. + +'GAWK_LOCALE_DIR' + Specifies the location of compiled message object files for 'gawk' + itself. This is passed to the 'bindtextdomain()' function when + 'gawk' starts up. + +'GAWK_NO_DFA' + If this variable exists, 'gawk' does not use the DFA regexp matcher + for "does it match" kinds of tests. This can cause 'gawk' to be + slower. Its purpose is to help isolate differences between the two + regexp matchers that 'gawk' uses internally. (There aren't + supposed to be differences, but occasionally theory and practice + don't coordinate with each other.) + +'GAWK_STACKSIZE' + This specifies the amount by which 'gawk' should grow its internal + evaluation stack, when needed. + +'INT_CHAIN_MAX' + This specifies intended maximum number of items 'gawk' will + maintain on a hash chain for managing arrays indexed by integers. + +'STR_CHAIN_MAX' + This specifies intended maximum number of items 'gawk' will + maintain on a hash chain for managing arrays indexed by strings. + +'TIDYMEM' + If this variable exists, 'gawk' uses the 'mtrace()' library calls + from the GNU C library to help track down possible memory leaks. + + +File: gawk.info, Node: Exit Status, Next: Include Files, Prev: Environment Variables, Up: Invoking Gawk + +2.6 'gawk''s Exit Status +======================== + +If the 'exit' statement is used with a value (*note Exit Statement::), +then 'gawk' exits with the numeric value given to it. + + Otherwise, if there were no problems during execution, 'gawk' exits +with the value of the C constant 'EXIT_SUCCESS'. This is usually zero. + + If an error occurs, 'gawk' exits with the value of the C constant +'EXIT_FAILURE'. This is usually one. + + If 'gawk' exits because of a fatal error, the exit status is two. On +non-POSIX systems, this value may be mapped to 'EXIT_FAILURE'. + + +File: gawk.info, Node: Include Files, Next: Loading Shared Libraries, Prev: Exit Status, Up: Invoking Gawk + +2.7 Including Other Files into Your Program +=========================================== + +This minor node describes a feature that is specific to 'gawk'. + + The '@include' keyword can be used to read external 'awk' source +files. This gives you the ability to split large 'awk' source files +into smaller, more manageable pieces, and also lets you reuse common +'awk' code from various 'awk' scripts. In other words, you can group +together 'awk' functions used to carry out specific tasks into external +files. These files can be used just like function libraries, using the +'@include' keyword in conjunction with the 'AWKPATH' environment +variable. Note that source files may also be included using the '-i' +option. + + Let's see an example. We'll start with two (trivial) 'awk' scripts, +namely 'test1' and 'test2'. Here is the 'test1' script: + + BEGIN { + print "This is script test1." + } + +and here is 'test2': + + @include "test1" + BEGIN { + print "This is script test2." + } + + Running 'gawk' with 'test2' produces the following result: + + $ gawk -f test2 + -| This is script test1. + -| This is script test2. + + 'gawk' runs the 'test2' script, which includes 'test1' using the +'@include' keyword. So, to include external 'awk' source files, you +just use '@include' followed by the name of the file to be included, +enclosed in double quotes. + + NOTE: Keep in mind that this is a language construct and the file + name cannot be a string variable, but rather just a literal string + constant in double quotes. + + The files to be included may be nested; e.g., given a third script, +namely 'test3': + + @include "test2" + BEGIN { + print "This is script test3." + } + +Running 'gawk' with the 'test3' script produces the following results: + + $ gawk -f test3 + -| This is script test1. + -| This is script test2. + -| This is script test3. + + The file name can, of course, be a pathname. For example: + + @include "../io_funcs" + +and: + + @include "/usr/awklib/network" + +are both valid. The 'AWKPATH' environment variable can be of great +value when using '@include'. The same rules for the use of the +'AWKPATH' variable in command-line file searches (*note AWKPATH +Variable::) apply to '@include' also. + + This is very helpful in constructing 'gawk' function libraries. If +you have a large script with useful, general-purpose 'awk' functions, +you can break it down into library files and put those files in a +special directory. You can then include those "libraries," either by +using the full pathnames of the files, or by setting the 'AWKPATH' +environment variable accordingly and then using '@include' with just the +file part of the full pathname. Of course, you can keep library files +in more than one directory; the more complex the working environment is, +the more directories you may need to organize the files to be included. + + Given the ability to specify multiple '-f' options, the '@include' +mechanism is not strictly necessary. However, the '@include' keyword +can help you in constructing self-contained 'gawk' programs, thus +reducing the need for writing complex and tedious command lines. In +particular, '@include' is very useful for writing CGI scripts to be run +from web pages. + + The rules for finding a source file described in *note AWKPATH +Variable:: also apply to files loaded with '@include'. + + +File: gawk.info, Node: Loading Shared Libraries, Next: Obsolete, Prev: Include Files, Up: Invoking Gawk + +2.8 Loading Dynamic Extensions into Your Program +================================================ + +This minor node describes a feature that is specific to 'gawk'. + + The '@load' keyword can be used to read external 'awk' extensions +(stored as system shared libraries). This allows you to link in +compiled code that may offer superior performance and/or give you access +to extended capabilities not supported by the 'awk' language. The +'AWKLIBPATH' variable is used to search for the extension. Using +'@load' is completely equivalent to using the '-l' command-line option. + + If the extension is not initially found in 'AWKLIBPATH', another +search is conducted after appending the platform's default shared +library suffix to the file name. For example, on GNU/Linux systems, the +suffix '.so' is used: + + $ gawk '@load "ordchr"; BEGIN {print chr(65)}' + -| A + +This is equivalent to the following example: + + $ gawk -lordchr 'BEGIN {print chr(65)}' + -| A + +For command-line usage, the '-l' option is more convenient, but '@load' +is useful for embedding inside an 'awk' source file that requires access +to an extension. + + *note Dynamic Extensions::, describes how to write extensions (in C +or C++) that can be loaded with either '@load' or the '-l' option. It +also describes the 'ordchr' extension. + + +File: gawk.info, Node: Obsolete, Next: Undocumented, Prev: Loading Shared Libraries, Up: Invoking Gawk + +2.9 Obsolete Options and/or Features +==================================== + +This minor node describes features and/or command-line options from +previous releases of 'gawk' that either are not available in the current +version or are still supported but deprecated (meaning that they will +_not_ be in the next release). + + The process-related special files '/dev/pid', '/dev/ppid', +'/dev/pgrpid', and '/dev/user' were deprecated in 'gawk' 3.1, but still +worked. As of version 4.0, they are no longer interpreted specially by +'gawk'. (Use 'PROCINFO' instead; see *note Auto-set::.) + + +File: gawk.info, Node: Undocumented, Next: Invoking Summary, Prev: Obsolete, Up: Invoking Gawk + +2.10 Undocumented Options and Features +====================================== + + Use the Source, Luke! + -- _Obi-Wan_ + + This minor node intentionally left blank. + + +File: gawk.info, Node: Invoking Summary, Prev: Undocumented, Up: Invoking Gawk + +2.11 Summary +============ + + * Use either 'awk 'PROGRAM' FILES' or 'awk -f PROGRAM-FILE FILES' to + run 'awk'. + + * The three standard options for all versions of 'awk' are '-f', + '-F', and '-v'. 'gawk' supplies these and many others, as well as + corresponding GNU-style long options. + + * Nonoption command-line arguments are usually treated as file names, + unless they have the form 'VAR=VALUE', in which case they are taken + as variable assignments to be performed at that point in processing + the input. + + * All nonoption command-line arguments, excluding the program text, + are placed in the 'ARGV' array. Adjusting 'ARGC' and 'ARGV' + affects how 'awk' processes input. + + * You can use a single minus sign ('-') to refer to standard input on + the command line. 'gawk' also lets you use the special file name + '/dev/stdin'. + + * 'gawk' pays attention to a number of environment variables. + 'AWKPATH', 'AWKLIBPATH', and 'POSIXLY_CORRECT' are the most + important ones. + + * 'gawk''s exit status conveys information to the program that + invoked it. Use the 'exit' statement from within an 'awk' program + to set the exit status. + + * 'gawk' allows you to include other 'awk' source files into your + program using the '@include' statement and/or the '-i' and '-f' + command-line options. + + * 'gawk' allows you to load additional functions written in C or C++ + using the '@load' statement and/or the '-l' option. (This advanced + feature is described later, in *note Dynamic Extensions::.) + + +File: gawk.info, Node: Regexp, Next: Reading Files, Prev: Invoking Gawk, Up: Top + +3 Regular Expressions +********************* + +A "regular expression", or "regexp", is a way of describing a set of +strings. Because regular expressions are such a fundamental part of +'awk' programming, their format and use deserve a separate major node. + + A regular expression enclosed in slashes ('/') is an 'awk' pattern +that matches every input record whose text belongs to that set. The +simplest regular expression is a sequence of letters, numbers, or both. +Such a regexp matches any string that contains that sequence. Thus, the +regexp 'foo' matches any string containing 'foo'. Thus, the pattern +'/foo/' matches any input record containing the three adjacent +characters 'foo' _anywhere_ in the record. Other kinds of regexps let +you specify more complicated classes of strings. + +* Menu: + +* Regexp Usage:: How to Use Regular Expressions. +* Escape Sequences:: How to write nonprinting characters. +* Regexp Operators:: Regular Expression Operators. +* Bracket Expressions:: What can go between '[...]'. +* Leftmost Longest:: How much text matches. +* Computed Regexps:: Using Dynamic Regexps. +* GNU Regexp Operators:: Operators specific to GNU software. +* Case-sensitivity:: How to do case-insensitive matching. +* Regexp Summary:: Regular expressions summary. + + +File: gawk.info, Node: Regexp Usage, Next: Escape Sequences, Up: Regexp + +3.1 How to Use Regular Expressions +================================== + +A regular expression can be used as a pattern by enclosing it in +slashes. Then the regular expression is tested against the entire text +of each record. (Normally, it only needs to match some part of the text +in order to succeed.) For example, the following prints the second +field of each record where the string 'li' appears anywhere in the +record: + + $ awk '/li/ { print $2 }' mail-list + -| 555-5553 + -| 555-0542 + -| 555-6699 + -| 555-3430 + + Regular expressions can also be used in matching expressions. These +expressions allow you to specify the string to match against; it need +not be the entire current input record. The two operators '~' and '!~' +perform regular expression comparisons. Expressions using these +operators can be used as patterns, or in 'if', 'while', 'for', and 'do' +statements. (*Note Statements::.) For example, the following is true +if the expression EXP (taken as a string) matches REGEXP: + + EXP ~ /REGEXP/ + +This example matches, or selects, all input records with the uppercase +letter 'J' somewhere in the first field: + + $ awk '$1 ~ /J/' inventory-shipped + -| Jan 13 25 15 115 + -| Jun 31 42 75 492 + -| Jul 24 34 67 436 + -| Jan 21 36 64 620 + + So does this: + + awk '{ if ($1 ~ /J/) print }' inventory-shipped + + This next example is true if the expression EXP (taken as a character +string) does _not_ match REGEXP: + + EXP !~ /REGEXP/ + + The following example matches, or selects, all input records whose +first field _does not_ contain the uppercase letter 'J': + + $ awk '$1 !~ /J/' inventory-shipped + -| Feb 15 32 24 226 + -| Mar 15 24 34 228 + -| Apr 31 52 63 420 + -| May 16 34 29 208 + ... + + When a regexp is enclosed in slashes, such as '/foo/', we call it a +"regexp constant", much like '5.27' is a numeric constant and '"foo"' is +a string constant. + + +File: gawk.info, Node: Escape Sequences, Next: Regexp Operators, Prev: Regexp Usage, Up: Regexp + +3.2 Escape Sequences +==================== + +Some characters cannot be included literally in string constants +('"foo"') or regexp constants ('/foo/'). Instead, they should be +represented with "escape sequences", which are character sequences +beginning with a backslash ('\'). One use of an escape sequence is to +include a double-quote character in a string constant. Because a plain +double quote ends the string, you must use '\"' to represent an actual +double-quote character as a part of the string. For example: + + $ awk 'BEGIN { print "He said \"hi!\" to her." }' + -| He said "hi!" to her. + + The backslash character itself is another character that cannot be +included normally; you must write '\\' to put one backslash in the +string or regexp. Thus, the string whose contents are the two +characters '"' and '\' must be written '"\"\\"'. + + Other escape sequences represent unprintable characters such as TAB +or newline. There is nothing to stop you from entering most unprintable +characters directly in a string constant or regexp constant, but they +may look ugly. + + The following list presents all the escape sequences used in 'awk' +and what they represent. Unless noted otherwise, all these escape +sequences apply to both string constants and regexp constants: + +'\\' + A literal backslash, '\'. + +'\a' + The "alert" character, 'Ctrl-g', ASCII code 7 (BEL). (This often + makes some sort of audible noise.) + +'\b' + Backspace, 'Ctrl-h', ASCII code 8 (BS). + +'\f' + Formfeed, 'Ctrl-l', ASCII code 12 (FF). + +'\n' + Newline, 'Ctrl-j', ASCII code 10 (LF). + +'\r' + Carriage return, 'Ctrl-m', ASCII code 13 (CR). + +'\t' + Horizontal TAB, 'Ctrl-i', ASCII code 9 (HT). + +'\v' + Vertical TAB, 'Ctrl-k', ASCII code 11 (VT). + +'\NNN' + The octal value NNN, where NNN stands for 1 to 3 digits between '0' + and '7'. For example, the code for the ASCII ESC (escape) + character is '\033'. + +'\xHH...' + The hexadecimal value HH, where HH stands for a sequence of + 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 + sequence is used when you want to write a regexp constant that + contains a slash (such as '/.*:\/home\/[[:alnum:]]+:.*/'; the + '[[:alnum:]]' notation is discussed in *note Bracket + Expressions::). Because the regexp is delimited by slashes, you + need to escape any slash that is part of the pattern, in order to + tell 'awk' to keep processing the rest of the regexp. + +'\"' + A literal double quote (necessary for string constants only). This + sequence is used when you want to write a string constant that + contains a double quote (such as '"He said \"hi!\" to her."'). + Because the string is delimited by double quotes, you need to + escape any quote that is part of the string, in order to tell 'awk' + to keep processing the rest of the string. + + In 'gawk', a number of additional two-character sequences that begin +with a backslash have special meaning in regexps. *Note GNU Regexp +Operators::. + + In a regexp, a backslash before any character that is not in the +previous list and not listed in *note GNU Regexp Operators:: means that +the next character should be taken literally, even if it would normally +be a regexp operator. For example, '/a\+b/' matches the three +characters 'a+b'. + + For complete portability, do not use a backslash before any character +not shown in the previous list or that is not an operator. + + Backslash Before Regular Characters + + If you place a backslash in a string constant before something that +is not one of the characters previously listed, POSIX 'awk' purposely +leaves what happens as undefined. There are two choices: + +Strip the backslash out + This is what BWK 'awk' and 'gawk' both do. For example, '"a\qc"' + is the same as '"aqc"'. (Because this is such an easy bug both to + introduce and to miss, 'gawk' warns you about it.) Consider 'FS = + "[ \t]+\|[ \t]+"' to use vertical bars surrounded by whitespace as + the field separator. There should be two backslashes in the + string: 'FS = "[ \t]+\\|[ \t]+"'.) + +Leave the backslash alone + Some other 'awk' implementations do this. In such implementations, + typing '"a\qc"' is the same as typing '"a\\qc"'. + + To summarize: + + * The escape sequences in the preceding list are always processed + first, for both string constants and regexp constants. This + happens very early, as soon as 'awk' reads your program. + + * 'gawk' processes both regexp constants and dynamic regexps (*note + Computed Regexps::), for the special operators listed in *note GNU + Regexp Operators::. + + * A backslash before any other character means to treat that + character literally. + + Escape Sequences for Metacharacters + + Suppose you use an octal or hexadecimal escape to represent a regexp +metacharacter. (See *note Regexp Operators::.) Does 'awk' treat the +character as a literal character or as a regexp operator? + + Historically, such characters were taken literally. (d.c.) However, +the POSIX standard indicates that they should be treated as real +metacharacters, which is what 'gawk' does. In compatibility mode (*note +Options::), 'gawk' treats the characters represented by octal and +hexadecimal escape sequences literally when used in regexp constants. +Thus, '/a\52b/' is equivalent to '/a\*b/'. + + +File: gawk.info, Node: Regexp Operators, Next: Bracket Expressions, Prev: Escape Sequences, Up: Regexp + +3.3 Regular Expression Operators +================================ + +You can combine regular expressions with special characters, called +"regular expression operators" or "metacharacters", to increase the +power and versatility of regular expressions. + + The escape sequences described in *note Escape Sequences:: are valid +inside a regexp. They are introduced by a '\' and are recognized and +converted into corresponding real characters as the very first step in +processing regexps. + + Here is a list of metacharacters. All characters that are not escape +sequences and that are not listed here stand for themselves: + +'\' + This suppresses the special meaning of a character when matching. + For example, '\$' matches the character '$'. + +'^' + This matches the beginning of a string. '^@chapter' matches + '@chapter' at the beginning of a string, for example, and can be + used to identify chapter beginnings in Texinfo source files. The + '^' is known as an "anchor", because it anchors the pattern to + match only at the beginning of the string. + + It is important to realize that '^' does not match the beginning of + a line (the point right after a '\n' newline character) embedded in + a string. The condition is not true in the following example: + + if ("line1\nLINE 2" ~ /^L/) ... + +'$' + This is similar to '^', but it matches only at the end of a string. + For example, 'p$' matches a record that ends with a 'p'. The '$' + is an anchor and does not match the end of a line (the point right + before a '\n' newline character) embedded in a string. The + condition in the following example is not true: + + if ("line1\nLINE 2" ~ /1$/) ... + +'.' (period) + This matches any single character, _including_ the newline + character. For example, '.P' matches any single character followed + by a 'P' in a string. Using concatenation, we can make a regular + expression such as 'U.A', which matches any three-character + sequence that begins with 'U' and ends with 'A'. + + In strict POSIX mode (*note Options::), '.' does not match the NUL + character, which is a character with all bits equal to zero. + Otherwise, NUL is just another character. Other versions of 'awk' + may not be able to match the NUL character. + +'['...']' + This is called a "bracket expression".(1) It matches any _one_ of + the characters that are enclosed in the square brackets. For + example, '[MVX]' matches any one of the characters 'M', 'V', or 'X' + in a string. A full discussion of what can be inside the square + brackets of a bracket expression is given in *note Bracket + Expressions::. + +'[^'...']' + This is a "complemented bracket expression". The first character + after the '[' _must_ be a '^'. It matches any characters _except_ + those in the square brackets. For example, '[^awk]' matches any + character that is not an 'a', 'w', or 'k'. + +'|' + This is the "alternation operator" and it is used to specify + alternatives. The '|' has the lowest precedence of all the regular + expression operators. For example, '^P|[aeiouy]' matches any + string that matches either '^P' or '[aeiouy]'. This means it + matches any string that starts with 'P' or contains (anywhere + within it) a lowercase English vowel. + + The alternation applies to the largest possible regexps on either + side. + +'('...')' + Parentheses are used for grouping in regular expressions, as in + arithmetic. They can be used to concatenate regular expressions + containing the alternation operator, '|'. For example, + '@(samp|code)\{[^}]+\}' matches both '@code{foo}' and '@samp{bar}'. + (These are Texinfo formatting control sequences. The '+' is + explained further on in this list.) + +'*' + This symbol means that the preceding regular expression should be + repeated as many times as necessary to find a match. For example, + 'ph*' applies the '*' symbol to the preceding 'h' and looks for + matches of one 'p' followed by any number of 'h's. This also + matches just 'p' if no 'h's are present. + + There are two subtle points to understand about how '*' works. + First, the '*' applies only to the single preceding regular + expression component (e.g., in 'ph*', it applies just to the 'h'). + To cause '*' to apply to a larger subexpression, use parentheses: + '(ph)*' matches 'ph', 'phph', 'phphph', and so on. + + Second, '*' finds as many repetitions as possible. If the text to + be matched is 'phhhhhhhhhhhhhhooey', 'ph*' matches all of the 'h's. + +'+' + This symbol is similar to '*', except that the preceding expression + must be matched at least once. This means that 'wh+y' would match + 'why' and 'whhy', but not 'wy', whereas 'wh*y' would match all + three. + +'?' + This symbol is similar to '*', except that the preceding expression + can be matched either once or not at all. For example, 'fe?d' + matches 'fed' and 'fd', but nothing else. + +'{'N'}' +'{'N',}' +'{'N','M'}' + One or two numbers inside braces denote an "interval expression". + If there is one number in the braces, the preceding regexp is + repeated N times. If there are two numbers separated by a comma, + the preceding regexp is repeated N to M times. If there is one + number followed by a comma, then the preceding regexp is repeated + at least N times: + + 'wh{3}y' + Matches 'whhhy', but not 'why' or 'whhhhy'. + + 'wh{3,5}y' + Matches 'whhhy', 'whhhhy', or 'whhhhhy' only. + + 'wh{2,}y' + Matches 'whhy', 'whhhy', and so on. + + Interval expressions were not traditionally available in 'awk'. + They were added as part of the POSIX standard to make 'awk' and + 'egrep' consistent with each other. + + Initially, because old programs may use '{' and '}' in regexp + constants, 'gawk' did _not_ match interval expressions in regexps. + + However, beginning with version 4.0, 'gawk' does match interval + expressions by default. This is because compatibility with POSIX + has become more important to most 'gawk' users than compatibility + with old programs. + + For programs that use '{' and '}' in regexp constants, it is good + practice to always escape them with a backslash. Then the regexp + constants are valid and work the way you want them to, using any + version of 'awk'.(2) + + Finally, when '{' and '}' appear in regexp constants in a way that + cannot be interpreted as an interval expression (such as '/q{a}/'), + then they stand for themselves. + + In regular expressions, the '*', '+', and '?' operators, as well as +the braces '{' and '}', have the highest precedence, followed by +concatenation, and finally by '|'. As in arithmetic, parentheses can +change how operators are grouped. + + In POSIX 'awk' and 'gawk', the '*', '+', and '?' operators stand for +themselves when there is nothing in the regexp that precedes them. For +example, '/+/' matches a literal plus sign. However, many other +versions of 'awk' treat such a usage as a syntax error. + + If 'gawk' is in compatibility mode (*note Options::), interval +expressions are not available in regular expressions. + + ---------- Footnotes ---------- + + (1) In other literature, you may see a bracket expression referred to +as either a "character set", a "character class", or a "character list". + + (2) Use two backslashes if you're using a string constant with a +regexp operator or function. + + +File: gawk.info, Node: Bracket Expressions, Next: Leftmost Longest, Prev: Regexp Operators, Up: Regexp + +3.4 Using Bracket Expressions +============================= + +As mentioned earlier, a bracket expression matches any character among +those listed between the opening and closing square brackets. + + Within a bracket expression, a "range expression" consists of two +characters separated by a hyphen. It matches any single character that +sorts between the two characters, based upon the system's native +character set. For example, '[0-9]' is equivalent to '[0123456789]'. +(See *note Ranges and Locales:: for an explanation of how the POSIX +standard and 'gawk' have changed over time. This is mainly of +historical interest.) + + With the increasing popularity of the Unicode character standard +(http://www.unicode.org), there is an additional wrinkle to consider. +Octal and hexadecimal escape sequences inside bracket expressions are +taken to represent only single-byte characters (characters whose values +fit within the range 0-256). To match a range of characters where the +endpoints of the range are larger than 256, enter the multibyte +encodings of the characters directly. + + To include one of the characters '\', ']', '-', or '^' in a bracket +expression, put a '\' in front of it. For example: + + [d\]] + +matches either 'd' or ']'. Additionally, if you place ']' right after +the opening '[', the closing bracket is treated as one of the characters +to be matched. + + The treatment of '\' in bracket expressions is compatible with other +'awk' implementations and is also mandated by POSIX. The regular +expressions in 'awk' are a superset of the POSIX specification for +Extended Regular Expressions (EREs). POSIX EREs are based on the +regular expressions accepted by the traditional 'egrep' utility. + + "Character classes" are a feature introduced in the POSIX standard. +A character class is a special notation for describing lists of +characters that have a specific attribute, but the actual characters can +vary from country to country and/or from character set to character set. +For example, the notion of what is an alphabetic character differs +between the United States and France. + + A character class is only valid in a regexp _inside_ the brackets of +a bracket expression. Character classes consist of '[:', a keyword +denoting the class, and ':]'. *note Table 3.1: table-char-classes. +lists the character classes defined by the POSIX standard. + +Class Meaning +-------------------------------------------------------------------------- +'[:alnum:]' Alphanumeric characters +'[:alpha:]' Alphabetic characters +'[:blank:]' Space and TAB characters +'[:cntrl:]' Control characters +'[:digit:]' Numeric characters +'[:graph:]' Characters that are both printable and visible (a space is + printable but not visible, whereas an 'a' is both) +'[:lower:]' Lowercase alphabetic characters +'[:print:]' Printable characters (characters that are not control + characters) +'[:punct:]' Punctuation characters (characters that are not letters, + digits, control characters, or space characters) +'[:space:]' Space characters (such as space, TAB, and formfeed, to name + a few) +'[:upper:]' Uppercase alphabetic characters +'[:xdigit:]'Characters that are hexadecimal digits + +Table 3.1: POSIX character classes + + For example, before the POSIX standard, you had to write +'/[A-Za-z0-9]/' to match alphanumeric characters. If your character set +had other alphabetic characters in it, this would not match them. With +the POSIX character classes, you can write '/[[:alnum:]]/' to match the +alphabetic and numeric characters in your character set. + + Some utilities that match regular expressions provide a nonstandard +'[:ascii:]' character class; 'awk' does not. However, you can simulate +such a construct using '[\x00-\x7F]'. This matches all values +numerically between zero and 127, which is the defined range of the +ASCII character set. Use a complemented character list ('[^\x00-\x7F]') +to match any single-byte characters that are not in the ASCII range. + + Two additional special sequences can appear in bracket expressions. +These apply to non-ASCII character sets, which can have single symbols +(called "collating elements") that are represented with more than one +character. They can also have several characters that are equivalent +for "collating", or sorting, purposes. (For example, in French, a plain +"e" and a grave-accented "e`" are equivalent.) These sequences are: + +Collating symbols + Multicharacter collating elements enclosed between '[.' and '.]'. + For example, if 'ch' is a collating element, then '[[.ch.]]' is a + regexp that matches this collating element, whereas '[ch]' is a + regexp that matches either 'c' or 'h'. + +Equivalence classes + Locale-specific names for a list of characters that are equal. The + name is enclosed between '[=' and '=]'. For example, the name 'e' + might be used to represent all of "e," "e^," "e`," and "e'." In + this case, '[[=e=]]' is a regexp that matches any of 'e', 'e^', + 'e'', or 'e`'. + + These features are very valuable in non-English-speaking locales. + + CAUTION: The library functions that 'gawk' uses for regular + expression matching currently recognize only POSIX character + classes; they do not recognize collating symbols or equivalence + classes. + + Inside a bracket expression, an opening bracket ('[') that does not +start a character class, collating element or equivalence class is taken +literally. This is also true of '.' and '*'. + + +File: gawk.info, Node: Leftmost Longest, Next: Computed Regexps, Prev: Bracket Expressions, Up: Regexp + +3.5 How Much Text Matches? +========================== + +Consider the following: + + echo aaaabcd | awk '{ sub(/a+/, ""); print }' + + This example uses the 'sub()' function to make a change to the input +record. ('sub()' replaces the first instance of any text matched by the +first argument with the string provided as the second argument; *note +String Functions::.) Here, the regexp '/a+/' indicates "one or more 'a' +characters," and the replacement text is ''. + + The input contains four 'a' characters. 'awk' (and POSIX) regular +expressions always match the leftmost, _longest_ sequence of input +characters that can match. Thus, all four 'a' characters are replaced +with '' in this example: + + $ echo aaaabcd | awk '{ sub(/a+/, ""); print }' + -| bcd + + For simple match/no-match tests, this is not so important. But when +doing text matching and substitutions with the 'match()', 'sub()', +'gsub()', and 'gensub()' functions, it is very important. *Note String +Functions::, for more information on these functions. Understanding +this principle is also important for regexp-based record and field +splitting (*note Records::, and also *note Field Separators::). + + +File: gawk.info, Node: Computed Regexps, Next: GNU Regexp Operators, Prev: Leftmost Longest, Up: Regexp + +3.6 Using Dynamic Regexps +========================= + +The righthand side of a '~' or '!~' operator need not be a regexp +constant (i.e., a string of characters between slashes). It may be any +expression. The expression is evaluated and converted to a string if +necessary; the contents of the string are then used as the regexp. A +regexp computed in this way is called a "dynamic regexp" or a "computed +regexp": + + BEGIN { digits_regexp = "[[:digit:]]+" } + $0 ~ digits_regexp { print } + +This sets 'digits_regexp' to a regexp that describes one or more digits, +and tests whether the input record matches this regexp. + + NOTE: When using the '~' and '!~' operators, be aware that there is + a difference between a regexp constant enclosed in slashes and a + string constant enclosed in double quotes. If you are going to use + a string constant, you have to understand that the string is, in + essence, scanned _twice_: the first time when 'awk' reads your + program, and the second time when it goes to match the string on + the lefthand side of the operator with the pattern on the right. + This is true of any string-valued expression (such as + 'digits_regexp', shown in the previous example), not just string + constants. + + What difference does it make if the string is scanned twice? The +answer has to do with escape sequences, and particularly with +backslashes. To get a backslash into a regular expression inside a +string, you have to type two backslashes. + + For example, '/\*/' is a regexp constant for a literal '*'. Only one +backslash is needed. To do the same thing with a string, you have to +type '"\\*"'. The first backslash escapes the second one so that the +string actually contains the two characters '\' and '*'. + + Given that you can use both regexp and string constants to describe +regular expressions, which should you use? The answer is "regexp +constants," for several reasons: + + * String constants are more complicated to write and more difficult + to read. Using regexp constants makes your programs less + error-prone. Not understanding the difference between the two + kinds of constants is a common source of errors. + + * It is more efficient to use regexp constants. 'awk' can note that + you have supplied a regexp and store it internally in a form that + makes pattern matching more efficient. When using a string + constant, 'awk' must first convert the string into this internal + form and then perform the pattern matching. + + * Using regexp constants is better form; it shows clearly that you + intend a regexp match. + + Using '\n' in Bracket Expressions of Dynamic Regexps + + Some older versions of 'awk' do not allow the newline character to be +used inside a bracket expression for a dynamic regexp: + + $ awk '$0 ~ "[ \t\n]"' + error-> awk: newline in character class [ + error-> ]... + error-> source line number 1 + error-> context is + error-> $0 ~ "[ >>> \t\n]" <<< + + But a newline in a regexp constant works with no problem: + + $ awk '$0 ~ /[ \t\n]/' + here is a sample line + -| here is a sample line + Ctrl-d + + 'gawk' does not have this problem, and it isn't likely to occur often +in practice, but it's worth noting for future reference. + + +File: gawk.info, Node: GNU Regexp Operators, Next: Case-sensitivity, Prev: Computed Regexps, Up: Regexp + +3.7 'gawk'-Specific Regexp Operators +==================================== + +GNU software that deals with regular expressions provides a number of +additional regexp operators. These operators are described in this +minor node and are specific to 'gawk'; they are not available in other +'awk' implementations. Most of the additional operators deal with word +matching. For our purposes, a "word" is a sequence of one or more +letters, digits, or underscores ('_'): + +'\s' + Matches any whitespace character. Think of it as shorthand for + '[[:space:]]'. + +'\S' + Matches any character that is not whitespace. Think of it as + shorthand for '[^[:space:]]'. + +'\w' + Matches any word-constituent character--that is, it matches any + letter, digit, or underscore. Think of it as shorthand for + '[[:alnum:]_]'. + +'\W' + Matches any character that is not word-constituent. Think of it as + shorthand for '[^[:alnum:]_]'. + +'\<' + Matches the empty string at the beginning of a word. For example, + '/\' + Matches the empty string at the end of a word. For example, + '/stow\>/' matches 'stow' but not 'stowaway'. + +'\y' + Matches the empty string at either the beginning or the end of a + word (i.e., the word boundar*y*). For example, '\yballs?\y' + matches either 'ball' or 'balls', as a separate word. + +'\B' + Matches the empty string that occurs between two word-constituent + characters. For example, '/\Brat\B/' matches 'crate', but it does + not match 'dirty rat'. '\B' is essentially the opposite of '\y'. + + There are two other operators that work on buffers. In Emacs, a +"buffer" is, naturally, an Emacs buffer. Other GNU programs, including +'gawk', consider the entire string to match as the buffer. The +operators are: + +'\`' + Matches the empty string at the beginning of a buffer (string) + +'\'' + Matches the empty string at the end of a buffer (string) + + Because '^' and '$' always work in terms of the beginning and end of +strings, these operators don't add any new capabilities for 'awk'. They +are provided for compatibility with other GNU software. + + In other GNU software, the word-boundary operator is '\b'. However, +that conflicts with the 'awk' language's definition of '\b' as +backspace, so 'gawk' uses a different letter. An alternative method +would have been to require two backslashes in the GNU operators, but +this was deemed too confusing. The current method of using '\y' for the +GNU '\b' appears to be the lesser of two evils. + + The various command-line options (*note Options::) control how 'gawk' +interprets characters in regexps: + +No options + In the default case, 'gawk' provides all the facilities of POSIX + regexps and the GNU regexp operators described in *note Regexp + Operators::. + +'--posix' + Match only POSIX regexps; the GNU operators are not special (e.g., + '\w' matches a literal 'w'). Interval expressions are allowed. + +'--traditional' + Match traditional Unix 'awk' regexps. The GNU operators are not + special, and interval expressions are not available. Because BWK + 'awk' supports them, the POSIX character classes ('[[:alnum:]]', + etc.) are available. Characters described by octal and + hexadecimal escape sequences are treated literally, even if they + represent regexp metacharacters. + +'--re-interval' + Allow interval expressions in regexps, if '--traditional' has been + provided. Otherwise, interval expressions are available by + default. + + +File: gawk.info, Node: Case-sensitivity, Next: Regexp Summary, Prev: GNU Regexp Operators, Up: Regexp + +3.8 Case Sensitivity in Matching +================================ + +Case is normally significant in regular expressions, both when matching +ordinary characters (i.e., not metacharacters) and inside bracket +expressions. Thus, a 'w' in a regular expression matches only a +lowercase 'w' and not an uppercase 'W'. + + The simplest way to do a case-independent match is to use a bracket +expression--for example, '[Ww]'. However, this can be cumbersome if you +need to use it often, and it can make the regular expressions harder to +read. There are two alternatives that you might prefer. + + One way to perform a case-insensitive match at a particular point in +the program is to convert the data to a single case, using the +'tolower()' or 'toupper()' built-in string functions (which we haven't +discussed yet; *note String Functions::). For example: + + tolower($1) ~ /foo/ { ... } + +converts the first field to lowercase before matching against it. This +works in any POSIX-compliant 'awk'. + + Another method, specific to 'gawk', is to set the variable +'IGNORECASE' to a nonzero value (*note Built-in Variables::). When +'IGNORECASE' is not zero, _all_ regexp and string operations ignore +case. + + Changing the value of 'IGNORECASE' dynamically controls the case +sensitivity of the program as it runs. Case is significant by default +because 'IGNORECASE' (like most variables) is initialized to zero: + + x = "aB" + if (x ~ /ab/) ... # this test will fail + + IGNORECASE = 1 + if (x ~ /ab/) ... # now it will succeed + + In general, you cannot use 'IGNORECASE' to make certain rules case +insensitive and other rules case sensitive, as there is no +straightforward way to set 'IGNORECASE' just for the pattern of a +particular rule.(1) To do this, use either bracket expressions or +'tolower()'. However, one thing you can do with 'IGNORECASE' only is +dynamically turn case sensitivity on or off for all the rules at once. + + 'IGNORECASE' can be set on the command line or in a 'BEGIN' rule +(*note Other Arguments::; also *note Using BEGIN/END::). Setting +'IGNORECASE' from the command line is a way to make a program case +insensitive without having to edit it. + + In multibyte locales, the equivalences between upper- and lowercase +characters are tested based on the wide-character values of the locale's +character set. Otherwise, the characters are tested based on the +ISO-8859-1 (ISO Latin-1) character set. This character set is a +superset of the traditional 128 ASCII characters, which also provides a +number of characters suitable for use with European languages.(2) + + The value of 'IGNORECASE' has no effect if 'gawk' is in compatibility +mode (*note Options::). Case is always significant in compatibility +mode. + + ---------- Footnotes ---------- + + (1) Experienced C and C++ programmers will note that it is possible, +using something like 'IGNORECASE = 1 && /foObAr/ { ... }' and +'IGNORECASE = 0 || /foobar/ { ... }'. However, this is somewhat obscure +and we don't recommend it. + + (2) If you don't understand this, don't worry about it; it just means +that 'gawk' does the right thing. + + +File: gawk.info, Node: Regexp Summary, Prev: Case-sensitivity, Up: Regexp + +3.9 Summary +=========== + + * Regular expressions describe sets of strings to be matched. In + 'awk', regular expression constants are written enclosed between + slashes: '/'...'/'. + + * Regexp constants may be used standalone in patterns and in + conditional expressions, or as part of matching expressions using + the '~' and '!~' operators. + + * Escape sequences let you represent nonprintable characters and also + let you represent regexp metacharacters as literal characters to be + matched. + + * Regexp operators provide grouping, alternation, and repetition. + + * Bracket expressions give you a shorthand for specifying sets of + characters that can match at a particular point in a regexp. + Within bracket expressions, POSIX character classes let you specify + certain groups of characters in a locale-independent fashion. + + * Regular expressions match the leftmost longest text in the string + being matched. This matters for cases where you need to know the + extent of the match, such as for text substitution and when the + record separator is a regexp. + + * Matching expressions may use dynamic regexps (i.e., string values + treated as regular expressions). + + * 'gawk''s 'IGNORECASE' variable lets you control the case + sensitivity of regexp matching. In other 'awk' versions, use + 'tolower()' or 'toupper()'. + + +File: gawk.info, Node: Reading Files, Next: Printing, Prev: Regexp, Up: Top + +4 Reading Input Files +********************* + +In the typical 'awk' program, 'awk' reads all input either from the +standard input (by default, this is the keyboard, but often it is a pipe +from another command) or from files whose names you specify on the 'awk' +command line. If you specify input files, 'awk' reads them in order, +processing all the data from one before going on to the next. The name +of the current input file can be found in the predefined variable +'FILENAME' (*note Built-in Variables::). + + The input is read in units called "records", and is processed by the +rules of your program one record at a time. By default, each record is +one line. Each record is automatically split into chunks called +"fields". This makes it more convenient for programs to work on the +parts of a record. + + On rare occasions, you may need to use the 'getline' command. The +'getline' command is valuable both because it can do explicit input from +any number of files, and because the files used with it do not have to +be named on the 'awk' command line (*note Getline::). + +* Menu: + +* Records:: Controlling how data is split into records. +* Fields:: An introduction to fields. +* Nonconstant Fields:: Nonconstant Field Numbers. +* Changing Fields:: Changing the Contents of a Field. +* 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. +* Input Exercises:: Exercises. + + +File: gawk.info, Node: Records, Next: Fields, Up: Reading Files + +4.1 How Input Is Split into Records +=================================== + +'awk' divides the input for your program into records and fields. It +keeps track of the number of records that have been read so far from the +current input file. This value is stored in a predefined variable +called 'FNR', which is reset to zero every time a new file is started. +Another predefined variable, 'NR', records the total number of input +records read so far from all data files. It starts at zero, but is +never automatically reset to zero. + +* Menu: + +* awk split records:: How standard 'awk' splits records. +* gawk split records:: How 'gawk' splits records. + + +File: gawk.info, Node: awk split records, Next: gawk split records, Up: Records + +4.1.1 Record Splitting with Standard 'awk' +------------------------------------------ + +Records are separated by a character called the "record separator". By +default, the record separator is the newline character. This is why +records are, by default, single lines. To use a different character for +the record separator, simply assign that character to the predefined +variable 'RS'. + + Like any other variable, the value of 'RS' can be changed in the +'awk' program with the assignment operator, '=' (*note Assignment +Ops::). The new record-separator character should be enclosed in +quotation marks, which indicate a string constant. Often, the right +time to do this is at the beginning of execution, before any input is +processed, so that the very first record is read with the proper +separator. To do this, use the special 'BEGIN' pattern (*note +BEGIN/END::). For example: + + awk 'BEGIN { RS = "u" } + { print $0 }' mail-list + +changes the value of 'RS' to 'u', before reading any input. The new +value is a string whose first character is the letter "u"; as a result, +records are separated by the letter "u". Then the input file is read, +and the second rule in the 'awk' program (the action with no pattern) +prints each record. Because each 'print' statement adds a newline at +the end of its output, this 'awk' program copies the input with each 'u' +changed to a newline. Here are the results of running the program on +'mail-list': + + $ awk 'BEGIN { RS = "u" } + > { print $0 }' mail-list + -| Amelia 555-5553 amelia.zodiac + -| sq + -| e@gmail.com F + -| Anthony 555-3412 anthony.assert + -| ro@hotmail.com A + -| Becky 555-7685 becky.algebrar + -| m@gmail.com A + -| Bill 555-1675 bill.drowning@hotmail.com A + -| Broderick 555-0542 broderick.aliq + -| otiens@yahoo.com R + -| Camilla 555-2912 camilla.inf + -| sar + -| m@skynet.be R + -| Fabi + -| s 555-1234 fabi + -| s. + -| ndevicesim + -| s@ + -| cb.ed + -| F + -| J + -| lie 555-6699 j + -| lie.perscr + -| tabor@skeeve.com F + -| Martin 555-6480 martin.codicib + -| s@hotmail.com A + -| Sam + -| el 555-3430 sam + -| el.lanceolis@sh + -| .ed + -| A + -| Jean-Pa + -| l 555-2127 jeanpa + -| l.campanor + -| m@ny + -| .ed + -| R + -| + +Note that the entry for the name 'Bill' is not split. In the original +data file (*note Sample Data Files::), the line looks like this: + + Bill 555-1675 bill.drowning@hotmail.com A + +It contains no 'u', so there is no reason to split the record, unlike +the others, which each have one or more occurrences of the 'u'. In +fact, this record is treated as part of the previous record; the newline +separating them in the output is the original newline in the data file, +not the one added by 'awk' when it printed the record! + + Another way to change the record separator is on the command line, +using the variable-assignment feature (*note Other Arguments::): + + awk '{ print $0 }' RS="u" mail-list + +This sets 'RS' to 'u' before processing 'mail-list'. + + Using an alphabetic character such as 'u' for the record separator is +highly likely to produce strange results. Using an unusual character +such as '/' is more likely to produce correct behavior in the majority +of cases, but there are no guarantees. The moral is: Know Your Data. + + When using regular characters as the record separator, there is one +unusual case that occurs when 'gawk' is being fully POSIX-compliant +(*note Options::). Then, the following (extreme) pipeline prints a +surprising '1': + + $ echo | gawk --posix 'BEGIN { RS = "a" } ; { print NF }' + -| 1 + + There is one field, consisting of a newline. The value of the +built-in variable 'NF' is the number of fields in the current record. +(In the normal case, 'gawk' treats the newline as whitespace, printing +'0' as the result. Most other versions of 'awk' also act this way.) + + Reaching the end of an input file terminates the current input +record, even if the last character in the file is not the character in +'RS'. (d.c.) + + The empty string '""' (a string without any characters) has a special +meaning as the value of 'RS'. It means that records are separated by +one or more blank lines and nothing else. *Note Multiple Line:: for +more details. + + If you change the value of 'RS' in the middle of an 'awk' run, the +new value is used to delimit subsequent records, but the record +currently being processed, as well as records already processed, are not +affected. + + After the end of the record has been determined, 'gawk' sets the +variable 'RT' to the text in the input that matched 'RS'. + + +File: gawk.info, Node: gawk split records, Prev: awk split records, Up: Records + +4.1.2 Record Splitting with 'gawk' +---------------------------------- + +When using 'gawk', the value of 'RS' is not limited to a one-character +string. It can be any regular expression (*note Regexp::). (c.e.) In +general, each record ends at the next string that matches the regular +expression; the next record starts at the end of the matching string. +This general rule is actually at work in the usual case, where 'RS' +contains just a newline: a record ends at the beginning of the next +matching string (the next newline in the input), and the following +record starts just after the end of this string (at the first character +of the following line). The newline, because it matches 'RS', is not +part of either record. + + When 'RS' is a single character, 'RT' contains the same single +character. However, when 'RS' is a regular expression, 'RT' contains +the actual input text that matched the regular expression. + + If the input file ends without any text matching 'RS', 'gawk' sets +'RT' to the null string. + + The following example illustrates both of these features. It sets +'RS' equal to a regular expression that matches either a newline or a +series of one or more uppercase letters with optional leading and/or +trailing whitespace: + + $ echo record 1 AAAA record 2 BBBB record 3 | + > gawk 'BEGIN { RS = "\n|( *[[:upper:]]+ *)" } + > { print "Record =", $0,"and RT = [" RT "]" }' + -| Record = record 1 and RT = [ AAAA ] + -| Record = record 2 and RT = [ BBBB ] + -| Record = record 3 and RT = [ + -| ] + +The square brackets delineate the contents of 'RT', letting you see the +leading and trailing whitespace. The final value of 'RT' is a newline. +*Note Simple Sed:: for a more useful example of 'RS' as a regexp and +'RT'. + + If you set 'RS' to a regular expression that allows optional trailing +text, such as 'RS = "abc(XYZ)?"', it is possible, due to implementation +constraints, that 'gawk' may match the leading part of the regular +expression, but not the trailing part, particularly if the input text +that could match the trailing part is fairly long. 'gawk' attempts to +avoid this problem, but currently, there's no guarantee that this will +never happen. + + NOTE: Remember that in 'awk', the '^' and '$' anchor metacharacters + match the beginning and end of a _string_, and not the beginning + and end of a _line_. As a result, something like 'RS = + "^[[:upper:]]"' can only match at the beginning of a file. This is + because 'gawk' views the input file as one long string that happens + to contain newline characters. It is thus best to avoid anchor + metacharacters in the value of 'RS'. + + The use of 'RS' as a regular expression and the 'RT' variable are +'gawk' extensions; they are not available in compatibility mode (*note +Options::). In compatibility mode, only the first character of the +value of 'RS' determines the end of the record. + + 'RS = "\0"' Is Not Portable + + There are times when you might want to treat an entire data file as a +single record. The only way to make this happen is to give 'RS' a value +that you know doesn't occur in the input file. This is hard to do in a +general way, such that a program always works for arbitrary input files. + + You might think that for text files, the NUL character, which +consists of a character with all bits equal to zero, is a good value to +use for 'RS' in this case: + + BEGIN { RS = "\0" } # whole file becomes one record? + + 'gawk' in fact accepts this, and uses the NUL character for the +record separator. This works for certain special files, such as +'/proc/environ' on GNU/Linux systems, where the NUL character is in fact +the record separator. However, this usage is _not_ portable to most +other 'awk' implementations. + + Almost all other 'awk' implementations(1) store strings internally as +C-style strings. C strings use the NUL character as the string +terminator. In effect, this means that 'RS = "\0"' is the same as 'RS = +""'. (d.c.) + + It happens that recent versions of 'mawk' can use the NUL character +as a record separator. However, this is a special case: 'mawk' does not +allow embedded NUL characters in strings. (This may change in a future +version of 'mawk'.) + + *Note Readfile Function:: for an interesting way to read whole files. +If you are using 'gawk', see *note Extension Sample Readfile:: for +another option. + + ---------- Footnotes ---------- + + (1) At least that we know about. + + +File: gawk.info, Node: Fields, Next: Nonconstant Fields, Prev: Records, Up: Reading Files + +4.2 Examining Fields +==================== + +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; other characters that are considered whitespace by other +languages (such as formfeed, vertical tab, etc.) are _not_ considered +whitespace by 'awk'. + + The purpose of fields is to make it more convenient for you to refer +to these pieces of the record. You don't have to use them--you can +operate on the whole record if you want--but fields are what make simple +'awk' programs so powerful. + + You use a dollar sign ('$') to refer to a field in an 'awk' program, +followed by the number of the field you want. Thus, '$1' refers to the +first field, '$2' to the second, and so on. (Unlike in the Unix shells, +the field numbers are not limited to single digits. '$127' is the 127th +field in the record.) For example, suppose the following is a line of +input: + + This seems like a pretty nice example. + +Here the first field, or '$1', is 'This', the second field, or '$2', is +'seems', and so on. Note that the last field, '$7', is 'example.'. +Because there is no space between the 'e' and the '.', the period is +considered part of the seventh field. + + 'NF' is a predefined variable whose value is the number of fields in +the current record. 'awk' automatically updates the value of 'NF' each +time it reads a record. No matter how many fields there are, the last +field in a record can be represented by '$NF'. So, '$NF' is the same as +'$7', which is 'example.'. If you try to reference a field beyond the +last one (such as '$8' when the record has only seven fields), you get +the empty string. (If used in a numeric operation, you get zero.) + + The use of '$0', which looks like a reference to the "zeroth" field, +is a special case: it represents the whole input record. Use it when +you are not interested in specific fields. Here are some more examples: + + $ awk '$1 ~ /li/ { print $0 }' mail-list + -| Amelia 555-5553 amelia.zodiacusque@gmail.com F + -| Julie 555-6699 julie.perscrutabor@skeeve.com F + +This example prints each record in the file 'mail-list' whose first +field contains the string 'li'. + + By contrast, the following example looks for 'li' in _the entire +record_ and prints the first and last fields for each matching input +record: + + $ awk '/li/ { print $1, $NF }' mail-list + -| Amelia F + -| Broderick R + -| Julie F + -| Samuel A + + +File: gawk.info, Node: Nonconstant Fields, Next: Changing Fields, Prev: Fields, Up: Reading Files + +4.3 Nonconstant Field Numbers +============================= + +A field number need not be a constant. Any expression in the 'awk' +language can be used after a '$' to refer to a field. The value of the +expression specifies the field number. If the value is a string, rather +than a number, it is converted to a number. Consider this example: + + awk '{ print $NR }' + +Recall that 'NR' is the number of records read so far: one in the first +record, two in the second, and so on. So this example prints the first +field of the first record, the second field of the second record, and so +on. For the twentieth record, field number 20 is printed; most likely, +the record has fewer than 20 fields, so this prints a blank line. Here +is another example of using expressions as field numbers: + + awk '{ print $(2*2) }' mail-list + + 'awk' evaluates the expression '(2*2)' and uses its value as the +number of the field to print. The '*' represents multiplication, so the +expression '2*2' evaluates to four. The parentheses are used so that +the multiplication is done before the '$' operation; they are necessary +whenever there is a binary operator(1) in the field-number expression. +This example, then, prints the type of relationship (the fourth field) +for every line of the file 'mail-list'. (All of the 'awk' operators are +listed, in order of decreasing precedence, in *note Precedence::.) + + If the field number you compute is zero, you get the entire record. +Thus, '$(2-2)' has the same value as '$0'. Negative field numbers are +not allowed; trying to reference one usually terminates the program. +(The POSIX standard does not define what happens when you reference a +negative field number. 'gawk' notices this and terminates your program. +Other 'awk' implementations may behave differently.) + + As mentioned in *note Fields::, 'awk' stores the current record's +number of fields in the built-in variable 'NF' (also *note Built-in +Variables::). Thus, the expression '$NF' is not a special feature--it +is the direct consequence of evaluating 'NF' and using its value as a +field number. + + ---------- Footnotes ---------- + + (1) A "binary operator", such as '*' for multiplication, is one that +takes two operands. The distinction is required because 'awk' also has +unary (one-operand) and ternary (three-operand) operators. + + +File: gawk.info, Node: Changing Fields, Next: Field Separators, Prev: Nonconstant Fields, Up: Reading Files + +4.4 Changing the Contents of a Field +==================================== + +The contents of a field, as seen by 'awk', can be changed within an +'awk' program; this changes what 'awk' perceives as the current input +record. (The actual input is untouched; 'awk' _never_ modifies the +input file.) Consider the following example and its output: + + $ awk '{ nboxes = $3 ; $3 = $3 - 10 + > print nboxes, $3 }' inventory-shipped + -| 25 15 + -| 32 22 + -| 24 14 + ... + +The program first saves the original value of field three in the +variable 'nboxes'. The '-' sign represents subtraction, so this program +reassigns field three, '$3', as the original value of field three minus +ten: '$3 - 10'. (*Note Arithmetic Ops::.) Then it prints the original +and new values for field three. (Someone in the warehouse made a +consistent mistake while inventorying the red boxes.) + + For this to work, the text in '$3' must make sense as a number; the +string of characters must be converted to a number for the computer to +do arithmetic on it. The number resulting from the subtraction is +converted back to a string of characters that then becomes field three. +*Note Conversion::. + + When the value of a field is changed (as perceived by 'awk'), the +text of the input record is recalculated to contain the new field where +the old one was. In other words, '$0' changes to reflect the altered +field. Thus, this program prints a copy of the input file, with 10 +subtracted from the second field of each line: + + $ awk '{ $2 = $2 - 10; print $0 }' inventory-shipped + -| Jan 3 25 15 115 + -| Feb 5 32 24 226 + -| Mar 5 24 34 228 + ... + + It is also possible to assign contents to fields that are out of +range. For example: + + $ awk '{ $6 = ($5 + $4 + $3 + $2) + > print $6 }' inventory-shipped + -| 168 + -| 297 + -| 301 + ... + +We've just created '$6', whose value is the sum of fields '$2', '$3', +'$4', and '$5'. The '+' sign represents addition. For the file +'inventory-shipped', '$6' represents the total number of parcels shipped +for a particular month. + + Creating a new field changes 'awk''s internal copy of the current +input record, which is the value of '$0'. Thus, if you do 'print $0' +after adding a field, the record printed includes the new field, with +the appropriate number of field separators between it and the previously +existing fields. + + This recomputation affects and is affected by 'NF' (the number of +fields; *note Fields::). For example, the value of 'NF' is set to the +number of the highest field you create. The exact format of '$0' is +also affected by a feature that has not been discussed yet: the "output +field separator", 'OFS', used to separate the fields (*note Output +Separators::). + + Note, however, that merely _referencing_ an out-of-range field does +_not_ change the value of either '$0' or 'NF'. Referencing an +out-of-range field only produces an empty string. For example: + + if ($(NF+1) != "") + print "can't happen" + else + print "everything is normal" + +should print 'everything is normal', because 'NF+1' is certain to be out +of range. (*Note If Statement:: for more information about 'awk''s +'if-else' statements. *Note Typing and Comparison:: for more +information about the '!=' operator.) + + It is important to note that making an assignment to an existing +field changes the value of '$0' but does not change the value of 'NF', +even when you assign the empty string to a field. For example: + + $ echo a b c d | awk '{ OFS = ":"; $2 = "" + > print $0; print NF }' + -| a::c:d + -| 4 + +The field is still there; it just has an empty value, delimited by the +two colons between 'a' and 'c'. This example shows what happens if you +create a new field: + + $ echo a b c d | awk '{ OFS = ":"; $2 = ""; $6 = "new" + > print $0; print NF }' + -| a::c:d::new + -| 6 + +The intervening field, '$5', is created with an empty value (indicated +by the second pair of adjacent colons), and 'NF' is updated with the +value six. + + Decrementing 'NF' throws away the values of the fields after the new +value of 'NF' and recomputes '$0'. (d.c.) Here is an example: + + $ echo a b c d e f | awk '{ print "NF =", NF; + > NF = 3; print $0 }' + -| NF = 6 + -| a b c + + CAUTION: Some versions of 'awk' don't rebuild '$0' when 'NF' is + decremented. + + Finally, there are times when it is convenient to force 'awk' to +rebuild the entire record, using the current values of the fields and +'OFS'. To do this, use the seemingly innocuous assignment: + + $1 = $1 # force record to be reconstituted + print $0 # or whatever else with $0 + +This forces 'awk' to rebuild the record. It does help to add a comment, +as we've shown here. + + There is a flip side to the relationship between '$0' and the fields. +Any assignment to '$0' causes the record to be reparsed into fields +using the _current_ value of 'FS'. This also applies to any built-in +function that updates '$0', such as 'sub()' and 'gsub()' (*note String +Functions::). + + Understanding '$0' + + It is important to remember that '$0' is the _full_ record, exactly +as it was read from the input. This includes any leading or trailing +whitespace, and the exact whitespace (or other characters) that +separates the fields. + + It is a common error to try to change the field separators in a +record simply by setting 'FS' and 'OFS', and then expecting a plain +'print' or 'print $0' to print the modified record. + + But this does not work, because nothing was done to change the record +itself. Instead, you must force the record to be rebuilt, typically +with a statement such as '$1 = $1', as described earlier. + + +File: gawk.info, Node: Field Separators, Next: Constant Size, Prev: Changing Fields, Up: Reading Files + +4.5 Specifying How Fields Are Separated +======================================= + +* Menu: + +* Default Field Splitting:: How fields are normally separated. +* Regexp Field Splitting:: Using regexps as the field separator. +* Single Character Fields:: Making each character a separate field. +* Command Line Field Separator:: Setting 'FS' from the command line. +* Full Line Fields:: Making the full line be a single field. +* Field Splitting Summary:: Some final points and a summary table. + +The "field separator", which is either a single character or a regular +expression, controls the way 'awk' splits an input record into fields. +'awk' scans the input record for character sequences that match the +separator; the fields themselves are the text between the matches. + + In the examples that follow, we use the bullet symbol (*) to +represent spaces in the output. If the field separator is 'oo', then +the following line: + + moo goo gai pan + +is split into three fields: 'm', '*g', and '*gai*pan'. Note the leading +spaces in the values of the second and third fields. + + The field separator is represented by the predefined variable 'FS'. +Shell programmers take note: 'awk' does _not_ use the name 'IFS' that is +used by the POSIX-compliant shells (such as the Unix Bourne shell, 'sh', +or Bash). + + The value of 'FS' can be changed in the 'awk' program with the +assignment operator, '=' (*note Assignment Ops::). Often, the right +time to do this is at the beginning of execution before any input has +been processed, so that the very first record is read with the proper +separator. To do this, use the special 'BEGIN' pattern (*note +BEGIN/END::). For example, here we set the value of 'FS' to the string +'","': + + awk 'BEGIN { FS = "," } ; { print $2 }' + +Given the input line: + + John Q. Smith, 29 Oak St., Walamazoo, MI 42139 + +this 'awk' program extracts and prints the string '*29*Oak*St.'. + + Sometimes the input data contains separator characters that don't +separate fields the way you thought they would. For instance, the +person's name in the example we just used might have a title or suffix +attached, such as: + + John Q. Smith, LXIX, 29 Oak St., Walamazoo, MI 42139 + +The same program would extract '*LXIX' instead of '*29*Oak*St.'. If you +were expecting the program to print the address, you would be surprised. +The moral is to choose your data layout and separator characters +carefully to prevent such problems. (If the data is not in a form that +is easy to process, perhaps you can massage it first with a separate +'awk' program.) + + +File: gawk.info, Node: Default Field Splitting, Next: Regexp Field Splitting, Up: Field Separators + +4.5.1 Whitespace Normally Separates Fields +------------------------------------------ + +Fields are normally separated by whitespace sequences (spaces, TABs, and +newlines), not by single spaces. Two spaces in a row do not delimit an +empty field. The default value of the field separator 'FS' is a string +containing a single space, '" "'. If 'awk' interpreted this value in +the usual way, each space character would separate fields, so two spaces +in a row would make an empty field between them. The reason this does +not happen is that a single space as the value of 'FS' is a special +case--it is taken to specify the default manner of delimiting fields. + + If 'FS' is any other single character, such as '","', then each +occurrence of that character separates two fields. Two consecutive +occurrences delimit an empty field. If the character occurs at the +beginning or the end of the line, that too delimits an empty field. The +space character is the only single character that does not follow these +rules. + + +File: gawk.info, Node: Regexp Field Splitting, Next: Single Character Fields, Prev: Default Field Splitting, Up: Field Separators + +4.5.2 Using Regular Expressions to Separate Fields +-------------------------------------------------- + +The previous node discussed the use of single characters or simple +strings as the value of 'FS'. More generally, the value of 'FS' may be +a string containing any regular expression. In this case, each match in +the record for the regular expression separates fields. For example, +the assignment: + + FS = ", \t" + +makes every area of an input line that consists of a comma followed by a +space and a TAB into a field separator. ('\t' is an "escape sequence" +that stands for a TAB; *note Escape Sequences::, for the complete list +of similar escape sequences.) + + For a less trivial example of a regular expression, try using single +spaces to separate fields the way single commas are used. 'FS' can be +set to '"[ ]"' (left bracket, space, right bracket). This regular +expression matches a single space and nothing else (*note Regexp::). + + There is an important difference between the two cases of 'FS = " "' +(a single space) and 'FS = "[ \t\n]+"' (a regular expression matching +one or more spaces, TABs, or newlines). For both values of 'FS', fields +are separated by "runs" (multiple adjacent occurrences) of spaces, TABs, +and/or newlines. However, when the value of 'FS' is '" "', 'awk' first +strips leading and trailing whitespace from the record and then decides +where the fields are. For example, the following pipeline prints 'b': + + $ echo ' a b c d ' | awk '{ print $2 }' + -| b + +However, this pipeline prints 'a' (note the extra spaces around each +letter): + + $ echo ' a b c d ' | awk 'BEGIN { FS = "[ \t\n]+" } + > { print $2 }' + -| a + +In this case, the first field is null, or empty. + + The stripping of leading and trailing whitespace also comes into play +whenever '$0' is recomputed. For instance, study this pipeline: + + $ echo ' a b c d' | awk '{ print; $2 = $2; print }' + -| a b c d + -| a b c d + +The first 'print' statement prints the record as it was read, with +leading whitespace intact. The assignment to '$2' rebuilds '$0' by +concatenating '$1' through '$NF' together, separated by the value of +'OFS' (which is a space by default). Because the leading whitespace was +ignored when finding '$1', it is not part of the new '$0'. Finally, the +last 'print' statement prints the new '$0'. + + There is an additional subtlety to be aware of when using regular +expressions for field splitting. It is not well specified in the POSIX +standard, or anywhere else, what '^' means when splitting fields. Does +the '^' match only at the beginning of the entire record? Or is each +field separator a new string? It turns out that different 'awk' +versions answer this question differently, and you should not rely on +any specific behavior in your programs. (d.c.) + + As a point of information, BWK 'awk' allows '^' to match only at the +beginning of the record. 'gawk' also works this way. For example: + + $ echo 'xxAA xxBxx C' | + > gawk -F '(^x+)|( +)' '{ for (i = 1; i <= NF; i++) + > printf "-->%s<--\n", $i }' + -| --><-- + -| -->AA<-- + -| -->xxBxx<-- + -| -->C<-- + + +File: gawk.info, Node: Single Character Fields, Next: Command Line Field Separator, Prev: Regexp Field Splitting, Up: Field Separators + +4.5.3 Making Each Character a Separate Field +-------------------------------------------- + +There are times when you may want to examine each character of a record +separately. This can be done in 'gawk' by simply assigning the null +string ('""') to 'FS'. (c.e.) In this case, each individual character +in the record becomes a separate field. For example: + + $ echo a b | gawk 'BEGIN { FS = "" } + > { + > for (i = 1; i <= NF; i = i + 1) + > print "Field", i, "is", $i + > }' + -| Field 1 is a + -| Field 2 is + -| Field 3 is b + + Traditionally, the behavior of 'FS' equal to '""' was not defined. +In this case, most versions of Unix 'awk' simply treat the entire record +as only having one field. (d.c.) In compatibility mode (*note +Options::), if 'FS' is the null string, then 'gawk' also behaves this +way. + + +File: gawk.info, Node: Command Line Field Separator, Next: Full Line Fields, Prev: Single Character Fields, Up: Field Separators + +4.5.4 Setting 'FS' from the Command Line +---------------------------------------- + +'FS' can be set on the command line. Use the '-F' option to do so. For +example: + + awk -F, 'PROGRAM' INPUT-FILES + +sets 'FS' to the ',' character. Notice that the option uses an +uppercase 'F' instead of a lowercase 'f'. The latter option ('-f') +specifies a file containing an 'awk' program. + + The value used for the argument to '-F' is processed in exactly the +same way as assignments to the predefined variable 'FS'. Any special +characters in the field separator must be escaped appropriately. For +example, to use a '\' as the field separator on the command line, you +would have to type: + + # same as FS = "\\" + awk -F\\\\ '...' files ... + +Because '\' is used for quoting in the shell, 'awk' sees '-F\\'. Then +'awk' processes the '\\' for escape characters (*note Escape +Sequences::), finally yielding a single '\' to use for the field +separator. + + As a special case, in compatibility mode (*note Options::), if the +argument to '-F' is 't', then 'FS' is set to the TAB character. If you +type '-F\t' at the shell, without any quotes, the '\' gets deleted, so +'awk' figures that you really want your fields to be separated with TABs +and not 't's. Use '-v FS="t"' or '-F"[t]"' on the command line if you +really do want to separate your fields with 't's. Use '-F '\t'' when +not in compatibility mode to specify that TABs separate fields. + + As an example, let's use an 'awk' program file called 'edu.awk' that +contains the pattern '/edu/' and the action 'print $1': + + /edu/ { print $1 } + + Let's also set 'FS' to be the '-' character and run the program on +the file 'mail-list'. The following command prints a list of the names +of the people that work at or attend a university, and the first three +digits of their phone numbers: + + $ awk -F- -f edu.awk mail-list + -| Fabius 555 + -| Samuel 555 + -| Jean + +Note the third line of output. The third line in the original file +looked like this: + + Jean-Paul 555-2127 jeanpaul.campanorum@nyu.edu R + + The '-' as part of the person's name was used as the field separator, +instead of the '-' in the phone number that was originally intended. +This demonstrates why you have to be careful in choosing your field and +record separators. + + Perhaps the most common use of a single character as the field +separator occurs when processing the Unix system password file. On many +Unix systems, each user has a separate entry in the system password +file, with one line per user. The information in these lines is +separated by colons. The first field is the user's login name and the +second is the user's encrypted or shadow password. (A shadow password +is indicated by the presence of a single 'x' in the second field.) A +password file entry might look like this: + + arnold:x:2076:10:Arnold Robbins:/home/arnold:/bin/bash + + The following program searches the system password file and prints +the entries for users whose full name is not indicated: + + awk -F: '$5 == ""' /etc/passwd + + +File: gawk.info, Node: Full Line Fields, Next: Field Splitting Summary, Prev: Command Line Field Separator, Up: Field Separators + +4.5.5 Making the Full Line Be a Single Field +-------------------------------------------- + +Occasionally, it's useful to treat the whole input line as a single +field. This can be done easily and portably simply by setting 'FS' to +'"\n"' (a newline):(1) + + awk -F'\n' 'PROGRAM' FILES ... + +When you do this, '$1' is the same as '$0'. + + Changing 'FS' Does Not Affect the Fields + + According to the POSIX standard, 'awk' is supposed to behave as if +each record is split into fields at the time it is read. In particular, +this means that if you change the value of 'FS' after a record is read, +the values of the fields (i.e., how they were split) should reflect the +old value of 'FS', not the new one. + + However, many older implementations of 'awk' do not work this way. +Instead, they defer splitting the fields until a field is actually +referenced. The fields are split using the _current_ value of 'FS'! +(d.c.) This behavior can be difficult to diagnose. The following +example illustrates the difference between the two methods: + + sed 1q /etc/passwd | awk '{ FS = ":" ; print $1 }' + +which usually prints: + + root + +on an incorrect implementation of 'awk', while 'gawk' prints the full +first line of the file, something like: + + root:x:0:0:Root:/: + + (The 'sed'(2) command prints just the first line of '/etc/passwd'.) + + ---------- Footnotes ---------- + + (1) Thanks to Andrew Schorr for this tip. + + (2) The 'sed' utility is a "stream editor." Its behavior is also +defined by the POSIX standard. + + +File: gawk.info, Node: Field Splitting Summary, Prev: Full Line Fields, Up: Field Separators + +4.5.6 Field-Splitting Summary +----------------------------- + +It is important to remember that when you assign a string constant as +the value of 'FS', it undergoes normal 'awk' string processing. For +example, with Unix 'awk' and 'gawk', the assignment 'FS = "\.."' assigns +the character string '".."' to 'FS' (the backslash is stripped). This +creates a regexp meaning "fields are separated by occurrences of any two +characters." If instead you want fields to be separated by a literal +period followed by any single character, use 'FS = "\\.."'. + + The following list summarizes how fields are split, based on the +value of 'FS' ('==' means "is equal to"): + +'FS == " "' + Fields are separated by runs of whitespace. Leading and trailing + whitespace are ignored. This is the default. + +'FS == ANY OTHER SINGLE CHARACTER' + Fields are separated by each occurrence of the character. Multiple + successive occurrences delimit empty fields, as do leading and + trailing occurrences. The character can even be a regexp + metacharacter; it does not need to be escaped. + +'FS == REGEXP' + Fields are separated by occurrences of characters that match + REGEXP. Leading and trailing matches of REGEXP delimit empty + fields. + +'FS == ""' + Each individual character in the record becomes a separate field. + (This is a common extension; it is not specified by the POSIX + standard.) + + 'FS' and 'IGNORECASE' + + The 'IGNORECASE' variable (*note User-modified::) affects field +splitting _only_ when the value of 'FS' is a regexp. It has no effect +when 'FS' is a single character, even if that character is a letter. +Thus, in the following code: + + FS = "c" + IGNORECASE = 1 + $0 = "aCa" + print $1 + +The output is 'aCa'. If you really want to split fields on an +alphabetic character while ignoring case, use a regexp that will do it +for you (e.g., 'FS = "[c]"'). In this case, 'IGNORECASE' will take +effect. + + +File: gawk.info, Node: Constant Size, Next: Splitting By Content, Prev: Field Separators, Up: Reading Files + +4.6 Reading Fixed-Width Data +============================ + +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. 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 +spaces_. Clearly, 'awk''s normal field splitting based on 'FS' does not +work well in this case. Although a portable 'awk' program can use a +series of 'substr()' calls on '$0' (*note String Functions::), this is +awkward and inefficient for a large number of fields. + + 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 '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': + + 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 + + The following program takes this input, converts the idle time to +number of seconds, and prints out the first two fields and the +calculated idle time: + + BEGIN { FIELDWIDTHS = "9 6 10 6 7 7 35" } + NR > 2 { + idle = $4 + sub(/^ +/, "", idle) # strip leading spaces + if (idle == "") + idle = 0 + if (idle ~ /:/) { # hh:mm + split(idle, t, ":") + idle = t[1] * 60 + t[2] + } + if (idle ~ /days/) + idle *= 24 * 60 * 60 + + print $1, $2, idle + } + + NOTE: The preceding program uses a number of 'awk' features that + haven't been introduced yet. + + Running the program on the data produces the following results: + + hzuo ttyV0 0 + hzang ttyV3 50 + eklye ttyV5 0 + dportein ttyV6 107 + gierd ttyD3 1 + dave ttyD4 0 + brent ttyp0 286 + dave ttyq4 1296000 + + Another (possibly more practical) example of fixed-width input data +is the input from a deck of balloting cards. In some parts of the +United States, voters mark their choices by punching holes in computer +cards. These cards are then processed to count the votes for any +particular candidate or on any particular issue. Because a voter may +choose not to vote on some issue, any column on the card may be empty. +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!) + + +File: gawk.info, Node: Skipping intervening, Next: Allowing trailing data, Prev: Fixed width data, Up: Constant Size + +4.6.2 Skipping Intervening Fields +--------------------------------- + +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: 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 +============================== + +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. + + Normally, when using 'FS', 'gawk' defines the fields as the parts of +the record that occur in between each field separator. In other words, +'FS' defines what a field _is not_, instead of what a field _is_. +However, there are times when you really want to define the fields by +what they are, and not by what they are not. + + The most notorious such case is so-called "comma-separated values" +(CSV) data. Many spreadsheet programs, for example, can export their +data into text files, where each record is terminated with a newline, +and fields are separated by commas. If commas only separated the data, +there wouldn't be an issue. The problem comes when one of the fields +contains an _embedded_ comma. In such cases, most programs embed the +field in double quotes.(1) So, we might have data like this: + + Robbins,Arnold,"1234 A Pretty Street, NE",MyTown,MyState,12345-6789,USA + + The 'FPAT' variable offers a solution for cases like this. The value +of 'FPAT' should be a string that provides a regular expression. This +regular expression describes the contents of each field. + + In the case of CSV data as presented here, each field is either +"anything that is not a comma," or "a double quote, anything that is not +a double quote, and a closing double quote." If written as a regular +expression constant (*note Regexp::), we would have +'/([^,]+)|("[^"]+")/'. Writing this as a string requires us to escape +the double quotes, leading to: + + FPAT = "([^,]+)|(\"[^\"]+\")" + + Putting this to use, here is a simple program to parse the data: + + BEGIN { + FPAT = "([^,]+)|(\"[^\"]+\")" + } + + { + print "NF = ", NF + for (i = 1; i <= NF; i++) { + printf("$%d = <%s>\n", i, $i) + } + } + + When run, we get the following: + + $ gawk -f simple-csv.awk addresses.csv + NF = 7 + $1 = + $2 = + $3 = <"1234 A Pretty Street, NE"> + $4 = + $5 = + $6 = <12345-6789> + $7 = + + Note the embedded comma in the value of '$3'. + + A straightforward improvement when processing CSV data of this sort +would be to remove the quotes when they occur, with something like this: + + if (substr($i, 1, 1) == "\"") { + len = length($i) + $i = substr($i, 2, len - 2) # Get text within the two quotes + } + + As with 'FS', the 'IGNORECASE' variable (*note User-modified::) +affects field splitting with 'FPAT'. + + Assigning a value to 'FPAT' overrides field splitting with 'FS' and +with 'FIELDWIDTHS'. + + NOTE: Some programs export CSV data that contains embedded newlines + between the double quotes. 'gawk' provides no way to deal with + this. Even though a formal specification for CSV data exists, + there isn't much more to be done; the 'FPAT' mechanism provides an + elegant solution for the majority of cases, and the 'gawk' + developers are satisfied with that. + + As written, the regexp used for 'FPAT' requires that each field +contain at least one character. A straightforward modification +(changing the first '+' to '*') allows fields to be empty: + + FPAT = "([^,]*)|(\"[^\"]+\")" + + Finally, the 'patsplit()' function makes the same functionality +available for splitting regular strings (*note String Functions::). + + ---------- Footnotes ---------- + + (1) The CSV format lacked a formal standard definition for many +years. RFC 4180 (http://www.ietf.org/rfc/rfc4180.txt) standardizes the +most common practices. + + +File: gawk.info, Node: Testing field creation, Next: Multiple Line, Prev: Splitting By Content, Up: Reading Files + +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 +information in one entry. In such cases, you can use multiline records. +The first step in doing this is to choose your data format. + + One technique is to use an unusual character or string to separate +records. For example, you could use the formfeed character (written +'\f' in 'awk', as in C) to separate them, making each record a page of +the file. To do this, just set the variable 'RS' to '"\f"' (a string +containing the formfeed character). Any other character could equally +well be used, as long as it won't be part of the data in a record. + + Another technique is to have blank lines separate records. By a +special dispensation, an empty string as the value of 'RS' indicates +that records are separated by one or more blank lines. When 'RS' is set +to the empty string, each record always ends at the first blank line +encountered. The next record doesn't start until the first nonblank +line that follows. No matter how many blank lines appear in a row, they +all act as one record separator. (Blank lines must be completely empty; +lines that contain only whitespace do not count.) + + You can achieve the same effect as 'RS = ""' by assigning the string +'"\n\n+"' to 'RS'. This regexp matches the newline at the end of the +record and one or more blank lines after the record. In addition, a +regular expression always matches the longest possible sequence when +there is a choice (*note Leftmost Longest::). So, the next record +doesn't start until the first nonblank line that follows--no matter how +many blank lines appear in a row, they are considered one record +separator. + + However, there is an important difference between 'RS = ""' and 'RS = +"\n\n+"'. In the first case, leading newlines in the input data file +are ignored, and if a file ends without extra blank lines after the last +record, the final newline is removed from the record. In the second +case, this special processing is not done. (d.c.) + + Now that the input is separated into records, the second step is to +separate the fields in the records. One way to do this is to divide +each of the lines into fields in the normal manner. This happens by +default as the result of a special feature. When 'RS' is set to the +empty string _and_ 'FS' is set to a single character, the newline +character _always_ acts as a field separator. This is in addition to +whatever field separations result from 'FS'.(1) + + The original motivation for this special exception was probably to +provide useful behavior in the default case (i.e., 'FS' is equal to +'" "'). This feature can be a problem if you really don't want the +newline character to separate fields, because there is no way to prevent +it. However, you can work around this by using the 'split()' function +to break up the record manually (*note String Functions::). If you have +a single-character field separator, you can work around the special +feature in a different way, by making 'FS' into a regexp for that single +character. For example, if the field separator is a percent character, +instead of 'FS = "%"', use 'FS = "[%]"'. + + Another way to separate fields is to put each field on a separate +line: to do this, just set the variable 'FS' to the string '"\n"'. +(This single-character separator matches a single newline.) A practical +example of a data file organized this way might be a mailing list, where +blank lines separate the entries. Consider a mailing list in a file +named 'addresses', which looks like this: + + Jane Doe + 123 Main Street + Anywhere, SE 12345-6789 + + John Smith + 456 Tree-lined Avenue + Smallville, MW 98765-4321 + ... + +A simple program to process this file is as follows: + + # addrs.awk --- simple mailing list program + + # Records are separated by blank lines. + # Each line is one field. + BEGIN { RS = "" ; FS = "\n" } + + { + print "Name is:", $1 + print "Address is:", $2 + print "City and State are:", $3 + print "" + } + + Running the program produces the following output: + + $ awk -f addrs.awk addresses + -| Name is: Jane Doe + -| Address is: 123 Main Street + -| City and State are: Anywhere, SE 12345-6789 + -| + -| Name is: John Smith + -| Address is: 456 Tree-lined Avenue + -| City and State are: Smallville, MW 98765-4321 + -| + ... + + *Note Labels Program:: for a more realistic program dealing with +address lists. The following list summarizes how records are split, +based on the value of 'RS'. ('==' means "is equal to.") + +'RS == "\n"' + Records are separated by the newline character ('\n'). In effect, + every line in the data file is a separate record, including blank + lines. This is the default. + +'RS == ANY SINGLE CHARACTER' + Records are separated by each occurrence of the character. + Multiple successive occurrences delimit empty records. + +'RS == ""' + Records are separated by runs of blank lines. When 'FS' is a + single character, then the newline character always serves as a + field separator, in addition to whatever value 'FS' may have. + Leading and trailing newlines in a file are ignored. + +'RS == REGEXP' + Records are separated by occurrences of characters that match + REGEXP. Leading and trailing matches of REGEXP delimit empty + records. (This is a 'gawk' extension; it is not specified by the + POSIX standard.) + + If not in compatibility mode (*note Options::), 'gawk' sets 'RT' to +the input text that matched the value specified by 'RS'. But if the +input file ended without any text that matches 'RS', then 'gawk' sets +'RT' to the null string. + + ---------- Footnotes ---------- + + (1) When 'FS' is the null string ('""') or a regexp, this special +feature of 'RS' does not apply. It does apply to the default field +separator of a single space: 'FS = " "'. + + +File: gawk.info, Node: Getline, Next: Read Timeout, Prev: Multiple Line, Up: Reading Files + +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 +output from another program) or the files specified on the command line. +The 'awk' language has a special built-in command called 'getline' that +can be used to read input under your explicit control. + + The 'getline' command is used in several different ways and should +_not_ be used by beginners. The examples that follow the explanation of +the 'getline' command include material that has not been covered yet. +Therefore, come back and study the 'getline' command _after_ you have +reviewed the rest of this Info file and have a good knowledge of how +'awk' works. + + The 'getline' command returns 1 if it finds a record and 0 if it +encounters the end of the file. If there is some error in getting a +record, such as a file that cannot be opened, then 'getline' returns -1. +In this case, 'gawk' sets the variable 'ERRNO' to a string describing +the error that occurred. + + 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. + + NOTE: When '--sandbox' is specified (*note Options::), reading + lines from files, pipes, and coprocesses is disabled. + +* Menu: + +* Plain Getline:: Using 'getline' with no arguments. +* Getline/Variable:: Using 'getline' into a variable. +* Getline/File:: Using 'getline' from a file. +* Getline/Variable/File:: Using 'getline' into a variable from a + file. +* Getline/Pipe:: Using 'getline' from a pipe. +* Getline/Variable/Pipe:: Using 'getline' into a variable from a + pipe. +* Getline/Coprocess:: Using 'getline' from a coprocess. +* Getline/Variable/Coprocess:: Using 'getline' into a variable from a + coprocess. +* Getline Notes:: Important things to know about 'getline'. +* Getline Summary:: Summary of 'getline' Variants. + + +File: gawk.info, Node: Plain Getline, Next: Getline/Variable, Up: Getline + +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 +record and split it up into fields. This is useful if you've finished +processing the current record, but want to do some special processing on +the next record _right now_. For example: + + # Remove text between /* and */, inclusive + { + if ((i = index($0, "/*")) != 0) { + out = substr($0, 1, i - 1) # leading part of the string + rest = substr($0, i + 2) # ... */ ... + j = index(rest, "*/") # is */ in trailing part? + if (j > 0) { + rest = substr(rest, j + 2) # remove comment + } else { + while (j == 0) { + # get more text + if (getline <= 0) { + print("unexpected EOF or error:", ERRNO) > "/dev/stderr" + exit + } + # build up the line using string concatenation + rest = rest $0 + j = index(rest, "*/") # is */ in trailing part? + if (j != 0) { + rest = substr(rest, j + 2) + break + } + } + } + # build up the output line using string concatenation + $0 = out rest + } + print $0 + } + + This 'awk' program deletes C-style comments ('/* ... */') from the +input. It uses a number of features we haven't covered yet, including +string concatenation (*note Concatenation::) and the 'index()' and +'substr()' built-in functions (*note String Functions::). By replacing +the 'print $0' with other statements, you could perform more complicated +processing on the decommented input, such as searching for matches of a +regular expression. (This program has a subtle problem--it does not +work if one comment ends and another begins on the same line.) + + This form of the 'getline' command sets 'NF', 'NR', 'FNR', 'RT', and +the value of '$0'. + + NOTE: The new value of '$0' is used to test the patterns of any + subsequent rules. The original value of '$0' that triggered the + rule that executed 'getline' is lost. By contrast, the 'next' + statement reads a new record but immediately begins processing it + normally, starting with the first rule in the program. *Note Next + Statement::. + + +File: gawk.info, Node: Getline/Variable, Next: Getline/File, Prev: Plain Getline, Up: Getline + +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, +suppose the next line is a comment or a special string, and you want to +read it without triggering any rules. This form of 'getline' allows you +to read that line and store it in a variable so that the main +read-a-line-and-check-each-rule loop of 'awk' never sees it. The +following example swaps every two lines of input: + + { + if ((getline tmp) > 0) { + print tmp + print $0 + } else + print $0 + } + +It takes the following list: + + wan + tew + free + phore + +and produces these results: + + tew + wan + phore + free + + The 'getline' command used in this way sets only the variables 'NR', +'FNR', and 'RT' (and, of course, VAR). The record is not split into +fields, so the values of the fields (including '$0') and the value of +'NF' do not change. + + +File: gawk.info, Node: Getline/File, Next: Getline/Variable/File, Prev: Getline/Variable, Up: Getline + +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 +called a "redirection" because it directs input to come from a different +place. For example, the following program reads its input record from +the file 'secondary.input' when it encounters a first field with a value +equal to 10 in the current input file: + + { + if ($1 == 10) { + getline < "secondary.input" + print + } else + print + } + + Because the main input stream is not used, the values of 'NR' and +'FNR' are not changed. However, the record it reads is split into +fields in the normal manner, so the values of '$0' and the other fields +are changed, resulting in a new value of 'NF'. 'RT' is also set. + + According to POSIX, 'getline < EXPRESSION' is ambiguous if EXPRESSION +contains unparenthesized operators other than '$'; for example, 'getline +< dir "/" file' is ambiguous because the concatenation operator (not +discussed yet; *note Concatenation::) is not parenthesized. You should +write it as 'getline < (dir "/" file)' if you want your program to be +portable to all 'awk' implementations. + + +File: gawk.info, Node: Getline/Variable/File, Next: Getline/Pipe, Prev: Getline/File, Up: Getline + +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 +specifies the file from which to read. + + In this version of 'getline', none of the predefined variables are +changed and the record is not split into fields. The only variable +changed is VAR.(1) For example, the following program copies all the +input files to the output, except for records that say +'@include FILENAME'. Such a record is replaced by the contents of the +file FILENAME: + + { + if (NF == 2 && $1 == "@include") { + while ((getline line < $2) > 0) + print line + close($2) + } else + print + } + + Note here how the name of the extra input file is not built into the +program; it is taken directly from the data, specifically from the +second field on the '@include' line. + + The 'close()' function is called to ensure that if two identical +'@include' lines appear in the input, the entire specified file is +included twice. *Note Close Files And Pipes::. + + One deficiency of this program is that it does not process nested +'@include' statements (i.e., '@include' statements in included files) +the way a true macro preprocessor would. *Note Igawk Program:: for a +program that does handle nested '@include' statements. + + ---------- Footnotes ---------- + + (1) This is not quite true. 'RT' could be changed if 'RS' is a +regular expression. + + +File: gawk.info, Node: Getline/Pipe, Next: Getline/Variable/Pipe, Prev: Getline/Variable/File, Up: Getline + +4.10.5 Using 'getline' from a Pipe +---------------------------------- + + Omniscience has much to recommend it. Failing that, attention to + details would be useful. + -- _Brian Kernighan_ + + The output of a command can also be piped into 'getline', using +'COMMAND | getline'. In this case, the string COMMAND is run as a shell +command and its output is piped into 'awk' to be used as input. This +form of 'getline' reads one record at a time from the pipe. For +example, the following program copies its input to its output, except +for lines that begin with '@execute', which are replaced by the output +produced by running the rest of the line as a shell command: + + { + if ($1 == "@execute") { + tmp = substr($0, 10) # Remove "@execute" + while ((tmp | getline) > 0) + print + close(tmp) + } else + print + } + +The 'close()' function is called to ensure that if two identical +'@execute' lines appear in the input, the command is run for each one. +*Note Close Files And Pipes::. Given the input: + + foo + bar + baz + @execute who + bletch + +the program might produce: + + foo + bar + baz + arnold ttyv0 Jul 13 14:22 + miriam ttyp0 Jul 13 14:23 (murphy:0) + bill ttyp1 Jul 13 14:23 (murphy:0) + bletch + +Notice that this program ran the command 'who' and printed the result. +(If you try this program yourself, you will of course get different +results, depending upon who is logged in on your system.) + + This variation of 'getline' splits the record into fields, sets the +value of 'NF', and recomputes the value of '$0'. The values of 'NR' and +'FNR' are not changed. 'RT' is set. + + According to POSIX, 'EXPRESSION | getline' is ambiguous if EXPRESSION +contains unparenthesized operators other than '$'--for example, '"echo " +"date" | getline' is ambiguous because the concatenation operator is not +parenthesized. You should write it as '("echo " "date") | getline' if +you want your program to be portable to all 'awk' implementations. + + NOTE: Unfortunately, 'gawk' has not been consistent in its + treatment of a construct like '"echo " "date" | getline'. Most + versions, including the current version, treat it at as '("echo " + "date") | getline'. (This is also how BWK 'awk' behaves.) Some + versions instead treat it as '"echo " ("date" | getline)'. (This + is how 'mawk' behaves.) In short, _always_ use explicit + parentheses, and then you won't have to worry. + + +File: gawk.info, Node: Getline/Variable/Pipe, Next: Getline/Coprocess, Prev: Getline/Pipe, Up: Getline + +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 +following program reads the current date and time into the variable +'current_time', using the 'date' utility, and then prints it: + + BEGIN { + "date" | getline current_time + close("date") + print "Report printed on " current_time + } + + In this version of 'getline', none of the predefined variables are +changed and the record is not split into fields. However, 'RT' is set. + + According to POSIX, 'EXPRESSION | getline VAR' is ambiguous if +EXPRESSION contains unparenthesized operators other than '$'; for +example, '"echo " "date" | getline VAR' is ambiguous because the +concatenation operator is not parenthesized. You should write it as +'("echo " "date") | getline VAR' if you want your program to be portable +to other 'awk' implementations. + + +File: gawk.info, Node: Getline/Coprocess, Next: Getline/Variable/Coprocess, Prev: Getline/Variable/Pipe, Up: Getline + +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_ +your 'awk' program. + + On occasion, you might want to send data to another program for +processing and then read the results back. 'gawk' allows you to start a +"coprocess", with which two-way communications are possible. This is +done with the '|&' operator. Typically, you write data to the coprocess +first and then read the results back, as shown in the following: + + print "SOME QUERY" |& "db_server" + "db_server" |& getline + +which sends a query to 'db_server' and then reads the results. + + The values of 'NR' and 'FNR' are not changed, because the main input +stream is not used. However, the record is split into fields in the +normal manner, thus changing the values of '$0', of the other fields, +and of 'NF' and 'RT'. + + Coprocesses are an advanced feature. They are discussed here only +because this is the minor node on 'getline'. *Note Two-way I/O::, where +coprocesses are discussed in more detail. + + +File: gawk.info, Node: Getline/Variable/Coprocess, Next: Getline Notes, Prev: Getline/Coprocess, Up: Getline + +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 +variable VAR. + + In this version of 'getline', none of the predefined variables are +changed and the record is not split into fields. The only variable +changed is VAR. However, 'RT' is set. + + Coprocesses are an advanced feature. They are discussed here only +because this is the minor node on 'getline'. *Note Two-way I/O::, where +coprocesses are discussed in more detail. + + +File: gawk.info, Node: Getline Notes, Next: Getline Summary, Prev: Getline/Variable/Coprocess, Up: Getline + +4.10.9 Points to Remember About 'getline' +----------------------------------------- + +Here are some miscellaneous points about 'getline' that you should bear +in mind: + + * When 'getline' changes the value of '$0' and 'NF', 'awk' does _not_ + automatically jump to the start of the program and start testing + the new record against every pattern. However, the new record is + tested against any subsequent rules. + + * Some very old 'awk' implementations limit the number of pipelines + that an 'awk' program may have open to just one. In 'gawk', there + is no such limit. You can open as many pipelines (and coprocesses) + as the underlying operating system permits. + + * An interesting side effect occurs if you use 'getline' without a + redirection inside a 'BEGIN' rule. Because an unredirected + 'getline' reads from the command-line data files, the first + 'getline' command causes 'awk' to set the value of 'FILENAME'. + Normally, 'FILENAME' does not have a value inside 'BEGIN' rules, + because you have not yet started to process the command-line data + files. (d.c.) (See *note BEGIN/END::; also *note Auto-set::.) + + * Using 'FILENAME' with 'getline' ('getline < FILENAME') is likely to + be a source of confusion. 'awk' opens a separate input stream from + the current input file. However, by not using a variable, '$0' and + 'NF' are still updated. If you're doing this, it's probably by + accident, and you should reconsider what it is you're trying to + accomplish. + + * *note Getline Summary::, presents a table summarizing the 'getline' + variants and which variables they can affect. It is worth noting + that those variants that do not use redirection can cause + 'FILENAME' to be updated if they cause 'awk' to start reading a new + input file. + + * If the variable being assigned is an expression with side effects, + different versions of 'awk' behave differently upon encountering + end-of-file. Some versions don't evaluate the expression; many + versions (including 'gawk') do. Here is an example, courtesy of + Duncan Moore: + + BEGIN { + system("echo 1 > f") + while ((getline a[++c] < "f") > 0) { } + print c + } + + Here, the side effect is the '++c'. Is 'c' incremented if + end-of-file is encountered before the element in 'a' is assigned? + + 'gawk' treats 'getline' like a function call, and evaluates the + expression 'a[++c]' before attempting to read from 'f'. However, + some versions of 'awk' only evaluate the expression once they know + that there is a string value to be assigned. + + +File: gawk.info, Node: Getline Summary, Prev: Getline Notes, Up: Getline + +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, +and whether the variant is standard or a 'gawk' extension. Note: for +each variant, 'gawk' sets the 'RT' predefined variable. + +Variant Effect 'awk' / 'gawk' +------------------------------------------------------------------------- +'getline' Sets '$0', 'NF', 'FNR', 'awk' + 'NR', and 'RT' +'getline' VAR Sets VAR, 'FNR', 'NR', 'awk' + and 'RT' +'getline <' FILE Sets '$0', 'NF', and 'RT' 'awk' +'getline VAR < FILE' Sets VAR and 'RT' 'awk' +COMMAND '| getline' Sets '$0', 'NF', and 'RT' 'awk' +COMMAND '| getline' Sets VAR and 'RT' 'awk' +VAR +COMMAND '|& getline' Sets '$0', 'NF', and 'RT' 'gawk' +COMMAND '|& getline' Sets VAR and 'RT' 'gawk' +VAR + +Table 4.1: 'getline' variants and what they set + + +File: gawk.info, Node: Read Timeout, Next: Retrying Input, Prev: Getline, Up: Reading Files + +4.11 Reading Input with a Timeout +================================= + +This minor node describes a feature that is specific to 'gawk'. + + You may specify a timeout in milliseconds for reading input from the +keyboard, a pipe, or two-way communication, including TCP/IP sockets. +This can be done on a per-input, per-command, or per-connection basis, +by setting a special element in the 'PROCINFO' array (*note Auto-set::): + + PROCINFO["input_name", "READ_TIMEOUT"] = TIMEOUT IN MILLISECONDS + + When set, this causes 'gawk' to time out and return failure if no +data is available to read within the specified timeout period. For +example, a TCP client can decide to give up on receiving any response +from the server after a certain amount of time: + + Service = "/inet/tcp/0/localhost/daytime" + PROCINFO[Service, "READ_TIMEOUT"] = 100 + if ((Service |& getline) > 0) + print $0 + else if (ERRNO != "") + print ERRNO + + Here is how to read interactively from the user(1) without waiting +for more than five seconds: + + PROCINFO["/dev/stdin", "READ_TIMEOUT"] = 5000 + while ((getline < "/dev/stdin") > 0) + print $0 + + 'gawk' terminates the read operation if input does not arrive after +waiting for the timeout period, returns failure, and sets 'ERRNO' to an +appropriate string value. A negative or zero value for the timeout is +the same as specifying no timeout at all. + + A timeout can also be set for reading from the keyboard in the +implicit loop that reads input records and matches them against +patterns, like so: + + $ gawk 'BEGIN { PROCINFO["-", "READ_TIMEOUT"] = 5000 } + > { print "You entered: " $0 }' + gawk + -| You entered: gawk + + In this case, failure to respond within five seconds results in the +following error message: + + error-> gawk: cmd. line:2: (FILENAME=- FNR=1) fatal: error reading input file `-': Connection timed out + + The timeout can be set or changed at any time, and will take effect +on the next attempt to read from the input device. In the following +example, we start with a timeout value of one second, and progressively +reduce it by one-tenth of a second until we wait indefinitely for the +input to arrive: + + PROCINFO[Service, "READ_TIMEOUT"] = 1000 + while ((Service |& getline) > 0) { + print $0 + PROCINFO[Service, "READ_TIMEOUT"] -= 100 + } + + NOTE: You should not assume that the read operation will block + exactly after the tenth record has been printed. It is possible + that 'gawk' will read and buffer more than one record's worth of + data the first time. Because of this, changing the value of + timeout like in the preceding example is not very useful. + + If the 'PROCINFO' element is not present and the 'GAWK_READ_TIMEOUT' +environment variable exists, 'gawk' uses its value to initialize the +timeout value. The exclusive use of the environment variable to specify +timeout has the disadvantage of not being able to control it on a +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. *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 +stall waiting for an input device to be ready. A network client can +sometimes take a long time to establish 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. + + ---------- Footnotes ---------- + + (1) This assumes that standard input is the keyboard. + + +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.13 Directories on the Command Line +==================================== + +According to the POSIX standard, files named on the 'awk' command line +must be text files; it is a fatal error if they are not. Most versions +of 'awk' treat a directory on the command line as a fatal error. + + By default, 'gawk' produces a warning for a directory on the command +line, but otherwise ignores it. This makes it easier to use shell +wildcards with your 'awk' program: + + $ gawk -f whizprog.awk * Directories could kill this program + + If either of the '--posix' or '--traditional' options is given, then +'gawk' reverts to treating a directory on the command line as a fatal +error. + + *Note Extension Sample Readdir:: for a way to treat directories as +usable data from an 'awk' program. + + +File: gawk.info, Node: Input Summary, Next: Input Exercises, Prev: Command-line directories, Up: Reading Files + +4.14 Summary +============ + + * Input is split into records based on the value of 'RS'. The + possibilities are as follows: + + Value of 'RS' Records are split on 'awk' / 'gawk' + ... + --------------------------------------------------------------------------- + Any single That character 'awk' + character + The empty string Runs of two or more 'awk' + ('""') newlines + A regexp Text that matches the 'gawk' + regexp + + * 'FNR' indicates how many records have been read from the current + input file; 'NR' indicates how many records have been read in + total. + + * 'gawk' sets 'RT' to the text matched by 'RS'. + + * After splitting the input into records, 'awk' further splits the + records into individual fields, named '$1', '$2', and so on. '$0' + is the whole record, and 'NF' indicates how many fields there are. + The default way to split fields is between whitespace characters. + + * Fields may be referenced using a variable, as in '$NF'. Fields may + also be assigned values, which causes the value of '$0' to be + recomputed when it is later referenced. Assigning to a field with + a number greater than 'NF' creates the field and rebuilds the + record, using 'OFS' to separate the fields. Incrementing 'NF' does + the same thing. Decrementing 'NF' throws away fields and rebuilds + the record. + + * Field splitting is more complicated than record splitting: + + Field separator value Fields are split ... 'awk' / + 'gawk' + --------------------------------------------------------------------------- + 'FS == " "' On runs of whitespace 'awk' + 'FS == ANY SINGLE On that character 'awk' + CHARACTER' + 'FS == REGEXP' On text matching the regexp 'awk' + 'FS == ""' Such that each individual 'gawk' + character is a separate + field + 'FIELDWIDTHS == LIST OF Based on character position 'gawk' + COLUMNS' + 'FPAT == REGEXP' On the text surrounding 'gawk' + text matching the regexp + + * Using 'FS = "\n"' causes the entire record to be a single field + (assuming that newlines separate records). + + * 'FS' may be set from the command line using the '-F' option. This + can also be done using command-line variable assignment. + + * Use 'PROCINFO["FS"]' to see how fields are being split. + + * Use 'getline' in its various forms to read additional records from + the default input stream, from a file, or from a pipe or coprocess. + + * Use 'PROCINFO[FILE, "READ_TIMEOUT"]' to cause reads to time out for + FILE. + + * Directories on the command line are fatal for standard 'awk'; + 'gawk' ignores them if not in POSIX mode. + + +File: gawk.info, Node: Input Exercises, Prev: Input Summary, Up: Reading Files + +4.15 Exercises +============== + + 1. Using the 'FIELDWIDTHS' variable (*note Constant Size::), write a + program to read election data, where each record represents one + voter's votes. Come up with a way to define which columns are + associated with each ballot item, and print the total votes, + including abstentions, for each item. + + 2. *note Plain Getline::, presented a program to remove C-style + comments ('/* ... */') from the input. That program does not work + if one comment ends on one line and another one starts later on the + same line. That can be fixed by making one simple change. What is + it? + + +File: gawk.info, Node: Printing, Next: Expressions, Prev: Reading Files, Up: Top + +5 Printing Output +***************** + +One of the most common programming actions is to "print", or output, +some or all of the input. Use the 'print' statement for simple output, +and the 'printf' statement for fancier formatting. The 'print' +statement is not limited when computing _which_ values to print. +However, with two exceptions, you cannot specify _how_ to print +them--how many columns, whether to use exponential notation or not, and +so on. (For the exceptions, *note Output Separators:: and *note +OFMT::.) For printing with specifications, you need the 'printf' +statement (*note Printf::). + + Besides basic and formatted printing, this major node also covers I/O +redirections to files and pipes, introduces the special file names that +'gawk' processes internally, and discusses the 'close()' built-in +function. + +* Menu: + +* Print:: The 'print' statement. +* Print Examples:: Simple examples of 'print' statements. +* Output Separators:: The output separators and how to change them. +* OFMT:: Controlling Numeric Output With 'print'. +* Printf:: The 'printf' statement. +* Redirection:: How to redirect output to multiple files and + pipes. +* Special FD:: Special files for I/O. +* Special Files:: File name interpretation in 'gawk'. + 'gawk' allows access to inherited file + descriptors. +* Close Files And Pipes:: Closing Input and Output Files and Pipes. +* Nonfatal:: Enabling Nonfatal Output. +* Output Summary:: Output summary. +* Output Exercises:: Exercises. + + +File: gawk.info, Node: Print, Next: Print Examples, Up: Printing + +5.1 The 'print' Statement +========================= + +Use the 'print' statement to produce output with simple, standardized +formatting. You specify only the strings or numbers to print, in a list +separated by commas. They are output, separated by single spaces, +followed by a newline. The statement looks like this: + + print ITEM1, ITEM2, ... + +The entire list of items may be optionally enclosed in parentheses. The +parentheses are necessary if any of the item expressions uses the '>' +relational operator; otherwise it could be confused with an output +redirection (*note Redirection::). + + The items to print can be constant strings or numbers, fields of the +current record (such as '$1'), variables, or any 'awk' expression. +Numeric values are converted to strings and then printed. + + The simple statement 'print' with no items is equivalent to 'print +$0': it prints the entire current record. To print a blank line, use +'print ""'. To print a fixed piece of text, use a string constant, such +as '"Don't Panic"', as one item. If you forget to use the double-quote +characters, your text is taken as an 'awk' expression, and you will +probably get an error. Keep in mind that a space is printed between any +two items. + + Note that the 'print' statement is a statement and not an +expression--you can't use it in the pattern part of a pattern-action +statement, for example. + + +File: gawk.info, Node: Print Examples, Next: Output Separators, Prev: Print, Up: Printing + +5.2 'print' Statement Examples +============================== + +Each 'print' statement makes at least one line of output. However, it +isn't limited to only one line. If an item value is a string containing +a newline, the newline is output along with the rest of the string. A +single 'print' statement can make any number of lines this way. + + The following is an example of printing a string that contains +embedded newlines (the '\n' is an escape sequence, used to represent the +newline character; *note Escape Sequences::): + + $ awk 'BEGIN { print "line one\nline two\nline three" }' + -| line one + -| line two + -| line three + + The next example, which is run on the 'inventory-shipped' file, +prints the first two fields of each input record, with a space between +them: + + $ awk '{ print $1, $2 }' inventory-shipped + -| Jan 13 + -| Feb 15 + -| Mar 15 + ... + + A common mistake in using the 'print' statement is to omit the comma +between two items. This often has the effect of making the items run +together in the output, with no space. The reason for this is that +juxtaposing two string expressions in 'awk' means to concatenate them. +Here is the same program, without the comma: + + $ awk '{ print $1 $2 }' inventory-shipped + -| Jan13 + -| Feb15 + -| Mar15 + ... + + To someone unfamiliar with the 'inventory-shipped' file, neither +example's output makes much sense. A heading line at the beginning +would make it clearer. Let's add some headings to our table of months +('$1') and green crates shipped ('$2'). We do this using a 'BEGIN' rule +(*note BEGIN/END::) so that the headings are only printed once: + + awk 'BEGIN { print "Month Crates" + print "----- ------" } + { print $1, $2 }' inventory-shipped + +When run, the program prints the following: + + Month Crates + ----- ------ + Jan 13 + Feb 15 + Mar 15 + ... + +The only problem, however, is that the headings and the table data don't +line up! We can fix this by printing some spaces between the two +fields: + + awk 'BEGIN { print "Month Crates" + print "----- ------" } + { print $1, " ", $2 }' inventory-shipped + + Lining up columns this way can get pretty complicated when there are +many columns to fix. Counting spaces for two or three columns is +simple, but any more than this can take up a lot of time. This is why +the 'printf' statement was created (*note Printf::); one of its +specialties is lining up columns of data. + + NOTE: You can continue either a 'print' or 'printf' statement + simply by putting a newline after any comma (*note + Statements/Lines::). + + +File: gawk.info, Node: Output Separators, Next: OFMT, Prev: Print Examples, Up: Printing + +5.3 Output Separators +===================== + +As mentioned previously, a 'print' statement contains a list of items +separated by commas. In the output, the items are normally separated by +single spaces. However, this doesn't need to be the case; a single +space is simply the default. Any string of characters may be used as +the "output field separator" by setting the predefined variable 'OFS'. +The initial value of this variable is the string '" "' (i.e., a single +space). + + The output from an entire 'print' statement is called an "output +record". Each 'print' statement outputs one output record, and then +outputs a string called the "output record separator" (or 'ORS'). The +initial value of 'ORS' is the string '"\n"' (i.e., a newline character). +Thus, each 'print' statement normally makes a separate line. + + In order to change how output fields and records are separated, +assign new values to the variables 'OFS' and 'ORS'. The usual place to +do this is in the 'BEGIN' rule (*note BEGIN/END::), so that it happens +before any input is processed. It can also be done with assignments on +the command line, before the names of the input files, or using the '-v' +command-line option (*note Options::). The following example prints the +first and second fields of each input record, separated by a semicolon, +with a blank line added after each newline: + + $ awk 'BEGIN { OFS = ";"; ORS = "\n\n" } + > { print $1, $2 }' mail-list + -| Amelia;555-5553 + -| + -| Anthony;555-3412 + -| + -| Becky;555-7685 + -| + -| Bill;555-1675 + -| + -| Broderick;555-0542 + -| + -| Camilla;555-2912 + -| + -| Fabius;555-1234 + -| + -| Julie;555-6699 + -| + -| Martin;555-6480 + -| + -| Samuel;555-3430 + -| + -| Jean-Paul;555-2127 + -| + + If the value of 'ORS' does not contain a newline, the program's +output runs together on a single line. + + +File: gawk.info, Node: OFMT, Next: Printf, Prev: Output Separators, Up: Printing + +5.4 Controlling Numeric Output with 'print' +=========================================== + +When printing numeric values with the 'print' statement, 'awk' +internally converts each number to a string of characters and prints +that string. 'awk' uses the 'sprintf()' function to do this conversion +(*note String Functions::). For now, it suffices to say that the +'sprintf()' function accepts a "format specification" that tells it how +to format numbers (or strings), and that there are a number of different +ways in which numbers can be formatted. The different format +specifications are discussed more fully in *note Control Letters::. + + The predefined variable 'OFMT' contains the format specification that +'print' uses with 'sprintf()' when it wants to convert a number to a +string for printing. The default value of 'OFMT' is '"%.6g"'. The way +'print' prints numbers can be changed by supplying a different format +specification for the value of 'OFMT', as shown in the following +example: + + $ awk 'BEGIN { + > OFMT = "%.0f" # print numbers as integers (rounds) + > print 17.23, 17.54 }' + -| 17 18 + +According to the POSIX standard, 'awk''s behavior is undefined if 'OFMT' +contains anything but a floating-point conversion specification. (d.c.) + + +File: gawk.info, Node: Printf, Next: Redirection, Prev: OFMT, Up: Printing + +5.5 Using 'printf' Statements for Fancier Printing +================================================== + +For more precise control over the output format than what is provided by +'print', use 'printf'. With 'printf' you can specify the width to use +for each item, as well as various formatting choices for numbers (such +as what output base to use, whether to print an exponent, whether to +print a sign, and how many digits to print after the decimal point). + +* Menu: + +* Basic Printf:: Syntax of the 'printf' statement. +* Control Letters:: Format-control letters. +* Format Modifiers:: Format-specification modifiers. +* Printf Examples:: Several examples. + + +File: gawk.info, Node: Basic Printf, Next: Control Letters, Up: Printf + +5.5.1 Introduction to the 'printf' Statement +-------------------------------------------- + +A simple 'printf' statement looks like this: + + printf FORMAT, ITEM1, ITEM2, ... + +As for 'print', the entire list of arguments may optionally be enclosed +in parentheses. Here too, the parentheses are necessary if any of the +item expressions uses the '>' relational operator; otherwise, it can be +confused with an output redirection (*note Redirection::). + + The difference between 'printf' and 'print' is the FORMAT argument. +This is an expression whose value is taken as a string; it specifies how +to output each of the other arguments. It is called the "format +string". + + The format string is very similar to that in the ISO C library +function 'printf()'. Most of FORMAT is text to output verbatim. +Scattered among this text are "format specifiers"--one per item. Each +format specifier says to output the next item in the argument list at +that place in the format. + + The 'printf' statement does not automatically append a newline to its +output. It outputs only what the format string specifies. So if a +newline is needed, you must include one in the format string. The +output separator variables 'OFS' and 'ORS' have no effect on 'printf' +statements. For example: + + $ awk 'BEGIN { + > ORS = "\nOUCH!\n"; OFS = "+" + > msg = "Don\47t Panic!" + > printf "%s\n", msg + > }' + -| Don't Panic! + +Here, neither the '+' nor the 'OUCH!' appears in the output message. + + +File: gawk.info, Node: Control Letters, Next: Format Modifiers, Prev: Basic Printf, Up: Printf + +5.5.2 Format-Control Letters +---------------------------- + +A format specifier starts with the character '%' and ends with a +"format-control letter"--it tells the 'printf' statement how to output +one item. The format-control letter specifies what _kind_ of value to +print. The rest of the format specifier is made up of optional +"modifiers" that control _how_ to print the value, such as the field +width. Here is a list of the format-control letters: + +'%c' + Print a number as a character; thus, 'printf "%c", 65' outputs the + letter 'A'. The output for a string value is the first character + of the string. + + NOTE: The POSIX standard says the first character of a string + is printed. In locales with multibyte characters, 'gawk' + attempts to convert the leading bytes of the string into a + valid wide character and then to print the multibyte encoding + of that character. Similarly, when printing a numeric value, + 'gawk' allows the value to be within the numeric range of + values that can be held in a wide character. If the + conversion to multibyte encoding fails, 'gawk' uses the low + eight bits of the value as the character to print. + + Other 'awk' versions generally restrict themselves to printing + the first byte of a string or to numeric values within the + range of a single byte (0-255). (d.c.) + +'%d', '%i' + Print a decimal integer. The two control letters are equivalent. + (The '%i' specification is for compatibility with ISO C.) + +'%e', '%E' + Print a number in scientific (exponential) notation. For example: + + printf "%4.3e\n", 1950 + + prints '1.950e+03', with a total of four significant figures, three + of which follow the decimal point. (The '4.3' represents two + modifiers, discussed in the next node.) '%E' uses 'E' instead of + 'e' in the output. + +'%f' + Print a number in floating-point notation. For example: + + printf "%4.3f", 1950 + + prints '1950.000', with a total of four significant figures, three + of which follow the decimal point. (The '4.3' represents two + modifiers, discussed in the next node.) + + On systems supporting IEEE 754 floating-point format, values + representing negative infinity are formatted as '-inf' or + '-infinity', and positive infinity as 'inf' or 'infinity'. The + special "not a number" value formats as '-nan' or 'nan' (*note Math + Definitions::). + +'%F' + Like '%f', but the infinity and "not a number" values are spelled + using uppercase letters. + + The '%F' format is a POSIX extension to ISO C; not all systems + support it. On those that don't, 'gawk' uses '%f' instead. + +'%g', '%G' + Print a number in either scientific notation or in floating-point + notation, whichever uses fewer characters; if the result is printed + in scientific notation, '%G' uses 'E' instead of 'e'. + +'%o' + Print an unsigned octal integer (*note Nondecimal-numbers::). + +'%s' + Print a string. + +'%u' + Print an unsigned decimal integer. (This format is of marginal + use, because all numbers in 'awk' are floating point; it is + provided primarily for compatibility with C.) + +'%x', '%X' + Print an unsigned hexadecimal integer; '%X' uses the letters 'A' + through 'F' instead of 'a' through 'f' (*note + Nondecimal-numbers::). + +'%%' + Print a single '%'. This does not consume an argument and it + ignores any modifiers. + + NOTE: When using the integer format-control letters for values that + are outside the range of the widest C integer type, 'gawk' switches + to the '%g' format specifier. If '--lint' is provided on the + command line (*note Options::), 'gawk' warns about this. Other + versions of 'awk' may print invalid values or do something else + entirely. (d.c.) + + +File: gawk.info, Node: Format Modifiers, Next: Printf Examples, Prev: Control Letters, Up: Printf + +5.5.3 Modifiers for 'printf' Formats +------------------------------------ + +A format specification can also include "modifiers" that can control how +much of the item's value is printed, as well as how much space it gets. +The modifiers come between the '%' and the format-control letter. We +use the bullet symbol "*" in the following examples to represent spaces +in the output. Here are the possible modifiers, in the order in which +they may appear: + +'N$' + An integer constant followed by a '$' is a "positional specifier". + Normally, format specifications are applied to arguments in the + order given in the format string. With a positional specifier, the + format specification is applied to a specific argument, instead of + what would be the next argument in the list. Positional specifiers + begin counting with one. Thus: + + printf "%s %s\n", "don't", "panic" + printf "%2$s %1$s\n", "panic", "don't" + + prints the famous friendly message twice. + + At first glance, this feature doesn't seem to be of much use. It + is in fact a 'gawk' extension, intended for use in translating + messages at runtime. *Note Printf Ordering::, which describes how + and why to use positional specifiers. For now, we ignore them. + +'-' (Minus) + The minus sign, used before the width modifier (see later on in + this list), says to left-justify the argument within its specified + width. Normally, the argument is printed right-justified in the + specified width. Thus: + + printf "%-4s", "foo" + + prints 'foo*'. + +SPACE + For numeric conversions, prefix positive values with a space and + negative values with a minus sign. + +'+' + The plus sign, used before the width modifier (see later on in this + list), says to always supply a sign for numeric conversions, even + if the data to format is positive. The '+' overrides the space + modifier. + +'#' + Use an "alternative form" for certain control letters. For '%o', + supply a leading zero. For '%x' and '%X', supply a leading '0x' or + '0X' for a nonzero result. For '%e', '%E', '%f', and '%F', the + result always contains a decimal point. For '%g' and '%G', + trailing zeros are not removed from the result. + +'0' + A leading '0' (zero) acts as a flag indicating that output should + be padded with zeros instead of spaces. This applies only to the + numeric output formats. This flag only has an effect when the + field width is wider than the value to print. + +''' + A single quote or apostrophe character is a POSIX extension to ISO + C. It indicates that the integer part of a floating-point value, or + the entire part of an integer decimal value, should have a + thousands-separator character in it. This only works in locales + that support such characters. For example: + + $ cat thousands.awk Show source program + -| BEGIN { printf "%'d\n", 1234567 } + $ LC_ALL=C gawk -f thousands.awk + -| 1234567 Results in "C" locale + $ LC_ALL=en_US.UTF-8 gawk -f thousands.awk + -| 1,234,567 Results in US English UTF locale + + For more information about locales and internationalization issues, + see *note Locales::. + + NOTE: The ''' flag is a nice feature, but its use complicates + things: it becomes difficult to use it in command-line + programs. For information on appropriate quoting tricks, see + *note Quoting::. + +WIDTH + This is a number specifying the desired minimum width of a field. + Inserting any number between the '%' sign and the format-control + character forces the field to expand to this width. The default + way to do this is to pad with spaces on the left. For example: + + printf "%4s", "foo" + + prints '*foo'. + + The value of WIDTH is a minimum width, not a maximum. If the item + value requires more than WIDTH characters, it can be as wide as + necessary. Thus, the following: + + printf "%4s", "foobar" + + prints 'foobar'. + + Preceding the WIDTH with a minus sign causes the output to be + padded with spaces on the right, instead of on the left. + +'.PREC' + A period followed by an integer constant specifies the precision to + use when printing. The meaning of the precision varies by control + letter: + + '%d', '%i', '%o', '%u', '%x', '%X' + Minimum number of digits to print. + + '%e', '%E', '%f', '%F' + Number of digits to the right of the decimal point. + + '%g', '%G' + Maximum number of significant digits. + + '%s' + Maximum number of characters from the string that should + print. + + Thus, the following: + + printf "%.4s", "foobar" + + prints 'foob'. + + The C library 'printf''s dynamic WIDTH and PREC capability (e.g., +'"%*.*s"') is supported. Instead of supplying explicit WIDTH and/or +PREC values in the format string, they are passed in the argument list. +For example: + + w = 5 + p = 3 + s = "abcdefg" + printf "%*.*s\n", w, p, s + +is exactly equivalent to: + + s = "abcdefg" + printf "%5.3s\n", s + +Both programs output '**abc'. Earlier versions of 'awk' did not support +this capability. If you must use such a version, you may simulate this +feature by using concatenation to build up the format string, like so: + + w = 5 + p = 3 + s = "abcdefg" + printf "%" w "." p "s\n", s + +This is not particularly easy to read, but it does work. + + C programmers may be used to supplying additional modifiers ('h', +'j', 'l', 'L', 't', and 'z') in 'printf' format strings. These are not +valid in 'awk'. Most 'awk' implementations silently ignore them. If +'--lint' is provided on the command line (*note Options::), 'gawk' warns +about their use. If '--posix' is supplied, their use is a fatal error. + + +File: gawk.info, Node: Printf Examples, Prev: Format Modifiers, Up: Printf + +5.5.4 Examples Using 'printf' +----------------------------- + +The following simple example shows how to use 'printf' to make an +aligned table: + + awk '{ printf "%-10s %s\n", $1, $2 }' mail-list + +This command prints the names of the people ('$1') in the file +'mail-list' as a string of 10 characters that are left-justified. It +also prints the phone numbers ('$2') next on the line. This produces an +aligned two-column table of names and phone numbers, as shown here: + + $ awk '{ printf "%-10s %s\n", $1, $2 }' mail-list + -| Amelia 555-5553 + -| Anthony 555-3412 + -| Becky 555-7685 + -| Bill 555-1675 + -| Broderick 555-0542 + -| Camilla 555-2912 + -| Fabius 555-1234 + -| Julie 555-6699 + -| Martin 555-6480 + -| Samuel 555-3430 + -| Jean-Paul 555-2127 + + In this case, the phone numbers had to be printed as strings because +the numbers are separated by dashes. Printing the phone numbers as +numbers would have produced just the first three digits: '555'. This +would have been pretty confusing. + + It wasn't necessary to specify a width for the phone numbers because +they are last on their lines. They don't need to have spaces after +them. + + The table could be made to look even nicer by adding headings to the +tops of the columns. This is done using a 'BEGIN' rule (*note +BEGIN/END::) so that the headers are only printed once, at the beginning +of the 'awk' program: + + awk 'BEGIN { print "Name Number" + print "---- ------" } + { printf "%-10s %s\n", $1, $2 }' mail-list + + The preceding example mixes 'print' and 'printf' statements in the +same program. Using just 'printf' statements can produce the same +results: + + awk 'BEGIN { printf "%-10s %s\n", "Name", "Number" + printf "%-10s %s\n", "----", "------" } + { printf "%-10s %s\n", $1, $2 }' mail-list + +Printing each column heading with the same format specification used for +the column elements ensures that the headings are aligned just like the +columns. + + The fact that the same format specification is used three times can +be emphasized by storing it in a variable, like this: + + awk 'BEGIN { format = "%-10s %s\n" + printf format, "Name", "Number" + printf format, "----", "------" } + { printf format, $1, $2 }' mail-list + + +File: gawk.info, Node: Redirection, Next: Special FD, Prev: Printf, Up: Printing + +5.6 Redirecting Output of 'print' and 'printf' +============================================== + +So far, the output from 'print' and 'printf' has gone to the standard +output, usually the screen. Both 'print' and 'printf' can also send +their output to other places. This is called "redirection". + + NOTE: When '--sandbox' is specified (*note Options::), redirecting + output to files, pipes, and coprocesses is disabled. + + A redirection appears after the 'print' or 'printf' statement. +Redirections in 'awk' are written just like redirections in shell +commands, except that they are written inside the 'awk' program. + + There are four forms of output redirection: output to a file, output +appended to a file, output through a pipe to another command, and output +to a coprocess. We show them all for the 'print' statement, but they +work identically for 'printf': + +'print ITEMS > OUTPUT-FILE' + This redirection prints the items into the output file named + OUTPUT-FILE. The file name OUTPUT-FILE can be any expression. Its + value is changed to a string and then used as a file name (*note + Expressions::). + + When this type of redirection is used, the OUTPUT-FILE is erased + before the first output is written to it. Subsequent writes to the + same OUTPUT-FILE do not erase OUTPUT-FILE, but append to it. (This + is different from how you use redirections in shell scripts.) If + OUTPUT-FILE does not exist, it is created. For example, here is + how an 'awk' program can write a list of peoples' names to one file + named 'name-list', and a list of phone numbers to another file + named 'phone-list': + + $ awk '{ print $2 > "phone-list" + > print $1 > "name-list" }' mail-list + $ cat phone-list + -| 555-5553 + -| 555-3412 + ... + $ cat name-list + -| Amelia + -| Anthony + ... + + Each output file contains one name or number per line. + +'print ITEMS >> OUTPUT-FILE' + This redirection prints the items into the preexisting output file + named OUTPUT-FILE. The difference between this and the single-'>' + redirection is that the old contents (if any) of OUTPUT-FILE are + not erased. Instead, the 'awk' output is appended to the file. If + OUTPUT-FILE does not exist, then it is created. + +'print ITEMS | COMMAND' + It is possible to send output to another program through a pipe + instead of into a file. This redirection opens a pipe to COMMAND, + and writes the values of ITEMS through this pipe to another process + created to execute COMMAND. + + The redirection argument COMMAND is actually an 'awk' expression. + Its value is converted to a string whose contents give the shell + command to be run. For example, the following produces two files, + one unsorted list of peoples' names, and one list sorted in reverse + alphabetical order: + + awk '{ print $1 > "names.unsorted" + command = "sort -r > names.sorted" + print $1 | command }' mail-list + + The unsorted list is written with an ordinary redirection, while + the sorted list is written by piping through the 'sort' utility. + + The next example uses redirection to mail a message to the mailing + list 'bug-system'. This might be useful when trouble is + encountered in an 'awk' script run periodically for system + maintenance: + + report = "mail bug-system" + print("Awk script failed:", $0) | report + print("at record number", FNR, "of", FILENAME) | report + close(report) + + The 'close()' function is called here because it's a good idea to + close the pipe as soon as all the intended output has been sent to + it. *Note Close Files And Pipes:: for more information. + + This example also illustrates the use of a variable to represent a + FILE or COMMAND--it is not necessary to always use a string + constant. Using a variable is generally a good idea, because (if + you mean to refer to that same file or command) 'awk' requires that + the string value be written identically every time. + +'print ITEMS |& COMMAND' + This redirection prints the items to the input of COMMAND. The + difference between this and the single-'|' redirection is that the + output from COMMAND can be read with 'getline'. Thus, COMMAND is a + "coprocess", which works together with but is subsidiary to the + 'awk' program. + + This feature is a 'gawk' extension, and is not available in POSIX + 'awk'. *Note Getline/Coprocess::, for a brief discussion. *Note + Two-way I/O::, for a more complete discussion. + + Redirecting output using '>', '>>', '|', or '|&' asks the system to +open a file, pipe, or coprocess only if the particular FILE or COMMAND +you specify has not already been written to by your program or if it has +been closed since it was last written to. + + It is a common error to use '>' redirection for the first 'print' to +a file, and then to use '>>' for subsequent output: + + # clear the file + print "Don't panic" > "guide.txt" + ... + # append + print "Avoid improbability generators" >> "guide.txt" + +This is indeed how redirections must be used from the shell. But in +'awk', it isn't necessary. In this kind of case, a program should use +'>' for all the 'print' statements, because the output file is only +opened once. (It happens that if you mix '>' and '>>' output is +produced in the expected order. However, mixing the operators for the +same file is definitely poor style, and is confusing to readers of your +program.) + + Many older 'awk' implementations limit the number of pipelines that +an 'awk' program may have open to just one! In 'gawk', there is no such +limit. 'gawk' allows a program to open as many pipelines as the +underlying operating system permits. + + Piping into 'sh' + + A particularly powerful way to use redirection is to build command +lines and pipe them into the shell, 'sh'. For example, suppose you have +a list of files brought over from a system where all the file names are +stored in uppercase, and you wish to rename them to have names in all +lowercase. The following program is both simple and efficient: + + { printf("mv %s %s\n", $0, tolower($0)) | "sh" } + + END { close("sh") } + + The 'tolower()' function returns its argument string with all +uppercase characters converted to lowercase (*note String Functions::). +The program builds up a list of command lines, using the 'mv' utility to +rename the files. It then sends the list to the shell for execution. + + *Note Shell Quoting:: for a function that can help in generating +command lines to be fed to the shell. + + +File: gawk.info, Node: Special FD, Next: Special Files, Prev: Redirection, Up: Printing + +5.7 Special Files for Standard Preopened Data Streams +===================================================== + +Running programs conventionally have three input and output streams +already available to them for reading and writing. These are known as +the "standard input", "standard output", and "standard error output". +These open streams (and any other open files or pipes) are often +referred to by the technical term "file descriptors". + + These streams are, by default, connected to your keyboard and screen, +but they are often redirected with the shell, via the '<', '<<', '>', +'>>', '>&', and '|' operators. Standard error is typically used for +writing error messages; the reason there are two separate streams, +standard output and standard error, is so that they can be redirected +separately. + + In traditional implementations of 'awk', the only way to write an +error message to standard error in an 'awk' program is as follows: + + print "Serious error detected!" | "cat 1>&2" + +This works by opening a pipeline to a shell command that can access the +standard error stream that it inherits from the 'awk' process. This is +far from elegant, and it also requires a separate process. So people +writing 'awk' programs often don't do this. Instead, they send the +error messages to the screen, like this: + + print "Serious error detected!" > "/dev/tty" + +('/dev/tty' is a special file supplied by the operating system that is +connected to your keyboard and screen. It represents the "terminal,"(1) +which on modern systems is a keyboard and screen, not a serial console.) +This generally has the same effect, but not always: although the +standard error stream is usually the screen, it can be redirected; when +that happens, writing to the screen is not correct. In fact, if 'awk' +is run from a background job, it may not have a terminal at all. Then +opening '/dev/tty' fails. + + 'gawk', BWK 'awk', and 'mawk' provide special file names for +accessing the three standard streams. If the file name matches one of +these special names when 'gawk' (or one of the others) redirects input +or output, then it directly uses the descriptor that the file name +stands for. These special file names work for all operating systems +that 'gawk' has been ported to, not just those that are POSIX-compliant: + +'/dev/stdin' + The standard input (file descriptor 0). + +'/dev/stdout' + The standard output (file descriptor 1). + +'/dev/stderr' + The standard error output (file descriptor 2). + + With these facilities, the proper way to write an error message then +becomes: + + print "Serious error detected!" > "/dev/stderr" + + Note the use of quotes around the file name. Like with any other +redirection, the value must be a string. It is a common error to omit +the quotes, which leads to confusing results. + + 'gawk' does not treat these file names as special when in +POSIX-compatibility mode. However, because BWK 'awk' supports them, +'gawk' does support them even when invoked with the '--traditional' +option (*note Options::). + + ---------- Footnotes ---------- + + (1) The "tty" in '/dev/tty' stands for "Teletype," a serial terminal. + + +File: gawk.info, Node: Special Files, Next: Close Files And Pipes, Prev: Special FD, Up: Printing + +5.8 Special File names in 'gawk' +================================ + +Besides access to standard input, standard output, and standard error, +'gawk' provides access to any open file descriptor. Additionally, there +are special file names reserved for TCP/IP networking. + +* Menu: + +* Other Inherited Files:: Accessing other open files with + 'gawk'. +* Special Network:: Special files for network communications. +* Special Caveats:: Things to watch out for. + + +File: gawk.info, Node: Other Inherited Files, Next: Special Network, Up: Special Files + +5.8.1 Accessing Other Open Files with 'gawk' +-------------------------------------------- + +Besides the '/dev/stdin', '/dev/stdout', and '/dev/stderr' special file +names mentioned earlier, 'gawk' provides syntax for accessing any other +inherited open file: + +'/dev/fd/N' + The file associated with file descriptor N. Such a file must be + opened by the program initiating the 'awk' execution (typically the + shell). Unless special pains are taken in the shell from which + 'gawk' is invoked, only descriptors 0, 1, and 2 are available. + + The file names '/dev/stdin', '/dev/stdout', and '/dev/stderr' are +essentially aliases for '/dev/fd/0', '/dev/fd/1', and '/dev/fd/2', +respectively. However, those names are more self-explanatory. + + Note that using 'close()' on a file name of the form '"/dev/fd/N"', +for file descriptor numbers above two, does actually close the given +file descriptor. + + +File: gawk.info, Node: Special Network, Next: Special Caveats, Prev: Other Inherited Files, Up: Special Files + +5.8.2 Special Files for Network Communications +---------------------------------------------- + +'gawk' programs can open a two-way TCP/IP connection, acting as either a +client or a server. This is done using a special file name of the form: + + /NET-TYPE/PROTOCOL/LOCAL-PORT/REMOTE-HOST/REMOTE-PORT + + The NET-TYPE is one of 'inet', 'inet4', or 'inet6'. The PROTOCOL is +one of 'tcp' or 'udp', and the other fields represent the other +essential pieces of information for making a networking connection. +These file names are used with the '|&' operator for communicating with +a coprocess (*note Two-way I/O::). This is an advanced feature, +mentioned here only for completeness. Full discussion is delayed until +*note TCP/IP Networking::. + + +File: gawk.info, Node: Special Caveats, Prev: Special Network, Up: Special Files + +5.8.3 Special File name Caveats +------------------------------- + +Here are some things to bear in mind when using the special file names +that 'gawk' provides: + + * Recognition of the file names for the three standard preopened + files is disabled only in POSIX mode. + + * Recognition of the other special file names is disabled if 'gawk' + is in compatibility mode (either '--traditional' or '--posix'; + *note Options::). + + * 'gawk' _always_ interprets these special file names. For example, + using '/dev/fd/4' for output actually writes on file descriptor 4, + and not on a new file descriptor that is 'dup()'ed from file + descriptor 4. Most of the time this does not matter; however, it + is important to _not_ close any of the files related to file + descriptors 0, 1, and 2. Doing so results in unpredictable + behavior. + + +File: gawk.info, Node: Close Files And Pipes, Next: Nonfatal, Prev: Special Files, Up: Printing + +5.9 Closing Input and Output Redirections +========================================= + +If the same file name or the same shell command is used with 'getline' +more than once during the execution of an 'awk' program (*note +Getline::), the file is opened (or the command is executed) the first +time only. At that time, the first record of input is read from that +file or command. The next time the same file or command is used with +'getline', another record is read from it, and so on. + + Similarly, when a file or pipe is opened for output, 'awk' remembers +the file name or command associated with it, and subsequent writes to +the same file or command are appended to the previous writes. The file +or pipe stays open until 'awk' exits. + + This implies that special steps are necessary in order to read the +same file again from the beginning, or to rerun a shell command (rather +than reading more output from the same command). The 'close()' function +makes these things possible: + + close(FILENAME) + +or: + + close(COMMAND) + + The argument FILENAME or COMMAND can be any expression. Its value +must _exactly_ match the string that was used to open the file or start +the command (spaces and other "irrelevant" characters included). For +example, if you open a pipe with this: + + "sort -r names" | getline foo + +then you must close it with this: + + close("sort -r names") + + Once this function call is executed, the next 'getline' from that +file or command, or the next 'print' or 'printf' to that file or +command, reopens the file or reruns the command. Because the expression +that you use to close a file or pipeline must exactly match the +expression used to open the file or run the command, it is good practice +to use a variable to store the file name or command. The previous +example becomes the following: + + sortcom = "sort -r names" + sortcom | getline foo + ... + close(sortcom) + +This helps avoid hard-to-find typographical errors in your 'awk' +programs. Here are some of the reasons for closing an output file: + + * To write a file and read it back later on in the same 'awk' + program. Close the file after writing it, then begin reading it + with 'getline'. + + * To write numerous files, successively, in the same 'awk' program. + If the files aren't closed, eventually 'awk' may exceed a system + limit on the number of open files in one process. It is best to + close each one when the program has finished writing it. + + * To make a command finish. When output is redirected through a + pipe, the command reading the pipe normally continues to try to + read input as long as the pipe is open. Often this means the + command cannot really do its work until the pipe is closed. For + example, if output is redirected to the 'mail' program, the message + is not actually sent until the pipe is closed. + + * To run the same program a second time, with the same arguments. + This is not the same thing as giving more input to the first run! + + For example, suppose a program pipes output to the 'mail' program. + If it outputs several lines redirected to this pipe without closing + it, they make a single message of several lines. By contrast, if + the program closes the pipe after each line of output, then each + line makes a separate message. + + If you use more files than the system allows you to have open, 'gawk' +attempts to multiplex the available open files among your data files. +'gawk''s ability to do this depends upon the facilities of your +operating system, so it may not always work. It is therefore both good +practice and good portability advice to always use 'close()' on your +files when you are done with them. In fact, if you are using a lot of +pipes, it is essential that you close commands when done. For example, +consider something like this: + + { + ... + command = ("grep " $1 " /some/file | my_prog -q " $3) + while ((command | getline) > 0) { + PROCESS OUTPUT OF command + } + # need close(command) here + } + + This example creates a new pipeline based on data in _each_ record. +Without the call to 'close()' indicated in the comment, 'awk' creates +child processes to run the commands, until it eventually runs out of +file descriptors for more pipelines. + + Even though each command has finished (as indicated by the +end-of-file return status from 'getline'), the child process is not +terminated;(1) more importantly, the file descriptor for the pipe is not +closed and released until 'close()' is called or 'awk' exits. + + 'close()' silently does nothing if given an argument that does not +represent a file, pipe, or coprocess that was opened with a redirection. +In such a case, it returns a negative value, indicating an error. In +addition, 'gawk' sets 'ERRNO' to a string indicating the error. + + Note also that 'close(FILENAME)' has no "magic" effects on the +implicit loop that reads through the files named on the command line. +It is, more likely, a close of a file that was never opened with a +redirection, so 'awk' silently does nothing, except return a negative +value. + + When using the '|&' operator to communicate with a coprocess, it is +occasionally useful to be able to close one end of the two-way pipe +without closing the other. This is done by supplying a second argument +to 'close()'. As in any other call to 'close()', the first argument is +the name of the command or special file used to start the coprocess. +The second argument should be a string, with either of the values '"to"' +or '"from"'. Case does not matter. As this is an advanced feature, +discussion is delayed until *note Two-way I/O::, which describes it in +more detail and gives an example. + + Using 'close()''s Return Value + + In many older versions of Unix 'awk', the 'close()' function is +actually a statement. (d.c.) It is a syntax error to try and use the +return value from 'close()': + + command = "..." + command | getline info + retval = close(command) # syntax error in many Unix awks + + 'gawk' treats 'close()' as a function. The return value is -1 if the +argument names something that was never opened with a redirection, or if +there is a system problem closing the file or process. In these cases, +'gawk' sets the predefined variable 'ERRNO' to a string describing the +problem. + + 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 with 512 + number of murderous signal +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 +implementations vary in what they report when closing pipes; thus, the +return value cannot be used portably. (d.c.) In POSIX mode (*note +Options::), 'gawk' just returns zero when closing a pipe. + + ---------- Footnotes ---------- + + (1) The technical terminology is rather morbid. The finished child +is called a "zombie," and cleaning up after it is referred to as +"reaping." + + (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: Nonfatal, Next: Output Summary, Prev: Close Files And Pipes, Up: Printing + +5.10 Enabling Nonfatal Output +============================= + +This minor node describes a 'gawk'-specific feature. + + 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 + error-> 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 + expression is separated by the value of 'OFS' and terminated by the + value of 'ORS'. 'OFMT' provides the conversion format for numeric + values for the 'print' statement. + + * The 'printf' statement provides finer-grained control over output, + with format-control letters for different data types and various + flags that modify the behavior of the format-control letters. + + * Output from both 'print' and 'printf' may be redirected to files, + pipes, and coprocesses. + + * 'gawk' provides special file names for access to standard input, + output, and error, and for network communications. + + * Use 'close()' to close open file, pipe, and coprocess redirections. + 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.12 Exercises +============== + + 1. Rewrite the program: + + awk 'BEGIN { print "Month Crates" + print "----- ------" } + { print $1, " ", $2 }' inventory-shipped + + from *note Output Separators::, by using a new value of 'OFS'. + + 2. Use the 'printf' statement to line up the headings and table data + for the 'inventory-shipped' example that was covered in *note + Print::. + + 3. What happens if you forget the double quotes when redirecting + output, as follows: + + BEGIN { print "Serious error detected!" > /dev/stderr } + + +File: gawk.info, Node: Expressions, Next: Patterns and Actions, Prev: Printing, Up: Top + +6 Expressions +************* + +Expressions are the basic building blocks of 'awk' patterns and actions. +An expression evaluates to a value that you can print, test, or pass to +a function. Additionally, an expression can assign a new value to a +variable or a field by using an assignment operator. + + An expression can serve as a pattern or action statement on its own. +Most other kinds of statements contain one or more expressions that +specify the data on which to operate. As in other languages, +expressions in 'awk' can include variables, array references, constants, +and function calls, as well as combinations of these with various +operators. + +* Menu: + +* Values:: Constants, Variables, and Regular Expressions. +* All Operators:: 'gawk''s operators. +* Truth Values and Conditions:: Testing for true and false. +* Function Calls:: A function call is an expression. +* Precedence:: How various operators nest. +* Locales:: How the locale affects things. +* Expressions Summary:: Expressions summary. + + +File: gawk.info, Node: Values, Next: All Operators, Up: Expressions + +6.1 Constants, Variables, and Conversions +========================================= + +Expressions are built up from values and the operations performed upon +them. This minor node describes the elementary objects that provide the +values used in expressions. + +* Menu: + +* Constants:: String, numeric and regexp constants. +* Using Constant Regexps:: When and how to use a regexp constant. +* Variables:: Variables give names to values for later use. +* Conversion:: The conversion of strings to numbers and vice + versa. + + +File: gawk.info, Node: Constants, Next: Using Constant Regexps, Up: Values + +6.1.1 Constant Expressions +-------------------------- + +The simplest type of expression is the "constant", which always has the +same value. There are three types of constants: numeric, string, and +regular expression. + + Each is used in the appropriate context when you need a data value +that isn't going to change. Numeric constants can have different forms, +but are internally stored in an identical manner. + +* Menu: + +* Scalar Constants:: Numeric and string constants. +* Nondecimal-numbers:: What are octal and hex numbers. +* Regexp Constants:: Regular Expression constants. + + +File: gawk.info, Node: Scalar Constants, Next: Nondecimal-numbers, Up: Constants + +6.1.1.1 Numeric and String Constants +.................................... + +A "numeric constant" stands for a number. This number can be an +integer, a decimal fraction, or a number in scientific (exponential) +notation.(1) Here are some examples of numeric constants that all have +the same value: + + 105 + 1.05e+2 + 1050e-1 + + A "string constant" consists of a sequence of characters enclosed in +double quotation marks. For example: + + "parrot" + +represents the string whose contents are 'parrot'. Strings in 'gawk' +can be of any length, and they can contain any of the possible eight-bit +ASCII characters, including ASCII NUL (character code zero). Other +'awk' implementations may have difficulty with some character codes. + + ---------- Footnotes ---------- + + (1) The internal representation of all numbers, including integers, +uses double-precision floating-point numbers. On most modern systems, +these are in IEEE 754 standard format. *Note Arbitrary Precision +Arithmetic::, for much more information. + + +File: gawk.info, Node: Nondecimal-numbers, Next: Regexp Constants, Prev: Scalar Constants, Up: Constants + +6.1.1.2 Octal and Hexadecimal Numbers +..................................... + +In 'awk', all numbers are in decimal (i.e., base 10). Many other +programming languages allow you to specify numbers in other bases, often +octal (base 8) and hexadecimal (base 16). In octal, the numbers go 0, +1, 2, 3, 4, 5, 6, 7, 10, 11, 12, and so on. Just as '11' in decimal is +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' 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 +notation to signify the base. Octal numbers start with a leading '0', +and hexadecimal numbers start with a leading '0x' or '0X': + +'11' + Decimal value 11 + +'011' + Octal 11, decimal value 9 + +'0x11' + Hexadecimal 11, decimal value 17 + + This example shows the difference: + + $ gawk 'BEGIN { printf "%d, %d, %d\n", 011, 11, 0x11 }' + -| 9, 11, 17 + + Being able to use octal and hexadecimal constants in your programs is +most useful when working with data that cannot be represented +conveniently as characters or as regular numbers, such as binary data of +various sorts. + + 'gawk' allows the use of octal and hexadecimal constants in your +program text. However, such numbers in the input data are not treated +differently; doing so by default would break old programs. (If you +really need to do this, use the '--non-decimal-data' command-line +option; *note Nondecimal Data::.) If you have octal or hexadecimal +data, you can use the 'strtonum()' function (*note String Functions::) +to convert the data into a number. Most of the time, you will want to +use octal or hexadecimal constants when working with the built-in +bit-manipulation functions; see *note Bitwise Functions:: for more +information. + + Unlike in some early C implementations, '8' and '9' are not valid in +octal constants. For example, 'gawk' treats '018' as decimal 18: + + $ gawk 'BEGIN { print "021 is", 021 ; print 018 }' + -| 021 is 17 + -| 18 + + Octal and hexadecimal source code constants are a 'gawk' extension. +If 'gawk' is in compatibility mode (*note Options::), they are not +available. + + A Constant's Base Does Not Affect Its Value + + Once a numeric constant has been converted internally into a number, +'gawk' no longer remembers what the original form of the constant was; +the internal value is always used. This has particular consequences for +conversion of numbers to strings: + + $ gawk 'BEGIN { printf "0x11 is <%s>\n", 0x11 }' + -| 0x11 is <17> + + +File: gawk.info, Node: Regexp Constants, Prev: Nondecimal-numbers, Up: Constants + +6.1.1.3 Regular Expression Constants +.................................... + +A "regexp constant" is a regular expression description enclosed in +slashes, such as '/^beginning and end$/'. Most regexps used in 'awk' +programs are constant, but the '~' and '!~' matching operators can also +match computed or dynamic regexps (which are typically just ordinary +strings or variables that contain a regexp, but could be more complex +expressions). + + +File: gawk.info, Node: Using Constant Regexps, Next: Variables, Prev: Constants, Up: Values + +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. +When a regexp constant appears by itself, it has the same meaning as if +it appeared in a pattern (i.e., '($0 ~ /foo/)'). (d.c.) *Note +Expression Patterns::. This means that the following two code segments: + + if ($0 ~ /barfly/ || $0 ~ /camelot/) + print "found" + +and: + + if (/barfly/ || /camelot/) + print "found" + +are exactly equivalent. One rather bizarre consequence of this rule is +that the following Boolean expression is valid, but does not do what its +author probably intended: + + # Note that /foo/ is on the left of the ~ + if (/foo/ ~ $1) print "found foo" + +This code is "obviously" testing '$1' for a match against the regexp +'/foo/'. But in fact, the expression '/foo/ ~ $1' really means '($0 ~ +/foo/) ~ $1'. In other words, first match the input record against the +regexp '/foo/'. The result is either zero or one, depending upon the +success or failure of the match. That result is then matched against +the first field in the record. Because it is unlikely that you would +ever really want to make this kind of test, 'gawk' issues a warning when +it sees this construct in a program. Another consequence of this rule +is that the assignment statement: + + matches = /foo/ + +assigns either zero or one to the variable 'matches', depending upon the +contents of the current input record. + + Constant regular expressions are also used as the first argument for +the 'gensub()', 'sub()', and 'gsub()' functions, as the second argument +of the 'match()' function, and as the third argument of the 'split()' +and 'patsplit()' functions (*note String Functions::). Modern +implementations of 'awk', including 'gawk', allow the third argument of +'split()' to be a regexp constant, but some older implementations do +not. (d.c.) Because some built-in functions accept regexp constants as +arguments, confusion can arise when attempting to use regexp constants +as arguments to user-defined functions (*note User-defined::). For +example: + + function mysub(pat, repl, str, global) + { + if (global) + gsub(pat, repl, str) + else + sub(pat, repl, str) + return str + } + + { + ... + text = "hi! hi yourself!" + mysub(/hi/, "howdy", text, 1) + ... + } + + In this example, the programmer wants to pass a regexp constant to +the user-defined function 'mysub()', which in turn passes it on to +either 'sub()' or 'gsub()'. However, what really happens is that the +'pat' parameter is assigned a value of either one or zero, depending +upon whether or not '$0' matches '/hi/'. 'gawk' issues a warning when +it sees a regexp constant used as a parameter to a user-defined +function, 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 +--------------- + +"Variables" are ways of storing values at one point in your program for +use later in another part of your program. They can be manipulated +entirely within the program text, and they can also be assigned values +on the 'awk' command line. + +* Menu: + +* Using Variables:: Using variables in your programs. +* Assignment Options:: Setting variables on the command line and a + summary of command-line syntax. This is an + advanced method of input. + + +File: gawk.info, Node: Using Variables, Next: Assignment Options, Up: Variables + +6.1.3.1 Using Variables in a Program +.................................... + +Variables let you give names to values and refer to them later. +Variables have already been used in many of the examples. The name of a +variable must be a sequence of letters, digits, or underscores, and it +may not begin with a digit. Here, a "letter" is any one of the 52 +upper- and lowercase English letters. Other characters that may be +defined as letters in non-English locales are not valid in variable +names. Case is significant in variable names; 'a' and 'A' are distinct +variables. + + A variable name is a valid expression by itself; it represents the +variable's current value. Variables are given new values with +"assignment operators", "increment operators", and "decrement operators" +(*note Assignment Ops::). In addition, the 'sub()' and 'gsub()' +functions can change a variable's value, and the 'match()', 'split()', +and 'patsplit()' functions can change the contents of their array +parameters (*note String Functions::). + + A few variables have special built-in meanings, such as 'FS' (the +field separator) and 'NF' (the number of fields in the current input +record). *Note Built-in Variables:: for a list of the predefined +variables. These predefined variables can be used and assigned just +like all other variables, but their values are also used or changed +automatically by 'awk'. All predefined variables' names are entirely +uppercase. + + Variables in 'awk' can be assigned either numeric or string values. +The kind of value a variable holds can change over the life of a +program. By default, variables are initialized to the empty string, +which is zero if converted to a number. There is no need to explicitly +initialize a variable in 'awk', which is what you would do in C and in +most other traditional languages. + + +File: gawk.info, Node: Assignment Options, Prev: Using Variables, Up: Variables + +6.1.3.2 Assigning Variables on the Command Line +............................................... + +Any 'awk' variable can be set by including a "variable assignment" among +the arguments on the command line when 'awk' is invoked (*note Other +Arguments::). Such an assignment has the following form: + + VARIABLE=TEXT + +With it, a variable is set either at the beginning of the 'awk' run or +in between input files. When the assignment is preceded with the '-v' +option, as in the following: + + -v VARIABLE=TEXT + +the variable is set at the very beginning, even before the 'BEGIN' rules +execute. The '-v' option and its assignment must precede all the file +name arguments, as well as the program text. (*Note Options:: for more +information about the '-v' option.) Otherwise, the variable assignment +is performed at a time determined by its position among the input file +arguments--after the processing of the preceding input file argument. +For example: + + awk '{ print $n }' n=4 inventory-shipped n=2 mail-list + +prints the value of field number 'n' for all input records. Before the +first file is read, the command line sets the variable 'n' equal to +four. This causes the fourth field to be printed in lines from +'inventory-shipped'. After the first file has finished, but before the +second file is started, 'n' is set to two, so that the second field is +printed in lines from 'mail-list': + + $ awk '{ print $n }' n=4 inventory-shipped n=2 mail-list + -| 15 + -| 24 + ... + -| 555-5553 + -| 555-3412 + ... + + Command-line arguments are made available for explicit examination by +the 'awk' program in the 'ARGV' array (*note ARGC and ARGV::). 'awk' +processes the values of command-line assignments for escape sequences +(*note Escape Sequences::). (d.c.) + + +File: gawk.info, Node: Conversion, Prev: Variables, Up: Values + +6.1.4 Conversion of Strings and Numbers +--------------------------------------- + +Number-to-string and string-to-number conversion are generally +straightforward. There can be subtleties to be aware of; this minor +node discusses this important facet of 'awk'. + +* Menu: + +* Strings And Numbers:: How 'awk' Converts Between Strings And + Numbers. +* Locale influences conversions:: How the locale may affect conversions. + + +File: gawk.info, Node: Strings And Numbers, Next: Locale influences conversions, Up: Conversion + +6.1.4.1 How 'awk' Converts Between Strings and Numbers +...................................................... + +Strings are converted to numbers and numbers are converted to strings, +if the context of the 'awk' program demands it. For example, if the +value of either 'foo' or 'bar' in the expression 'foo + bar' happens to +be a string, it is converted to a number before the addition is +performed. If numeric values appear in string concatenation, they are +converted to strings. Consider the following: + + two = 2; three = 3 + print (two three) + 4 + +This prints the (numeric) value 27. The numeric values of the variables +'two' and 'three' are converted to strings and concatenated together. +The resulting string is converted back to the number 23, to which 4 is +then added. + + If, for some reason, you need to force a number to be converted to a +string, concatenate that number with the empty string, '""'. To force a +string to be converted to a number, add zero to that string. A string +is converted to a number by interpreting any numeric prefix of the +string as numerals: '"2.5"' converts to 2.5, '"1e3"' converts to 1,000, +and '"25fix"' has a numeric value of 25. Strings that can't be +interpreted as valid numbers convert to zero. + + The exact manner in which numbers are converted into strings is +controlled by the 'awk' predefined variable 'CONVFMT' (*note Built-in +Variables::). Numbers are converted using the 'sprintf()' function with +'CONVFMT' as the format specifier (*note String Functions::). + + 'CONVFMT''s default value is '"%.6g"', which creates a value with at +most six significant digits. For some applications, you might want to +change it to specify more precision. On most modern machines, 17 digits +is usually enough to capture a floating-point number's value exactly.(1) + + Strange results can occur if you set 'CONVFMT' to a string that +doesn't tell 'sprintf()' how to format floating-point numbers in a +useful way. For example, if you forget the '%' in the format, 'awk' +converts all numbers to the same constant string. + + As a special case, if a number is an integer, then the result of +converting it to a string is _always_ an integer, no matter what the +value of 'CONVFMT' may be. Given the following code fragment: + + CONVFMT = "%2.2f" + a = 12 + b = a "" + +'b' has the value '"12"', not '"12.00"'. (d.c.) + + Pre-POSIX 'awk' Used 'OFMT' for String Conversion + + Prior to the POSIX standard, 'awk' used the value of 'OFMT' for +converting numbers to strings. 'OFMT' specifies the output format to +use when printing numbers with 'print'. 'CONVFMT' was introduced in +order to separate the semantics of conversion from the semantics of +printing. Both 'CONVFMT' and 'OFMT' have the same default value: +'"%.6g"'. In the vast majority of cases, old 'awk' programs do not +change their behavior. *Note Print:: for more information on the +'print' statement. + + ---------- Footnotes ---------- + + (1) Pathological cases can require up to 752 digits (!), but we doubt +that you need to worry about this. + + +File: gawk.info, Node: Locale influences conversions, Prev: Strings And Numbers, Up: Conversion + +6.1.4.2 Locales Can Influence Conversion +........................................ + +Where you are can matter when it comes to converting between numbers and +strings. The local character set and language--the "locale"--can affect +numeric formats. In particular, for 'awk' programs, it affects the +decimal point character and the thousands-separator character. The +'"C"' locale, and most English-language locales, use the period +character ('.') as the decimal point and don't have a thousands +separator. However, many (if not most) European and non-English locales +use the comma (',') as the decimal point character. European locales +often use either a space or a period as the thousands separator, if they +have one. + + The POSIX standard says that 'awk' always uses the period as the +decimal point when reading the 'awk' program source code, and for +command-line variable assignments (*note Other Arguments::). However, +when interpreting input data, for 'print' and 'printf' output, and for +number-to-string conversion, the local decimal point character is used. +(d.c.) In all cases, numbers in source code and in input data cannot +have a thousands separator. Here are some examples indicating the +difference in behavior, on a GNU/Linux system: + + $ export POSIXLY_CORRECT=1 Force POSIX behavior + $ gawk 'BEGIN { printf "%g\n", 3.1415927 }' + -| 3.14159 + $ LC_ALL=en_DK.utf-8 gawk 'BEGIN { printf "%g\n", 3.1415927 }' + -| 3,14159 + $ echo 4,321 | gawk '{ print $1 + 1 }' + -| 5 + $ echo 4,321 | LC_ALL=en_DK.utf-8 gawk '{ print $1 + 1 }' + -| 5,321 + +The 'en_DK.utf-8' locale is for English in Denmark, where the comma acts +as the decimal point separator. In the normal '"C"' locale, 'gawk' +treats '4,321' as 4, while in the Danish locale, it's treated as the +full number including the fractional part, 4.321. + + Some earlier versions of 'gawk' fully complied with this aspect of +the standard. However, many users in non-English locales complained +about this behavior, because their data used a period as the decimal +point, so the default behavior was restored to use a period as the +decimal point character. You can use the '--use-lc-numeric' option +(*note Options::) to force 'gawk' to use the locale's decimal point +character. ('gawk' also uses the locale's decimal point character when +in POSIX mode, either via '--posix' or the 'POSIXLY_CORRECT' environment +variable, as shown previously.) + + *note Table 6.1: table-locale-affects. describes the cases in which +the locale's decimal point character is used and when a period is used. +Some of these features have not been described yet. + +Feature Default '--posix' or + '--use-lc-numeric' +------------------------------------------------------------ +'%'g' Use locale Use locale +'%g' Use period Use locale +Input Use period Use locale +'strtonum()'Use period Use locale + +Table 6.1: Locale decimal point versus a period + + Finally, modern-day formal standards and the IEEE standard +floating-point representation can have an unusual but important effect +on the way 'gawk' converts some special string values to numbers. The +details are presented in *note POSIX Floating Point Problems::. + + +File: gawk.info, Node: All Operators, Next: Truth Values and Conditions, Prev: Values, Up: Expressions + +6.2 Operators: Doing Something with Values +========================================== + +This minor node introduces the "operators" that make use of the values +provided by constants and variables. + +* Menu: + +* Arithmetic Ops:: Arithmetic operations ('+', '-', + etc.) +* Concatenation:: Concatenating strings. +* Assignment Ops:: Changing the value of a variable or a field. +* Increment Ops:: Incrementing the numeric value of a variable. + + +File: gawk.info, Node: Arithmetic Ops, Next: Concatenation, Up: All Operators + +6.2.1 Arithmetic Operators +-------------------------- + +The 'awk' language uses the common arithmetic operators when evaluating +expressions. All of these arithmetic operators follow normal precedence +rules and work as you would expect them to. + + The following example uses a file named 'grades', which contains a +list of student names as well as three test scores per student (it's a +small class): + + Pat 100 97 58 + Sandy 84 72 93 + Chris 72 92 89 + +This program takes the file 'grades' and prints the average of the +scores: + + $ awk '{ sum = $2 + $3 + $4 ; avg = sum / 3 + > print $1, avg }' grades + -| Pat 85 + -| Sandy 83 + -| Chris 84.3333 + + The following list provides the arithmetic operators in 'awk', in +order from the highest precedence to the lowest: + +'X ^ Y' +'X ** Y' + Exponentiation; X raised to the Y power. '2 ^ 3' has the value + eight; the character sequence '**' is equivalent to '^'. (c.e.) + +'- X' + Negation. + +'+ X' + Unary plus; the expression is converted to a number. + +'X * Y' + Multiplication. + +'X / Y' + Division; because all numbers in 'awk' are floating-point numbers, + the result is _not_ rounded to an integer--'3 / 4' has the value + 0.75. (It is a common mistake, especially for C programmers, to + forget that _all_ numbers in 'awk' are floating point, and that + division of integer-looking constants produces a real number, not + an integer.) + +'X % Y' + Remainder; further discussion is provided in the text, just after + this list. + +'X + Y' + Addition. + +'X - Y' + Subtraction. + + Unary plus and minus have the same precedence, the multiplication +operators all have the same precedence, and addition and subtraction +have the same precedence. + + When computing the remainder of 'X % Y', the quotient is rounded +toward zero to an integer and multiplied by Y. This result is +subtracted from X; this operation is sometimes known as "trunc-mod." +The following relation always holds: + + b * int(a / b) + (a % b) == a + + One possibly undesirable effect of this definition of remainder is +that 'X % Y' is negative if X is negative. Thus: + + -17 % 8 = -1 + + In other 'awk' implementations, the signedness of the remainder may +be machine-dependent. + + NOTE: The POSIX standard only specifies the use of '^' for + exponentiation. For maximum portability, do not use the '**' + operator. + + +File: gawk.info, Node: Concatenation, Next: Assignment Ops, Prev: Arithmetic Ops, Up: All Operators + +6.2.2 String Concatenation +-------------------------- + + It seemed like a good idea at the time. + -- _Brian Kernighan_ + + There is only one string operation: concatenation. It does not have +a specific operator to represent it. Instead, concatenation is +performed by writing expressions next to one another, with no operator. +For example: + + $ awk '{ print "Field number one: " $1 }' mail-list + -| Field number one: Amelia + -| Field number one: Anthony + ... + + Without the space in the string constant after the ':', the line runs +together. For example: + + $ awk '{ print "Field number one:" $1 }' mail-list + -| Field number one:Amelia + -| Field number one:Anthony + ... + + Because string concatenation does not have an explicit operator, it +is often necessary to ensure that it happens at the right time by using +parentheses to enclose the items to concatenate. For example, you might +expect that the following code fragment concatenates 'file' and 'name': + + file = "file" + name = "name" + print "something meaningful" > file name + +This produces a syntax error with some versions of Unix 'awk'.(1) It is +necessary to use the following: + + print "something meaningful" > (file name) + + Parentheses should be used around concatenation in all but the most +common contexts, such as on the righthand side of '='. Be careful about +the kinds of expressions used in string concatenation. In particular, +the order of evaluation of expressions used for concatenation is +undefined in the 'awk' language. Consider this example: + + BEGIN { + a = "don't" + print (a " " (a = "panic")) + } + +It is not defined whether the second assignment to 'a' happens before or +after the value of 'a' is retrieved for producing the concatenated +value. The result could be either 'don't panic', or 'panic panic'. + + The precedence of concatenation, when mixed with other operators, is +often counter-intuitive. Consider this example: + + $ awk 'BEGIN { print -12 " " -24 }' + -| -12-24 + + This "obviously" is concatenating -12, a space, and -24. But where +did the space disappear to? The answer lies in the combination of +operator precedences and 'awk''s automatic conversion rules. To get the +desired result, write the program this way: + + $ awk 'BEGIN { print -12 " " (-24) }' + -| -12 -24 + + This forces 'awk' to treat the '-' on the '-24' as unary. Otherwise, +it's parsed as follows: + + -12 ('" "' - 24) + => -12 (0 - 24) + => -12 (-24) + => -12-24 + + As mentioned earlier, when mixing concatenation with other operators, +_parenthesize_. Otherwise, you're never quite sure what you'll get. + + ---------- Footnotes ---------- + + (1) It happens that BWK 'awk', 'gawk', and 'mawk' all "get it right," +but you should not rely on this. + + +File: gawk.info, Node: Assignment Ops, Next: Increment Ops, Prev: Concatenation, Up: All Operators + +6.2.3 Assignment Expressions +---------------------------- + +An "assignment" is an expression that stores a (usually different) value +into a variable. For example, let's assign the value one to the +variable 'z': + + z = 1 + + After this expression is executed, the variable 'z' has the value +one. Whatever old value 'z' had before the assignment is forgotten. + + Assignments can also store string values. For example, the following +stores the value '"this food is good"' in the variable 'message': + + thing = "food" + predicate = "good" + message = "this " thing " is " predicate + +This also illustrates string concatenation. The '=' sign is called an +"assignment operator". It is the simplest assignment operator because +the value of the righthand operand is stored unchanged. Most operators +(addition, concatenation, and so on) have no effect except to compute a +value. If the value isn't used, there's no reason to use the operator. +An assignment operator is different; it does produce a value, but even +if you ignore it, the assignment still makes itself felt through the +alteration of the variable. We call this a "side effect". + + The lefthand operand of an assignment need not be a variable (*note +Variables::); it can also be a field (*note Changing Fields::) or an +array element (*note Arrays::). These are all called "lvalues", which +means they can appear on the lefthand side of an assignment operator. +The righthand operand may be any expression; it produces the new value +that the assignment stores in the specified variable, field, or array +element. (Such values are called "rvalues".) + + It is important to note that variables do _not_ have permanent types. +A variable's type is simply the type of whatever value was last assigned +to it. In the following program fragment, the variable 'foo' has a +numeric value at first, and a string value later on: + + foo = 1 + print foo + foo = "bar" + print foo + +When the second assignment gives 'foo' a string value, the fact that it +previously had a numeric value is forgotten. + + String values that do not begin with a digit have a numeric value of +zero. After executing the following code, the value of 'foo' is five: + + foo = "a string" + foo = foo + 5 + + NOTE: Using a variable as a number and then later as a string can + be confusing and is poor programming style. The previous two + examples illustrate how 'awk' works, _not_ how you should write + your programs! + + An assignment is an expression, so it has a value--the same value +that is assigned. Thus, 'z = 1' is an expression with the value one. +One consequence of this is that you can write multiple assignments +together, such as: + + x = y = z = 5 + +This example stores the value five in all three variables ('x', 'y', and +'z'). It does so because the value of 'z = 5', which is five, is stored +into 'y' and then the value of 'y = z = 5', which is five, is stored +into 'x'. + + Assignments may be used anywhere an expression is called for. For +example, it is valid to write 'x != (y = 1)' to set 'y' to one, and then +test whether 'x' equals one. But this style tends to make programs hard +to read; such nesting of assignments should be avoided, except perhaps +in a one-shot program. + + Aside from '=', there are several other assignment operators that do +arithmetic with the old value of the variable. For example, the +operator '+=' computes a new value by adding the righthand value to the +old value of the variable. Thus, the following assignment adds five to +the value of 'foo': + + foo += 5 + +This is equivalent to the following: + + foo = foo + 5 + +Use whichever makes the meaning of your program clearer. + + There are situations where using '+=' (or any assignment operator) is +_not_ the same as simply repeating the lefthand operand in the righthand +expression. For example: + + # Thanks to Pat Rankin for this example + BEGIN { + foo[rand()] += 5 + for (x in foo) + print x, foo[x] + + bar[rand()] = bar[rand()] + 5 + for (x in bar) + print x, bar[x] + } + +The indices of 'bar' are practically guaranteed to be different, because +'rand()' returns different values each time it is called. (Arrays and +the 'rand()' function haven't been covered yet. *Note Arrays::, and +*note Numeric Functions:: for more information.) This example +illustrates an important fact about assignment operators: the lefthand +expression is only evaluated _once_. + + It is up to the implementation as to which expression is evaluated +first, the lefthand or the righthand. Consider this example: + + i = 1 + a[i += 2] = i + 1 + +The value of 'a[3]' could be either two or four. + + *note Table 6.2: table-assign-ops. lists the arithmetic assignment +operators. In each case, the righthand operand is an expression whose +value is converted to a number. + +Operator Effect +-------------------------------------------------------------------------- +LVALUE '+=' Add INCREMENT to the value of LVALUE. +INCREMENT +LVALUE '-=' Subtract DECREMENT from the value of LVALUE. +DECREMENT +LVALUE '*=' Multiply the value of LVALUE by COEFFICIENT. +COEFFICIENT +LVALUE '/=' DIVISOR Divide the value of LVALUE by DIVISOR. +LVALUE '%=' MODULUS Set LVALUE to its remainder by MODULUS. +LVALUE '^=' POWER Raise LVALUE to the power POWER. +LVALUE '**=' POWER Raise LVALUE to the power POWER. (c.e.) + +Table 6.2: Arithmetic assignment operators + + NOTE: Only the '^=' operator is specified by POSIX. For maximum + portability, do not use the '**=' operator. + + Syntactic Ambiguities Between '/=' and Regular Expressions + + There is a syntactic ambiguity between the '/=' assignment operator +and regexp constants whose first character is an '='. (d.c.) This is +most notable in some commercial 'awk' versions. For example: + + $ awk /==/ /dev/null + error-> awk: syntax error at source line 1 + error-> context is + error-> >>> /= <<< + error-> awk: bailing out at source line 1 + +A workaround is: + + awk '/[=]=/' /dev/null + + 'gawk' does not have this problem; BWK 'awk' and 'mawk' also do not. + + +File: gawk.info, Node: Increment Ops, Prev: Assignment Ops, Up: All Operators + +6.2.4 Increment and Decrement Operators +--------------------------------------- + +"Increment" and "decrement operators" increase or decrease the value of +a variable by one. An assignment operator can do the same thing, so the +increment operators add no power to the 'awk' language; however, they +are convenient abbreviations for very common operations. + + The operator used for adding one is written '++'. It can be used to +increment a variable either before or after taking its value. To +"pre-increment" a variable 'v', write '++v'. This adds one to the value +of 'v'--that new value is also the value of the expression. (The +assignment expression 'v += 1' is completely equivalent.) Writing the +'++' after the variable specifies "post-increment". This increments the +variable value just the same; the difference is that the value of the +increment expression itself is the variable's _old_ value. Thus, if +'foo' has the value four, then the expression 'foo++' has the value +four, but it changes the value of 'foo' to five. In other words, the +operator returns the old value of the variable, but with the side effect +of incrementing it. + + The post-increment 'foo++' is nearly the same as writing '(foo += 1) +- 1'. It is not perfectly equivalent because all numbers in 'awk' are +floating point--in floating point, 'foo + 1 - 1' does not necessarily +equal 'foo'. But the difference is minute as long as you stick to +numbers that are fairly small (less than 10e12). + + Fields and array elements are incremented just like variables. (Use +'$(i++)' when you want to do a field reference and a variable increment +at the same time. The parentheses are necessary because of the +precedence of the field reference operator '$'.) + + The decrement operator '--' works just like '++', except that it +subtracts one instead of adding it. As with '++', it can be used before +the lvalue to pre-decrement or after it to post-decrement. Following is +a summary of increment and decrement expressions: + +'++LVALUE' + Increment LVALUE, returning the new value as the value of the + expression. + +'LVALUE++' + Increment LVALUE, returning the _old_ value of LVALUE as the value + of the expression. + +'--LVALUE' + Decrement LVALUE, returning the new value as the value of the + expression. (This expression is like '++LVALUE', but instead of + adding, it subtracts.) + +'LVALUE--' + Decrement LVALUE, returning the _old_ value of LVALUE as the value + of the expression. (This expression is like 'LVALUE++', but + instead of adding, it subtracts.) + + Operator Evaluation Order + + Doctor, it hurts when I do this! + Then don't do that! + -- _Groucho Marx_ + +What happens for something like the following? + + b = 6 + print b += b++ + +Or something even stranger? + + b = 6 + b += ++b + b++ + print b + + In other words, when do the various side effects prescribed by the +postfix operators ('b++') take effect? When side effects happen is +"implementation-defined". In other words, it is up to the particular +version of 'awk'. The result for the first example may be 12 or 13, and +for the second, it may be 22 or 23. + + In short, doing things like this is not recommended and definitely +not anything that you can rely upon for portability. You should avoid +such things in your own programs. + + +File: gawk.info, Node: Truth Values and Conditions, Next: Function Calls, Prev: All Operators, Up: Expressions + +6.3 Truth Values and Conditions +=============================== + +In certain contexts, expression values also serve as "truth values"; +i.e., they determine what should happen next as the program runs. This +minor node describes how 'awk' defines "true" and "false" and how values +are compared. + +* Menu: + +* Truth Values:: What is "true" and what is "false". +* Typing and Comparison:: How variables acquire types and how this + affects comparison of numbers and strings with + '<', etc. +* Boolean Ops:: Combining comparison expressions using boolean + operators '||' ("or"), '&&' + ("and") and '!' ("not"). +* Conditional Exp:: Conditional expressions select between two + subexpressions under control of a third + subexpression. + + +File: gawk.info, Node: Truth Values, Next: Typing and Comparison, Up: Truth Values and Conditions + +6.3.1 True and False in 'awk' +----------------------------- + +Many programming languages have a special representation for the +concepts of "true" and "false." Such languages usually use the special +constants 'true' and 'false', or perhaps their uppercase equivalents. +However, 'awk' is different. It borrows a very simple concept of true +and false from C. In 'awk', any nonzero numeric value _or_ any nonempty +string value is true. Any other value (zero or the null string, '""') +is false. The following program prints 'A strange truth value' three +times: + + BEGIN { + if (3.1415927) + print "A strange truth value" + if ("Four Score And Seven Years Ago") + print "A strange truth value" + if (j = 57) + print "A strange truth value" + } + + There is a surprising consequence of the "nonzero or non-null" rule: +the string constant '"0"' is actually true, because it is non-null. +(d.c.) + + +File: gawk.info, Node: Typing and Comparison, Next: Boolean Ops, Prev: Truth Values, Up: Truth Values and Conditions + +6.3.2 Variable Typing and Comparison Expressions +------------------------------------------------ + + The Guide is definitive. Reality is frequently inaccurate. + -- _Douglas Adams, 'The Hitchhiker's Guide to the Galaxy'_ + + Unlike in other programming languages, in 'awk' variables do not have +a fixed type. Instead, they can be either a number or a string, +depending upon the value that is assigned to them. We look now at how +variables are typed, and how 'awk' compares variables. + +* Menu: + +* Variable Typing:: String type versus numeric type. +* Comparison Operators:: The comparison operators. +* POSIX String Comparison:: String comparison with POSIX rules. + + +File: gawk.info, Node: Variable Typing, Next: Comparison Operators, Up: Typing and Comparison + +6.3.2.1 String Type versus Numeric Type +....................................... + +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. + + * A string constant or the result of a string operation has the + "string" attribute. + + * 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.(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. + + The last rule is particularly important. In the following program, +'a' has numeric type, even though it is later used in a string +operation: + + BEGIN { + a = 12.345 + b = a " is a cute number" + print b + } + + When two operands are compared, either string comparison or numeric +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 +--------+---------------------------------------------- + + 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 +characters and is therefore also a string. Thus, for example, the +string constant '" +3.14"', when it appears in program source code, is a +string--even though it looks numeric--and is _never_ treated as a number +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. (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: 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 + $ echo ' +3.14' | awk '{ print($0 == "+3.14") }' False + -| 0 + $ echo ' +3.14' | awk '{ print($0 == "3.14") }' False + -| 0 + $ echo ' +3.14' | awk '{ print($0 == 3.14) }' True + -| 1 + $ echo ' +3.14' | awk '{ print($1 == " +3.14") }' False + -| 0 + $ echo ' +3.14' | awk '{ print($1 == "+3.14") }' True + -| 1 + $ echo ' +3.14' | awk '{ print($1 == "3.14") }' False + -| 0 + $ 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 + +6.3.2.2 Comparison Operators +............................ + +"Comparison expressions" compare strings or numbers for relationships +such as equality. They are written using "relational operators", which +are a superset of those in C. *note Table 6.3: table-relational-ops. +describes them. + +Expression Result +-------------------------------------------------------------------------- +X '<' Y True if X is less than Y +X '<=' Y True if X is less than or equal to Y +X '>' Y True if X is greater than Y +X '>=' Y True if X is greater than or equal to Y +X '==' Y True if X is equal to Y +X '!=' Y True if X is not equal to Y +X '~' Y True if the string X matches the regexp denoted by Y +X '!~' Y True if the string X does not match the regexp + denoted by Y +SUBSCRIPT 'in' True if the array ARRAY has an element with the +ARRAY subscript SUBSCRIPT + +Table 6.3: Relational operators + + Comparison expressions have the value one if true and zero if false. +When comparing operands of mixed types, numeric operands are converted +to strings using the value of 'CONVFMT' (*note Conversion::). + + Strings are compared by comparing the first character of each, then +the second character of each, and so on. Thus, '"10"' is less than +'"9"'. If there are two strings where one is a prefix of the other, the +shorter string is less than the longer one. Thus, '"abc"' is less than +'"abcd"'. + + It is very easy to accidentally mistype the '==' operator and leave +off one of the '=' characters. The result is still valid 'awk' code, +but the program does not do what is intended: + + if (a = b) # oops! should be a == b + ... + else + ... + +Unless 'b' happens to be zero or the null string, the 'if' part of the +test always succeeds. Because the operators are so similar, this kind +of error is very difficult to spot when scanning the source code. + + The following list of expressions illustrates the kinds of +comparisons 'awk' performs, as well as what the result of each +comparison is: + +'1.5 <= 2.0' + Numeric comparison (true) + +'"abc" >= "xyz"' + String comparison (false) + +'1.5 != " +2"' + String comparison (true) + +'"1e2" < "3"' + String comparison (true) + +'a = 2; b = "2"' +'a == b' + String comparison (true) + +'a = 2; b = " +2"' +'a == b' + String comparison (false) + + In this example: + + $ echo 1e2 3 | awk '{ print ($1 < $2) ? "true" : "false" }' + -| false + +the result is 'false' because both '$1' and '$2' are user input. They +are numeric strings--therefore both have the strnum attribute, dictating +a numeric comparison. The purpose of the comparison rules and the use +of numeric strings is to attempt to produce the behavior that is "least +surprising," while still "doing the right thing." + + String comparisons and regular expression comparisons are very +different. For example: + + x == "foo" + +has the value one, or is true if the variable 'x' is precisely 'foo'. +By contrast: + + x ~ /foo/ + +has the value one if 'x' contains 'foo', such as '"Oh, what a fool am +I!"'. + + The righthand operand of the '~' and '!~' operators may be either a +regexp constant ('/'...'/') or an ordinary expression. In the latter +case, the value of the expression as a string is used as a dynamic +regexp (*note Regexp Usage::; also *note Computed Regexps::). + + A constant regular expression in slashes by itself is also an +expression. '/REGEXP/' is an abbreviation for the following comparison +expression: + + $0 ~ /REGEXP/ + + One special place where '/foo/' is _not_ an abbreviation for '$0 ~ +/foo/' is when it is the righthand operand of '~' or '!~'. *Note Using +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 Based on Locale Collating Order +......................................................... + +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 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")) }' + -| ABC < abc = TRUE + $ gawk --posix 'BEGIN { printf("ABC < abc = %s\n", + > ("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 + +6.3.3 Boolean Expressions +------------------------- + +A "Boolean expression" is a combination of comparison expressions or +matching expressions, using the Boolean operators "or" ('||'), "and" +('&&'), and "not" ('!'), along with parentheses to control nesting. The +truth value of the Boolean expression is computed by combining the truth +values of the component expressions. Boolean expressions are also +referred to as "logical expressions". The terms are equivalent. + + Boolean expressions can be used wherever comparison and matching +expressions can be used. They can be used in 'if', 'while', 'do', and +'for' statements (*note Statements::). They have numeric values (one if +true, zero if false) that come into play if the result of the Boolean +expression is stored in a variable or used in arithmetic. + + In addition, every Boolean expression is also a valid pattern, so you +can use one as a pattern to control the execution of rules. The Boolean +operators are: + +'BOOLEAN1 && BOOLEAN2' + True if both BOOLEAN1 and BOOLEAN2 are true. For example, the + following statement prints the current input record if it contains + both 'edu' and 'li': + + if ($0 ~ /edu/ && $0 ~ /li/) print + + The subexpression BOOLEAN2 is evaluated only if BOOLEAN1 is true. + This can make a difference when BOOLEAN2 contains expressions that + have side effects. In the case of '$0 ~ /foo/ && ($2 == bar++)', + the variable 'bar' is not incremented if there is no substring + 'foo' in the record. + +'BOOLEAN1 || BOOLEAN2' + True if at least one of BOOLEAN1 or BOOLEAN2 is true. For example, + the following statement prints all records in the input that + contain _either_ 'edu' or 'li': + + if ($0 ~ /edu/ || $0 ~ /li/) print + + The subexpression BOOLEAN2 is evaluated only if BOOLEAN1 is false. + This can make a difference when BOOLEAN2 contains expressions that + have side effects. (Thus, this test never really distinguishes + records that contain both 'edu' and 'li'--as soon as 'edu' is + matched, the full test succeeds.) + +'! BOOLEAN' + True if BOOLEAN is false. For example, the following program + prints 'no home!' in the unusual event that the 'HOME' environment + variable is not defined: + + BEGIN { if (! ("HOME" in ENVIRON)) + print "no home!" } + + (The 'in' operator is described in *note Reference to Elements::.) + + The '&&' and '||' operators are called "short-circuit" operators +because of the way they work. Evaluation of the full expression is +"short-circuited" if the result can be determined partway through its +evaluation. + + Statements that end with '&&' or '||' can be continued simply by +putting a newline after them. But you cannot put a newline in front of +either of these operators without using backslash continuation (*note +Statements/Lines::). + + The actual value of an expression using the '!' operator is either +one or zero, depending upon the truth value of the expression it is +applied to. The '!' operator is often useful for changing the sense of +a flag variable from false to true and back again. For example, the +following program is one way to print lines in between special +bracketing lines: + + $1 == "START" { interested = ! interested; next } + interested { print } + $1 == "END" { interested = ! interested; next } + +The variable 'interested', as with all 'awk' variables, starts out +initialized to zero, which is also false. When a line is seen whose +first field is 'START', the value of 'interested' is toggled to true, +using '!'. The next rule prints lines as long as 'interested' is true. +When a line is seen whose first field is 'END', 'interested' is toggled +back to false.(1) + + Most commonly, the '!' operator is used in the conditions of 'if' and +'while' statements, where it often makes more sense to phrase the logic +in the negative: + + if (! SOME CONDITION || SOME OTHER CONDITION) { + ... DO WHATEVER PROCESSING ... + } + + NOTE: The 'next' statement is discussed in *note Next Statement::. + 'next' tells 'awk' to skip the rest of the rules, get the next + record, and start processing the rules over again at the top. The + reason it's there is to avoid printing the bracketing 'START' and + 'END' lines. + + ---------- Footnotes ---------- + + (1) This program has a bug; it prints lines starting with 'END'. How +would you fix it? + + +File: gawk.info, Node: Conditional Exp, Prev: Boolean Ops, Up: Truth Values and Conditions + +6.3.4 Conditional Expressions +----------------------------- + +A "conditional expression" is a special kind of expression that has +three operands. It allows you to use one expression's value to select +one of two other expressions. The conditional expression in 'awk' is +the same as in the C language, as shown here: + + SELECTOR ? IF-TRUE-EXP : IF-FALSE-EXP + +There are three subexpressions. The first, SELECTOR, is always computed +first. If it is "true" (not zero or not null), then IF-TRUE-EXP is +computed next, and its value becomes the value of the whole expression. +Otherwise, IF-FALSE-EXP is computed next, and its value becomes the +value of the whole expression. For example, the following expression +produces the absolute value of 'x': + + x >= 0 ? x : -x + + Each time the conditional expression is computed, only one of +IF-TRUE-EXP and IF-FALSE-EXP is used; the other is ignored. This is +important when the expressions have side effects. For example, this +conditional expression examines element 'i' of either array 'a' or array +'b', and increments 'i': + + x == y ? a[i++] : b[i++] + +This is guaranteed to increment 'i' exactly once, because each time only +one of the two increment expressions is executed and the other is not. +*Note Arrays::, for more information about arrays. + + As a minor 'gawk' extension, a statement that uses '?:' can be +continued simply by putting a newline after either character. However, +putting a newline in front of either character does not work without +using backslash continuation (*note Statements/Lines::). If '--posix' +is specified (*note Options::), this extension is disabled. + + +File: gawk.info, Node: Function Calls, Next: Precedence, Prev: Truth Values and Conditions, Up: Expressions + +6.4 Function Calls +================== + +A "function" is a name for a particular calculation. This enables you +to ask for it by name at any point in the program. For example, the +function 'sqrt()' computes the square root of a number. + + A fixed set of functions are "built in", which means they are +available in every 'awk' program. The 'sqrt()' function is one of +these. *Note Built-in:: for a list of built-in functions and their +descriptions. In addition, you can define functions for use in your +program. *Note User-defined:: for instructions on how to do this. +Finally, 'gawk' lets you write functions in C or C++ that may be called +from your program (*note Dynamic Extensions::). + + The way to use a function is with a "function call" expression, which +consists of the function name followed immediately by a list of +"arguments" in parentheses. The arguments are expressions that provide +the raw materials for the function's calculations. When there is more +than one argument, they are separated by commas. If there are no +arguments, just write '()' after the function name. The following +examples show function calls with and without arguments: + + sqrt(x^2 + y^2) one argument + atan2(y, x) two arguments + rand() no arguments + + CAUTION: Do not put any space between the function name and the + opening parenthesis! A user-defined function name looks just like + the name of a variable--a space would make the expression look like + concatenation of a variable with an expression inside parentheses. + With built-in functions, space before the parenthesis is harmless, + but it is best not to get into the habit of using space to avoid + mistakes with user-defined functions. + + Each function expects a particular number of arguments. For example, +the 'sqrt()' function must be called with a single argument, the number +of which to take the square root: + + sqrt(ARGUMENT) + + Some of the built-in functions have one or more optional arguments. +If those arguments are not supplied, the functions use a reasonable +default value. *Note Built-in:: for full details. If arguments are +omitted in calls to user-defined functions, then those arguments are +treated as local variables. Such local variables act like the empty +string if referenced where a string value is required, and like zero if +referenced where a numeric value is required (*note User-defined::). + + As an advanced feature, 'gawk' provides indirect function calls, +which is a way to choose the function to call at runtime, instead of +when you write the source code to your program. We defer discussion of +this feature until later; see *note Indirect Calls::. + + Like every other expression, the function call has a value, often +called the "return value", which is computed by the function based on +the arguments you give it. In this example, the return value of +'sqrt(ARGUMENT)' is the square root of ARGUMENT. The following program +reads numbers, one number per line, and prints the square root of each +one: + + $ awk '{ print "The square root of", $1, "is", sqrt($1) }' + 1 + -| The square root of 1 is 1 + 3 + -| The square root of 3 is 1.73205 + 5 + -| The square root of 5 is 2.23607 + Ctrl-d + + A function can also have side effects, such as assigning values to +certain variables or doing I/O. This program shows how the 'match()' +function (*note String Functions::) changes the variables 'RSTART' and +'RLENGTH': + + { + if (match($1, $2)) + print RSTART, RLENGTH + else + print "no match" + } + +Here is a sample run: + + $ awk -f matchit.awk + aaccdd c+ + -| 3 2 + foo bar + -| no match + abcdefg e + -| 5 1 + + +File: gawk.info, Node: Precedence, Next: Locales, Prev: Function Calls, Up: Expressions + +6.5 Operator Precedence (How Operators Nest) +============================================ + +"Operator precedence" determines how operators are grouped when +different operators appear close by in one expression. For example, '*' +has higher precedence than '+'; thus, 'a + b * c' means to multiply 'b' +and 'c', and then add 'a' to the product (i.e., 'a + (b * c)'). + + The normal precedence of the operators can be overruled by using +parentheses. Think of the precedence rules as saying where the +parentheses are assumed to be. In fact, it is wise to always use +parentheses whenever there is an unusual combination of operators, +because other people who read the program may not remember what the +precedence is in this case. Even experienced programmers occasionally +forget the exact rules, which leads to mistakes. Explicit parentheses +help prevent any such mistakes. + + When operators of equal precedence are used together, the leftmost +operator groups first, except for the assignment, conditional, and +exponentiation operators, which group in the opposite order. Thus, 'a - +b + c' groups as '(a - b) + c' and 'a = b = c' groups as 'a = (b = c)'. + + Normally the precedence of prefix unary operators does not matter, +because there is only one way to interpret them: innermost first. Thus, +'$++i' means '$(++i)' and '++$x' means '++($x)'. However, when another +operator follows the operand, then the precedence of the unary operators +can matter. '$x^2' means '($x)^2', but '-x^2' means '-(x^2)', because +'-' has lower precedence than '^', whereas '$' has higher precedence. +Also, operators cannot be combined in a way that violates the precedence +rules; for example, '$$0++--' is not a valid expression because the +first '$' has higher precedence than the '++'; to avoid the problem the +expression can be rewritten as '$($0++)--'. + + This list presents 'awk''s operators, in order of highest to lowest +precedence: + +'('...')' + Grouping. + +'$' + Field reference. + +'++ --' + Increment, decrement. + +'^ **' + Exponentiation. These operators group right to left. + +'+ - !' + Unary plus, minus, logical "not." + +'* / %' + Multiplication, division, remainder. + +'+ -' + Addition, subtraction. + +String concatenation + There is no special symbol for concatenation. The operands are + simply written side by side (*note Concatenation::). + +'< <= == != > >= >> | |&' + Relational and redirection. The relational operators and the + redirections have the same precedence level. Characters such as + '>' serve both as relationals and as redirections; the context + distinguishes between the two meanings. + + Note that the I/O redirection operators in 'print' and 'printf' + statements belong to the statement level, not to expressions. The + redirection does not produce an expression that could be the + operand of another operator. As a result, it does not make sense + to use a redirection operator near another operator of lower + precedence without parentheses. Such combinations (e.g., 'print + foo > a ? b : c') result in syntax errors. The correct way to + write this statement is 'print foo > (a ? b : c)'. + +'~ !~' + Matching, nonmatching. + +'in' + Array membership. + +'&&' + Logical "and." + +'||' + Logical "or." + +'?:' + Conditional. This operator groups right to left. + +'= += -= *= /= %= ^= **=' + Assignment. These operators group right to left. + + NOTE: The '|&', '**', and '**=' operators are not specified by + POSIX. For maximum portability, do not use them. + + +File: gawk.info, Node: Locales, Next: Expressions Summary, Prev: Precedence, Up: Expressions + +6.6 Where You Are Makes a Difference +==================================== + +Modern systems support the notion of "locales": a way to tell the system +about the local character set and language. The ISO C standard defines +a default '"C"' locale, which is an environment that is typical of what +many C programmers are used to. + + Once upon a time, the locale setting used to affect regexp matching, +but this is no longer true (*note Ranges and Locales::). + + Locales can affect record splitting. For the normal case of 'RS = +"\n"', the locale is largely irrelevant. For other single-character +record separators, setting 'LC_ALL=C' in the environment will give you +much better performance when reading records. Otherwise, 'gawk' has to +make several function calls, _per input character_, to find the record +terminator. + + Locales can affect how dates and times are formatted (*note Time +Functions::). For example, a common way to abbreviate the date +September 4, 2015, in the United States is "9/4/15." In many countries +in Europe, however, it is abbreviated "4.9.15." Thus, the '%x' +specification in a '"US"' locale might produce '9/4/15', while in a +'"EUROPE"' locale, it might produce '4.9.15'. + + According to POSIX, string comparison is also affected by locales +(similar to regular expressions). The details are presented in *note +POSIX String Comparison::. + + Finally, the locale affects the value of the decimal point character +used when 'gawk' parses input data. This is discussed in detail in +*note Conversion::. + + +File: gawk.info, Node: Expressions Summary, Prev: Locales, Up: Expressions + +6.7 Summary +=========== + + * Expressions are the basic elements of computation in programs. + They are built from constants, variables, function calls, and + combinations of the various kinds of values with operators. + + * 'awk' supplies three kinds of constants: numeric, string, and + regexp. 'gawk' lets you specify numeric constants in octal and + hexadecimal (bases 8 and 16) as well as decimal (base 10). In + certain contexts, a standalone regexp constant such as '/foo/' has + the same meaning as '$0 ~ /foo/'. + + * Variables hold values between uses in computations. A number of + built-in variables provide information to your 'awk' program, and a + number of others let you control how 'awk' behaves. + + * Numbers are automatically converted to strings, and strings to + numbers, as needed by 'awk'. Numeric values are converted as if + they were formatted with 'sprintf()' using the format in 'CONVFMT'. + Locales can influence the conversions. + + * 'awk' provides the usual arithmetic operators (addition, + subtraction, multiplication, division, modulus), and unary plus and + minus. It also provides comparison operators, Boolean operators, + an array membership testing operator, and regexp matching + operators. String concatenation is accomplished by placing two + expressions next to each other; there is no explicit operator. The + three-operand '?:' operator provides an "if-else" test within + expressions. + + * Assignment operators provide convenient shorthands for common + arithmetic operations. + + * In 'awk', a value is considered to be true if it is nonzero _or_ + non-null. Otherwise, the value is false. + + * A variable's type is set upon each assignment and may change over + its lifetime. The type determines how it behaves in comparisons + (string or numeric). + + * Function calls return a value that may be used as part of a larger + expression. Expressions used to pass parameter values are fully + evaluated before the function is called. 'awk' provides built-in + and user-defined functions; this is described in *note Functions::. + + * Operator precedence specifies the order in which operations are + performed, unless explicitly overridden by parentheses. 'awk''s + operator precedence is compatible with that of C. + + * Locales can affect the format of data as output by an 'awk' + program, and occasionally the format for data read as input. + + +File: gawk.info, Node: Patterns and Actions, Next: Arrays, Prev: Expressions, Up: Top + +7 Patterns, Actions, and Variables +********************************** + +As you have already seen, each 'awk' statement consists of a pattern +with an associated action. This major node describes how you build +patterns and actions, what kinds of things you can do within actions, +and 'awk''s predefined variables. + + The pattern-action rules and the statements available for use within +actions form the core of 'awk' programming. In a sense, everything +covered up to here has been the foundation that programs are built on +top of. Now it's time to start building something useful. + +* Menu: + +* Pattern Overview:: What goes into a pattern. +* Using Shell Variables:: How to use shell variables with 'awk'. +* Action Overview:: What goes into an action. +* Statements:: Describes the various control statements in + detail. +* Built-in Variables:: Summarizes the predefined variables. +* Pattern Action Summary:: Patterns and Actions summary. + + +File: gawk.info, Node: Pattern Overview, Next: Using Shell Variables, Up: Patterns and Actions + +7.1 Pattern Elements +==================== + +* Menu: + +* Regexp Patterns:: Using regexps as patterns. +* Expression Patterns:: Any expression can be used as a pattern. +* Ranges:: Pairs of patterns specify record ranges. +* BEGIN/END:: Specifying initialization and cleanup rules. +* BEGINFILE/ENDFILE:: Two special patterns for advanced control. +* Empty:: The empty pattern, which matches every record. + +Patterns in 'awk' control the execution of rules--a rule is executed +when its pattern matches the current input record. The following is a +summary of the types of 'awk' patterns: + +'/REGULAR EXPRESSION/' + A regular expression. It matches when the text of the input record + fits the regular expression. (*Note Regexp::.) + +'EXPRESSION' + A single expression. It matches when its value is nonzero (if a + number) or non-null (if a string). (*Note Expression Patterns::.) + +'BEGPAT, ENDPAT' + A pair of patterns separated by a comma, specifying a "range" of + records. The range includes both the initial record that matches + BEGPAT and the final record that matches ENDPAT. (*Note Ranges::.) + +'BEGIN' +'END' + Special patterns for you to supply startup or cleanup actions for + your 'awk' program. (*Note BEGIN/END::.) + +'BEGINFILE' +'ENDFILE' + Special patterns for you to supply startup or cleanup actions to be + done on a per-file basis. (*Note BEGINFILE/ENDFILE::.) + +'EMPTY' + The empty pattern matches every input record. (*Note Empty::.) + + +File: gawk.info, Node: Regexp Patterns, Next: Expression Patterns, Up: Pattern Overview + +7.1.1 Regular Expressions as Patterns +------------------------------------- + +Regular expressions are one of the first kinds of patterns presented in +this book. This kind of pattern is simply a regexp constant in the +pattern part of a rule. Its meaning is '$0 ~ /PATTERN/'. The pattern +matches when the input record matches the regexp. For example: + + /foo|bar|baz/ { buzzwords++ } + END { print buzzwords, "buzzwords seen" } + + +File: gawk.info, Node: Expression Patterns, Next: Ranges, Prev: Regexp Patterns, Up: Pattern Overview + +7.1.2 Expressions as Patterns +----------------------------- + +Any 'awk' expression is valid as an 'awk' pattern. The pattern matches +if the expression's value is nonzero (if a number) or non-null (if a +string). The expression is reevaluated each time the rule is tested +against a new input record. If the expression uses fields such as '$1', +the value depends directly on the new input record's text; otherwise, it +depends on only what has happened so far in the execution of the 'awk' +program. + + Comparison expressions, using the comparison operators described in +*note Typing and Comparison::, are a very common kind of pattern. +Regexp matching and nonmatching are also very common expressions. The +left operand of the '~' and '!~' operators is a string. The right +operand is either a constant regular expression enclosed in slashes +('/REGEXP/'), or any expression whose string value is used as a dynamic +regular expression (*note Computed Regexps::). The following example +prints the second field of each input record whose first field is +precisely 'li': + + $ awk '$1 == "li" { print $2 }' mail-list + +(There is no output, because there is no person with the exact name +'li'.) Contrast this with the following regular expression match, which +accepts any record with a first field that contains 'li': + + $ awk '$1 ~ /li/ { print $2 }' mail-list + -| 555-5553 + -| 555-6699 + + A regexp constant as a pattern is also a special case of an +expression pattern. The expression '/li/' has the value one if 'li' +appears in the current input record. Thus, as a pattern, '/li/' matches +any record containing 'li'. + + Boolean expressions are also commonly used as patterns. Whether the +pattern matches an input record depends on whether its subexpressions +match. For example, the following command prints all the records in +'mail-list' that contain both 'edu' and 'li': + + $ awk '/edu/ && /li/' mail-list + -| Samuel 555-3430 samuel.lanceolis@shu.edu A + + The following command prints all records in 'mail-list' that contain +_either_ 'edu' or 'li' (or both, of course): + + $ awk '/edu/ || /li/' mail-list + -| Amelia 555-5553 amelia.zodiacusque@gmail.com F + -| Broderick 555-0542 broderick.aliquotiens@yahoo.com R + -| Fabius 555-1234 fabius.undevicesimus@ucb.edu F + -| Julie 555-6699 julie.perscrutabor@skeeve.com F + -| Samuel 555-3430 samuel.lanceolis@shu.edu A + -| Jean-Paul 555-2127 jeanpaul.campanorum@nyu.edu R + + The following command prints all records in 'mail-list' that do _not_ +contain the string 'li': + + $ awk '! /li/' mail-list + -| Anthony 555-3412 anthony.asserturo@hotmail.com A + -| Becky 555-7685 becky.algebrarum@gmail.com A + -| Bill 555-1675 bill.drowning@hotmail.com A + -| Camilla 555-2912 camilla.infusarum@skynet.be R + -| Fabius 555-1234 fabius.undevicesimus@ucb.edu F + -| Martin 555-6480 martin.codicibus@hotmail.com A + -| Jean-Paul 555-2127 jeanpaul.campanorum@nyu.edu R + + The subexpressions of a Boolean operator in a pattern can be constant +regular expressions, comparisons, or any other 'awk' expressions. Range +patterns are not expressions, so they cannot appear inside Boolean +patterns. Likewise, the special patterns 'BEGIN', 'END', 'BEGINFILE', +and 'ENDFILE', which never match any input record, are not expressions +and cannot appear inside Boolean patterns. + + The precedence of the different operators that can appear in patterns +is described in *note Precedence::. + + +File: gawk.info, Node: Ranges, Next: BEGIN/END, Prev: Expression Patterns, Up: Pattern Overview + +7.1.3 Specifying Record Ranges with Patterns +-------------------------------------------- + +A "range pattern" is made of two patterns separated by a comma, in the +form 'BEGPAT, ENDPAT'. It is used to match ranges of consecutive input +records. The first pattern, BEGPAT, controls where the range begins, +while ENDPAT controls where the pattern ends. For example, the +following: + + awk '$1 == "on", $1 == "off"' myfile + +prints every record in 'myfile' between 'on'/'off' pairs, inclusive. + + A range pattern starts out by matching BEGPAT against every input +record. When a record matches BEGPAT, the range pattern is "turned on", +and the range pattern matches this record as well. As long as the range +pattern stays turned on, it automatically matches every input record +read. The range pattern also matches ENDPAT against every input record; +when this succeeds, the range pattern is "turned off" again for the +following record. Then the range pattern goes back to checking BEGPAT +against each record. + + The record that turns on the range pattern and the one that turns it +off both match the range pattern. If you don't want to operate on these +records, you can write 'if' statements in the rule's action to +distinguish them from the records you are interested in. + + It is possible for a pattern to be turned on and off by the same +record. If the record satisfies both conditions, then the action is +executed for just that record. For example, suppose there is text +between two identical markers (e.g., the '%' symbol), each on its own +line, that should be ignored. A first attempt would be to combine a +range pattern that describes the delimited text with the 'next' +statement (not discussed yet, *note Next Statement::). This causes +'awk' to skip any further processing of the current record and start +over again with the next input record. Such a program looks like this: + + /^%$/,/^%$/ { next } + { print } + +This program fails because the range pattern is both turned on and +turned off by the first line, which just has a '%' on it. To accomplish +this task, write the program in the following manner, using a flag: + + /^%$/ { skip = ! skip; next } + skip == 1 { next } # skip lines with `skip' set + + In a range pattern, the comma (',') has the lowest precedence of all +the operators (i.e., it is evaluated last). Thus, the following program +attempts to combine a range pattern with another, simpler test: + + echo Yes | awk '/1/,/2/ || /Yes/' + + The intent of this program is '(/1/,/2/) || /Yes/'. However, 'awk' +interprets this as '/1/, (/2/ || /Yes/)'. This cannot be changed or +worked around; range patterns do not combine with other patterns: + + $ echo Yes | gawk '(/1/,/2/) || /Yes/' + error-> gawk: cmd. line:1: (/1/,/2/) || /Yes/ + error-> gawk: cmd. line:1: ^ syntax error + + As a minor point of interest, although it is poor style, POSIX allows +you to put a newline after the comma in a range pattern. (d.c.) + + +File: gawk.info, Node: BEGIN/END, Next: BEGINFILE/ENDFILE, Prev: Ranges, Up: Pattern Overview + +7.1.4 The 'BEGIN' and 'END' Special Patterns +-------------------------------------------- + +All the patterns described so far are for matching input records. The +'BEGIN' and 'END' special patterns are different. They supply startup +and cleanup actions for 'awk' programs. 'BEGIN' and 'END' rules must +have actions; there is no default action for these rules because there +is no current record when they run. 'BEGIN' and 'END' rules are often +referred to as "'BEGIN' and 'END' blocks" by longtime 'awk' programmers. + +* Menu: + +* Using BEGIN/END:: How and why to use BEGIN/END rules. +* I/O And BEGIN/END:: I/O issues in BEGIN/END rules. + + +File: gawk.info, Node: Using BEGIN/END, Next: I/O And BEGIN/END, Up: BEGIN/END + +7.1.4.1 Startup and Cleanup Actions +................................... + +A 'BEGIN' rule is executed once only, before the first input record is +read. Likewise, an 'END' rule is executed once only, after all the +input is read. For example: + + $ awk ' + > BEGIN { print "Analysis of \"li\"" } + > /li/ { ++n } + > END { print "\"li\" appears in", n, "records." }' mail-list + -| Analysis of "li" + -| "li" appears in 4 records. + + This program finds the number of records in the input file +'mail-list' that contain the string 'li'. The 'BEGIN' rule prints a +title for the report. There is no need to use the 'BEGIN' rule to +initialize the counter 'n' to zero, as 'awk' does this automatically +(*note Variables::). The second rule increments the variable 'n' every +time a record containing the pattern 'li' is read. The 'END' rule +prints the value of 'n' at the end of the run. + + The special patterns 'BEGIN' and 'END' cannot be used in ranges or +with Boolean operators (indeed, they cannot be used with any operators). +An 'awk' program may have multiple 'BEGIN' and/or 'END' rules. They are +executed in the order in which they appear: all the 'BEGIN' rules at +startup and all the 'END' rules at termination. 'BEGIN' and 'END' rules +may be intermixed with other rules. This feature was added in the 1987 +version of 'awk' and is included in the POSIX standard. The original +(1978) version of 'awk' required the 'BEGIN' rule to be placed at the +beginning of the program, the 'END' rule to be placed at the end, and +only allowed one of each. This is no longer required, but it is a good +idea to follow this template in terms of program organization and +readability. + + Multiple 'BEGIN' and 'END' rules are useful for writing library +functions, because each library file can have its own 'BEGIN' and/or +'END' rule to do its own initialization and/or cleanup. The order in +which library functions are named on the command line controls the order +in which their 'BEGIN' and 'END' rules are executed. Therefore, you +have to be careful when writing such rules in library files so that the +order in which they are executed doesn't matter. *Note Options:: for +more information on using library functions. *Note Library Functions::, +for a number of useful library functions. + + If an 'awk' program has only 'BEGIN' rules and no other rules, then +the program exits after the 'BEGIN' rules are run.(1) However, if an +'END' rule exists, then the input is read, even if there are no other +rules in the program. This is necessary in case the 'END' rule checks +the 'FNR' and 'NR' variables. + + ---------- Footnotes ---------- + + (1) The original version of 'awk' kept reading and ignoring input +until the end of the file was seen. + + +File: gawk.info, Node: I/O And BEGIN/END, Prev: Using BEGIN/END, Up: BEGIN/END + +7.1.4.2 Input/Output from 'BEGIN' and 'END' Rules +................................................. + +There are several (sometimes subtle) points to be aware of when doing +I/O from a 'BEGIN' or 'END' rule. The first has to do with the value of +'$0' in a 'BEGIN' rule. Because 'BEGIN' rules are executed before any +input is read, there simply is no input record, and therefore no fields, +when executing 'BEGIN' rules. References to '$0' and the fields yield a +null string or zero, depending upon the context. One way to give '$0' a +real value is to execute a 'getline' command without a variable (*note +Getline::). Another way is simply to assign a value to '$0'. + + The second point is similar to the first, but from the other +direction. Traditionally, due largely to implementation issues, '$0' +and 'NF' were _undefined_ inside an 'END' rule. The POSIX standard +specifies that 'NF' is available in an 'END' rule. It contains the +number of fields from the last input record. Most probably due to an +oversight, the standard does not say that '$0' is also preserved, +although logically one would think that it should be. In fact, all of +BWK 'awk', 'mawk', and 'gawk' preserve the value of '$0' for use in +'END' rules. Be aware, however, that some other implementations and +many older versions of Unix 'awk' do not. + + The third point follows from the first two. The meaning of 'print' +inside a 'BEGIN' or 'END' rule is the same as always: 'print $0'. If +'$0' is the null string, then this prints an empty record. Many +longtime 'awk' programmers use an unadorned 'print' in 'BEGIN' and 'END' +rules, to mean 'print ""', relying on '$0' being null. Although one +might generally get away with this in 'BEGIN' rules, it is a very bad +idea in 'END' rules, at least in 'gawk'. It is also poor style, because +if an empty line is needed in the output, the program should print one +explicitly. + + Finally, the 'next' and 'nextfile' statements are not allowed in a +'BEGIN' rule, because the implicit +read-a-record-and-match-against-the-rules loop has not started yet. +Similarly, those statements are not valid in an 'END' rule, because all +the input has been read. (*Note Next Statement:: and *note Nextfile +Statement::.) + + +File: gawk.info, Node: BEGINFILE/ENDFILE, Next: Empty, Prev: BEGIN/END, Up: Pattern Overview + +7.1.5 The 'BEGINFILE' and 'ENDFILE' Special Patterns +---------------------------------------------------- + +This minor node describes a 'gawk'-specific feature. + + Two special kinds of rule, 'BEGINFILE' and 'ENDFILE', give you +"hooks" into 'gawk''s command-line file processing loop. As with the +'BEGIN' and 'END' rules (*note BEGIN/END::), all 'BEGINFILE' rules in a +program are merged, in the order they are read by 'gawk', and all +'ENDFILE' rules are merged as well. + + The body of the 'BEGINFILE' rules is executed just before 'gawk' +reads the first record from a file. 'FILENAME' is set to the name of +the current file, and 'FNR' is set to zero. + + The 'BEGINFILE' rule provides you the opportunity to accomplish two +tasks that would otherwise be difficult or impossible to perform: + + * You can test if the file is readable. Normally, it is a fatal + error if a file named on the command line cannot be opened for + reading. However, you can bypass the fatal error and move on to + the next file on the command line. + + You do this by checking if the 'ERRNO' variable is not the empty + string; if so, then 'gawk' was not able to open the file. In this + case, your program can execute the 'nextfile' statement (*note + Nextfile Statement::). This causes 'gawk' to skip the file + entirely. Otherwise, 'gawk' exits with the usual fatal error. + + * If you have written extensions that modify the record handling (by + inserting an "input parser"; *note Input Parsers::), you can invoke + them at this point, before 'gawk' has started processing the file. + (This is a _very_ advanced feature, currently used only by the + 'gawkextlib' project + (https://sourceforge.net/projects/gawkextlib).) + + The 'ENDFILE' rule is called when 'gawk' has finished processing the +last record in an input file. For the last input file, it will be +called before any 'END' rules. The 'ENDFILE' rule is executed even for +empty input files. + + Normally, when an error occurs when reading input in the normal +input-processing loop, the error is fatal. However, if an 'ENDFILE' +rule is present, the error becomes non-fatal, and instead 'ERRNO' is +set. This makes it possible to catch and process I/O errors at the +level of the 'awk' program. + + The 'next' statement (*note Next Statement::) is not allowed inside +either a 'BEGINFILE' or an 'ENDFILE' rule. The 'nextfile' statement is +allowed only inside a 'BEGINFILE' rule, not inside an 'ENDFILE' rule. + + The 'getline' statement (*note Getline::) is restricted inside both +'BEGINFILE' and 'ENDFILE': only redirected forms of 'getline' are +allowed. + + 'BEGINFILE' and 'ENDFILE' are 'gawk' extensions. In most other 'awk' +implementations, or if 'gawk' is in compatibility mode (*note +Options::), they are not special. + + +File: gawk.info, Node: Empty, Prev: BEGINFILE/ENDFILE, Up: Pattern Overview + +7.1.6 The Empty Pattern +----------------------- + +An empty (i.e., nonexistent) pattern is considered to match _every_ +input record. For example, the program: + + awk '{ print $1 }' mail-list + +prints the first field of every record. + + +File: gawk.info, Node: Using Shell Variables, Next: Action Overview, Prev: Pattern Overview, Up: Patterns and Actions + +7.2 Using Shell Variables in Programs +===================================== + +'awk' programs are often used as components in larger programs written +in shell. For example, it is very common to use a shell variable to +hold a pattern that the 'awk' program searches for. There are two ways +to get the value of the shell variable into the body of the 'awk' +program. + + A common method is to use shell quoting to substitute the variable's +value into the program inside the script. For example, consider the +following program: + + printf "Enter search pattern: " + read pattern + awk "/$pattern/ "'{ nmatches++ } + END { print nmatches, "found" }' /path/to/data + +The 'awk' program consists of two pieces of quoted text that are +concatenated together to form the program. The first part is +double-quoted, which allows substitution of the 'pattern' shell variable +inside the quotes. The second part is single-quoted. + + Variable substitution via quoting works, but can potentially be +messy. It requires a good understanding of the shell's quoting rules +(*note Quoting::), and it's often difficult to correctly match up the +quotes when reading the program. + + A better method is to use 'awk''s variable assignment feature (*note +Assignment Options::) to assign the shell variable's value to an 'awk' +variable. Then use dynamic regexps to match the pattern (*note Computed +Regexps::). The following shows how to redo the previous example using +this technique: + + printf "Enter search pattern: " + read pattern + awk -v pat="$pattern" '$0 ~ pat { nmatches++ } + END { print nmatches, "found" }' /path/to/data + +Now, the 'awk' program is just one single-quoted string. The assignment +'-v pat="$pattern"' still requires double quotes, in case there is +whitespace in the value of '$pattern'. The 'awk' variable 'pat' could +be named 'pattern' too, but that would be more confusing. Using a +variable also provides more flexibility, as the variable can be used +anywhere inside the program--for printing, as an array subscript, or for +any other use--without requiring the quoting tricks at every point in +the program. + + +File: gawk.info, Node: Action Overview, Next: Statements, Prev: Using Shell Variables, Up: Patterns and Actions + +7.3 Actions +=========== + +An 'awk' program or script consists of a series of rules and function +definitions interspersed. (Functions are described later. *Note +User-defined::.) A rule contains a pattern and an action, either of +which (but not both) may be omitted. The purpose of the "action" is to +tell 'awk' what to do once a match for the pattern is found. Thus, in +outline, an 'awk' program generally looks like this: + + [PATTERN] '{ ACTION }' + PATTERN ['{ ACTION }'] + ... + 'function NAME(ARGS) { ... }' + ... + + An action consists of one or more 'awk' "statements", enclosed in +braces ('{...}'). Each statement specifies one thing to do. The +statements are separated by newlines or semicolons. The braces around +an action must be used even if the action contains only one statement, +or if it contains no statements at all. However, if you omit the action +entirely, omit the braces as well. An omitted action is equivalent to +'{ print $0 }': + + /foo/ { } match 'foo', do nothing -- empty action + /foo/ match 'foo', print the record -- omitted action + + The following types of statements are supported in 'awk': + +Expressions + Call functions or assign values to variables (*note Expressions::). + Executing this kind of statement simply computes the value of the + expression. This is useful when the expression has side effects + (*note Assignment Ops::). + +Control statements + Specify the control flow of 'awk' programs. The 'awk' language + gives you C-like constructs ('if', 'for', 'while', and 'do') as + well as a few special ones (*note Statements::). + +Compound statements + Enclose one or more statements in braces. A compound statement is + used in order to put several statements together in the body of an + 'if', 'while', 'do', or 'for' statement. + +Input statements + Use the 'getline' command (*note Getline::). Also supplied in + 'awk' are the 'next' statement (*note Next Statement::) and the + 'nextfile' statement (*note Nextfile Statement::). + +Output statements + Such as 'print' and 'printf'. *Note Printing::. + +Deletion statements + For deleting array elements. *Note Delete::. + + +File: gawk.info, Node: Statements, Next: Built-in Variables, Prev: Action Overview, Up: Patterns and Actions + +7.4 Control Statements in Actions +================================= + +"Control statements", such as 'if', 'while', and so on, control the flow +of execution in 'awk' programs. Most of 'awk''s control statements are +patterned after similar statements in C. + + All the control statements start with special keywords, such as 'if' +and 'while', to distinguish them from simple expressions. Many control +statements contain other statements. For example, the 'if' statement +contains another statement that may or may not be executed. The +contained statement is called the "body". To include more than one +statement in the body, group them into a single "compound statement" +with braces, separating them with newlines or semicolons. + +* Menu: + +* If Statement:: Conditionally execute some 'awk' + statements. +* While Statement:: Loop until some condition is satisfied. +* Do Statement:: Do specified action while looping until some + condition is satisfied. +* For Statement:: Another looping statement, that provides + initialization and increment clauses. +* Switch Statement:: Switch/case evaluation for conditional + execution of statements based on a value. +* Break Statement:: Immediately exit the innermost enclosing loop. +* Continue Statement:: Skip to the end of the innermost enclosing + loop. +* Next Statement:: Stop processing the current input record. +* Nextfile Statement:: Stop processing the current file. +* Exit Statement:: Stop execution of 'awk'. + + +File: gawk.info, Node: If Statement, Next: While Statement, Up: Statements + +7.4.1 The 'if'-'else' Statement +------------------------------- + +The 'if'-'else' statement is 'awk''s decision-making statement. It +looks like this: + + 'if (CONDITION) THEN-BODY' ['else ELSE-BODY'] + +The CONDITION is an expression that controls what the rest of the +statement does. If the CONDITION is true, THEN-BODY is executed; +otherwise, ELSE-BODY is executed. The 'else' part of the statement is +optional. The condition is considered false if its value is zero or the +null string; otherwise, the condition is true. Refer to the following: + + if (x % 2 == 0) + print "x is even" + else + print "x is odd" + + In this example, if the expression 'x % 2 == 0' is true (i.e., if the +value of 'x' is evenly divisible by two), then the first 'print' +statement is executed; otherwise, the second 'print' statement is +executed. If the 'else' keyword appears on the same line as THEN-BODY +and THEN-BODY is not a compound statement (i.e., not surrounded by +braces), then a semicolon must separate THEN-BODY from the 'else'. To +illustrate this, the previous example can be rewritten as: + + if (x % 2 == 0) print "x is even"; else + print "x is odd" + +If the ';' is left out, 'awk' can't interpret the statement and it +produces a syntax error. Don't actually write programs this way, +because a human reader might fail to see the 'else' if it is not the +first thing on its line. + + +File: gawk.info, Node: While Statement, Next: Do Statement, Prev: If Statement, Up: Statements + +7.4.2 The 'while' Statement +--------------------------- + +In programming, a "loop" is a part of a program that can be executed two +or more times in succession. The 'while' statement is the simplest +looping statement in 'awk'. It repeatedly executes a statement as long +as a condition is true. For example: + + while (CONDITION) + BODY + +BODY is a statement called the "body" of the loop, and CONDITION is an +expression that controls how long the loop keeps running. The first +thing the 'while' statement does is test the CONDITION. If the +CONDITION is true, it executes the statement BODY. (The CONDITION is +true when the value is not zero and not a null string.) After BODY has +been executed, CONDITION is tested again, and if it is still true, BODY +executes again. This process repeats until the CONDITION is no longer +true. If the CONDITION is initially false, the body of the loop never +executes and 'awk' continues with the statement following the loop. +This example prints the first three fields of each record, one per line: + + awk ' + { + i = 1 + while (i <= 3) { + print $i + i++ + } + }' inventory-shipped + +The body of this loop is a compound statement enclosed in braces, +containing two statements. The loop works in the following manner: +first, the value of 'i' is set to one. Then, the 'while' statement +tests whether 'i' is less than or equal to three. This is true when 'i' +equals one, so the 'i'th field is printed. Then the 'i++' increments +the value of 'i' and the loop repeats. The loop terminates when 'i' +reaches four. + + A newline is not required between the condition and the body; +however, using one makes the program clearer unless the body is a +compound statement or else is very simple. The newline after the open +brace that begins the compound statement is not required either, but the +program is harder to read without it. + + +File: gawk.info, Node: Do Statement, Next: For Statement, Prev: While Statement, Up: Statements + +7.4.3 The 'do'-'while' Statement +-------------------------------- + +The 'do' loop is a variation of the 'while' looping statement. The 'do' +loop executes the BODY once and then repeats the BODY as long as the +CONDITION is true. It looks like this: + + do + BODY + while (CONDITION) + + Even if the CONDITION is false at the start, the BODY executes at +least once (and only once, unless executing BODY makes CONDITION true). +Contrast this with the corresponding 'while' statement: + + while (CONDITION) + BODY + +This statement does not execute the BODY even once if the CONDITION is +false to begin with. The following is an example of a 'do' statement: + + { + i = 1 + do { + print $0 + i++ + } while (i <= 10) + } + +This program prints each input record 10 times. However, it isn't a +very realistic example, because in this case an ordinary 'while' would +do just as well. This situation reflects actual experience; only +occasionally is there a real use for a 'do' statement. + + +File: gawk.info, Node: For Statement, Next: Switch Statement, Prev: Do Statement, Up: Statements + +7.4.4 The 'for' Statement +------------------------- + +The 'for' statement makes it more convenient to count iterations of a +loop. The general form of the 'for' statement looks like this: + + for (INITIALIZATION; CONDITION; INCREMENT) + BODY + +The INITIALIZATION, CONDITION, and INCREMENT parts are arbitrary 'awk' +expressions, and BODY stands for any 'awk' statement. + + The 'for' statement starts by executing INITIALIZATION. Then, as +long as the CONDITION is true, it repeatedly executes BODY and then +INCREMENT. Typically, INITIALIZATION sets a variable to either zero or +one, INCREMENT adds one to it, and CONDITION compares it against the +desired number of iterations. For example: + + awk ' + { + for (i = 1; i <= 3; i++) + print $i + }' inventory-shipped + +This prints the first three fields of each input record, with one input +field per output line. + + It isn't possible to set more than one variable in the INITIALIZATION +part without using a multiple assignment statement such as 'x = y = 0'. +This makes sense only if all the initial values are equal. (But it is +possible to initialize additional variables by writing their assignments +as separate statements preceding the 'for' loop.) + + The same is true of the INCREMENT part. Incrementing additional +variables requires separate statements at the end of the loop. The C +compound expression, using C's comma operator, is useful in this +context, but it is not supported in 'awk'. + + Most often, INCREMENT is an increment expression, as in the previous +example. But this is not required; it can be any expression whatsoever. +For example, the following statement prints all the powers of two +between 1 and 100: + + for (i = 1; i <= 100; i *= 2) + print i + + If there is nothing to be done, any of the three expressions in the +parentheses following the 'for' keyword may be omitted. Thus, +'for (; x > 0;)' is equivalent to 'while (x > 0)'. If the CONDITION is +omitted, it is treated as true, effectively yielding an "infinite loop" +(i.e., a loop that never terminates). + + In most cases, a 'for' loop is an abbreviation for a 'while' loop, as +shown here: + + INITIALIZATION + while (CONDITION) { + BODY + INCREMENT + } + +The only exception is when the 'continue' statement (*note Continue +Statement::) is used inside the loop. Changing a 'for' statement to a +'while' statement in this way can change the effect of the 'continue' +statement inside the loop. + + The 'awk' language has a 'for' statement in addition to a 'while' +statement because a 'for' loop is often both less work to type and more +natural to think of. Counting the number of iterations is very common +in loops. It can be easier to think of this counting as part of looping +rather than as something to do inside the loop. + + There is an alternative version of the 'for' loop, for iterating over +all the indices of an array: + + for (i in array) + DO SOMETHING WITH array[i] + +*Note Scanning an Array:: for more information on this version of the +'for' loop. + + +File: gawk.info, Node: Switch Statement, Next: Break Statement, Prev: For Statement, Up: Statements + +7.4.5 The 'switch' Statement +---------------------------- + +This minor node describes a 'gawk'-specific feature. If 'gawk' is in +compatibility mode (*note Options::), it is not available. + + The 'switch' statement allows the evaluation of an expression and the +execution of statements based on a 'case' match. Case statements are +checked for a match in the order they are defined. If no suitable +'case' is found, the 'default' section is executed, if supplied. + + Each 'case' contains a single constant, be it numeric, string, or +regexp. The 'switch' expression is evaluated, and then each 'case''s +constant is compared against the result in turn. The type of constant +determines the comparison: numeric or string do the usual comparisons. +A regexp constant does a regular expression match against the string +value of the original expression. The general form of the 'switch' +statement looks like this: + + switch (EXPRESSION) { + case VALUE OR REGULAR EXPRESSION: + CASE-BODY + default: + DEFAULT-BODY + } + + Control flow in the 'switch' statement works as it does in C. Once a +match to a given case is made, the case statement bodies execute until a +'break', 'continue', 'next', 'nextfile', or 'exit' is encountered, or +the end of the 'switch' statement itself. For example: + + while ((c = getopt(ARGC, ARGV, "aksx")) != -1) { + switch (c) { + case "a": + # report size of all files + all_files = TRUE; + break + case "k": + BLOCK_SIZE = 1024 # 1K block size + break + case "s": + # do sums only + sum_only = TRUE + break + case "x": + # don't cross filesystems + fts_flags = or(fts_flags, FTS_XDEV) + break + case "?": + default: + usage() + break + } + } + + Note that if none of the statements specified here halt execution of +a matched 'case' statement, execution falls through to the next 'case' +until execution halts. In this example, the 'case' for '"?"' falls +through to the 'default' case, which is to call a function named +'usage()'. (The 'getopt()' function being called here is described in +*note Getopt Function::.) + + +File: gawk.info, Node: Break Statement, Next: Continue Statement, Prev: Switch Statement, Up: Statements + +7.4.6 The 'break' Statement +--------------------------- + +The 'break' statement jumps out of the innermost 'for', 'while', or 'do' +loop that encloses it. The following example finds the smallest divisor +of any integer, and also identifies prime numbers: + + # find smallest divisor of num + { + num = $1 + for (divisor = 2; divisor * divisor <= num; divisor++) { + if (num % divisor == 0) + break + } + if (num % divisor == 0) + printf "Smallest divisor of %d is %d\n", num, divisor + else + printf "%d is prime\n", num + } + + When the remainder is zero in the first 'if' statement, 'awk' +immediately "breaks out" of the containing 'for' loop. This means that +'awk' proceeds immediately to the statement following the loop and +continues processing. (This is very different from the 'exit' +statement, which stops the entire 'awk' program. *Note Exit +Statement::.) + + The following program illustrates how the CONDITION of a 'for' or +'while' statement could be replaced with a 'break' inside an 'if': + + # find smallest divisor of num + { + num = $1 + for (divisor = 2; ; divisor++) { + if (num % divisor == 0) { + printf "Smallest divisor of %d is %d\n", num, divisor + break + } + if (divisor * divisor > num) { + printf "%d is prime\n", num + break + } + } + } + + The 'break' statement is also used to break out of the 'switch' +statement. This is discussed in *note Switch Statement::. + + The 'break' statement has no meaning when used outside the body of a +loop or 'switch'. However, although it was never documented, historical +implementations of 'awk' treated the 'break' statement outside of a loop +as if it were a 'next' statement (*note Next Statement::). (d.c.) +Recent versions of BWK 'awk' no longer allow this usage, nor does +'gawk'. + + +File: gawk.info, Node: Continue Statement, Next: Next Statement, Prev: Break Statement, Up: Statements + +7.4.7 The 'continue' Statement +------------------------------ + +Similar to 'break', the 'continue' statement is used only inside 'for', +'while', and 'do' loops. It skips over the rest of the loop body, +causing the next cycle around the loop to begin immediately. Contrast +this with 'break', which jumps out of the loop altogether. + + The 'continue' statement in a 'for' loop directs 'awk' to skip the +rest of the body of the loop and resume execution with the +increment-expression of the 'for' statement. The following program +illustrates this fact: + + BEGIN { + for (x = 0; x <= 20; x++) { + if (x == 5) + continue + printf "%d ", x + } + print "" + } + +This program prints all the numbers from 0 to 20--except for 5, for +which the 'printf' is skipped. Because the increment 'x++' is not +skipped, 'x' does not remain stuck at 5. Contrast the 'for' loop from +the previous example with the following 'while' loop: + + BEGIN { + x = 0 + while (x <= 20) { + if (x == 5) + continue + printf "%d ", x + x++ + } + print "" + } + +This program loops forever once 'x' reaches 5, because the increment +('x++') is never reached. + + The 'continue' statement has no special meaning with respect to the +'switch' statement, nor does it have any meaning when used outside the +body of a loop. Historical versions of 'awk' treated a 'continue' +statement outside a loop the same way they treated a 'break' statement +outside a loop: as if it were a 'next' statement (*note Next +Statement::). (d.c.) Recent versions of BWK 'awk' no longer work this +way, nor does 'gawk'. + + +File: gawk.info, Node: Next Statement, Next: Nextfile Statement, Prev: Continue Statement, Up: Statements + +7.4.8 The 'next' Statement +-------------------------- + +The 'next' statement forces 'awk' to immediately stop processing the +current record and go on to the next record. This means that no further +rules are executed for the current record, and the rest of the current +rule's action isn't executed. + + Contrast this with the effect of the 'getline' function (*note +Getline::). That also causes 'awk' to read the next record immediately, +but it does not alter the flow of control in any way (i.e., the rest of +the current action executes with a new input record). + + At the highest level, 'awk' program execution is a loop that reads an +input record and then tests each rule's pattern against it. If you +think of this loop as a 'for' statement whose body contains the rules, +then the 'next' statement is analogous to a 'continue' statement. It +skips to the end of the body of this implicit loop and executes the +increment (which reads another record). + + For example, suppose an 'awk' program works only on records with four +fields, and it shouldn't fail when given bad input. To avoid +complicating the rest of the program, write a "weed out" rule near the +beginning, in the following manner: + + NF != 4 { + printf("%s:%d: skipped: NF != 4\n", FILENAME, FNR) > "/dev/stderr" + next + } + +Because of the 'next' statement, the program's subsequent rules won't +see the bad record. The error message is redirected to the standard +error output stream, as error messages should be. For more detail, see +*note Special Files::. + + If the 'next' statement causes the end of the input to be reached, +then the code in any 'END' rules is executed. *Note BEGIN/END::. + + The 'next' statement is not allowed inside 'BEGINFILE' and 'ENDFILE' +rules. *Note BEGINFILE/ENDFILE::. + + According to the POSIX standard, the behavior is undefined if the +'next' statement is used in a 'BEGIN' or 'END' rule. 'gawk' treats it +as a syntax error. Although POSIX does not disallow it, most other +'awk' implementations don't allow the 'next' statement inside function +bodies (*note User-defined::). Just as with any other 'next' statement, +a 'next' statement inside a function body reads the next record and +starts processing it with the first rule in the program. + + +File: gawk.info, Node: Nextfile Statement, Next: Exit Statement, Prev: Next Statement, Up: Statements + +7.4.9 The 'nextfile' Statement +------------------------------ + +The 'nextfile' statement is similar to the 'next' statement. However, +instead of abandoning processing of the current record, the 'nextfile' +statement instructs 'awk' to stop processing the current data file. + + Upon execution of the 'nextfile' statement, 'FILENAME' is updated to +the name of the next data file listed on the command line, 'FNR' is +reset to one, and processing starts over with the first rule in the +program. If the 'nextfile' statement causes the end of the input to be +reached, then the code in any 'END' rules is executed. An exception to +this is when 'nextfile' is invoked during execution of any statement in +an 'END' rule; in this case, it causes the program to stop immediately. +*Note BEGIN/END::. + + The 'nextfile' statement is useful when there are many data files to +process but it isn't necessary to process every record in every file. +Without 'nextfile', in order to move on to the next data file, a program +would have to continue scanning the unwanted records. The 'nextfile' +statement accomplishes this much more efficiently. + + In 'gawk', execution of 'nextfile' causes additional things to +happen: any 'ENDFILE' rules are executed if 'gawk' is not currently in +an 'END' or 'BEGINFILE' rule, 'ARGIND' is incremented, and any +'BEGINFILE' rules are executed. ('ARGIND' hasn't been introduced yet. +*Note Built-in Variables::.) + + With 'gawk', 'nextfile' is useful inside a 'BEGINFILE' rule to skip +over a file that would otherwise cause 'gawk' to exit with a fatal +error. In this case, 'ENDFILE' rules are not executed. *Note +BEGINFILE/ENDFILE::. + + Although it might seem that 'close(FILENAME)' would accomplish the +same as 'nextfile', this isn't true. 'close()' is reserved for closing +files, pipes, and coprocesses that are opened with redirections. It is +not related to the main processing that 'awk' does with the files listed +in 'ARGV'. + + NOTE: For many years, 'nextfile' was a common extension. In + September 2012, it was accepted for inclusion into the POSIX + standard. See the Austin Group website + (http://austingroupbugs.net/view.php?id=607). + + The current version of BWK 'awk' and 'mawk' also support 'nextfile'. +However, they don't allow the 'nextfile' statement inside function +bodies (*note User-defined::). 'gawk' does; a 'nextfile' inside a +function body reads the first record from the next file and starts +processing it with the first rule in the program, just as any other +'nextfile' statement. + + +File: gawk.info, Node: Exit Statement, Prev: Nextfile Statement, Up: Statements + +7.4.10 The 'exit' Statement +--------------------------- + +The 'exit' statement causes 'awk' to immediately stop executing the +current rule and to stop processing input; any remaining input is +ignored. The 'exit' statement is written as follows: + + 'exit' [RETURN CODE] + + When an 'exit' statement is executed from a 'BEGIN' rule, the program +stops processing everything immediately. No input records are read. +However, if an 'END' rule is present, as part of executing the 'exit' +statement, the 'END' rule is executed (*note BEGIN/END::). If 'exit' is +used in the body of an 'END' rule, it causes the program to stop +immediately. + + An 'exit' statement that is not part of a 'BEGIN' or 'END' rule stops +the execution of any further automatic rules for the current record, +skips reading any remaining input records, and executes the 'END' rule +if there is one. 'gawk' also skips any 'ENDFILE' rules; they do not +execute. + + In such a case, if you don't want the 'END' rule to do its job, set a +variable to a nonzero value before the 'exit' statement and check that +variable in the 'END' rule. *Note Assert Function:: for an example that +does this. + + If an argument is supplied to 'exit', its value is used as the exit +status code for the 'awk' process. If no argument is supplied, 'exit' +causes 'awk' to return a "success" status. In the case where an +argument is supplied to a first 'exit' statement, and then 'exit' is +called a second time from an 'END' rule with no argument, 'awk' uses the +previously supplied exit value. (d.c.) *Note Exit Status:: for more +information. + + For example, suppose an error condition occurs that is difficult or +impossible to handle. Conventionally, programs report this by exiting +with a nonzero status. An 'awk' program can do this using an 'exit' +statement with a nonzero argument, as shown in the following example: + + BEGIN { + if (("date" | getline date_now) <= 0) { + print "Can't get system date" > "/dev/stderr" + exit 1 + } + print "current date is", date_now + close("date") + } + + NOTE: For full portability, exit values should be between zero and + 126, inclusive. Negative values, and values of 127 or greater, may + not produce consistent results across different operating systems. + + +File: gawk.info, Node: Built-in Variables, Next: Pattern Action Summary, Prev: Statements, Up: Patterns and Actions + +7.5 Predefined Variables +======================== + +Most 'awk' variables are available to use for your own purposes; they +never change unless your program assigns values to them, and they never +affect anything unless your program examines them. However, a few +variables in 'awk' have special built-in meanings. 'awk' examines some +of these automatically, so that they enable you to tell 'awk' how to do +certain things. Others are set automatically by 'awk', so that they +carry information from the internal workings of 'awk' to your program. + + This minor node documents all of 'gawk''s predefined variables, most +of which are also documented in the major nodes describing their areas +of activity. + +* Menu: + +* User-modified:: Built-in variables that you change to control + 'awk'. +* Auto-set:: Built-in variables where 'awk' gives + you information. +* ARGC and ARGV:: Ways to use 'ARGC' and 'ARGV'. + + +File: gawk.info, Node: User-modified, Next: Auto-set, Up: Built-in Variables + +7.5.1 Built-in Variables That Control 'awk' +------------------------------------------- + +The following is an alphabetical list of variables that you can change +to control how 'awk' does certain things. + + The variables that are specific to 'gawk' are marked with a pound +sign ('#'). These variables are 'gawk' extensions. In other 'awk' +implementations or if 'gawk' is in compatibility mode (*note Options::), +they are not special. (Any exceptions are noted in the description of +each variable.) + +'BINMODE #' + On non-POSIX systems, this variable specifies use of binary mode + for all I/O. Numeric values of one, two, or three specify that + input files, output files, or all files, respectively, should use + binary I/O. A numeric value less than zero is treated as zero, and + a numeric value greater than three is treated as three. + Alternatively, string values of '"r"' or '"w"' specify that input + files and output files, respectively, should use binary I/O. A + string value of '"rw"' or '"wr"' indicates that all files should + use binary I/O. Any other string value is treated the same as + '"rw"', but causes 'gawk' to generate a warning message. 'BINMODE' + is described in more detail in *note PC Using::. 'mawk' (*note + Other Versions::) also supports this variable, but only using + numeric values. + +'CONVFMT' + A string that controls the conversion of numbers to strings (*note + Conversion::). It works by being passed, in effect, as the first + argument to the 'sprintf()' function (*note String Functions::). + Its default value is '"%.6g"'. 'CONVFMT' was introduced by the + POSIX standard. + +'FIELDWIDTHS #' + A space-separated list of columns that tells 'gawk' how to split + 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 + fields based on text that matches the regular expression. + Assigning a value to 'FPAT' overrides the use of 'FS' and + 'FIELDWIDTHS' for field splitting. *Note Splitting By Content:: + for more information. + +'FS' + The input field separator (*note Field Separators::). The value is + a single-character string or a multicharacter regular expression + that matches the separations between fields in an input record. If + the value is the null string ('""'), then each character in the + record becomes a separate field. (This behavior is a 'gawk' + extension. POSIX 'awk' does not specify the behavior when 'FS' is + the null string. Nonetheless, some other versions of 'awk' also + treat '""' specially.) + + 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. It also + causes spaces, TABs, and newlines at the beginning and end of a + record to be ignored. + + You can set the value of 'FS' on the command line using the '-F' + option: + + awk -F, 'PROGRAM' INPUT-FILES + + If 'gawk' is using 'FIELDWIDTHS' or 'FPAT' for field splitting, + assigning a value to 'FS' causes 'gawk' to return to the normal, + 'FS'-based field splitting. An easy way to do this is to simply + say 'FS = FS', perhaps with an explanatory comment. + +'IGNORECASE #' + If 'IGNORECASE' is nonzero or non-null, then all string comparisons + and all regular expression matching are case-independent. This + applies to regexp matching with '~' and '!~', the 'gensub()', + 'gsub()', 'index()', 'match()', 'patsplit()', 'split()', and + 'sub()' functions, record termination with 'RS', and field + splitting with 'FS' and 'FPAT'. However, the value of 'IGNORECASE' + does _not_ affect array subscripting and it does not affect field + splitting when using a single-character field separator. *Note + Case-sensitivity::. + +'LINT #' + When this variable is true (nonzero or non-null), 'gawk' behaves as + if the '--lint' command-line option is in effect (*note Options::). + With a value of '"fatal"', lint warnings become fatal errors. With + a value of '"invalid"', only warnings about things that are + actually invalid are issued. (This is not fully implemented yet.) + Any other true value prints nonfatal warnings. Assigning a false + value to 'LINT' turns off the lint warnings. + + This variable is a 'gawk' extension. It is not special in other + 'awk' implementations. Unlike with the other special variables, + changing 'LINT' does affect the production of lint warnings, even + if 'gawk' is in compatibility mode. Much as the '--lint' and + '--traditional' options independently control different aspects of + 'gawk''s behavior, the control of lint warnings during program + execution is independent of the flavor of 'awk' being executed. + +'OFMT' + A string that controls conversion of numbers to strings (*note + Conversion::) for printing with the 'print' statement. It works by + being passed as the first argument to the 'sprintf()' function + (*note String Functions::). Its default value is '"%.6g"'. + Earlier versions of 'awk' used 'OFMT' to specify the format for + converting numbers to strings in general expressions; this is now + done by 'CONVFMT'. + +'OFS' + The output field separator (*note Output Separators::). It is + output between the fields printed by a 'print' statement. Its + default value is '" "', a string consisting of a single space. + +'ORS' + The output record separator. It is output at the end of every + 'print' statement. Its default value is '"\n"', the newline + character. (*Note Output Separators::.) + +'PREC #' + The working precision of arbitrary-precision floating-point + numbers, 53 bits by default (*note Setting precision::). + +'ROUNDMODE #' + The rounding mode to use for arbitrary-precision arithmetic on + numbers, by default '"N"' ('roundTiesToEven' in the IEEE 754 + standard; *note Setting the rounding mode::). + +'RS' + The input record separator. Its default value is a string + containing a single newline character, which means that an input + record consists of a single line of text. It can also be the null + string, in which case records are separated by runs of blank lines. + If it is a regexp, records are separated by matches of the regexp + in the input text. (*Note Records::.) + + The ability for 'RS' to be a regular expression is a 'gawk' + extension. In most other 'awk' implementations, or if 'gawk' is in + compatibility mode (*note Options::), just the first character of + 'RS''s value is used. + +'SUBSEP' + The subscript separator. It has the default value of '"\034"' and + is used to separate the parts of the indices of a multidimensional + array. Thus, the expression 'foo["A", "B"]' really accesses + 'foo["A\034B"]' (*note Multidimensional::). + +'TEXTDOMAIN #' + Used for internationalization of programs at the 'awk' level. It + sets the default text domain for specially marked string constants + in the source text, as well as for the 'dcgettext()', + 'dcngettext()', and 'bindtextdomain()' functions (*note + Internationalization::). The default value of 'TEXTDOMAIN' is + '"messages"'. + + +File: gawk.info, Node: Auto-set, Next: ARGC and ARGV, Prev: User-modified, Up: Built-in Variables + +7.5.2 Built-in Variables That Convey Information +------------------------------------------------ + +The following is an alphabetical list of variables that 'awk' sets +automatically on certain occasions in order to provide information to +your program. + + The variables that are specific to 'gawk' are marked with a pound +sign ('#'). These variables are 'gawk' extensions. In other 'awk' +implementations or if 'gawk' is in compatibility mode (*note Options::), +they are not special: + +'ARGC', 'ARGV' + The command-line arguments available to 'awk' programs are stored + in an array called 'ARGV'. 'ARGC' is the number of command-line + arguments present. *Note Other Arguments::. Unlike most 'awk' + arrays, 'ARGV' is indexed from 0 to 'ARGC' - 1. In the following + example: + + $ awk 'BEGIN { + > for (i = 0; i < ARGC; i++) + > print ARGV[i] + > }' inventory-shipped mail-list + -| awk + -| inventory-shipped + -| mail-list + + 'ARGV[0]' contains 'awk', 'ARGV[1]' contains 'inventory-shipped', + and 'ARGV[2]' contains 'mail-list'. The value of 'ARGC' is three, + one more than the index of the last element in 'ARGV', because the + elements are numbered from zero. + + The names 'ARGC' and 'ARGV', as well as the convention of indexing + the array from 0 to 'ARGC' - 1, are derived from the C language's + method of accessing command-line arguments. + + The value of 'ARGV[0]' can vary from system to system. Also, you + should note that the program text is _not_ included in 'ARGV', nor + are any of 'awk''s command-line options. *Note ARGC and ARGV:: for + information about how 'awk' uses these variables. (d.c.) + +'ARGIND #' + The index in 'ARGV' of the current file being processed. Every + time 'gawk' opens a new data file for processing, it sets 'ARGIND' + to the index in 'ARGV' of the file name. When 'gawk' is processing + the input files, 'FILENAME == ARGV[ARGIND]' is always true. + + This variable is useful in file processing; it allows you to tell + how far along you are in the list of data files as well as to + distinguish between successive instances of the same file name on + the command line. + + While you can change the value of 'ARGIND' within your 'awk' + program, 'gawk' automatically sets it to a new value when it opens + the next file. + +'ENVIRON' + An associative array containing the values of the environment. 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'. + + 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 + 'ENVIRON["AWKPATH"]' and 'ENVIRON["AWKLIBPATH"]'; *note AWKPATH + Variable:: and *note AWKLIBPATH Variable::). + +'ERRNO #' + If a system error occurs during a redirection for 'getline', during + a read for 'getline', or during a 'close()' operation, then 'ERRNO' + contains a string describing the error. + + In addition, 'gawk' clears 'ERRNO' before opening each command-line + input file. This enables checking if the file is readable inside a + 'BEGINFILE' pattern (*note BEGINFILE/ENDFILE::). + + Otherwise, 'ERRNO' works similarly to the C variable 'errno'. + Except for the case just mentioned, 'gawk' _never_ clears it (sets + it to zero or '""'). Thus, you should only expect its value to be + meaningful when an I/O operation returns a failure value, such as + '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 + 'FILENAME' is set to '"-"'. 'FILENAME' changes each time a new + file is read (*note Reading Files::). Inside a 'BEGIN' rule, the + value of 'FILENAME' is '""', because there are no input files being + processed yet.(1) (d.c.) Note, though, that using 'getline' + (*note Getline::) inside a 'BEGIN' rule can give 'FILENAME' a + value. + +'FNR' + The current record number in the current file. 'awk' increments + 'FNR' each time it reads a new record (*note Records::). 'awk' + resets 'FNR' to zero each time it starts a new input file. + +'NF' + The number of fields in the current input record. 'NF' is set each + time a new record is read, when a new field is created, or when + '$0' changes (*note Fields::). + + Unlike most of the variables described in this node, assigning a + value to 'NF' has the potential to affect 'awk''s internal + workings. In particular, assignments to 'NF' can be used to create + fields in or remove fields from the current record. *Note Changing + Fields::. + +'FUNCTAB #' + An array whose indices and corresponding values are the names of + all the built-in, user-defined, and extension functions in the + program. + + NOTE: Attempting to use the 'delete' statement with the + 'FUNCTAB' array causes a fatal error. Any attempt to assign + to an element of 'FUNCTAB' also causes a fatal error. + +'NR' + The number of input records 'awk' has processed since the beginning + of the program's execution (*note Records::). 'awk' increments + 'NR' each time it reads a new record. + +'PROCINFO #' + The elements of this array provide access to information about the + 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, '"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. + + 'PROCINFO["identifiers"]' + A subarray, indexed by the names of all identifiers used in + the text of the 'awk' program. An "identifier" is simply the + name of a variable (be it scalar or array), built-in function, + user-defined function, or extension function. For each + identifier, the value of the element is one of the following: + + '"array"' + The identifier is an array. + + '"builtin"' + The identifier is a built-in function. + + '"extension"' + The identifier is an extension function loaded via + '@load' or '-l'. + + '"scalar"' + The identifier is a scalar. + + '"untyped"' + The identifier is untyped (could be used as a scalar or + an array; 'gawk' doesn't know yet). + + '"user"' + The identifier is a user-defined function. + + The values indicate what 'gawk' knows about the identifiers + after it has finished parsing the program; they are _not_ + updated while the program runs. + + 'PROCINFO["pgrpid"]' + The process group ID of the current process. + + 'PROCINFO["pid"]' + The process ID of the current process. + + 'PROCINFO["ppid"]' + The parent process ID of the current process. + + 'PROCINFO["strftime"]' + The default time format string for 'strftime()'. Assigning a + new value to this element changes the default. *Note Time + Functions::. + + 'PROCINFO["uid"]' + The value of the 'getuid()' system call. + + 'PROCINFO["version"]' + The version of 'gawk'. + + The following additional elements in the array are available to + provide information about the MPFR and GMP libraries if your + version of 'gawk' supports arbitrary-precision arithmetic (*note + Arbitrary Precision Arithmetic::): + + 'PROCINFO["gmp_version"]' + The version of the GNU MP library. + + 'PROCINFO["mpfr_version"]' + The version of the GNU MPFR library. + + 'PROCINFO["prec_max"]' + The maximum precision supported by MPFR. + + 'PROCINFO["prec_min"]' + The minimum precision required by MPFR. + + The following additional elements in the array are available to + provide information about the version of the extension API, if your + version of 'gawk' supports dynamic loading of extension functions + (*note Dynamic Extensions::): + + 'PROCINFO["api_major"]' + The major version of the extension API. + + 'PROCINFO["api_minor"]' + The minor version of the extension API. + + On some systems, there may be elements in the array, '"group1"' + through '"groupN"' for some N. N is the number of supplementary + groups that the process has. Use the 'in' operator to test for + these elements (*note Reference to Elements::). + + The following elements allow you to change 'gawk''s behavior: + + 'PROCINFO["NONFATAL"]' + If this element exists, then I/O errors for all redirections + become nonfatal. *Note Nonfatal::. + + 'PROCINFO["NAME", "NONFATAL"]' + Make I/O errors for 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 + information. + + 'PROCINFO["INPUT_NAME", "READ_TIMEOUT"]' + Set a timeout for reading from input redirection INPUT_NAME. + *Note Read Timeout:: for more information. + + 'PROCINFO["INPUT_NAME", "RETRY"]' + If an I/O error that may be retried occurs when reading data + from INPUT_NAME, and this array entry exists, then 'getline' + returns -2 instead of following the default behavior of + returning -1 and configuring INPUT_NAME to return no further + data. An I/O error that may be retried is one where 'errno' + has the value 'EAGAIN', 'EWOULDBLOCK', 'EINTR', or + 'ETIMEDOUT'. This may be 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. *Note Retrying Input:: for more + information. + + 'PROCINFO["sorted_in"]' + If this element exists in 'PROCINFO', its value controls the + order in which array indices will be processed by 'for (INDX + in ARRAY)' loops. This is an advanced feature, so we defer + the full description until later; see *note Scanning an + Array::. + +'RLENGTH' + The length of the substring matched by the 'match()' function + (*note String Functions::). 'RLENGTH' is set by invoking the + 'match()' function. Its value is the length of the matched string, + or -1 if no match is found. + +'RSTART' + The start index in characters of the substring that is matched by + the 'match()' function (*note String Functions::). 'RSTART' is set + by invoking the 'match()' function. Its value is the position of + the string where the matched substring starts, or zero if no match + was found. + +'RT #' + The input text that matched the text denoted by 'RS', the record + separator. It is set every time a record is read. + +'SYMTAB #' + An array whose indices are the names of all defined global + variables and arrays in the program. 'SYMTAB' makes 'gawk''s + symbol table visible to the 'awk' programmer. It is built as + 'gawk' parses the program and is complete before the program starts + to run. + + The array may be used for indirect access to read or write the + value of a variable: + + foo = 5 + SYMTAB["foo"] = 4 + print foo # prints 4 + + The 'isarray()' function (*note Type Functions::) may be used to + test if an element in 'SYMTAB' is an array. Also, you may not use + the 'delete' statement with the 'SYMTAB' array. + + You may use an index for 'SYMTAB' that is not a predefined + identifier: + + SYMTAB["xxx"] = 5 + print SYMTAB["xxx"] + + This works as expected: in this case 'SYMTAB' acts just like a + regular array. The only difference is that you can't then delete + 'SYMTAB["xxx"]'. + + The 'SYMTAB' array is more interesting than it looks. Andrew + Schorr points out that it effectively gives 'awk' data pointers. + Consider his example: + + # Indirect multiply of any variable by amount, return result + + function multiply(variable, amount) + { + return SYMTAB[variable] *= amount + } + + You would use it like this: + + BEGIN { + answer = 10.5 + multiply("answer", 4) + print "The answer is", answer + } + + When run, this produces: + + $ gawk -f answer.awk + -| The answer is 42 + + NOTE: In order to avoid severe time-travel paradoxes,(2) + neither 'FUNCTAB' nor 'SYMTAB' is available as an element + within the 'SYMTAB' array. + + Changing 'NR' and 'FNR' + + 'awk' increments 'NR' and 'FNR' each time it reads a record, instead +of setting them to the absolute value of the number of records read. +This means that a program can change these variables and their new +values are incremented for each record. (d.c.) The following example +shows this: + + $ echo '1 + > 2 + > 3 + > 4' | awk 'NR == 2 { NR = 17 } + > { print NR }' + -| 1 + -| 17 + -| 18 + -| 19 + +Before 'FNR' was added to the 'awk' language (*note V7/SVR3.1::), many +'awk' programs used this feature to track the number of records in a +file by resetting 'NR' to zero when 'FILENAME' changed. + + ---------- Footnotes ---------- + + (1) Some early implementations of Unix 'awk' initialized 'FILENAME' +to '"-"', even if there were data files to be processed. This behavior +was incorrect and should not be relied upon in your programs. + + (2) Not to mention difficult implementation issues. + + +File: gawk.info, Node: ARGC and ARGV, Prev: Auto-set, Up: Built-in Variables + +7.5.3 Using 'ARGC' and 'ARGV' +----------------------------- + +*note Auto-set:: presented the following program describing the +information contained in 'ARGC' and 'ARGV': + + $ awk 'BEGIN { + > for (i = 0; i < ARGC; i++) + > print ARGV[i] + > }' inventory-shipped mail-list + -| awk + -| inventory-shipped + -| mail-list + +In this example, 'ARGV[0]' contains 'awk', 'ARGV[1]' contains +'inventory-shipped', and 'ARGV[2]' contains 'mail-list'. Notice that +the 'awk' program is not entered in 'ARGV'. The other command-line +options, with their arguments, are also not entered. This includes +variable assignments done with the '-v' option (*note Options::). +Normal variable assignments on the command line _are_ treated as +arguments and do show up in the 'ARGV' array. Given the following +program in a file named 'showargs.awk': + + 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 } + +Running it produces the following: + + $ awk -v A=1 -f showargs.awk B=2 /dev/null + -| A=1, B=0 + -| ARGV[0] = awk + -| ARGV[1] = B=2 + -| ARGV[2] = /dev/null + -| A=1, B=2 + + A program can alter 'ARGC' and the elements of 'ARGV'. Each time +'awk' reaches the end of an input file, it uses the next element of +'ARGV' as the name of the next input file. By storing a different +string there, a program can change which files are read. Use '"-"' to +represent the standard input. Storing additional elements and +incrementing 'ARGC' causes additional files to be read. + + If the value of 'ARGC' is decreased, that eliminates input files from +the end of the list. By recording the old value of 'ARGC' elsewhere, a +program can treat the eliminated arguments as something other than file +names. + + To eliminate a file from the middle of the list, store the null +string ('""') into 'ARGV' in place of the file's name. As a special +feature, 'awk' ignores file names that have been replaced with the null +string. Another option is to use the 'delete' statement to remove +elements from 'ARGV' (*note Delete::). + + All of these actions are typically done in the 'BEGIN' rule, before +actual processing of the input begins. *Note Split Program:: and *note +Tee Program:: for examples of each way of removing elements from 'ARGV'. + + To actually get options into an 'awk' program, end the 'awk' options +with '--' and then supply the 'awk' program's options, in the following +manner: + + awk -f myprog.awk -- -v -q file1 file2 ... + + The following fragment processes 'ARGV' in order to examine, and then +remove, the previously mentioned command-line options: + + 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: unrecognized option -- %c", + ARGV[0], substr(ARGV[i], 2, 1)) + print e > "/dev/stderr" + } else + break + delete ARGV[i] + } + } + + Ending the 'awk' options with '--' isn't necessary in 'gawk'. Unless +'--posix' has been specified, 'gawk' silently puts any unrecognized +options into 'ARGV' for the 'awk' program to deal with. As soon as it +sees an unknown option, 'gawk' stops looking for other options that it +might otherwise recognize. The previous command line with 'gawk' would +be: + + gawk -f myprog.awk -q -v file1 file2 ... + +Because '-q' is not a valid 'gawk' option, it and the following '-v' are +passed on to the 'awk' program. (*Note Getopt Function:: for an 'awk' +library function that parses command-line options.) + + When designing your program, you should choose options that don't +conflict with 'gawk''s, because it will process any options that it +accepts before passing the rest of the command line on to your program. +Using '#!' with the '-E' option may help (*note Executable Scripts:: and +*note Options::). + + +File: gawk.info, Node: Pattern Action Summary, Prev: Built-in Variables, Up: Patterns and Actions + +7.6 Summary +=========== + + * Pattern-action pairs make up the basic elements of an 'awk' + program. Patterns are either normal expressions, range + expressions, or regexp constants; one of the special keywords + 'BEGIN', 'END', 'BEGINFILE', or 'ENDFILE'; or empty. The action + executes if the current record matches the pattern. Empty + (missing) patterns match all records. + + * I/O from 'BEGIN' and 'END' rules has certain constraints. This is + also true, only more so, for 'BEGINFILE' and 'ENDFILE' rules. The + latter two give you "hooks" into 'gawk''s file processing, allowing + you to recover from a file that otherwise would cause a fatal error + (such as a file that cannot be opened). + + * Shell variables can be used in 'awk' programs by careful use of + shell quoting. It is easier to pass a shell variable into 'awk' by + using the '-v' option and an 'awk' variable. + + * Actions consist of statements enclosed in curly braces. Statements + are built up from expressions, control statements, compound + statements, input and output statements, and deletion statements. + + * The control statements in 'awk' are 'if'-'else', 'while', 'for', + and 'do'-'while'. 'gawk' adds the 'switch' statement. There are + two flavors of 'for' statement: one for performing general looping, + and the other for iterating through an array. + + * 'break' and 'continue' let you exit early or start the next + iteration of a loop (or get out of a 'switch'). + + * 'next' and 'nextfile' let you read the next record and start over + at the top of your program or skip to the next input file and start + over, respectively. + + * The 'exit' statement terminates your program. When executed from + an action (or function body), it transfers control to the 'END' + statements. From an 'END' statement body, it exits immediately. + You may pass an optional numeric value to be used as 'awk''s exit + status. + + * Some predefined variables provide control over 'awk', mainly for + I/O. Other variables convey information from 'awk' to your program. + + * 'ARGC' and 'ARGV' make the command-line arguments available to your + program. Manipulating them from a 'BEGIN' rule lets you control + how 'awk' will process the provided data files. + + +File: gawk.info, Node: Arrays, Next: Functions, Prev: Patterns and Actions, Up: Top + +8 Arrays in 'awk' +***************** + +An "array" is a table of values called "elements". The elements of an +array are distinguished by their "indices". Indices may be either +numbers or strings. + + This major node describes how arrays work in 'awk', how to use array +elements, how to scan through every element in an array, and how to +remove array elements. It also describes how 'awk' simulates +multidimensional arrays, as well as some of the less obvious points +about array usage. The major node moves on to discuss 'gawk''s facility +for sorting arrays, and ends with a brief description of 'gawk''s +ability to support true arrays of arrays. + +* Menu: + +* Array Basics:: The basics of arrays. +* Numeric Array Subscripts:: How to use numbers as subscripts in + 'awk'. +* Uninitialized Subscripts:: Using Uninitialized variables as subscripts. +* Delete:: The 'delete' statement removes an element + from an array. +* Multidimensional:: Emulating multidimensional arrays in + 'awk'. +* Arrays of Arrays:: True multidimensional arrays. +* Arrays Summary:: Summary of arrays. + + +File: gawk.info, Node: Array Basics, Next: Numeric Array Subscripts, Up: Arrays + +8.1 The Basics of Arrays +======================== + +This minor node presents the basics: working with elements in arrays one +at a time, and traversing all of the elements in an array. + +* Menu: + +* Array Intro:: Introduction to Arrays +* Reference to Elements:: How to examine one element of an array. +* Assigning Elements:: How to change an element of an array. +* Array Example:: Basic Example of an Array +* Scanning an Array:: A variation of the 'for' statement. It + loops through the indices of an array's + existing elements. +* Controlling Scanning:: Controlling the order in which arrays are + scanned. + + +File: gawk.info, Node: Array Intro, Next: Reference to Elements, Up: Array Basics + +8.1.1 Introduction to Arrays +---------------------------- + + Doing linear scans over an associative array is like trying to club + someone to death with a loaded Uzi. + -- _Larry Wall_ + + The 'awk' language provides one-dimensional arrays for storing groups +of related strings or numbers. Every 'awk' array must have a name. +Array names have the same syntax as variable names; any valid variable +name would also be a valid array name. But one name cannot be used in +both ways (as an array and as a variable) in the same 'awk' program. + + Arrays in 'awk' superficially resemble arrays in other programming +languages, but there are fundamental differences. In 'awk', it isn't +necessary to specify the size of an array before starting to use it. +Additionally, any number or string, not just consecutive integers, may +be used as an array index. + + In most other languages, arrays must be "declared" before use, +including a specification of how many elements or components they +contain. In such languages, the declaration causes a contiguous block +of memory to be allocated for that many elements. Usually, an index in +the array must be a nonnegative integer. For example, the index zero +specifies the first element in the array, which is actually stored at +the beginning of the block of memory. Index one specifies the second +element, which is stored in memory right after the first element, and so +on. It is impossible to add more elements to the array, because it has +room only for as many elements as given in the declaration. (Some +languages allow arbitrary starting and ending indices--e.g., '15 .. +27'--but the size of the array is still fixed when the array is +declared.) + + A contiguous array of four elements might look like *note Figure 8.1: +figure-array-elements, conceptually, if the element values are eight, +'"foo"', '""', and 30. + +