pax_global_header00006660000000000000000000000064146530110220014504gustar00rootroot0000000000000052 comment=f0999ab76dd2e0d977298348ec5c4535a360710d ksh-1.0.10/000077500000000000000000000000001465301102200123505ustar00rootroot00000000000000ksh-1.0.10/.github/000077500000000000000000000000001465301102200137105ustar00rootroot00000000000000ksh-1.0.10/.github/workflows/000077500000000000000000000000001465301102200157455ustar00rootroot00000000000000ksh-1.0.10/.github/workflows/ci.yml000066400000000000000000000025401465301102200170640ustar00rootroot00000000000000name: CI on: [push] jobs: Linux: name: Linux runs-on: ubuntu-latest steps: - name: Checkout sources uses: actions/checkout@v2 - name: Build run: bin/package make - name: Regression tests run: | PS4="$PS4[ci.yml] " set -o xtrace export TZ=UTC ulimit -n 1024 : default regression tests && script -q -e -c "bin/package test" && : regression tests with OS-provided multibyte locales && LANG=nl_NL.UTF-8 script -q -e -c "bin/shtests --locale --nocompile" && LANG=ja_JP.SJIS script -q -e -c "bin/shtests --locale --nocompile" && : disable most SHOPTs, rebuild ksh && sed --regexp-extended --in-place=.orig \ '/^SHOPT (AUDIT|BGX|BRACEPAT|DEVFD|DYNAMIC|EDPREDICT|ESH|FIXEDARRAY|HISTEXPAND|MULTIBYTE|NAMESPACE|OPTIMIZE|SPAWN|STATS|SUID_EXEC|VSH)=/ s/=1?/=0/' \ src/cmd/ksh93/SHOPT.sh && bin/package make && : default regression tests with SHOPTs disabled && script -q -e -c "bin/shtests" && : enable SHOPT_SCRIPTONLY, rebuild ksh && sed --regexp-extended --in-place=.orig \ '/^SHOPT SCRIPTONLY=/ s/=0?/=1/' \ src/cmd/ksh93/SHOPT.sh && bin/package make && : default regression tests with SHOPT_SCRIPTONLY enabled && script -q -e -c "bin/shtests" ksh-1.0.10/.gitignore000066400000000000000000000016261465301102200143450ustar00rootroot00000000000000# Project-specific files arch tgz lcl # Flat make libs, binaries, etc *.a *.o *.req FEATURE/ /bin/.paths /bin/crossexec /bin/iffe /bin/ksh /bin/mamake /bin/mktest /bin/ok/ /bin/proto /bin/pty /bin/regress /bin/shcomp /fun/ /include/ /lib/ /man/ /src/cmd/INIT/crossexec /src/cmd/INIT/iffe /src/cmd/INIT/mamake /src/cmd/INIT/mamprobe /src/cmd/INIT/mktest /src/cmd/INIT/mprobe /src/cmd/INIT/package /src/cmd/INIT/probe /src/cmd/INIT/probe.sh /src/cmd/INIT/regress /src/cmd/builtin/pty /src/cmd/ksh93/ksh /src/cmd/ksh93/shcomp /src/lib/libast/*.h /src/lib/libast/astmath.exe /src/lib/libast/conf /src/lib/libast/conftab.c /src/lib/libast/lcgen /src/lib/libast/lctab.c /src/lib/libast/t.c /src/lib/libcmd/cmdext.h /src/lib/libcmd/cmdlist.h /src/lib/libdll/dlldefs.h # Miscellaneous artefacts *.stackdump *.dSYM/ *.bak *.sav *.old *.orig .*.swp *.DS_Store *~ .nfs* *.tmp *.rej *.project *.core core **/#*# tags cscope.out ksh-1.0.10/ANNOUNCE000066400000000000000000000525051465301102200135100ustar00rootroot00000000000000Announcing: KornShell 93u+m/1.0.10 https://github.com/ksh93/ksh Here is the tenth ksh 93u+m/1.0 bugfix release -- exactly two years after 93u+m/1.0.0 and twelve years after 93u+. Unfortunately, we're not done fixing bugs yet, but progress continues steadily. This release fixes a serious bug in the arithmetic subsystem that was triggered on non-Intel processors (such as ARM): any division of an integer by a negative integer threw a spurious "divide by zero" error. This bug has been in ksh since 2005. There are other bug fixes as well; see below. For greater detail, see the NEWS file in the distribution. For complete detail, see the git(1) commit log, which has full documentation of every significant change. ### HOW TO GET IT ### Please download the source code tarball from our GitHub releases page: https://github.com/ksh93/ksh/releases To build, follow the instructions in README.md or src/cmd/ksh93/README. Or ask your distribution package maintainer to upgrade ksh to this version. ### ABOUT KSH ### KornShell (ksh) is a full-featured and very fast shell script interpreter and interactive command shell with a distinguished lineage: it is a direct descendant of the Bourne shell and, like its ancestor, was developed at AT&T, the birthplace of UNIX. ksh has been open source since 2000. But when AT&T terminated development in 2020, ksh was left buggy and unreliable. ksh 93u+m aims to fix this situation whilst maintaining and growing the tradition. For now, we are focusing mostly on fixing bugs and egregious flaws but we also prioritise backward compatibility, performance, portability, and occasionally adding a feature. Work on ksh 93u+m started in May 2020, based on the last AT&T stable release, ksh 93u+. Unique ksh features include discipline functions (every variable expansion or assignment can trigger a shell function call determining its value), static scoping of local variables in functions, the ability to define your own data types, customisable tilde expansion (new in 93u+m), a shell option for file system case (in)sensitivity detection for pathname expansion and file name completion (new in 93u+m), and much more. ### CONTRIBUTORS ### Main ksh 93u+m developers: Martijn Dekker, Johnothan King, hyenias Direct contributors: Andy Fiddaman, Anuradha Weeraman, atheik, Chase, Cy Schubert, Govind Kamat, Harald van Dijk, hyousatsu, K. Eugene Carlson, Lev Kujawski, Marc Wilson, Phi, Ryan Schmidt, rymrg, Sterling Jensen, Trey Valenta, Vincent Mihalkovic Also includes backported contributions by: David Korn, Glenn Fowler, Lefteris Koutsofios, Siteshwar Vashisht, Kurtis Rader, Roland Mainz, Finnbarr P. Murphy, Lijo George, OpenSUSE ksh 93u+ patch authors, Red Hat ksh 93u+ path authors, Solaris ksh 93u+ patch authors, Debian ksh 93u+ patch authors, Apple ksh 93u+ patch authors, Graphviz maintainers Many fixes have also been backported from the AT&T 93v- beta as well as the former AT&T ksh2020 project lead by Kurtis Rader and Siteshwar Vashisht; we appreciate and benefit from their work. Many thanks also to Siteshwar for graciously donating his 'ksh93' GitHub organisation account! ### HOW TO GET INVOLVED ### To report a bug, please open an issue at our GitHub page (see above). Alternatively, email me at martijn@inlv.org with your report. To get involved in development, read the brief policy information in README.md and then jump right in with a pull request or email a patch. Feel free to use Discussions to introduce yourself to the community. You can also join the mailing list/Google group at: https://groups.google.com/g/korn-shell ### MAIN CHANGES between ksh 93u+m/1.0.9 and 93u+m/1.0.10 ### - Fixed a serious and longstanding bug in the arithmetic subsystem that was triggered on non-Intel processors (such as ARM): any division of an integer by a negative integer threw a spurious "divide by zero" error. - Fixed a regression where a broken pipe signal (SIGPIPE), when occurring in a pipe construct within a subshell, caused incorrect signal handling in the parent/main shell, in some cases causing a script to abort. - Fixed a bug where printf %T, after having printed the time in UTC once with the TZ variable set to "UTC", would always print the time in UTC from then on, even if the TZ variable was changed to another time zone. - The history expansion character ('!' by default) is now not processed when immediately following '${'. This makes it psosible to use expansion syntax like ${!varname} and ${!prefix@} on the interactive command line with the histexpand option on; these no longer trigger an "event not found" error. - The shell is now capable of handling more than 32767 simultaneous background jobs, subject to system limitations. ### MAIN CHANGES between ksh 93u+m/1.0.8 and 93u+m/1.0.9 ### - Android/Termux is now a supported platform. Build dependencies: binutils, clang, getconf. Runtime dependencies (optional): ncurses-utils, getconf. - Reintroduced support for building a dynamically linked ksh(1)/shcomp(1), with libast, libdll, libcmd, and libshell available to other programs as dynamic libraries. 'bin/package install /your/basepath' will install development headers. The dynamically linked version is built in a 'dyn' subdirectory; there are no changes to the statically linked version. Dynamic linking is currently tested and supported on Linux, Android, macOS, all the BSDs, illumos, Solaris, QNX, and Haiku. - On systems where the external printf(1) utility supports deprecated pre-POSIX syntax for formatters starting with '-', ksh now adapts its built-in printf to match, for compatibility with system scripts. However, ksh's built-in printf options such as -v or --man are not affected. - Fixed a regression in the 'printf' built-in, introduced in 93u+m/1.0.5, where each instance of '\0' or '%Z' in the format operand caused a string argument to be incorrectly skipped. - Fixed a regression, introduced in 93u+m/1.0.5, in ordinal specifiers in 'printf %T' date specifications. For example, printf '%(%F)T\n' '4th tuesday in march 2016' wrongly printed '2016-04-09' and now again correctly prints '2016-03-22'. - Fixed a regression of 'return' within traps, reintroduced in 93u+m/1.0.8 after being fixed in 93u+m/1.0.0. The regression caused a 'return' or 'exit' with no arguments to assume the before-trap exit status instead of that of the last-run command. This broke the shipped 'autocd' function. - Fixed a longstanding bug in shell arithmetic: the representation of negative integers with a base other than 10 was incorrectly treated as unsigned long. For example, typeset -i16 n=-12; echo $n now correctly outputs '-16#c' and no longer ouputs '16#fffffffffffffff4'. - Fixed a bug, introduced in ksh93q+ 2005-05-22, that stopped an append assignment from working together with a declaration command. For example, 'typeset var+=value' or 'export var+=value' now again work as expected. - Fixed a longstanding bug where the default terminal width for typeset -L, -R, or -Z, if not given, was miscalculated for multibyte or control characters. - Fixed: expansions of name references in loops were incorrectly treated as invariant so they yielded the wrong values. - If a .get or .getn discipline function is set for a variable, it is no longer incorrectly triggered when performing an arithmetic assignment on that variable; only the .set discipline is now triggered (as documented). - Many other bug fixes (see the NEWS file). ### MAIN CHANGES between ksh 93u+m/1.0.7 and 93u+m/1.0.8 ### - Fixed a regression in the behavior of 'exit' in a trap action. The exit status used when no argument is given to 'exit' is now once again the exit status of the last command executed *before* the trap action. - Fixed a race condition, introduced in 1.0.7, that occurred on some systems when running an external command with a standard output redirection from a command substitution. - Fixed an init-time crash on failure to trim the shell command history file due to a non-writable parent directory; ksh now prints a warning instead. - The 'kill' built-in command now correctly refuses to issue SIGSTOP to the shell's own process if the shell is a login shell. ### MAIN CHANGES between ksh 93u+m/1.0.6 and 93u+m/1.0.7 ### - Fixed a hang in command substitutions (introduced in 93u+m/1.0.0) that was triggered when redirecting standard output within a command substitution, in combination with other factors. E.g., the following no longer hangs: { v=$(redirect 2>&1 1>&9); } 9>&1 - Fixed a crash on trying to append an indexed array value to an unset name reference, e.g.: nameref unsetref; unsetref+=(foo bar). This now produces a "removing nameref attribute" warning before performing the assignment. - Fixed: assignments like name=(...) to arrays did not preserve the array and variable types; similarly, assigning an empty set () to a compound indexed array caused the -C attribute to be lost. - Fixed incorrect rejection of the tab key while reading input using the 'read' built-in command. - Fixed a bug in printf %T: when using dates and times in the past, time zones for the present were incorrectly used, ignoring historical changes. ### MAIN CHANGES between ksh 93u+m/1.0.5 and 93u+m/1.0.6 ### - Fixed a serious regression in pathname expansion where quoted wildcard characters were incorrectly expanded if a pattern contains both a brace expansion and a variable expansion. - Fixed a bug where the command to launch a full-screen editor (^X^E in emacs and 'v' in vi) could cause the wrong command line to be edited if two shell sessions share a .sh_history file. ### MAIN CHANGES between ksh 93u+m/1.0.4 and 93u+m/1.0.5 ### - Fixed various bugs causing crashes. - Fixed many bugs in the emacs and vi line editors, in command completion, and in file name completion. - Fixed various bugs in the handling of quotes, backslash escapes and braces when processing shell glob patterns (e.g. in pathname expansion and 'case'). - ksh now throws a panic and exits if a read error (such as an I/O error) occurs while trying to read the next command(s) from a running script. - Fixed many bugs in 'printf' and 'print -f' built-in commands, including: . Multiple bugs causing incorrect output for relative date specifications, e.g., printf %T\\n 'exactly 20 months ago' now outputs a correct result. . More printf bugs with mix and match of % and %x$. . A data corruption bug when using %B with 'printf -v varname'. . A bug causing double evaluation of arithmetic expressions. - Fixed a bug where 'unset -f commandname', executed in a subshell, hides any built-in command by the same name for the duration of that subshell. - Fixed ${var/#/string} and ${var/%/string} (with anchored empty pattern) to work as on mksh, bash and zsh; these are no longer ineffective. - Fixed incorrect result of array slicing ${array[@]:offset:length} where 'length' is a nested expansion involving an array. - Command names can now end in ':' as they can on other shells. - Fixed a spurious syntax error in compound assignments upon encountering a pair of repeated opening parentheses '(('. - Fixed spurious syntax error in ${parameter:offset:length}: the arithmetic expressions 'offset' and 'length' may now contain the operators ( ) & |. - Fixed a parsing bug in the declaration of .sh.math.* arithmetic functions. - Fixed nameref self-reference loop detection for more than two namerefs. - Several improvements to the POSIX compatibility mode. - Many more minor and/or esoteric bugfixes. ### MAIN CHANGES between ksh 93u+m/1.0.3 and 93u+m/1.0.4 ### - Fixed multiple scoping-related bugs in the += additive assignment operator. - A number of crashing bugs have been fixed. - Various fixes for the Haiku operating system, notably 'ulimit -a' now works. - Fixed the expansion of out-of-range \n back references in the string part of ${parameter//pattern/string}. For example: v=AB; echo "${v/@(A)B/\0:\1:\2}" now yields 'AB:A:' instead of 'AB:A:\2'. - Fixed quoted '!', '^' and '-' within [bracket] expressions in glob patterns; single or double quotes failed to disable their operator behaviour. - Fixed a bug introduced on 2021-04-04 that incorrectly allowed 'typeset' to turn off the readonly and export attributes on a readonly variable. - In the emacs line editor, the Ctrl+R reverse-search prompt is now visually distinct from a literal control character ("^R: " instead of "^R"). - In the vi line editor, fixed the behaviour of 'C', 'c$' and 'I' to be consistent with standard vi(1) and with Bolsky & Korn (1995, p. 121). - Aliases for many GNU long options have been added to the /opt/ast/bin built-in commands. Additionally, 'kill -s' now has a --signal long option alias compatible with the util-linux option. - Backported support for 'print -u p' from ksh 93v- for compatibility with scripts written for 93v-/ksh2020 (this is equivalent to 'print -p'). ### MAIN CHANGES between ksh 93u+m/1.0.2 and 93u+m/1.0.3 ### This point release fixes the following: - An old bug in history expansion (set -H) where any use of the history comment character caused processing to be aborted as if it were an invalid history expansion. - A bug in command line options processing that caused short-form option equivalents on some built-in commands to be ignored after one use, e.g., the new read -a equivalent of read -A. - Ksh freezing or using excessive memory if HISTSIZE is assigned a pathologically large value. - A bug that caused ksh in the vi editor mode to crash or produce invalid completions if ESC = was used at the beginning of a line. ### MAIN CHANGES between ksh 93u+m/1.0.1 and 93u+m/1.0.2 ### This bugfix release fixes the interactive shell crashing when one of the predefined aliases (currently 'history' and 'r') is redefined, whether from a profile/kshrc script or manually. This crash occurred in two scenarios: 1. when redefining and then unsetting a predefined alias; 2. when redefining a predefined alias and then executing a shell script that does not begin with a #! path. ### MAIN CHANGES between ksh 93u+m/1.0.0 and 93u+m/1.0.1 ### This is an urgent bugfix release that removes an incorrect exec optimization that was capable of terminating the execution of scripts prematurely in certain corner cases. It is known to make the build scripts of GNU binutils produce corrupted results if ksh is used as /bin/sh. See https://github.com/ksh93/ksh/issues/507 for more information. ### MAIN CHANGES between ksh 93u+ and 93u+m/1.0.0 ### Roughly a thousand bugs have been fixed, including many serious/critical bugs. See the NEWS file for more information, and the git commit log for complete documentation of every fix. Incompatible changes have been minimised, but not at the expense of fixing bugs. For a list of potentially incompatible changes, see src/cmd/ksh93/COMPATIBILITY. Though there was a "no new features, bugfixes only" policy, some new features were found necessary, either to fix serious design flaws or to complete functionality that was evidently intended, but not finished. Below is a summary of these new features. New command line editor features: - The forward-delete and End keys are now handled as expected in the emacs and vi built-in line editors. - In the vi and emacs line editors, repeat counts can now also be used for arrow keys and the forward-delete key, e.g., 7 works. - Various keys on extended PC keyboards are now handled as expected in the emacs and vi built-in line editors. New shell language features: - Pathname expansion (a.k.a. globbing) now never matches the special names '.' (current directory) and '..' (parent directory). This change makes a pattern like .* useful; it now matches all hidden files (dotfiles) in the current directory, without the harmful inclusion of '.' and '..'. - Tilde expansion can now be extended or modified by defining a .sh.tilde.get or .sh.tilde.set discipline function. See the manual for details. - The &>file redirection shorthand (for >file 2>&1) is now available for all scripts and interactive sessions and not only for profile/login scripts. - Arithmetic expressions in native ksh mode no longer interpret a number with a leading zero as octal in any context. Use 8#octalnumber instead (e.g. 8#400 == 256). Arithmetic expressions now also behave identically within and outside ((...)) and $((...)). If the POSIX mode is turned on, a leading zero now denotes an octal number in all arithmetic contexts. New features in built-in commands: - Usage error messages now show the --help/--man self-documentation options. - Path-bound built-ins (such as /opt/ast/bin/cat) can now be executed by invoking the canonical path, so the following will now work as expected: $ /opt/ast/bin/cat --version version cat (AT&T Research) 2012-05-31 - 'cd' now supports an -e option that, when combined with -P, verifies that $PWD is correct after changing directories; this helps detect access permission problems. See: https://www.austingroupbugs.net/view.php?id=253 - 'command -x' now looks for external commands only, skipping built-ins. In addition, its xargs-like functionality no longer freezes the shell on Linux and macOS, making it effectively a new feature on these systems. - 'printf' now supports a -v option as in bash. This assigns formatted output directly to variables, which is very fast and will not strip final newline (\n) characters. - 'redirect' now checks if all arguments are valid redirections before performing them. If an error occurs, it issues an error message instead of terminating the shell. - 'return', when used to return from a function, can now return any status value in the 32-bit signed integer range, like on zsh. However, due to a traditional Unix kernel limitation, $? is still trimmed to its least significant 8 bits whenever a shell or subshell exits. - 'suspend' now refuses to suspend a login shell, as there is probably no parent shell to return to and the login session would freeze. - 'test'/'[' now supports all the same operators as [[ (including =~, \<, \>) except for the different 'and'/'or' operators. Note that 'test'/'[' remains deprecated due to its unfixable pitfalls; [[ ... ]] is recommended instead. - 'times' now gives high precision output in a POSIX compliant format. - 'type'/'whence': Two bash-like flags were backported from ksh 93v-: - 'whence -P/type -P' is an alias to the existing -p flag. - 'whence -t/type -t' will print only the type of a command in a simple format that is designed to be easy to use for scripts. - 'typeset' has a new '-g' flag that forces variables to be created or modified at the global scope regardless of context, as on bash 4.2+. - 'typeset' now gives an informative error message if an incompatible combination of options is given. - 'ulimit': Added three options inspired by bash: - 'ulimit -k' sets the maximum number of kqueues. - 'ulimit -P' sets the maximum number of pseudo-terminals. - 'ulimit -R' sets the maximum time in microseconds a real-time process can run before blocking. Note that not all operating systems support the limits set by these options. - 'whence -v/-a' now reports the location of autoloadable functions. New features in shell options: - When the -b/--notify shell option is on and the vi or emacs/gmacs shell line editor is in use, 'Done' and similar notifications from completed background jobs are now inserted directly above the line you're typing, without affecting your command line display. - A new --functrace long-form shell option causes the -x/--xtrace option's state and the DEBUG trap action to be inherited by function scopes instead of being reset to default. Changes made to them within a function scope still do not propagate back to the parent scope. Similarly, this option also causes the DEBUG trap action to be inherited by subshells. - A new --globcasedetect shell option is added on operating systems where we can check for a case-insensitive file system (currently Linux, macOS, QNX 7.0+, and Windows/Cygwin). When this option is turned on, pathname expansion (globbing), as well as tab completion on interactive shells, automatically become case-insensitive depending on the file system. This is separately determined for each pathname component. - Enhancement to -G/--globstar: symbolic links to directories are now followed if they match a normal (non-**) glob pattern. For example, if '/lnk' is a symlink to a directory, '/lnk/**' and '/l?k/**' now work as you would expect. - The new --histreedit and --histverify options modify history expansion (--histexpand). If --histreedit is on and a history expansion fails, the command line is reloaded into the next prompt's edit buffer, allowing corrections. If --histverify is on, the results of a history expansion are not immediately executed but instead loaded into the next prompt's edit buffer, allowing further changes. - A new --nobackslashctrl shell option disables the special escaping behaviour of the backslash character in the emacs and vi built-in editors. Particularly in the emacs editor, this makes it much easier to go back, insert a forgotten backslash into a command, and then continue editing without having your next arrow key replace your backslash with garbage. - A new --posix shell option has been added to ksh 93u+m that makes the ksh language more compatible with other shells by following the POSIX standard more closely. See the manual page for details. It is enabled by default if ksh is invoked as sh, otherwise it is disabled by default. ksh-1.0.10/COPYRIGHT000066400000000000000000000234721465301102200136530ustar00rootroot00000000000000ksh 93u+m general copyright notice ######################################################################## # # # The KornShell 93u+m distribution # # Copyright (c) 2020-2024 Contributors to ksh 93u+m # # # # Derived from AT&T's ast package (see below) # # Licensed under the Eclipse Public License, Version 2.0 # # # # A copy of the License is available at # # https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html # # (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) # # # # CONTRIBUTORS # # # # Martijn Dekker # # Johnothan King # # K. Eugene Carlson # # hyenias <58673227+hyenias@users.noreply.github.com> # # Anuradha Weeraman # # Lev Kujawski # # Phi # # atheik <14833674+atheik@users.noreply.github.com> # # Vincent Mihalkovic # # Ryan Schmidt # # Harald van Dijk # # Chase # # rymrg <54061433+rymrg@users.noreply.github.com> # # hyousatsu <118750527+hyousatsu@users.noreply.github.com> # # Trey Valenta # # Sterling Jensen <5555776+sterlingjensen@users.noreply.github.com> # # Marc Wilson # # Govind Kamat # # Cy Schubert # # Andy Fiddaman # # # # ALSO INCLUDES BACKPORTED CONTRIBUTIONS BY # # # # David Korn # # Glenn Fowler # # Lefteris Koutsofios # # Siteshwar Vashisht # # Kurtis Rader # # Roland Mainz # # Finnbarr P. Murphy # # Lijo George # # OpenSUSE ksh 93u+ patch authors # # Red Hat ksh 93u+ patch authors # # Solaris ksh 93u+ patch authors # # Debian ksh 93u+ patch authors # # Apple ksh 93u+ patch authors # # Graphviz maintainers (libast, sfio) # # # ######################################################################## ast package general copyright notice ######################################################################## # # # This software is part of the ast package # # Copyright (c) 1986-2014 AT&T Intellectual Property # # and is licensed under the # # Eclipse Public License, Version 1.0 # # by AT&T Intellectual Property # # # # A copy of the License is available at # # http://www.eclipse.org/org/documents/epl-v10.html # # (with md5 checksum b35adb5213ca9657e911e9befb180842) # # # # Information and Software Systems Research # # AT&T Research # # Florham Park NJ # # # # CONTRIBUTORS # # # # Glenn Fowler # # David Korn # # Phong Vo # # Roland Mainz # # Karsten Fleischer # # Adam Edgar # # Adam Buchsbaum # # Aman Shaikh # # Bala Krishnamurthy # # Brian Russell # # Robin Chen # # Don Caldwell # # Lefty Koutsofios # # Bob Gruber # # Jia Wang # # Jeff Fellin # # Jeff Korn <@google.com> # # Kathleen Fisher # # Ken Church <@microsoft.com> # # Brian Kernighan # # Dennis Ritchie # # Doug McIlroy # # Eduardo Krell # # John Snyder # # Herman Rao # # AST users mailgroup # # AST developers mailgroup # # # ######################################################################## bsd package general copyright notice ######################################################################## # # # This software is part of the BSD package # # Copyright (c) 1979-2012 The Regents of the University of California # # # # Redistribution and use in source and binary forms, with or without # # modification, are permitted provided that the following conditions # # are met: # # 1. Redistributions of source code must retain the above copyright # # notice, this list of conditions and the following disclaimer. # # 2. 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. # # 3. Neither the name of the University 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. # # # # CONTRIBUTORS # # # # Bill Joy # # # ######################################################################## ksh-1.0.10/LICENSE.md000066400000000000000000000333261465301102200137630ustar00rootroot00000000000000## Eclipse Public License - v 2.0 THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. ### 1. DEFINITIONS "Contribution" means: a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and b) in the case of each subsequent Contributor: * i) changes to the Program, and * ii) additions to the Program; where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution "originates" from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works. "Contributor" means any person or entity that Distributes the Program. "Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. "Program" means the Contributions Distributed in accordance with this Agreement. "Recipient" means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors. "Derivative Works" shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. "Modified Works" shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof. "Distribute" means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy. "Source Code" means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files. "Secondary License" means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor. ### 2. GRANT OF RIGHTS a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works. b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3). ### 3. REQUIREMENTS 3.1 If a Contributor Distributes the Program in any form, then: a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license: * i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; * ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; * iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and * iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3. 3.2 When the Program is Distributed as Source Code: a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and b) a copy of this Agreement must be included with each copy of the Program. 3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability ('notices') contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices. ### 4. COMMERCIAL DISTRIBUTION Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. ### 5. NO WARRANTY EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. ### 6. DISCLAIMER OF LIABILITY EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. ### 7. GENERAL If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement. ### Exhibit A – Form of Secondary Licenses Notice "This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}." > Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses. > > If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. > > You may add additional accurate notices of copyright ownership. ksh-1.0.10/NEWS000066400000000000000000003564331465301102200130650ustar00rootroot00000000000000This documents significant changes in the 1.0 branch of ksh 93u+m. For full details, see the git log at: https://github.com/ksh93/ksh/tree/1.0 Uppercase BUG_* IDs are shell bug IDs as used by the Modernish shell library. 2024-08-01: - Release 1.0.10 -- exactly two years after 1.0.0 and twelve years after 93u+. 2024-07-31: - Fixed a bug where printf %T, after having printed the time in UTC once with the TZ variable set to "UTC", would always print the time in UTC from then on, even if the TZ variable was changed to another time zone. Bug introduced in ksh 93t+ 2009-10-21. 2024-07-26: - Fixed a regression where a broken pipe signal (SIGPIPE), when occurring in a pipe construct within a subshell, caused incorrect signal handling in the parent/main shell, in some cases causing a script to abort. Bug introduced on 2022-07-02. - Fixed a bug in the pipefail shell option where the status of a signalled non-rightmost process in a pipeline was just the signal number, instead of that number + 256. Bug introduced in ksh 93u+ 2011-04-15. 2024-07-24: - Fixed a serious bug in the arithmetic subsystem that was triggered on non-Intel processors (such as ARM): any division of an integer by a negative integer threw a spurious "divide by zero" error. Bug introduced in ksh 93q 2005-01-31. - Similarly fixed: the return value of the assignment of a negative value to an unsigned integer in an arithmetic expression was always 0 on ARM processors (instead of being equal to the assigned wrapped-around value). Bug introduced by the discipline fix on 2024-01-21. 2024-07-21: - Fixed a long-standing parsing bug: a '((' that was unmatched by corresponding closing parentheses and enclosed within a compound command failed to throw a syntax error and could cause the shell to crash. 2024-07-18: - Fixed a regression where 'read' cannot create a previously nonexistent variable when used within a namespace block. Bug introduced on 2023-06-02. 2024-07-17: - Fixed: if the --posix or --letoctal option was turned on, octal numbers designated by the leading-zero octal prefix enabled by these options but containing the invalid digits 8 or 9 (e.g., $((09)) or let "09") failed to throw an error and were instead incorrectly reinterpreted as decimal. - Fixed: invalid leading zeros in the '0x' hexadecimal prefix or in ksh arithmetic base specifiers, e.g., 00x2F or 016#2F (instead of 0x2F or 16#2F), failed to throw an arithmetic syntax error. 2024-07-16: - The history expansion character ('!' by default) is now not processed when immediately following '${'. This makes it psosible to use expansion syntax like ${!varname} and ${!prefix@} on the interactive command line with the histexpand option on; these no longer trigger an "event not found" error. 2024-07-13: - The shell is now capable of handling more than 32767 simultaneous background jobs, subject to system limitations. 2024-07-02: - Release 1.0.9. - Support for UNC paths (//server/dir) is now enabled by default on Cygwin. 2024-06-30: - Fixed: the 'hash' and 'alias -t' commands no longer autoload functions from executable files on FPATH as an unintended side effect. 2024-06-27: - Fixed: a builtin activated with the 'builtin' command was not found if invoked within a namespace block on the same line as the 'builtin' command. 2024-06-26: - Fixed: when the --showme option was used with a command containing multiple redirections, only the first redirection was shown, without a newline. This bug was introduced along with --showme in ksh 93s- 2006-09-12. 2024-03-05: - Fixed a corner case bug causing incorrect field splitting behaviour of a repeated whitespace character in the IFS variable. The behaviour was incorrect when the posix option was changed while xtrace was on, or when a shell discipline function was defined for IFS. Bug introduced on 2022-03-05. 2024-03-03: - Fixed incorrect behaviour of {n1..n2..incr} range brace expansions, which sometimes occurred if the value of n1 multiplied by incr falls outside of the INT_MIN..INT_MAX range. For instance, {1696512000..1696512000..300} now correctly outputs only 1696512000. 2024-03-30: - A regression was fixed in ordinal specifiers in 'printf %T' date specifications. For example, printf '%(%F)T\n' '4th tuesday in march 2016' wrongly printed '2016-04-09' and now again correctly prints '2016-03-22'. This regression was introduded with the printf fixes on 2023-05-18. 2024-03-24: - We now support building a dynamically linked ksh 93u+m with libast, libdll, libcmd, and libshell available as dynamic libraries for other applications to use. The dynamically linked version is built in a 'dyn' subdirectory; there are no changes to the statically linked version. See README.md for more information. Dynamic linking is tested and supported on Linux, Android, macOS, FreeBSD, NetBSD, OpenBSD, illumos and Solaris. Please test this on other platforms and send us your reports and patches. 2024-03-22: - Fixed a crash in the getconf built-in that could occur after the 'builtin' command was used to bind it to the same path as the external getconf command. 2024-03-20: - Android with Termux is now a supported environment for ksh 93u+m. Testing was done on Android 14.0 with Termux 0.118.0. Please report any breakage. Build dependencies (Termux packages): clang, binutils, getconf. Runtime depenencies: ncurses-utils (for --multiline), getconf (fallback for the /opt/ast/bin/getconf builtin). 2024-03-12: - Fixed a regression in the 'printf' built-in, introduced on 2023-05-17, where each instance of '\0' or '%Z' in the format operand caused a string argument to be incorrectly skipped. 2024-03-10: - Fixed a longstanding bug where the default terminal width for typeset -L, -R, or -Z, if not given, was miscalculated for multibyte or control characters. - Fixed a crash on redefining an array inherited from the parent environment in a subshell. - Fixed corner case breakage of universe handling in the 'echo' command: it broke when used in a namespace block before being used anywhere else, and only if _AST_FEATURES was not exported first. The bug caused _AST_FEATURES to be incorrectly placed in that namespace. Bug introduced on 2023-06-02. 2024-03-07: - Fixed a bug that caused some systems to corrupt the display of multibyte characters in the command prompt. 2024-03-05: - Fixed a regression, introduced on 2021-02-07, that made the common AST options '--???ESC' and '--???noESC' ineffective for enabling/disabling ANSI escape codes for emphasis in the output of --man or --help. (Type, e.g., print '--???' for more information about common options.) - Fixed a rare crash in the 'print' built-in due to the use of uninitialised memory while parsing options. Bug introduced in ksh 93u+ 2012-05-31. - Fixed a 2021-04-14 regression: the 'exec' command (which runs a command that replaces the shell process and therefore should only run external commands) would run a path-bound built-in if /opt/ast/bin is in PATH. - Fixed a corner case bug: a ${ shared-state command substitution;} failed to capture the standard output of a command that replces the shell via 'exec'. 2024-02-29: - Improved the robustness of the routines handling the execution by ksh of a script without an initial #! path. More memory is freed up after ksh forks. - Fixed a crash that could occur after 'typeset +x var' when var was imported from the environment and then a discipline function was set for it. 2024-02-22: - Fixed a crash that occurred when starting ksh with no TERM variable in the environment (e.g., in single user mode on NetBSD and DragonFlyBSD). - Fixed a regression of 'return' within traps, reintroduced on 2023-12-25 after being fixed on 2020-09-09. The regression caused a 'return' or 'exit' with no arguments to assume the before-trap exit status instead of that of the last-run command. This broke the shipped 'autocd' function. - Fixed some integer overflows that could occur when using TMOUT. - Fixed a crash on Solaris and illumos when cancelling a here-document with ^C or ^D in an interactive shell. 2024-02-17: - Fixed a crash that could occur when using 'typeset -T' typed variables in a virtual subshell. 2024-02-11: - Added SHOPT_PRINTF_LEGACY compile-time option for compatibility with POSIX-ignorant external printf(1) commands that process a format operand starting with '-' without the standard preceding '--' options terminator. This is for backward compatibility with local system scripts. The behaviour of the system's external printf(1) determines whether this is compiled in or out by default. Normal ksh printf options keep working. - Fixed a bug, introduced on 2023-06-02, that made it impossible within a namespace to unset a function defined outside the namespace. - Fixed: ksh didn't pass the exit status of the last command it executed to the parent process on entering EOF (Ctrl+D) on a terminal. 2024-02-09: - Fixed multiple inaccurate or missing values in the /opt/ast/bin/getconf path-bound built-in command. 2024-02-08: - Fixed an init-time crash that may occur if standard error is on a terminal, but the path to its tty device can't be found (e.g., in a chroot situation). - Fixed corrupted output of the 'time' keyword as formatted via TIMEFORMAT on systems where sizeof(time_t) != sizeof(int). Bug introduced on 2020-07-13. 2024-02-06: - Fixed a regression introduced on 2023-03-04 that caused ksh to lock up after using the Arch Linux arch-chroot script. 2024-02-03: - Fixed: the arithmetic representation of negative integers with a base other than 10 is no longer incorrectly treated as unsigned long. For example, typeset -i16 n=-12; echo $n now correctly outputs '-16#c' and no longer ouputs '16#fffffffffffffff4'. 2024-01-27: - Fixed: tilde expansion discipline functions (see 2021-03-16) were not reinitialised when executing a ksh script without a #! path line. 2024-01-23: - Fixed a rare crash or rare incorrect behaviour in .sh.tilde.{get,set} discipline functions for ~ expansion (see 2021-03-16 below). - Fixed a bug that caused listing the .sh.match variable with ${!.sh.match} to show spurious elements. 2024-01-22: - Fixed a bug in the loop invariants optimizer (SHOPT_OPTIMIZE) that caused expansions of name references to be incorrectly treated as invariant so they yielded the wrong values. Fix backported from from ksh 93v- 2013-02-13. - Fixed a buffer overflow that could occur when using tab completion with multibyte filenames. 2024-01-21: - A bug was fixed that caused both the 'set' and 'get'/'getn' discipline functions of a variable to be triggered when performing an assignment in an arithmetic expression; only the 'set' discipline is now triggered when assigning (as was always the documented behaviour). This applies to the shell's internal disciplines as well. For example, $RANDOM is no longer spuriously read from while seeding it via an arithmetic expression. - Fixed: assigning to LINENO, RANDOM, or _ via an arithmetic expression gave undefined results on systems where sizeof(long double)!=sizeof(double). 2024-01-16: - Fixed a parsing bug in array subscripts containing '=' in combination with a declaration command (such as 'typeset' or 'export'). For instance, 'typeset -A arr; typeset -i arr[foo=bar]=123' now works correctly. 2024-01-15: - Fixed a bug, introduced in ksh93q+ 2005-05-22, that stopped an append assignment from working together with a declaration command. For example, 'typeset var+=value' or 'export var+=value' now again work as expected. 2024-01-14: - Fixed a regression introduced on 2022-11-01 that caused ksh to enter an infinite loop after using the up arrow in emacs mode with an empty history file. - Fixed a bug in 'read -s': in a script, the first invocation of that command, with the emacs or vi shell option on, did not allow the user to navigate through the shell history file. 2024-01-11: - Fixed ancient incorrect behaviour in the 'kill' built-in: it sent SIGCONT to the given process along with every other non-SIGCONT signal issued, causing a stopped process to be incorrectly resumed upon sending it any signal and causing any SIGCONT trap handler to be incorrectly triggered. - Fixed: the 'kill' built-in was not able to terminate an interactive shell by sending a signal such as SIGHUP to its own shell (e.g. kill -s HUP $$). 2024-01-05: - Fixed a potential crash on pressing Ctrl+C on the command line while history expansion (the -H or histexpand option) is active. 2024-01-01: - Release 1.0.8. 2023-12-28: - Fixed intermittent incorrect behaviour (a race condition), introduced on 2023-09-15, that occurred on some systems when running an external command with a redirection from a command substitution. - Fixed an init-time crash on failure to trim the shell command history file due to a non-writable parent directory; ksh now prints a warning instead. 2023-12-25: - Fixed a regression in the behavior of 'exit' in a trap action, introduced on 2020-09-09. The default exit status, used when no argument is given to 'exit', is now once again the exit status of the last command executed *before* the trap action, as expected. 2023-09-16: - The 'kill' built-in command was meant to refuse to issue SIGSTOP to the shell's process if the shell is a login shell (because this normally causes an unrecoverable freeze of the terminal session). The code prohibiting this did not work on modern systems and is now fixed. 2023-09-15: - Release 1.0.7. - Fixed a hang in command substitutions (introduced in 93u+m/1.0.0) that was triggered when redirecting standard output within a command substitution, in combination with other factors. E.g., the following no longer hangs: { v=$(redirect 2>&1 1>&9); } 9>&1 2023-09-13: - Fixed a crash on trying to append an indexed array value to an unset name reference, e.g.: nameref unsetref; unsetref+=(foo bar). This now produces a "removing nameref attribute" warning before performing the assignment. - Fixed: assignments like name=(...) to arrays did not preserve the array and variable types. Fix backported from ksh 93v- beta (2013-07-19, 2013-07-27). - Fixed: assigning an empty set () to a compound indexed array caused the -C attribute to be lost. Fix backported from ksh 93v- beta (2013-09-13). 2023-09-09: - Fixed incorrect rejection of the tab key while reading input using the `read` built-in command. Bugs introduced on 2021-02-26 (emacs) and 2022-08-24 (vi). - Fixed a minor bug that could cause '/opt/ast/bin/getconf PID_MAX' to return the wrong value when ksh is built with strict C99. - Fixed a bug in printf %T: when using dates and times in the past, time zones for the present were incorrectly used, ignoring historical changes. 2023-06-13: - Release 1.0.6. - Fixed a serious regression in pathname expansion where quoted wildcard characters were incorrectly expanded if a pattern contains both a brace expansion and a variable expansion. 2023-06-12: - Fixed a bug where ^X^E in emacs or 'v' in vi, which invoke a full-screen editor to edit the command line, could cause the wrong command line to be edited if two shell sessions share a .sh_history file. - In the emacs line editor, ^X^E no longer echos the hist command it invokes. 2023-06-10: - Ksh can now compile on most operating systems when using -std=c99 in CCFLAGS. 2023-06-09: - Fixed a bug where the 'break' and 'continue' commands stopped working after changing scope levels (.sh.level=n) within a loop invoked from a DEBUG trap. 2023-06-07: - Release 1.0.5. 2023-06-05: - Fixed a bug in command completion: when a shell built-in or defined function was preceded in alphabetical order by an undefined function (on FPATH or after 'autoload'), the built-in or defined function failed to tab-complete. 2023-06-04: - Fixed a bug in 'case', introduced in ksh 93t 2008-10-31, where extended patterns containing a closing brace ('}') caused a spurious syntax error. - The POSIX mode was amended to make 'test -e /dev/fd/n' (where n is a file descriptor number) actually test for the existence of /dev/fd/n in the file system. By default it tests if that file descriptor is open. 2023-06-02: - Fixed a bug introduced on 2021-04-24 where unsetting a function in a subshell hides any built-in command by the same name for the duration of that subshell. 2023-05-30: - Fixed a bug in the 'type -t'/'whence -t' output for an undefined function. - The autoloadable directory stack and menu-based cd functions in the 'fun' directory have been reorganised and fixed to play well together when that directory is added to FPATH. 2023-05-29: - Fixed a bug in bracket expressions in glob patterns where quoting a '!' (e.g., to disable its negator function) caused a '\' to be wrongly matched. For example, case '\' in ['!'X]) echo BAD;; esac no longer outputs BAD, and touch '\'; ls ['!'X] no longer incorrectly lists the file '\'. 2023-05-28: - Fixed a bug, introduced on 2020-06-08 and exacerbated on 2022-07-02, where the exit status of a script did not reflect the signal with the 9th bit set if the script exited on receiving a signal and an EXIT trap was set. 2023-05-27: - Fixed a bug in the handling of backslashes in pathname expansion patterns resulting from field splitting. For example, the following: $ mkdir testdir; cd testdir; touch b; p='[a\-c]'; echo $p now correctly recognises the backslash escape and no longer outputs 'b'. - The 2023-05-19 fix for brace expansion interfering with extended patterns has been improved to also recognise and handle extended patterns that are parts of larger patterns, e.g., 'ls file~(E)[[:digit:]]{3,6}\.txt$' now works. 2023-05-19: - Fixed a bug in the loop invariants optimizer where a variable for which a .get or .getn discipline function is set within a loop is incorrectly treated as invariant. - Fixed two bugs in pathname expansion: 1. Brace expansion interfered with EREs and other extended pattern types used with ~(...) pattern option prefixes, e.g. the {3,6} in 'ls ~(E)^file[[:digit:]]{3,6}\.txt$' was incorrectly parsed as a brace expansion instead of an ERE bound matching 3 to 6 digits. That command will now list any matching files such as file1234.txt. 2. With brace expansion disabled (set +B), any '{' character in a file name pattern stopped it from being resolved unless a wildcard followed it. Now, 'set +B; ls *{' will list files with names ending in '{'. 2023-05-18: - Fixed multiple bugs causing incorrect output for relative date specifications given as arguments to printf %(dateformat)T. For example, something like printf '%(%Y-%m-%d %H:%M)T\n' 'exact 9 weeks ago' will now produce the correct output, which is the same as GNU date: date '+%Y-%m-%d %H:%M' '9 weeks ago' - In the ${parameter/pattern/string} search-and-replace expansion, an anchored empty pattern will now match the beginning or the end of the string, so that ${parameter/#/string} will prefix the string to the parameter value and ${parameter/%/string} will append it. Previously, these operations were no-ops (equivalent to ${parameter}). This change brings ksh 93u+m into line with mksh, zsh and bash. 2023-05-17: - Fixed buggy behaviour of printf with mix and match of % and %x$. 2023-05-15: - Fixed a crash on executing a nested compound assignment in a command substitution. 2023-05-14: - If history expansion is active, then command and file name completion now quotes the history expansion characters with a backslash as needed to avoid triggering history expansion failures if one of those characters occurs in a command or file name. - Fixed completion of file names starting with an escaped literal tilde. - Undocumented and non-functional goto label functionality has been removed. Command names can now end in ':' like on other shells, as POSIX requires. 2023-05-11: - The ability to use multi-line editing is now detected at runtime instead of compile time, making detection more reliable across terminals and platforms. 2023-05-01: - Fixes for indexed arrays declared to use enum constants for subscripts: - Syntax validation: add missing check for ] in 'typeset -a \[type] array'. - Fixed error message when type in 'typeset -a \[type] array' is unknown. - Fixed 'typeset -p' output of such arrays to quote the square brackets. 2023-04-09: - Fixed command line redrawing on resizing the window with --multiline off. - Multiline editing is now automatically disabled if and when the TERM environment variable is unset, not exported, or set to a terminal type that does not support the necessary operations. It is automatically re-enabled when the TERM variable is corrected and --multiline is on. 2023-04-08: - Fixed a termcap(5) detection bug that broke multiline editing on FreeBSD. 2023-04-05: - Fixed a spurious syntax error in compound assignments upon encountering a pair of repeated opening parentheses '(('. This bug behaved differently depending on whether the compound assignment was outside or within a command substitution of the form $(...) or ${ ...; }. Both cases are now fixed. - Fixed a parsing bug in arithmetic functions like function .sh.math.add x y { .sh.value=x+y; } so that the '.sh.value=x+y' is correctly interpreted as an assignment, not as a command name. After this, (( z = add(x,y) )) works correctly. 2023-04-03: - Fixed multiple crashing bugs in discipline functions invoked from non-forked subshells, including corruption of the $_ variable. 2023-04-02: - Corrected the 2022-07-05 fix for the detection of a syntax error in compound assignments to associative arrays. - Fixed spurious syntax error in ${parameter:offset:length}: the arithmetic expressions 'offset' and 'length' may now contain the operators ( ) & |. 2023-03-29: - Fixed a bug in 'printf -v' (added on 2021-11-18) where using the %B format specifier would overwrite any data already written to the variable. 2023-03-26: - Fixed an intermittent crash in 'command -x' experienced on some arm/arm64 systems running Linux. - Fixed a bug that caused 'printf "%(%Z)T\n" now' to print nonsense strings such as 'ica' on Cygwin. 2023-03-24: - Fixed a crash in read -d D in multibyte locales that occurred when a byte with the 8th bit set was passed as the delimiter character D. For example, read -d $'\200' crashed in a UTF-8 locale. (Note that multibyte delimiter characters are not supported yet.) 2023-03-23: - A bug has been fixed in 'printf' and 'print -f' that caused the %a, %A, %e, %E, %f, %F, %g, and %G conversion specifiers to evaluate any unexpanded arithmetic expression passed to them twice, causing any side effects, such as incrementing a variable, to be incorrect. Bug introduced in 93t- (2008). - The POSIX compatibility mode has been amended to cause 'printf' to parse only decimal/hexadecimal/octal constants for its numerical conversion specifiers, instead of arithmetic expressions. (POSIX mode does not change 'print -f'.) 2023-03-20: - Fixed incorrect result of array slicing ${array[@]:offset:length} where 'length' is a nested expansion involving an array. For example, ${array[@]:0:${#array[@]}} is now correctly equivalent to ${array[@]}. - Fixed bugs in 'command -x' and 'command -v -x' (see 2021-01-30) that caused it to fail to disregard built-ins if /opt/ast/bin (the virtual path for path-bound built-ins) is in $PATH. 2023-03-19: - Fixed a crash in 'read' (as well as a spurious error in 'printf -v', added on 2021-11-18) when using an indexed array subscript with an arithmetic expression that yields 0 while also modifying the variable. For example, 'i=-1; read a[i+=1]' crashed. Bug introduced in ksh 93s+ 2008-01-31. - In the 'read' built-in, a '=' in a variable name argument is now once again an error and is no longer misparsed as an assignment, which caused inconsistent behaviour or (in the case of 'read -C foo=bar') a crash. This fixes a bug introduced in ksh 93u+ 2011-04-28. 2023-03-17: - Fixed nameref self-reference loop detection; as of ksh 93u 2010-11-22, this failed for loops of more than two refs. For example, 'nameref a=b b=c c=a' now correctly outputs an 'invalid self reference' error message. 2023-03-16: - Backported a fix from ksh 93v- beta for a bug in the 'for' loop optimizer which could falsely treat 'typeset -b' variables as loop invariants. 2023-03-04: - Fixed a bug introduced on 2022-02-08 that caused string translation using $"..." to either crash or fail silently. 2023-03-03: - A new SHOPT_SCRIPTONLY compile-time option was added that, if enabled, compiles out the interactive shell, resulting in a ksh binary that can only run scripts. See src/cmd/ksh93/README for more information. 2023-02-23: - Fixed a crash or corrupted output that occurred on some systems if the vi '.' repeater command was used immediately after starting ksh in vi mode. - In vi mode, when navigating back in the command history and then editing a line from the history, the U command now correctly undoes the latest edit to the history line instead of jumping back to the current command line. - In vi mode, issuing the v command from a completely empty line now invokes the full editor with an empty file instead of beeping. - Fixed a bug in vi mode where the v command from a line with only whitespace resulted in an "invalid range" hist error and the editor failed to open. - Fixed a bug in emacs mode where calling the full editor saved the current command line to the history file without a terminating newline. - Fixed a bug in emacs and vi modes where navigating to a null or empty history line displays an empty line onscreen. - Fixed a bug in emacs and vi modes where attempting to tab-complete an alias or $PATH item containing wide characters failed before the first normal-width character had been entered. 2023-02-22: - ksh now throws a panic and exits if a read error (such as an I/O error) occurs while trying to read the next command(s) from a running script. Previously, ksh acted as if EOF was reached, and the script ended normally. - The '.' and 'source' commands now throw an error if a dot script can be only partially read, instead of ignoring the error. As ksh reads the entire dot script before running it, no part of the script is executed in that case. 2023-02-20: - The SHOPT_RAWONLY compile-time has been removed. Ksh's vi editor now always operates in raw mode (but note that "raw only" was already the default compiled-in behaviour as of 93m+ 2002-03-17). 2023-02-16: - Fixed a bug in 'cd' with no arguments. When changing the working directory to the default value ($HOME), it incorrectly used the global scope of the HOME variable even if a local scope was active. 2023-01-09: - Fixed a bug causing incorrect greedy ${.sh.match} results when matching the pattern [^]] in a non-ASCII locale. - Fixed a crash on initialisation that occurred if ksh was launched from a parent process with a very high or very low open files limit (ulimit -n). 2023-01-08: - Fixed a completion bug in vi mode in multibyte character locales, in which one or more invalid characters were output at the end of the completion if the cursor was on a "wide" character (or if the last character of the word is wide and the cursor is in the immediately-following position). - Fixed a bug in vi and emacs in which using = or * completion from within a word failed to replace the word; any trailing characters were printed at the end of the completion. (Bolsky and Korn, pp. 105-106 and 114-115) 2022-10-22: - Release 1.0.4. 2022-10-18: - Fixed the expansion of out-of-range \n back references in the string part of ${parameter//pattern/string}. For example: v=AB; echo "${v/@(A)B/\0:\1:\2}" now yields 'AB:A:' instead of 'AB:A:\2'. - Fixed a corner case regression in the BUG_IFSGLOBS fix applied on 2022-07-28: unquoted $* was affected. The fix now properly applies only to quoted "$*". 2022-10-14: - Fixed: the generic --version option was not recognised for the built-in commands ., bg, disown, fc, fg, hist, jobs, let, source, times, and ulimit. - Fixed a bug introduced by the 2022-10-07 BUG_BRACQUOT fix, which caused the fallback string in an expansion like ${emptyvar:-fallback string} to fail to split into fields correctly if the fallback string contained a !, ^ or -. - Fixed a few different build errors on Haiku that prevented ksh from compiling with the mkservice and eloop builtins enabled, caused compiling with -lnetwork to fail, and could interrupt the build with crash report popups. 2022-10-13: - Added a -V/--novmon option to ulimit that supports setting the number of open vnodes (only applies to Haiku). - Fixed a bug on Haiku that caused the ulimit command to print '(null)' in the error string when 'ulimit -t' fails. - 'ulimit -a' no longer exits immediately after an error occurs when failing to get the current limits for cpu time and file size on Haiku. 2022-10-11: - Fixed a bug that caused inconsistent behavior when handling a dangling backslash in a case statement. 2022-10-07: - Fixed BUG_BRACQUOT: single and double shell quotes did not work to escape the !, ^ or - operators in a bracket expression within a glob pattern. - The -e option of test/[/[[ no longer returns true for pseudodevices that are only supported by the shell and do not in fact exist in the file system, such as /dev/tcp/*. This reverts a change made in ksh 93u- on 2010-08-24. 2022-09-28: - Fixed a bug where LINENO was reset to 1 after being temporarily changed in an assignment preceding a regular command (e.g. LINENO=5 true). 2022-09-27: - Fixed a parsing bug in (uncommonly used) function definitions of the form 'functname() simple_command' that could cause the first word of simple_command to be corrupted with trailing garbage. 2022-09-25: - Backported support for 'print -u p' from ksh93v- 2014-06-06 (this is equivalent to using 'print -p'). - Fixed a bug introduced on 2021-04-04 that incorrectly allowed 'typeset' to turn off the readonly and export attributes on a readonly variable. - Fixed multiple scoping-related bugs in the += additive assignment operator, including a bug introduced on 2021-04-11 that caused it to append to the value of a global variable when used on a local variable with the same name. 2022-09-24: - In the emacs line editor, the Ctrl+R reverse-search prompt is now visually distinct from a literal control character ("^R: " instead of "^R"). - Fixed a crashing bug involving incorrect data alignment in variables of types defined by 'typeset -T'. 2022-09-11: - Fixed a bug introduced in ksh93u+ 2012-04-23 that caused LINENO to have the wrong value after parsing a multi-line compound assignment. - Fixed a bug in vi mode that caused reverse search to remain active after receiving an interrupt. 2022-09-01: - Fixed a bug where 'command -x' would create a tracked alias for a command, causing 'whence' not to find an /opt/ast/bin built-in command correctly. 2022-08-30: - In the vi line editor, 'C' and 'c$' at the start of a line now enter insert mode instead of beeping, and 'I' jumps to the first non-blank character on the line instead of the start of the line. These changes are consistent with standard vi(1) behavior and with Bolsky & Korn (1995, p. 121). - Aliases for many GNU long options have been added to the /opt/ast/bin built-in commands. Additionally, 'kill -s' now has a --signal long option alias compatible with the util-linux option. - All of the /opt/ast/bin built-ins available in src/lib/libcmd (excluding vmstate if vmalloc isn't enabled) can now be enabled with the new SHOPT_ALL_LIBCMD setting in src/cmd/ksh93/SHOPT.sh. 2022-08-25: - Release 1.0.3. - In the vi line editor, a bug was fixed that caused erratic behaviour after using the 0 or ^ commands when already at the beginning of the command line. 2022-08-24: - Fixed a bug that caused ksh in the vi editor mode to crash or produce invalid completions if ESC = was used at the beginning of a line. Both tab and = completions are now disabled at the start of the command line. - Fixed ksh freezing or using excessive memory if HISTSIZE is assigned a pathologically large value. A new bounds check makes the theoretical maximum number of history lines equal to the number of bytes kept in the history file at cleanup time. On 64-bit systems, that maximum is 16384. 2022-08-20: - Fixed a bug in command line options processing that caused short-form option equivalents on some built-in commands to be ignored after one use, e.g., the new read -a equivalent of read -A (introduced on 2022-02-16). - Fixed a bug in the /opt/ast/bin/cp built-in command that caused the -r and -R options to sometimes ignore -P, -L and -H. Additionally, the -r and -R options no longer follow symlinks by default. 2022-08-16: - Fixed an old bug in history expansion (set -H) where any use of the history comment character caused processing to be aborted as if it were an invalid history expansion. (On 2022-01-24 the history comment character was set to '#' instead of being disabled by default, which exposed this bug.) - Fixed a bug introduced on 2022-02-12 that would cause the optional head builtin's -s option to fail. 2022-08-08: - Release 1.0.2. 2022-08-06: - Fixed an interactive shell crashing on redefining, then unsetting one of the predefined aliases. - Fixed an interactive shell crashing on redefining one of the predefined aliases, then executing a shell script that does not start with a #! path. 2022-08-05: - Reverted a buggy exec optimisation introduced on 2022-06-18. It is known to make the build scripts of GNU binutils produce corrupted results. - Release 1.0.1. 2022-08-01: _ _ ___ _____ ___ ___ ___ | | _____| |__ / _ \___ / _ _ _ _ __ ___ / / | / _ \ / _ \ | |/ / __| '_ \ | (_) ||_ \| | | |_| |_| '_ ` _ \ / /| || | | | | | | | <\__ \ | | | \__, |__) | |_| |_ _| | | | | |/ / | || |_| | |_| | |_|\_\___/_| |_| /_/____/ \__,_| |_| |_| |_| |_/_/ |_(_)___(_)___/ - Exactly ten years after ksh 93u+ 2012-08-01, we now have a new ksh release. Many thanks to all the direct and indirect contributors for their hard work! 2022-07-28: - Fixed BUG_IFSGLOBS ("$*" does pattern matching if the first character of $IFS is a wildcard). 2022-07-27: - Fixed a bug introduced on 2022-02-08 where $PPID was incorrect when a script without a #! path was executed. - Fixed a completion bug in the vi line editor. It now correctly completes the sole member of a directory when tab is pressed immediately after /. Thanks to K. Eugene Carlson for the report and the fix. 2022-07-26: - Fixed incorrect handling of initial zeros in test/[ and [[ arithmetic comparison operators. For example, [[ 0x0A -eq 10 ]] yielded false but [[ 1+0x0A -eq 11 ]] yielded true. - Fixed comparing long floating point (typeset -lF) values in test/[ and [[; the values were reduced to standard floating point before comparing. 2022-07-25: - Release candidate: ksh 93u+m/1.0.0-rc.1. 2722-07-24: - Add new 'man' function in src/cmd/ksh93/fun/man. This integrates the --man self-documentation of ksh built-in and external AST commands with your system's 'man' command so you can conveniently use 'man' for all commands, whether built-in or external. To use this, put the file in a directory in your $FPATH and then issue 'autoload man' in your .kshrc to override the system's man(1) command. See the file for details. - Add new 'autocd' function in src/cmd/ksh93/fun/autocd. This activates a feature like 'shopt -s autocd' in bash: type only a directory name to change. See the file for details. Add this file to a directory in your $FPATH to use. - New feature to make 'set -b'/'set -o notify' more usable. When that option is on (and either the vi or emacs/gmacs line editor is in use), 'Done' and similar notifications from completed background jobs no longer mess up the command line you're typing. Instead, the notification is inserted directly above the line you're typing, without affecting your command line display. - Fixed a bug that caused the -b/--notify option to only notify on one job if more than one background job completed at the same time. - Fixed a bug in the 'command -x' feature introduced on 2021-01-30; it is meant to always run an external command, but failed to bypass path-bound builtins. 2022-07-21: - Fixed a bug where a reproducible $RANDOM sequence (after assigning a specific value to $RANDOM) was influenced by running any external command. - When an error occurs in a POSIX name() function or a dot script, the function or script name is now reported in the error message. 2022-07-14: - Fixed a bug that caused a spurious "Done" message on the interactive shell when an external command was run as a foreground job from a SIGINT trap. 2022-07-12: - The .sh.level variable can now only be changed within a DEBUG trap. When trap execution ends, the variable and the scope are now restored. These changes disallow an inconsistent shell scoping state causing instability. 2022-07-10: - Fixed a potential crash on retrieving an empty line from the command history. - Fixed a potential crash in the lexical analyser on processing single-byte characters with the highest bit set. 2022-07-09: - Fixed a bug that broke '[[ ... ]]' test expressions for the command following a syntax error in an associative array assignment. 2022-07-05: - Fixed a spurious syntax error on encountering a process substitution following a redirection without being an argument to a redirection. For example, this now writes 'OK' to standard error: cat >&2 <(echo OK) - Fixed the detection of a syntax error in compound assignments to associative arrays. 2022-07-02: - Fixed a bug where, if the last command in a subshell was an external command that was terminated by a signal, the exit status ($?) of the subshell did not reflect this by adding 256 to the signal number. - Fixed a bug that caused signal traps to be ignored if the shell was signalled from a subshell that is the last command in the script. 2022-07-01: - In scripts, $COLUMNS and $LINES are now kept up to date in scripts at initialization and when the window size changes (previously, this required setting a dummy trap for the SIGWINCH signal in the script). 2022-06-28: - Fixed a bug that caused the <#((num)) or >#((num)) arithmetic seek redirection operator to fail if used with file descriptor 0, 1 or 2 connected to a block device. 2022-06-22: - Fixed: 'echo' failed when used inside a command substitution that is inside a nested compound assignment. - Fixed a crash in KEYBD trap handling introduced on 2021-11-29. 2022-06-20: - Fixed a race condition that could cause redirections to fail with a "cannot create" or "cannot open" error while processing a signal trap. 2022-06-18: - Fixed a bug where, with the monitor or pipefail option on, the shell failed to wait for all component commands in a pipeline to terminate if the last component command was an external command and the pipeline was the last command in a background subshell. - When any trap except DEBUG, KILL or STOP is set to a non-empty command, the last command in a script or forked subshell will no longer avoid forking before executing; this optimization incorrectly bypassed the traps. 2022-06-15: - Fixed a bug where converting an indexed array into an associative array in a subshell failed, resulting in an empty associative array. 2022-06-13: - Trapping a signal that is not a pseudosignal will now cause a virtual subshell to fork into a real one. This ensures a persistent PID where other processes can signal the subshell (the PID of a virtual subshell may change as other commands cause it to fork), and fixes a bug where a signal could not be correctly or effectively trapped in a subshell if the same signal was also trapped in the main shell environment. 2022-06-12: - The POSIX mode now disables zero-padding of seconds in 'time'/'times' output. 2022-06-09: - The POSIX mode has been amended to use a UNIX pipe(2) instead of a socketpair(2) to connect commands in a pipeline, as the standard requires. (When reading directly from a pipeline in posix mode, the <#pattern and <##pattern redirection operators will not work and the -n option to the read built-in will not return early when reading from a slow device.) - An interactive shell initialized in POSIX mode now once again has the preset aliases defined. This amends a change made on 2020-09-11. - If a long-form shell option name is abbreviated so it matches multiple options, the error message from ksh or 'set' now reads "ambiguous option". 2022-06-08: - If -B/--braceexpand is turned on in --posix mode, it now only allows brace expansion on literal strings and not on the values of unquoted expansions. This behaviour is like bash and zsh, as well as compliant with a future version of the POSIX standard that may specify brace expansion: https://www.austingroupbugs.net/view.php?id=1193 2022-06-07: - Fixed a bug in 'typeset' where compound variables could acquire a spurious -x (export) attribute when printing their values, triggering other bugs. 2022-06-05: - Fixed a bug where tab completion would spuriously execute a command substitution after entering: '`something or generate a spurious 'end of file unexpected' syntax error after entering: '$(something. - Fixed bug where tab completion stopped working for arguments following a quoted string with an escaped backslash in the form $'foo\'bar'. 2022-06-04: - Added a new --functrace long-form shell option which causes the -x/--xtrace option's state and the DEBUG trap action to be inherited by function scopes instead of being reset to default. Changes made to them within a function scope still do not propagate back to the parent scope. Similarly, this option also causes the DEBUG trap action to be inherited by subshells. 2022-06-03: - Fixed a couple of bugs that caused floating point variables imported from a parent ksh through the environment to be corrupted. - Fixed a bug where invocation-local assignments preceding a built-in or external command or function call did not honour their pre-existing attributes set by typeset (such as -i or -F) in certain cases. 2022-06-01: - New 'typeset' feature inspired by bash (and zsh and mksh): the -g flag causes the specified variable(s) to be created globally, ignoring the local scope of ksh functions or name spaces. For example, this allows creating a global array or numeric variable from a ksh function. Thanks to @ormaaj for the feature suggestion and to @hyenias for testing. 2022-05-29: - Fixed a bug causing an inconsistent state after a special built-in command threw an error within a namespace. 2022-05-27: - Fixed a bug introduced on 2022-03-05 where 'set --default', while turning off the --posix option, did not re-enable the special handling of a repeated $IFS whitespace character as non-whitespace. 2022-05-25: - Fixed a bug introduced on 2021-02-20 that caused incorrect output for typeset -L/-R/-Z when the variable contained leading or trailing spaces. Thanks to George Lijo for the report and the fix. 2022-05-21: - Fixed a bug, present since the beginning of ksh93, that broke backslash line continuation within $(standard) and ${ shared-state; } command substitutions. Thanks to atheik for the analysis and the fix. (BUG_CSUBLNCONT) 2022-05-20: - Fixed an ancient bug that caused a spurious syntax error when using double quotes within a `backtick` command substitution within double quotes. Thanks to atheik for the analysis and the fix. (BUG_CSUBBTQUOT) 2022-03-10: - Fixed another corner case bug in the 'test'/'[' command. - A memory leak was fixed in the --man self-documentation options of built-in commands. 2022-03-05: - The 'enum' command can now create more than one type per invocation. - The POSIX compatibility mode has been amended to disable the special handling of a repeated $IFS whitespace character as non-whitespace. 2022-02-23: - When reading input from the keyboard, ksh now turns off nonblocking I/O mode for standard input if a previously ran program left it on, so that interactive programs that expect it to be off work properly. - Fixed a regression introduced on 2022-02-02 that caused interactive shells to enter an infinite loop when a command failed to execute on Linux systems with version 2.35 of glibc. - Fixed a SIGTTOU lockup that could cause ksh to freeze under strace(1) after a command failed to execute in an interactive shell. 2022-02-18: - Fixed a regression introduced on 2021-04-11 that caused the += operator in invocation-local assignments to crash the shell or modify variables outside of the invocation-local scope. 2022-02-17: - Fixed a crash, introduced on 2021-01-19, that occurred when using 'cd' in a subshell with the PWD variable unset. - Fixed a crash that could occur when or after entering the suspend character (Ctrl+Z) while the shell was blocked trying to write to a FIFO special file. 2022-02-16: - Backported minor additions to the 'read' built-in command from ksh 93v-: '-a' is now the same as '-A' and '-u p' is the same as '-p'. This is for compatibility with some 93v- or ksh2020 scripts. (Note that their change to the '-p' option to support both prompts and coprocess reads was not backported because we found it to be broken and unfixable.) 2022-02-15: - A bug was fixed in fast filescan loops (like 'while &- or <&- redirection could persist past a subshell in certain corner cases involving 'exec' or 'redirect'. 2022-02-08: - Multiple bugs were fixed in the method that ksh uses to execute a shell script without a #! path. Among other things, custom types and other changes in built-in commands will no longer affect the invoked script. The state of the 'posix' option is now inherited by the script. - To avoid an inconsistent state, the 'enum' and 'typeset -T' commands are no longer allowed to replace special built-in commands. For instance, 'enum trap=(a b c)' is now an error because 'trap' is a special built-in. The ability of 'typeset -T' to redefine a type is not affected. - A command like 'typeset -T foo_t' without any assignment no longer creates an incompletely defined 'foo_t' built-in command that will crash the shell when used. Instead, it is now silently ignored for backwards compatibility. - Compound arrays belonging to a type created with 'typeset -T' now have their -C attribute preserved in the output of 'typeset -p'. - A bug has been fixed in which the 'typeset -p' output of a two-dimensional sparse indexed array would cause the second subscript to be treated as an associative array when read back in by the shell. Elements that are sparse indexed arrays are now prefixed with "typeset -a". - The rewritten .sh.match code from ksh93v- has been backported to ksh93u+m, fixing many bugs and improving performance by a considerable amount. 2022-02-05: - Fixed: for indexed arrays, given an unset array member a[i] with i > 0, ${a[i]=value} failed to assign the value and ${v[i]?error} failed to throw an error. - Fixed: the -a/--allexport shell option incorrectly exported some variables with names containing a dot to the environment. Note that the '-x' typeset attribute may still be set for them, but this will now not have any effect. Variables created in namespaces declared with the 'namespace' keyword are only exported while their namespace is active. 2022-02-04: - Fixed a bug in 'typeset -p': for an indexed array variable that is set but empty, it will no longer output a nonexistent '[0]=' element. 2022-02-02: - Fixed the -a/allexport option to export all variables that are assigned values. Previously, arithmetic $((var=1)) or conditional ${var:=value} assignments were not exported even with allexport on. - Fixed a memory leak that could occur when using traps. - Fixed a use after free issue that could occur when modifying or setting a SIGCHLD trap. 2022-02-01: - Upon invocation, the interactive shell no longer leaves the user without a line editor if the VISUAL or EDITOR variable does not indicate emacs, gmacs or vi; instead, it now turns on the emacs option by default. 2022-01-31: - Improved keyboard support for the vi and emacs built-in line editors: - Added support for Home key sequences ^[[1~ and ^[[7~ as well as End key sequences ^[[4~ and ^[[8~. - Added support for arrow key sequences ^[OA, ^[OB, ^[OC and ^[OD. - Added support for the following keyboard shortcuts (if the platform supports the expected escape sequence): - Ctrl-Left Arrow: Go back one word - Alt-Left Arrow: Go back one word (Not supported on Haiku) - Ctrl-Right Arrow: Go forward one word - Alt-Right Arrow: Go forward one word (Not supported on Haiku) - Ctrl-G: Cancel reverse search - Ctrl-Delete: Delete next word (Not supported on Haiku) - Added a keybind for the Insert key, which differs in the emacs and vi editing modes: - In emacs mode, Insert escapes the next character. - In vi mode, Insert will switch the editor to insert mode (like in vim). - Fixed a bug in SIGINT handling: if a script ran an external command that interrupted itself (and only itself, not the process group) with SIGINT, the script that ran the command was also interrupted. 2022-01-28: - Fixed longstanding job control breakage that occurred on the interactive shell when suspending (Ctrl+Z) an external command invoked by a dot script or POSIX shell function, or via 'eval'. - Fixed a memory leak that occurred when running a command that was found on the PATH. 2022-01-26: - On Cygwin, ksh now executes scripts that do not have a #! path itself, like it does on other systems, instead of with /bin/sh. - Fixed a spurious syntax error which occurred when attempting to use array subscript expansion with unset variables (i.e., ${foo[${bar}..${baz}]}). 2022-01-24: - Fixed a crashing bug in history expansion that could occur when using the "&" modifier to repeat a substitution while there was no previous substitution. - History expansion is now documented in the ksh(1) manual page. - In history expansion, the history comment character '#' is now enabled by default, as it is on bash. - In history expansion, the 'a' modifier is now a synonym for 'g', as on bash. - Fixed a bug in history expansion where the 'p' modifier had no effect if the 'histverify' option is on. 2022-01-20: - Disallow out-of-range event numbers in history expansion (-H/-o histexpand). Previously these were accepted, resulting in corrupted expansions. - Fixed a potential crash in history expansion due to a buffer overflow. 2022-01-12: - Added bash-inspired --histreedit and --histverify options that modify history expansion (--histexpand), allowing editing on failure or before execution. 2022-01-04: - Fixed an issue in vi mode that caused tab completion to fail if the last character on the command line was a space. 2021-12-29: - Fixed numerous build errors that prevented ksh from running on Haiku OS. - Added support for the SIGKILLTHR signal on operating systems that implement it. 2021-12-28: - Fixed a bug that caused CDPATH to continue working after unsetting it. - Added three options to the ulimit builtin with the same names and functionality as in Bash: - 'ulimit -k' sets the maximum number of kqueues. - 'ulimit -P' sets the maximum number of pseudo-terminals. - 'ulimit -R' sets the maximum time in microseconds a real-time process can run before blocking. Note that to use these options the operating system must support the corresponding resource limit. - Ported performance optimizations from illumos to improve the performance of the cksum builtin. (Note that the cksum builtin is not enabled by default.) 2021-12-27: - Two bash-like flags for 'whence' were backported from ksh 93v-: - 'whence -P/type -P' is an alias to the existing -p flag. - 'whence -t/type -t' will print only the type of a command in a simple format that is designed to be easy to use for scripts. Example: $ type -t typeset; whence -t sh builtin file - Fixed a crash or freeze that would occur on Linux when using Ctrl+C to interrupt a command substitution containing a pipe in an interactive shell. - Fixed a crash that could occur while processing a here-document while xtrace (set -x) is on and the $PS4 prompt contains parameter expansions or command substitutions. - The mkservice and eloop builtins can now be built by enabling the new SHOPT_MKSERVICE setting in src/cmd/ksh93/SHOPT.sh. 2021-12-26: - Listing aliases or tracked aliases in a script no longer corrupts shcomp's generated bytecode. - Listing specific aliases with 'alias -p' and specific tracked aliases with 'alias -pt' now works as documented. This means that the following string of commands now works as you would expect: $ hash -r; unalias -a $ alias foo=bar; hash cat $ alias -p foo; alias -pt cat alias foo=bar alias -t cat - As a result of the above fix, listing all tracked aliases with 'alias -pt' now prints commands that can be reused to recreate the tracked aliases. - Attempting to list a non-existent alias or tracked alias with the -p option now causes an error and sets the exit status to the number of non-existent aliases passed. - Attempting to list 256 non-existent aliases now errors out with the exit status set to one. 2021-12-22: - Process substitutions run in a profile script no longer print their process ID when run. 2021-12-21: - Fixed a bug that caused subshells (such as code blocks in parentheses) to partially behave like the interactive main shell after running anything that invokes the parser. For example: $ (eval :; sleep 1 & echo done) [1] 30909 <--- incorrect job control output from subshell done - Fixed: after suspending (Ctrl+Z) a subshell that is running an external command, resuming the subshell with 'fg' failed and the job was lost. $ (vi) <--- press Ctrl+Z [2] + Stopped (vi) $ fg (vi) <--- vi failed to resume; immediate return to command line $ fg ksh: no such job 2021-12-17: - Release 1.0.0-beta.2. - Ksh no longer behaves badly when parsing a type definition command ('typeset -T' or 'enum') without executing it or when executing it in a subshell. Types can now safely be defined in subshells and defined conditionally as in 'if condition; then enum ...; fi'. - Single digits can now be compared lexically in [[ ... ]] with the < and > operators. 2021-12-16: - Changed the default selection of compiled-in /opt/ast/bin built-in libcmd commands to: basename, cat, cp, cut, dirname, getconf, ln, mktemp, mv. Add /opt/ast/bin to your $PATH to use these. Type 'cp --man', etc. for info. - A bug introduced on 2020-09-17 was fixed that caused interactive ksh to exit if Ctrl+C was pressed while SIGINT was being ignored (as in "trap '' INT"). 2021-12-13: - Fixed a bug introduced on 2020-08-09 that prevented '.' and '..' from being completed when using file name tab completion. - Fixed a bug on illumos that caused the chown builtin to fail with 'Invalid argument' after failing to change the ownership of a file twice using an ID that doesn't exist in /etc/passwd. (Note that the chown builtin is not enabled by default.) 2021-12-11: - Fixed two more crashing bugs that occurred if ksh received a signal (such as SIGINT due to Ctrl+C) while the user is entering a multi-line command substitution in an interactive shell. - The shell linter's warning for variable expansion in ((...)) now tells the user which variable is causing performance degradation. - The shell linter now warns the user x=$((expr)) is slower than ((x=expr)) when assigning a value to a variable. 2021-12-09: - Increased the general robustness of discipline function handling, fixing crashing bugs with PS2.get() and .sh.tilde.get() disciplines, among others. - Fixed a crash that occurred on the interactive shell if the PS1 prompt contains multiple command substitutions and the user interrupts input while the shell is on a PS2 prompt waiting for the user to complete a command substitution of the form $( ... ). 2021-12-08: - Fixed: if a function returned with a status > 256 using the 'return' command and the return value corresponded to a value that could have resulted from a signal, and an EXIT trap was active, then the shell mistakenly issued that signal to itself. Depending on the signal, this could cause the shell to terminate ungracefully, e.g. 'return 267' caused SIGSEGV ("memory fault"). - For the 'return' built-in command, you can now freely specify any return value that fits in a signed integer, typically a 32-bit value. Note that $? is truncated to 8 bits when the current (sub)shell exits. - The head and tail builtins now correctly handle files that do not have an ending newline. (Note that the tail builtin is not compiled in by default.) 2021-12-05: - Fixed an issue on illumos that caused some parameters in the getconf builtin to fail. - The cd built-in command now supports a -e option (as specified in https://www.austingroupbugs.net/view.php?id=253). Passing -e alongside -P is used to guarantee the cd built-in returns with exit status 1 if the current working directory couldn't be determined after successfully changing the directory. 2021-12-01: - Fixed a memory fault that occurred when a discipline function exited with an error from a special builtin or when a discipline function exited because of a signal. 2021-11-29: - Fixed a memory fault that prevented ksh from functioning on ARM-based Macs. - A bug that caused the time keyword to override the errexit shell option has been fixed. - Fixed a crash that could occur when a KEYBD trap was set and a multi-line command substitution was input in an interactive shell. - The shell linter's warnings for obsolete arithmetic operators in [[ ... ]] and unnecessary variable expansion in ((...)) have been improved. 2021-11-24: - The --posix mode was amended to stop the '.' command (but not 'source') from looking up functions defined with the 'function' keyword. In the POSIX standard and on other shells, the '.' command finds only script files. - The rm built-in's -d/--directory option has been fixed. It now properly removes empty directories and refuses to remove non-empty directories (as specified in https://www.austingroupbugs.net/view.php?id=802). Note that the rm built-in command isn't compiled in by default. 2021-11-23: - A bug was fixed that allowed arithmetic expressions to assign out-of-range values to variables of an enumeration type defined with the 'enum' command, causing undefined behavior. Within arithmetic expressions, enumeration values translate to index numbers from 0 to the number of elements minus 1. That range is now checked for. Decimal fractions are ignored. 2021-11-21: - It is now possible to use types defined by 'enum' in contexts where the script is entirely parsed before (or without) being executed, such as dotted/sourced scripts and scripts compiled by shcomp. - Added support for the size mode to the stty(1) built-in. This mode is used to display the terminal's number of rows and columns. Note that the stty built-in is not compiled in by default. This can be changed by adding stty to the table of built-ins in src/cmd/ksh93/data/builtins.c. 2021-11-20: - Listing types with 'typeset -T' no longer displays incomplete versions of types created by the enum built-in. 2021-11-18: - The printf built-in command now supports a -v option as on bash and zsh. This allows you to assign formatted output directly to a variable. - Fixed a performance regression introduced on 2021-05-03 that caused the shbench[*] fibonacci benchmark to run slower. [*]: https://github.com/ksh-community/shbench 2021-11-16: - By default, arithmetic expressions in ksh no longer interpret a number with a leading zero as octal in any context. Use 8#octalnumber instead. Before, ksh would arbitrarily recognize the leading octal zero in some contexts but not others, e.g., both of: $ x=010; echo "$((x)), $(($x))" $ set -o letoctal; x=010; let y=$x z=010; echo "$y, $z" would output '10, 8'. These now output '10, 10' and '8, 8', respectively. Arithmetic expressions now also behave identically within and outside ((...)) and $((...)). Setting the --posix compliance option turns on the recognition of the leading octal zero for all arithmetic contexts. 2021-11-15: - In arithmetic evaluation, the --posix compliance option now disables the special floating point constants Inf and NaN so that $((inf)) and $((nan)) refer to the variables by those names as the standard requires. (BUG_ARITHNAN) - Fixed two file descriptor leaks in the hist builtin that occurred when the -s flag ran a command or encountered an error. 2021-11-14: - Fixed: ksh crashed after unsetting .sh.match and then matching a pattern. - Another test/[ fix: "test \( string1 -a string2 \)" and "test \( string1 -o string2 \)" no longer give an incorrect "argument expected" error message. 2021-11-13: - The test/[ built-in command now supports the '<' and '=~' operators from [[. As of now, test/[ supports the same operators as [[ except for the different and/or operators. Note: test/[ remains deprecated due to its many pitfalls. - The test/[ built-in command is fixed so that the binary -a (and) and -o (or) operators, as in [ "$a" -a "$b" ] or [ "$a" -o "$b" ], work even if "$a" is '!' or '('. To avoid breaking backwards compatibility with the nonstandard unary [ -a "$file" ] and [ -o "$option" ] operators in combination with '!' or parentheses, this fix is only activated if the posix option is on. 2021-11-07: - Fixed a bug that could corrupt output if standard output is closed upon initializing the shell. - Improved BUG_PUTIOERR fix (2020-05-14) with more error checking. On systems with the "disk full" error testing device /dev/full, an echo/print/printf to /dev/full now always yields a non-zero exit status. 2021-09-13: - Disable the POSIX arithmetic context while running a command substitution invoked from within an arithmetic expression. This fixes a bug that caused integer arguments with a leading zero to be incorrectly interpreted as octal numbers in non-POSIX arithmetic contexts within such command substitutions. 2021-09-12: - When invoking a script without an interpreter/hashbang path on Linux and macOS, ksh can now update 'ps' output to show longer command lines. 2021-08-13: - An issue was fixed that could cause old-style `backtick` command substitutions to hang in certain cases. 2021-06-03: - Fixed a bug in the [[ compound command: the '!' logical negation operator now correctly negates another '!', e.g., [[ ! ! 1 -eq 1 ]] now returns 0/true. Note that this has always been the case for 'test'/'['. 2021-05-18: - Fixed SHLVL so that replacing ksh by itself (exec ksh) will not increase it. - Fixed a regression introduced on 2020-08-05 that caused a non-interactive shell to exit if an I/O redirection of a function call encountered an error. 2021-05-13: - Fixed a bug with 'test -t 1' that was introduced on 2021-04-26: v=$(test -t 1 >/dev/tty && echo ok) did not assign 'ok' to v. 2021-05-10: - Release 1.0.0-beta.1. 2021-05-07: - Backported three ksh 93v- math.tab changes, allowing for an exp10() arithmetic function if one exists in the C library, a new float() function, and lastly an updated int() function that rounds to zero instead of being an alias to floor(). 2021-05-05: - Fixed: a preceding variable assignment like foo=bar in 'foo=bar command' (with no command arguments after 'command') incorrectly survived the 'command' regular built-in command invocation. - Fixed: 'command -p some_utility' intermittently failed to find the utility under certain conditions due to a memory corruption issue. 2021-05-03: - Subshells (even if non-forked) now keep a properly separated state of the pseudorandom generator used for $RANDOM, so that using $RANDOM in a non-forked subshell no longer influences a reproducible $RANDOM sequence in the parent environment. In addition, upon invoking a subshell, $RANDOM is now reseeded (as mksh and bash do). - Fixed program flow corruption that occurred in scripts on executing a background job in a nested subshell, as in ( ( simple_command & ) ). - Completed the 2021-04-30 fix for ${var'{}'} where is '-', '+', ':-' or ':+' by fixing a bug that caused an extra '}' to be output. - Following the resolution of Austin Group bug 1393[*] that is set to be included in the next version of the POSIX standard, the 'command' prefix in POSIX mode (set -o posix) no longer disables the declaration properties of declaration built-ins. This reverts a change introduced on 2020-09-11. [*] https://austingroupbugs.net/view.php?id=1393 - Fixed arithmetic assignment operations for multidimensional indexed arrays. 2021-04-30: - The emacs 'ESC .' (M-.) and vi '_' commands now take shell quoting into account when repeating a word from the previous command line. For example, if the previous command is 'ls Stairway\ To\ Heaven.mp3', then they now insert 'Stairway\ To\ Heaven.mp3' instead of 'Heaven.mp3'. Thanks to Govind Kamat. - Fixed a bug introduced on 2020-09-05 that caused "echo ${var:+'{}'}" to be misparsed. - Fixed: the effects of 'builtin', 'exec' and 'ulimit' leaked out of a parent virtual subshell if run from a ${ shared-state; } command substitution. 2021-04-26: - Fixed a bug introduced on 2021-02-20 in which a shared-state command substitution stopped sharing its state with the calling shell environment if it executed a command that locally redirected standard output. 2021-04-22: - shcomp (the shell bytecode compiler) was fixed to correctly compile process substitutions used as the file name to a redirection, as in 'cmd < <(cmd)'. - Fixed a bug introduced on 2020-07-13 that set LINENO to the wrong line number after leaving a virtual subshell in which LINENO had been unset. 2021-04-21: - Fixed a bug introduced on 2020-09-28 that caused an interactive ksh to exit if a profile script (such as ~/.kshrc) contains a syntax error. 2021-04-20: - Fixed three problems with the /opt/ast/bin/getconf built-in command: 1. The -l/--lowercase option did not change all variable names to lower case. 2. The -q/--quote option now quotes all string values. Previously, it only quoted string values that had a space or other non-shellsafe character. 3. The -c/--call, -n/--name and -s/--standard options matched all variable names provided by 'getconf -a', even if none were actual matches. - The readonly attribute of ksh variables is no longer imported from or exported to other ksh shell instances through the environment. 2021-04-16: - Fixed a bug in emacs mode: after using tab completion to complete the name of a directory, it was not possible to type numbers after the slash. - Fixed an optimization bug that caused the <>; redirection operator to fail when used with the last command in a -c script. 2021-04-14: - Path-bound built-ins (such as /opt/ast/bin/cat) can now be executed by invoking the canonical path, so the following will now work as expected: $ /opt/ast/bin/cat --version version cat (AT&T Research) 2012-05-31 $ (PATH=/opt/ast/bin:$PATH; "$(whence -p cat)" --version) version cat (AT&T Research) 2012-05-31 Non-canonical paths such as /opt/ast/./bin/cat will not find the built-ins. - Path-bound built-ins will now also be found on a PATH set locally using an assignment preceding the command, so the following will now work as expected: $ PATH=/opt/ast/bin cat --version version cat (AT&T Research) 2012-05-31 2021-04-13: - Fixed a few bugs that could cause ksh to show the wrong error message and/or return the wrong exit status if a command couldn't be executed. In scenarios where the command was found in the PATH but it was not executable, ksh now returns with exit status 126. Otherwise, ksh will return with exit status 127 (such as if the command isn't found or if the command name is too long). 2021-04-12: - Corrected a memory fault when an attempt was made to unset the default nameref KSH_VERSION from the shell environment prior to any other name reference variable creation or modification. 2021-04-11: - Fixed two related regressions introduced on 2020-06-16: 1. The += assignment failed to append the value of variables when used in an invocation-local scope. The following should print '5', but the regression resulted in '3' being printed instead: $ integer foo=2; foo+=3 command eval 'echo $foo' 3 2. Any += assignment used in an invocation-local scope could modify readonly variables. 2021-04-10: - Fixed: the internal count of the recursion level for arithmetic expressions was not reset when certain errors occurred in a virtual subshell. This could cause an erroneous "recursion to deep" error when a loop executed many subshells containing arithmetic expressions with errors, e.g. for testing. 2021-04-09: - Fixed a bug that caused ksh to enable -c during the shell's initialization if the only argument passed was --posix. - Fixed a related bug that caused 'set --posix' to leave the braceexpand and letoctal shell options unchanged. - Fixed a bug that caused 'set --default' to unset the restricted option in restricted shells. 2021-04-08: - Path-bound builtins will now be used by restricted shells if /opt/ast/bin is in the $PATH upon invoking the shell or before setting it to restricted. - Fixed a bug that caused "printf '%T\n' now" to ignore $LC_ALL and $LC_TIME if the current locale was previously set, unset then set again. 2021-04-07: - The $LC_TIME variable is now recognized by ksh and if set to an invalid locale will show an error. - Fixed BUG_CSUBSTDO: If standard output is closed before running a command substitution, redirecting any other file descriptor no longer closes standard output inside of the command substitution. 2021-04-05: - Fixed a regression, introduced in ksh 93t+ 2009-07-31, that caused a command like 'unset arr[3]' to unset not just element 3 of the array but all elements starting from 3, if a range expansion like ${arr[5..10]} was previously used. - Several fixes for arrays of a type created by 'enum' were backported from ksh 93v-, further to the two enum array fixes already applied on 2021-02-01: 1. The array[@]} expansion was fixed for associative arrays of an enum type. 2. Assignments now work correctly for all enum values for both indexed and associative arrays. 3. 'unset' will now completely unset an associative array of an enum type. 2021-04-04: - A bug was fixed that caused a broken prompt display upon redrawing the command line if the last line of the prompt includes an xterm escape sequence that is terminated by $'\a' (the bell character). - Harden readonly variables. Readonly variables or arrays no longer allow attribute changes which would otherwise allow their value to be altered. Expanded support for readonly variables within multidimensional arrays. 2021-04-03: - Fixed a bug that caused the uname builtin's -d option to change the output of the -o option. - Fixed a possible crash that could occur when showing the domain name with the uname builtin's -d option. 2021-03-31: - Fixed a bug that caused 'cd -' to ignore the current value of $OLDPWD when it's set to a different directory in a new scope. - Fixed a related bug that caused ksh to use the wrong value for $PWD when in a new scope. 2021-03-29: - Fixed an intermittent crash that could occur in vi mode when using the 'b' or 'B' commands to go back one word. 2021-03-27: - The 'test' builtin will now show an error message when given the invalid ']]' or '=~' operators; it also properly returns with exit status 2 now (instead of exit status 1). If the invalid operator is supported by [[ ... ]] (such as '=~'), test will now suggest the usage of [[ ... ]] instead. 2021-03-22: - A new --globcasedetect shell option is added to ksh on OSs where we can check for a case-insensitive file system (currently macOS, Windows/Cygwin, Linux and QNX 7.0+). When this option is turned on, file name generation (globbing), as well as file name tab completion on interactive shells, automatically become case-insensitive on file systems where the difference between upper- and lowercase is ignored for file names. This is transparently determined for each directory, so a path pattern that spans multiple file systems can be part case-sensitive and part case-insensitive. The option is not compiled into ksh on systems where we do not know of a method to check for file system case insensitivity. The shell option can be force-compiled by setting SHOPT_GLOBCASEDET to 1 in src/cmd/ksh93/SHOPT.sh, but it won't have any effect on non-supported systems, so this is not recommended. It can be removed from ksh by setting SHOPT_GLOBCASEDET to 0. 2021-03-17: - Fixed a bug with file name completion on the interactive shell in multibyte locales. Upon encountering two filenames with multibyte characters starting with the same byte, a partial multibyte character was autocompleted. 2021-03-16: - Tilde expansion can now be extended or modified by defining a .sh.tilde.get or .sh.tilde.set discipline function. This replaces a 2004 undocumented attempt to add this functionality via a .sh.tilde built-in, which never worked and crashed the shell. See the manual for details on the new method. - Fixed a bug in interactive shells: if a variable used by the shell called a discipline function (such as PS1.get() or COLUMNS.set()), the value of $? was set to the exit status of the discipline function instead of the last command run. 2021-03-15: - If the HOME variable is unset, the bare tilde ~ now expands to the current user's system-configured home directory instead of merely the username. - Tighten up potential invalid typeset attribute combos when more than one numeric type has been requested. In particular, -F and -i are no longer masked over by previously given float types. 2021-03-13: - Fixed a file descriptor leak that occurred when ksh used /dev/fd for process substitutions passed to functions. - Fixed a separate file descriptor leak that happened when a process substitution was passed to a nonexistent command. 2021-03-11: - Fixed an intermittent bug that caused process substitutions to infinitely loop in Linux virtual machines that use systemd. - Fixed a bug that caused process substitutions to leave lingering processes if the command invoking them never reads from them. 2021-03-09: - The ${!foo@} and ${!foo*} expansions yield variable names beginning with foo, but excluded 'foo' itself. The fix for this is now backported from 93v- beta. - test -v var, [ -v var ], and [[ -v var ]] did not correctly test if a variable is set or unset after it has been given a numeric attribute with 'typeset' but not yet assigned a value. This has been fixed so that [[ -v var ]] is now equivalent to [[ -n ${var+set} ]] as documented. 2021-03-07: - Fixed the typeset -p display of short integers without an assigned value. Also, the last -s or -l attribute option supplied for an integer is used. - Fixed a bug with -G/--globstar introduced on 2020-08-09: patterns did not match anything if any pathname component was '.' or '..', e.g. '**/./glob.c' never matched. The 2020-08-09 fix does still apply to patterns like '.*'. - Enhancement to -G/--globstar: symbolic links to directories are now followed if they match a normal (non-**) glob pattern. For example, if '/lnk' is a symlink to a directory, '/lnk/**' and '/l?k/**' now work as you would expect. - Fixed a bug introduced on 2021-02-11 that caused job control on interactive ksh sessions to misbehave if the login shell was replaced by ksh using 'exec'. 2021-03-06: - Fixed an old expansion bug: expansions of type ${var=value} and ${var:=value} did not perform an assignment and yielded the value 0 if 'var' was typeset as numeric (integer or float) but had not yet been assigned a value. - Fixed a bug introduced on 2020-08-19: Ctrl+D would break after an interactive shell received SIGWINCH. - Fixed a bug introduced on 2020-05-21: on an interactive shell, command lines containing a syntax error were not added to the command history file and sometimes corrupted the command history. 2021-03-05: - Unbalanced quotes and backticks now correctly produce a syntax error in -c scripts, 'eval', and backtick-style command substitutions. 2021-03-04: - Fixed an arbitrary command execution vulnerability that occurred when parsing the subscripts of arrays within arithmetic commands and expansion. 2021-03-01: - Fixed the retention of size attributes when 'readonly' or 'typeset -r' was applied to an existing variable. 2021-02-26: - Fixed three long-standing bugs with tab completion in the emacs editor: 1. The editor accepted literal tabs without escaping in certain cases, causing buggy and inconsistent completion behaviour. Details: https://github.com/ksh93/ksh/issues/71#issuecomment-656970959 https://github.com/ksh93/ksh/issues/71#issuecomment-657216472 To enter a literal tab in emacs, you need to escape it with ^V or \. 2. After completing a filename by choosing from a file completion menu, the terminal cursor was placed one position too far to the right, corrupting command line display. This happened with multiline active. Details: https://github.com/ksh93/ksh/issues/71#issue-655093805 3. A completion menu was displayed if the file name to be completed was at the point where the rest of it started with a number, even if that part uniquely identified it so the menu only showed one item. Details: https://www.mail-archive.com/ast-users@lists.research.att.com/msg00436.html - A bug with ${.sh.fun} in combination with the DEBUG trap has been fixed. The ${.sh.fun} variable wrongly continued to contain the name of the last function executed by the DEBUG trap after the trap action completed. 2021-02-21: - Fixed: The way that SIGWINCH was handled (i.e. the signal emitted when the terminal window size changes) could cause strange emacs/vi editor behaviour. 2021-02-20: - Fixed a bug introduced on 2021-01-20: if a DEBUG trap action yielded exit status 2, the execution of the next command was not skipped as documented. - Fixed multiple buffer overflows causing crashes in typeset -L/-R-/-Z. - Fixed typeset -Z zero-filling: if the number was zero, all zeros were skipped when changing the initial size value of the -Z attribute, leaving an empty string. 2021-02-18: - A bug was fixed in the 'read' builtin that caused it to fail to process multibyte characters properly in Shift-JIS locales. 2021-02-17: - Emacs mode fixes: 1. Erasing a backslash while doing a reverse search (^R) no longer deletes extra characters. 2. The backslash now escapes a subsequent interrupt (^C) as documented. - Fixed a longstanding bug with shared-state command substitutions of the form ${ command; }. If these were executed in a subshell, changes made within could survive not only the command substitution but also the parent subshell. 2021-02-15: - Fixed a regression introduced by ksh93 (was not in ksh88): an empty 'case' list on a single line ('case x in esac') was a syntax error. - Fixed a bug in the emacs built-in editor, introduced on 2020-09-17, that made the Meta-D and Meta-H keys delete single characters instead of words. - A new 'backslashctrl' shell option has been added. It is on by default. Turning it off (set +o backslashctrl or set --nobackslashctrl) disables the special escaping behaviour of the backslash character in the emacs and vi built-in editors. Particularly in the emacs editor, this makes it much easier to go back, insert a forgotten backslash into a command, and then continue editing without having your next cursor key replace your backslash with garbage. Note that Ctrl+V (or whatever other character was set using 'stty lnext') always escapes all control characters in either editing mode. 2021-02-14: - Due to a deficiency in some UNIX variants, the 'sleep' built-in command could occasionally sleep for slightly less than the time specified. It now performs an additional check against the system clock to make sure it sleeps at least the given amount of time. Thanks to Lev Kujawski for adding this feature. - A few bugs were fixed that 93u+m introduced along with the new '-o posix' shell option on 2020-09-01: 1. 'set --posix' now works as the expected equivalent of 'set -o posix'. 2. As of 2020-09-18, the posix option turns off braceexpand and turns on letoctal. Any attempt to override that in a single command such as 'set -o posix +o letoctal' was quietly ignored. This now works as long as the overriding option follows the posix option on the command line. 3. The --default option to 'set' now stops the 'posix' option, if set or unset in the same 'set' command, from changing other options. This allows the command output by 'set +o' to correctly restore the current options. 2021-02-11: - Fixed a bug that caused ksh to lose track of all running background jobs if a shared-state command substitution of the form v=${ cmd; } was used twice. - Job control (the -m/-o monitor option) has been fixed for scripts. Background jobs are now correctly assigned their own process group when run from subshells (except command substitutions). The 'fg' command now also works for scripts as it does on other shells, though 'wait' should be preferred. 2021-02-05: - Fixed a longstanding bug that caused redirections that store a file descriptor > 10 in a variable, such as {var}>file, to stop working if brace expansion (the -B or -o braceexpand option) was turned off. (Note that '{var}' is not a brace expansion as it does not contain ',' or '..'.) 2021-02-04: - Fixed ksh crashing if an autoloaded function tried to autoload itself. ksh now errors out gracefully with an "autoload loop" error message. - Fixed crash on trying a very long nonexistent command. 2021-02-01: - Fixed a bug in 'typeset': the '-s' modifier option for short integer will now only be applied if the integer option '-i' is also present, avoiding inconsistent results and a crash. - Fixed: scalar arrays (-a) and associative arrays (-A) of a type created by 'enum' allowed values not specified by the enum type, corrupting results. - Fixed: the "${array[@]}" expansion for associative arrays of a type created by 'enum' expanded to random numbers instead of the array's values. 2021-01-30: - The -x option to the 'command' built-in now causes it to bypass built-ins so that it always runs/queries an external command. See 'command --man'. - Fixed a bug in 'command -x' that caused the minimum exit status to be 1 if a command with many arguments was divided into several command invocations. - The 2020-08-16 fix is improved with a compile-time feature test that detects if the OS requires extra bytes per argument in the arguments list, maximising the efficiency of 'command -x' for the system it runs on. 2021-01-24: - Fixed a bug in 'typeset': combining the -u option with -F or -E caused the variable to become a hexadecimal floating point in error. - Fixed: an unquoted variable expansion evaluated in a DEBUG trap action caused IFS field splitting to be deactivated in code executed after the trap action. This bug was introduced in ksh 93t+ 2009-11-30. 2021-01-23: - Fixed: when the DEBUG trap was redefined in a subshell, the DEBUG trap in the parent environment was corrupted or the shell crashed. When a redirection was used in a DEBUG trap action, the trap was disabled. DEBUG traps were also incorrectly inherited by subshells and ksh functions. All this was caused by a bug introduced in ksh 93t 2008-06-24. 2021-01-22: - Compile-time shell options can now be edited in src/cmd/ksh93/SHOPT.sh before building. 2021-01-20: - Fixed: executing a DEBUG trap in a command substitution had side effects on the exit status ($?) of non-trap commands. This bug was introduced in ksh 93t 2008-09-21. - The typeset builtin command now gives an informative error message if an incompatible combination of options is given. 2021-01-19: - Fixed a crash when using 'cd' in a virtual/non-forking subshell in a situation where the current working directory cannot be determined. 2021-01-08: - Fixed a crash on exceeding the maximum size of the $PS1 prompt. The maximum size is also increased from 160 to 256 bytes. 2021-01-07: - Fixed a crash that could occur while ksh updated ${.sh.match}. - Any changes to the hash table (a.k.a. "tracked aliases", i.e. cached $PATH searches) in a subshell now no longer affect the parent shell's hash table. 2021-01-05: - Fixed a bug in 'cd' that caused 'cd ./foo' to search for 'foo' in $CDPATH. 2021-01-03: - The invocation $ ksh +s caused an infinite loop and corrupted ~/.sh_history. This is now fixed so that the '-s' option is automatically turned on if there are no non-option command arguments, as documented in Bolsky & Korn (1995), p. 261. 2020-10-22: - Fixed: 'typeset -F0', 'typeset -E0', and 'typeset -X0' floating point numerics having a precision of 0 with variable assignment. 'typeset -F0 x; x=4.56' worked but not 'typeset -F0 x=4.56'. 2020-10-21: - Fixed: More concisely correct the exporting of uppercase and lowercase variables when only the export and change case attributes were applied. This fix improves upon the previous 2020-09-30 modifications. 2020-10-06: - The security of virtual/non-forking subshells that locally change the present working directory (PWD) using 'cd' has been improved in two ways. 1. On entering a subshell, if the parent shell's PWD proves inaccessible upon saving it, the subshell will now fork into a separate process so the parent process never changes its PWD, avoiding the need to restore it. 2. If some attack renders the parent shell's PWD unrestorable *after* ksh enters a virtual subshell, ksh will now error out on exiting it, as continuing would mean running arbitrary commands in the wrong PWD. Hopefully this is an acceptable compromise between performance and security. The proper fix would be to always fork a subshell when changing the working directory within it, but the resulting slowdown would likely be unpopular. 2020-09-30: - Fixed: 'typeset -xu' and 'typeset -xl' (export + change case) failed to change the case of a variable's value in certain conditions. - A ksh 93u+ regression was fixed in the combination of ERR trap handling and the 'pipefail' option. A pipeline now triggers the ERR trap correctly again if the 'pipefail' option is active and any of the pipeline elements return a nonzero exit status. Similarly, if both the 'errexit' and 'pipefail' options are active, ksh now correctly exits if any pipeline element returns nonzero. - Autoloading a function no longer causes the calling script's $LINENO to be off by the number of lines in the function definition file that was loaded. This also corrects line numbers in warnings and error messages. 2020-09-28: - While executing a ksh-style function, ksh 93u+ ignored all signals for which the function had not set a local trap, except for SIGINT and SIGQUIT. This was contrary to the manual, which states that a "trap condition that is not caught or ignored by the function causes the function to terminate and the condition to be passed on to the caller". This has now been fixed in 93u+m to match the documentation, so that e.g. global traps work as expected again. 2020-09-27: - The shell's lexical analysis of a 'case' statement within a do...done block within a command substitution of the form $(...) has been fixed so that code like the following no longer throws a spurious syntax error: x=$(for i in 1; do case $i in word) true;; esac; done) Previously, this required a leading parenthesis before 'word', although the syntax error claimed that the ';;' was unexpected. 2020-09-26: - 'whence -f' now completely ignores the existence of functions, as documented. - ksh now does not import environment variables whose names are not valid in the shell language, as it would be impossible to change or unset them. However, they stay in the environment to be passed to child processes. 2020-09-25: - whence -v/-a now reports the path to the file that an "undefined" (i.e. autoloadable) function will be loaded from when invoked, if found in $FPATH. - When ksh invoked a shell script that does not have a leading #!/hashbang/path, 'ps' and /proc//cmdline showed corrupted output if the new script's command line was shorter than that of the invoking script. This has been fixed by wiping the arguments buffer correctly. 2020-09-24: - An omission made it impossible to turn off brace expansion within command substitutions (`...`, $(...) or ${ ...; }) as the code for parsing these did not check the -B/braceexpand option. This check has now been added. 2020-09-23: - Fixed a crash that could occur when running a pipeline containing backtick-style command substitutions with job control enabled. - Fixed a crash that occurred when using 'typeset -u' or 'typeset -l' on a special variable such as PATH, ENV or SHELL. 2020-09-21: - A bug was fixed that caused command substitutions embedded in here-documents to lose the output of the commands they ran. This bug occurred when ksh was compiled with the SHOPT_SPAWN compile-time option. - Bugfix: var=$(< file) now reads the file even if the standard input, standard output and/or standard error file descriptors are closed. 2020-09-20: - Bugfix: when whence -v/-a found an "undefined" (i.e. autoloadable) function in $FPATH, it actually loaded the function as a side effect of reporting on its existence. Now it only reports, as documented. - 'whence' will now canonicalise paths properly, resolving '.' and '..' elements in paths given to it. It also no longer prefixes a spurious double slash when doing something like 'cd / && whence bin/echo'. 2020-09-18: - Setting the 'posix' option now turns off the 'braceexpand' option, as brace expansion is not specified by POSIX and potentially incompatible with sh scripts. In addition, 'set -o posix' now turns on the 'letoctal' option instead of controlling that behaviour directly. 'set +o posix' does the reverse of these. 2020-09-17: - In the vi and emacs line editors, repeat count parameters can now also be used for the arrow keys and the forward-delete key. E.g., in emacs mode, 7 will now move the cursor seven positions to the left. In vi control mode, this would be entered as: 7 . - When a background job on an interactive shell received SIGINT or SIGPIPE, the job termination message was empty. It now shows "Interrupt" or "Broken Pipe". - The -m (-o monitor) option is no longer ignored when specified on the shell invocation command line. - A script that is interrupted with Ctrl+C now terminates its background jobs as expected, unless the -m (-o monitor) option was turned on. 2020-09-14: - Corrected rounding of floating point values by ksh's printf %f formatting operator. Fix contributed by @hyenias. - The forward-delete key now works as expected in emacs and vi editing modes. 2020-09-11: - The 'command' regular builtin utility (which runs a simple command, removing special properties) has been made fully POSIX compliant. 1. The 'command' name can now result from an expansion (fixing BUG_CMDEXPAN), e.g. 'c=command; "$c" ls' and 'set -- command ls; "$@"' now work. 2. If and only if the POSIX mode (the new -o posix shell option) is active, then the 'command' utility now disables not only "special" but also "declaration" properties of builtin commands that it invokes, meaning: a. arguments that start with a variable name followed by '=' are always treated as regular words subject to normal shell syntax; b. 'command' can now stop the shell from exiting if a command that it invokes tries to modify a readonly variable (fixing BUG_CMDSPEXIT). - The 'history' (== 'hist -l') and 'r' (== 'hist -s') interactive shell history commands have reverted to preset aliases and are now only loaded if the shell is interactive and not initialised in POSIX mode. This avoids unneeded conflicts with external commands by these names, particularly 'r'. 2020-09-09: - Fixed BUG_LOOPRET2 and related bugs. The 'exit' and 'return' commands without an argument now correctly default to passing down the exit status of the last-run command. Tests like the following, in which the last-run command is 'false', now correctly output 1 instead of 0: fn() { return || true; }; false; fn; echo "$?" fn() { while return; do true; done; }; false; fn; echo "$?" fn() { for i in 1; do return; done; }; false; fn; echo "$?" fn() { case 1 in 1) return ;; esac; }; false; fn; echo "$?" fn() { { return; } 2>&1; }; false; fn; echo "$?" 2020-09-05: - Fixed erroneous syntax errors in parameter expansions such as ${var:-wor)d} or ${var+w(ord}. The parentheses now correctly lose their normal grammatical meaning within the braces. Fix by Eric Scrivner backported from ksh2020. 2020-09-04: - Fixed a bug that caused a syntax error to be thrown if the special parameter expansions ${!} and ${$} (including braces) were used within a here-document. Bug reported by @Saikiran-m on GitHub. 2020-09-01: - The bash-style '&>file' redirection shorthand (for '>file 2>&1') is now always recognised and not only when running rc/profile init scripts. It no longer issues a warning. This brings ksh93 in line with mksh, bash and zsh. - A long-form shell option '-o posix' has been added, which implements a mode for better compatibility with the POSIX standard. It is automatically turned on if ksh is invoked under the name 'sh'. For now, it: * disables the &> redirection shorthand * causes the 'let' arithmetic command to recognise octal numbers by leading zeros regardless of the setting of the 'letoctal' option * causes file descriptors > 2 to be left open when invoking another program * makes the <> redirection operator default to stdin instead of stdout (this keeps the 2020-05-13 BUG_REDIRIO fix for the POSIX mode while restoring traditional ksh93 behaviour for backwards compatibility) * disables a noncompliant 'test -t' == 'test -t 1' compatibility hack * disables passing an exported variable's attributes (such as integer or readonly) to a new ksh process through the environment 2020-08-19: - Sped up the 'read' command on most systems by 15-25%. Fixed a hanging bug on reading from a FIFO that could occur on macOS. 2020-08-17: - 'command -p' incorrectly used the hash table entry (a.k.a. tracked alias) for a command if its path was previously hashed. It has now been fixed so it never consults the hash table. 2020-08-16: - Fixed 'command -x' on macOS, Linux and Solaris by accounting for a 16-byte argument alignment. If execution does fail, it now aborts with an internal error message instead of entering an infinite retry loop. 2020-08-13: - Fixed memory leaks and a crashing bug that occurred when defining and running functions in subshells. 2020-08-11: - Fixed an intermittent crash upon running a large number of subshells. 2020-08-10: - A number of fixes have been applied to the printf formatting directives %H and %#H (as well as the undocumented equivalents %(html)q and %(url)q): 1. Both formatters have been made multibyte/UTF-8 aware, and no longer delete multibyte characters. Invalid UTF-8 byte sequences are rendered as ASCII question marks. 2. %H no longer wrongly changes spaces to non-breaking spaces ( ). 3. %H now converts the single quote (') to '%#39;' instead of ''' which is not a valid entity in all HTML versions. 4. %#H failed to encode some reserved characters (e.g. '?') while encoding some unreserved ones (e.g. '~'). It now percent-encodes all characters except those 'unreserved' as per RFC3986 (ASCII alphanumeric plus -._~). - Fixed a crash that occurred intermittently after running an external command from a command substitution expanded from the $PS1 shell prompt. 2020-08-09: - File name generation (a.k.a. pathname expansion, a.k.a. globbing) now never matches the special navigational names '.' (current directory) and '..' (parent directory). This change makes a pattern like .* useful; it now matches all hidden files (dotfiles) in the current directory, without the harmful inclusion of '.' and '..'. 2020-08-08: - Argument checking in the 'redirect' builtin command (see 2020-06-11) has been improved to error out before executing redirections. For example, an error like 'redirect ls >foo.txt' now will not create 'foo.txt' and will not leave your standard output permanently redirected to it. 2020-08-06: - Added the '${.sh.pid}' variable as an alternative to Bash's '$BASHPID'. This variable is set to the current shell's PID, unlike '$$' (which is set to the main shell's PID). In virtual subshells '${.sh.pid}' is not changed from its previous value, while in forked subshells '${.sh.pid}' is set to the subshell's process ID. 2020-08-05: - Fixed a bug in functions that caused ksh to crash when an array with an unset method was turned into a multidimensional array. - Fixed a bug that caused scripts to continue running after over-shifting in a function when the function call had a redirection. - When generating shellquoted strings (such as with 'printf %q'), the hexadecimal value of a quoted unprintable character was not protected with square braces, e.g. 0x12 followed by '3' would be quoted as '\x123', which is a different value. Such strings are now quoted like '\x[12]3' if the next character is a hexadecimal digit. 2020-07-31: - Fixed a bug that caused multidimensional associative arrays to be created with an extra array member. - Fixed a bug that caused the expansions of positional parameters $1 - $9, as well as special parameters such as $? and $-, to corrupt any multibyte characters immediately following the expansion if a UTF-8 locale is active. 2020-07-29: - On a ksh compiled to use fork(2) to run external commands, a bug has been fixed that caused signals (such as SIGINT, Ctrl+C) to be ignored within a non-forked subshell after running an external command within that subshell. 2020-07-25: - Fixed BUG_MULTIBIFS: Multibyte characters can now be used as IFS delimiters. "$*" was incorrectly joining positional parameters on the first byte of a multibyte character. This was due to truncation based on the incorrect assumption the IFS would never be larger than a single byte. - Fixed a bug that caused the sleep builtin to continue after being given an unrecognized option. 'sleep -: 1' will now show a usage message and exit instead of sleep for one second. - Fixed a bug that caused the 'typeset' variable attributes -a, -A, -l, and -u to leak out of a subshell if they were set without assigning a value. 2020-07-23: - Fixed an infinite loop that could occur when ksh is the system's /bin/sh. - A command substitution that is run on the same line as a here-document will no longer cause a syntax error. 2020-07-22: - Fixed two race conditions when running external commands on interactive shells with job control active. 2020-07-20: - If a shell function and a built-in command by the same name exist, 'whence -a' and 'type -a' now report both. - Fixed a bug that caused file descriptors opened with 'redirect' or 'exec' to survive a subshell environment after exiting it. 2020-07-19: - Fixed a crash that occurred in the '.' command when using kshdb. - Fixed a crash that occurred when attempting to use redirection with an invalid file descriptor. 2020-07-16: - The 'history' and 'r' default aliases have been made regular built-ins, leaving zero default aliases. - Fixed a bug that caused 'sleep -s' to have no effect with intervals longer than 30 seconds. - The accuracy of the sleep builtin has been improved. It no longer ignores microseconds and doesn't add extra milliseconds when the interval is less than 31 seconds. 2020-07-15: - The 'autoload', 'compound', 'float', 'functions', 'integer' and 'nameref' default aliases have been converted into regular built-in commands, so that 'unalias -a' does not remove them. Shell functions can now use these names, which improves compatibility with POSIX shell scripts. - The End key escape sequence '^[[F' is now handled in the emacs and vi editing modes. The End key moves the cursor to the end of the line (in contrast to the Home key doing the opposite). 2020-07-14: - Fixed a bug that caused 'set -b' to have no effect. - Following the 'time' keyword, the 'times' builtin command now also supports millisecond precision. 2020-07-13: - Fixed a fork bomb that could occur when the vi editor was sent SIGTSTP while running in a ksh script. - Appending a lone percent to the end of a format specifier no longer causes a syntax error. The extra percent will be treated as a literal '%', like in Bash and zsh. - The 'time' keyword now has proper support for millisecond precision. Although this feature was previously documented, the 'time' keyword only supported up to centisecond precision, which caused a command like the one below to return '0.000' on certain operating systems: $ TIMEFORMAT='%3R'; time sleep .003 - The 'time' keyword now zero-pads seconds less than ten (like mksh). 2020-07-10: - Fixed a bug that caused types created with 'typeset -T' to throw an error when used if the type name started with a lowercase 'a'. - A potential crash due to memory corruption when using many file descriptors has been fixed. 2020-07-09: - Fixed a crash on syntax error when sourcing/dotting multiple files. - Fixed a crash when listing indexed arrays. - Fixed a memory leak when restoring PATH when temporarily setting PATH for a command (e.g. PATH=/foo/bar command ...) or in a virtual subshell. - Combining ((...)) with redirections no longer causes a syntax error due to the parser handling '>' incorrectly. - Fixed a bug that corrupted KIA/CQL cross-reference databases created using ksh's -R option; shell warnings were wrongly included in the database file. - The shell's quoting algorithm (used in xtrace, printf %q, and more) has been fixed for UTF-8 (Unicode) locales; it no longer needlessly and inconsistently encodes normal printable UTF-8 characters into hexadecimal \u[xxxx] codes. 2020-07-07: - Four of the date formats accepted by 'printf %()T' have had their functionality altered to the common behavior of date(1): - '%k' and '%l' print the current hour with blank padding, the former based on a 24-hour clock and the latter a 12-hour clock. These are common extensions present on Linux and *BSD. - '%f' prints a date with the format string '%Y.%m.%d-%H:%M:%S' (BusyBox). - '%q' prints the quarter of the year (GNU). 2020-07-06: - 'notty' is now written to the ksh auditing file instead of '(null)' if the user's tty could not be determined. - Unsetting an associative array no longer causes a memory leak to occur. 2020-07-05: - In UTF-8 locales, fix corruption of the shell's internal string quoting algorithm (as used by xtrace, 'printf %q', and more) that occurred when the processing of a multibyte character was interrupted. 2020-07-03: - Backslashes are no longer escaped in the raw Bourne Shell-like editing mode in multibyte locales, i.e. backslashes are no longer treated like Control-V if the emacs and vi modes are disabled. - Deleting a backslash in vi mode with Control-H or Backspace now only escapes a backslash if it was the previous input. This means erasing a string such as 'ab\\\' will only cause the first backslash to escape a Backspace as '^?', like in emacs mode. - An odd interaction with Backspace when the last character of a separate buffer created with Shift-C was '\' has been fixed. '^?' will no longer be output repeatedly when attempting to erase a separate buffer with a Backspace. Note that buffers created with Shift-C are not meant to be erasable: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/vi.html#tag_20_152_13_49 - The 'kill' builtin now supports the SIGINFO signal (on operating systems with support for SIGINFO). 2020-07-02: - Fixed a crash that occurred if a directory named '.paths' existed in any directory listed in $PATH. The fix was to only read '.paths' if it is a regular file or a symlink to a regular file. 2020-06-30: - 'read -u' will no longer crash with a memory fault when given an out of range or negative file descriptor. - The '=~' operator no longer raises an error if a regular expression combines the '{x}' quantifier with a sub-expression. 2020-06-28: - Variables created with 'typeset -RF' no longer cause a memory fault when accessed. - Unsetting an array that was turned into a compound variable will no longer cause silent memory corruption. - Variables created with 'readonly' in functions are now set to the specified value instead of nothing. Note that 'readonly' does not create a function-local scope, unlike 'typeset -r' which does. 2020-06-26: - Changing to a directory that has a name starting with a '.' will no longer fail if preceded by '../' (i.e. 'cd ../.local' will now work). 2020-06-24: - Fixed buggy tab completion of tilde-expanded paths such as ~/some in 'vi' mode. - In the raw/default Bourne Shell-like editing mode that occurs when neither the 'emacs' nor the 'vi' shell option is active: * tab completion is now correctly disabled, instead of enabled and broken; * entering tab characters now moves the cursor the correct amount. 2020-06-23: - Fixed a bug that caused combining process substitution with redirection to create a bizarre file in the user's current working directory. - Using process substitution while the shell is interactive no longer causes the process ID of the asynchronous process to be printed. 2020-06-22: - The 'stop' and 'suspend' default aliases have been converted into regular built-in commands, so that 'unalias -a' does not remove them, 'suspend' can do a couple of sanity checks, and something like cmd=stop; $cmd $! will now work. See 'stop --man' and 'suspend --man' for more information. - Fixed a bug that caused the kill and stop commands to segfault when given a non-existent job. - Nested functions no longer ignore variable assignments that were prefixed to their parent function, i.e. 'VAR=foo func' will now set $VAR to 'foo' in the scope of any nested function 'func' runs. 2020-06-20: - Fixed a bug that caused setting the following variables as readonly in a virtual subshell to affect the environment outside of the subshell: $_ ${.sh.name} ${.sh.subscript} ${.sh.level} $RANDOM $LINENO - Fixed two bugs that caused 'unset .sh.lineno' to always produce a memory fault and '(unset .sh.level)' to memory fault when run in nested functions. 2020-06-18: - A two decade old bug that caused 'whence -a' to base the path of tracked aliases on the user's current working directory has been fixed. Now the real path to tracked aliases is shown when '-a' is passed to the whence command. 2020-06-17: - A bug in 'unset -f' was fixed that prevented shell functions from unsetting themselves while they were running. A POSIX function no longer crashes when doing so, and a KornShell-style function no longer silently ignores an 'unset -f' on itself. A function of either form now continues running after unsetting itself, and is removed at the end of the run. 2020-06-16: - Passing the '-d' flag to the read builtin will no longer cause the '-r' flag to be discarded when 'read -r -d' is run. - Fix BUG_CMDSPASGN: preceding a "special builtin"[*] with 'command' now prevents preceding invocation-local variable assignments from becoming global. [*] https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_14 2020-06-15: - The 'source' alias has been converted into a regular built-in command. - Functions that set variables in a virtual subshell will no longer affect variables of the same name outside of the virtual subshell's environment. - Terse usage messages written by builtin commands now point the user to the --help and --man options for more information. 2020-06-14: - 'read -S' is now able to correctly handle strings with double quotes nested inside of double quotes. 2020-06-13: - Fixed a timezone name determination bug on FreeBSD that caused the output from "LC_ALL=C printf '%T\n' now" to print the wrong time zone name. 2020-06-11: - Fixed a bug that caused running 'builtin -d' on a special builtin to delete it. The man page for the 'builtin' command documents that special builtins cannot be deleted. - POSIX compliance fix: It is now possible to set shell functions named 'alias' or 'unalias', overriding the commands by the same names. In technical terms, they are now regular builtins, not special builtins. - The redirect='command exec' alias has been converted to a regular 'redirect' builtin command that only accepts I/O redirections, which persist as in 'exec'. This means that: * 'unlias -a' no longer removes the 'redirect' command; * users no longer accidentally get logged out of their shells if they type something intuitive but wrong, like 'redirect ls >file'. - The undocumented 'login' and 'newgrp' builtin commands have been removed. These replaced your shell session with the external commands by the same name, as in 'exec'. If an error occurred (e.g. due to a typo), you would end up immediately logged out. If you do want this behaviour, you can restore it by setting: alias login='exec login' alias newgrp='exec newgrp' 2020-06-10: - The 'hash' utility is now a regular builtin instead of an alias to 'alias -t --'. The functionality of the old command has been removed from the alias builtin. - 'set +r' is no longer able to unset the restricted option. This change makes the behavior of 'set +r' identical to 'set +o restricted'. 2020-06-09: - The 'unalias' builtin will now return a non-zero status if it tries to remove a previously set alias that is not currently set. 2020-06-08: - Fix an issue with the up arrow key in Emacs editing mode. Emacs editing mode is bugged in ksh93u+ and ksh2020. Let's say you were to run the following commands after starting a fresh instance of ksh: $ alias foo=true $ unalias foo If you type 'a' and then press the up arrow on your keyboard, ksh will complete 'a' to 'alias foo=true' by doing a reverse search for the last command that starts with 'a'. Run the alias command again, then type 'u' and press the up arrow key again. If ksh is in Vi mode, you will get 'unalias foo', but in Emacs mode you will get 'alias foo=true' again. All subsequent commands were ignored as ksh was saving the first command and only based later searches off of it. - If 'set -u'/'set -o nounset' is active, then the shell now errors out if a nonexistent positional parameter such as $1, $2, ... is accessed, as other shells do and POSIX requires. (This does *not* apply to "$@" and "$*".) - If 'set -u'/'set -o nounset' is active, then the shell now errors out if $! is accessed before the shell has launched any background process. - Removed support for an obscure early 1990s Bell Labs file system research project called 3DFS, which has not existed for decades. This removes: - an obnoxious default alias 2d='set -f;_2d' that turned off your file name wildcard expansion and then tried to run a nonexistent '_2d' command - undocumented builtins 'vmap' and 'vpath' that only printed error messages - a non-functional -V unary operator for the test and [[ commands - If the last program run by a ksh script exits with a signal (e.g. crashed), ksh itself now exits normally instead of repeating that same signal. In addition, using 'exit x' for x > 256 no longer makes ksh issue a signal. 2020-06-06: - The 'times' command is now a builtin command that conforms to POSIX instead of an alias for the 'time' command. It displays the accumulated user and system CPU times, one line with the times used by the shell and another with those used by all of the shell's child processes. https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_27 - The default aliases command='command ' and nohup='nohup ' have been removed because they caused breakage in an attempt to circumvent other breakage which is being fixed. In the unlikely even that anyone still needs alias substitution to continue on the command argument following 'command' or 'nohup', it's easy to set these aliases yourself. 2020-06-05: - Fix a bug that caused special variables such as PATH, LANG, LC_ALL, etc. to lose their effect after being unset in a subshell. For example: (unset PATH; PATH=/dev/null; ls); : wrongly ran 'ls' (unset LC_ALL; LC_ALL=badlocale); : failed to print a diagnostic This also fixes BUG_KUNSETIFS: unsetting IFS in a subshell failed if IFS was set to the empty value in the parent shell. - Fix crashes on some systems, including at least a crash in 'print -v' on macOS, by eliminating an invalid/undefined use of memccpy() on overlapping buffers in the commonly used sfputr() function. - Fix the ${.sh.subshell} level counter; it is no longer reset to zero when a non-forked subshell happens to fork into a separate process for some reason (an internal implementation detail that should be unnoticeable to scripts). 2020-06-04: - Fix BUG_KBGPID: the $! special parameter was not set if a background job (somecommand &) or co-process (somecommand |&) was launched as the only command within a braces block with an attached redirection, for example: { somecommand & } >&2 With the bug, $! was unchanged; now it contains the PID of somecommand. 2020-05-31: - Fix a bug in autoloading functions. Directories in the path search list which should be skipped (e.g. because they don't exist) did not interact correctly with autoloaded functions, so that a function to autoload was not always found correctly. Details: https://github.com/att/ast/issues/1454 2020-05-30: - Fix POSIX compliance of 'test'/'[' exit status on error. The command now returns status 2 instead of 1 when given an invalid number or arithmetic expression, e.g.: [ 123 -eq 123x ]; echo $? now outputs 2 instead of 1. 2020-05-29: - Fix BUG_FNSUBSH: functions can now be correctly redefined and unset in subshell environments (such as ( ... ), $(command substitutions), etc). Before this fix, this was silently ignored, causing the function by the same name from the parent shell environment to be executed instead. fn() { echo mainsh; } (fn() { echo subsh; }; fn); fn This now correctly outputs "subsh mainsh" instead of "mainsh mainsh". ls() { echo "ls executed"; } (unset -f ls; ls); ls This now correctly lists your directory and then prints "ls executed", instead of printing "ls executed" twice. - Fix a similar bug with aliases. These can now be correctly unset in subshell environments. 2020-05-21: - Fix truncating of files with the combined redirections '<>;file' and '<#pattern'. The bug was caused by out-of-sync streams. Details and discussion: https://github.com/att/ast/issues/61 - Patched code injection vulnerability CVE-2019-14868. As a result, you can no longer use expressions in imported numeric environment variables; only integer literals are allowed. 2020-05-20: - Fix BUG_ISSETLOOP. Expansions like ${var+set} remained static when used within a 'for', 'while' or 'until' loop; the expansions din't change along with the state of the variable, so they could not be used to check whether a variable is set within a loop if the state of that variable changed in the course of the loop. - Fix BUG_IFSISSET. ${IFS+s} always yielded 's', and [[ -v IFS ]] always yielded true, even if IFS is unset. This applied to IFS only. 2020-05-19: - Fix 'command -p'. The -p option causes the operating system's standard utilities path (as output by 'getconf PATH') to be searched instead of $PATH. Before this fix, this was broken on non-interactive shells as the internal variable holding the default PATH value was not correctly initialised. 2020-05-16: - Fix 'test -t 1', '[ -t 1 ]', '[[ -t 1 ]]' in command substitutions. Standard output (file descriptor 1) tested as being on a terminal within a command substitution, which makes no sense as the command substitution is supposed to be catching standard output. v=$(echo begincomsub [ -t 1 ] && echo oops echo endcomsub) echo "$v" This now does not output "oops". 2020-05-14: - Fix syncing history when print -s -f is used. For example, the following now correctly adds a 'cd' command to the history: print -s -f 'cd -- %q\n' "$PWD" Ref.: https://github.com/att/ast/issues/425 https://github.com/att/ast/pull/442 - Fix BUG_PUTIOERR: Output builtins now correctly detect input/output errors. This allows scripts to check for a nonzero exit status on the 'print', 'printf' and 'echo' builtins and prevent possible infinite loops if SIGPIPE is ignored. - Add a convenient bin/shtests script to the source tree that sets up the necessary environment and runs the ksh regression tests. 2020-05-13: - Fix BUG_CASELIT: an undocumented 'case' pattern matching misbehaviour that goes back to the original Bourne shell, but wasn't discovered until 2018. If a pattern doesn't match as a pattern, it was tried again as a literal string. This broke common validation use cases, e.g.: n='[0-9]' case $n in ( [0-9] ) echo "$n is a number" ;; esac would output "[0-9] is a number" as the literal string fallback matches the pattern. As this misbehaviour was never documented anywhere (not for Bourne, ksh88, or ksh93), and it was never replicated in other shells (not even in ksh88 clones pdksh and mksh), it is unlikely any scripts rely on it. Of course, a literal string fallback, should it be needed, is trivial to implement correctly without this breakage: case $n in ( [0-9] | "[0-9]") echo "$n is a number or the number pattern" ;; esac Ref.: https://github.com/att/ast/issues/476 - Fix BUG_REDIRIO: ksh used to redirect standard output by default when no file descriptor was specified with the rarely used '<>' reading/writing redirection operator. It now redirects standard input by default, as POSIX specifies and as all other POSIX shells do. To redirect standard output for reading and writing, you now need '1<>'. Ref.: https://github.com/att/ast/issues/75 https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_07_07 2020-05-12: - ksh development rebooted based on 93u+ 2012-08-01. ksh-1.0.10/README.md000066400000000000000000000253031465301102200136320ustar00rootroot00000000000000![](https://github.com/ksh93/ksh/workflows/CI/badge.svg) # KornShell 93u+m This is version 1.0.x of the 93u+m fork of the KornShell, including a sizeable number of enhancements and roughly a thousand bugfixes compared to the last stable release (93u+ 2012-08-01) of [ksh93](http://www.kornshell.com/), formerly developed by AT&T Software Technology (AST). The sources in this repository were forked from the GitHub [AST repository](https://github.com/att/ast) which is no longer under active development. For information on the shell, see [`src/cmd/ksh93/README`](https://github.com/ksh93/ksh/tree/1.0/src/cmd/ksh93#readme) and other files in the same directory. For user-visible fixes, see [NEWS](https://github.com/ksh93/ksh/blame/1.0/NEWS) and click on commit messages for full details. For all fixes, see [the commit log](https://github.com/ksh93/ksh/commits/1.0). For known issues in the current release, see [TODO](https://github.com/ksh93/ksh/blob/1.0/TODO). ## Build To build ksh with a custom configuration of features, edit [`src/cmd/ksh93/SHOPT.sh`](https://github.com/ksh93/ksh/blob/1.0/src/cmd/ksh93/SHOPT.sh). Then `cd` to the top directory and run: ```sh bin/package make ``` To suppress compiler output, use `quiet make` instead of `make`. In some non-POSIX shells you might need to prepend `sh` to all calls to `bin/package`. The compiled binaries are stored in the `arch` directory, in a subdirectory that corresponds to your architecture. The command `bin/package host type` outputs the name of this subdirectory. Dynamically linked binaries, if supported for your system, are stored in `dyn/bin` and `dyn/lib` subdirectories of your architecture directory. If built, they are built in addition to the statically linked versions. Export `AST_NO_DYLIB` to deactivate building dynamically linked versions. If you have trouble or want to tune the binaries, you may pass additional compiler and linker flags. It is usually best to export these as environment variables *before* running `bin/package` as they could change the name of the build subdirectory of the `arch` directory, so exporting them is a convenient way to keep them consistent between build and test commands. **Note that this system uses `CCFLAGS` instead of the usual `CFLAGS`.** An example that makes Solaris Studio cc produce a 64-bit binary: ```sh export CCFLAGS="-m64 -O" LDFLAGS="-m64" bin/package make ``` Alternatively you can append these to the command, and they will only be used for that command. You can also specify an alternative shell in which to run the build scripts this way. For example: ```sh bin/package make SHELL=/bin/bash CCFLAGS="-O2 -I/opt/local/include" LDFLAGS="-L/opt/local/lib" ``` **Note:** Do not add compiler flags that cause the compiler to emit terminal escape codes, such as `-fdiagnostics-color=always`; this will cause the build to fail as the probing code greps compiler diagnostics. Additionally, do not add the `-ffast-math` compiler flag; arithmetic bugs will occur when using that flag. For more information run ```sh bin/package help ``` Many other commands in this repo self-document via the `--help`, `--man` and `--html` options; those that do have no separate manual page. The autoloadable `man` function in [`src/cmd/ksh93/fun/man`](https://github.com/ksh93/ksh/blob/1.0/src/cmd/ksh93/fun/man) integrates this self-documentation into your regular `man` command. ### Test After compiling, you can run the regression tests. To run the default test sets for ksh and the build system, use: ```sh bin/package test ``` For ksh, use the `shtests` command directly to control the regression test runs. Start by reading the information printed by: ```sh bin/shtests --man ``` To hand-test ksh (as well as the utilities and the autoloadable functions that come with it) without installing, run: ```sh bin/package use ``` ### Install Usage: `bin/package install` *destination_directory* [ *command* ... ] Any command from the `arch` directory can be installed. If no *command* is specified, `ksh` and `shcomp` are assumed. The *destination_directory* is created if it does not exist. Commands are installed in its `bin` subdirectory and each command's manual page, if available, is installed in `share/man`. Destination directories with whitespace or shell pattern characters in their pathnames are not yet supported. If a dynamically linked version of ksh and associated commands has been built, then the `install` subcommand will prefer that: commands, dynamic libraries and associated header files will be installed then. To install the statically linked version instead (and skip the header files), either delete the `dyn` subdirectory, or export `AST_NO_DYLIB=y` before building to prevent it from being created in the first place. ## What is ksh93? The following is the official AT&T description from 1993 that came with the ast-open distribution. The text is original, but hyperlinks were added here. ---- KSH-93 is the most recent version of the KornShell Language described in "The KornShell Command and Programming Language," by Morris Bolsky and David Korn of AT&T Bell Laboratories, ISBN 0-13-182700-6. The KornShell is a shell programming language, which is upward compatible with "sh" (the Bourne Shell), and is intended to conform to the IEEE P1003.2/ISO 9945.2 [Shell and Utilities standard](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/contents.html). KSH-93 provides an enhanced programming environment in addition to the major command-entry features of the BSD shell "csh". With KSH-93, medium-sized programming tasks can be performed at shell-level without a significant loss in performance. In addition, "sh" scripts can be run on KSH-93 without modification. The code should conform to the [IEEE POSIX 1003.1 standard](https://www.opengroup.org/austin/papers/posix_faq.html) and to the proposed ANSI C standard so that it should be portable to all such systems. Like the previous version, KSH-88, it is designed to accept eight bit character sets transparently, thereby making it internationally compatible. It can support multi-byte characters sets with some characteristics of the character set given at run time. KSH-93 provides the following features, many of which were also inherent in KSH-88: * Enhanced Command Re-entry Capability: The KSH-93 history function records commands entered at any shell level and stores them, up to a user-specified limit, even after you log off. This allows you to re-enter long commands with a few keystrokes - even those commands you entered yesterday. The history file allows for eight bit characters in commands and supports essentially unlimited size histories. * In-line Editing: In "sh", the only way to fix mistyped commands is to backspace or retype the line. KSH-93 allows you to edit a command line using a choice of EMACS-TC or "vi" functions. You can use the in-line editors to complete filenames as you type them. You may also use this editing feature when entering command lines from your history file. A user can capture keystrokes and rebind keys to customize the editing interface. * Extended I/O Capabilities: KSH-93 provides several I/O capabilities not available in "sh", including the ability to: * specify a file descriptor for input and output * start up and run co-processes * produce a prompt at the terminal before a read * easily format and interpret responses to a menu * echo lines exactly as output without escape processing * format output using printf formats. * read and echo lines ending in "\\". * Improved performance: KSH-93 executes many scripts faster than the System V Bourne shell. A major reason for this is that many of the standard utilities are built-in. To reduce the time to initiate a command, KSH-93 allows commands to be added as built-ins at run time on systems that support dynamic loading such as System V Release 4. * Arithmetic: KSH-93 allows you to do integer arithmetic in any base from two to sixty-four. You can also do double precision floating point arithmetic. Almost the complete set of C language operators are available with the same syntax and precedence. Arithmetic expressions can be used to as an argument expansion or as a separate command. In addition, there is an arithmetic for command that works like the for statement in C. * Arrays: KSH-93 supports both indexed and associative arrays. The subscript for an indexed array is an arithmetic expression, whereas, the subscript for an associative array is a string. * Shell Functions and Aliases: Two mechanisms - functions and aliases - can be used to assign a user-selected identifier to an existing command or shell script. Functions allow local variables and provide scoping for exception handling. Functions can be searched for and loaded on first reference the way scripts are. * Substring Capabilities: KSH-93 allows you to create a substring of any given string either by specifying the starting offset and length, or by stripping off leading or trailing substrings during parameter substitution. You can also specify attributes, such as upper and lower case, field width, and justification to shell variables. * More pattern matching capabilities: KSH-93 allows you to specify extended regular expressions for file and string matches. * KSH-93 uses a hierarchical name space for variables. Compound variables can be defined and variables can be passed by reference. In addition, each variable can have one or more disciplines associated with it to intercept assignments and references. * Improved debugging: KSH-93 can generate line numbers on execution traces. Also, I/O redirections are now traced. There is a DEBUG trap that gets evaluated before each command so that errors can be localized. * Job Control: On systems that support job control, including System V Release 4, KSH-93 provides a job-control mechanism almost identical to that of the BSD "csh", version 4.1. This feature allows you to stop and restart programs, and to move programs between the foreground and the background. * Added security: KSH-93 can execute scripts which do not have read permission and scripts which have the setuid and/or setgid set when invoked by name, rather than as an argument to the shell. It is possible to log or control the execution of setuid and/or setgid scripts. The noclobber option prevents you from accidentally erasing a file by redirecting to an existing file. * KSH-93 can be extended by adding built-in commands at run time. In addition, KSH-93 can be used as a library that can be embedded into an application to allow scripting. Documentation for KSH-93 consists of an "Introduction to KSH-93", "Compatibility with the Bourne Shell" and a manual page and a README file. In addition, the "New KornShell Command and Programming Language" book is available from Prentice Hall. ksh-1.0.10/TODO000066400000000000000000000034351465301102200130450ustar00rootroot00000000000000The following bugs and issues are known for ksh 93u+m 1.0.10: Memory leak when initialising associative array in subshell https://github.com/ksh93/ksh/issues/94 command substitution botches output of non-waited-for child processes https://github.com/ksh93/ksh/issues/124 Segfault with very large extended glob patterns https://github.com/ksh93/ksh/issues/207 process substitution cannot be part of a larger argument https://github.com/ksh93/ksh/issues/215 Builtins don't handle I/O errors https://github.com/ksh93/ksh/issues/313 Associative arrays of various types fail to be unset https://github.com/ksh93/ksh/issues/345 Variable with discipline function in subshell causes memory leak https://github.com/ksh93/ksh/issues/404 Memory leak(s) when modifying PATH in various contexts https://github.com/ksh93/ksh/issues/405 Discipline function .unset only called once for array subscripts https://github.com/ksh93/ksh/issues/419 Function autoload apparently broken on DragonFly BSD https://github.com/ksh93/ksh/issues/432 nameref fails with nested associative arrays https://github.com/ksh93/ksh/issues/594 globstar fails to resolve symlink https://github.com/ksh93/ksh/issues/629 Race condition in job notification https://github.com/ksh93/ksh/issues/655 ksh remains in "noecho" mode forever https://github.com/ksh93/ksh/issues/672 bogus typeset -p output for compounds with disciplines https://github.com/ksh93/ksh/issues/729 test a = a b: undetected error https://github.com/ksh93/ksh/issues/739 Occasional "write error" when writing to pipe https://github.com/ksh93/ksh/issues/741 sleep 10 | read hangs interactive shell after ^Z https://github.com/ksh93/ksh/issues/750 Shell arithmetic is broken for integer values beyond the system's maximum float precision https://github.com/ksh93/ksh/issues/771 ksh-1.0.10/bin/000077500000000000000000000000001465301102200131205ustar00rootroot00000000000000ksh-1.0.10/bin/package000077500000000000000000002407151465301102200144520ustar00rootroot00000000000000######################################################################## # # # This software is part of the ast package # # Copyright (c) 1994-2012 AT&T Intellectual Property # # Copyright (c) 2020-2024 Contributors to ksh 93u+m # # and is licensed under the # # Eclipse Public License, Version 2.0 # # # # A copy of the License is available at # # https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html # # (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) # # # # Glenn Fowler # # Martijn Dekker # # Trey Valenta # # Johnothan King # # Sterling Jensen <5555776+sterlingjensen@users.noreply.github.com> # # Chase # # Anuradha Weeraman # # # ######################################################################## ### this sh script is POSIX compliant and compatible with shell bugs ### # KornShell 93u+m build system, main control script # # based on AST 'package' by Glenn Fowler # # simplified and rewritten by Martijn Dekker # ######################################################################## # Escape from a non-POSIX shell min_posix=/if/this/is/csh/ignore/the/error/message || exec sh $0:q $argv:q # ('test X -ef Y' is technically non-POSIX, but practically universal) min_posix='test / -ef / && path=Bad && case $PATH in (Bad) exit 1;; esac && '\ 'PWD=Bad && cd -P -- / && case $PWD in (/) ;; (*) exit 1;; esac && '\ '! { ! case x in ( x ) : ${0##*/} || : $( : ) ;; esac; } && '\ 'trap "exit 0" 0 && exit 1' if (eval "$min_posix") 2>/dev/null then : good shell else "$SHELL" -c "$min_posix" 2>/dev/null && exec "$SHELL" -- "$0" ${1+"$@"} sh -c "$min_posix" 2>/dev/null && exec sh -- "$0" ${1+"$@"} DEFPATH=`getconf PATH 2>/dev/null` || DEFPATH=/usr/xpg4/bin:/bin:/usr/bin:/sbin:/usr/sbin PATH=$DEFPATH:$PATH export PATH sh -c "$min_posix" 2>/dev/null && exec sh -- "$0" ${1+"$@"} echo "$0: Can't escape from obsolete or broken shell. Run me with a POSIX shell." >&2 exit 128 fi readonly min_posix # use for checksh() # Set standards compliance mode (command set -o posix) 2>/dev/null && set -o posix # As this code heavily uses field splitting of unquoted variable expansions, # turn off global pathname expansion for safety (turn on locally in subshells) set -o noglob # Sanitize 'cd' unset CDPATH # Make the package root the current working directory # This makes it possible to run '/my/path/package make' without cd'ing first # (for all its featuritis, the AT&T version never could manage this) case $0 in [0123456789+-]*) echo "dodgy \$0: $0" >&2 exit 128 ;; */*) me=$0 ;; *) me=$(command -v "$0") || exit 128 ;; esac me=$(dirname "$me") cd "$me" || exit unset -v me case $PWD in */arch/*/*/bin) cd .. ;; */arch/*/bin) cd ../../.. ;; */bin) cd .. ;; *) echo "this script must live in bin/" >&2 exit 1 ;; esac || exit # shell checks checksh() { "$1" -c "$min_posix" 2>/dev/null || return 1 } # simple shell-quoting function # usage: shellquote VARNAME # NOTE: a valid variable name is assumed shellquote() { eval "_q_=\${$1}" case ${_q_} in *\'*) # change every ' to '\'' # protect final linefeeds from being stripped by the $(comsub) by adding a trailing X _q_=$(printf '%sX' "${_q_}" | sed "s/'/'\\\\''/g") || exit # remove the trailing X _q_=${_q_%X} ;; esac # add leading/trailing ' and store back in given variable eval "$1=\\'\${_q_}\\'" } LC_ALL=C export LC_ALL TMPDIR=${TMPDIR:-/tmp} export TMPDIR src="cmd contrib etc lib" use="/usr/common /exp /usr/local /usr/add-on /usr/addon /usr/tools /usr /opt" usr="/home" ccs="/usr/kvm /usr/ccs/bin" org="gnu GNU" makefiles="Mamfile" # ksh 93u+m no longer uses these: Nmakefile nmakefile Makefile makefile env="HOSTTYPE PACKAGEROOT INSTALLROOT PATH DEFPATH FPATH MANPATH" package_use='=$HOSTTYPE=$PACKAGEROOT=$INSTALLROOT=$EXECROOT=$CC=' CROSS=0 MAKESKIP=${MAKESKIP:-"*[-.]*"} all_types='*.*|sun4' # all but sun4 match *.* command=${0##*/} case $(getopts '[-][123:xyz]' opt --xyz 2>/dev/null; echo 0$opt) in 0123) USAGE=$' [-? @(#)$Id: '$command$' (ksh 93u+m) 2024-07-30 $ ] [-author?Glenn Fowler ] [-author?Contributors to https://github.com/ksh93/ksh] [-copyright?(c) 1994-2012 AT&T Intellectual Property] [-copyright?(c) 2020-2024 Contributors to ksh 93u+m] [-license?https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html] [+NAME?'$command$' - build, test and install ksh 93u+m] [+DESCRIPTION?The \b'$command$'\b command is the main control script for building and installing KornShell 93u+m. It is a POSIX \bsh\b(1) script coded for maximal portability. A POSIX shell and C compiler installation are the only requirements. All package files are in the \b$PACKAGEROOT\b directory tree. Binary package files are in the \b$INSTALLROOT\b (\b$PACKAGEROOT/arch/\b\ahosttype\a) tree, where \ahosttype\a=$(\bbin/package host type\b). See \bDETAILS\b for more information.] [+?Note that no environment variables need be set by the user; \b'$command$'\b determines the environment based on the current working directory. The \buse\b action starts a \bsh\b(1) with the environment initialized. \bCC\b, \bCCFLAGS\b, \bHOSTTYPE\b and \bSHELL\b may be set by explicit command argument assignments to override the defaults.] [+?The command arguments are composed of a sequence of words: zero or more \aqualifiers\a, one \aaction\a, and zero or more action-specific \aarguments\a, and zero or more \aname=value\a definitions. \boptget\b(3) documentation options such as \b--man\b, \b--html\b and \b--nroff\b are also supported. The default with no arguments is \bhost type\b.] [+?The qualifiers are:] { [+debug|environment?Show environment and actions but do not execute.] [+flat?With the \bmake\b action, create a flat view by linking all files from \b$INSTALLROOT\b, minus \b*.old\b files, onto their corresponding path under \b$PACKAGEROOT\b. Subsequent \bmake\b actions will update an existing flat view whether or not \bflat\b is specified. Only one architecture can have a flat view. If \bflat\b is specified with the \bclean\b action, then only clean up this flat view and do not delete \b$INSTALLROOT\b.] [+force?Force the action to override saved state.] [+never?Run make -N and show other actions.] [+only?Only operate on the specified packages.] [+quiet?Do not list captured action output.] [+show?Run make -n and show other actions.] [+verbose?Provide detailed action output.] [+DEBUG?Trace the package script actions in detail.] } [+?The actions are:] { [+clean | clobber?Clean up the flat view, if any. Then, unless \bflat\b was given, delete the \barch/\b\aHOSTTYPE\a hierarchy; this deletes all generated files and directories for \aHOSTTYPE\a. The hierarchy can be rebuilt by \b'$command$' make\b.] [+export\b [ \avariable\a ...]]?List \aname\a=\avalue\a for \avariable\a, one per line. If the \bonly\b attribute is specified then only the variable values are listed. If no variables are specified then \b'$env$'\b are assumed.] [+help\b [ \aaction\a ]]?Display help text on the standard error (standard output for \aaction\a).] [+host\b [ \aattribute\a ... ]]?List architecture/implementation dependent host information on the standard output. \btype\b is listed if no attributes are specified. Information is listed on a single line in \aattribute\a order. The attributes are:] { [+canon \aname\a?An external host type name to be converted to \b'$command$'\b syntax.] [+cpu?The number of CPUs; 1 if the host is not a multiprocessor.] [+name?The host name.] [+type?The host type, usually in the form \avendor\a.\aarchitecture\a, with an optional trailing -\aversion\a. The main theme is that type names within a family of architectures are named in a similar, predictable style. OS point release information is avoided as much as possible, but vendor resistance to release incompatibilities has for the most part been futile.] } [+install\b [ \adest_dir\a ]] [ \acommand\a ... ]]?Install commands from the \b$INSTALLROOT\b tree into appropriate subdirectories of \adest_dir\a. If \adest_dir\a does not exist, then it and any necessary subdirectories are created. \adest_dir\a can be a directory like \a/usr/local\a to install the \acommand\as directly, or a temporary directory like \a/tmp/pkgtree/usr\a to prepare for packaging with operating system-specific tools. Each \acommand\a is first searched in \b$INSTALLROOT/dyn/bin\b (dynamically linked version) and then in \b$INSTALLROOT/bin\b. If no \acommand\a is specified, then \aksh\a and \ashcomp\a are assumed.] [+make\b [ \apackage\a ]] [ \aoption\a ... ]] [ \atarget\a ... ]]?Build and install. The default \atarget\a is \binstall\b, which makes and installs \apackage\a. If the standard output is a terminal then the output is also captured in \b$INSTALLROOT/lib/package/gen/make.out\b. The build is done in the \b$INSTALLROOT\b directory tree viewpathed on top of the \b$PACKAGEROOT\b directory tree. Leaf directory names matching the \b|\b-separated shell pattern \b$MAKESKIP\b are ignored. The \bview\b action is done before making. \aoption\a operands are passed to the underlying make command.] [+results\b [ \bfailed\b ]] [ \bpath\b ]] [ \bold\b ]] [\bmake\b | \btest\b | \bwrite\b ]]?List results and interesting messages captured by the most recent \bmake\b (default), \btest\b or \bwrite\b action. \bold\b specifies the previous results, if any (current and previous results are retained). \b$HOME/.pkgresults\b, if it exists, must contain an \begrep\b(1) expression of result lines to be ignored. \bfailed\b lists failures only and \bpath\b lists the results file path name only.] [+test\b [ \b\adir\a\b ]]\b?Run all available default regression tests. If the optional \adir\a argument (such as \bsrc/cmd/ksh93\b) is given, only the tests in that directory are run. If the standard output is a terminal then the output is also captured in \b$INSTALLROOT/lib/package/gen/test.out\b. Programs must be made before they can be tested. For \bksh\b, a separate \bshtests\b command is available that allows passing arguments to select and tune the regression tests. See \bbin/shtests --man\b for more information.] [+use\b [ \auid\a | \apackage\a | . | - [ command ... ]] ]]?Run \acommand\a, or an interactive shell if \acommand\a is omitted, with the environment initialized for using the package. If \auid\a or \apackage\a or \a.\a is specified then it is used to determine a \b$PACKAGEROOT\b, possibly different from the current directory. For example, to try out bozo'\'$'s package: \bpackage use bozo\b. The \buse\b action may be run from any directory. If the file \b$INSTALLROOT/lib/package/profile\b is readable then it is sourced to initialize the environment.] [+view\b?Initialize the architecture specific viewpath hierarchy. The \bmake\b action implicitly calls this action.] } [+DETAILS?The package directory hierarchy is rooted at \b$PACKAGEROOT\b. All source and binaries reside under this tree. A two level viewpath is used to separate source and binaries. The top view is architecture specific, the bottom view is shared source. All building is done in the architecture specific view; no source view files are intentionally changed. This means that many different binary architectures can be made from a single copy of the source.] [+?Independent \b$PACKAGEROOT\b hierarchies can be combined by appending \b$INSTALLROOT:$PACKAGEROOT\b pairs to \bVPATH\b. The \bVPATH\b viewing order is from left to right.] [+?\b$HOSTTYPE\b names the current binary architecture and is determined by the output of \b'$command$'\b (no arguments). The \b$HOSTTYPE\b naming scheme is used to separate incompatible executable and object formats. All architecture specific binaries are placed under \b$INSTALLROOT\b (\b$PACKAGEROOT/arch/$HOSTTYPE\b). There are a few places that match against \b$HOSTTYPE\b when making binaries; these are limited to makefile compiler workarounds, e.g., if \b$HOSTTYPE\b matches \bhp.*\b then turn off the optimizer for these objects. All other architecture dependent logic is handled either by the \bAST\b \biffe\b(1) command or by component specific configure scripts. Explicit \b$HOSTTYPE\b values matching *,*cc*[,-*,...]] optionally set the default \bCC\b and \bCCFLAGS\b. This is handy for build farms that support different compilers on the same architecture.] [+?Each component contains a \bMAM\b (make abstract machine) file (\bMamfile\b). A Mamfile contains a portable makefile description written in a simple dependency tree language using indented \bmake\b...\bdone\b blocks.] [+?All scripts and commands under \b$PACKAGEROOT\b use \b$PATH\b relative pathnames (via the \bAST\b \bpathpath\b(3) function); there are no embedded absolute pathnames. This means that binaries generated under \b$PACKAGEROOT\b may be copied to a different root; users need only change their \b$PATH\b variable to reference the new installation root \bbin\b directory. \b'$command$' install\b installs binary packages in a new \b$INSTALLROOT\b.] [ qualifier ... ] [ action ] [ arg ... ] [ n=v ... ] [+SEE ALSO?\bautoconfig\b(1), \bcksum\b(1), \bexpmake\b(1), \bgzip\b(1), \bmake\b(1), \bmamake\b(1), \bpax\b(1), \bpkgadd\b(1), \bpkgmk\b(1), \brpm\b(1), \bsh\b(1), \btar\b(1), \boptget\b(3)] ' case $* in help) set -- --man ;; esac while getopts -a "$command" "$USAGE" OPT do : done shift $((OPTIND-1)) ;; esac # check the args case $AR in '') AR=ar ;; esac case $CC in '') CC=cc ;; esac case $LD in '') LD=ld ;; esac case $NM in '') NM=nm ;; esac action= bit= exec= flat=0 force=0 global= hi= ifs=${IFS-' '} lo= make= makeflags='' nl=" " noexec= only=0 output= quiet=0 show=: tab=" " verbose=0 AUTHORIZE= DEBUG= unset FIGNORE BINDIR DLLDIR ETCDIR FUNDIR INCLUDEDIR LIBDIR LOCALEDIR MANDIR SHAREDIR 2>/dev/null || true while : do case $# in 0) set host type ;; esac case $1 in clean|clobber|export|host|install|make|results|test|use|view) action=$1 shift break ;; debug|environment) exec=echo make=echo show=echo ;; flat) flat=1 ;; force) force=1 ;; never) exec=echo noexec=-N ;; only) only=1 ;; quiet) quiet=1 ;; show) exec=echo noexec=-n ;; verbose)verbose=1 ;; DEBUG) DEBUG=1 PS4='+$LINENO:$SECONDS+ ' set -x ;; help|HELP|html|man|--[?m]*) case $1 in help) code=0 case $2 in '') exec 1>&2 ;; esac ;; html) code=0 html=1 echo "$command help

$command help

"
			;;
		*)	code=2
			exec 1>&2
			;;
		esac
		# Plain-text fallback. Regenerate with:
		# ksh -c 'COLUMNS=80 bin/package --man' 2>&1 | sed "s/'/'\\\\''/g; 1s/^/echo '/; \$s/\$/'/"
		echo 'NAME
  package - build, test and install ksh 93u+m

SYNOPSIS
  package [ options ] [ qualifier ... ] [ action ] [ arg ... ] [ n=v ... ]

DESCRIPTION
  The package command is the main control script for building and installing
  KornShell 93u+m. It is a POSIX sh(1) script coded for maximal portability. A
  POSIX shell and C compiler installation are the only requirements. All
  package files are in the $PACKAGEROOT directory tree. Binary package files
  are in the $INSTALLROOT ($PACKAGEROOT/arch/hosttype) tree, where
  hosttype=$(bin/package host type). See DETAILS for more information.

  Note that no environment variables need be set by the user; package
  determines the environment based on the current working directory. The use
  action starts a sh(1) with the environment initialized. CC, CCFLAGS, HOSTTYPE
  and SHELL may be set by explicit command argument assignments to override the
  defaults.

  The command arguments are composed of a sequence of words: zero or more
  qualifiers, one action, and zero or more action-specific arguments, and zero
  or more name=value definitions. optget(3) documentation options such as
  --man, --html and --nroff are also supported. The default with no arguments
  is host type.

  The qualifiers are:
    debug|environment
          Show environment and actions but do not execute.
    flat  With the make action, create a flat view by linking all files from
          $INSTALLROOT, minus *.old files, onto their corresponding path under
          $PACKAGEROOT. Subsequent make actions will update an existing flat
          view whether or not flat is specified. Only one architecture can have
          a flat view. If flat is specified with the clean action, then only
          clean up this flat view and do not delete $INSTALLROOT.
    force Force the action to override saved state.
    never Run make -N and show other actions.
    only  Only operate on the specified packages.
    quiet Do not list captured action output.
    show  Run make -n and show other actions.
    verbose
          Provide detailed action output.
    DEBUG Trace the package script actions in detail.

  The actions are:
    clean | clobber
          Clean up the flat view, if any. Then, unless flat was given, delete
          the arch/HOSTTYPE hierarchy; this deletes all generated files and
          directories for HOSTTYPE. The hierarchy can be rebuilt by package
          make.
    export [ variable ...]
          List name=value for variable, one per line. If the only attribute is
          specified then only the variable values are listed. If no variables
          are specified then HOSTTYPE PACKAGEROOT INSTALLROOT PATH FPATH
          MANPATH are assumed.
    help [ action ]
          Display help text on the standard error (standard output for action).
    host [ attribute ... ]
          List architecture/implementation dependent host information on the
          standard output. type is listed if no attributes are specified.
          Information is listed on a single line in attribute order. The
          attributes are:
            canon name
                  An external host type name to be converted to package syntax.
            cpu   The number of CPUs; 1 if the host is not a multiprocessor.
            name  The host name.
            type  The host type, usually in the form vendor.architecture, with
                  an optional trailing -version. The main theme is that type
                  names within a family of architectures are named in a
                  similar, predictable style. OS point release information is
                  avoided as much as possible, but vendor resistance to release
                  incompatibilities has for the most part been futile.
    install [ dest_dir ] [ command ... ]
          Install commands from the $INSTALLROOT tree into appropriate
          subdirectories of dest_dir. If dest_dir does not exist, then it and
          any necessary subdirectories are created. dest_dir can be a directory
          like /usr/local to install the commands directly, or a temporary
          directory like /tmp/pkgtree/usr to prepare for packaging with
          operating system-specific tools. Each command is first searched in
          $INSTALLROOT/dyn/bin (dynamically linked version) and then in
          $INSTALLROOT/bin. If no command is specified, then ksh and shcomp
          are assumed.
    make [ package ] [ option ... ] [ target ... ]
          Build and install. The default target is install, which makes and
          installs package. If the standard output is a terminal then the
          output is also captured in $INSTALLROOT/lib/package/gen/make.out. The
          build is done in the $INSTALLROOT directory tree viewpathed on top of
          the $PACKAGEROOT directory tree. Leaf directory names matching the
          |-separated shell pattern $MAKESKIP are ignored. The view action is
          done before making. option operands are passed to the underlying make
          command.
    results [ failed ] [ path ] [ old ] [make | test | write ]
          List results and interesting messages captured by the most recent
          make (default), test or write action. old specifies the previous
          results, if any (current and previous results are retained).
          $HOME/.pkgresults, if it exists, must contain an egrep(1) expression
          of result lines to be ignored. failed lists failures only and path
          lists the results file path name only.
    test [ dir ]
          Run all available default regression tests. If the optional dir
          argument (such as src/cmd/ksh93) is given, only the tests in that
          directory are run. If the standard output is a terminal then the
          output is also captured in $INSTALLROOT/lib/package/gen/test.out.
          Programs must be made before they can be tested. For ksh, a separate
          shtests command is available that allows passing arguments to select
          and tune the regression tests. See bin/shtests --man for more
          information.
    use [ uid | package | . | - [ command ... ] ]
          Run command, or an interactive shell if command is omitted, with the
          environment initialized for using the package. If uid or package or .
          is specified then it is used to determine a $PACKAGEROOT, possibly
          different from the current directory. For example, to try out bozo'\''s
          package: package use bozo. The use action may be run from any
          directory. If the file $INSTALLROOT/lib/package/profile is readable
          then it is sourced to initialize the environment.
    view  Initialize the architecture specific viewpath hierarchy. The make
          action implicitly calls this action.

DETAILS
  The package directory hierarchy is rooted at $PACKAGEROOT. All source and
  binaries reside under this tree. A two level viewpath is used to separate
  source and binaries. The top view is architecture specific, the bottom view
  is shared source. All building is done in the architecture specific view; no
  source view files are intentionally changed. This means that many different
  binary architectures can be made from a single copy of the source.

  Independent $PACKAGEROOT hierarchies can be combined by appending
  $INSTALLROOT:$PACKAGEROOT pairs to VPATH. The VPATH viewing order is from
  left to right.

  $HOSTTYPE names the current binary architecture and is determined by the
  output of package (no arguments). The $HOSTTYPE naming scheme is used to
  separate incompatible executable and object formats. All architecture
  specific binaries are placed under $INSTALLROOT
  ($PACKAGEROOT/arch/$HOSTTYPE). There are a few places that match against
  $HOSTTYPE when making binaries; these are limited to makefile compiler
  workarounds, e.g., if $HOSTTYPE matches hp.* then turn off the optimizer for
  these objects. All other architecture dependent logic is handled either by
  the AST iffe(1) command or by component specific configure scripts. Explicit
  $HOSTTYPE values matching *,*cc*[,-*,...] optionally set the default CC and
  CCFLAGS. This is handy for build farms that support different compilers on
  the same architecture.

  Each component contains a MAM (make abstract machine) file (Mamfile). A
  Mamfile contains a portable makefile description written in a simple
  dependency tree language using indented make...done blocks.

  All scripts and commands under $PACKAGEROOT use $PATH relative pathnames (via
  the AST pathpath(3) function); there are no embedded absolute pathnames. This
  means that binaries generated under $PACKAGEROOT may be copied to a different
  root; users need only change their $PATH variable to reference the new
  installation root bin directory. package install installs binary packages in
  a new $INSTALLROOT.

SEE ALSO
  autoconfig(1), cksum(1), expmake(1), gzip(1), make(1), mamake(1), pax(1),
  pkgadd(1), pkgmk(1), rpm(1), sh(1), tar(1), optget(3)

IMPLEMENTATION
  version         package (ksh 93u+m) 2024-07-30
  author          Glenn Fowler 
  author          Contributors to https://github.com/ksh93/ksh
  copyright       (c) 1994-2012 AT&T Intellectual Property
  copyright       (c) 2020-2024 Contributors to ksh 93u+m
  license         https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html'
		case $1 in
		html)	echo "
" ;; esac exit $code ;; *=*) set DEFAULT host type "$@" ;; *) # simulate AST getopt(3) usage output echo "Usage: $command [ options ] [ qualifier ... ] [ action ] [ arg ... ] [ n=v ... ]" >&2 echo " Help: $command [ --help | --man ] 2>&1" >&2 exit 2 ;; esac global="$global $1" shift done # gather HOSTTYPE *,* options # ,*cc*,-*,... set CC and CCFLAGS hostopts() { _ifs_=$IFS IFS=, set -- $HOSTTYPE IFS=$_ifs_ while : do case $# in 0|1) break ;; esac shift case $1 in *cc*) CC=$1 while : do case $# in 0|1) break ;; esac case $2 in -*) case $assign_CCFLAGS in ?*) assign_CCFLAGS="$assign_CCFLAGS " ;; esac assign_CCFLAGS="$assign_CCFLAGS$2" shift ;; *) break ;; esac done ;; esac done } # collect command line targets and definitions case $_PACKAGE_HOSTTYPE_ in ?*) HOSTTYPE=$_PACKAGE_HOSTTYPE_ KEEP_HOSTTYPE=1 ;; *) KEEP_HOSTTYPE=0 ;; esac KEEP_PACKAGEROOT=0 KEEP_SHELL=0 # set to 1 if SHELL is a known-good system shell, 2 if SHELL supplied by user USER_VPATH= args= assign= assign_CCFLAGS= for i do case $i in 'debug=1') makeflags="$makeflags --debug-symbols -e" ;; 'strip=1') makeflags="$makeflags --strip-symbols" ;; *=*) # treat as assignment if the variable name is valid n=${i%%=*} v=${i#*=} case $n in [!A-Za-z_]* | *[!A-Za-z0-9_]*) # if not, it's just a regular argument shellquote i args="$args $i" ;; esac vq=$v shellquote vq case $n in AR | LD | NM) assign="$assign $n=$vq" eval "$n=\$v" ;; CC) eval "$n=\$v" ;; CCFLAGS) eval "$n=\$v" assign_CCFLAGS="CCFLAGS=\"\$CCFLAGS\"" ;; HOSTTYPE) eval "$n=\$v" case $HOSTTYPE in ?*) KEEP_HOSTTYPE=1 ;; esac ;; PACKAGEROOT) eval "$n=\$v" case $PACKAGEROOT in ?*) KEEP_PACKAGEROOT=1 ;; esac ;; SHELL) eval "$n=\$v" case $SHELL in ?*) KEEP_SHELL=2 ;; esac ;; VPATH) eval "USER_$n=\$v" ;; *) assign="$assign $n=$vq" ;; esac ;; *) shellquote i args="$args $i" ;; esac done case $HOSTTYPE in *,*) hostopts $HOSTTYPE ;; esac case $assign_CCFLAGS in ?*) assign="$assign $assign_CCFLAGS" esac case $CC in ''|cc) ;; *) export CC ;; esac # grab action specific args case $action in use) case $1 in .) shift PACKAGEROOT=$PWD $show export PACKAGEROOT esac ;; esac # true if arg is a valid PACKAGEROOT packageroot() # dir { test -d "$1/lib/$command" || test -x "$1/bin/$command" } # true if arg is executable executable() # [!] command { case $1 in '!') test ! -x "$2" && test ! -x "$2.exe" ;; *) test -x "$1" || test -x "$1.exe" ;; esac } # true if arg is executable command on $PATH onpath() # command { _onpath_b=$1 case $_onpath_b in /*) if executable $_onpath_b then _onpath_=$_onpath_b return 0 fi return 1 ;; esac IFS=':' set -- $PATH IFS=$ifs for _onpath_d do case $_onpath_d in '') _onpath_d=. ;; esac if executable "$_onpath_d/$_onpath_b" then _onpath_=$_onpath_d/$_onpath_b return 0 fi done return 1 } # determine local host attributes hostinfo() # attribute ... { case $DEBUG in 1) set -x ;; esac map= something= path=$PATH for i in $ccs do PATH=$PATH:$i done for i in $use do for j in $org do PATH=$PATH:$i/$j/bin done PATH=$PATH:$i/bin done case $PACKAGE_PATH in ?*) for i in $(echo "$PACKAGE_PATH" | sed 's,:, ,g') do PATH=$PATH:$i/bin done ;; esac # validate the args canon= cc=$CC for info do case $canon in -) canon=$info ;; *) case $info in */*|*[cC][cC]) cc=$info ;; canon) canon=- something=1 ;; cpu|name|type) something=1 ;; *) err_out "$action: $info: unknown attribute" ;; esac ;; esac done case $canon in -) err_out "$action: canon: host type name expected" ;; esac case $something in "") set "$@" type ;; esac case $DEBUG in '') exec 9>&2 exec 2>/dev/null ;; esac # compute the info _hostinfo_= for info do case $info in cpu) cpu=$(sysctl -n hw.ncpu) case $cpu in [123456789]*) _hostinfo_="$_hostinfo_ $cpu" continue ;; esac cpu=$(grep -ic '^processor[ ][ ]*:[ ]*[0123456789]' /proc/cpuinfo) case $cpu in [123456789]*) _hostinfo_="$_hostinfo_ $cpu" continue ;; esac cpu=1 # exact match set \ hinv '^Processor [0123456789]' \ psrinfo 'on-line' \ 'cat /reg/LOCAL_MACHINE/Hardware/Description/System/CentralProcessor' '.' \ 'cat /proc/registry/HKEY_LOCAL_MACHINE/Hardware/Description/System/CentralProcessor' '.' \ while : do case $# in 0) break ;; esac i=$($1 2>/dev/null | grep -c "$2") case $i in [123456789]*) cpu=$i break ;; esac shift;shift done case $cpu in 0|1) set \ /bin/mpstat while : do case $# in 0) break ;; esac if executable $1 then case $($1 | grep -ic '^cpu ') in 1) cpu=$($1 | grep -ic '^ *[0123456789][0123456789]* ') break ;; esac fi shift done ;; esac case $cpu in 0|1) # token match set \ /usr/kvm/mpstat 'cpu[0123456789]' \ /usr/etc/cpustatus 'enable' \ /usr/alliant/showsched 'CE' \ 'ls /config/hw/system/cpu' 'cpu' \ prtconf 'cpu-unit' \ while : do case $# in 0) break ;; esac i=$($1 2>/dev/null | tr ' ' ' ' | grep -c "^$2") case $i in [123456789]*) cpu=$i break ;; esac shift;shift done ;; esac case $cpu in 0|1) # special match set \ \ hinv \ '/^[0123456789][0123456789]* .* Processors*$/' \ '/[ ].*//' \ \ /usr/bin/hostinfo \ '/^[0123456789][0123456789]* .* physically available\.*$/' \ '/[ ].*//' \ while : do case $# in 0) break ;; esac i=$($1 2>/dev/null | sed -e "${2}!d" -e "s${3}") case $i in [123456789]*) cpu=$i break ;; esac shift;shift;shift done ;; esac case $cpu in 0|1) cpu=$( cd "$TMPDIR" tmp=hi$$ trap 'set +o noglob; rm -f $tmp.*' 0 1 2 cat > $tmp.c < #include int main(void) { printf("%d\n", pthread_num_processors_np()); return 0; } ! for o in -lpthread '' do if $CC $o -O -o $tmp.exe $tmp.c $o >/dev/null 2>&1 || gcc $o -O -o $tmp.exe $tmp.c $o >/dev/null 2>&1 then ./$tmp.exe break fi done ) case $cpu in [0123456789]*) ;; *) cpu=1 ;; esac ;; esac _hostinfo_="$_hostinfo_ $cpu" ;; name) _name_=$(hostname || uname -n || cat /etc/whoami || echo local) _hostinfo_="$_hostinfo_ $_name_" ;; type|canon) case $CROSS:$canon in 0:) case $cc in cc) case $KEEP_HOSTTYPE:$HOSTTYPE in 0:?*) if test -d ${PACKAGEROOT:-.}/arch/$HOSTTYPE then KEEP_HOSTTYPE=1 fi ;; esac ;; esac case $KEEP_HOSTTYPE in 1) _hostinfo_="$_hostinfo_ $HOSTTYPE" continue ;; esac ;; esac a=$($cc -dumpmachine $CCFLAGS 2>/dev/null) case $a in '') case $CCFLAGS in ?*) a=$($cc -dumpmachine 2>/dev/null) ;; esac ;; esac case $a in ''|*' '*|*/*:*) ;; *.*-*) _hostinfo_="$_hostinfo_ $a" continue ;; *-*-*) case $canon in '') canon=$a ;; esac ;; *-*) case $canon in '') canon=${a%-*}-unknown-${a#*-} ;; esac ;; *) _hostinfo_="$_hostinfo_ $a" continue ;; esac IFS=: set /$IFS$PATH IFS=$ifs shift f=../lib/hostinfo/typemap for i do case $i in "") i=. ;; esac case $canon in '') case $cc in /*|cc) ;; *) if executable $i/$cc then a=$($i/$cc -dumpmachine $CCFLAGS 2>/dev/null) case $a in '') case $CCFLAGS in ?*) a=$($cc -dumpmachine 2>/dev/null) ;; esac ;; esac case $a in ''|*' '*|*/*:*) ;; *-*) canon=$a ;; *) _hostinfo_="$_hostinfo_ $a" continue 2 ;; esac fi ;; esac ;; esac if test -f "$i/$f" then map="$(grep -v '^#' $i/$f) $map" fi done # inconsistent -dumpmachine filtered here case $canon in *-*-linux-gnu* | *-*-linux-musl*) ;; *-linux-gnu* | *-linux-musl*) # fix missing machine field, e.g. aarch64-linux-gnu => aarch64-unknown-linux-gnu canon=${canon%%-*}-unknown-${canon#*-} ;; *-linux-android*) # Android/Termux is very much its own thing, so identify it as 'android', not 'linux' canon=${canon%-linux-*}-android ;; esac case -${canon}- in --|*-powerpc-*) h=$(hostname || uname -n || cat /etc/whoami) case $h in '') h=local ;; esac a=$(arch || uname -m || att uname -m || uname -s || att uname -s) case $a in *[\ \ ]*) a=$(echo $a | sed "s/[ ]/-/g") ;; esac case $a in '') a=unknown ;; esac m=$(mach || machine || uname -p || att uname -p) case $m in *[\ \ ]*) m=$(echo $m | sed "s/[ ]/-/g") ;; esac case $m in '') m=unknown ;; esac x=$(uname -a || att uname -a) case $x in '') x="unknown $host unknown unknown unknown unknown unknown" ;; esac set "" $h $a $m $x expected=$1 host=$2 arch=$3 mach=$4 os=$5 sys=$6 rel=$7 ver=$8 ;; *) case $canon in *-*) IFS=- set "" $canon shift IFS=$ifs case $# in 2) host= mach= arch=$1 os=$2 sys= rel= ;; *) host= mach=$2 arch=$1 os=$3 sys= rel= ;; esac case $os in [abcdefghijklmnopqrstuvwxyz]*[0123456789]) eval $(echo $os | sed -e 's/^\([^0123456789.]*\)\.*\(.*\)/os=\1 rel=\2/') ;; esac ;; *) arch=$canon mach= os= sys= rel= ;; esac ;; esac type=unknown case $host in *.*) host=$(echo $host | sed -e 's/\..*//') ;; esac case $arch in aarch64) # some call it aarch64, some arm64 -- let's stick to one arch=arm64 ;; esac case $mach in unknown) mach= ;; [Rr][0123][0123456789][0123456789][0123456789]) mach=mips1 ;; [Rr][4][0123456789][0123456789][0123456789]) mach=mips2 ;; [Rr][56789][0123456789][0123456789][0123456789]|[Rr][123456789][0123456789][0123456789][0123456789][0123456789]) mach=mips4 ;; pc) arch=i386 mach= ;; [Pp][Oo][Ww][Ee][Rr][Pp][Cc]) arch=ppc mach= ;; *) case $arch in 34[0123456789][0123456789]) os=ncr arch=i386 ;; esac ;; esac case $canon in '') set \ \ /NextDeveloper -d next - \ /config/hw/system/cpu -d tandem mach \ while : do case $# in 0) break ;; esac if test $2 $1 then os=$3 case $4 in arch) mach=$arch ;; mach) arch=$mach ;; esac break fi shift;shift;shift;shift done ;; esac case $os in AIX*|aix*) type=ibm.risc ;; HP-UX) case $arch in 9000/[78]*) type=hp.pa ;; */*) type=hp.$(echo $arch | sed 's,/,_,g') ;; *) type=hp.$arch ;; esac ;; [Ii][Rr][Ii][Xx]*) set xx $(hinv | sed -e '/^CPU:/!d' -e 's/CPU:[ ]*\([^ ]*\)[ ]*\([^ ]*\).*/\1 \2/' -e q | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz) shift type=$1 n= case $2 in r[0123][0123456789][0123456789][0123456789]) n=1 ;; r[4][0123][0123456789][0123456789]) n=2 ;; r[4][456789][0123456789][0123456789]|r[5][0123456789][0123456789][0123456789]) n=3 ;; r[6789][0123456789][0123456789][0123456789]|r[123456789][0123456789][0123456789][0123456789][0123456789]) n=4 ;; esac case $rel in [01234].*|5.[012]|5.[012].*) case $n in 1) ;; *) n=2 ;; esac ;; 5.*) case $n in 2) n=3 ;; esac ;; esac if executable $cc then a=$cc else IFS=: set /$IFS$PATH IFS=$ifs shift for i do a=$i/$cc if executable $a then break fi done fi split=' ' a=$(strings $a < /dev/null | sed -e 's/[^abcdefghijklmnopqrstuvwxyz0123456789]/ /g' -e 's/[ ][ ]*/\'"$split"'/g' | sed -e "/^${type}[0123456789]$/!d" -e "s/^${type}//" -e q) case $a in [0123456789]) n=$a ;; esac case $n in 4) a=$($cc -${type}3 2>&1) case $a in *unknown*|*install*|*conflict*) ;; *) n=3 ;; esac ;; esac a=$($cc -show F0oB@r.c 2>&1) case $n:$a in [!2]:*mips2*) n=2 ;; [!23]:*mips3*) n=3 ;; [!234]:*mips4*) n=4 ;; esac case $n:$a in [!2]:*[Oo]32*) abi=-o32 ;; [!3]:*[Nn]32*) abi=-n32 ;; esac mach=${type}$n type=sgi.$mach ;; OSx*|SMP*|pyramid) type=pyr ;; OS/390) type=mvs.390 ;; [Ss][Cc][Oo]*) type=sco ;; [Ss]ol*) v=$(echo $rel | sed -e 's/^[25]\.//' -e 's/\.[^.]*$//') case $v in [6789]|[1-9][0-9]) ;; *) v= ;; esac case $arch in '') case $mach in '') arch=sun4 ;; *) arch=$mach ;; esac ;; esac case $arch in sparc) arch=sun4 ;; esac type=sol$v.$arch ;; [Ss]un*)type=$(echo $arch | sed -e 's/\(sun.\).*/\1/') case $type in sparc) type=sun4 ;; esac case $rel in [01234]*) ;; '') case $os in *[Oo][Ss]) ;; *) type=sol.$type ;; esac ;; *) case $type in '') case $mach in sparc*) type=sun4 ;; *) type=$mach ;; esac ;; esac v=$(echo $rel | sed -e 's/^[25]\.//' -e 's/\.[^.]*$//') case $v in [6789]|[1-9][0-9]) ;; *) v= ;; esac type=sol$v.$type ;; esac case $type in sun*|*.*) ;; *) type=sun.$type ;; esac ;; [Uu][Nn][Ii][Xx]_[Ss][Vv]) type=unixware ;; UTS*|uts*) if test -x /bin/u370 || test -x /bin/u390 then type=uts.390 else case $arch in '') arch=$mach ;; esac type=uts.$arch fi ;; $host) type=$arch case $type in *.*|*[0123456789]*86|*68*) ;; *) case $mach in *[0123456789]*86|*68*|mips) type=$type.$mach ;; esac ;; esac ;; unknown) case $arch in ?*) case $arch in sun*) mach= ;; esac type=$arch case $mach in ?*) type=$type.$mach ;; esac ;; esac ;; *) case $ver in FTX*|ftx*) case $mach in *[0123456789][abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]*) mach=$(echo $mach | sed -e 's/[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]*$//') ;; esac type=stratus.$mach ;; *) case $arch in [Oo][Ss][-/.]2) type=os2 arch=$rel ;; *) type=$(echo $os | sed -e 's/[0123456789].*//' -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_0123456789.].*//') ;; esac case $type in [Cc][Yy][Gg][Ww][Ii][Nn]_*) type=cygwin ;; esac case $arch in '') case $mach in ?*) type=$type.$mach ;; esac ;; *) type=$type.$arch ;; esac ;; esac esac case $type in [0123456789]*) case $mach in ?*) type=$mach ;; esac case $type in */MC) type=ncr.$type ;; esac ;; *.*) ;; *[0123456789]*86|*68*) case $rel in [34].[0123456789]*) type=att.$type ;; esac ;; [abcdefghijklmnopqrstuvwxyz]*[0123456789]) ;; [abcdefghijklmnopqrstuvwxyz]*) case $mach in $type) case $ver in Fault*|fault*|FAULT*) type=ft.$type ;; esac ;; ?*) case $arch in '') type=$type.$mach ;; *) type=$type.$arch ;; esac ;; esac ;; esac case $type in *[-_]32|*[-_]64|*[-_]128) bits=$(echo $type | sed 's,.*[-_],,') type=$(echo $type | sed 's,[-_][0-9]*$,,') ;; *) bits= ;; esac type=$(echo $type | sed -e 's%[-+/].*%%' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz) case $type in *.*) lhs=$(echo $type | sed -e 's/\..*//') rhs=$(echo $type | sed -e 's/.*\.//') case $rhs in [x0123456789]*86) rhs=i$rhs ;; 68*) rhs=m$rhs ;; esac case $rhs in i[x23456789]86|i?[x23456789]86|*86pc) rhs=i386 ;; powerpc) rhs=ppc ;; s[0123456789]*[0123456789]x) rhs=$(echo $rhs | sed -e 's/x$/-64/') ;; esac case $rhs in arm[abcdefghijklmnopqrstuvwxyz_][0123456789]*) rhs=arm ;; hppa) rhs=pa ;; esac case $lhs in ?*coff|?*dwarf|?*elf) case $lhs in ?*coff) x=coff ;; ?*dwarf)x=coff ;; ?*elf) x=elf ;; esac lhs=$(echo ${lhs}XXX | sed -e "s/${x}XXX//") ;; esac case $lhs in bsdi) lhs=bsd ;; darwin) case $(/usr/bin/cc --version) in *'(GCC)'*) case $rel in '' | [0-9].* | 10.*) lhs=darwin07 ;; *) lhs=darwin11 ;; esac ;; esac ;; freebsd) case $rel in [01234].*) lhs=${lhs}4 ;; [123456789]*.*) lhs=${lhs}$(echo $rel | sed -e 's/\..*//') ;; esac ;; hpux) lhs=hp ;; mvs) rhs=390 ;; esac case $lhs in '') type=$rhs ;; $rhs) type=$lhs ;; *) type=$lhs.$rhs ;; esac ;; esac case $type in sgi.mips*) case $mach in mips2) type=sgi.$mach abi=-o32 ;; mips3) type=sgi.$mach abi=-n32 ;; mips[456789]) type=sgi.$mach case $abi in *-n32) ;; *) abi=-64 ;; esac ;; *) pwd=$PWD cd "$TMPDIR" tmp=hi$$ trap 'set +o noglob; rm -rf $tmp.*' 0 1 2 cat > $tmp.a.c < $tmp.b.c </dev/null 2>&1 (set +o noglob; rm -rf $tmp.*) trap - 0 1 2 cd $pwd ;; esac case $type$abi in sgi.mips2-o32) ;; sgi.mips3) type=$type-o32 ;; sgi.mips3-n32) ;; sgi.mips4) type=$type-o32 ;; sgi.mips[456789]-64) ;; *) type=$type$abi ;; esac ;; *) case $bits in '') bits=$( set -e cd "$TMPDIR" tmp=hi$$ trap 'set +o noglob; rm -rf "$tmp".*' 0 1 2 echo 'int main(void) { return 0; }' > $tmp.a.c checkcc $cc $CCFLAGS -o $tmp.a.exe $tmp.a.c /dev/null 2>&1 file $tmp.a.exe 2>/dev/null | sed "s/$tmp\.a\.exe//g" ) case $bits in *\ 64-bit* | *\ 64\ bit* | *\ 64bit*) bits=64 ;; *) bits= ;; esac ;; esac ;; esac case $bits in 32) case $type in *.i386) bits= ;; esac ;; esac case $bits in ?*) type=$type-$bits ;; esac # last chance mapping set "" "" $map while : do case $# in [012]) break ;; esac shift;shift eval " case \$type in $1) type=\$2; break ;; esac" done _hostinfo_="$_hostinfo_ $type" ;; esac done set -- $_hostinfo_ _hostinfo_=$* # restore the global state PATH=$path case $DEBUG in '') exec 2>&9 exec 9>&- ;; esac } # info message note() # message ... { printf "$command: %s\\n" "$@" >&2 } err_out() { note "$@" exit 1 } trace() ( PS4="${action}: executing: " exec 2>&1 # trace to standard output set -o xtrace "$@" ) trace() ( PS4="${action}: executing: " exec 2>&1 # trace to standard output set -o xtrace "$@" ) # cc checks # # CC: compiler base name name # cc: full path, empty if not found checkcc() { cc= if onpath $CC then cc=$_onpath_ else case $CC in cc) if onpath clang then CC=clang cc=$_onpath_ elif onpath gcc then CC=gcc cc=$_onpath_ fi ;; esac fi case $cc in '') case $action in make|test) err_out "$CC: not found" ;; *) note "warning: $CC: not found" ;; esac ;; esac } # output sanitized system $PATH, eliminating duplicate and nonexistent dirs, '..', etc. sanitize_PATH() ( set -fu +e IFS=':' unset -v CDPATH sPATH='' for dir in $1; do # Sanitize this path, resolving symlinks, # with special-casing of ksh's virtual built-ins directory case $dir in /opt/ast/bin) test ! -d "$dir" && sdir=$dir ;; */* | [!+-]* | [+-]*[!0123456789]*) sdir=$(cd -- $dir 2>/dev/null && pwd -P && echo X) ;; *) sdir=$(cd ./$dir 2>/dev/null && pwd -P && echo X) ;; esac || continue sdir=${sdir%?X} # Skip duplicates case :$sPATH: in *:"$sdir":*) continue ;; esac # Found one, add it sPATH=${sPATH:+$sPATH:}$sdir done printf '%s\n' "${sPATH#:}" ) # Ensure a sane $PATH beginning with standard utilities. # POSIXly, a simple 'getconf PATH' should do it, but reality is otherwise. # Find preferred getconf(1) on NixOS and Solaris/illumos. # Compile fallback programs on systems without getconf(1). DEFPATH=$( # support Android/Termux, NixOS, Solaris/illumos, generic /bin:/usr/bin PATH=/data/data/com.termux/files/usr/bin:/run/current-system/sw/bin:/usr/xpg7/bin:/usr/xpg6/bin:/usr/xpg4/bin:/bin:/usr/bin:$PATH getconf PATH 2>/dev/null || { # no getconf(1) -- try confstr(3) checkcc t=${TMPDIR:-/tmp}/path_test.$$ trap 'set +f; rm -rf "$t."*' 0 cat > $t.c <<-EOF #include #include int main(void) { char buf[8192]; size_t len = confstr(_CS_PATH, &buf, sizeof(buf)); if (len > 0 && len < sizeof(buf)) { printf("%s\n", buf); return 0; } return 1; } EOF $CC $CCFLAGS $LDFLAGS -o "$t.exe" "$t.c" 2>/dev/null && "$t.exe" } || { # no confstr(3) either -- try non-standard _PATH_DEFPATH cat > $t.c <<-EOF #include #include int main(void) { printf("%s\n", _PATH_DEFPATH); return 0; } EOF $CC $CCFLAGS $LDFLAGS -o "$t.exe" "$t.c" 2>/dev/null && "$t.exe" } ) || DEFPATH=/bin:/usr/bin:/sbin:/usr/sbin # Fix for Android/Termux. The /bin directory exists with standard # utilities (sh, Toybox utils) but it is not included in _PATH_DEFPATH. # It should come first because /bin is read-only. if test -d /data/data/com.termux && test "$(/bin/uname -o 2>/dev/null)" = Android then case ":$DEFPATH:" in *:/bin:* ) ;; * ) DEFPATH=/bin:$DEFPATH ;; esac fi # Fix for NixOS. Not all POSIX standard utilities come with the default system, # e.g. 'bc', 'file', 'vi'. The command that NixOS recommends to get missing # utilities, e.g. 'nix-env -iA nixos.bc', installs them in a default profile # directory that is not in $(getconf PATH). So add this path to the standard path. # See: https://github.com/NixOS/nixpkgs/issues/65512 if test -e /etc/NIXOS && nix_profile_dir=/nix/var/nix/profiles/default/bin && test -d "$nix_profile_dir" then case ":$DEFPATH:" in *:"$nix_profile_dir":* ) # nothing to do ;; * ) # insert the default profile directory as the second entry DEFPATH=$( set -f IFS=: set -- $DEFPATH one=$1 shift echo "$one:$nix_profile_dir${1+:}$*" ) ;; esac fi # Fix for AIX. At least as of version 7.1, the system default 'find', 'diff -u' and 'patch' utilities # are broken and/or non-compliant in ways that make them incompatible with POSIX 2018. However, GNU # utilities are commonly installed in /opt/freeware/bin, and under standard names (no g- prefix). if test -d /opt/freeware/bin then case $(uname) in AIX ) DEFPATH="/opt/freeware/bin:$DEFPATH" ;; esac fi export DEFPATH # for iffe, etc. PATH=$(sanitize_PATH "/opt/ast/bin:$DEFPATH:$PATH") # some actions have their own PACKAGEROOT or kick out early case $action in host) eval u=$package_use case $u in $PACKAGE_USE) ;; *) if onpath $0 then case $_onpath_ in */arch/$HOSTTYPE/bin/package) KEEP_HOSTTYPE=1 ;; *) KEEP_HOSTTYPE=0 ;; esac else KEEP_HOSTTYPE=0 fi ;; esac eval "hostinfo $args" echo $_hostinfo_ exit 0 ;; export|setup|use) x= ;; *) x= eval u=$package_use case $u in $PACKAGE_USE) case :$PATH: in *:$INSTALLROOT/bin:*) case $LD_LIBRARY_PATH: in $INSTALLROOT/dyn/lib:*) case $DYLD_LIBRARY_PATH: in $INSTALLROOT/dyn/lib:*) x=1 ;; esac ;; esac ;; esac ;; esac ;; esac run=- case $x in 1) : accept the current package use environment INITROOT=$PACKAGEROOT/src/cmd/INIT checkcc ;; *) hosttype= case $KEEP_PACKAGEROOT in 0) case $action in use) PACKAGEROOT= case $show in echo) exec=echo make=echo show=echo ;; esac eval "set -- $args" case $# in 0) ;; *) case $1 in -|.) ;; /*) PACKAGEROOT=$1 ;; *) i=$(echo ~$1) if packageroot $i then PACKAGEROOT=$i else for i in $(echo $HOME | sed -e 's,/[^/]*$,,') $usr $use do if packageroot $i/$1 then PACKAGEROOT=$i/$1 break fi done case $PACKAGEROOT in '') hosttype=$1 ;; esac fi ;; esac shift ;; esac run="$@" ;; esac case $PACKAGEROOT in '') PACKAGEROOT=$PWD ;; esac # . must be within the PACKAGEROOT tree i=X$PACKAGEROOT IFS=/ set $i IFS=$ifs while : do i=$1 shift case $i in X) break ;; esac done case $PACKAGEROOT in //*) d=/ ;; *) d= ;; esac case $1 in home) k=1 ;; *) k=0 ;; esac for i do case $i in '') continue ;; esac d=$d/$i case $k in 2) k=1 ;; 1) k=0 ;; 0) case $i in arch) k=2 ;; *) if packageroot $d then PACKAGEROOT=$d fi ;; esac ;; esac done ;; esac INITROOT=$PACKAGEROOT/src/cmd/INIT $show PACKAGEROOT=$PACKAGEROOT $show export PACKAGEROOT export PACKAGEROOT # initialize the architecture environment case $KEEP_HOSTTYPE in 0) hostinfo type HOSTTYPE=$_hostinfo_ ;; 1) _PACKAGE_HOSTTYPE_=$HOSTTYPE export _PACKAGE_HOSTTYPE_ ;; esac $show HOSTTYPE=$HOSTTYPE $show export HOSTTYPE export HOSTTYPE INSTALLROOT=$PACKAGEROOT/arch/$HOSTTYPE case $action in install|make|test|view) ;; *) if test ! -d $INSTALLROOT then INSTALLROOT=$PACKAGEROOT fi ;; esac $show INSTALLROOT=$INSTALLROOT $show export INSTALLROOT export INSTALLROOT # check the basic package hierarchy case $action in export|use) packageroot $PACKAGEROOT || err_out "$PACKAGEROOT: invalid package root directory" case $KEEP_HOSTTYPE:$hosttype in 0:?*) if test -d ${PACKAGEROOT:-.}/arch/$hosttype then KEEP_HOSTTYPE=1 HOSTTYPE=$hosttype else err_out "$hosttype: package root not found" fi ;; esac ;; *) packageroot $PACKAGEROOT || { case $KEEP_PACKAGEROOT in 1) ;; *) err_out "$PACKAGEROOT: must be in the package root directory tree" ;; esac } for i in arch arch/$HOSTTYPE do test -d $PACKAGEROOT/$i || $exec mkdir $PACKAGEROOT/$i || exit done for i in lib do test -d $INSTALLROOT/$i || $exec mkdir $INSTALLROOT/$i || exit done ;; esac path=$PATH PATH=$INSTALLROOT/bin:$PACKAGEROOT/bin:$PATH checkcc PATH=$path case $cc in ?*) if test -f $INITROOT/hello.c then # check if $CC (full path $cc) is a cross compiler ( cd "$TMPDIR" || exit 3 cp $INITROOT/hello.c pkg$$.c || exit 3 $cc -o pkg$$.exe pkg$$.c > pkg$$.e 2>&1 || { if $cc -Dnew=old -o pkg$$.exe pkg$$.c > /dev/null 2>&1 then err_out "${warn}$CC: must be a C compiler (not C++)" else cat pkg$$.e err_out "${warn}$CC: failed to compile and link $INITROOT/hello.c -- is it a C compiler?" fi } if ./pkg$$.exe >/dev/null 2>&1 then code=0 else code=1 fi (set +o noglob; rm -f pkg$$.*) exit $code ) code=$? case $code in 1) CROSS=1 ;; esac fi ;; esac EXECTYPE=$HOSTTYPE EXECROOT=$INSTALLROOT case $CROSS in 0) case $action in test | use) # Allow loading dynamic libraries from $INSTALLROOT/dyn/lib by setting library # path variables for various systems; instead of bothering to detect the system, # just set them all. (Note: not needed and potentially harmful while building.) case $LD_LIBRARY_PATH: in $INSTALLROOT/dyn/lib:*) ;; *) LD_LIBRARY_PATH=$INSTALLROOT/dyn/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} $show LD_LIBRARY_PATH=$LD_LIBRARY_PATH $show export LD_LIBRARY_PATH export LD_LIBRARY_PATH ;; esac case $LIBPATH: in $INSTALLROOT/dyn/bin:$INSTALLROOT/dyn/lib:*) ;; *) case $LIBPATH in '') LIBPATH=/usr/lib:/lib ;; esac LIBPATH=$INSTALLROOT/dyn/bin:$INSTALLROOT/dyn/lib:$LIBPATH $show LIBPATH=$LIBPATH $show export LIBPATH export LIBPATH ;; esac case $SHLIB_PATH: in $INSTALLROOT/dyn/lib:*) ;; *) SHLIB_PATH=$INSTALLROOT/dyn/lib${SHLIB_PATH:+:$SHLIB_PATH} $show SHLIB_PATH=$SHLIB_PATH $show export SHLIB_PATH export SHLIB_PATH ;; esac case $DYLD_LIBRARY_PATH: in $INSTALLROOT/dyn/lib:*) ;; *) DYLD_LIBRARY_PATH=$INSTALLROOT/dyn/lib${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH} $show DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH $show export DYLD_LIBRARY_PATH export DYLD_LIBRARY_PATH ;; esac case $_RLD_ROOT in $INSTALLROOT/arch*) ;; ':') _RLD_ROOT=$INSTALLROOT/arch:/ ;; /|*:/) _RLD_ROOT=$INSTALLROOT/arch:$_RLD_ROOT ;; *) _RLD_ROOT=$INSTALLROOT/arch:$_RLD_ROOT:/ ;; esac $show _RLD_ROOT=$_RLD_ROOT $show export _RLD_ROOT export _RLD_ROOT # Haiku case $LIBRARY_PATH: in $INSTALLROOT/dyn/lib:*) ;; *) LIBRARY_PATH=$INSTALLROOT/dyn/lib${LIBRARY_PATH:+:$LIBRARY_PATH} $show LIBRARY_PATH=$LIBRARY_PATH $show export LIBRARY_PATH export LIBRARY_PATH ;; esac ;; esac # now set up PATH # # NOTE: PACKAGEROOT==INSTALLROOT is possible for binary installations case $PATH: in $PACKAGEROOT/bin:*) ;; *) PATH=$PACKAGEROOT/bin:$PATH ;; esac case $PATH: in $INSTALLROOT/bin:*) ;; *) PATH=$INSTALLROOT/bin:$PATH test -n "${MANPATH+s}" && MANPATH=$INSTALLROOT/man:$MANPATH ;; esac case $PATH: in $INSTALLROOT/dyn/bin:*) ;; *) PATH=$INSTALLROOT/dyn/bin:$PATH ;; esac case $FPATH: in $INSTALLROOT/fun:*) ;; *) FPATH=$INSTALLROOT/fun${FPATH:+:$FPATH} ;; esac $show "export PATH=$PATH" export PATH $show "export FPATH=$FPATH" export FPATH if test -n "${MANPATH+s}" then export MANPATH $show "export MANPATH=$PATH" fi ;; *) for i in package do if onpath $i then EXECROOT=$(echo $_onpath_ | sed -e 's,//*[^/]*//*[^/]*$,,') EXECTYPE=$(echo $EXECROOT | sed -e 's,.*/,,') break fi done case $HOSTTYPE in $EXECTYPE) OCC=$CC CC=cc hostinfo type EXECTYPE=$_hostinfo_ case $HOSTTYPE in $EXECTYPE) err_out "$CC seems to be a cross-compiler." \ "Set HOSTTYPE to something other than the native $EXECTYPE." \ "If not, your $TMPDIR directory may be mounted without execute permission." \ "Try exporting TMPDIR as a directory where you can execute binary files." ;; esac ;; esac $show EXECTYPE=$EXECTYPE $show export EXECTYPE export EXECTYPE ;; esac $show EXECROOT=$EXECROOT $show export EXECROOT export EXECROOT # grab a decent default shell case $KEEP_SHELL in 0) save_PATH=$PATH PATH=$DEFPATH:$path for i in ksh ksh93 mksh yash bash sh do if onpath "$i" && checksh "$_onpath_" then SHELL=$_onpath_ KEEP_SHELL=1 break fi done PATH=$save_PATH unset save_PATH case $KEEP_SHELL in 0) err_out "Cannot find a good default shell; please supply SHELL=/path/to/shell" ;; esac ;; esac export SHELL $show SHELL=$SHELL $show export SHELL # tame the environment unset ERROR_OPTIONS ENV _KSHRC_WELCOMED_ # finalize the views case $USER_VPATH in '') case $VPATH in ?*) IFS=':' set -- $VPATH IFS=$ifs USER_VPATH= for i do case $i in */arch/$HOSTTYPE) ;; */arch/*/*) ;; */arch/*) continue ;; esac if packageroot $i then case $USER_VPATH in '') USER_VPATH=$i ;; ?*) USER_VPATH=$USER_VPATH:$i ;; esac fi done esac ;; esac case $USER_VPATH in ?*) IFS=':' set -- $USER_VPATH IFS=$ifs USER_VPATH= USER_VPATH_CHAIN= p=$PACKAGEROOT for i do case $i in ''|$PACKAGEROOT|$INSTALLROOT) ;; ?*) USER_VPATH=$USER_VPATH:$i USER_VPATH_CHAIN="$USER_VPATH_CHAIN $p $i" p=$i ;; esac done ;; esac ;; esac PACKAGEBIN=$INSTALLROOT/lib/package case $action:$run in use:-) eval "set -- $args" case $# in 0) ;; *) shift ;; esac run="$@" ;; esac # HOSTTYPE specific package profile if test -r $INSTALLROOT/lib/package/profile then . $INSTALLROOT/lib/package/profile fi # more Cygwin hassles case $HOSTTYPE in cygwin.*) lose= case $CYGWIN in *nontsec*) lose=ntsec ;; *ntsec*);; *) exe=$TMPDIR/pkg$$.exe rm -f "$exe" : > "$exe" if test -x "$exe" then lose=ntsec fi ;; esac case $CYGWIN in *nobinmode*) case $lose in '') lose=binmode ;; *) lose="$lose binmode" ;; esac ;; esac case $lose in ?*) err_out "$HOSTTYPE: export '$lose' in CYGWIN or languish in Windows" ;; esac ;; esac # set up the view state VIEW_bin=$INSTALLROOT VIEW_src=$PACKAGEROOT VIEW_all="$INSTALLROOT $PACKAGEROOT" VPATH=$INSTALLROOT:$PACKAGEROOT$USER_VPATH $show VPATH=$VPATH $show export VPATH export VPATH IFS=':' set -- $VPATH IFS=$ifs for i do case $i in */arch/*/*) VIEW_src="$VIEW_src $i" ;; */arch/*) VIEW_bin="$VIEW_bin $i" ;; *) VIEW_src="$VIEW_src $i" ;; esac VIEW_all="$VIEW_all $i" done # return 0 if arg in src|bin|all view view() # [test] [-|type] [src|bin|all] file { case $1 in -[dfsx])_view_T_=$1; shift ;; *) _view_T_=-f ;; esac case $1 in -) _view_t_= ;; *) _view_t_=$1 ;; esac shift case $1 in all) shift; _view_v_=$VIEW_all ;; bin) shift; _view_v_=$VIEW_bin ;; src) shift; _view_v_=$VIEW_src ;; *) _view_v_=$VIEW_all ;; esac case $1 in /*) if test $_view_T_ $1 then _view_=$1 return 0 fi ;; *) for _view_d_ in $_view_v_ do if test $_view_T_ $_view_d_/$1 then _view_=$_view_d_/$1 return 0 fi done ;; esac _view_= case $_view_t_ in ?*) note "$1: $_view_t_ not found" ;; esac return 1 } # determine the targets eval "set -- $args" # skip and save mamake(1) options in makeflags # (if mamake learns/forgets an option, replace the option string below with the output of 'mamake --posix') OPTIND=1 target= while getopts 'ef:iknr:C:D:FKNVGS' o do case $o in '?') exit 2 ;; f | r | C | D) shellquote OPTARG makeflags="$makeflags -$o $OPTARG" ;; *) makeflags="$makeflags -$o" ;; esac done shift $((OPTIND - 1)) for i do shellquote i target="$target $i" done # check that cmd args are up to date a.out's checkaout() # cmd ... { case $cc in '') _PACKAGE_cc=0 ;; *) _PACKAGE_cc=1 test -f "$INITROOT/hello.c" && test -f "$INITROOT/p.c" || { note "$INITROOT: INIT package source not found" return 1 } for i in arch arch/$HOSTTYPE arch/$HOSTTYPE/bin do test -d $PACKAGEROOT/$i || $exec mkdir $PACKAGEROOT/$i || return done ;; esac case $_PACKAGE_cc in '') case $cc in '') _PACKAGE_cc=0 ;; *) _PACKAGE_cc=1 ;; esac ;; esac for i do eval j=\$_PACKAGE_AOUT_$i case $j in '') eval _PACKAGE_AOUT_$i=1 ;; *) continue ;; esac k=$_PACKAGE_cc if test -f $INITROOT/$i.c then k=${k}1 else k=${k}0 fi if executable $EXECROOT/bin/$i then k=${k}1 else k=${k}0 fi : $k : compiler : source : binary : case $k in *00) view - bin/$i && continue ;; esac case $k in 000) note "$i: not found: download the INIT package $HOSTTYPE binary to continue" return 1 ;; 010) note "$i: not found: set CC=C-compiler or download the INIT package $HOSTTYPE binary to continue" return 1 ;; 100) note "$i: not found: download the INIT package source or $HOSTTYPE binary to continue" return 1 ;; 110) case $CROSS in 1) note "$i: not found: make the local $EXECTYPE binary package before $HOSTTYPE" return 1 ;; esac ;; ?01) : accept binary continue ;; 011) : accept binary continue ;; ??1) case $CROSS in 1) continue ;; esac ;; esac case $(ls -t $INITROOT/$i.c $INSTALLROOT/bin/$i 2>/dev/null) in "$INITROOT/$i.c"*) note "update $INSTALLROOT/bin/$i" if test ! -d $INSTALLROOT/bin then for j in arch arch/$HOSTTYPE arch/$HOSTTYPE/bin do test -d $PACKAGEROOT/$j || $exec mkdir $PACKAGEROOT/$j || return done fi rm -f "$INSTALLROOT/dyn/bin/$i" "$INSTALLROOT/src/lib/libast/$i" & case $HOSTTYPE in cygwin.*) # Windows/Cygwin kills fork(2) after deleting *or* renaming an executable that's in use :-/ # To allow relinking the binary against libast later, add a _bootstrap suffix and create # a symlink to it. The symlink can be removed/renamed instead of the _bootstrap binary. $exec $CC -O $CCFLAGS $LDFLAGS -o "$INSTALLROOT/bin/${i}_bootstrap" "$INITROOT/$i.c" || return $exec ln -sf "${i}_bootstrap" "$INSTALLROOT/bin/$i" || return ;; *) $exec $CC -O $CCFLAGS $LDFLAGS -o "$INSTALLROOT/bin/$i" "$INITROOT/$i.c" || return ;; esac test -f $i.o && $exec rm -f $i.o hash -r ;; esac done return 0 } # capture command output capture() # file command ... { tee_pid= case $make:$noexec in :) d=$PACKAGEBIN/gen test -d $d || $exec mkdir $d o=$d/$action case $o in $output)o=$o.out s= ;; *) output=$o if test -f $o.old then mv $o.old $o.out.1 if test -f $o.out then mv $o.out $o.out.2 fi elif test -f $o.out then for i in $(set +o noglob; ls -t $o.out.? 2>/dev/null) do break done case $i in *.1) i=2 ;; *.2) i=3 ;; *.3) i=4 ;; *.4) i=5 ;; *.5) i=6 ;; *.6) i=7 ;; *.7) i=8 ;; *.8) i=9 ;; *) i=1 ;; esac mv $o.out $o.out.$i fi o=$o.out : > $o note "$action output captured in $o" s="$command: $action start at $(date) in $INSTALLROOT" cmd='case $error_status in 0) r=done;; *) r=failed;; esac;' cmd=$cmd' echo "$command: $action $r at $(date) in $INSTALLROOT"' case $quiet in 0) cmd="$cmd 2>&1 | tee -a $o" ;; *) cmd="$cmd >> $o" ;; esac trap "$cmd" 0 trap "error_status=1; $cmd; trap 1 0; kill -1 $$" 1 trap "error_status=1; $cmd; trap 2 0; kill -2 $$" 2 ;; esac case $quiet in 0) # Connect 'tee' to a FIFO instead of a pipe, so that we can obtain # the build's exit status and use it for $error_status rm -f $o.fifo mkfifo -m 600 $o.fifo || exit ( sleep 1 # unlink early exec rm $o.fifo ) & tee -a $o < $o.fifo & tee_pid=$! o=$o.fifo ;; esac { case $s in ?*) echo "$s" ;; esac case $action in '' | make) # list main environment values for i in CC SHELL $env do case $i in FPATH | MANPATH) continue ;; # not relevant for building esac eval "echo \"$i=\$$i\"" done ;; esac (PS4="$action: executing"; set -o xtrace; : "$@") "$@" } < /dev/null > $o 2>&1 ;; *) $make "$@" ;; esac exit_status=$? if test "$exit_status" -gt "$error_status" then error_status=$exit_status fi case $tee_pid in ?*) # allow 'tee' to catch up before returning to prompt wait "$tee_pid" ;; esac } make_recurse() # dir { for _make_recurse_j in $makefiles do if view - $1/$_make_recurse_j then return fi done } do_install() # dir [ command ... ] { cd "$INSTALLROOT" printf 'install: installing from %s\n' "$PWD" dd=$1 shift case $dd in '' | [!/]*) err_out "ERROR: destination directory '$dd' must begin with a /" ;; /) # avoid //foo dd='' ;; esac # commands to install by default test "$#" -eq 0 && set -- ksh shcomp for f do test -f "bin/$f" || err_out "Not found: $f" "Build first? Run $0 make" done # set install directories bindir=$dd/bin fundir=${dd:-/usr}/share/fun mandir=${dd:-/usr}/share/man man1dir=$mandir/man1 man3dir=$mandir/man3 libdir=$dd/lib includedir=$dd/include # and off we go trace mkdir -p "$bindir" "$man1dir" || exit for f do # macOS throws code signature error if in-use Mach-O binary is overwritten or deleted; must rename first if test -e "$bindir/$f" then trace mv "$bindir/$f" "$bindir/$f.old" || exit fi # install executable if test -f "dyn/bin/$f" then trace cp "dyn/bin/$f" "$bindir/" || exit else trace cp "bin/$f" "$bindir/" || exit fi # install manual pages and autoloadable functions case $f in ksh) trace cp "$PACKAGEROOT/src/cmd/ksh93/sh.1" "$man1dir/ksh.1" || exit trace mkdir -p "$fundir" || exit (set +o noglob; trace cp "$PACKAGEROOT"/src/cmd/ksh93/fun/* "$fundir/") || exit ;; *) # AT&T --man, etc. is a glorified error message: writes to stderr and exits with status 2 :-/ # So we cannot reliably check for success; must check the result, too. manfile=$man1dir/${f##*/}.1 bin/ksh -c '"$@" 2>&1' _ "bin/$f" --\?\?nroff >$manfile if test "$?" -eq 2 && read -r magic < "$manfile" && test "X$magic" = 'X.\" format with nroff|troff|groff -man' # string from optget.c then printf '%s: executing: %s --\\?\\?nroff > %s\n' "$action" "bin/$f" "$manfile" else rm "$manfile" fi ;; esac done if test -d "dyn/lib" then trace mkdir -p "$libdir" "$man3dir" "$includedir" # install libraries set +o noglob for f in dyn/lib/* do set -o noglob # macOS throws code signature error if in-use Mach-O binary is overwritten or deleted; must rename first fi=$libdir/${f##*/} if test -e "$fi" && ! test -L "$fi" then trace mv "$fi" "$fi.old" || exit fi # the extra -R is needed as a workaround for /bin/cp to copy a symlink on (at least) macOS 12.7.5 trace cp -PR "$f" "$libdir"/ || exit done # install developer stuff test -d "$includedir/ast" && trace rm -rf -- "$includedir/ast" trace cp -R "include/ast" "$includedir"/ || exit printf "install: writing into %s:" "$man3dir" ( set +o noglob for f in man/man3/*.3 do printf " %sast" "${f##*/}" # give .3 pages an ast suffix to avoid conflicts sed '/^\.TH .* 3/ s/ 3/ 3ast/' "$f" > "$man3dir/${f##*/}ast" done ) printf '\n' fi } error_status=0 case $action in clean|clobber) cd "$PACKAGEROOT" || exit note "cleaning up flat view" # clean up all links with arch dir except bin/package $exec find "arch/$HOSTTYPE" -path "arch/$HOSTTYPE/bin/package" -o -type f -exec "$SHELL" -c ' first=y for h # loop through the PPs do case $first in y) set -- # clear PPs ("for" uses a copy) first=n ;; esac p=${h#"arch/$HOSTTYPE/"} # get flat view path if test "$p" -ef "$h" # is it part of the flat view? then set -- "$@" "$p" # add to new PPs fi done exec rm -f -- "$@" # rm all at once: fast ' "$0" {} + case $flat in 0) note "deleting arch/$HOSTTYPE" $exec rm -rf arch/$HOSTTYPE ;; esac note "removing empty directories" $exec find . -depth -type d -exec rmdir {} + 2>/dev/null ;; export) case $INSTALLROOT in $PACKAGEROOT) INSTALLROOT=$INSTALLROOT/arch/$HOSTTYPE ;; esac case $only in 0) v='$i=' ;; *) v= ;; esac eval "set -- $target" test "$#" -eq 0 && set -- $env while test "$#" -gt 0 do i=$1 eval "echo \"$v\$$i\"" shift done ;; install)cd $PACKAGEROOT test -n "$args" || err_out "Usage: $0 install ROOTDIR [ COMMANDNAME ... ]" eval "capture do_install $args" ;; make|view) cd $PACKAGEROOT # check for some required commands must="$AR" warn="$NM" test="$must $warn" have= IFS=: set /$IFS$PATH IFS=$ifs shift for t in $test do if executable $t then have="$have $t" fi done for d do for t in $test do case " $have " in *" $t "*) ;; *) if executable $d/$t then have="$have $t" fi ;; esac done done for t in $test do case " $have " in *" $t "*) ;; *) case " $must " in *" $t "*) err_out "$t: not found -- must be on PATH to $action" ;; *) note "warning: $t: not found -- some $action actions may fail" ;; esac ;; esac done # verify the top view if test ! -d $PACKAGEROOT/src then note "no source packages to make" exit 0 elif test ! -d $INSTALLROOT/src then note "initialize the $INSTALLROOT view" fi for i in arch arch/$HOSTTYPE do test -d $PACKAGEROOT/$i || $exec mkdir $PACKAGEROOT/$i || exit done for i in bin bin/ok bin/ok/lib fun include lib lib/package lib/package/gen src man man/man1 man/man3 man/man8 do test -d $INSTALLROOT/$i || $exec mkdir $INSTALLROOT/$i || exit done make_recurse src o= k= for i in $makefiles do case $o in ?*) o="$o -o" k="$k|" ;; esac o="$o -name $i" k="$k$i" done o="( $o ) -print" for d in $src do i=src/$d if test -d $i then test -d $INSTALLROOT/$i || $exec mkdir $INSTALLROOT/$i || exit make_recurse $i for j in $(cd $i; find . $o 2>/dev/null | sed -e 's,^\./,,' -e '/\//!d' -e 's,/[^/]*$,,' | sort -u) do case $j in $k|$MAKESKIP) continue ;; esac test -d $INSTALLROOT/$i/$j || $exec mkdir -p $INSTALLROOT/$i/$j || exit done fi done # check $CC and { ar cc ld ldd } intercepts h="${HOSTTYPE} ${HOSTTYPE}.*" case $HOSTTYPE in *.*) t=$(echo $HOSTTYPE | sed 's/[.][^.]*//') h="$h $t" ;; *) t=$HOSTTYPE ;; esac case $t in *[0123456789]) t=$(echo $t | sed 's/[0123456789]*$//') h="$h $t" ;; esac case $CC in cc) c=cc b=$INSTALLROOT/bin/$c t=$INSTALLROOT/lib/package/gen/$c.tim intercept=0 for k in $h do for s in $INITROOT/$c.$k do test -x "$s" || continue if cmp -s "$s" "$b" >/dev/null 2>&1 then intercept=1 break 2 fi case $(ls -t "$t" "$b" "$s" 2>/dev/null) in $t*) ;; $b*) cc=$b ;; $s*) $exec cd $INSTALLROOT/lib/package/gen tmp=pkg$$ $exec eval "echo 'int main(void){return 0;}' > $tmp.c" if $exec $s -o $tmp.exe $tmp.c >/dev/null 2>&1 && test -x $tmp.exe then case $HOSTTYPE in *.mips*)$s -version >/dev/null 2>&1 || s= ;; esac case $s in ?*) $exec sed "s/^HOSTTYPE=.*/HOSTTYPE=$HOSTTYPE/" < "$s" > "$b" || exit $exec chmod +x "$b" || exit cc=$b intercept=1 note "update $b" ;; esac fi (set +o noglob; $exec rm -rf $tmp.*) $exec touch "$t" cd $PACKAGEROOT ;; esac break 2 done done case $intercept in 1) c=ld b=$INSTALLROOT/bin/$c for k in $h do for s in $INITROOT/$c.$k do test -x "$s" || continue case $(ls -t "$b" "$s" 2>/dev/null) in $b*) ;; $s*) $exec cp "$s" "$b" note "update $b" ;; esac done done ;; esac ;; esac c=ldd b=$INSTALLROOT/bin/$c for t in $h do s=$INITROOT/$c.$t test -x "$s" || continue onpath $c || case $(ls -t "$b" "$s" 2>/dev/null) in $b*) ;; $s*) $exec cp "$s" "$b" note "update $b" ;; esac done c=ar b=$INSTALLROOT/bin/$c for t in $h do s=$INITROOT/$c.$t test -x "$s" || continue case $(ls -t "$b" "$s" 2>/dev/null) in $b*) ;; $s*) $exec cp "$s" "$b" note "update $b" ;; esac done case $cc in /*) ;; *) err_out "$CC: not found -- set CC=C-compiler" ;; esac case $exec in '') cd $INSTALLROOT/lib/package/gen tmp=pkg$$ echo 'int main(void){return 0;}' > $tmp.c if $CC -o $tmp.exe $tmp.c > /dev/null 2> $tmp.err && test -x $tmp.exe then : ok else note "$CC: failed to compile this program:" cat $tmp.c >&2 if test -s $tmp.err then cat $tmp.err >&2 else note "$CC: not a C compiler" fi (set +o noglob; rm -rf $tmp.*) exit 1 fi (set +o noglob; rm -rf $tmp.*) cd $PACKAGEROOT ;; esac # check against previous compiler and flags err= for var in CC CCFLAGS CCLDFLAGS LDFLAGS do store=$INSTALLROOT/lib/package/gen/$var eval "new=\$$var" if test -e "$store" then old=$(cat "$store") || exit case $old in "$new") ;; *) case $old in '') old="(none)" ;; *) old="'$old'" ;; esac case $new in '') new="(none)" ;; *) new="'$new'" ;; esac note "$var changed from $old to $new" err=y ;; esac elif test -d "$INSTALLROOT/lib/package/gen" # does not exist if 'bin/package debug make' then case $new in '') ;; *) echo "$new" ;; esac > $store || exit fi done case $err,${FORCE_FLAGS+f} in y,) err_out "This would likely break the build. Restore the flag(s)," \ "or delete the build directory and rebuild from scratch." ;; esac unset err var store old new # remember the default $CC case $CC in cc) ;; *) if test -x $INSTALLROOT/bin/cc then case $(sed 1q $INSTALLROOT/bin/cc) in ": $CC :") CC=cc export CC ;; *) assign="$assign CC=\"\$CC\"" ;; esac else case $CROSS in 1) assign="$assign CC=\"\$CC\"" ;; *) case $exec in '') { echo ": $CC :" echo "$CC \"\$@\"" } > $INSTALLROOT/bin/cc chmod +x $INSTALLROOT/bin/cc ;; *) note "generate a $INSTALLROOT/bin/cc wrapper for $CC" ;; esac CC=cc export CC ;; esac fi ;; esac # update probe scripts i=$INSTALLROOT/bin/mamprobe j=$INITROOT/mamprobe.sh case $(ls -t "$i" "$j" 2>/dev/null) in "$i"*) ;; *) note "update $i" $exec cp "$j" "$i" || exit $exec chmod +x "$i" || exit ;; esac for i in lib/probe lib/probe/C lib/probe/C/make do test -d "$INSTALLROOT/$i" || $exec mkdir "$INSTALLROOT/$i" || exit done i=$INSTALLROOT/lib/probe/C/make/probe j=$INITROOT/C+probe k=$INITROOT/make.probe case $(ls -t "$i" "$j" "$k" 2>/dev/null) in "$i"*) ;; *) if test -f "$j" && test -f "$k" then note "update $i" case $exec in '') cat "$j" "$k" > $i || exit ;; *) echo "cat $j $k > $i" ;; esac $exec chmod +x "$i" || exit fi ;; esac # initialize mamake checkaout mamake || exit case $action in view) exit 0 ;; esac # all work under $INSTALLROOT/src $make cd $INSTALLROOT/src # record the build host name case $exec in '') hostinfo name echo "$_hostinfo_" | sed 's,\..*,,' > $PACKAGEBIN/gen/host ;; esac # transition - TODO: remove when dust settles rm -f "$INSTALLROOT/bin/.paths" & # run from separate copies since ksh may be rebuilt case $EXECROOT in $INSTALLROOT) $make cd $INSTALLROOT/bin cp=$(PATH=$DEFPATH; command -v cp) || cp=cp mv=$(PATH=$DEFPATH; command -v mv) || mv=mv rm=$(PATH=$DEFPATH; command -v rm) || rm=rm for i in \ ksh tee cp ln mv rm \ *ast*.dll *cmd*.dll *dll*.dll *shell*.dll do executable $i && { cmp -s $i ok/$i 2>/dev/null || { test -f ok/$i && $exec $rm ok/$i /dev/null || ln -sf "$INSTALLROOT/$p" "$p" || exit done ' "$0" {} + ;; esac ;; results)eval "set -- $target" def=make dir=$PACKAGEBIN/gen case $verbose in 0) filter=yes ;; *) filter=cat ;; esac path=0 suf=out on= while : do case $# in 0) break ;; esac case $1 in --) shift break ;; error*|fail*) filter=errors ;; make|test|view) def=$1 ;; old) suf=old ;; on) case $# in 1) err_out "$action: $1: host pattern argument expected" ;; esac shift case $on in ?*) on="$on|" ;; esac on="$on$1" ;; path) path=1 ;; test) def=test ;; *) break ;; esac shift done case $dir in */admin)case $on in '') on="*" ;; *) on="@($on)" ;; esac def=$def.log/$on ;; esac case $# in 0) set "$def" ;; esac m= t= for i do k=0 eval set '""' $i - $i.$suf - $dir/$i - $dir/$i.$suf - shift for j do case $j in -) case $k in 1) continue 2 ;; esac ;; *) if test -f $j then k=1 case /$j in */test.*) t="$t $j" ;; *) m="$m $j" ;; esac fi ;; esac done err_out "$i action output not found" done sep= case $t in ?*) case $path in 0) for j in $t do echo "$sep==> $j <==" sep=$nl case $filter in cat) $exec cat $j ;; errors) $exec grep -E -i '\*\*\*|FAIL[ES]|^TEST.* [123456789][0123456789]* error|core.*dump' $j | sed -e '/^TEST.\//s,/[^ ]*/,,' ;; *) $exec grep -E -i '^TEST|FAIL' $j ;; esac done ;; 1) echo $t ;; esac ;; esac case $m in ?*) case $path in 0) case $filter in cat) cat $m ;; *) if test -f $HOME/.pkgresults then i=$(cat $HOME/.pkgresults) case $i in '|'*) ;; *) i="|$i" ;; esac else i= fi for j in $m do echo "$sep==> $j <==" sep=$nl case $filter in errors) $exeg grep -E '^pax:|\*\*\*' $j ;; *) $exec grep -E -iv '^($||[\+\[]|cc[^-:]|kill |make.*(file system time|has been replaced)|so|[0123456789]+ error|uncrate |[0123456789]+ block|ar: creat|iffe: test: |conf: (check|generate|read|probe|test)|[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_][abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789]*=|gsf@research|ar:.*warning|cpio:|ld:.*(duplicate symbol|to obtain more information)|[0123456789]*$|(checking|creating|touch) [/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789])| obsolete predefined symbol | is (almost always misused|dangerous|deprecated|not implemented)| trigraph| assigned to | cast .* different size| integer overflow .*<<| optimization may be attained | passed as |::__builtin|^creating.*\.a$|warning.*not optimized|exceeds size thresh|ld:.*preempts|is unchanged|with value >=|(-l|lib)\*|/(ast|sys)/(dir|limits|param|stropts)\.h.*redefined|usage|base registers|`\.\.\.` obsolete'"$i" $j | $exec grep : ;; esac done ;; esac ;; 1) echo $m ;; esac esac ;; test) # run all available default regression tests, using our newly compiled shell unless overridden cd "$INSTALLROOT" || err_out "run '$0 make' first" if test "$KEEP_SHELL" -lt 2 then executable bin/ksh || err_out "build ksh first, or supply a SHELL=/path/to/ksh argument" SHELL=$INSTALLROOT/bin/ksh fi export SHELL set -f eval "set -- ${args:-src}" cd "$1" || exit capture $MAMAKE_DEBUG_PREFIX mamake test ;; use) # finalize the environment if test "$KEEP_SHELL" -lt 2 && executable "$INSTALLROOT/bin/ksh" then SHELL=$INSTALLROOT/bin/ksh fi export ENV=$INSTALLROOT/etc/kshrc x=:.. for d in $(set +o noglob; cd $PACKAGEROOT; ls src/*/Mamfile 2>/dev/null | sed 's,/[^/]*$,,' | sort -u) do x=$x:$INSTALLROOT/$d done x=$x:$INSTALLROOT case $CDPATH: in $x:*) ;; *) CDPATH=$x:$CDPATH $show CDPATH=$CDPATH $show export CDPATH export CDPATH ;; esac eval PACKAGE_USE=$package_use export PACKAGE_USE unset LC_ALL # respect the user's locale again; avoids multibyte corruption for s in "$INSTALLROOT/dyn/bin/ksh" "$INSTALLROOT/$OK/bin/ksh" "$INSTALLROOT/bin/ksh" do if "$s" -c ':' 2>/dev/null then export SHELL=$s break fi done # run the command case $run in '') note "You are now entering a new environment set up to use the package in:" \ " $INSTALLROOT" \ "You're using the shell:" \ " $SHELL" \ "Type 'exit' to leave and go back to normal." case $show in ':') $exec exec $SHELL ;; esac ;; *) $exec exec $SHELL -c "$run" ;; esac ;; *) err_out "$action: internal error" ;; esac exit "$error_status" ksh-1.0.10/bin/shtests000077500000000000000000000044721465301102200145520ustar00rootroot00000000000000# Wrapper script to run the ksh93 regression tests directly. # By Martijn Dekker 2020-05-14, 2023-03-17, 2024-03-05 # Public domain. https://creativecommons.org/publicdomain/zero/1.0/ # # The manual: bin/shtests --man # Brief help: bin/shtests --help # # By default, this runs your compiled arch/*/bin/ksh. # Escape from a non-POSIX shell min_posix=/if/this/is/csh/ignore/the/error/message || exec sh $0:q $argv:q # ('test X -ef Y' is technically non-POSIX, but practically universal) min_posix='test / -ef / && path=Bad && case $PATH in (Bad) exit 1;; esac && '\ 'PWD=Bad && cd -P -- / && case $PWD in (/) ;; (*) exit 1;; esac && '\ '! { ! case x in ( x ) : ${0##*/} || : $( : ) ;; esac; } && '\ 'trap "exit 0" 0 && exit 1' if (eval "$min_posix") 2>/dev/null then : good shell else "$SHELL" -c "$min_posix" 2>/dev/null && exec "$SHELL" -- "$0" ${1+"$@"} sh -c "$min_posix" 2>/dev/null && exec sh -- "$0" ${1+"$@"} DEFPATH=`getconf PATH` 2>/dev/null || DEFPATH=/usr/xpg4/bin:/bin:/usr/bin:/sbin:/usr/sbin PATH=$DEFPATH:$PATH export PATH sh -c "$min_posix" 2>/dev/null && exec sh -- "$0" ${1+"$@"} echo "$0: Can't escape from obsolete or broken shell. Run me with a POSIX shell." >&2 exit 128 fi # bin/package will have set $SHELL to our ksh. # Allow override by passing SHELL= or KSH= as arguments. for arg do case $arg in ( SHELL=* | KSH=* ) export KSH=${arg#*=} ;; ( * ) set -- "$@" "$1" ;; esac shift done # Relaunch with necessary environment stuff from bin/package case ${HOSTTYPE+h}${INSTALLROOT+i}${PACKAGEROOT+p}${LD_LIBRARY_PATH+l} in hipl) ;; *) mydir=$(dirname "$0") \ && mydir=$(CDPATH='' cd -P -- "$mydir/.." && printf '%sX' "$PWD") \ && mydir=${mydir%X} \ || exit exec "$mydir/bin/package" use "$mydir" "$0" "$@" ;; esac # Check if there is a ksh to test. case ${KSH+set} in ( '' ) KSH=$SHELL ;; esac if ! test -x "$KSH" || ! test -f "$KSH"; then printf '%s: shell not found: %s\n' "${0##*/}" "$KSH" >&2 printf 'Specify a shell like: KSH=path/to/ksh bin/shtests\n' >&2 exit 1 fi # Ensure absolute path to ksh KSH=$(CDPATH='' cd -P -- "$(dirname "$KSH")" \ && printf '%s/%sX' "$PWD" "${KSH##*/}") \ && KSH=${KSH%X} # Run the test suite CDPATH='' cd -P -- "$PACKAGEROOT/src/cmd/ksh93/tests" || exit SHELL=$KSH unset -v KSH printf '#### Regression-testing %s ####\n' "$SHELL" exec "$SHELL" shtests "$@" ksh-1.0.10/docs/000077500000000000000000000000001465301102200133005ustar00rootroot00000000000000ksh-1.0.10/docs/index.html000066400000000000000000000001661465301102200153000ustar00rootroot00000000000000 AST Software The KornShell
ksh-1.0.10/docs/ksh/000077500000000000000000000000001465301102200140655ustar00rootroot00000000000000ksh-1.0.10/docs/ksh/builtins.html000066400000000000000000000711031465301102200166060ustar00rootroot00000000000000 www/ksh/builtins.mm mm document

Guidelines for writing ksh-93 built-in commands


David G. Korn

Abstract

One of the features of ksh93, the latest version of ksh, is the ability to add built-in commands at run time. This feature only works on operating systems that have the ability to load and link code into the current process at run time. Some examples of the systems that have this feature are Linux, System V Release 4, Solaris, Sun OS, HP-UX Release 8 and above, AIX 3.2 and above, and Microsoft Windows systems.

This memo describes how to write and compile programs that can be loaded into ksh at run time as built-in commands.


INTRODUCTION

A built-in command is executed without creating a separate process. Instead, the command is invoked as a C function by ksh. If this function has no side effects in the shell process, then the behavior of this built-in is identical to that of the equivalent stand-alone command. The primary difference in this case is performance. The overhead of process creation is eliminated. For commands of short duration, the effect can be dramatic. For example, on SUN OS 4.1, the time to run wc on a small file of about 1000 bytes, runs about 50 times faster as a built-in command.

In addition, built-in commands may have side effects on the shell environment. This is usually done to extend the application domain for shell programming. For example, there is a group of X-windows extension built-ins that make heavy use of the shell variable namespace. These built-ins are added at run time and result in a windowing shell that can be used to write X-windows applications.

While there are definite advantages to adding built-in commands, there are some disadvantages as well. Since the built-in command and ksh share the same address space, a coding error in the built-in program may affect the behavior of ksh; perhaps causing it to core dump or hang. Debugging is also more complex since your code is now a part of a larger entity. The isolation provided by a separate process guarantees that all resources used by the command will be freed when the command completes. Resources used by a built-in must be meticulously maintained and freed. Also, since the address space of ksh will be larger when built-in are loaded, it may increase the time it takes ksh to fork() and exec() non-built-in commands. It makes no sense to add a built-in command that takes a long time to run or that is run only once, since the performance benefits will be negligible. Built-ins that have side effects in the current shell environment have the disadvantage of increasing the coupling between the built-in and ksh, making the overall system less modular and more monolithic.

Despite these drawbacks, in many cases extending ksh by adding built-in commands makes sense and allows reuse of the shell scripting ability in an application specific domain. This memo describes how to write ksh extensions.


WRITING BUILT-IN COMMANDS

There is a development kit available for writing ksh built-ins as part of the AST (AT&T Software Technology) Toolkit. The development kit has three directories, include, lib, and bin. It is best to set the value of the environment variable PACKAGE_ast to the pathname of the directory containing the development kit. The include directory contains a subdirectory named ast that contains interface prototypes for functions that you can call from built-ins. The lib directory contains the ast library and a library named cmd that contains a version of several of the standard POSIX[1] utilities that can be made run time built-ins. The lib/ksh directory contains shared libraries that implement other ksh built-ins. The bin directory contains build tools such as nmake[2]. To add built-ins at runtime, it is necessary to build a shared library containing one or more built-ins that you wish to add. The built-ins are then added by running builtin -f shared_lib. Since the procedure for building share libraries is system dependent, it is best to use nmake using the sample nmake makefile below as a prototype. The AST Toolkit also contains some examples of built-in libraries under the src/cmd/kshlib directory.

There are two ways to code adding built-ins. One method is to replace the function main with a function b_name, where name is the name of the built-in you wish to define. A built-in command has a calling convention similar to the main function of a program, int main(int argc, char *argv[]). except that it takes a third argument of type Shbltin_t* which can be passed as NULL if it is not used. The definition for Shbltin_t* is in <ast/shcmd.h>. Instead of exit, you need to use return to terminate your command. The return value will become the exit status of the command. The open built-in, installed in lib/ksh in the AST Toolkit, uses this method. The Shbltin_t structure contains a field named shp which is a pointer to the shell data that is needed for shell library callbacks. It also contains the fields, shrun, shtrap, shexit, and shbltin that are function pointers to the shell library functions sh_run, sh_trap sh_exit, and sh_addbuiltin, respectively. These functions can be invoked without the need for runtime symbol lookup when the shell is statically linked with libshell.

The alternative method is to create a function lib_init and use the Shbltin_t.shbltin() function to add one or more built-ins. The lib_init function will be called with two arguments. The first argument will be 0 when the library is loaded and the second argument will be of type Shbltin_t*. The dbm_t and dss shell built-ins use this method.

No matter which way you add built-ins you should add the line SHLIB(identifier) as the last line of one of the built-in source file, where identifier is any C identifier. This line provides version information to the shell builtin command that it uses to verify compatibility between the built-in and ksh implementation versions. builtin fails with a diagnostic on version mismatch. The diagnostic helps determine whether ksh is out of date and requires an upgrade or the built-in is out of date and requires recompilation.

The steps necessary to create and add a run time built-in are illustrated in the following simple example. Suppose you wish to add a built-in command named hello which requires one argument and prints the word hello followed by its argument. First, write the following program in the file hello.c:

#include     <stdio.h>
int b_hello(int argc, char *argv[], void *context)
{
        if(argc != 2)
        {
                fprintf(stderr,"Usage: hello arg\n");
                return(2);
        }
        printf("hello %s\n",argv[1]);
        return(0);
}
SHLIB(hello)

Next, the program needs to be compiled. If you are building with AT&T nmake use the following Makefile:

:PACKAGE: --shared ast
hello plugin=ksh :LIBRARY: hello.c
and run nmake install to compile, link, and install the built-in shared library in lib/ksh/ under PACKAGE_ast. If the built-in extension uses several .c files, list all of these on the :LIBRARY: line.

Otherwise you will have to compile hello.c with an option to pick up the AST include directory (since the AST <stdio.h> is required for ksh compatibility) and options required for generating shared libraries. For example, on Linux use this to compile:

cc -fpic -I$PACKAGE_ast/include/ast -c hello.c
and use the appropriate link line. It really is best to use nmake because the 2 line Makefile above will work on all systems that have ksh installed.

If you have several built-ins, it is desirable to build a shared library that contains them all.

The final step is using the built-in. This can be done with the ksh command builtin. To load the shared library libhello.so from the current directory and add the built-in hello, invoke the command,

builtin -f ./libhello.so hello
The shared library prefix (lib here) and suffix (.so here) be omitted; the shell will add an appropriate suffix for the system that it is loading from. If you install the shared library in lib/ksh/, where ../lib/ksh/ is a directory on $PATH, the command
builtin -f hello hello
will automatically find, load and install the built-in on any system. Once this command has been invoked, you can invoke hello as you do any other command. If you are using lib_init method to add built-ins then no arguments follow the -f option.

It is often desirable to make a command built-in the first time that it is referenced. The first time hello is invoked, ksh should load and execute it, whereas for subsequent invocations ksh should just execute the built-in. This can be done by creating a file named hello with the following contents:

function hello
{
        unset -f hello
        builtin -f hello hello
        hello "$@"
}
This file hello needs to be placed in a directory that is in your FPATH variable, and the built-in shared library should be installed in lib/ksh/, as described above.


CODING REQUIREMENTS AND CONVENTIONS

As mentioned above, the entry point for built-ins must either be of the form b_name or else be loaded from a function named lib_init. Your built-ins can call functions from the standard C library, the ast library, interface functions provided by ksh, and your own functions. You should avoid using any global symbols beginning with sh_, nv_, and ed_ since these are used by ksh itself. #define constants in ksh interface files use symbols beginning with SH_ and NV_, so avoid using names beginning with these too.

Header Files

The development kit provides a portable interface to the C library and to libast. The header files in the development kit are compatible with K&R C[3], ANSI C[4], and C++[5].

The best thing to do is to include the header file <shell.h>. This header file causes the <ast.h> header, the <error.h> header and the <stak.h> header to be included as well as defining prototypes for functions that you can call to get shell services for your builtins. The header file <ast.h> provides prototypes for many libast functions and all the symbol and function definitions from the ANSI C headers, <stddef.h>, <stdlib.h>, <stdarg.h>, <limits.h>, and <string.h>. It also provides all the symbols and definitions for the POSIX[6] headers <sys/types.h>, <fcntl.h>, and <unistd.h>. You should include <ast.h> instead of one or more of these headers. The <error.h> header provides the interface to the error and option parsing routines defined below. The <stak.h> header provides the interface to the memory allocation routines described below.

Programs that want to use the information in <sys/stat.h> should include the file <ls.h> instead. This provides the complete POSIX interface to stat() related functions even on non-POSIX systems.

Input/Output

ksh uses sfio, the Safe/Fast I/O library[7], to perform all I/O operations. The sfio library, which is part of libast, provides a superset of the functionality provided by the standard I/O library defined in ANSI C. If none of the additional functionality is required, and if you are not familiar with sfio and you do not want to spend the time learning it, then you can use sfio via the stdio library interface. The development kit contains the header <stdio.h> which maps stdio calls to sfio calls. In most instances the mapping is done by macros or inline functions so that there is no overhead. The man page for the sfio library is in an Appendix.

However, there are some very nice extensions and performance improvements in sfio and if you plan any major extensions I recommend that you use it natively.

Error Handling

For error messages it is best to use the ast library function errormsg() rather that sending output to stderr or the equivalent sfstderr directly. Using errormsg() will make error message appear more uniform to the user. Furthermore, using errormsg() should make it easier to do error message translation for other locales in future versions of ksh.

The first argument to errormsg() specifies the dictionary in which the string will be searched for translation. The second argument to errormsg() contains that error type and value. The third argument is a printf style format and the remaining arguments are arguments to be printed as part of the message. A new-line is inserted at the end of each message and therefore, should not appear as part of the format string. The second argument should be one of the following:

ERROR_exit(n):

If n is not-zero, the builtin will exit value n after printing the message.
ERROR_system(n):

Exit builtin with exit value n after printing the message. The message will display the message corresponding to errno enclosed within [ ] at the end of the message.
ERROR_usage(n):

Will generate a usage message and exit. If n is non-zero, the exit value will be 2. Otherwise the exit value will be 0.
ERROR_debug(n):

Will print a level n debugging message and will then continue.
ERROR_warn(n):

Prints a warning message. n is ignored.

Option Parsing

The first thing that a built-in should do is to check the arguments for correctness and to print any usage messages on standard error. For consistency with the rest of ksh, it is best to use the libast functions optget() and optusage()for this purpose. The header <error.h> includes prototypes for these functions. The optget() function is similar to the System V C library function getopt(), but provides some additional capabilities. Built-ins that use optget() provide a more consistent user interface.

The optget() function is invoked as

int optget(char *argv[], const char *optstring)
where argv is the argument list and optstring is a string that specifies the allowable arguments and additional information that is used to format usage messages. In fact a complete man page in troff or html can be generated by passing a usage string as described by the getopts command. Like getopt(), single letter options are represented by the letter itself, and options that take a string argument are followed by the : character. Option strings have the following special characters:
:
Used after a letter option to indicate that the option takes an option argument. The variable opt_info.arg will point to this value after the given argument is encountered.
#
Used after a letter option to indicate that the option can only take a numerical value. The variable opt_info.num will contain this value after the given argument is encountered.
?
Used after a : or # (and after the optional ?) to indicate the preceding option argument is not required.
[...]

After a : or #, the characters contained inside the brackets are used to identify the option argument when generating a usage message.
space

The remainder of the string will only be used when generating usage messages.

The optget() function returns the matching option letter if one of the legal option is matched. Otherwise, optget() returns

':'
If there is an error. In this case the variable opt_info.arg contains the error string.
0
Indicates the end of options. The variable opt_info.index contains the number of arguments processed.
'?'
A usage message has been required. You normally call optusage() to generate and display the usage message.

The following is an example of the option parsing portion of the wc utility.

#include <shell.h>
while(1) switch(n=optget(argv,"xf:[file]"))
{
	case 'f':
		file = opt_info.arg;
		break;
	case ':':
		error(ERROR_exit(0), opt_info.arg);
		break;
	case '?':
		error(ERROR_usage(2), opt_info.arg);
		UNREACHABLE();
}

Storage Management

It is important that any memory used by your built-in be returned. Otherwise, if your built-in is called frequently, ksh will eventually run out of memory. You should avoid using malloc() for memory that must be freed before returning from you built-in, because by default, ksh will terminate you built-in in the event of an interrupt and the memory will not be freed.

The best way to allocate variable sized storage is through calls to the stak library which is included in libast and which is used extensively by ksh itself. Objects allocated with the stakalloc() function are freed when you function completes or aborts. The stak library provides a convenient way to build variable length strings and other objects dynamically. The man page for the stak library is contained in the Appendix.

Before ksh calls each built-in command, it saves the current stack location and restores it after it returns. It is not necessary to save and restore the stack location in the b_ entry function, but you may want to write functions that use this stack are restore it when leaving the function. The following coding convention will do this in an efficient manner:

yourfunction()
{
        char	*savebase;
        int	saveoffset;
        if(saveoffset=staktell())
        	savebase = stakfreeze(0);
        ...
        if(saveoffset)
        	stakset(savebase,saveoffset);
        else
        	stakseek(0);
}


CALLING ksh SERVICES

Some of the more interesting applications are those that extend the functionality of ksh in application specific directions. A prime example of this is the X-windows extension which adds builtins to create and delete widgets. The nval library is used to interface with the shell name space. The shell library is used to access other shell services.

The nval library

A great deal of power is derived from the ability to use portions of the hierarchical variable namespace provided by ksh-93 and turn these names into active objects.

The nval library is used to interface with shell variables. A man page for this file is provided in an Appendix. You need to include the header <nval.h> to access the functions defined in the nval library. All the functions provided by the nval library begin with the prefix nv_. Each shell variable is an object in an associative table that is referenced by name. The type Namval_t* is pointer to a shell variable. To operate on a shell variable, you first get a handle to the variable with the nv_open() function and then supply the handle returned as the first argument of the function that provides an operation on the variable. You must call nv_close() when you are finished using this handle so that the space can be freed once the value is unset. The two most frequent operations are to get the value of the variable, and to assign value to the variable. The nv_getval() function returns a pointer to the value of the variable. In some cases the pointer returned is to a region that will be overwritten by the next nv_getval() call so that if the value isn't used immediately, it should be copied. Many variables can also generate a numeric value. The nv_getnum() function returns a numeric value for the given variable pointer, calling the arithmetic evaluator if necessary.

The nv_putval() function is used to assign a new value to a given variable. The second argument to putval() is the value to be assigned and the third argument is a flag which is used in interpreting the second argument.

Each shell variable can have one or more attributes. The nv_isattr() is used to test for the existence of one or more attributes. See the appendix for a complete list of attributes.

By default, each shell variable passively stores the string you give with with nv_putval(), and returns the value with getval(). However, it is possible to turn any node into an active entity by assigning functions to it that will be called whenever nv_putval() and/or nv_getval() is called. In fact there are up to five functions that can associated with each variable to override the default actions. The type Namfun_t is used to define these functions. Only those that are non-NULL override the default actions. To override the default actions, you must allocate an instance of Namfun_t, and then assign the functions that you wish to override. The putval() function is called by the nv_putval() function. A NULL for the value argument indicates a request to unset the variable. The type argument might contain the NV_INTEGER bit so you should be prepared to do a conversion if necessary. The getval() function is called by nv_getval() value and must return a string. The getnum() function is called by the arithmetic evaluator and must return double. If omitted, then it will call nv_getval() and convert the result to a number.

The functionality of a variable can further be increased by adding discipline functions that can be associated with the variable. A discipline function allows a script that uses your variable to define functions whose name is varname.discname where varname is the name of the variable, and discname is the name of the discipline. When the user defines such a function, the settrap() function will be called with the name of the discipline and a pointer to the parse tree corresponding to the discipline function. The application determines when these functions are actually executed. By default, ksh defines get, set, and unset as discipline functions.

In addition, it is possible to provide a data area that will be passed as an argument to each of these functions whenever any of these functions are called. To have private data, you need to define and allocate a structure that looks like

struct yours
{
        Namfun_t	fun;
	your_data_fields;
};

The shell library

There are several functions that are used by ksh itself that can also be called from built-in commands. The man page for these routines are in the Appendix.

The sh_addbuiltin() function can be used to add or delete builtin commands. It takes the name of the built-in, the address of the function that implements the built-in, and a void* pointer that will be passed to this function as the third argument whenever it is invoked. If the function address is NULL, the specified built-in will be deleted. However, special built-in functions cannot be deleted or modified.

The sh_fmtq() function takes a string and returns a string that is quoted as necessary so that it can be used as shell input. This function is used to implement the %q option of the shell built-in printf command.

The sh_parse() function returns a parse tree corresponding to a give file stream. The tree can be executed by supplying it as the first argument to the sh_trap() function and giving a value of 1 as the second argument. Alternatively, the sh_trap() function can parse and execute a string by passing the string as the first argument and giving 0 as the second argument.

The sh_isoption() function can be used to set to see whether one or more of the option settings is enabled.


References

[1]
POSIX - Part 2: Shell and Utilities, IEEE Std 1003.2-1992, ISO/IEC 9945-2:1993.
[2]
Glenn Fowler, A Case for make, Software - Practice and Experience, Vol. 20 No. S1, pp. 30-46, June 1990.
[3]
Brian W. Kernighan and Dennis M. Ritchie, The C Programming Language, Prentice Hall, 1978.
[4]
American National Standard for Information Systems - Programming Language - C, ANSI X3.159-1989.
[5]
Bjarne Stroustroup, C++, Addison Wesley, xxxx
[6]
POSIX - Part 1: System Application Program Interface, IEEE Std 1003.1-1990, ISO/IEC 9945-1:1990.
[7]
David Korn and Kiem-Phong Vo, SFIO - A Safe/Fast Input/Output library, Proceedings of the Summer Usenix, pp. , 1991.


March 13, 2012

ksh-1.0.10/docs/ksh/examples.html000066400000000000000000000053411465301102200165740ustar00rootroot00000000000000 www/ksh/examples.mm mm document

Sample Functions

dirs    getopt    popd    title
emacs_keybind    keybind    pushd    vi_keybind


Sample Scripts

cgi-lib.ksh    env    which     
dump-cgi.ksh    line          


March 13, 2012

ksh-1.0.10/docs/ksh/faq.html000066400000000000000000001017311465301102200155250ustar00rootroot00000000000000 general shell

general

What is KornShell?
KornShell is a command and scripting language that is a superset of the System V UNIX shell, aka, BourneShell (or sh).
What is ksh?
ksh is the name of the program that implements the KornShell language.
What is the history of ksh?
ksh was written by David Korn at Bell Telephone Laboratories. David Korn is currently at AT&T Research. The first version of ksh was in 1983. It was the first shell to have command line editing with both emacs and vi style interaction. The 1986 version was the first to offer multibyte support. The 1988 version of ksh is the version that was adopted by System V Release 4 UNIX and was a source document for the IEEE POSIX and ISO shell standards. The 1993 version is a major rewrite of the 1988 version and focuses more on scripting.
Where is the official description of the KornShell language?
The Bolsky and Korn book, The KornShell Command and Programming Language, published by Prentice Hall, defines the 1988 version. The newer Bolsky and Korn book, The New KornShell Command and Programming Language, also published by Prentice Hall, describes the 1993 version. There are many new features since this book was published and the man page for ksh93 is kept up to date.
What are the major new features of KornShell 1993?
The only major new interactive features are key binding and tab completion. Major new language features are floating point arithmetic, associative arrays, complete ANSI C printf, name reference variables, new expansion operators, dynamic loading of built-in commands, active variables, and compound variables. Active and compound variables allow shell variables to behave like objects. The ability to define types was added in 2009. In addition, ksh93 has been written to be extensible with an C language API for programming extensions.
Are any further releases of ksh planned?
Yes, the KornShell language and ksh implementation are in active development. Most of the focus will be on scripting and reusability.
Why are newer release of ksh still called ksh93?
We started the AST/ksh OpenSource release process in the late 90's. At that point ksh93 was the well-known name for ksh. The OpenSource release was finally granted in March 2000. No one has since volunteered to repeat that process for kshXX.
How can I determine the release or version of a particular ksh?
The current version and release string may be accessed by ${.sh.version} and $KSH_VERSION. The format is Version features 93version[-/+] release:
  • features -- compile time features, typically enabled by SHOPT_foo state variables in the ksh93 Makefile. A single letter represents each feature:
    • A (SHOPT_AUDIT)
    • B (SHOPT_BASH) bash compatibility mode.
    • J (SHOPT_COSHELL) -lcoshell job pools.
    • j (SHOPT_BGX)
    • L (SHOPT_ACCT)
    • M (SHOPT_MULTIBYTE)
    • P (SHOPT_PFSH)
    • R (SHOPT_REGRESS)
  • version-- a lowercase letter signifying major release points. An optional - following features signifies an alpha release. The first stable release has no -. An optional + signifies a stable release with bug patches and minor enhancements.
  • release-- the release date in YYYY-MM-DD form. This date corresponds to AST package and git repository releases.
KSH_VERSION in a numeric context is an integer that encodes the release YYYYMMDD.
What new features are planned for ksh?
We are in the early stage of planning but the likely additions are namespaces, ability to read XML and JSON object into shell variables, and handling of queued signals. Support for multi-threading is also being considered.
Is KornShell public domain?
Yes, the language description is public domain and can be reimplemented. Some of the KornShell language features have been reimplemented in the GNU shell, bash, in zsh and mksh, and in pdksh, a public domain implementation.
Is ksh public domain?
No, earlier versions were owned by both AT&T and Novell. The 1993 version is owned by both Lucent and AT&T.
Is source code available?
Starting in March 2000, the ksh93 source is available as part of a larger collection of software called the ast-open software package which can be downloaded from the github page.
What are the licensing terms?
The exact license terms can be found on the licence page.
Does the license allow binaries to be freely redistributed?
Yes, provided you make the license terms available to everyone you distribute binaries to.
If I make changes to the code, do I have to make them public?
No, you do not have to make them public. However, if you distribute the changes, you must allow us to be able to get these changes and distribute them along with the source.
Why do some vendors still ship ksh88, not ksh93?
Since ksh88 was included in System V release 4, most vendors have just included this version. However most Linux systems and Mac OS provide ksh93 version 's' or later. Solaris11 uses ksh93 as /bin/sh.
Do you provide support for ksh?
No, we will try to fix any bugs we hear about in future releases, but we do not provide any official support.
Is ksh supported commercially?
Software vendors that supply ksh with their systems typically support it for that system.
What is pdksh and is it related to ksh or KornShell?
pdksh is a public domain version of a UNIX shell that is unrelated to ksh. It supports most of the 1988 KornShell language features and some of the 1993 features. Some KornShell scripts will not run with pdksh.
How is the MKS Toolkit KornShell related to KornShell?
MKS Toolkit KornShell is a completely independent implementation that supports a subset of the 1988 KornShell language.
What systems does ksh run on?
ksh has been written to be portable. It has been ported to virtually run on every known UNIX system. In addition, it runs on non-UNIX systems such as IBM's MVS using OpenEdition, and Microsoft's Windows 9X, Windows NT and Windows 2000. ksh is part of the UWIN (Unix for Windows) software,
Does ksh conform to the IEEE POSIX and ISO shell standard?
The 1993 version should conform to the 1992 standard. At one point it had passed the test suite created by X/OPEN.
Will KornShell 88 scripts run with KornShell 93?
In almost all cases, the answer is yes. However, the IEEE POSIX and ISO standards required a few changes that could cause scripts to fail. There is a separate document that lists all known incompatibilities.
Can ksh run as /bin/sh?
We have installed ksh as /bin/sh on several systems without encountering any problems. It is /bin/sh on Solaris11. Our Linux systems use this instead of bash.


interactive

How do I get separate history files for shell?
ksh uses a shared history file for all shells that use the same history file name. This means that commands entered in one window will be seen by shells in other windows. To get separate windows, the HISTFILE variable needs to be set to different name before the first history command is created.
How do I get the time of day in my prompt?
You can use printf with supports the %T format for time and date formatting. For example, the format %(%H:%M:%S)T specifies time in hour, minute, second format and if no argument is specified, the current time is used. Thus setting PS1='$(printf "%(%H:%M:%S)T" $' will output the time of day before the $ prompt.
Why does the screen width not function correctly when non-printing characters are in my prompt?
The shell computes the screen width by subtracting the width of the prompt from the screen width. To account for non-printing characters, for example escape sequences that display in the title bar, follow these characters with a carriage return. The shell starts recomputing the width after each carriage return.
What is the PS4 prompt and how is it used?
The PS4 prompt is evaluated and displayed before each line when running an execution trace. If unset, a + and a <space> will be output before each line in the trace. Putting '$LINENO' inside PS4 will cause the line number to be displayed. Putting '$SECONDS' in the PS4 prompt will cause the elapsed time to be displayed before each line. Note that single quotes are used to prevent the expansion from happening when PS4 is defined.
How is keybinding done?
ksh93 provides a KEYBD trap that gets executed whenever a key is entered from the keyboard. Using this trap, and the associative array feature of ksh93, a keybind function can easily be written which will map any entered key sequence to another key sequence.
How do I get the arrow keys to work?
Starting with the 'h' point release, on most keyboards you do not have to do anything to get the arrow keys to work. However, if they do not generate standard escape sequences, then you will have to use a keybinding function to get them to work.
Does ksh support file name completion?
Yes, it does. The default key binding is <ESC><ESC> however, starting with the 'g' point release, <TAB> also works for completion.
Does ksh support command completion?
If you perform completion on the first word of a command, ksh will do completion using aliases, functions, and commands.
Is completion programmable?
Yes, using the key binding mechanism, you can script the behavior of any key and therefore cause the current contents of any line to be replaced by any other line.
Is there any way to get the command-line editor to go to more than a single line?
The multiline option (now on by default) allows lines longer than the width of the screen to be displayed on multiple lines on the screen. Also in vi-mode, if you hit 'v' while in control mode, it will bring up a full screen version of vi on the current command. The command will execute when you exit vi.
What is predictive editing?
In 2010, a compile option was added that cause the shell to try to predict what you were trying to type by looking in the history file for all lines that matched and presenting them as a menu. Any line starting with # would use the characters you type to find matching lines from the history file. If you find the line you wanted, you can enter the number followed by <TAB> or newline. However bugs in earlier version led to core dumps.
Can I use the shell line editor on other commands?
The command ie, that comes along with shell, can be used to run line input oriented commands with command line editing.
When I do echo $?, I am getting 267. What does this mean?
ksh93 reports process that terminate with a signal as 256+signo. Earlier versions used 128+signo but this makes it impossible to distinguish from a command exit with that value. If you run
kill -l $?
on this signal number, it will give the name of the signal that caused this exit.
When I type builtin, I notice that some of these are full pathnames. What does this mean?
Builtins that are not bound to pathnames are always searched for before doing a path search. Builtins that are bound to pathnames are only executed when the path search would bind to this pathname.
What is a self generating man page?
A self generating man page is one that is generated by the option parser within that command using an extended version of the getopts function. The man page can be generated in html, troff, or directly for the terminal. Most builtin commands in the shell have self generating man pages so that you can run for example, kill --man or kill --html to get the description of kill to the screen or as an html file. All self-documenting output is to the standard error, so you must redirect 2>... to capture the output.

This same method can also be used for shell scripts. Run getopts --man for more details.

What is autoloading?
Autoloading was a method used in ksh88, and still permitted in ksh93 to declare that a name corresponded to a function. The function would be loaded and executed when first referenced. This was necessary since FPATH was always searched after PATH with ksh88 and therefore if you defined a function whose name was the same as that of a program on your path, the program on your path would have been executed. With ksh93, when a pathname is encountered that is on PATH, but also is in FPATH, this directory is assumed to be a function directory. Thus, you can have function directories searched before program directories so that autoloading is no longer needed.
Why does the output from 'time command 2> file' come out on the screen?
The time command is a compound command in ksh and time is a reserved word It can be followed by any pipeline. Thus, redirections applied at the end are for the command, not to time itself. You can use time {...;} 2> file to capture the timing output to a file. Note, that with ksh, time works with all commands, for example, time for i; do xxx;done.
When I run 'mv * ../elsewhere' I so that get '-ksh: mv: cannot execute [Arg list too long]', what causes this?
UNIX systems have a limit to the space consumed by command arguments and environment variables when running commands that are not built into the shell. The configuration parameter ARG_MAX defines this limit. You can run 'getconf ARG_MAX' to find the limit for your system. Note that the shell expands * to the list of files in the current directory before running mv. In many case the xargs or tw command can be used to work around this problem by splitting the line into chunks and invoking the command. Another way to work around this limit is to make the command a builtin. On systems in which the cmd library is installed, you can invoke 'builtin -f cmd mv' to make mv a shell builtin in which case the line length limit no longer applies. Another alternative is to use a for loop and invoke the mv command for each file, for example, 'for i in *;do mv $i ../elsewhere;done'. Starting with ksh93o+, a new feature was added to ksh to overcome this limit in some cases. If a command is preceded by 'command -x', and it fails because there are two many arguments, the command will be run multiple times with subsets of the arguments. However, the change in ksh93o+ does not work in the above case because the ../elsewhere is not used for each subset. This problem was resolved starting in ksh93p so that command -x mv * ../elsewhere should work. Note that it is possible to do alias mv='command -x mv'
Is there any way to generate the list of .c files in the current directory and all the subdirectories?
Starting with ksh93o+, the globstar option (set -G or set -o globstar) was added. With globstar enabled, ** by itself matches zero or more directories or files, and **/ matches zero or more directories so that **/*.c will match all .c files under the current directory.
Is there any way to prevent sending a HUP signal to a job when I log out if I didn't nohup the job?
Yes, the disown command tells ksh not to forward the HUP signal to the specified jobs when it disconnects.


programming

What is the difference between * and @, for example, and ?
When used outside of "", they are equivalent. However, within double quotes, "$@" produces one argument for each positional parameter, and "$* produces a single argument. Note that "$@" preserves arguments lists, whereas $* may not unless both word splitting and pathname expansion are disabled.
Why do I need spaces around { and } but not around ( and )?
The characters ( and ) are shell metacharacters and are always treated specially. For historical reasons, { and } were treated as reserved words and are only special as separate words at locations in which a command can begin.
How do I get read to maintain the \ characters?
Use read -r instead.
How can I a write a ksh script that responds directly to each character so that you user just has to enter y, not y<return>?
There are two ways to do this. The easiest is to use
read -n1 x
Alternatively, you could do
function keytrap
{
	.sh.edchar=${sh.edchar}$'
}
trap keytrap KEYBD
and then
read x
What is the purpose of $'...'?
The $'...' string literal syntax was added to ksh93 to solve the problem of entering special characters in scripts. It uses ANSI C rules to translate the string between the '...'. It would have been cleaner to have all "..." strings handle ANSI C escapes, but that would not be backward compatible.
What is the -n option used for?
You should always run ksh -n on each script you write. The -n option will check for syntax errors on paths that might not even be checked when you run the script. It also produces a number of warning messages.
Why are both `...` and $(...) used for command substitution?
The `...` method has some rather strange quoting rules and does not nest easily. $(...) was added to ksh88 to make command substitution easy to use. `...` is provided for backwards compatibility only.
How can I tell if all the commands of a pipeline have succeeded?
The pipefail option was added to the 'g' point release of ksh93. With pipefail set, a pipeline will fail if any element of the pipeline fails. The exit status will be that of the first command that has failed.
What is the difference between [...] and [[...]]?
The [[...]] is processed as part of the shell grammar whereas [...] is processed like any other command. Operators and operands are detected when the command is read, not after expansions are performed. The shell does not do word splitting or pathname generation inside [[...]]. This allows patterns to be specified for string matching purposes. You should use [[...]] instead of [...] and test.
How come [[ $foo == $bar ]] is true and [[ $bar == $foo ]] is false?
The == operator is not symmetrical. It takes a string on the left and a pattern on the right. However, if you double quote the right hand side, which removes the special meaning of pattern match characters, then this becomes a string comparison so that [[ "$foo" == "bar" ]] and [[ "$bar" == "$foo" ]] are equivalent.
Why does ksh93 have print since echo already exists and is widely used?
The behavior of echo varies from system to system. The POSIX standard does not define the behavior of echo when the first argument beings with a - or when any argument contains a  character. This makes echo pretty useless for use in portable scripts.
What is $bar after running 'echo foo | read bar'?
The answer is foo. ksh runs the last component of a pipeline in the current process. Some shells run it as a subshell as if you had invoked it as echo foo | (read bar).
How can I access a substring of a variable?
The syntax ${varname:offset:len} can be used to generate the string of length len starting at the specified offset. String offsets start at 0. If :len is omitted, then the remainder of the string will be used. Both offset and len can be arithmetic expressions. A negative offset is subtracted from the last offset.
What is the difference between ((expr)) and $((expr))?
((expr)) is a command that evaluates an arithmetic expression. The exit status of this command is 0 if the expression evaluates to non-zero and is 1 if it evaluates to 0. 0 is an string expansion that expands to a string representation of the value of this arithmetic expression. It can be used anywhere a variable substitution is permitted.

What is the difference between $((x*y)) and $(($x*$y))?
In the first case the value of x and the value of y are multiplied together, and then their result is converted to a string. In the second case variables $x, *, and $y are concatenated to form an arithmetic expression which is then evaluated. This can yield different results, for example,
x=2+3 y=4+5
print $((x*y)) \$(($x*$y))
45 19
When x and y are numeric the first form is recommended for better
performance.
How do I handle filenames with spaces in them?
To be POSIX conforming, ksh has to do word splitting and pathname expansion the results of substitutions. You can enclose variable substitutions in "..." to prevent both word splitting and pathname expansion. Alternatively, you can disable word splitting by setting IFS='' and pathname generation with set -o noglob.
What are active variables?
By default shell variables are passive. They hold values given to them on assignment, and return values on reference. Active variables allow the assignment and reference (and other actions) be controlled by functions specific to that variable. At the shell level, a 'get', 'set', or 'unset' shell function can be defined for any variable to make them active, so that the function foo.set will be invoked whenever the variable foo is assigned a value. At the C interface level, several functions can be stacked together for an active variable.
What is the difference between function name and name()?
In ksh88 these were the same. However, the POSIX standard choose foo() for functions and defined System V Release 2 semantics to them so that there are no local variables and so that traps are not scoped. ksh93 keeps the ksh88 semantics for functions defined as function name, and has changed the name() semantics to match the POSIX semantics. Clearly, function name is more useful.
What is the naming conventions for files in FPATH and can one file contain more than one function definition?
You can have more than one function defined in each file defined in FPATH and all of them will be added to the list of known functions. Any commands placed in this file outside of function definitions will be invoked first. The name of the file must be that of the first function you invoke. If you have several functions defined in one file, then you should create a link to each of the function names that can potentially be invoked first.
What are name reference variables and how are they used?
Reference variables are variables in which all references and assignments refer to the variable that they reference. For example,
typeset -n name=$1
name=value
is equivalent to
eval \$1='value'
References are most useful for passing arguments such as arrays to functions.
If i=1 and var1=some value, how do I print var$i to get its value?
Either use
eval print var\$i
or
typeset -n x=var$i
print $x
How can I shift the elements of an array?
The shift special builtin-command only works for positional parameters. However, noting that array subscripts start at 0, you can use
typeset -A name "${name[@]:1}"
to shift the array.
Why are the braces required with array references, e.g. ${x[1]}?
It would be nice to do $x[1], but the POSIX shell would expand $x and then search for the file pattern resulting by concatenating [1]. ksh is POSIX compatible.
How do I get the list of subscript names for an associative array?
The prefix operator ! in variable expansions can be used to get names. To get the names of subscripts for an array, associative or indexed, use ${!var[@]}.
How do I do global substitutions on the contents of shell variables?
Use // instead of / for global substitution, ${var//aa/bb} will expand to the value of var with each "aa" replaced by "bb".
How can I convert %XX values to ASCII?
You can convert this to a sequence of ANSI C strings and then eval that string, for example suppose the variable 'foo' contains %XX strings, then
eval print -r -- "\$'${foo//'%'@(??)/'\x\1"'\$'"}'"
will print out the string in ASCII.
I want to use exec to open a file. How do I prevent the script from exiting if the exec fails?
If you run
command exec ... || error ...
then error will be executed if the exec fails, but the script will not terminate. The command builtin will prevent the shell from exiting when special built-ins fail.
How do I execute a builtin inside a function of the same name?
You use the command builtin for this. For example,
function cd
{
	command cd "$@" && title "$PWD"
}
will run the builtin command cd from within the function cd rather than calling the function cd recursively.
How are variables scoped in ksh?
The scoping of variables was not defined for ksh88 but in ksh93 static scoping was specified. For example the output from
function f1
{
	print foo=$foo
}
function f2
{
	typeset foo=local
	f1
}
foo=global
f2
will be "global". To get f2 to cause f1 to print the local value of foo, f2 can run "foo=$foo f1" instead.
Can you write a self reproducing program in KornShell?
Yes, the following program is self reproducing. Any shorter ones?
n="
" q="'" x="cat <<-!" y=! z='n="$n" q="$q" x="$x" y=$y z=$q$z$q$n$x$n$z$n$y'
cat <<-!
n="$n" q="$q" x="$x" y=$y z=$q$z$q$n$x$n$z$n$y
!


redirections

How do I redirect both standard input and standard output to a file?
Add the following redirections to the command. > file 2> &1. This will redirect standard output (file descriptor 1) to "file" and standard error (file descriptor 2) to the same place as file descriptor 1. ksh redirection allows you to redirect any single digit file descriptor by putting the descriptor number in front of the redirection operator with no intervening space.
Is there a way for the shell to pick the file number when I open a file?
Yes, a redirection operator operator can be preceded by {n} without any intervening space where n is the name of a variable. The file descriptor will be placed in variable n.
How do I connect to a socket from a shell script?
exec 3<> /dev/tcp/hostname/portnum will open a tcp connection to portnum on hostname for reading and writing on file descriptor 3. You can then use read and print statements with file descriptor 3, or redirection operators <&3 or >&3 to use these connections.
How do I seek to a given location in a file?
The redirection operators <# and ># allow you to seek to a specified location in a file. The operator can be followed by an arithmetic expression contained in ((...)). The variables CUR and EOF can be used in the arithmetic expression to get relative locations or locations relative to the end of file respectively. Alternatively, <# and ># can be followed by a shell pattern. In this case, the file will be positioned to beginning of the next line containing this pattern.
What is the <<< redirection operator?
It denotes a here-document in which the document is contained the argument that follows <<< and therefore there is no delimiter.
What is the >; redirection operator?
This operator writes the output into a temporary file in the same directory as the file specified after >;. If the command completes successfully, then the file is replaced. Otherwise, the original file is unchanged and the temporary file removed.
What is the <>; redirection operator?
The file is opened for reading and writing as with <>. However, when the file is closed it is truncated to the its current location.


extensions

Is there a shell compiler?
There is a separate command named shcomp that will convert a script into an intermediate machine independent form. The shell will detect this format whenever it runs a script and execute directly from this intermediate format.
What is the advantage of making commands built-in?
The startup time is reduced by a couple of orders of magnitude. In addition, built-in commands can access ksh internals.
What is the disadvantage of making commands built-in?
Errors in these built-ins can cause the shell to crash.
How do I add built-in commands?
There are two ways to do this. One is write a shared library with functions whose names are b_xxxx where xxxx is the name of the builtin. The function b_xxxx takes three arguments. The first two are the same as a mail program. The third parameter is a pointer argument which will point to the current shell context. The second way is to write a shared library with a function named lib_init(). This function will be called with an argument of 0 after the library is loaded. This function can add built-ins with the sh_addbuiltin() API function. In both cases, the library is loaded into the shell with the "builtin" utility.
Can ksh93 be embedded?
Yes, ksh93 can be compiled as a shared or dynamically linked library which can be embedded into applications. There is an API for interfacing to shell variables and to several of the internal shell functions.
Can I write GUI applications with ksh?
There are two extensions to ksh that can be used to write GUI applications as shell script. One is dtksh which was written by Steve Pendergrast at Novell and is included with the Common Desktop Environment, CDE. The other is tksh which was written by Jeff Korn. tksh combines the tk graphics package with ksh93 and reimplements the tcl language as an extension so that both tcl and ksh scripts can run in the same address space. The source for tksh is included in the ast-open package.
show all answers hide all answers


June 19, 2012

ksh-1.0.10/docs/ksh/features.html000066400000000000000000000154611465301102200166000ustar00rootroot00000000000000 www/ksh/features.mm mm document

ksh features

KSH-93 is the most recent version of the KornShell Language described in The KornShell Command and Programming Language, by Morris Bolsky and David Korn of AT&T Research. The KornShell is a shell programming language, which is upward compatible with sh (the Bourne Shell), and is intended to conform to the IEEE P1003.2/ISO 9945.2 Shell and Utilities standard. KSH-93 provides an enhanced programming environment in addition to the major command-entry features of the BSD shell csh. With KSH-93, medium-sized programming tasks can be performed at shell-level without a significant loss in performance. In addition, sh scripts can be run on KSH-93 without modification.

The code should conform to the IEEE POSIX 1003.1 standard and to the proposed ANSI C standard so that it should be portable to all such systems. Like the previous version, KSH-88, it is designed to accept eight bit character sets transparently, thereby making it internationally compatible. It can support multi-byte characters sets with some characteristics of the character set given at run time.

KSH-93 provides the following features, many of which were also inherent in KSH-88:

Enhanced Command Re-entry Capability

The KSH-93 history function records commands entered at any shell level and stores them, up to a user-specified limit, even after you log off. This allows you to re-enter long commands with a few keystrokes - even those commands you entered yesterday. The history file allows for eight bit characters in commands and supports essentially unlimited size histories.

In-line Editing

In sh the only way to fix mistyped commands is to backspace or retype the line. KSH-93 allows you to edit a command line using a choice of EMACS-TC or vi functions. You can use the in-line editors to complete filenames as you type them. You may also use this editing feature when entering command lines from your history file. A user can capture keystrokes and rebind keys to customize the editing interface.

Extended I/O Capabilities

KSH-93 provides several I/O capabilities not available in sh, including the ability to:
  • specify a file descriptor for input and output
  • start up and run co-processes
  • produce a prompt at the terminal before a read
  • easily format and interpret responses to a menu
  • echo lines exactly as output without escape processing
  • format output using printf formats.
  • read and echo lines ending in "\e".

Improved performance

KSH-93 executes many scripts faster than the System V Bourne shell. A major reason for this is that many of the standard utilities are built-in. To reduce the time to initiate a command, KSH-93 allows commands to be added as built-ins at run time on systems that support dynamic loading such as System V Release 4.

Arithmetic

KSH-93 allows you to do integer arithmetic in any base from two to sixty-four. You can also do double precision floating point arithmetic. Almost the complete set of C language operators are available with the same syntax and precedence. Arithmetic expressions can be used to as an argument expansion or as a separate command. In addition, there is an arithmetic for command that works like the for statement in C.

Arrays

KSH-93 supports both indexed and associative arrays. The subscript for an indexed array is an arithmetic expression, whereas, the subscript for an associative array is a string.

Functions and Aliases

Two mechanisms - functions and aliases - can be used to assign a user-selected identifier to an existing command or shell script. Functions allow local variables and provide scoping for exception handling. Functions can be searched for and loaded on first reference the way scripts are.

Substring Capabilities

KSH-93 allows you to create a substring of any given string either by specifying the starting offset and length, or by stripping off leading or trailing substrings during parameter substitution. You can also specify attributes, such as upper and lower case, field width, and justification to shell variables.

Enhanced pattern matching capabilities

KSH-93 allows you to specify regular expressions for file and string matches.

Improved debugging

KSH-93 can generate line numbers on execution traces. Also, I/O redirections are now traced. There is a DEBUG trap that gets evaluated after each command so that errors can be localized.

Job Control

On systems that support job control, including System V Release 4, KSH-93 provides a job-control mechanism almost identical to that of the BSD "csh", version 4.1. This feature allows you to stop and restart programs, and to move programs between the foreground and the background.

Added security

KSH-93 can execute scripts which do not have read permission and scripts which have the setuid and/or setgid set when invoked by name, rather than as an argument to the shell. It is possible to log or control the execution of setuid and/or setgid scripts. The noclobber option prevents you from accidentally erasing a file by redirecting to an existing file.

Documentation

Documentation for KSH-93 consists of an Introduction to KSH-93, Compatibility with the Bourne Shell, a manual page and a README file. In addition, the New KornShell Command and Programming Language book is available from Prentice Hall.


March 13, 2012

ksh-1.0.10/docs/ksh/functions/000077500000000000000000000000001465301102200160755ustar00rootroot00000000000000ksh-1.0.10/docs/ksh/functions/dirs.txt000066400000000000000000000047141465301102200176050ustar00rootroot00000000000000# # DIRECTORY MANIPULATION FUNCTIONS PUSHD, POPD AND DIRS # # Uses global parameters _push_max _push_top _push_stack integer _push_max=100 _push_top=100 # Display directory stack -- $HOME displayed as ~ function dirs { typeset dir="${PWD#$HOME/}" case $dir in $HOME) dir=\~ ;; /*) ;; *) dir=\~/$dir esac print -r - "$dir ${_push_stack[@]}" } # Change directory and put directory on front of stack function pushd { typeset dir= type=0 integer i case $1 in "") # pushd if ((_push_top >= _push_max)) then print pushd: No other directory. return 1 fi type=1 dir=${_push_stack[_push_top]} ;; +[1-9]|+[1-9][0-9]) # pushd +n integer i=_push_top$1-1 if ((i >= _push_max)) then print pushd: Directory stack not that deep. return 1 fi type=2 dir=${_push_stack[i]} ;; *) if ((_push_top <= 0)) then print pushd: Directory stack overflow. return 1 fi esac case $dir in \~*) dir=$HOME${dir#\~} esac cd "${dir:-$1}" > /dev/null || return 1 dir=${OLDPWD#$HOME/} case $dir in $HOME) dir=\~ ;; /*) ;; *) dir=\~/$dir esac case $type in 0) # pushd name _push_stack[_push_top=_push_top-1]=$dir ;; 1) # pushd _push_stack[_push_top]=$dir ;; 2) # push +n type=${1#+} i=_push_top-1 set -- "${_push_stack[@]}" "$dir" "${_push_stack[@]}" shift $type for dir do (((i=i+1) < _push_max)) || break _push_stack[i]=$dir done esac dirs } # Pops the top directory function popd { typeset dir if ((_push_top >= _push_max)) then print popd: Nothing to pop. return 1 fi case $1 in "") dir=${_push_stack[_push_top]} case $dir in \~*) dir=$HOME${dir#\~} esac cd "$dir" || return 1 ;; +[1-9]|+[1-9][0-9]) typeset savedir integer i=_push_top$1-1 if ((i >= _push_max)) then print pushd: Directory stack not that deep. return 1 fi while ((i > _push_top)) do _push_stack[i]=${_push_stack[i-1]} i=i-1 done ;; *) print pushd: Bad directory. return 1 esac unset '_push_stack[_push_top]' _push_top=_push_top+1 dirs } ksh-1.0.10/docs/ksh/functions/emacs_keybind.txt000066400000000000000000000005521465301102200214350ustar00rootroot00000000000000typeset -A Keytable trap 'eval "${Keytable[${.sh.edchar}]}"' KEYBD function emacs_keybind { keybind $'\E[A' $'\020' # Up key keybind $'\E[B' $'\016' # Down key keybind $'\E[C' $'\06' # Right key keybind $'\E[D' $'\02' # Left key keybind $'\E[H' $'\01' # Home key keybind $'\E[Y' $'\05' # End key keybind $'\t' $'\E\E' # Tab for command-line completion } ksh-1.0.10/docs/ksh/functions/getopt.txt000066400000000000000000000007501465301102200201420ustar00rootroot00000000000000function getopt { typeset c optstring=$1 options= sep= shift while getopts $optstring c do case $c in [:?]) exit 2 ;; *) options="$options$sep-$c" sep=' ' if [[ $optstring == *$c:* ]] then options=" $options $OPTARG" fi #then print -rn -- " -$c" "$OPTARG" #else print -rn -- " -$c" ;; esac done print -rn -- "$options" if [[ ${@:$OPTIND-1} != -- ]] then print -rn -- " --" fi if [[ -n ${@:$OPTIND} ]] then print -r -- " ${@:$OPTIND}" fi } ksh-1.0.10/docs/ksh/functions/keybind.txt000066400000000000000000000004321465301102200202620ustar00rootroot00000000000000typeset -A Keytable trap 'eval "${Keytable[${.sh.edchar}]}"' KEYBD function keybind # key action { typeset key=$(print -f "%q" "$2") case $# in 2) Keytable[$1]='.sh.edchar=${.sh.edmode}'"$key" ;; 1) unset Keytable[$1] ;; *) print -u2 "Usage: $0 key [action]" ;; esac } ksh-1.0.10/docs/ksh/functions/popd.txt000066400000000000000000000047121465301102200176040ustar00rootroot00000000000000# # DIRECTORY MANIPULATION FUNCTIONS PUSHD, POPD AND DIRS # # Uses global parameters _push_max _push_top _push_stack integer _push_max=100 _push_top=100 # Display directory stack -- $HOME displayed as ~ function dirs { typeset dir="${PWD#$HOME/}" case $dir in $HOME) dir=\~ ;; /*) ;; *) dir=\~/$dir esac print -r - "$dir ${_push_stack[@]}" } # Change directory and put directory on front of stack function pushd { typeset dir= type=0 integer i case $1 in "") # pushd if ((_push_top >= _push_max)) then print pushd: No other directory. return 1 fi type=1 dir=${_push_stack[_push_top]} ;; +[1-9]|+[1-9][0-9]) # pushd +n integer i=_push_top$1-1 if ((i >= _push_max)) then print pushd: Directory stack not that deep. return 1 fi type=2 dir=${_push_stack[i]} ;; *) if ((_push_top <= 0)) then print pushd: Directory stack overflow. return 1 fi esac case $dir in \~*) dir=$HOME${dir#~} esac cd "${dir:-$1}" > /dev/null || return 1 dir=${OLDPWD#$HOME/} case $dir in $HOME) dir=\~ ;; /*) ;; *) dir=\~/$dir esac case $type in 0) # pushd name _push_stack[_push_top=_push_top-1]=$dir ;; 1) # pushd _push_stack[_push_top]=$dir ;; 2) # push +n type=${1#+} i=_push_top-1 set -- "${_push_stack[@]}" "$dir" "${_push_stack[@]}" shift $type for dir do (((i=i+1) < _push_max)) || break _push_stack[i]=$dir done esac dirs } # Pops the top directory function popd { typeset dir if ((_push_top >= _push_max)) then print popd: Nothing to pop. return 1 fi case $1 in "") dir=${_push_stack[_push_top]} case $dir in \~*) dir=$HOME${dir#~} esac cd "$dir" || return 1 ;; +[1-9]|+[1-9][0-9]) typeset savedir integer i=_push_top$1-1 if ((i >= _push_max)) then print pushd: Directory stack not that deep. return 1 fi while ((i > _push_top)) do _push_stack[i]=${_push_stack[i-1]} i=i-1 done ;; *) print pushd: Bad directory. return 1 esac unset '_push_stack[_push_top]' _push_top=_push_top+1 dirs } ksh-1.0.10/docs/ksh/functions/pushd.txt000066400000000000000000000047141465301102200177670ustar00rootroot00000000000000# # DIRECTORY MANIPULATION FUNCTIONS PUSHD, POPD AND DIRS # # Uses global parameters _push_max _push_top _push_stack integer _push_max=100 _push_top=100 # Display directory stack -- $HOME displayed as ~ function dirs { typeset dir="${PWD#$HOME/}" case $dir in $HOME) dir=\~ ;; /*) ;; *) dir=\~/$dir esac print -r - "$dir ${_push_stack[@]}" } # Change directory and put directory on front of stack function pushd { typeset dir= type=0 integer i case $1 in "") # pushd if ((_push_top >= _push_max)) then print pushd: No other directory. return 1 fi type=1 dir=${_push_stack[_push_top]} ;; +[1-9]|+[1-9][0-9]) # pushd +n integer i=_push_top$1-1 if ((i >= _push_max)) then print pushd: Directory stack not that deep. return 1 fi type=2 dir=${_push_stack[i]} ;; *) if ((_push_top <= 0)) then print pushd: Directory stack overflow. return 1 fi esac case $dir in \~*) dir=$HOME${dir#\~} esac cd "${dir:-$1}" > /dev/null || return 1 dir=${OLDPWD#$HOME/} case $dir in $HOME) dir=\~ ;; /*) ;; *) dir=\~/$dir esac case $type in 0) # pushd name _push_stack[_push_top=_push_top-1]=$dir ;; 1) # pushd _push_stack[_push_top]=$dir ;; 2) # push +n type=${1#+} i=_push_top-1 set -- "${_push_stack[@]}" "$dir" "${_push_stack[@]}" shift $type for dir do (((i=i+1) < _push_max)) || break _push_stack[i]=$dir done esac dirs } # Pops the top directory function popd { typeset dir if ((_push_top >= _push_max)) then print popd: Nothing to pop. return 1 fi case $1 in "") dir=${_push_stack[_push_top]} case $dir in \~*) dir=$HOME${dir#\~} esac cd "$dir" || return 1 ;; +[1-9]|+[1-9][0-9]) typeset savedir integer i=_push_top$1-1 if ((i >= _push_max)) then print pushd: Directory stack not that deep. return 1 fi while ((i > _push_top)) do _push_stack[i]=${_push_stack[i-1]} i=i-1 done ;; *) print pushd: Bad directory. return 1 esac unset '_push_stack[_push_top]' _push_top=_push_top+1 dirs } ksh-1.0.10/docs/ksh/functions/title.txt000066400000000000000000000015441465301102200177630ustar00rootroot00000000000000# add to (+), delete from (-), print (.), or set ([=]) window title # arguments are eval'd before printing # title text string exported in TITLE_TEXT function title # [+ | - | =] title ... { typeset x t="$TITLE_TEXT" case $1 in +) shift case $# in 0) ;; *) for x do case " $t " in *" $x "*) ;; " ") t=$x ;; *) t="$t $x" ;; esac done case $t in $TITLE_TEXT) return 1 ;; esac ;; esac ;; -) shift case $# in 0) ;; *) for x do case " $t " in *" $x "*) t="${t%?( )$x*}${t##*$x?( )}" ;; esac done case $t in $TITLE_TEXT) return 1 ;; esac ;; esac ;; .) print -r -- "$TITLE_TEXT" return 0 ;; *) t="$*" ;; esac export TITLE_TEXT="$t" eval x=\"$t\" case $TERM in 630*) print -nr -- "[?${#x};0v$x" ;; vt100|xterm*) print -nr -- "]0;$x" ;; *) return 1 ;; esac return 0 } ksh-1.0.10/docs/ksh/functions/vi_keybind.txt000066400000000000000000000004071465301102200207620ustar00rootroot00000000000000typeset -A Keytable trap 'eval "${Keytable[${.sh.edchar}]}"' KEYBD function vi_keybind { keybind $'\E[A' k # Up key keybind $'\E[B' j # Down key keybind $'\E[C' l # Right key keybind $'\E[D' h # Left key keybind $'\t' '\' # Tab for command-line completion } ksh-1.0.10/docs/ksh/index.html000066400000000000000000000003721465301102200160640ustar00rootroot00000000000000 KSH93 Overview
FAQ
Features
Builtins
Examples ksh-1.0.10/docs/ksh/ksh.html000066400000000000000000000112641465301102200155440ustar00rootroot00000000000000 www/ksh/ksh.mm mm document

ksh overview

The KornShell language was designed and developed by David G. Korn at AT&T Bell Laboratories and AT&T Research. It is an interactive command language that provides access to the UNIX system and to many other systems, on the many different computers and workstations on which it is implemented. The KornShell language is also a complete, powerful, high-level programming language for writing applications, often more easily and quickly than with other high-level languages. This makes it especially suitable for prototyping. There are two other widely used shells, the Bourne shell developed by Steven Bourne at AT&T Bell Laboratories, and the C shell developed by Bill Joy at the University of California. ksh has the best features of both, plus many new features of its own. Thus ksh can do much to enhance your productivity and the quality of your work, both in interacting with the system, and in programming. ksh programs are easier to write, and are more concise and readable than programs written in a lower level language such as C.

The new version of ksh has the functionality of other scripting languages such as awk, icon, perl, rexx, and tcl. For this and many other reasons, ksh is a much better scripting language than any of the other popular shells. The code size for ksh is larger than the Bourne shell or C shell programs. The revised version is even larger.

In spite of its increased size, ksh provides better performance. You can write programs to run faster with ksh than with either the Bourne shell or the C shell, sometimes an order of magnitude faster. ksh has evolved and matured with extensive user feedback. It has been used by many thousands of people at AT&T since 1982, and at many other companies and universities. A survey conducted at one of the largest AT&T Bell Laboratories computer centers showed that 80% of their customers, both programmers and non-programmers, use ksh. ksh is compatible with the Bourne shell. Virtually all programs written for the Bourne shell run with ksh. If you are familiar with the Bourne shell, you can use ksh immediately, without retraining. The new version of ksh is compatible with earlier versions of ksh. ksh is readily available. It is sold (source and binary) by AT&T and Novell, and by other companies under license from AT&T both in the USA and abroad. It has been purchased by dozens of major corporations, and by many individuals for use on home computers. ksh is extensible.

The KornShell language uses the same syntax for built-in commands as for non built-in commands. Therefore, system developers can add new commands "transparently" to the KornShell language; that is, with minimum effort and with no differences visible to users other than faster execution. On systems with dynamic linking, it is possible to add new built-in commands at run time. Novell has extended the new version of ksh to enable X-windows programming for their desktop ksh product, dtksh. dtksh is a standard part of CDE, the Common Desktop Environment defined by COSE (Common Operating System Environment), supported by most major UNIX system hardware vendors. An extended version of ksh that enables Tk programming, called tksh, is available as well.

ksh is intended to conform to the Shell Language Standard developed by the IEEE POSIX 1003.2 Shell and Utilities Language Committee.


March 13, 2012

ksh-1.0.10/docs/ksh/scripts/000077500000000000000000000000001465301102200155545ustar00rootroot00000000000000ksh-1.0.10/docs/ksh/scripts/cgi-lib.ksh.txt000066400000000000000000000046671465301102200204240ustar00rootroot00000000000000typeset -A COOKIE HEADER typeset Cgi _CGI_c _CGI_multipart function cgi_header { typeset h for h in "${!HEADER[@]}" do printf '%s: %s\n' "$h" "${HEADER[$h]}" done print } function cgi_url { if [[ $SERVER_PORT != 80 ]] then print "http://$SERVER_NAME:$SERVER_PORT$SCRIPT_NAME" else print "http://$SERVER_NAME$SCRIPT_NAME" fi } function cgi_parse { if [[ $REQUEST_METHOD == POST ]] then if [[ $CONTENT_TYPE == multipart/form-data* ]] then _CGI_multipart=${TMPDIR-/tmp}/cgi-form-$$ trap 'rm -rf "$_CGI_multipart"' EXIT mkdir $_CGI_multipart unset -f Cgi.set typeset -A Cgi.file typeset i b v pax --nosummary --read --edit ",.*/,," --edit ",^,$_CGI_multipart/," for i in $_CGI_multipart/* do b=${i##*/} if [[ $b == +([a-z]) ]] then v=$(<$i) eval Cgi.$b='$v' else Cgi.file[$b]=$i fi done else Cgi=$(<&0) # Read from stdin fi else Cgi="$QUERY_STRING" fi cgi_cookie "$HTTP_COOKIE" HEADER["Content-type"]="text/html" } function cgi_cookie { typeset cookie=$1 name val c IFS=';' set -- $cookie for c do IFS='=' set -- $c name=${1##' '} val=${2##' '} # trim white space name=${name%%' '} val=${val%%' '} COOKIE[$name]=$val done } function cgi_setcookie # name value { HEADER["Set-Cookie"]="$1=$2; path=$SCRIPT_NAME" } ## Cgi variable disciplines function Cgi.set { set -f typeset i j n val IFS='&' set -- ${.sh.value} for i do n=${i%%=*} [[ $n == [[:alpha:]_]*([[:alnum:]_]) ]] || continue val=${i#$n=} val=${val//+/ } val=${val//@([\'\\])/'\'\1} eval j=\${#${.sh.name}.${n}[@]} \ "${.sh.name}.${n}[j]=\$'${val//'%'@(??)/'\x'\1"'\$'"}'" done } function cgi_C_init { integer i for ((i=1; i < 256; i++)) do if (( i!=16#22 && i!=16#27 && i!=16#5C && i!=16#5B && i!=16#5D )) then printf $'_CGI_c[$\'\\\\x%.2X\']=%%%.2X\n' $i $i fi done print } function cgi_encode { typeset v=$1 var=${v//' '/+} cbrace='}' eval var=${var//@([!a-zA-Z0-9_+])/\${_CGI_c[\\\1]$cbrace} print -r -- "$var" } function Cgi.get { typeset i val name vname if [[ ! ${_CGI_c[\\]} ]] then val='"' _CGI_c[""]=%00 _CGI_c[$var]=%22 _CGI_c[\']=%27 _CGI_c[\]]=%5B _CGI_c[\[]=%5D _CGI_c[\\]=%5C eval $(cgi_C_init) unset -f cgi_C_init fi vname=${.sh.name} # .sh.name contains variable name .sh.value= # .sh.value stores value for i in ${!Cgi.@} do name=${i#$vname.} nameref v=${i} val=$(cgi_encode "$v") .sh.value="${.sh.value}${.sh.value:+&}$name=$val" done } ksh-1.0.10/docs/ksh/scripts/dump-cgi.ksh.txt000066400000000000000000000003131465301102200206030ustar00rootroot00000000000000#!/bin/ksh . ./cgi-lib.ksh cgi_parse cgi_header print "" print "
"
print -r "Url: $(cgi_url)"
for i in ${!Cgi.*}
do
	nameref val=$i
	print -r "$i = $val"
done
print "
" print "" ksh-1.0.10/docs/ksh/scripts/env.txt000066400000000000000000000036151465301102200171120ustar00rootroot00000000000000#! /usr/bin/ksh # shell version of env command case $(getopts '[-]' opt '--???man' 2>&1) in version=[0-9]*) usage=$'[-?@(#)env (AT&T Labs Research) 1999-05-20\n] [-author?David Korn ] [-license?http://www.research.att.com/sw/tools/reuse] [+NAME?env - set environment for command invocation] [+DESCRIPTION?\benv\b modifies the current environment according to the \aname\a\b=\b\avalue\a arguments, and then invokes \acommand\a with the modified environment.] [+?If \acommand\a is not specified, the resulting environment is written to standard output quoted as required for reading by the \bsh\b.] [i:ignore-environment?Invoke \acommand\a with the exact environment specified by the \aname\a\b=\b\avalue\a arguments; inherited environment variables are ignored. As an obsolete feature, \b-\b by itself can be specified instead of \b-i\b.] [u:unset]:[name?Unset the environment variable \aname\a if it was in the environment. This option can be repeated to unset additional variables.] [name=value]... [command ...] [+EXIT STATUS?If \acommand\a is invoked, the exit status of \benv\b will be that of \acommand\a. Otherwise, it will be one of the following:]{ [+0?\benv\b completed successfully.] [+126?\acommand\a was found but could not be invoked.] [+127?\acommand\a could not be found.] } [+SEE ALSO?\bsh\b(1), \bexport\b(1)] ' ;; *) usage='iu:[name] [name=value]... [command ...]' ;; esac clear= while getopts "$usage" var do case $var in i) clear=1;; u) command unset $OPTARG 2> /dev/null;; esac done #[[ $var == "" ]] || exit 1 shift $((OPTIND-1)) if [[ $1 == - ]] # obsolete form then clear=1 shift fi if [[ $clear == 1 ]] then typeset +x $(typeset +x) fi while true do case $1 in *=*) export "$1";; *) break;; esac shift done if (( $# >0 )) then exec "$@" else export exit 0 fi ksh-1.0.10/docs/ksh/scripts/line.txt000066400000000000000000000000541465301102200172430ustar00rootroot00000000000000#! /bin/ksh read -r && print -r -- "$REPLY" ksh-1.0.10/docs/ksh/scripts/which.txt000066400000000000000000000000331465301102200174130ustar00rootroot00000000000000#! /bin/ksh whence -p "$@" ksh-1.0.10/src/000077500000000000000000000000001465301102200131375ustar00rootroot00000000000000ksh-1.0.10/src/Mamfile000066400000000000000000000010501465301102200144300ustar00rootroot00000000000000note * note * This build script is in an extended Make Abstract Machine (MAM) note * language. Documentation is at: src/cmd/INIT/README-mamake.md note * setv MAMAKE_STRICT 4 make install virtual make all virtual exec - %{MAMAKE} -r '*/*' %{MAMAKEARGS} done make announce_build_done virtual notrace makp cmd/ksh93/ksh exec - %{<} -c 'print "# KornShell $KSH_VERSION"' exec - echo "# Type 'bin/package use' to try it out" done done make test virtual exec - : testing KornShell $KSH_VERSION : exec - %{MAMAKE} -r '*/*' %{MAMAKEARGS} done ksh-1.0.10/src/cmd/000077500000000000000000000000001465301102200137025ustar00rootroot00000000000000ksh-1.0.10/src/cmd/INIT/000077500000000000000000000000001465301102200144455ustar00rootroot00000000000000ksh-1.0.10/src/cmd/INIT/C+probe000066400000000000000000000416101465301102200156570ustar00rootroot00000000000000: ### this script contains archaic constructs that work with all sh variants ### # Glenn Fowler # AT&T Research # # @(#)C probe (ksh 93u+m) 2022-10-26 # # probe [ -d ] c-compiler-path [ attributes ] # # common C probe preamble for the tool specific probes # # NOTE: some cc -E's do syntax analysis! # # probe_* are first eval'd and then attempted from left to right # probe_binding="-dy -dn -Bdynamic -Bstatic '-Wl,-ashared -Wl,+s' -Wl,-aarchive -call_shared -non_shared -dynamic -static -bshared -bstatic '' -static" probe_env="CC_OPTIONS CCOPTS LD_OPTIONS LDOPTS LIBPATH LPATH" probe_include="stdio.h iostream.h complex.h ctype.h plot.h stdarg.h varargs.h ranlib.h hash.h sys/types.h stab.h cmath cstdio iostream string" probe_longlong="long 'long long'" probe_longlong_t="__int64_t _int64_t __int64 _int64 int64" probe_l="l yyreject m sin mopt sin" probe_lxx="C exit ++ exit g++ exit" probe_ppprefix="a n" probe_size="size" probe_src="cxx C cc c" probe_sa=".sa" probe_sd=".dll .lib .dll .x" probe_sdb=".pdb" probe_so=".dylib .so .sl" probe_symprefix="_" probe_verbose="'-v -v' '-# -#' '-d -d' -dryrun '-V -V'" probe_version="--version -V -version -v" # # the following are set by the preamble for the tool specific probe # cc=cc debug= dir=. dll=.dll dynamic= exe=exe executable="test -x" hosted= ifs=${IFS-' '} obj=o ppenv= ppopt= predef= prepred= sa= sd= sdb= so= sov= static= stdlib= stdpp= suffix_command= if test "" != "$TMPDIR" -a -d "$TMPDIR" then tmpdir=$TMPDIR else tmpdir=/tmp fi tmpdir=$tmpdir/probe$$ undef="define defined elif else endif error if ifdef ifndef include line pragma undef __STDC__ __ARGC__ __BASE__ __BASE_FILE__ __DATE__ __FILE__ __FUNCTION__ __INCLUDE_LEVEL__ __LINE__ __PATH__ __TIME__ __TIMESTAMP__ __VERSION__" version_flags= version_stamp= version_string= # # constrain the environment # DISPLAY= LC_ALL=C export DISPLAY LC_ALL # # now the common probes # while : do case $1 in -d) debug=1 ;; -*) set ''; break ;; *) break ;; esac shift done cc=$1 case $cc in [\\/]*|[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]:\\*) ;; *) echo "Usage: $0 [ -d ] c-compiler-path [ attributes ]" >&2 exit 1 ;; esac ATTRIBUTES= eval $2 _probe_PATH=$PATH PATH=/usr/bin:/bin:$PATH case $0 in *[\\/]*) dir=`echo $0 | sed -e 's,[\\/][\\/]*[^\\/]*\$,,'` ;; esac $executable . 2>/dev/null || executable='test -r' case $SHELL in [\\/]*|[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]:\\*) sh=$SHELL ;; *) sh=/bin/sh ;; esac trap 'code=$?; cd ..; rm -rf $tmpdir; exit $code' 0 1 2 3 mkdir $tmpdir cd $tmpdir exec 3>&1 4>&2 /dev/null 2>&1 (ulimit -c 0) >/dev/null 2>&1 && ulimit -c 0 ;; *) PS4='+$LINENO+ ' set -x ;; esac if (xxx=xxx; unset xxx) then UNSET=1 else UNSET= fi eval set x $probe_env while : do shift case $# in 0) break ;; esac eval x='$'$1 case $x in '') continue ;; esac case $1 in *PATH) _probe_export="$_probe_export $1='$x'" ;; esac case $UNSET in '') eval $1= export $1 ;; *) unset $1 ;; esac done mkdir suffix cd suffix for src in $probe_src do echo "int main(void){return 0;}" > ../test.$src rm -f test* if $cc -c ../test.$src then set test.* if test -f "$1" then o="$*" mv $* .. for i in $o do if $cc -o test.exe ../$i then obj=`echo "$i" | sed -e 's,test.,,'` $executable test.exe || executable="test -r" set test* rm * if $cc -o test ../$i then rm $* set test.* if $executable "$1" then exe=`echo "$1" | sed -e 's,test.,,'` suffix_command=.$exe fi fi break 2 fi done fi fi done cd .. case $src in c) ;; *) echo '// ( int main(void) { class { public: int i; } j; j.i = 0; int k = j.i + 1; return k; }' > dialect.$src if $cc -c dialect.$src && $cc -o dialect.$exe dialect.$obj && $executable dialect.$exe then mv dialect.$src dialect.c rm -f dialect.$obj dialect.$exe if $cc -c dialect.c && $cc -o dialect.$exe dialect.$obj && $executable dialect.$exe then src=c else set x $cc while : do shift case $# in 0) break ;; esac case $1 in *=*) continue ;; esac case `echo $1 | sed -e 's,.*/,,'` in *CC*|*++*|*[xX][xX]*|*[pP][lL][uU][sS]*) ;; *) src=c ;; esac break done fi else src=c fi ;; esac set x x '(' 1 'int x;' 0 while : do shift shift case $# in [01]) break ;; esac rm -f test.$obj echo "$1" > test.$src $cc -c test.$src r=$? case $r in 0) test -f test.$obj || r=1 ;; *) r=1 ;; esac case $2:$r in 0:0) ;; 0:1) echo "$cc: not a C compiler: failed to compile \`\`$1''" >&4 exit 1 ;; 1:0) echo "$cc: not a C compiler: successfully compiled \`\`$1''" >&4 exit 1 ;; esac done hosttype=`package CC="$cc" || $SHELL -c "package CC='$cc'"` case $hosttype in *[Uu][Ss][Aa][Gg][Ee]:*) hosttype=`PATH=$_probe_PATH; export PATH; package CC="$cc" || $SHELL -c "package CC='$cc'"` ;; esac echo '#include int main(void){printf("hello");return 0;}' > dynamic.$src echo 'extern int sfclose(void) { return 0; }' > fun.$src if $cc -c dynamic.$src && $cc -c fun.$src then eval set x $probe_so while : do shift case $# in 0) break ;; esac for i in foo junk do rm -f dynamic.$exe if $cc -L. -o dynamic.$exe dynamic.$obj -l$i then : "there's really a -l$i"? else rm -f dynamic.$exe cat fun.$obj > lib$i$1 $cc -L. -o dynamic.$exe dynamic.$obj -l$i && $executable dynamic.$exe x=$? rm lib$i$1 case $x in 0) so=$1 rm -f dynamic.$exe > lib$i$1.1 $cc -L. -o dynamic.$exe dynamic.$obj -l$i && $executable dynamic.$exe x=$? rm lib$i$1.1 case $x in 0) sov=1 ;; esac break 2 ;; *) break ;; esac fi done k= for i in "" .1 .2 .3 .4 .5 .6 .7 .8 .9 do rm -f dynamic.$exe > libc$1$i $cc -L. -o dynamic.$exe dynamic.$obj && $executable dynamic.$exe x=$? (cd ..; rm $tmpdir/libc$1$i) case $x in 0) ;; *) k=X$k case $k in XXX) break ;; esac ;; esac done case $k in XXX) so=$1 sov=1 break ;; ?*) so=$1 break ;; esac done rm -f dynamic.$exe if $cc -o dynamic.$exe dynamic.$obj 2>e && $executable dynamic.$exe then e=`wc -l e` maybe= eval set x x $probe_binding while : do shift shift case $# in 0) break ;; esac rm -f dynamic.$exe $cc -o dynamic.$exe $1 dynamic.$obj 2>e && $executable dynamic.$exe || continue case $1 in ?*) case $maybe in "") maybe=$1 ;; *) maybe=-- ;; esac ;; esac case `wc -l e` in $e) ;; *) continue ;; esac d=`ls -s dynamic.$exe` rm -f dynamic.$exe $cc -o dynamic.$exe $2 dynamic.$obj 2>e && $executable dynamic.$exe || continue case `wc -l e` in $e) ;; *) continue ;; esac case `ls -s dynamic.$exe` in $d) ;; *) dynamic=$1 static=$2 maybe= break ;; esac done case $maybe in ""|--) ;; *) rm -f dynamic.$exe if $cc -o dynamic.$exe $maybe dynamic.$obj 2>e && $executable dynamic.$exe then e=`wc -l e` if $cc -o dynamic.$exe $maybe-bogus-bogus-bogus dynamic.$obj 2>e && $executable dynamic.$exe then case `wc -l e` in $e) ;; *) dynamic=$maybe ;; esac else dynamic=$maybe fi fi ;; esac fi fi eval set x $probe_version shift for o in "$@" do if $cc $o > version.out 2>&1 then version_string=`sed -e '/ is /d' -e 's/;/ /g' version.out | sed -e 1q` case $version_string in ''|*[Ee][Rr][Rr][Oo][Rr]*|*[Ff][Aa][Tt][Aa][Ll]*|*[Ww][Aa][Rr][Nn][Ii][Nn][Gg]*|*[Oo][Pp][Tt][Ii][Oo][Nn]*) ;; *) version_flags=$o version_stamp=";VERSION;$o;$version_string;PATH;$cc" break ;; esac fi done case $version_stamp in '') eval set x $probe_version shift echo 'int main(void) { return 0; }' > version.i for o in "$@" do if $cc -c $o version.i > version.out 2>&1 then version_string=`sed -e '/ is /d' -e 's/;/ /g' version.out | sed -e 1q` case $version_string in ''|*[Ee][Rr][Rr][Oo][Rr]*|*[Ff][Aa][Tt][Aa][Ll]*|*[Ww][Aa][Rr][Nn][Ii][Nn][Gg]*|*[Oo][Pp][Tt][Ii][Oo][Nn]*) ;; *) version_flags=$o break ;; esac fi done ;; esac echo 'int main(void){return 0;}' > hosted.$src $cc -o hosted.$exe hosted.$src && ./hosted.$exe && hosted=1 echo '#!'$sh' echo "" $@' > cpp chmod +x cpp case `./cpp -Dprobe` in *-Dprobe*) ;; *) cp /bin/echo cpp chmod u+w cpp ;; esac for prefix in $probe_ppprefix `echo $cc | sed -e '/cc\$/!d' -e 's,cc\$,,' -e 's,.*/,,'` do cp cpp ${prefix}cpp done echo "" > flags.$src echo '#pragma pp:version' > libpp.$src if test `realcppC=./cpp $cc -Dprobe -E flags.$src | tee cpp.out | grep -c '[-]Dprobe'` -eq 1 then ppenv='realcppC=${ppcmd}' elif test `cppC=./cpp $cc -Dprobe -E flags.$src | tee cpp.out | grep -c '[-]Dprobe'` -eq 1 then ppenv='cppC=${ppcmd}' elif test `_CPPNAME=./cpp $cc -Dprobe -E flags.$src | tee cpp.out | grep -c '[-]Dprobe'` -eq 1 then ppenv='_CPPNAME=${ppcmd}' elif test `_CPP=./cpp $cc -Dprobe -E flags.$src | tee cpp.out | grep -c '[-]Dprobe'` -eq 1 then ppenv='_CPP=${ppcmd}' elif test `$cc -Dprobe -E -%p+. flags.$src | tee cpp.out | grep -c '[-]Dprobe'` -eq 1 && test `$cc -Dprobe -E -%p+. flags.$src | wc -l` -eq 1 then ppopt='-%p+${ppdir}' elif test `$cc -Dprobe -E -Yp,. flags.$src | tee cpp.out | grep -c '[-]Dprobe'` -eq 1 then ppopt='-Yp,${ppdir}' elif test `$cc -Dprobe -E -Qpath $tmpdir flags.$src | tee cpp.out | grep -c '[-]Dprobe'` -eq 1 then ppopt='-Qpath ${ppdir}' elif test `$cc -Dprobe -E -tp -B./ flags.$src 2>err.out | tee cpp.out | grep -c '[-]Dprobe'` -eq 1 -a ! -s err.out then ppopt='-tp -B${ppdir}/' elif test `$cc -Dprobe -E -B./ flags.$src | tee cpp.out | grep -c '[-]Dprobe'` -eq 1 then ppopt='-B${ppdir}/' elif test `$cc -Dprobe -E -tp -h./ -B flags.$src | tee cpp.out | grep -c '[-]Dprobe'` -eq 1 then ppopt='-tp -h${ppdir}/ -B' elif test `$cc -Dprobe -E -t p,./cpp flags.$src | tee cpp.out | grep -c '[-]Dprobe'` -eq 1 then ppopt='-t p,${ppcmd}' else { eval set x $probe_verbose shift for o in "$@" do $cc -E $o flags.$src done } 2>&1 | sed -e "s/['\"]//g" > cpp.out fi set x `sed -e 's,[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]:\\\\,/,g' -e 's,\\\\,/,g' cpp.out` def= definclude="-I+C -I-H" stdinclude=$definclude case $hosted in "") usrinclude= ;; esac cmdinclude= while : do case $# in 0|1) break ;; esac shift case $1 in -A) case $2 in *\(*\)) shift prepred="$prepred `echo $1 | sed 's/\(.*\)(\(.*\))/\1 \2/'`" ;; esac ;; -A\(*\)) prepred="$prepred `echo $1 | sed 's/-A\(.*\)(\(.*\))/\1 \2/'`" ;; -[DI][-+][ABCDEFGHIJKLMNOPQRSTUVWXYZ]*) stdpp=1 case $1 in -I?[CH]) case $def in ?*) definclude="$definclude $1" ;; *) stdinclude="$stdinclude $1" ;; esac ;; -I-S*|-YI,*) usrinclude="`echo $1 | sed 's/....//'`" ;; -Y?,*) ;; -Y*) usrinclude="`echo $1 | sed 's/..//'`" ;; esac ;; -D) shift case $1 in [ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_]*=*) predef="$predef `echo $1 | sed -e 's/=.*//'`" ;; [ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_]*) predef="$predef $1" ;; esac ;; -Dprobe);; -D*) case $1 in -D[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_]*=*) predef="$predef `echo $1 | sed -e 's/^-D//' -e 's/=.*//'`" ;; -D[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_]*) predef="$predef `echo $1 | sed -e 's/^-D//'`" ;; esac ;; -I) shift case $1 in /*) case $def in ?*) definclude="$definclude $1" ;; *) stdinclude="$stdinclude $1" ;; esac cmdinclude="$cmdinclude $1" ;; esac ;; -I/*) f=`echo X$1 | sed 's/X-I//'` case $def in ?*) definclude="$definclude $f" ;; *) stdinclude="$stdinclude $f" ;; esac cmdinclude="$cmdinclude $f" ;; -U) shift undef="$undef $1" ;; -U*) undef="$undef `echo $1 | sed 's/^-U//'`" ;; flags.$src)def= ;; esac done stdinclude="$stdinclude $definclude" case " $stdinclude " in *\ $usrinclude\ *) case $usrinclude in /usr/include) usrinclude= ;; *) case " $stdinclude " in *\ /usr/include\ *) usrinclude= ;; *) usrinclude=/usr/include ;; esac ;; esac ;; esac tstinclude=`$cc -v -E flags.$src 2>&1 | sed -e '1,/[iI][nN][cC][lL][uU][dD][eE][ ]*<[.][.][.]>/d' -e '/^[eE][nN][dD] [oO][fF] [sS][eE][aA][rR][cC][hH]/,\$d'` j=$tstinclude case $j in */*) ;; *) j=$cmdinclude ;; esac tstinclude= good= nogood= c_hdr="stdio.h ctype.h" C_hdr="libc.h" for i in $j do if test -d "$i" then tstinclude="$tstinclude $i" h= for f in $c_hdr do if test -f "$i/$f" then case $i in */CC) nogood=1 ;; *) good=1 ;; esac else h="$h $f" fi done c_hdr=$h h= for f in $C_hdr do if test -f "$i/$f" then case $i in */CC) nogood=1 ;; *) good=1 ;; esac else h="$h $f" fi done C_hdr=$h fi done case $nogood in 1) good=0 ;; esac case $good in 1) case $c_hdr in ?*) bad=1 usrinclude=/usr/include set '' $tstinclude /usr/include ;; *) set '' $tstinclude ;; esac shift stdinclude=$* echo "#include " > include.$src $cc -E include.$src | sed -e '/# 1 "[\\/]/!d' -e 's,[^"]*",,' -e 's,[\\/][^\\/]*".*,,' -e 's,[\\/]sys,,' > include.out for f in `cat include.out` do if test -d "$f" then g=`echo $f | sed -e 's,[\\/][\\/]*[^\\/]*$,,'` case " $stdinclude " in *\ $f\ *|*\ $g\ *) ;; *) stdinclude="$stdinclude $f" case $f in /usr/include) usrinclude=$f ;; esac bad=1 ;; esac fi done ;; *) case $ppopt$ppenv in ?*) echo '#!'$sh' echo $VIRTUAL_ROOT | sed "s/:.*//"' > cpp chmod +x cpp ppcmd=cpp ppdir=. eval x='`'$ppenv '$'cc -E $ppopt flags.$src'`' case $x in ?*) tstinclude=$x/usr/include ;; esac cp /bin/echo cpp chmod u+w cpp ;; esac eval set x $probe_include while : do shift case $# in 0) break ;; esac echo "#include <$1>" > include.$src $cc -E include.$src done > include.out ccinclude= x=$stdinclude stdinclude= subinclude= for f in $x $tstinclude `sed -e 's,\\\\,/,g' -e 's,///*,/,g' -e 's,"[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]:/,"/,g' -e '/^#[line ]*[0123456789][0123456789]*[ ][ ]*"[\\/]/!d' -e 's/^#[line ]*[0123456789][0123456789]*[ ][ ]*"\(.*\)[\\/].*".*/\1/' include.out | sort -u` do case $f in -*) ;; */) f=`echo $f | sed -e 's,//*\$,,'` ;; */.) f=`echo $f | sed -e 's,//*.\$,,'` ;; esac case $f in -I*) ;; */cc) ccinclude=1 ;; */sys) continue ;; */include/*/*) ;; */include/*) subinclude="$subinclude $f" continue ;; esac if test -d "$f" then case " $stdinclude " in *\ $f\ *) ;; *) stdinclude="$stdinclude $f" ;; esac fi done rm include.out case $ccinclude in ?*) eval set x $probe_include while : do shift case $# in 0) break ;; esac echo "#include " > include.$src if $cc -E include.$src > /dev/null then break fi done case $# in 0) ;; *) x=$stdinclude stdinclude= for f in $x do case $f in */cc) ;; *) stdinclude="$stdinclude $f" ;; esac done ;; esac ;; esac case $subinclude in ?*) for i in $subinclude do for j in $stdinclude do case $i in $j/*/*) ;; $j/*) both= eval set x $probe_include while : do shift case $# in 0) for k in $both do echo "#include <$k>" > include.$src $cc -E include.$src > include.out I=`grep -c $i/$k < include.out` J=`grep -c $j/$k < include.out` case $I:$J in 0:*) ;; *:0) stdinclude="$i $stdinclude" break ;; esac done continue 3 ;; esac if test -f $i/$1 then if test ! -f $j/$1 then break 2 fi both="$both $1" fi done ;; $j) continue 2 ;; esac done stdinclude="$i $stdinclude" done ;; esac { for i in $stdinclude do case $i in $usrinclude) ;; *) echo $i $i ;; esac done eval set x $probe_include while : do shift case $# in 0) break ;; esac echo "#include <$1>" > t.c p= for j in `$cc -E t.c | grep "$1" | sed -e 's,\\\\,/,g' -e 's,"[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]:/,"/,g' -e '/^#[line ]*1[ ][ ]*"[\\/]/!d' -e 's/^#[line ]*1[ ][ ]*"\(.*\)[\\/].*".*/\1/'` do j=`echo $j | sed -e 's,///*,/,g' -e 's,/$,,'` case $p in ?*) echo $p $j ;; esac p=$j done done case $usrinclude in ?*) echo $usrinclude $usrinclude ;; esac } | tsort > tmp.tmp tstinclude=`cat tmp.tmp` bad= for i in $stdinclude do case " $tstinclude " in *" $i "*) ;; *) bad=1 break ;; esac done ;; esac case $bad in "") x=$stdinclude stdinclude= z= for i in $tstinclude do case " $x " in *" $i "*) stdinclude="$stdinclude $i" z=$i ;; esac done case $usrinclude in '') usrinclude=$z ;; esac ;; esac case $hosted in "") case $usrinclude in /usr/include) usrinclude= ;; esac ;; esac case $usrinclude in ?*) case " $stdinclude " in *\ $usrinclude\ *) x=$stdinclude stdinclude= for f in $x do case $f in $usrinclude) ;; *) stdinclude="$stdinclude $f" ;; esac done ;; esac ;; esac # drop dups -- they creep in somehow x=$stdinclude stdinclude= for f in $x do case " $stdinclude $usrinclude " in *" $f "*) ;; *) stdinclude="$stdinclude $f" ;; esac done ksh-1.0.10/src/cmd/INIT/Mamfile000066400000000000000000000107011465301102200157410ustar00rootroot00000000000000note * note * This build script is in an extended Make Abstract Machine (MAM) note * language. Documentation is at: src/cmd/INIT/README-mamake.md note * setv MAMAKE_STRICT 4 setv INSTALLROOT ../../.. setv CC cc note * note * initialization for the build system note * make install virtual loop DIR bin include/ast lib/lib lib/probe/C/make lib/probe/C/pp lib/probe/C/mam make %{INSTALLROOT}/%{DIR} exec - mkdir -p %{@} done done note * note * install helper scripts note * make %{INSTALLROOT}/bin/probe make probe make probe.sh makp C+probe makp make.probe exec - cat %{^} > %{@} done exec - cp %{<} %{@} && chmod u+w,+x %{@} done exec - cp -f %{<} %{@} done loop SCRIPT iffe mktest regress crossexec mkreq mkreq-maplib mprobe proto dylink mkdeps make %{INSTALLROOT}/bin/%{SCRIPT} make %{SCRIPT} makp %{@}.sh exec - cp %{<} %{@} && chmod u+w,+x %{@} done exec - cp -f %{<} %{@} done done make %{INSTALLROOT}/bin/mamprobe note * the probe.sh dependency is needed for mamake to redo the probe when C+probe or make.probe is edited prev probe.sh makp mamprobe.sh exec - cp %{<} %{@} && chmod u+w,+x %{@} done note * note * probe initialization note * make %{INSTALLROOT}/lib/probe/C/probe prev C+probe exec - cp -f %{<} %{@} done make %{INSTALLROOT}/lib/probe/C/mam/probe prev mprobe exec - cp -f %{<} %{@} done make %{INSTALLROOT}/lib/probe/C/mam/mprobe prev mprobe exec - cp -f %{<} %{@} done make %{INSTALLROOT}/lib/probe/C/make/probe prev probe exec - cp -f %{<} %{@} done note * note * check if -ldl is required note * note * NOTE: this works around the sgi botch: note * (1) irix 5.* made -ldl optional but warned note * (2) irix 6.* has no -ldl note * (3) dynamic progs built on irix 5.* and using -ldl fail note * at runtime on irix 6.* because -ldl is not there note * make %{INSTALLROOT}/lib/lib/dl make dl.req makp dl.c exec - mkreq-maplib %{CC} : dl : %{^} : dl prev mkreq-maplib done exec - cp -f %{<} %{@} done note * note * requiring these is a botch note * make %{INSTALLROOT}/lib/lib/iconv make iconv.req makp iconv.c exec - mkreq-maplib %{CC} : iconv : %{^} : iconv prev mkreq-maplib done exec - cp -f %{<} %{@} done make %{INSTALLROOT}/lib/lib/w make w.req makp w.c makp w2.c exec - mkreq-maplib %{CC} : w : %{^} : w prev mkreq-maplib done exec - cp -f %{<} %{@} done note * note * miscellaneous -l* checks note * make %{INSTALLROOT}/lib/lib/intl make intl.req makp intl.c exec - mkreq-maplib %{CC} : intl : %{^} : intl prev mkreq-maplib done exec - cp -f %{<} %{@} done make %{INSTALLROOT}/lib/lib/m make m.req makp m.c makp m2.c makp m3.c makp m4.c makp m5.c makp m6.c exec - mkreq-maplib %{CC} : m : %{^} : m prev mkreq-maplib done exec - cp -f %{<} %{@} done make %{INSTALLROOT}/lib/lib/nsl make nsl.req makp nsl.c exec - mkreq-maplib %{CC} : nsl : %{^} : nsl prev mkreq-maplib done exec - cp -f %{<} %{@} done note * note * what was sco smoking note * almost all of gethost* are in -lnsl except gethostbyname which note * is in -lsocket which isn't needed to resolve socket() but seems note * to do the -lnsl job note * make %{INSTALLROOT}/lib/lib/socket make socket.req makp socket.c prev nsl.c exec - mkreq-maplib %{CC} : socket : %{^} : socket prev mkreq-maplib done exec - cp -f %{<} %{@} done note * note * more substance abuse note * gdbm's ndbm "compatibility" doesn't supply , instead supplies note * which provides K&R prototypes *and* it requires -lgdbm note * some implementations use -lndbm, others -ldbm, still others -lc note * this is why unix is starting to look like windows note * this map allows makefiles to use -ldbm on all systems note * note * and this just in: sometimes its and possibly -lgdbm_compat note * note * at least the -l* buck stops here note * make %{INSTALLROOT}/lib/lib/dbm make dbm.req makp db.c makp gdbm.c makp gdbm1.c makp gdbm2.c exec - mkreq-maplib %{CC} : dbm : %{^} : db gdbm_compat gdbm ndbm dbm prev mkreq-maplib done exec - cp -f %{<} %{@} done done install make test dontcare virtual make test.iffe virtual makp iffe.tst exec - regress iffe.tst iffe done make test.mamake virtual makp mamake.tst exec - : testing non-libast mamake at $PWD/mamake : exec - regress mamake.tst mamake done done test ksh-1.0.10/src/cmd/INIT/README-mamake.md000066400000000000000000000661701465301102200171670ustar00rootroot00000000000000# mamake and the MAM language # MAM (Make Abstract Machine) is a simple rule-based make language that is implemented in just eight four-letter commands and four attributes, yet allows unlimited flexibility as it can execute arbitrary shell code. The program implementing MAM, `mamake`, is a portable C90 program written in a single file, `mamake.c`. This allows ksh 93u+m, or other programs using this build system, to be built using only a standard C compiler and utilities installation without any other dependencies or complications. MAM was originally designed by Glenn Fowler at AT&T and intended as an abstraction layer for `make` implementations such as AT&T `nmake`. The [original documentation](https://web.archive.org/web/20041227143022/http://www2.research.att.com/~gsf/mam/mam.html) for MAM specified a more extensive and markedly different language than was actually implemented in `mamake.c`. This file documents the MAM implementation that is currently in use. Since fixing and maintaining AT&T `nmake` proved impractical, `mamake` is used here as a full `make` replacement, with some features gradually added to the language to facilitate human maintenance of the `Mamfile`s. ## Table of contents ## * [General overview of the MAM language](#user-content-general-overview-of-the-mam-language) * [Strict and legacy modes](#user-content-strict-and-legacy-modes) * [MAM variables](#user-content-mam-variables) * [Special expansion syntax](#user-content-special-expansion-syntax) * [Automatic variables](#user-content-automatic-variables) * [Commands](#user-content-commands) * [Comments](#user-content-comments) * [Rules](#user-content-rules) * [Simple prerequisite rules](#user-content-simple-prerequisite-rules) * [Referencing previously defined rules](#user-content-referencing-previously-defined-rules) * [Setting MAM variables](#user-content-setting-mam-variables) * [Shell actions](#user-content-shell-actions) * [Viewpathing](#user-content-viewpathing) * [Execution](#user-content-execution) * [Strict level 2+ change](#user-content-strict-level-2-change) * [Declaring common code for shell actions](#user-content-declaring-common-code-for-shell-actions) * [Binding libraries](#user-content-binding-libraries) * […while scanning and sorting leaf directories](#user-content-while-scanning-and-sorting-leaf-directories) * […while building the current directory](#user-content-while-building-the-current-directory) * [Repeatedly iterating through a block](#user-content-repeatedly-iterating-through-a-block) * [Debugging mamake](#user-content-debugging-mamake) * [Appendix: Main changes from the AT&T version](#user-content-appendix-main-changes-from-the-att-version) ## General overview of the MAM language ## MAM is a simple declarative language, easy to parse for machines and easy to read for humans, in which targets are defined that correspond to files that need to be generated or updated, or that are prerequisites. `mamake` reads build scripts from a file, `Mamfile` by default, from start to finish. As it encounters `make` *target*…`done` blocks, it ‘makes’ (updates) the *target*s using the instructions within those blocks. Those instructions may declare dependencies and/or specify shell command actions. If a *target* is specified on the command line, `mamake` will update the actions contained within that target and ignore the rest. ### Strict and legacy modes ### By default, `mamake` remains fully backward compatible with Mamfiles as originally generated by AT&T `nmake`. If the `MAMAKE_STRICT` variable is set, some backward incompatible changes and deprecation warnings are activated to ensure correct operation and to facilitate human maintenance of the Mamfiles. A numeric value assigned to `MAMAKE_STRICT` indicates the backward incompatibility level. The empty value is equivalent to level 1. These are called the "strict levels" and their absence the "legacy mode", also known as strict level 0. Each time backward incompatible changes are introduced to `mamake` that would break previous Mamfiles, those are made subject to a `MAMAKE_STRICT` value of one higher than the previous highest one; details of those changes are documented throughout this file and listed in the appendix below. This makes it possible to test or backport old code using the current build system. Current Mamfiles should use the highest strict level available. The current highest available strict level is **4**. ## MAM variables ## MAM variables are imported from the environment or set via `setv` (see below). They are referenced and expanded using the syntax `%{`*variable_name*`}`. Except for the special expansion syntax described below, it is an error to reference an undefined variable using a `%` expansion. > *Obsolete:* At strict levels 3 and below, expansions may start with `${` > instead of `%{`, making the syntax similar to `sh`(1), though the braces are > *not* optional. This syntax potentially conflicts with the expansion of shell > variables in shell actions. If an undefined MAM variable is expanded with the > `$` syntax and the variable name is valid in `sh`(1) syntax, the expansion is > left in place unexpanded, otherwise it is removed. At strict level 2 and 3, > it is left unexpanded even if it is not a valid `sh`(1) variable name; this > allows POSIX shell expansions like `${foo#*bar}` in shell actions. > Old `$` and new `%` syntax may be mixed. Variables always expand to their literal values, and variable references (including in `setv` values) only work for previously defined variables. > *Obsolete:* At strict levels 1 and 0, the expansion of MAM variable references > is recursive, i.e., the value may itself contain other variable references. > Beware: there is no reference loop detection; any variable referencing itself > directly or indirectly will cause `mamake` to crash. Note that, in shell actions (see `exec` below), MAM variables are expanded before the script ever reaches the shell. Consequently, the use of single shell quotes `'`…`'` does not stop their expansion as you might expect. ### Special expansion syntax ### In `%{`*variable*`?`*str*`?`*x*`?`*y*`?}`, if the string value of the *variable* is identical to *str*, then the value *x* is substituted, otherwise *y*. A *str* of `*` is treated specially: if the *variable* is set to a non-empty string, then the value *x* is substituted, otherwise *y*. The *x* and *y* values may result from nested variable references. The last `?` is optional. In `%{`*variable*`-`*x*`}`, the value of *variable* is substituted if it is defined and non-empty, otherwise the value of *x* is substituted. In `%{`*variable*`+`*x*`}`, *x* is substituted if the value of *variable* is defined and non-empty, otherwise the reference is removed. Note that, unlike in `sh`(1), no distinction is made between an undefined variable and a defined variable with an empty value. ### Automatic variables ### The following variables are set and updated automatically. They are inspired by similar variables in `make` implementations, but since `mamake` is different, so are these variables. `%{@}` is the name of the rule currently being made. `%{<}` is the name of the prerequisite rule (`make`…`done` or `prev`) that was *last* processed within the current rule. `%{^}` is a space-separated list of names of all the current rule's previously processed prerequisites. `%{?}` is a space-separate list of the current rule's previously processed prerequisites that have been updated by a shell action (see `exec` below) during the current `mamake` run. Prequisites that were already up to date, or prerequisites that do not contain a shell action, are not included. ## Commands ## MAM commands have the following basic form: *command* [ *argument* [ *operand string* ] ] The *command* name consists of four lower-case letters. Unrecognized commands or attributes are an error. The *argument* is a single word. The *operand string* is any arbitrary text until the end of the line. ### Comments ### `note` is the comment command and is ignored. In the legacy mode, `info` and `meta` are also ignored. ### Rules ### `make` *target* [ *attribute* … ] `done` [ *target* ] A `make`…`done` block defines the rule named *target* using the other commands described here. Unless the `virtual` attribute is used, *target* names the pathname of the file generated or referenced by the rule. `mamake` processes the commands within the block if the *target* is out of date or if the rule has the `virtual` attribute (see below). The *target* may be repeated as the operand to the `done` command. In that case, it is matched against the current `make` *target* and any mismatch will produce a "mismatched done statement" error. If it is omitted, the current `make` *target* is assumed. Dependencies may be defined in two ways: 1. By nesting `make`…`done` blocks: the enclosing rule is the parent and the enclosed rules are the prerequisites. 2. By using the `prev` command (see **Referencing previously defined rules** below) to reference a previous `make`…`done` block. The dependency is defined as if that block were repeated at the `prev` command's location. If the block contains one or more `exec` commands (see **Shell actions** below), the `done` command executes the shell script defined by them. A `make`…`done` rule may lack any `exec` action, in which case it declares a dependency (a file that must be present and whose timestamp is propagated to potentially outdate parent rules, such as a source code file that comes with the distribution or a header file preinstalled by a previously run Mamfile). The rule may include its own dependencies. If it does not have any dependencies of its own, the `make`…`done` block is empty, with `make` immediately followed by `done`. The one-line `makp` command (see below) may be used as a shorthand for the latter case. Making a prerequisite that is currently being made, or one that has already been made, produces a warning; at strict level 3 and up, this is an error. One or more *attribute*s may be specified by appending them to the `make` command. (At strict levels \< 2, they may also be appended to the `done` command; the effect is the same either way. At strict level 1, this produces a deprecation warning.) Attributes apply to the current rule only and do not propagate down to nested rules. The following *attribute*s are available: * `dontcare`: Marks files that do not need to exist. If the file exists then its last-modified timestamp is checked and propagated, otherwise it is silently ignored. * `ignore`: The timestamp associated with the *target* is ignored in dependency resolution. * `notrace`: Disables echoing (xtrace) of shell action commands. This does not disable the trace header for the containing rule (see *Shell actions* below). * `virtual`: Marks a rule that is not associated with any file. The commands within are executed every time the rule is processed. By convention, a virtual rule with target `install` performs pre-installation. > *Obsolete:* > At strict level 4 and up, the following *attribute* is not available. > * `implicit`: Equivalent to `dontcare`. > > At strict level 1 and up, specifying the following *attribute*s is > deprecated and will produce a warning; at strict level 2 and up, > specifying these is an error. > * `archive`: Ignored. > Historically used to mark the generation of an `ar`(1) archive. > * `generated`: Marks rules that produce output files generated by a shell action. > The explicit assignment of this attribute is ignored at strict level 1. > The `exec` command implicitly assigns this attribute. > If a rule has this attribute, other rules dependent on this rule > will avoid applying viewpathing based on this rule. > * `joint`: Ignored. > Historically used to mark one of a group of rules that are built by a single shell action. ### Simple prerequisite rules ### `makp` *target* [ *attribute* … ] `makp` creates a rule that declares a dependency on a prerequisite file named by *target* in a manner equivalent to an empty `make` *target*/`done` block, with the optional *attribute*s applied to the new rule. A nonexistent prerequisite is an error unless a `virtual` or `dontcare` attribute is given. Declaring a dependency on a prerequisite that is currently being made (i.e.: directly or indirectly within that prerequisite's block) is an error. ### Referencing previously defined rules ### `prev` *target* If *target* matches a previously defined rule, `prev` adds a dependency on that rule to the current rule. This is used to make a rule a prerequisite of multiple `make`…`done` blocks without repeating the rule. It is an error to specify attributes, because the attributes of the referenced rule are used. In the legacy mode, attributes are silently ignored. > *Obsolete:* If the strict level is \< 4, and if *target* does not match a > previously defined rule, then the following applies. In the legacy mode, > `prev` creates an empty dummy rule and ignores the *attribute*s; this is > for backward compatibility. At strict levels 1 and up, `prev` in this > context is equivalent to `makp` (see above). Declaring a dependency on a > prerequisite that is currently being made produces a warning; at strict > level 3, this is an error. ### Setting MAM variables ### `setv` *variable* [ *defaultvalue* ] Defines a new MAM *variable*, optionally assigning the initial *defaultvalue*. If the variable already has a value, the `setv` command is ignored; assigning a new value is not possible. When `mamake` starts, it imports all environment variables as MAM variables, so any variable's default value can be overridden by exporting an environment variable by its name. Any leading and trailing whitespace is stripped from the value. The value is otherwise taken entirely literally, with no parsing of quotes, etc. > *Obsolete:* If the strict level is less than 2 and the *defaultvalue* > begins and ends with double quotes (`"`), those quotes are discarded, > though double quotes elsewhere in the value are not treated specially. When the *variable* is `CC`, `mamake` runs the `mamprobe` script to probe the C compiler for flags and features, or uses that script's stored results if not outdated. The results are stored as a series of `setv` commands in a file in the directory `%{INSTALLROOT}/lib/probe/C/mam`, the file name being a hash of full path to the compiler indicated by `%{CC}`. That results file is then read and included in the current Mamfile as if it followed the `setv CC` command. ### Shell actions ### `exec` `-` *code* One or more `exec` commands within a `make`…`done` block define a shell script that is run to generate the *target*. The argument following `exec` is ignored; by convention it is `-`. Each `exec` command appends a line of code to the shell script for the current rule. It is customary for a rule's `exec` commands to be contiguous, but not necessary. Before adding each line of code to the script, MAM variable references (see **MAM variables** above) are expanded; their literal values are inserted into the *code* line (beware: no quoting is applied!). Because variables are expanded when the line is encountered, the value of the automatic variables for any `exec` line depends on the position of the line in the rule. #### Viewpathing #### After MAM variable expansion, *viewpathing* is applied. The first colon-separated element of `%{VPATH}` is considered the object code directory and the second the source code directory; viewpathing provides the first with a vew to the second. Viewpathing applies two transformations. The first is *prerequisite replacement*. Each word (separated by whitespace, `;`, `(`, `)`, `` ` ``, `|`, `&` or `=`) is searched for in the current rule's prerequisites, and if it matches the name of a prerequisite that was not generated by a shell action, it is replaced by the canonical path to it in the source directory, ensuring that things like prerequisite headers are found. The second is *include flag duplication*. After every argument that looks like a compiler include directory path (i.e., starting with `-I`) with a relative path name (i.e., a directory path that does *not* start with a `/`), another argument starting with `-I` is inserted with that path name prefixed by the path to the source directory. This mechanism ensures that headers are found both in the object directory and in the source directory. It is processed regardless of the command; for example, it also works for compiler flags passed to `iffe`(1). Note that shell quotes are *not* treated specially. If an argument starting with `-I` ends in a shell quote without preceding whitespace, that trailing quote is repeated along with the prefixed path and causes a syntax error. #### Execution #### When `mamake` encounters the `done` command, the script is executed by the shell whose path is in the `SHELL` environment variable or, absent that, by `sh`(1). Each shell action is run in a new instance of the shell. Before executing the script, an empty line followed by a trace header in the following format is written to standard error: # path/to/Mamfile: startline-endline: rule During script execution, shell action comands are traced using the shell's xtrace option, unless the rule has the `notrace` attribute. #### Strict level 2+ change #### At strict level 2 and up, `mamake` turns off global pathname expansion (globbing) using `set -f` to make safer MAM variable expansion and shell field splitting possible; this avoids unexpected pathname expansion if a value contains `?`, `*` or `[`. A shell action can override this using `set +f`; this should only be done for individual commands in a `(`subshell`)`. ### Declaring common code for shell actions ### `shim` `-` *code* One or more `shim` commands declare a ‘shim’: a common section of `sh`(1) code that will be automatically inserted in front of subsequent shell actions upon execution. Like `exec`, `shim` combines multiple lines of *code* into one section, with MAM variables expanded at declaration time and viewpathing applied at execution time. The effect of `shim` is global. One use case is defining a shell function that each shell action can call. For example, such a function might invoke the compiler with a series of compiler flags common to all compiler invocations, with other flags added via arguments to the function, so the common flags do not need to be repeated in every shell action. Only one shim is active at a time, but it can be redefined. When the next `exec` command is encountered, the shim is marked ready for use. The next time a `shim` command is encountered after that, it starts a new shim from scratch that affects subsequently executed shell actions. A single `shim -` deactivates the shim. ### Binding libraries ### `bind` `-l`*libraryname* [ `dontcare` ] These commands are scanned for while sorting leaf directories for recursive building, and executed as normal commands while building the current directory. #### …while scanning and sorting leaf directories #### Any leaf directories with names that start with `INIT` will always be built before all others. For all other leaf directories, the presence of any `bind` command of the form `bind -lfoo` anywhere in a leaf directory's Mamfile causes the leaf directory named `libfoo` (if it exists) to be a prerequisite of that leaf directory. The prerequisite leaf directory does not have to be in the same parent directory, as long as it is processed as part of the same scan. At this stage, attributes are ignored. #### …while building the current directory #### The `bind` command takes an argument of the form `-l`*libraryname*, which causes a MAM variable `mam_lib`*libraryname* to be defined (see **MAM variables** above). The variable will contain either the compiler argument for linking to the library *libraryname* (either the `-l`*libraryname* flag, or the full path in case of a static library) or, if the `dontcare` attribute is specified, possibly the empty string. Any library dependencies are also included (see below). This can be used both for AST libraries shipped with the distribution and for system libraries. If the current rule's name starts with `FEATURE/` or is `configure.h`, this is all that the `bind` command does. Otherwise, it also does the following. For each corresponding *.a library archive dependency built previously, its time stamp is checked and the current target is marked as outdated if it is newer, as if a `prev` had been executed for it. The variable set by `bind` is global, but the marking of the target as outdated applies to the current rule only, so it may be necessary to repeat a `bind` command when statically linking executables that depend on a library, otherwise they may not be relinked when the library changes. The `mam_lib`*libraryname* variable will not be regenerated when repeating a `bind`. There is also a mechanism to communicate library dependency information across Mamfiles and `mamake` invocations. If a file named *libraryname*`.req` in the current directory or an `%{INSTALLROOT}/lib/lib/`*libraryname* file exists, `mamake` processes each of the words in the form `-l`*libraryname* in its contents as if they were arguments to `bind` commands and the resulting values are appended to the value of `mam_lib`*libraryname* as dependencies separated by spaces. `mamake` does not create these dependency files; they are expected to be generated by Mamfile shell actions (see **Shell actions** above). The `INIT` package preinstalls the `mkreq` and `mkreq-maplib` scripts for this purpose. If no such dependency file exists, and the `dontcare` attribute is added, then `mamake` compiles a small test program on the fly to check if the library exists; if this fails, the `mam_lib`*libraryname* variable will be emptied. Cross-directory dependencies on AST library headers (preinstalled in `$INSTALLROOT/include/ast`) are similarly communicated via a file with the path `%{INSTALLROOT}/lib/mam/`*libraryname*. The `bind` command automatically includes this file as necessary. Note that this may have side effects on the automatic variables. The `INIT` package preinstalls the `mkdeps` script that Mamfile shell actions should use to generate this file while building each library. The generated file is expected to: 1. set the `INCLUDE_AST` variable to `%{INSTALLROOT}/include/ast`; 2. define a single virtual rule by the name of `_hdrdeps_lib`*libraryname*`_` which contains all the rules that define the library's public `include/ast` headers and how they depend on each other. This way, Mamfiles can declare a dependency on a single header and all its dependencies using a simple `prev %{INCLUDE_AST}/`*headername*`.h` command. Any `bind -l`*libraryname* command will automatically apply the dependencies defined in the corresponding file to the context of the current rule. The non-existence of this file is not an error and is silently ignored. ### Repeatedly iterating through a block ### `loop` *variable* *word* [ *word* … ] `done` `loop` reads the lines contained between it and the corresponding `done` repeatedly with a named *variable* set to each of the *word*s. The lines are processed as part of the rule containing the loop. The *variable* is restored to its previous state after the loop completes. Note that `loop` causes repeated reading and processing of Mamfile lines, *not* necessarily repeated execution. For instance, a loop can be used to consolidate repetitive `make`…`done` rules. However, each rule is only made once and subsequent rules by the same name are an error at strict level 3 and up, or skipped over at strict \< 3. So it only makes sense to do this if the contained make target names are modified by the expansion of the iteration *variable*. `loop` requires a seekable input file (i.e.: not a pipe). ## Debugging mamake ## If the environment variable `MAMAKE_DEBUG_PREFIX` is exported, its value is split into whitespace-separated command arguments and inserted before every `mamake` invocation. This allows debugging `mamake` with tools like `valgrind`, `strace`, or `dtruss`, which are used by passing a command to them as a set of operands. ## Appendix: Main changes from the AT&T version ## Compared to the original AT&T version, ksh 93u+m made a number of changes to `mamake` that facilitate correct operation and make it easier to maintain Mamfiles by hand. The following lists the important changes. * Introduced the notion of ‘strict mode’ levels that tidy things up by activating some backward incompatible changes and deprecation warnings. * Indentation and word separators may use any whitespace (e.g. tabs), not only spaces. * Fixed a bug that stopped a rule marked `virtual` (not associated with any file) from being executed if a file by that rule's name exists. * Unrecognized commands and rule attributes throw an error instead of being silently ignored. This also applies to the `bind` command with an argument not starting with `-l`. * It has been made optional to repeat the `make` target after `done`. * The `notrace` attribute was added to disable xtrace for a rule's shell action. * The automatic variables `%{@}`, `%{<}`, `%{^}` and `%{?}` have been added. * An iteration block command, `loop`…`done`, has been added. * A command to set common code for shell actions, `shim`, has been added. * The `bind` command now reads library header dependency rules from a central rules file that is automatically generated for each library by the supplied `mkdeps` script. * Attempting to make a rule that has already been made produces a warning. * Attempting to declare a dependency on a rule currently being made produces a warning. * MAM expansions may start with `%{` instead of `${`, avoiding conflicts and confusion with the shell's `${` syntax in shell actions. * The `makp` command may be used instead of an empty `make`…`done` block to declare a simple prerequisite with optional attributes. * **At strict level 1 and up:** * Appending attributes to `done` instead of `make` is deprecated and produces a warning. * The ignored `archive` and `joint` attributes are deprecated. * Explicitly specifying the `generated` attribute is deprecated. * The dummy `info` and `meta` commands are unavailable instead of ignored. * The `prev` may be used as an equivalent of `makp`. * When `prev` references a previously processed target, attributes are an error instead of being ignored. * The legacy `silent` and `ignore` command prefixes are unavailable. * **At strict level 2 and up:** * Appending attributes to `done` instead of `make` is an error. * The `archive` and `joint` attributes are unavailable. * Explicitly specifying the `generated` attribute is an error. * All variable references are expanded to their literal values without scanning the values for recursive variable references. * `setv` does not remove leading and trailing `"` from the value. * Shell actions have pathname expansion (globbing) disabled by default. * **At strict level 3 and up:** * Attempting to make a rule that has already been made is an error. * Attempting to declare a dependency on a rule currently being made is an error. * **At strict level 4 and up:** * MAM expansions can no longer start with `${`. Only `%{` is recognized. * The `prev` command may no longer be used as an equivalent of `makp`. * The `implicit` attribute is not available. ksh-1.0.10/src/cmd/INIT/RELEASE000066400000000000000000001454361465301102200154650ustar00rootroot00000000000000This file is of historical interest only. For recent changes in both ksh 93u+m and the accompanying libraries, see the file NEWS in the top-level directory. ____ 12-07-17 iffe.sh: add C code NOTE("...") to amend --verbose output 12-06-26 iffe.sh: fix "npt foo" to handle function-like macro foo() 12-06-20 package.sh: use $KSH for rt in "results test" 12-06-15 Makefile: add PLUGIN_LIB to $INSTALLROOT/bin/.paths and BUILTIN_LIB => PLUGIN_LIB 12-06-15 package.sh: add PLUGIN_LIB to $INSTALLROOT/bin/.paths and BUILTIN_LIB => PLUGIN_LIB 12-06-13 package.sh: handle admin.db column output 12-06-08 iffe.sh: fix 12-06-06 typo 12-06-06 iffe.sh: check for -l* in reverse and accumulative order (e.g., for -last & -lm) 12-06-04 package.sh: always check $INSTALLROOT/lib/package/profile 12-05-31 Makefile: ID=ast; $(INSTALLROOT)/prototyped.h => $(INSTALLROOT)/$(ID)/prototyped.h 12-05-28 iffe.sh: API foo YYYYMMDD => FOOAPI(rel) test macro 12-05-24 package.sh: change admin.db comment => owner attributes 12-04-25 ratz.c: add sear -k option to keep installation tmp dir on exit 12-04-17 package.sh: skip sh version logic for ``use'' 12-04-17 cc.ibm.risc*: _LARGEFILE64_SOURCE => _LARGE_FILE_API moved to libast/features 12-04-09 cc.ibm.risc*: speak aixese for _LARGEFILE64_SOURCE 12-02-29 cc.darwin.i386*: handle default cc vs kernel bittedness 12-02-29 C+probe: add __TIMESTAMP__ to the nopredefined list 12-02-29 package.sh: don't assume grep -q or /usr/local/lib in LD_LIBRARY_PATH 12-02-29 package.sh: fix ksh vs -lcmd compatibility checks 12-02-23 iffe.sh: checkcc() before checkread() for sensible diagnostics 12-02-14 package.mk: { --clobber --compare --link=lib*.a* } for --mam=static 12-02-14 package.mk: export LICENSEFILEDEFAULT instead of LICENSEFILE 12-02-14 package.sh: handle @(cc|ld).${HOSTTYPE}* intercepts 12-02-07 package.sh: add { clean clobber } actions 12-02-02 regress.sh: fix ulimit -c defaults for --nokeep 12-01-18 regress.sh: add INPUT|OUTPUT|ERROR -e 'filter' to filter before comparison 12-01-21 package.sh: fix `admin make' bug that created unused $INSTALLROOT/lib 12-01-21 Makefile: :PACKAGE: license=ast -- oops 12-01-20 cc.darwin,cc.mvs.390: tmp=/tmp/cc.${USER:-$LOGNAME}.$$.err 12-01-12 package.sh: add admin make share closure to handle alternate HOSTTYPEs 11-12-13 iffe.sh: add /**/ test code comment to disable default #include 11-11-11 C+probe: test for .so before .sl 11-10-26 package.sh: don't forget about *.pkg for admin update 11-10-18 cc.*-icc: update and add more 11-10-11 package.sh: handle package make|view when no source installed 11-09-11 package.sh: count admin '*** termination code' errors 11-08-31 mamake.c: add -e, ignore use recursive prereq timestamps 11-08-29 iffe.sh: add ``set stdio try1.h - try2.h ...'' 11-08-29 iffe.sh: trap EXIT => trap 0 for ancient sh 11-08-11 iffe.sh: handle ancient sort that doesn't have -k 11-06-01 make.probe: add more /lib64 logic 11-05-01 package.sh: fix admin ditto to sync LICENSES too 11-03-25 package.sh: initialize { $SED $TR } before first use! 11-03-21 package.sh: fix vpath probes 11-03-17 iffe.sh: fix cleanup to rm $tmp* instead of $tmp*.* 11-02-24 package.sh: change curl usage to "curl -L ..." 11-02-11 package.sh,C+probe,make.probe,mamprobe.sh: add ###.*archaic.*### 11-02-02 Makefile: add :MAPLIB: check for ancient -lw 11-02-02 make.probe: handle -print-multi-directory => 64 => /usr/lib64 /lib64 11-02-02 package.sh: HOSTTYPE=*,*cc*[,-*,...] sets CC [ and CCFLAGS ] 11-02-02 make.probe: handle gcc $ORIGIN link but exec failure -- gee thanks 11-01-25 cc.hp.ia64: bundled cc is a pile of shaving cream 11-01-07 iffe.sh: check debug==3 for is_hdr() failure 10-11-22 ditto.sh: fix timing problem between |& and exec &p 10-11-10 package.sh: fix cc cross compile check to use checkcc absolute path 10-10-10 package.sh: list main env vars at start of make action 10-10-10 ratz.c: tweak windows delays 10-09-10 ratz.c: add _SEAR_ARGS for _SEAR_EXEC 10-09-01 package.sh: fix ratz from source logic 10-08-25 package.mk: consolidate license file search in .package.licenses. 10-08-22 ratz.c: run sear bootstrap command detached 10-08-20 C+probe: version_stamp only if version_flags works 10-08-17 package.sh: unset makerules *DIR variables in env 10-08-15 package.sh: "make" action now lists some env values 10-08-11 mktest.sh: add "DO command ..." 10-07-27 rt.sh: handle "rt X=Y ..." 10-06-29 ratz.c: non-option sear args passed to sear_exec() 10-06-25 iffe.sh: "api" op changed to not do "map-libc" type mappings 10-06-25 package.sh: "force admin ditto" => no ditto --update option 10-06-22 C+probe: handle cc that require .[ci] input for version info 10-06-21 ditto.sh: change default remote access to ssh (about time) 10-06-12 regress.sh: DIAGNOSTICS [ 1 | 0 | pattern ] and fix EXIT for all 10-06-09 package.sh: add AT&T to usable nmake check 10-06-06 iffe.sh,iffe.tst: add { api ver } ops 10-04-22 package.sh: update "html binary|source" NAME/PASSWORD info 10-04-15 iffe.sh: don't forget candidate headers for hdr|sys! 10-04-11 WWW.mk: disable man page metarule -- now done by admin-man(1) 10-02-14 package.sh: $CC verification needs $INSTALLROOT/bin in PATH 10-02-11 package.sh: fix package admin make report error count 10-02-02 package.sh: fix write binary bug that did scp on local fs 10-02-02 package.mk: up to date binary targets must still be in PACKAGE.*.lst 10-01-01 package.sh: fix premature $INSTALLROOT/bin during cross compile check 10-01-01 make.probe: handle ['"] in CC.VERSION.STRING 09-12-04 iffe.sh: add "opt name" to check for name in $PACKAGE_OPTIONS 09-11-30 mktest.sh: change RESET to STATE.RESET to make it global 09-11-14 make.probe: use gcc { -print-multi-directory -print-search-dirs } 09-11-11 package.sh: re-order and combine cc checks 09-10-27 C+probe,make.probe,probe.win32: add CC.SUFFIX.DEBUG 09-10-21 iffe.sh,Makefile: test -e is not in ksh88! 09-10-06 iffe.sh: handle cc -E #error with 0 exit status (sgi) 09-10-06 package.sh: stub in ar intercept checks -- not used yet 09-10-06 ar.ibm.risc: add ar intercept because some AIX require -Xfoo first!! 09-09-24 regress.sh: fix UMASK logic to create test support files before umask 09-08-28 release.c: change docs to mention stdin if no file operands 09-08-24 package.sh: fix isascii() bug that failed on od(1) trailing space 09-08-20 make.probe: add CC.SHARED.NAME 09-08-20 regress.sh: add { JOB CONTINUE EXITED KILL FIFO } 09-08-11 package.sh: filter lines containing : for package results 09-07-31 make.probe: add CC.AR.ARFLAGS (for AIX ar -xany) 09-07-31 package.sh,cc.*: fix -dumpmachine to handle 32/64/* bit options 09-06-24 package.sh: fix admin.db output formatting 09-05-05 package.sh: export dll hackery environment vars 09-05-05 package.sh: handle non-identifier hostnames 09-05-05 mamake.c: pass undefined ${...} identifiers to the shell 09-05-05 mamake.rt: add macro expansion regression tests 09-05-01 iffe.sh: fix output initialization *again* 09-04-28 package.sh: handle admin.db contact field $9 09-04-15 iffe.sh: add implicit "ini" op to initialize io for subsequent ops 09-03-31 regress.sh: EXPORT before test => global ENVIRON[] 09-03-26 package.sh: test fail pattern is 'fail[es]' 09-03-26 UNIT - ... appends (options) to command line 09-03-19 TEST.mk: x.tst => x only if x is command target 09-03-15 regress.sh: add ${MAIN} for base name of main unit 09-03-10 TEST.mk: add .SOURCE:tests if tests is a dir 09-03-03 regress.sh: allow command line unit to override UNIT 09-03-03 mktest.sh: handle IO == $'\n' 09-02-02 package.sh: delay $INSTALLROOT/bin/.paths generation until mamprobe runs 09-01-30 cc.mvs.390: c89 balks at [ ()] in -Dname="..."! 09-01-27 package.sh: add isascii() to use ratz instead of tar 09-01-20 hurl.sh: add --size=bytes option 09-01-08 TEST.mk: add test.* prereqs, multiple arg lists with :T=*: binding 09-01-03 regress.sh: fix UNIT to allow command line override 09-01-03 mktest.sh: handle TWD 08-12-24 package.sh: fix cross-compile HOSTTYPE logic 08-12-15 package.sh,hurl.sh: handle http codes { 301 302 303 } 08-10-16 make.probe '-fno-stack-protector -fno-stack-protector-all' to cop out!! 08-09-30 rt.sh: fix ksh93 regression test signal count 08-09-26 regress.sh: ignore SIGPIPE for SET pipe-input 08-09-24 package.sh: package only test foo => make --recurse=only recurse tests foo 08-09-20 make.probe: handle another /usr/bin/file shared lib description 08-09-20 regress.sh: add --pipefail for SET pipe-input ... 08-09-17 Makefile: add gdbm1.c for 08-09-10 make.probe: add CC.NOPROTECT 08-08-08 mktest.sh: add --width=width 08-08-05 dbm.req: favor sleepycat ndbm compatibility 08-08-04 C+probe: fix stdlib initialization logic 08-06-24 package.sh: fix $INSTALLROOT/bin/cc intercept time stamp file typo 08-06-20 TEST.mk: make the localyunit before *.rt => *.tst -- doh 08-06-20 mktest.sh: prepend $PWD onto PATH for local units -- doh^2 08-06-11 regress.sh: fix bug that skipped the last test 08-05-20 regress.sh: add --local to put *.tmp dir in local fs 08-05-05 regress.sh: add IF command ... ELIF command ... ELSE ... FI 08-05-01 package.sh: package test => ulimit -c 0 08-04-28 regress.sh: fix EXPORT quoting 08-04-28 regress.sh: fix UNIT set check args too 08-04-24 rt.sh: exit code > 256 => signal termination 08-04-10 C+probe: change probe_so order to check .so last (Mac OS X ld workaround) 08-04-01 package.sh: handle multiple admin HOSTTYPEs per HOST 08-03-28 C+probe: add C++ #include (no extension) dir probes 08-03-17 regress.sh: fix trap on EXIT, add terminated note to final tally 08-02-28 make.probe: fix probe_warn to include ld! 08-02-02 make.probe: add CC.RUNPATH to match default -L order 08-01-31 package.sh: check lib64 for LD_LIBRARY_PATH 08-01-31 iffe.sh: tweak ancient /bin/sh workarounds 08-01-28 make.probe: Darwin ld export dynamic is -force_flat_namespace 08-01-28 C+probe: handle SGI cc error message but exit 0 botch(es) 08-01-23 package.sh: fix checksum doc typo 08-01-09 C+probe: add __FUNCTION__ to the undef (don't check) list 07-12-14 iffe.sh: add set nooptimize 07-12-03 package.sh: add LC_ALL=C 07-11-27 package.sh: fix overaggressive *.md5 cleanup 07-11-20 iffe.sh: treat exit status >= 250 as normal error with no signal 07-11-05 package.sh: fix write op error count pattern 07-11-05 package.mk: fix $(~req) .ver binding 07-08-11 probe.win32: add cl.exe setuid workaround, CC.VERSION[.STRING] 07-08-01 package.sh: handle 'package read lcl|tgz' 07-05-08 regress.sh: execute basename instead of absolute path for short $0 07-04-27 cc.sgi.mips[34]: for #error to exit non-zero -- a no brainer 07-04-20 mktest.sh: defer to systems without 'grep -q' -- sigh 07-04-11 mamprobe.sh: handle $(CC.*) => ${mam_cc_*}, $(...) => ${...} 07-04-11 make.probe: fix CC.PICBIG probe, default { CC.PIC CC.DLL } to BIG 07-04-04 iffe.sh: prepend ${tst}${ext} to each .c probe 07-03-28 package.sh: fix binary tgz architecture type duplication 07-03-28 package.mk: add binary write PACKAGE.$HOSTTYPE.lst 07-03-28 iffe.sh: add -F header to mac test 07-03-23 make.probe: handle file(1) that returns 'archive' for .so 07-03-22 mamprobe.sh: fix STDED probe for implementations that ignore EOF 07-03-11 package.sh: add nocopyright and tst => nocopyright 07-03-11 package.mk: add copyright=0 07-03-08 C+probe: restore IFS after probe.ini 07-02-26 mamake.c: expand first of ${mam_lib*} for ${AR} 07-01-05 package.sh: fix "admin write binary" logic 07-01-01 iffe.sh: add "cmd" --verbose trace 07-01-01 iffe.sh: sort => LC_ALL=C sort 07-01-01 C+probe: LC_ALL=C 06-12-22 make.probe: lean on gcc -v for stdlib, but preserve /usr/local! 06-11-23 package.sh: *.md5 are not tarballs -- doh 06-11-23 iffe.sh: add -F, --features=feature-test-header 06-11-11 make.probe: favor lib64 over lib for hosttype==*64 06-10-31 make.probe: add "-ignore-source-dir -iquote" test 06-10-31 iffe.sh: add status{...} code block 06-10-11 regress.sh: fix DO to handle {...} (time for regress.tst?) 06-10-11 package.sh: handle already gunzip'd *.tgz 06-10-06 iffe.sh: add reference for header content tests 06-09-27 regress.sh: fix UMASK to do DO too (duh) 06-09-22 iffe.sh: drop -O for npt tests (for msvc intrinsics) 06-09-14 cc.darwin: drop -O until gcc 4.* gets its act together 06-09-11 package.sh: { cc ld ldd } intercepts check ${HOSTTYPE%.*} too 06-09-08 regress.sh: add PIPE INPUT|OUTPUT for pipe io 06-09-05 C+probe: add { probe_version version_stamp version_string } 06-09-05 make.probe: add version stamp comment, CC.VERSION[.STRING] 06-08-27 regress.sh,mktest.sh: add UMASK 06-08-25 regress.sh: add -b,--ignore-space,IGNORESPACE 06-08-25 mktest.sh: add IGNORESPACE 06-08-24 mktest.sh: handle \000 in data 06-08-24 regress.sh: handle -f* for INPUT|OUTPUT|ERROR 06-08-16 package.sh: fix 'install flat' logic 06-08-11 rt.sh: handle style=shell %K date format 06-07-17 ratz.c: fix __MVS__ FAR definition 06-07-17 iffe.sh: "header x.h" -- deprecate "include x.h" for .SCAN.iffe 06-07-17 package.sh: differentiate urls vs. assignments 06-06-27 rt.sh: add --failed, --heading 06-06-27 C+probe,TEST.mk,make.probe,mktest.sh,regress.sh: 'ulimit -c 0' 06-06-26 cc.darwin.ppc: handle -lcc_dynamic disappearance 06-06-25 mktest.sh: implement PROG 06-06-11 Makefile: add -ldbm :MAPLIB:, provide public MAPLIB.mk 06-05-06 package.sh: add PACKAGE_admin_tail_timeout 06-05-22 ratz.c: upgrade to zlib-1.2.3 06-05-09 package.sh: fix admin.db docs 06-03-11 package.sh: fix `package use - command ...' 06-03-05 make.probe: work around pedantic bash 3.1 mismatched " in `.` 06-02-14 package.sh: "results failed test" == "results test failed" cc.sgi.*: add _AST_cc_OPTIONS parameterization, -OPT:Olimit=0 cc.linux.ia64-icc: add for Intel cc 06-02-02 package.sh: FreeBSD stuck with OS version for all arch 06-02-01 package.mk: fix locale logic (tw -d requires dir arg) 06-01-31 package.sh: require $CC only for make|test 06-01-30 package.sh,hurl.sh: use the backwards-compatible --http-passwd package.sh: add more pdksh => /bin/sh checks 06-01-26 package.sh: wget --http-pass => --http-password package.sh: fix wget error logic hurl.sh: wget --http-pass => --http-password 06-01-11 package.mk: pass package.license.class to make --mam too package.mk: variants=pattern => --variants=pattern package.sh: Darwin rel<=7 => darwin7.ppc package.sh: FreeBSD rel<=4 => freebsd4 package.sh: FreeBSD rel<=5 => freebsd5 05-12-07 iffe.sh: don't emit if | (XXX) 05-12-05 make.probe: disable readonly.exe core dump via ulimit -c 0 05-09-22 mktest.sh: add EXEC [ ++NOOUTPUT ++NOERROR ++NOEXIT ] 05-09-21 mktest.sh: fix --style=shell compare to ignore \r 05-09-12 TEST.mk: all --force to force %.rt regeneration 05-09-05 TEST.mk: regenerate from %.rt only if newer, :SAVE: %.tst 05-08-25 mktest.sh: add TEST.mk: add %.rt=>%.tst for mktest 05-08-18 package.sh: 'package host cpu' now checks $NPROC first 05-07-17 iffe.sh: add { define extern include print } ops iffe.sh: accept output{...}end output on success only -- doh 05-07-01 package.sh: add TARPROBE for tar B flag probe 05-06-24 package.sh: fix binary read chmod via *.sum 05-06-06 package.sh: fix KEEP_HOSTTYPE logic to handle synthesized types 05-06-01 make.probe: verify that cc_pic works for hosted cc cc.lynxos.ppc: make -mshared the default package.sh: note $INSTALLROOT/bin/@(cc|ld|ldd) installation 05-05-25 make.probe: add CC.INCLUDE.LOCAL instead of -I- in CC.DIALECT 05-05-24 iffe.sh: really fix grouping logic -- with tests this time package.sh: pipe/socket configuration mismatches => use /bin/sh 05-04-28 TEST.mk: add $(TESTS) 05-04-19 package.sh: package results test uses rt if possible iffe.sh: fix 'op var - ... - ...' grouping logic 05-04-15 rt.sh: handle autom4ate style 05-04-11 regress.sh: fix unit name when command line unit also specified rt.sh: handle all AST package test output formats package.sh: fix make docs for options passed to underlying make 05-04-08 package.sh: cp -p makerules.mo to $OK to preserve mtime regress.sh: add "TITLE name" to change TEST output title 05-04-01 rt.sh: add pretty make test + regress.sh wrapper 05-03-29 package.sh: test -e path => test -f path -o -d path 05-03-24 make.probe: fix CC.PICBIG probe to prefer -fPIC over -fpic -- doh 05-03-19 mamake.c: command line name=var also defines name.FORCE=var 05-03-11 regress.sh: unset LC_ALL when LC_* EXPORT'd package.sh: old make.out saved in circular make.out.[1-9] mamake.c: sync with nmake :W=O: 05-03-01 package.sh: fix flat hierarchy initialization package.sh: admin action now properly resets sibling remote logs package.mk: relax unknown/unwritten package messages to warnings package.sh: handle space in command line name=value make.probe: add MVS -Wc,dll,exportall,longname,rent to CC.DLL probe 05-02-24 package.sh: hosttype *.powerpc => *.ppc cc.lynxos.ppc,ldd.lynxos.ppc: add 05-02-22 mamake.c: fix { -G --debug-symbols -S --strip-symbols } MAMAKEFLAGS bug 05-02-20 probe.win32: handle /platformsdk mount 05-02-19 package.sh,package.mk: add write tst for tgz in tst subdir 05-02-18 package.sh: accept cc -dumpmachine with 0 or 1 - 05-02-14 package.sh: handle multiple architectures per host in admin.db Makefile,package.sh: honor $INSTALLROOT/bin/.paths overrides package.sh: normalize trailing [-_]bits in host type iffe.sh: some ksh-compatible shells don't do *(pattern) 05-02-11 iffe.sh: back out 05-01-11 child process stdin hijack cc.lynxos.i386: -dynamic instead of -static default 05-02-10 package.sh: cyg usr/doc => usr/share/doc 05-02-08 package.sh: drop -m with pax -- delta bug fixed 2005-02-08 iffe.sh: work around old bash 0<... redirection bug 05-02-06 package.mk: source.tgz: update generated files only when they change 05-02-02 *.sh,*probe: IFS may be unset and { ash bsh } don't on startup -- wow 05-01-11 package.sh: update setup docs to include authorize+password package.mk: fix .source.cyg final directory edit package.mk: notice=1 for conspicuous empty NOTICE file WWW.mk: fix *-index.html installation filter.sh: retain input file suffix in tmp copy mamexec.c: fix non-contiguous "exec" bug that skipped lines iffe.sh: fix candidate lib test to try grouping subsequent libs iffe.sh: fix child process stdin hijack that skipped input lines iffe.sh: --shell=osh to force read -r compatibility command iffe.sh: chop iffe input leading space before # for KnR compatibility 05-01-05 package.sh: add ${TAR} ${TARFLAGS} and tar B flag for pipes mamake.c: fix makefile scan to ignore lib*.[hH] iffe.sh: immunize function/symbol tests from aggressive -O 04-12-28 WWW.mk: add :WWWPAGE: faq.*.mm index generator 04-12-21 ratz.c: make sure tmp dir is writable -- doh 04-12-08 iffe.sh: fix dat test for aggressive -O 04-12-01 iffe.sh: add `include file' to pull in #define's for `exp' 04-11-11 package.sh: default MAKESKIP is "*[-.]*" 04-10-22 ratz.c: change docs to note zlib license mamake.c: handle --debug-symbols and --strip-symbols package.sh: make (debug|strip)=1 => --(debug|strip)-symbols package.mk: add :LICENSE: => package.license.class mamake.c: fix recursive order logic 04-10-18 package.mk: add :LICENSE:, :OMIT: to omit package subdirs 04-10-11 package.sh: add 'authorize name' and 'password password' 04-10-01 iffe.sh: double check $static link with ! $static Makefile: add BUILTIN_LIB to $INSTALLROOT/bin/.paths make.probe: add CC.DIALECT EXPORT={ALL,REF,EXT,DLL} package.sh: add BUILTIN_LIB to $INSTALLROOT/bin/.paths 04-09-21 package.mk: $(init)$(name) is now an implicit prereq 04-09-09 package.sh: copy makerules.mo to $INSTALLROOT/bin/ok 04-09-01 package.mk,package.sh: rename *.txt => *.README package.mk: add the runtime package type (no *.[ah]) iffe.sh: fix key test reports 04-08-26 Makefile: { add m2.c m3.c } -lm tests for { frexp[l] ldexp[l] } 04-08-11 package.mk: handle HOSTTYPE for Solaris > 9 package.sh: add `checkaout proto' for { make view } package.sh: check for { md5sum md5 } iffe.sh: add {if|elif|else|endif} test ... iffe.sh: add 'exp - expression' and '( expression )' iffe.sh: add 'name = test ...' user defined macros iffe.sh: add '! test ...' negation TEST.mk: add implied { .c .sh } generated prereq cc.darwin.ppc: handle 10.3 -dylib mess 04-08-01 package.mk: let include handle nested requirements -- duh 04-07-31 package.sh: attempt a second ping before admin assumes host down 04-07-26 package.sh: fix hp.ia64 HOSTTYPE 04-07-23 probe.win32: generalize #include dir order search 04-07-17 regress.sh: add INPUT -x for chmod +x 04-07-01 regress.sh: TMP => TWD 04-06-29 regress.sh: put COMMAND in $TWD too 04-06-21 regress.sh: mkdir -p INPUT and OUTPUT intermediate dirs TEST.mk: add :TEST: -- to disable .c .sh search 04-06-18 TEST.mk: add .SCAN.tst 04-06-17 regress.sh: TEST returns true if active, false otherwise regress.sh: add CD to change test pwd from $TWD 04-06-16 regress.sh: add TWD for ./unit.tmp override regress.sh: DO now flushes previous test regress.sh: INPUT and OUTPUT handle -f for printf instead of print 04-06-11 package.sh: make sure $INSTALLROOT/bin is in front of $PATH package.sh: skip nmake if older than 2000-10-31 04-05-20 package.sh: fix arg vs. package parse with - or '' to disambiguate 04-05-11 package.sh: package verbose update lists closure for package setup package.sh: add src/lib/libardir to nmake proto bootstrap regress.sh: probe for rm -u vs. chmod -R u+rwx 04-05-01 package.sh: $CC must be C, not C++; allow release command on $PATH 04-04-15 make.probe: check probe_libdir false positives package.sh: add lib/package/*.lic src package subdirs package.mk: add mamfile=0 to inhibit Mamfile generation iffe.sh: config name_DECLARED => HAVE_name_DECL iffe.sh: fix mac to handle default value 04-04-11 iffe.sh: normalize sed [\\\\/] quoting 04-04-04 package.mk: only checksum generated tarballs mamprobe.sh: add STDCHMOD 04-04-01 C+probe: set export LANG=C for uniform error messages make.probe: another CC.STDLIB tweak package.sh: fix regress core dump pattern, expand [a-z] match ranges 04-03-31 Makefile: add intl :MAPLIB: test make.probe: fix CC.STDLIB search; drop CC.* path duplicates 04-03-28 iffe.sh: drop unused exec $stdin<&0 dup 04-03-25 Makefile: add iconv :MAPLIB: package.sh: use ${PING:-ping -c 1 -w 4}, allowing admin.db override 04-03-24 package.mk: add *.md5 checksum for each *.(c|exe|tgz) package.sh: update base change on md5 sum instead of size iffe.sh: adjust case label \ and keyword quoting for ancient /bin/sh 04-03-22 probe.win32: ncc => nld 04-03-19 CONVERT.mk: change the instructions and old source dir default package.mk: fix recurse=list check package.mk: add *.md5 checksum for each *.(c|exe|tgz) package.sh: fix update base/delta/sync existence check 04-03-18 iffe.sh: -d2 does not remove core dumps on exit 04-03-17 package.sh: fix make recurse arg/action order 04-02-29 package.sh: add regress action to compare current and previous tests package.sh: fix sgi.mips[23] HOSTTYPE test for old IRIX cc package.sh: add `export variable ...' package.sh: admin action now handles host name with non-id chars package.sh: non-numeric M T W in admin.db disables that action package.sh: fix admin write binary local vs. shared clash cc.hp.pa: add _AST_CC_hp_pa_DEFAULT=+DAportable cc.hp.pa64: sync with cc.hp.pa cc.ibm.risc: -bnolibpath => -blibpath:/usr/lib:/lib probe.win32: sync with make.probe make.probe: fix last chance dynamic test make.probe: add hp.pa CC.EXPORT.DYNAMIC -Wl,-E make.probe: add ibm.risc CC.EXPORT.DYNAMIC -bexpall make.probe: move probe_dll_def to the end of probe_dll package.mk: capture subcomponent mamfile recursion 04-02-24 make.probe: strip "..." from cc/ld traces iffe.sh: add ``set [no]define'' to disable macro #define/#undef 04-02-23 make.probe: rework CC.LD search 04-02-14 make.probe: add CC.EXPORT.DYNAMIC for main dynamic sym export make.probe: resurrect CC.PIC with separate semantics from CC.DLL make.probe: add CC.SHARED.LD for CC.SHARED linker C+probe: clear DISPLAY to stifle interactive windows 04-02-11 iffe.sh: handle ``siz void*'', add cross{ ... }end make.probe: add { CC.AR CC.SIZE }, fix cross command search cc.darwin.ppc: change $cc => $CC for old ksh + libast conf bug 04-02-09 make.probe: drop -nostartfiles from CC.SHARED for C++ 04-02-04 package.sh: fix cross compilation bug that mixed binary formats 04-02-02 package.sh: package admin now ditto's bin/package too 04-01-30 cc.sgi.mips3: drop warning 3421 04-01-11 regress.sh: output label#count for tests in loops 04-01-05 regress.sh: fix bug that ignored the first SAME 04-01-04 crossexec.sh: fix typo that did not recognize rcp 03-12-19 mamake.c: add `foolib:foo:libfoo' to recurse() 03-10-11 regress.sh: add EXPORT, export COLUMNS=80 for message consistency 03-09-23 ratz.c: fix tar header number parse bug that skipped to next number regress.sh: rm cleanup now handles files matching -* 03-09-11 iffe.sh: add unnamed { ... } blocks regress.sh: add COPY from to, like MOVE but comparison still done regress.sh: rm -rfu to handle test dirs w/o u+rwx 03-08-14 Makefile: add hello.c to the manifest 03-08-11 package.sh: fix `html binary' generation 03-06-21 package.sh: fix INITROOT initialization bug package.sh: make sure admin logs exists before tail'ing 03-06-11 probe.win32: fix $(BINDIR) typo that expanded in sh instead of make cc.mvs.390: return code 4 yields exit code 3 but it's *really* ok package.sh: fix onpath function global var conflict make.probe: add CC.DIALECT { GNU -dD } package.mk: add Mamfile to lcl manifest 03-06-10 package.sh: fix setup action typo that only checked the INIT package package.sh: *.s390x => *.s390-64 03-06-09 package.mk: add cyg :POSTINSTALL: 03-06-08 make.probe: fix CC.STDLIB logic hurl.sh: add User-Agent identification package.sh: tweak source and binary installation instructions cc.hp.pa,ld.hp.pa: +-Wl,+cdp,${INSTALLROOT}/lib/: drops abs lib paths ldd.hp.pa: add 03-06-06 package.sh: fix $INSTALLROOT/bin/ldd check make.probe: add CC.STDLIB verification 03-06-04 make.probe: add +forceread +noforceread 03-05-11 hurl.sh: handle http://host:port/path 03-05-06 package.sh: fix setup action PACKAGEROOT and INIT logic 03-05-05 package.mk: fix Cygwin tarball names 03-04-30 package.sh: move (cc|ld|ldd).$HOSTTYPE updates from Makefile 03-04-27 make.probe: fix MVS CC.PREFIX.SHARED "lib" => "" make.probe: add CC.DLL.DIR = $(BINDIR) or $(LIBDIR) make.probe: add { CC.LD.LAZY CC.LD.NOLAZY CC.LD.RECORD CC.LD.NORECORD } probe.win32: sync with latest CC.* 03-04-25 mamprobe.sh: add args to `. $makeprobe' for ancient sh 03-04-23 package.mk: fix dup "covered by" licenses 03-04-22 probe.win32: CC.DIALECT += "LIBPP -I-" for all cc's package.sh: fix admin write binary tarball snarf 03-04-21 package.mk: package covered *.@(pkg|lic) too 03-04-15 package.mk: don't generate incremental archives for lcl package.mk: add incremental=[source:1 binary:0] archive control package.sh: generate $INSTALLROOT/bin/cc wrapper for CC != cc package.sh: admin must ditto lib/package/*.@(pkg|lic) too mamake.c: ignore time of ignore prereqs mamake.c: -D2 lists propagated times 03-04-11 package.mk: tidy up cyg tarballs package.sh: fix old shell clash between get() and $get 03-04-05 package.mk: restore *.inx generation somehow lost during cyg additions package.sh: add pthread_num_processors_np() last resort for CPU count package.sh: use `make believe' to accept mamake generated files package.sh: handle `make [make-flags] [target ...]' mamake.c: ignore -e 03-03-21 package.mk: fix cyg old make typo package.sh: switch to `package setup' instructions 03-03-19 package.sh: add registry checks for `host cpu' package.sh: `results failed' now lists core dump messages 03-03-17 package.sh: on Cygwin verify 'ntsec binmode' in $CYGWIN or die Makefile: install gcc wrapper if no cc package.mk: add :DETAILS: { :README: :EXPORT: :INSTALL: :TEST: } ops 03-03-12 package.mk: add :DETAILS: for style-specific details 03-03-11 package.sh: add beta setup/update support TEST.mk: add (TESTCC) prereq for .sh tests 03-03-07 hurl.sh: add 03-03-06 iffe.sh: fix lib Win32 test Cygwin vs native incompatibility iffe.sh: change internal stdio.h guard to handle C++ inline vs. macro 03-03-03 package.sh: check for curl or wget for update package.sh: add setup action == update read make package.sh: fix packageroot() typo that showed up in non ~user shells mamake.c: treat name+=value args like name=value mamake.c: add ${var?*|value?match?no-match?} mamake.c: fix archive vs. dynamic bind logic 03-02-28 package.sh: add the "cyg" (Cygwin) package type package.mk: add "cyg" stubs, :CATEGORY: for category name(s) 03-02-25 mamake.c: add -D4 system(3) debug trace 03-02-24 package.mk: change --mismatch to --corrupt=accept 03-02-14 ratz.c: add _WIN32 setmode([01],O_BINARY) and fopen "rb"/"wb" 03-02-12 Makefile: handle getconf LIBPATH with host pattern 03-01-31 package.mk: fix .lic search 03-01-30 package.sh: handle { INIT ksh nmake } already installed elsewhere package.sh: admin handles command outside of $PACKAGEROOT/bin Makefile: install $(INSTALLROOT)/lib/make/package.mk 03-01-28 package.sh: admin remote commands on one line to please syslog 03-01-23 probe.win32: borland and mingw32 tweaks 03-01-22 package.sh: fix $CC test to ignore set -x trace -- duh 03-01-16 ditto.sh: tw --chop on by default 03-01-14 package.sh: use /bin/cp to copy previous binaries to bin/ok/ package.sh: admin now initiates remote exec and copy from local host 03-01-12 package.sh: handle admin "xxx:" default root 03-01-03 probe.win32: add /usr/include/borland path truncation workaround 02-12-10 iffe.sh: add <&$nullin >&$nullout to checkread() $cc 02-12-06 probe.win32: fix inlcude => include typo, add lcc lib probe.win32: CC.MAKE.OPTIONS = nativepp=0 02-12-04 mamake.c: fix ${foo-bar} to expand foo if defined 02-11-28 probe.win32: add C++ and -I- CC.DIALECT checks 02-11-26 package.sh: package release now checks for second level files 02-11-22 package.sh: update action now uses HTTP/1.0 02-11-21 probe.win32: update the vc include dir test 02-11-20 make.probe: fix CC.LD.ORIGIN typo that expanded make var 02-11-13 packahe.mk: fix list.install => list.installed typo 02-11-12 make.probe: add CC.LD.ORIGIN for a.out origin dir relative dll search make.probe: add CC.LD.STRIP for link time a.out strip package.sh: fix package_use vs. PACKAGE_USE check 02-10-24 WWW.mk: fix bug that required a :WWWBIN: assertion to post 02-10-23 mamake.c: fix uninitialized time in make() ratz.c: fix meter buffer overflow 02-10-20 package.sh: fix lib/probe/C/make/probe update test 02-10-18 probe.win32: update for mingw make.probe: add bash workaround to SHELLMAGIC test package.sh: work around yet another Cygwin hassle 02-10-17 iffe.sh: short circuit ID check for *[-+/\\]* 02-10-08 regress.sh: unset FIGNORE to avoid rm . errors package.sh: unset FIGNORE to avoid rm . errors package.sh: $CC must at least compile and executable hello world 02-10-04 package.sh: $INSTALLROOT/lib/package/tgz=>$PACKAGEROOT/lib/package/tgz package.mk: $(ED) => $(STDED), $(EDFLAGS) => $(STDEDFLAGS) iffe.sh: add identifier checks for tests that (implicitly) require them iffe.sh: disambiguate a few --config macros 02-10-02 iffe.sh: fix shell=bsh `hdr a/b' 02-09-30 package.sh: handle chmod of -* files package.sh: verify that $SHELL is Bourne compatible package.sh: tighten PACKAGE_USE logic PATH,LIBPATH,etc. validation iffe.sh: fix bug that didn't define mac variable on success 02-09-22 package.sh: handle admin_action=ditto iffe.sh: --config sizeof(foo) macro is SIZEOF_foo iffe.sh: fix long.long test so it doesn't defeat UWIN "typ long.long" mamprobe.sh: convert $("foo") nmake string constants 02-09-21 mamprobe.sh: "-" info-path writes probe info to stdout 02-09-11 make.probe: move from nmake src to be part of mamprobe.sh mamprobe: generate from mamprobe.beg C.probe make.probe mamprobe.end mamake.c: pass cc absolute path to mamprobe package.sh: generate mamprobe -- yuk (at least it's confined to INIT) iffe.sh: lcl,nxt: drop default sys/ check ditto.sh: tw --logical by default; add --physical 02-09-10 package.sh: SHELLMAGIC creeps into package too -- duh and fooey 02-09-09 ditto.sh: test that remote .profile exists before sourcing 02-09-06 package.sh: don't ditto nfs junk ditto.sh: --show now lists directory ops instead of enumerating all 02-09-05 ditto.sh: add --remote={rsh|ssh} package.sh: add admin [[{rsh|ssh|-}]:]directory 02-09-02 iffe.sh: change 'print -r --' to 'print -r -' for ksh86 compatibility 02-09-01 cc.unix.mc68k: add for ancient 3b1 02-08-22 package.sh: fix component() to test for components -- duh Makefile: add LICENSE:.DONTCARE to workaround mam 02-08-11 iffe.sh: provide defaults for LD_* additions 02-08-07 ratz.c: change -m to use * instead of non-portable inverse video 02-07-17 mamprobe.sh: close tmp file in trap before rm for Cygwin package.sh: fix "type" to handle i1586 (P4) package.sh: add the view action 02-06-28 package.sh: handle multiple packages for release action 02-06-27 package.sh: catch sol*.sparc=>sol*.sun4 when CC=gcc 02-06-14 package.sh: fix admin_action to not include qualifiers package.sh: fix help/html doc typo 02-06-11 package.sh: fix ditto update doc to `PACKAGEROOT field matching *:*' 02-06-07 WWW.mk: change substitute $("\n") to \n 02-06-06 package.sh: clarify output streams for help/html 02-05-22 mamake.c: fix executable file check to use (S_IXUSR|S_IXGRP|S_IXOTH) 02-04-04 package.sh: fix update to differentiate *.sun4 and sun4 02-03-27 package.sh: yacc/bison warning only if both missing 02-03-24 mamake.c: all shell actions wrapped with -c to avoid #! problems 02-03-23 package.sh: recover $PACKAGEROOT/bin/package if not in INIT package package.sh: precheck $CC, not `cc' package.sh: fix install to use pax -ps to preserve setuid/setgid package.sh: fix install to use list.installed for existing files only 02-03-17 package.sh: fix PAX initialization that was sometimes omitted for read package.sh: fix update delta sync fetch 02-02-14 iffe.sh: fix macro{ }end docs to include " iffe.sh: add dfn to extract #define from headers iffe.sh: handle nxt #include ok but no line sync iffe.sh: drop local header clash logic iffe.sh: add -X, --exclude=dir to exclude -I dirs iffe.sh: lcl,nxt now generate <...> headers instead of "..." package.sh: admin.db root dir matching -* disables host package.mk: fix package.src.pat typo -- too many ) package.mk: add { :COVERS: :DESCRIPTION: :REQUIRES: } package.sh: handle { :COVERS: :DESCRIPTION: :REQUIRES: } Makefile: move proto.c generation to the proto component dir 02-02-02 execrate.sh: add for .exe challenged Win32 systems/commands mamprobe.sh: add STD* commands/flags mamake.c: update mamprobe info when older than mamprobe executable package.sh: move ed/ex workaround to mamprobe.sh package.sh: fix `host type' bug that incorrectly assumed sun4 for sol package.sh: add execrate(1) hooks for challenged systems package.sh: add check for { cc ar nm yacc/bison } before make ratz.c: fix "rb" vs. "r" macro tests iffe.sh: add nxt, similar to lcl but defines _nxt_foo for #include iffe.sh,package.sh: remove variable from sccs,cvs ident strings -- duh 02-01-24 C+probe: check CC.DYNAMIC to handle cc that accept but ignore -B* iffe.sh: handle 'mem struct.a.b' 02-01-22 iffe.sh: cache (internal) `foo vs. struct foo' test results package.sh: uts.370 => uts.390 02-01-18 package.sh: fix uts hosttype 02-01-17 package.sh: add 'results failed ...' to list failures only package.sh: change ARCH internal var to all_types to avoid env conflict iffe.sh: fix hdr/lib precheck that missed some -- ouch iffe.sh: fix noexecute test that forgot to check compile first! 02-01-15 ratz.c: fix path[] type typo 02-01-01 package.mk: tighten license search 02-01-08 package.sh: `pwd` => ${PWD:-`pwd`} package.mk: expand license file pattern match 02-01-04 iffe.sh: fix `exp name "value"' bug that duped "value" iffe.sh: fix initial check to honor --config 01-12-25 iffe.sh: fix bug where -o file restored old file 01-12-23 package.mk: uniq the closure lists 01-12-07 ratz.c: fix --meter to retain paths containing " -- " 01-11-30 ratz.c: use sear_system() to execute; should work on all windows 01-11-28 ratz.c: fix sear_rm_r() to check SetCurrentDirectory() status 01-11-26 ditto.sh: drop n+=v for ksh compatibility 01-11-21 ditto.sh: add rsync script replacement [hey, it works!] package.sh: add [ditto]:directory notation to admin.db 01-10-31 package.sh: handle *.sum paths with embedded space package.sh: change executable() to onpath() package.sh: executable([!] foo) replaces test [!] -x foo (.exe hack) package.sh: add os2 fix to `host type' mamake.c: add .exe hack iffe.sh: fix intrinsic function lib test mamprobe.sh: update pic probe to match make.probe for linux.ia64 01-10-30 package.sh: make action skeleton view now checks subdirs 01-10-20 package.sh: don't recurse into leaf dirs matching $MAKESKIP package.mk: tarball package.notice replaces `license accepted' prompt package.sh: eliminate `license accepted' prompt package.sh: add update to download latest from a url package.sh: use builtin arithmetic when we know it's ksh iffe.sh: unkown -> unknown 01-10-18 package.sh: convert to YYYY-MM-DD delta releases instead of NNNN package.mk: convert to YYYY-MM-DD delta releases instead of NNNN ratz.c: fix -m for paths containing \f\n\r\v 01-10-16 ratz.c: _SEA_* => SEAR_* ratz.c: preserve stdin for sear_exec() ratz.c: add recursive sear_rm_r() to sear_exec() tmp dir cleanup 01-10-10 mamprobe.sh: add mam_cc_SHELLMAGIC package.sh: add nfs wakeup call to admin to avoid stale file handles 01-10-04 cc.darwin.ppc: -flat_namespace is not longer the default (huh) 01-10-01 package make: prepend $INSTALLROOT/bin/ok to PATH package read: save cpy of bin/package when reading the INIT package mamprobe.sh: allow cc path with optional arguments 01-09-24 Makefile,package.sh: add $INSTALLROOT/bin/.paths initialization 01-09-19 package.mk: add recurse to list.package.* package.sh: bootstrap build nmake with _BLD_STATIC for _WIN32 01-09-11 ratz.c: add _SEA_SKIP & _SEA_COMMAND for self extracting archives 01-09-07 package.mk: fix output capture to not generate files names with spaces 01-09-07 package.mk: fix delta release number search 01-08-11 package.mk: handle single gz executable packages (e.g., for ksh) package.sh: fix package install to require nmake only if no *.sum iffe.sh: drop ancient menu and prompt actions; check ./hdr.h clash 01-07-17 package: fix use cross compile test to generate files in /tmp 01-06-27 ratz: handle hard and soft links if possible 01-06-07 Makefile: fix :MAPLIB: for sco 01-05-31 crossexec.sh: add iffe.sh: add -x crosstype to run crossexec iffe.sh: exp test now handles pass{}end fail{}end yes{}end no{}end package.sh: add package host canon external-host-type-name package.sh: fix `use USER' lookup for shells that support ~USER cc.*: add -dumpmachine to dump target HOSTTYPE 01-05-18 iffe.sh: drop $HOME/tmp/t.sh debug trace -- oops 01-05-01 mamake.c: scan() now handles :PACKAGE: foo:command 01-04-26 *.sh: expand [a-z][A-Z][0-9] for non-contiguous character codes iffe.sh: fix run *.sh for shells that don't $* across . command cc.mvs.390: recode for /bin/sh 01-04-25 package.mk: include non cc-g variants by default package.sh: *[._]* => *?[_.]* for mvs.390 /bin/sh 01-04-24 TEST.mk: no tests for VARIANT=="DLL" 01-04-22 package.mk,package.sh: tarball text members are ASCII encoded 01-04-18 package.mk: allow package name to be the same as one of its components cc.mvs.390: handle .C .cpp .cxx cc.mvs.390: compensate for -o that does not overwrite 01-04-01 regress: fix SAME that just skipped it -- we should regress regress! iffe: fix bug that didn't emit _hdr_foo for internal hdr tests iffe: fix lcl bug for cc -E that doesn't emit line syncs ratz: add ASCII=>EBCDIC conversion for text archive members mamake: fix buffer overlap bug that clobbered the probe file path 01-03-17 iffe: handle : separator as first arg 01-03-15 mamake.c,ratz.c,release.c: add and 01-02-26 iffe.sh: fix bug that omitted runtime #define for `mac' op 01-02-22 cc.ibm.risc: handle SF_CLOSE clash in 01-02-14 cc.sgi.mips3,cc.sgi.mips4: handle -mips2 -mips3 -mips4 for cross cc C+probe: quote "$cc" when it's an argument! mamake: execute actions with $SHELL, ignored signals back to default package.sh: nmake check error output to /dev/null package.sh: fix INIT a.out updates for knr cc package.sh: package list now handles large tgz dirs package.sh: *-ok executables moved to ok/* for *.dll systems iffe.sh: change "exec >&-" to "exec >/dev/null" else Linux mkdir fails! mamake: handle `bind -lx [dontcare]' 01-02-12 ratz.c: fix _PACKAGE_ast includes package.sh: $HOSTTYPE env overrides if $PACKAGEROOT/arch/$HOSTTYPE/ package.sh: $CC ^HOSTTYPE=[A-Za-z_0-9.]*$ overrides HOSTTYPE iffe.sh: fix dat code that used previous $tmp.exe iffe.sh: fix dat code for _DLL imports 01-02-09 iffe.sh: add copy() for shells with the disappearing here doc bug 01-02-08 Makefile: guard against null $(CC.HOSTTYPE) 01-02-06 Makefile: separate out cc,ld,ldd workarounds (so they will be packaged) 01-02-02 package.sh: fix package use for $INSTALLROOT != */$HOSTTYPE package.sh: create intermediate recursion makefiles when needed package.sh: add $SECONDS to the DEBUG trace prompt 01-01-01 ratz.c: #ifdef for UWIN ncc iffe.sh,package.sh: check PACKAGE_PATH for local installations package.sh: add psrinfo for osf.alpha host cpu package.sh: change pax --meter probe; some hang on /dev/tty package.sh: fix `install flat ARCH' mamake: eliminate loops from scan order C+probe: add probe_verbose -V for AIX cc=xlc cc.ibm.risc,ldd.ibm.risc: add package.mk: list refs to top-level licenses only package.mk: add local link table to change log html 00-12-25 package.sh: `no package archives' is a hard error, duh package.sh: reorder host type logic for lame shells mamake.c: getcwd => getwd for NeXT -- how about posix==default guys iffe.sh: really gross workaround for NeXT -lposix stdout null's iffe.sh: handle cc -E that insists on compiling 00-12-15 iffe.sh: ancient sh function call blows $*; call only when $# == 0 *.sh: `getopts 2>/dev/null` => `(getopts)2>/dev/null` for ancient sh package.sh: fix LD_LIBRARY*_PATH initialization cc.next.m68k: add for _POSIX_SOURCE and linker multiply defined syms 00-12-12 ratz: add --meter package.sh: a few VPATH fixes Makefile: don't override *.mips* cc if -version not accepted 00-12-11 package.mk: *.inx now contains name=value 00-12-07 package.sh: handle PC netscape . => _ pathname mangle WWW.mk: .tar.gz => .tgz 00-11-27 package.sh: add checklicense() to do license checks at read time package.mk: change component list from preformat to table 00-10-31 package.mk: *.pkg must assert closure package.mk: add cc- variants to list.package.binary package.sh: omit dups from package list package.sh: invalid arg gives one line Usage package.sh: relax checkaout checks for non-owners package.sh: package use sets NPROC if not already set or [01] proto.c: add $(INSTALLROOT)/include/ast hack 00-10-26 WWW.mk: add .SOURCE rhs to :WWWPAGE: 00-10-25 package: fix install package.mk: add list.install 00-10-22 regress: fix VIEW to skip empty dirs 00-10-19 package.mk: $(PACKAGEROOT)/bin/nmake => $(PACKAGEROOT)/bin/manmake iffe: validate #define identifiers 00-10-18 C+probe: Mac OS X additions package: add DYLD_LIBRARY_PATH initialization add ldd.$(CC.HOSTTYPE) 00-10-01 iffe: handle -I* -L* options 00-09-21 mamake: add libxxx and xxx to makefile ordered prereqs 00-09-19 C+probe: add probe_longlong 00-09-11 package: drop manmake and $PACKAGEROOT/bin/nmake 00-09-08 iffe: verify that $cc is a C compiler 00-06-14 mamprobe: fix win32.* probe mamake: fix bug that used lower view path for generation package: don't clobber $PACKAGEROOT/bin/nmake 00-06-01 C+probe: fix stdinclude *again* package: fix write delta source to use default pax format package: add disambiguating bias for sgi.mips3 over sgi.mips4 package.mk: fix for directory content packages lib ast-locale 00-05-01 iffe: fix invalid _LIB_ macro identifier 00-04-11 C+probe: uniq stdinclude and stdlib, fix usrinclude 00-04-01 regress: fix explicit OUTPUT bug that didn't compare with expected 00-03-17 package: all archives are .tgz for binary download package: $(PACKAGEROOT)/LICENSES/* in source and binary archives package: implement install and verify actions iffe: add exp, pth file dir ..., fix lib - -lfoo, fix lib - - -la -lb iffe: -L* must affect LD_LIBRARY* hacks for .exe tests -- yuk package.mk: add *.pkg :INDEX: 00-03-07 package: add admin action 00-03-06 makefile: install optional make probe override script C+make+probe.lcl 00-02-14 --- release 1.0 --- ratz: treat "foo/" as a dir, not a regular file package: clarify source and binary installation instructions package: fix so binary packages can install without cc package: "ratz" now a non-archive package (the only one) for bootstrap package: handle VPATH=a:b arg package.mk: "ratz" package adjustments Makefile: use :PACKAGE_INIT: to support binary INIT packages WWW.mk: add :WWWALL: C.probe: fix .so check that let .dll slip through iffe: fix config sh var assignment for HAVE_member_IN_struct iffe: fix config sh var assignment for symbol_DECLARED package: delay PATH export until dll hack exports complete package: don't forget binary package $(INSTALLROOT)/lib(32|64) package: add delta change log for source packages 00-02-10 mamprobe: add mam_cc_DLLBIG package: fix spelling typos package: add html help output package.mk: beef up source and binary help => html 00-02-08 package: mkdir man/man[138] in the new arch to cover MAM bug 00-01-28 package,release: add -rcount to release package: fix Linux "host cpu" and "host rating" package: copy *.lic to $PACKAGEBIN for "make" and "write binary" package: fix 'release change log' case match 00-01-24 package: add copyright action mamprobe: add -D_BLD_DLL to mam_cc_DLL 00-01-11 package: tsort for package write package: early verification that $CC works package: add non-interactive command arg for use action proto: fix -C intermediate mkdir() mamprobe: unixware.i386 ksh workaround C.probe: move hosttype to C.probe (with unixware.i386 workaround) WWW.mk: fix mm2html option quoting WWW.mk: add .SCAN.mm WWW.mk: don't force static=1; grab dll's instead *.sh: fix getopts test to handle botched implementations like osf.alpha iffe.sh: fix read -r test 99-12-25 iffe: tweak verbose messages iffe: hand code non-optget getopts parse iffe: fix bash quoting bug again iffe: do test -w . after option parse package: fix PACKAGEROOT search 99-11-19 --- release 0.2 --- 99-11-19 first working package & friends 99-10-31 change from lib0ast to INIT; add MAM and package bootstrap hostinfo: gobbled by package 99-10-01 iffe: add --config, yes{...}end no{...}end, fix read -r workaround 99-09-27 iffe: add --all --verbose, --* set options 99-09-22 regress: -v disables long line truncation 99-09-11 WWW.mk: WWWDIR and MM2HTMLINFO are now lists searched in $(HOME) 99-08-11 hostinfo: fix type sgi.mips4 99-06-24 WWW.mk: add 99-06-08 hostinfo.sh: ${TMPDIR:-/tmp} 99-06-07 TEST.mk: add 99-06-01 iffe: add `siz type' for _siz_type == sizeof(type) 99-05-11 hostinfo,iffe,regress,use: long options 99-05-01 C.probe: fix over aggressive stdinclude, e.g., /usr/include/machine 99-04-01 hostinfo: sgi.mips? -o32 and -n32 checks iffe: check that . is writable 99-03-17 hostinfo: fix for cc not found dl.c,hello.c,m.c: headers in conditionals to force .DONTCARE C.probe: extra check for include dirs pulled in by 99-03-03 regress: add `UNIT - ...' for extra args Makefile: add (_hosttype_) prereq for cc 99-01-23 hostinfo: tweak rating, use /proc/cpuinfo if there 99-01-11 C.probe: shlib before lib, /usr before / 98-12-25 iffe: work around win32.alpha intrinsic clash with -O 98-11-11 regress: fix UNIT PATH lookup 98-11-01 regress: add PROG 98-10-01 hostinfo: add unixware.* use: export PACKAGE_* 98-08-11 C.probe: add /usr/include check (for sco CC) hostinfo: handle UWIN uname update 98-05-01 regress: fix bug sometimes didn't list last test 98-04-01 hostinfo: add cc path arg hostinfo: now works with /bin/sh Makefile: strengthen -lm probe 98-01-23 Makefile: check for -ldl -lm C.probe: handle gcc -v -E phony include dirs iffe: fix lcl by dropping sort -u -- we need the real first iffe: `mem x' to test if x is a non-opaque struct 98-01-11 $(INSTALLROOT)/lib32 for sgi.mips3 $(INSTALLROOT)/lib64 for sgi.mips4 add cc.hp.pa 98-01-01 cc.sgi.mips*: turn off ld library multiply defined 97-10-11 regress: add VIEW function for locating data 97-10-01 Makefile: -ldl test moved to libdll Makefile 97-08-11 regress: add MOVE regress: add SAME regress: use getopts regress: `EXEC' repeats previous test 97-07-17 use: tweak PATH and LIBPATH bootstrap order iffe: fix lcl bug that botched pathnames with embedded spaces 97-06-12 iffe: add npt `needs prototype' test 97-05-09 hostinfo: mvs.* => mvs.390 Makefile: cc.$(_hosttype_) workaround installed here iffe: fix nolink{ ... }end iffe: add [no]static{ ... }end for static link test C.probe: _probe_PATH => _probe_export which must be eval'd 97-04-01 use: _RLD_ROOT set too 97-03-17 mm2html: changed inner loop mm2html: handle .if|.ie|.el, .so mm2html: handle different man styles mm2html: differentiate mm/man in some non-obvious cases hostinfo: r5000 is not mips4 97-02-14 hostinfo: validate type with cc 96-12-25 C.probe: UWIN tweaks iffe: use `...` instead of $(...) for alpha /bin/sh iffe: fix `typ' divide by 0 iffe: `lcl' now drops X: prefix iffe: +l* -> -l* iffe: eval around ${...#%...} for BSD /bin/sh use: add sgi.mips LD_LIBRARY_PATH variants use: add -e to list exports iffe: lcl leaves leading [a-zA-Z]: for DOS iffe: fix no{link|output|execute} logic C.probe: don't automatically add /usr/include for non-hosted compilers C.probe: don't automatically place /usr/include last C.probe: check gcc style -v -E for stdinclude usrinclude 96-11-28 iffe: check BASH_VERSION for IFS botch iffe: typ long.xxx only if sizeof(long xxx) != sizeof(xxx) hostinfo: fix sgi.mips[234] tests hostinfo: fix ncr.i386 tests 96-10-31 iffe: work around old bsh here doc bug by running separate sh 96-10-11 iffe: *.iffe and *.iff for iffe src files hostinfo: tighten sgi.mips CPU type check 96-10-01 C.probe: add probe_libdir to catch alpha /usr/shlib 96-09-17 iffe: fix typ bug that failed for single ID types! 96-08-31 hostinfo: handle recent SGI hinv CPU changes 96-07-17 make sure sizeof(long xxx)>sizeof(xxx) for typ long.xxx 96-05-09 C.probe: drop multiple / in stdinclude 96-02-29 use: package root must have bin and lib subdir mm2html: add C.probe: probe_members += -whole-archive for gcc iffe: add + fix the blasted `...'...\\...'...` 96-01-31 use: add pkg dir hostinfo: add tandem 96-01-01 hostinfo: windows_nt|windows[0-9][0-9] -> win32 95-11-24 hostinfo: linux-aout.* for non-ELF Linux 95-11-11 use: add AIX LIBPATH 95-10-11 hostinfo: no args prints type 95-08-11 use: add 95-05-09 save original PATH in _probe_PATH beef up library dir probe 95-04-01 use c source suffix if it still preserves the dialect add hostinfo add lib/hostinfo/typemap user type map add sol.sun4 CPU count fix C.probe to properly handle C/C++ combined compiler drivers add NeXT to hostinfo bummer: mach has /usr/bin/hostinfo 95-03-19 fix dialect executable test 95-03-19 --- release 0.0 --- ksh-1.0.10/src/cmd/INIT/ar.ibm.risc000077500000000000000000000002131465301102200164760ustar00rootroot00000000000000: ar requires a non-standard option to work : 2009-10-06 : op=$1 shift case $op in -*) ;; *) op=-$op ;; esac /usr/bin/ar -Xany "$op" "$@" ksh-1.0.10/src/cmd/INIT/ar.ibm.risc-64000077500000000000000000000002121465301102200167240ustar00rootroot00000000000000: ar requires a non-standard option to work : 2022-01-14 : op=$1 shift case $op in -*) ;; *) op=-$op ;; esac /usr/bin/ar -X64 "$op" "$@" ksh-1.0.10/src/cmd/INIT/cc.hp.ia64000077500000000000000000000005521465301102200161320ustar00rootroot00000000000000: hp.ia64 cc wrapper for reasonable ANSI C defaults : 2011-01-25 : [ /usr/bin/cc -ef /usr/ccs/bin/cc ] || exit 1 : bundled cc -- really, in the face of gcc you ship a subpar /usr/bin/cc? : HOSTTYPE=hp.ia64 case " $* " in *" -dumpmachine "*) echo $HOSTTYPE; exit ;; esac /usr/bin/cc -D_HPUX_SOURCE -D_INCLUDE__STDC_A1_SOURCE -D_INCLUDE_XOPEN_SOURCE_500 "$@" ksh-1.0.10/src/cmd/INIT/cc.hp.pa000077500000000000000000000005301465301102200157630ustar00rootroot00000000000000: hp.pa cc wrapper for reasonable ANSI C defaults : 2004-02-29 : HOSTTYPE=hp.pa case " $* " in *" -dumpmachine "*) echo $HOSTTYPE; exit ;; esac _AST_CC_hp_pa_DEFAULT=${_AST_CC_hp_pa_DEFAULT-"+DAportable"} /opt/ansic/bin/cc -Ae +e -Wl,+s $_AST_CC_hp_pa_DEFAULT \ ${INSTALLROOT:+-Wl,+cdp,${INSTALLROOT}/lib/:} \ -Wl,+vnocompatwarnings "$@" ksh-1.0.10/src/cmd/INIT/cc.hp.pa64000077500000000000000000000004161465301102200161400ustar00rootroot00000000000000: hp.pa64 cc wrapper for reasonable ANSI C defaults : 2001-02-11 : HOSTTYPE=hp.pa64 case " $* " in *" -dumpmachine "*) echo $HOSTTYPE; exit ;; esac /opt/ansic/bin/cc +D2.0W -Ae +e -Wl,+s \ ${INSTALLROOT:+-Wl,+cdp,${INSTALLROOT}/lib/:} \ -Wl,+vnocompatwarnings "$@" ksh-1.0.10/src/cmd/INIT/cc.ibm.risc000077500000000000000000000017141465301102200164700ustar00rootroot00000000000000: cc wrapper for AIX RISC xlc : 2012-04-17 : hosttype=ibm.risc case $HOSTTYPE in $hosttype-64) case " $* " in *" -q64 "*) ;; *) set -- -q64 "$@" ;; esac ;; *) case " $* " in *" -q64 "*) HOSTTYPE=$hosttype-64 ;; *) HOSTTYPE=$hosttype ;; esac ;; esac case " $* " in *" -dumpmachine "*) echo $HOSTTYPE exit ;; esac bin=/usr/vac/bin cc=$bin/xlc ccflags="-brtl -qhalt=e -qsuppress=1506-224:1506-507" case " $@ " in *" -G "*) ccflags="$ccflags -berok" ;; esac if test -x $bin/c99 then # the xlc optimizer vintage that supports c99 is flawed and causes the AST build to fail # case " $* " in *" -O "*) set '' "$@" '' shift while : do a=$1 shift case $a in '') break ;; -O) ;; *) set '' "$@" $a ;; esac shift done ;; esac $cc $ccflags "$@" code=$? else export PATH=/bin:$PATH LIBPATH=/usr/lib:/lib ccflags="$ccflags -blibpath:$LIBPATH" fi $cc $ccflags "$@" code=$? case $code in 127|255) code=1 ;; esac exit $code ksh-1.0.10/src/cmd/INIT/cc.ibm.risc.gcc000077500000000000000000000007541465301102200172260ustar00rootroot00000000000000: cc wrapper for AIX RISC gcc : 2012-04-17 : hosttype=ibm.risc case $HOSTTYPE in $hosttype-64) case " $* " in *" -maix64 "*) ;; *) set -- -maix64 "$@" ;; esac ;; *) case " $* " in *" -maix64 "*) HOSTTYPE=$hosttype-64 ;; *) HOSTTYPE=$hosttype ;; esac ;; esac case " $* " in *" -dumpmachine "*) echo $HOSTTYPE exit ;; esac cc=gcc ccflags= case " $@ " in *" -shared "*) ccflags="$ccflags -shared -Wl,-G -Wl,-berok" ;; *) ccflags="-Wl,-brtl" ;; esac $cc $ccflags "$@" ksh-1.0.10/src/cmd/INIT/cc.lynxos.i386000077500000000000000000000022531465301102200170050ustar00rootroot00000000000000: lynxos.i386 cc wrapper with -dynamic default : 2005-02-14 : HOSTTYPE=lynxos.i386 case " $* " in *" -dumpmachine "*) echo $HOSTTYPE; exit ;; esac cc=gcc link=1 static=0 set . "$@" /../ while : do shift case $1 in /../) break ;; esac case $1 in *.[cChHiI]|*.[cChHiI][pPxX][pPxX]) set . -D__NO_INCLUDE_WARN__ -I/sys/include/kernel -I/sys/include/family/x86 "$@" shift break ;; -o) case $2 in /../) ;; *) x=$1 shift set . "$@" "$x" shift ;; esac ;; -static)static=1 ;; -l*) case $static in 0) static=n set . -L/lib/shlib "$@" shift ;; esac ;; -[cE]) link=0 ;; esac x=$1 shift set . "$@" "$x" done while : do case $1 in /../) shift break ;; -l*) case $static in 0) static=n set . -L/lib/shlib "$@" shift ;; esac ;; -[cE]) link=0 ;; esac x=$1 shift set . "$@" "$x" shift done case $link:$static in 1:0) static=n ;; esac case $static in n) specs=/tmp/cc$$.specs trap 'status=$?; rm -f $specs; exit $status' 0 1 2 echo '*link: %{shared:-shared} %{static:-static} %{mshared|shared: %{static: %eerror: -shared and -static may not be combined. }}' > $specs $cc -specs=$specs "$@" ;; *) $cc "$@" ;; esac ksh-1.0.10/src/cmd/INIT/cc.lynxos.ppc000077500000000000000000000023301465301102200170720ustar00rootroot00000000000000: lynxos.ppc cc wrapper with -mshared default : 2005-06-01 : HOSTTYPE=lynxos.ppc case " $* " in *" -dumpmachine "*) echo $HOSTTYPE; exit ;; esac cc=gcc link=1 static=0 set . "$@" /../ while : do shift case $1 in /../) break ;; esac case $1 in *.[cChHiI]|*.[cChHiI][pPxX][pPxX]) set . -D__NO_INCLUDE_WARN__ -I/sys/include/kernel -I/sys/include/family/ppc "$@" shift break ;; -o) case $2 in /../) ;; *) x=$1 shift set . "$@" "$x" shift ;; esac ;; -static)static=1 ;; -mshared) static=n continue ;; -l*) case $static in 0) static=n set . -L/lib/shlib "$@" shift ;; esac ;; -[cE]) link=0 ;; esac x=$1 shift set . "$@" "$x" done while : do case $1 in /../) shift break ;; -l*) case $static in 0) static=n set . -L/lib/shlib "$@" shift ;; esac ;; -[cE]) link=0 ;; esac x=$1 shift set . "$@" "$x" shift done case $link:$static in 1:0) static=n ;; esac case $static in n) specs=/tmp/cc$$.specs trap 'status=$?; rm -f $specs; exit $status' 0 1 2 echo '*link: %{shared:-shared} %{static:-static} %{mshared|shared: %{static: %eerror: -shared and -static may not be combined. }}' > $specs $cc -specs=$specs -mshared "$@" ;; *) $cc "$@" ;; esac ksh-1.0.10/src/cmd/INIT/cc.mvs.390000077500000000000000000000115541465301102200161040ustar00rootroot00000000000000: mvs.390 cc wrapper for Unix message and exit code semantics : 2012-01-20 : HOSTTYPE=mvs.390 case " $* " in *" -dumpmachine "*) echo $HOSTTYPE; exit ;; esac ar=ar cc=/bin/c89 CC=/bin/c++ ccflags="-D_ALL_SOURCE -Wc,dll" objmax=60 tmpfiles= unbotch= # -n as *first* arg shows but does not do # -Wc,exportall => -Wl,dll # -Bdynamic => .c,.o dynamic # -Bstatic => .c,.o static # *.C => cc=$CC # *.cpp => cc=$CC # *.cxx => cc=$CC # no optimization until the optimizer is fixed: # -O dropped (no optimization) # -0 dropped (no optimization) # -1 -O (default level 1 optimization) # -2 -2 (maximal level 2 optimization) let argc=0 cmp=0 dll=0 libc=0 dynamic=1 dynamic_objc=0 static_objc=0 relc=0 botched=0 case $1 in -n) exec=print shift ;; *) exec= ;; esac export _CC_ACCEPTABLE_RC=1 export _C89_ACCEPTABLE_RC=$_CC_ACCEPTABLE_RC export _CXX_ACCEPTABLE_RC=$_CC_ACCEPTABLE_RC case " $* " in *.C" "*)let dll=2 cc=$CC export _CXXSUFFIX=C ;; *.cpp" "*)let dll=2 cc=$CC export _CXXSUFFIX=cpp ;; *.cxx" "*)let dll=2 cc=$CC export _CXXSUFFIX=cxx ;; esac exe= xxx= while : do case $# in 0) break ;; esac arg=$1 case $arg in -1) arg=-O ;; -Bdynamic) let dynamic=1 ;; -Bstatic) let dynamic=0 ;; -c) let cmp=1 ;; -D_ALL_SOURCE|-D_ALL_SOURCE=*) arg= ;; -D*[\ \(\)]*) arg=${arg#-D} botch_macro[botched]=${arg%%=*} botch_value[botched]=${arg#*=} let botched=botched+1 arg= ;; -o) argv[argc]=$arg let argc=argc+1 shift arg=$1 exe=$arg rm -f "$exe" ;; -[O0]) arg= ;; -Wc,dll)arg= ;; -Wc,exportall) let dll=1 ;; -Wl,dll)arg= let dll=1 ;; *.c) if [[ $botched != 0 ]] then src=$arg arg=${arg##*/} unbotch="$unbotch ${arg%.c}.o" arg=__$arg tmpfiles="$tmpfiles $arg" { while [[ $botched != 0 ]] do let botched=botched-1 print -r -- "#define ${botch_macro[botched]} ${botch_value[botched]}" done cat $src } > $arg fi ;; *.o) if test 0 != $dynamic then let dynamic_objc=dynamic_objc+1 else let static_objc=static_objc+1 fi ;; *.x) a=${arg%.x}.a if test -f $a then argv[argc]=$a let argc=argc+1 xxx=-Wl,dll case $a in ast.a|*/ast.a) cc="$CC -u_ast_init" ;; esac fi ;; esac case $arg in ?*) argv[argc]=$arg let argc=argc+1 ;; esac shift done tmp=/tmp/cc.${USER:-$LOGNAME}.$$.err tmpfiles="$tmp $tmpfiles" # if any dll .o's are in .a then a .x gets generated # but the native cc doesn't jcl for the .x # -Wl,dll does that, so we nuke the .x and keep the exe test 0 != $dll && xxx= case $xxx in ?*) case $exe in ?*) a=${exe##*/} a=${a%.*} case $exe in */*) tmpfiles="$tmpfiles ${exe%/*}/${a}.x" ;; *) tmpfiles="$tmpfiles ${a}.x" ;; esac ;; esac ;; esac if test 0 != $dll then if test 0 != $cmp then xxx="-D_SHARE_EXT_VARS $xxx" else xxx="-Wl,dll $xxx" fi fi set -- $xxx "${argv[@]}" # can't handle more than objmax .o's # -r into intermediates doesn't work, but the cat trick does # also, the runtime dll file must be executable but cc -Wl,dll forgets if test 0 != $dll -a \( $dynamic_objc -ge $objmax -o 0 != $static_objc \) then unset argv argc=0 libc=0 dynamic=1 dynamic_objc=0 static_objc=0 endc=0 while : do case $# in 0) break ;; esac case $1 in -Bdynamic) let dynamic=1 ;; -Bstatic) let dynamic=0 ;; *.o) if test 0 != $dynamic then dynamic_objv[dynamic_objc]=$1 let dynamic_objc=dynamic_objc+1 else static_objv[static_objc]=$1 let static_objc=static_objc+1 fi ;; -l*) libv[libc]=$1 let libc=libc+1 ;; -o) argv[argc]=$1 let argc=argc+1 shift argv[argc]=$1 let argc=argc+1 exe=$1 ;; *) argv[argc]=$1 let argc=argc+1 ;; esac shift done if test 0 != $static_objc then case $exe in ?*) $exec $ar cr ${exe%.*}.a "${static_objv[@]}" ;; esac fi if test 0 != $dynamic_objc then cat=0.0.o tmpfiles="$tmpfiles $cat" cat "${dynamic_objv[@]}" > $cat || exit else cat= fi set -- "${argv[@]}" $cat "${libv[@]}" fi # grep through the warning/error messages to get the true exit code # some annoying messages are dropped while we're at it trap 'rm -f $tmpfiles' 0 1 2 15 $exec $cc $ccflags "$@" 2> $tmp code=$? for i in $unbotch do test -f __$i && mv __$i $i done typeset -l lc while : do if read line then lc=$line case $lc in *'#include file'*'not found'*) code=1 ;; *'#pragma ignored'*) continue ;; *'definition side file is not defined'*) continue ;; *'step ended with return code 4'*) code=0 continue ;; *'step ended with return code'*) code=1 continue ;; *'try again'*) code=1 continue ;; *'unknown preprocessing directive'*) code=1 case $lc in 'warning '*) set -- $line shift line=$* ;; esac ;; *'unresolved writable static references are detected'*) test 0 != $dll && continue ;; esac else case $code:$exe in 0:?*) $exec chmod +x $exe ;; esac exit $code fi echo "$line" >&2 done < $tmp ksh-1.0.10/src/cmd/INIT/cc.next.i386000077500000000000000000000055621465301102200164350ustar00rootroot00000000000000: next.i386 cc wrapper for Unix message and exit code semantics : 1995-05-09 : HOSTTYPE=next.i386 case " $* " in *" -dumpmachine "*) echo $HOSTTYPE; exit ;; esac # 1995-05-09 -lposix termios.o waitpid.o setpgid.o *do* work # 1994-11-04 -posix has old redirection hole bug # -D_POSIX_SOURCE requires manual fixes # libexpr/exeval.c bombs -O, no -O ok command=cc cc="/bin/cc -D_POSIX_SOURCE" nooptimize="exeval" # first check $INSTALLROOT/botch case $INSTALLROOT in "") echo "$command: INSTALLROOT: must be defined and exported" >&2; exit 1 ;; esac if test ! -d $INSTALLROOT/botch -a -dryrun != "$1" then if mkdir $INSTALLROOT/botch then : ok to initialize else echo "$command: $INSTALLROOT/botch must be initialized by the owner of $INSTALLROOT" 2>&1 exit 1 fi ( cd $INSTALLROOT/botch dir=. for i in lib . include sys do case $i in .) dir=. ;; *) case $i in /*) dir=$i ;; *) dir=$dir/$i ;; esac test -d $dir || mkdir $dir ;; esac done if test ! -f include/sys/dirent.h then echo "#include " > tmp.c header=`$cc -E tmp.c | sed -e '/^#[ ]*1[ ].*\/sys\/dirent\.h"/!d' -e 's/.*"\(.*\)".*/\1/'` sed -e 's/[ ]off_t[ ][ ]*d_off[ ]*;//' $header > include/sys/dirent.h fi if test ! -f lib/libbotch.a then lipo /usr/lib/libposix.a -thin i386 -output tmp.a ar x tmp.a termios.o waitpid.o setpgid.o ar cr lib/libbotch.a *.o ranlib lib/libbotch.a fi rm -f *.[aco] ) fi # now slip in our args case $nooptimize in "") nooptimize=. ;; *) optimize= for arg in $nooptimize do case $optimize in ?*) optimize="$optimize|" ;; esac optimize="$optimize$arg.[ci]|*/$arg.[ci]" done nooptimize=$optimize ;; esac set . "$@" . noexec= library= local= optimize= verbose= while : do shift arg=$1 shift case $arg in .) break ;; -[cES]) library=1 ;; -O) optimize=1 ;; -v) verbose=1 ;; -dryrun)noexec=1 verbose=1 ;; -I-) case $local in "") local=1 set . "$@" -I$INSTALLROOT/botch/include -I- -I$INSTALLROOT/botch/include ;; *) set . "$@" -I- -I$INSTALLROOT/botch/include ;; esac continue ;; -I*|*.[cChHiI]|*.[cChHiI][pPxX][pPxX]) case $optimize in 1) eval " case \$arg in $nooptimize) optimize=0 ;; esac " ;; esac case $local in "") local=1 set . "$@" -I$INSTALLROOT/botch/include "$arg" continue ;; esac ;; -last|*/libast.a) case $library in "") library=1 set . "$@" $INSTALLROOT/botch/lib/libbotch.a "$arg" $INSTALLROOT/botch/lib/libbotch.a continue ;; esac ;; esac set . "$@" "$arg" done case $library in "") set . "$@" $INSTALLROOT/botch/lib/libbotch.a shift ;; esac case $optimize in 0) set . "$@" . while : do shift arg=$1 shift case $arg in .) break ;; -O) set . "$@" ;; *) set . "$@" "$arg" ;; esac done ;; esac case $verbose in ?*) echo $cc "$@" ;; esac case $noexec in "") $cc "$@" ;; esac ksh-1.0.10/src/cmd/INIT/cc.next.m68k000077500000000000000000000002571465301102200165250ustar00rootroot00000000000000: next.m68k cc wrapper that enables POSIX : 2000-12-15 : HOSTTYPE=next.m68k case " $* " in *" -dumpmachine "*) echo $HOSTTYPE; exit ;; esac /bin/cc -posix -Xlinker -m "$@" ksh-1.0.10/src/cmd/INIT/cc.osf.alpha000077500000000000000000000003371465301102200166350ustar00rootroot00000000000000: osf.alpha cc wrapper with reasonable namespace defaults : 1998-02-04 : HOSTTYPE=osf.alpha case " $* " in *" -dumpmachine "*) echo $HOSTTYPE; exit ;; esac /usr/bin/cc -std -Dnoshare=_noshare_ -Dreadonly=_readonly_ "$@" ksh-1.0.10/src/cmd/INIT/cc.pentium4000077500000000000000000000006371465301102200165320ustar00rootroot00000000000000: linux.pentium4 gcc wrapper : 2005-10-24 : HOSTTYPE=linux.pentium4 case " $* " in *" -dumpmachine "*) echo $HOSTTYPE; exit ;; esac case " $* " in *" -O "*) set -A argv -- "$@" set -A nargv integer i j for ((i = j = 0; i < ${#argv[@]}; i++)) do if [[ ${argv[i]} == -O ]] then nargv[j++]=-O3 nargv[j++]=-march=pentium4 else nargv[j++]=${argv[i]} fi done gcc "${nargv[@]}" exit ;; esac gcc "$@" ksh-1.0.10/src/cmd/INIT/cc.sco.i386000077500000000000000000000002741465301102200162360ustar00rootroot00000000000000: sco.i386 cc wrapper with reasonable binary and namespace : 1998-02-04 : HOSTTYPE=sco.i386 case " $* " in *" -dumpmachine "*) echo $HOSTTYPE; exit ;; esac /bin/cc -b elf -D_SVID3 "$@" ksh-1.0.10/src/cmd/INIT/cc.sgi.mips2000077500000000000000000000020251465301102200165710ustar00rootroot00000000000000: sgi.mips2 cc wrapper that generates MIPS II binaries : 2006-02-14 : HOSTTYPE=sgi.mips2 case " $* " in *" -dumpmachine "*) echo $HOSTTYPE; exit ;; esac cc=/usr/bin/cc debug= dynamic=-G0 flags=-OPT:Olimit=0 ignore=1685,733,1048,1155,1171,1184,1209,1343,3169,3170,3433 ldignore=15,84,85,13 optimize= case $_AST_cc_OPTIONS in ?*) eval $_AST_cc_OPTIONS ;; esac case $ignore in ?*) ignore="-woff $ignore" ;; esac case $ldignore in ?*) ifs=$IFS IFS=, v=$ldignore ldignore= for i in $v do ldignore="$ldignore -Wl,-woff,$i" done IFS=$ifs ;; esac case $debug in ?*) integer n=0 for i do case $i in -g*) case $debug in -) continue ;; esac i=$debug ;; esac a[n++]=$i done set -- ${a[@]} ;; esac case $optimize in ?*) integer n=0 for i do case $i in -O*) case $optimize in -) continue ;; esac i=$optimize ;; esac a[n++]=$i done set -- ${a[@]} ;; esac if test -d /usr/lib32 then LD_LIBRARYN32_PATH=/lib32 $cc -32 -mips2 $flags $dynamic $ldignore $ignore "$@" else $cc -mips2 $flags $ignore "$@" fi ksh-1.0.10/src/cmd/INIT/cc.sgi.mips3000077500000000000000000000040171465301102200165750ustar00rootroot00000000000000: sgi.mips3 cc wrapper that generates MIPS III binaries : 2007-04-27 : HOSTTYPE=sgi.mips3 case " $* " in *" -dumpmachine "*) echo $HOSTTYPE; exit ;; esac # ld: # 15 # 84 # 85 # 134 # cc: # 1685 (first!!) Invalid error number: X. # 1035 cpp #error -- 0 exit status by default - botch botch botch # 1048 # 1155 # 1171 The indicated expression has no effect. # 1184 "=" is used where where "==" may have been intended. # 1209 The controlling expression is constant. # 1343 # 3169 X not marked as intrinsic because it is not yet declared # 3170 X not marked as intrinsic because it is not yet declared # 3421 expecting function name #pragma intrinsic (X) # 3433 X not marked as intrinsic because it is not yet declared # 3434 X not marked as intrinsic because it is not yet declared cc=/usr/bin/cc debug= dynamic=-G0 flags=-OPT:Olimit=0 fatal=1035 ignore=1685,733,1048,1155,1171,1184,1209,1343,3169,3170,3421,3433,3434 ldignore=15,84,85,13 optimize= case $_AST_cc_OPTIONS in ?*) eval $_AST_cc_OPTIONS ;; esac case $fatal in ?*) fatal="-diag_error $fatal" ;; esac case $ignore in ?*) ignore="-woff $ignore" ;; esac case $ldignore in ?*) ifs=$IFS IFS=, v=$ldignore ldignore= for i in $v do ldignore="$ldignore -Wl,-woff,$i" done IFS=$ifs ;; esac case $debug in ?*) integer n=0 for i do case $i in -g*) case $debug in -) continue ;; esac i=$debug ;; esac a[n++]=$i done set -- ${a[@]} ;; esac case $optimize in ?*) integer n=0 for i do case $i in -O*) case $optimize in -) continue ;; esac i=$optimize ;; esac a[n++]=$i done set -- ${a[@]} ;; esac case $1 in -mips2) if test -d /usr/lib32 then LD_LIBRARYN32_PATH=/lib32 $cc -32 -mips2 $flags $dynamic $ldignore $ignore "$@" else $cc -mips2 $flags $ignore "$@" fi ;; -mips4) case " $* " in *" -ldl "*) integer n=0 for i do case $i in -ldl) ;; *) a[n++]=$i ;; esac done set -- ${a[@]} esac $cc -64 -mips4 $flags $dynamic $fatal $ldignore $ignore "$@" ;; *) $cc -n32 -mips3 $flags $dynamic $fatal $ldignore $ignore "$@" ;; esac ksh-1.0.10/src/cmd/INIT/cc.sgi.mips3-o32000077500000000000000000000016721465301102200172020ustar00rootroot00000000000000: sgi.mips3-o32 cc wrapper that generates MIPS III O32 binaries : 2006-02-14 : HOSTTYPE=sgi.mips3-o32 case " $* " in *" -dumpmachine "*) echo $HOSTTYPE; exit ;; esac cc=/usr/bin/cc debug= dynamic=-G0 flags= ignore=1685,733,1048,1155,1171,1184,1209,1343,3169,3170,3433 ldignore=15,84,85,13 optimize= case $_AST_cc_OPTIONS in ?*) eval $_AST_cc_OPTIONS ;; esac case $ignore in ?*) ignore="-woff $ignore" ;; esac case $ldignore in ?*) ifs=$IFS IFS=, v=$ldignore ldignore= for i in $v do ldignore="$ldignore -Wl,-woff,$i" done IFS=$ifs ;; esac case $debug in ?*) integer n=0 for i do case $i in -g*) case $debug in -) continue ;; esac i=$debug ;; esac a[n++]=$i done set -- ${a[@]} ;; esac case $optimize in ?*) integer n=0 for i do case $i in -O*) case $optimize in -) continue ;; esac i=$optimize ;; esac a[n++]=$i done set -- ${a[@]} ;; esac $cc -o32 -mips3 $flags $dynamic $ldignore $ignore "$@" ksh-1.0.10/src/cmd/INIT/cc.sgi.mips4000077500000000000000000000026131465301102200165760ustar00rootroot00000000000000: sgi.mips4 cc wrapper that generates MIPS IV binaries : 2007-04-27 : HOSTTYPE=sgi.mips4 case " $* " in *" -dumpmachine "*) echo $HOSTTYPE; exit ;; esac cc=/usr/bin/cc debug= dynamic=-G0 flags=-OPT:Olimit=0 fatal=1035 ignore=1685,733,1048,1155,1171,1184,1209,1343,3169,3170,3433 ldignore=15,84,85,13 optimize= case $_AST_cc_OPTIONS in ?*) eval $_AST_cc_OPTIONS ;; esac case $fatal in ?*) fatal="-diag_error $fatal" ;; esac case $ignore in ?*) ignore="-woff $ignore" ;; esac case $ldignore in ?*) ifs=$IFS IFS=, v=$ldignore ldignore= for i in $v do ldignore="$ldignore -Wl,-woff,$i" done IFS=$ifs ;; esac case $debug in ?*) integer n=0 for i do case $i in -g*) case $debug in -) continue ;; esac i=$debug ;; esac a[n++]=$i done set -- ${a[@]} ;; esac case $optimize in ?*) integer n=0 for i do case $i in -O*) case $optimize in -) continue ;; esac i=$optimize ;; esac a[n++]=$i done set -- ${a[@]} ;; esac case $1 in -mips2) if test -d /usr/lib32 then LD_LIBRARYN32_PATH=/lib32 $cc -32 -mips2 $flags $dynamic $ldignore $ignore "$@" else $cc -mips2 $flags $ignore "$@" fi ;; -mips3) $cc -n32 -mips3 $flags $dynamic $fatal $ldignore $ignore "$@" ;; *) case " $* " in *" -ldl "*) integer n=0 for i do case $i in -ldl) ;; *) a[n++]=$i ;; esac done set -- ${a[@]} esac $cc -64 -mips4 $flags $dynamic $fatal $ldignore $ignore "$@" ;; esac ksh-1.0.10/src/cmd/INIT/cc.sgi.mips4-n32000077500000000000000000000016711465301102200172010ustar00rootroot00000000000000: sgi.mips4-n32 cc wrapper that generates MIPS IV N32 binaries : 2006-02-14 : HOSTTYPE=sgi.mips4-n32 case " $* " in *" -dumpmachine "*) echo $HOSTTYPE; exit ;; esac cc=/usr/bin/cc debug= dynamic=-G0 flags= ignore=1685,733,1048,1155,1171,1184,1209,1343,3169,3170,3433 ldignore=15,84,85,13 optimize= case $_AST_cc_OPTIONS in ?*) eval $_AST_cc_OPTIONS ;; esac case $ignore in ?*) ignore="-woff $ignore" ;; esac case $ldignore in ?*) ifs=$IFS IFS=, v=$ldignore ldignore= for i in $v do ldignore="$ldignore -Wl,-woff,$i" done IFS=$ifs ;; esac case $debug in ?*) integer n=0 for i do case $i in -g*) case $debug in -) continue ;; esac i=$debug ;; esac a[n++]=$i done set -- ${a[@]} ;; esac case $optimize in ?*) integer n=0 for i do case $i in -O*) case $optimize in -) continue ;; esac i=$optimize ;; esac a[n++]=$i done set -- ${a[@]} ;; esac $cc -n32 -mips4 $flags $dynamic $ldignore $ignore "$@" ksh-1.0.10/src/cmd/INIT/cc.specialize000077500000000000000000000007741465301102200171170ustar00rootroot00000000000000: -O* specialization cc wrapper : 2011-11-11 : case " $* " in *" -dumpmachine "*) echo $HOSTTYPE; exit ;; esac cc=cc CCREPLACE='' # these (possibly empty) options replace -O* CCALWAYS='' # these (possibly empty) options always set case $CCREPLACE in '') ;; *) case " $* " in *" -O"*) set '' "$@" '' shift while : do a=$1 shift case $a in '') break ;; -O*) set '' "$@" $CCREPLACE ;; *) set '' "$@" "$a" ;; esac shift done ;; esac ;; esac $cc $CCALWAYS "$@" ksh-1.0.10/src/cmd/INIT/cc.unix.mc68k000077500000000000000000000026171465301102200166770ustar00rootroot00000000000000: 3B1/PC7300 unix.mc68k cc wrapper for ANSI C : 2002-09-01 : HOSTTYPE=unix.mc68k case " $* " in *" -dumpmachine "*) echo $HOSTTYPE; exit ;; esac # /bin/cc predates ANSI C; use gcc # some headers depend on SYSTEM5 or mc68k being defined # headers for Ethernet software are under /usr/ethernet/include # both /usr/lib/libnet.a and /usr/lib/libcurses.a define select() # -lcurses uses a version of select for napms(), but that # implementation always returns an error if given file # descriptors to watch # the one in -lnet must be used if fds (instead of or in addition to # a timeout) are of interest therefore, -lnet should be # specified before -lcurses # rename(old, new) in /usr/lib/libnet.a fails if new exists # (permitted by ANSI/ISO C-1990 7.9.4.2) # gcc -fpic doesn't work as there's no _GLOBAL_OFFSET_TABLE symbol cc="gcc" exec= show=: inc=0 lib=0 set '' -DSYSTEM5 -Dmc68k "$@" '' shift while : do a=$1 shift case $a in '') break ;; -lcurses|libcurses.a|*/libcurses.a) lib=1 set '' "$@" -lnet shift ;; -lnet|libnet.a|*/libnet.a) lib=1 ;; -o) a=$1 shift set '' "$@" -o shift ;; -fpic) continue ;; -n) exec=: continue ;; -v) show=echo continue ;; -*) ;; *) case $inc in 0) inc=1 set '' "$@" -I/usr/ethernet/include shift ;; esac ;; esac set '' "$@" "$a" shift done case $lib in 0) set '' "$@" -lnet shift ;; esac $show $cc "$@" $exec $cc "$@" ksh-1.0.10/src/cmd/INIT/cc.unixware.i386000077500000000000000000000002511465301102200173070ustar00rootroot00000000000000: unixware.i386 cc wrapper HOSTTYPE=unixware.i386 case " $* " in *" -dumpmachine "*) echo $HOSTTYPE; exit ;; esac /bin/cc -D_XOPEN_UNIX -D_XOPEN_SOURCE_EXTENDED "$@" ksh-1.0.10/src/cmd/INIT/crossexec.sh000066400000000000000000000102531465301102200170000ustar00rootroot00000000000000######################################################################## # # # This software is part of the ast package # # Copyright (c) 1994-2011 AT&T Intellectual Property # # Copyright (c) 2020-2022 Contributors to ksh 93u+m # # and is licensed under the # # Eclipse Public License, Version 2.0 # # # # A copy of the License is available at # # https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html # # (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) # # # # Glenn Fowler # # Martijn Dekker # # # ######################################################################## : cross compiler a.out execution (command set -o posix) 2>/dev/null && set -o posix command=crossexec tmp=/tmp/cross$$ case `(getopts '[-][123:xyz]' opt --xyz; echo 0$opt) 2>/dev/null` in 0123) ARGV0="-a $command" USAGE=$' [-? @(#)$Id: crossexec (AT&T Labs Research) 2004-01-04 $ ] [-author?Glenn Fowler ] [-copyright?Copyright (c) 1994-2012 AT&T Intellectual Property] [-license?https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html] [+NAME?crossexec - cross compiler a.out execution] [+DESCRIPTION?\bcrossexec\b runs a cross-compiled \acommand\a in an environment that supports a cross-compilation architecture different from the current host. The cross environment is determined by \acrosstype\a, usually a host type name produced by \bpackage\b(1). \acrosstype\a is used to find an entry in \b$HOME/.crossexec\b that specifies the cross compiler host and access details.] [+?The exit status of \bcrossexec\b is the exit status of \acommand\a.] [+CROSS ENVIRONMENT FILE?\b$HOME/.crossexec\b contains one line for each supported \acrosstype\a. Each line contains 5 tab separated fields. Field default values are specified as \b-\b. The fields are:]{ [+crosstype?The host type produced by \bpackage\b(1).] [+host?The host name.] [+user?The user name on \ahost\a. The default is the current user.] [+dir?The directory to copy \acommand\a and execute it. The default is the \auser\a \b$HOME\b on \ahost\a.] [+shell?The command used to get shell access to \ahost\a. Currently only \brsh\b and \bssh\b are supported.] [+copy?The command used to copy \acommand\a to \ahost\a. Currently only \brcp\b and \bscp\b are supported.] } [n:show?Show the underlying commands but do not execute.] crosstype command [ option ... ] [ file ... ] [+SEE ALSO?\brcp\b(1), \brsh\b(1), \bscp\b(1), \bssh\b(1)] ' ;; *) ARGV0="" USAGE="crosstype command [ option ... ] [ file ... ]" ;; esac usage() { OPTIND=0 getopts $ARGV0 "$USAGE" OPT '-?' exit 2 } exec= # get the options and operands while getopts $ARGV0 "$USAGE" OPT do case $OPT in n) exec=echo ;; *) usage ;; esac done shift $OPTIND-1 case $# in [01]) usage ;; esac type=$1 shift cmd=$1 shift # get the host info info=$HOME/.$command if test ! -r $info then echo "$command: $info: not found" >&2 exit 1 fi ifs=${IFS-' '} while : do IFS=' ' read hosttype hostname usr dir sh cp code=$? IFS=$ifs case $code in 0) ;; *) echo "$command: $type: unknown cross compiler host type" >&2 exit 1 ;; esac case $hosttype in $type) break ;; esac done < $info # fill in the defaults case $usr in -) cpu= shu= ;; *) cpu=${usr}@ shu="-l $usr" ;; esac case $dir in -) dir= ;; esac case $sh in ''|-) sh=ssh ;; esac case $cp in ''|-) cp=scp ;; scp) cp="$cp -q" ;; esac trap "rm -f $tmp" 0 1 2 3 15 $exec $cp $cmd $cpu$hostname:$dir /dev/null; code=\$?; rm -f $cmd; echo $command: exit \$code >&2" $tmp exit `sed -e '/^'$command': exit [0-9][0-9]*$/!d' -e 's/.* //' $tmp` ksh-1.0.10/src/cmd/INIT/db.c000066400000000000000000000026241465301102200152020ustar00rootroot00000000000000/*********************************************************************** * * * This software is part of the ast package * * Copyright (c) 1994-2011 AT&T Intellectual Property * * Copyright (c) 2020-2023 Contributors to ksh 93u+m * * and is licensed under the * * Eclipse Public License, Version 2.0 * * * * A copy of the License is available at * * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html * * (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) * * * * Glenn Fowler * * Martijn Dekker * * Johnothan King * * * ***********************************************************************/ /* * small test for sleepycat dbm compatibility */ #define DB_DBM_HSEARCH 1 #if DB_DBM_HSEARCH #include #endif int main(void) { DBM* dbm = 0; dbm_close(dbm); return 0; } ksh-1.0.10/src/cmd/INIT/dl.c000066400000000000000000000025271465301102200152160ustar00rootroot00000000000000/*********************************************************************** * * * This software is part of the ast package * * Copyright (c) 1994-2011 AT&T Intellectual Property * * Copyright (c) 2020-2023 Contributors to ksh 93u+m * * and is licensed under the * * Eclipse Public License, Version 2.0 * * * * A copy of the License is available at * * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html * * (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) * * * * Glenn Fowler * * Martijn Dekker * * Johnothan King * * * ***********************************************************************/ /* * small test for -ldl */ #ifndef dlopen #include #endif int main(void) { dlopen("libdl.so",0); return 0; } ksh-1.0.10/src/cmd/INIT/dylink.sh000066400000000000000000000105021465301102200162710ustar00rootroot00000000000000######################################################################## # # # This file is part of the ksh 93u+m package # # Copyright (c) 2021-2024 Contributors to ksh 93u+m # # and is licensed under the # # Eclipse Public License, Version 2.0 # # # # A copy of the License is available at # # https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html # # (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) # # # # Martijn Dekker # # # ######################################################################## # Dynamic library linking tool for ksh 93u+m and supporting libraries. # Called from **/Mamfile. case ${ZSH_VERSION+z} in z) emulate ksh ;; *) (command set -o posix) 2>/dev/null && set -o posix ;; esac set -o noglob # avoid pathname expansion interfering with field splitting note() { printf "$0: %s\\n" "$@" >&2 } err_out() { note "$@" exit 3 } do_link() { target=$dest_dir/$1 shift test -e "$target" && rm -f "$target" ( PS4="[dylink] $PS4" set -o xtrace # why pass CCFLAGS here? because it *might* have a flag like -m64 that the linker also needs ${CC:-cc} $CCFLAGS $LDFLAGS -o "$target" "$@" ) || exit } # Basic sanity check. case ${HOSTTYPE:+H}${INSTALLROOT:+I}${AST_NO_DYLIB+n} in HI) ;; HIn) note "Building dynamic libraries was disabled; skipping" exit 0 # continue build ;; *) err_out "Required environment missing" ;; esac # Parse options. unset exec_file module_name l_flags version prefix suffix while getopts 'e:m:l:v:p:s:' opt do case $opt in e) exec_file=$OPTARG ;; m) module_name=$OPTARG ;; l) l_flags="$l_flags -l$OPTARG" ;; v) version=$OPTARG ;; # this should be like 6.0 p) prefix=$OPTARG ;; # this should be 'lib' or empty s) suffix=$OPTARG ;; # this should be like .dylib or .so '?') exit 2 ;; *) err_out "Internal error (getopts)" ;; esac done shift $((OPTIND - 1)) # Validate options. case ${exec_file:+e}${module_name:+m} in e | m) ;; *) err_out "Either -e or -m should be specified" ;; esac case ${module_name:+m}${prefix+p}${suffix+s}${version:+v} in '' | mpsv ) ;; *) err_out "-m requires -v/-p/-s and vice versa" ;; esac # Check for supported system. case $HOSTTYPE in android.* | darwin.* | dragonflybsd.* | freebsd* | haiku.* | linux.* | netbsd.* | openbsd.* | qnx.* | sol* ) # supported ;; cygwin.*) note "Dynamic libraries are not supported on Cygwin." exit 0 # continue build ;; *) note "The system $HOSTTYPE is currently untested for dynamic libraries" \ "so dynamic libraries are disabled by default. To test them," \ "export AST_DYLIB_TEST to try to build a dynamically linked ksh." case ${AST_DYLIB_TEST:+y} in y) ;; *) exit 0 # continue build ;; esac ;; esac # Set destination directory. dest_dir=$INSTALLROOT/dyn mkdir -p "$dest_dir/bin" "$dest_dir/lib" || err_out "could not mkdir" # Do the dynamic linking. case ${exec_file} in '') # ... figure out library file name(s) and internal name for linking purposes # on macOS we have version before extension (libast.6.0.dylib), on other systems, after (libast.so.6.0) case $suffix in .dylib) lib_file=$prefix$module_name.$version$suffix lib_linkname=$prefix$module_name.${version%%.*}$suffix ;; *) lib_file=$prefix$module_name$suffix.$version lib_linkname=$prefix$module_name$suffix.${version%%.*} ;; esac sym_links="$lib_linkname $prefix$module_name$suffix" # ... remove possible old versions (set +o noglob; exec rm -f "$dest_dir/lib/lib$module_name".*) # ... execute linker command case $HOSTTYPE in darwin.*) do_link "lib/$lib_file" -dynamiclib \ -Wl,-dylib_install_name -Wl,"$lib_linkname" \ "$@" -L"$dest_dir/lib" $l_flags ;; *) do_link "lib/$lib_file" -shared -Wl,-soname -Wl,"$lib_linkname" \ "$@" -L"$dest_dir/lib" $l_flags ;; esac for f in $sym_links do ln -sf "$lib_file" "$dest_dir/lib/$f" done ;; *) # Link an executable. do_link "bin/$exec_file" "$@" -L"$dest_dir/lib" $l_flags ;; esac ksh-1.0.10/src/cmd/INIT/gdbm.c000066400000000000000000000026061465301102200155260ustar00rootroot00000000000000/*********************************************************************** * * * This software is part of the ast package * * Copyright (c) 1994-2011 AT&T Intellectual Property * * Copyright (c) 2020-2023 Contributors to ksh 93u+m * * and is licensed under the * * Eclipse Public License, Version 2.0 * * * * A copy of the License is available at * * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html * * (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) * * * * Glenn Fowler * * Martijn Dekker * * Johnothan King * * * ***********************************************************************/ /* * small test for -lgdbm */ #define _hdr_gdbm_ndbm 1 #if _hdr_gdbm_ndbm #include #endif int main(void) { DBM* dbm = 0; dbm_close(dbm); return 0; } ksh-1.0.10/src/cmd/INIT/gdbm1.c000066400000000000000000000026061465301102200156070ustar00rootroot00000000000000/*********************************************************************** * * * This software is part of the ast package * * Copyright (c) 1994-2011 AT&T Intellectual Property * * Copyright (c) 2020-2023 Contributors to ksh 93u+m * * and is licensed under the * * Eclipse Public License, Version 2.0 * * * * A copy of the License is available at * * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html * * (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) * * * * Glenn Fowler * * Martijn Dekker * * Johnothan King * * * ***********************************************************************/ /* * small test for -lgdbm */ #define _hdr_gdbm_ndbm 1 #if _hdr_gdbm_ndbm #include #endif int main(void) { DBM* dbm = 0; dbm_close(dbm); return 0; } ksh-1.0.10/src/cmd/INIT/gdbm2.c000066400000000000000000000025661465301102200156150ustar00rootroot00000000000000/*********************************************************************** * * * This software is part of the ast package * * Copyright (c) 1994-2011 AT&T Intellectual Property * * Copyright (c) 2020-2023 Contributors to ksh 93u+m * * and is licensed under the * * Eclipse Public License, Version 2.0 * * * * A copy of the License is available at * * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html * * (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) * * * * Glenn Fowler * * Martijn Dekker * * Johnothan King * * * ***********************************************************************/ /* * small test for -lgdbm */ #define _hdr_ndbm 1 #if _hdr_ndbm #include #endif int main(void) { DBM* dbm = 0; dbm_close(dbm); return 0; } ksh-1.0.10/src/cmd/INIT/hello.c000066400000000000000000000025061465301102200157170ustar00rootroot00000000000000/*********************************************************************** * * * This software is part of the ast package * * Copyright (c) 1994-2011 AT&T Intellectual Property * * Copyright (c) 2020-2023 Contributors to ksh 93u+m * * and is licensed under the * * Eclipse Public License, Version 2.0 * * * * A copy of the License is available at * * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html * * (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) * * * * Glenn Fowler * * Martijn Dekker * * Johnothan King * * * ***********************************************************************/ #ifndef printf #include #endif int main(void) { int new = 0; printf("hello world\n"); return new;} ksh-1.0.10/src/cmd/INIT/iconv.c000066400000000000000000000024671465301102200157400ustar00rootroot00000000000000/*********************************************************************** * * * This software is part of the ast package * * Copyright (c) 1994-2011 AT&T Intellectual Property * * Copyright (c) 2020-2023 Contributors to ksh 93u+m * * and is licensed under the * * Eclipse Public License, Version 2.0 * * * * A copy of the License is available at * * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html * * (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) * * * * Glenn Fowler * * Martijn Dekker * * Johnothan King * * * ***********************************************************************/ #ifndef iconv #include #endif int main(void) { iconv(0, 0, 0, 0, 0); return 0; } ksh-1.0.10/src/cmd/INIT/iffe.sh000066400000000000000000003053401465301102200157170ustar00rootroot00000000000000######################################################################## # # # This software is part of the ast package # # Copyright (c) 1994-2012 AT&T Intellectual Property # # Copyright (c) 2020-2024 Contributors to ksh 93u+m # # and is licensed under the # # Eclipse Public License, Version 2.0 # # # # A copy of the License is available at # # https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html # # (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) # # # # Glenn Fowler # # Martijn Dekker # # Johnothan King # # # ######################################################################## # Glenn Fowler & Phong Vo # AT&T Research # # test if feature exists # this script is written to make it through POSIX sh variants # # NOTE: .exe a.out suffix and [\\/] in path patterns for DOS/NT case ${ZSH_VERSION+z} in z) emulate ksh ;; *) (command set -o posix) 2>/dev/null && set -o posix ;; esac case $HOSTTYPE in ibm.*) unset LIBPATH ;; # AIX: avoid failure to link to libiconv esac set -o noglob command=iffe version=2024-03-20 # DEFPATH should be inherited from package(1) case $DEFPATH in /*) ;; *) echo "$command: DEFPATH not set" >&2 exit 1 ;; esac compile() # $cc ... { case $debug in 1) # level 1 doesn't xtrace, but compiler command lines are useful (set -x; "$@") ;; *) "$@" ;; esac 2>$tmp.err _compile_status=$? if test -s $tmp.err then cat $tmp.err >&2 fi if test "$_compile_status" -gt 128 then echo "$command: $@" >&$stderr cat $tmp.err >&$stderr sig=$(kill -l "$_compile_status") case $sig in [!0-9]?*) echo "$command: $1: terminated by SIG$sig" ;; *) echo "$command: $1: fatal interruption ($_compile_status)" ;; esac >&$stderr exit $_compile_status fi return $_compile_status } is_hdr() # [ - ] [ file.c ] hdr { case $1 in -) _is_hdr_flag=-; shift ;; *) _is_hdr_flag= ;; esac case $1 in *.c) _is_hdr_file=$1; shift ;; *) _is_hdr_file=$tmp.c ;; esac is hdr $1 case $1 in sys/types.h | limits.h | stdio.h | unistd.h) # These are often tested for repeatedly, especially sys/types.h. # But POSIX has specified these since issue 1 (1988). It's 2023. # Skip the compile to save time, but act like a positive test. : 2>$tmp.e ;; *) compile $cc -c $_is_hdr_file <&$nullin >&$nullout 2>$tmp.e ;; esac _is_hdr_status=$? case $_is_hdr_status in 0) if test -s $tmp.e then case $(grep '#.*error' $tmp.e) in ?*) _is_hdr_status=1 ;; esac fi ;; esac case $_is_hdr_status in 0) success $_is_hdr_flag ;; *) case $debug in 3) cat $tmp.e >&$stderr ;; esac failure $_is_hdr_flag ;; esac return $_is_hdr_status } pkg() # package { case $1 in '') # Determine default system path, store in $pth. pth=$(echo "$DEFPATH" | sed 's/:/ /g') return ;; '<') shift ;; *) return ;; esac case $1 in X|X11*) i="openwin" case $1 in X) set X11 ;; esac case $1 in X11) case $# in 1) set $1 6 5 4 ;; esac ;; esac ;; *) i= ;; esac pth="{ usr . - . contrib local $i - . share - . lib - $1" i=$1 while : do shift case $# in 0) break ;; esac case $1 in '>') shift; break ;; esac pth="$pth ${i}R$1 ${i}.$1" done pth="$pth . } $*" } show_test() { case $shell in ksh) print -n - "$command: test: $* ..." ;; *) printf '%s: test: %s ...' "$command" "$*" ;; esac case $debug in 0) ;; *) echo ;; # when debugging, add newline before compiler error messages esac } >&$stderr is() # op name { case $verbose in 1) case $complete in 1) failure ;; esac oo=$1 shift case $1 in ?*) yy=is ii=$1 complete=1 case $oo in cmd) mm="a command" ;; dat) mm="a library data symbol" ;; dfn) mm="a macro with extractable value" ;; exp) mm="true" ;; hdr) mm="a header" ;; id) mm="an identifier" ;; lcl) mm="a native header" ;; key) mm="a reserved keyword" ;; lib) mm="a library function" ;; LIB) case $2 in "") mm="a library" ;; *) ii=$*; mm="a library group" ;; esac ;; mac) mm="a macro" ;; mem) mm="a member of $2" ;; mth) mm="a math library symbol" ;; nos) mm="a non-opaque struct" ;; npt) mm="a symbol that needs a prototype" ;; num) mm="a numeric constant or enum" ;; nxt) mm="an include path for the native header" ;; opt) mm="set in \$PACKAGE_OPTIONS" ;; pth) mm="a file" ;; run) yy="capture output of" mm= ;; siz) mm="a type with known size" ;; sym) mm="a typed variable" ;; sys) mm="a system header" ;; typ) mm="a type or typedef" ;; val) yy="determine" mm="value" ;; *) yy= mm= ;; esac case $ii in [abcdefghijklmnopqrstuvwxyz]*[abcdefghijklmnopqrstuvwxyz]'{') ii="$ii ... }end" ;; esac show_test $yy $ii $mm complete=1 ;; esac ;; esac } success() { case $1 in -) shift ;; *) case $result in UNKNOWN) result=SUCCESS ;; esac case $1 in +) return ;; esac ;; esac case $complete:$verbose in 1:1) case $suspended in 1) suspended=0 show_test $yy $ii $mm ;; esac complete=0 case $# in 0) mm="yes" ;; *) mm="'$*'" ;; esac case $debug in 0) echo " $mm" >&$stderr ;; *) echo "$command: ... $mm" >&$stderr ;; esac ;; esac } failure() { case $1 in -) shift ;; *) result=FAILURE case $1 in +) return ;; esac ;; esac case $complete:$verbose in 1:1) case $suspended in 1) suspended=0 show_test $yy $ii $mm ;; esac complete=0 case $group in '') case $# in 0) mm="no" ;; *) mm=$* ;; esac ;; *) mm= ;; esac case $debug in 0) echo " $mm" >&$stderr ;; *) echo "$command: ... $mm" >&$stderr ;; esac ;; esac } # report # # - ignore global status # -0 normal sense # -1 inverted sense if ! def # status test status 0:success *:failure # success success comment # failure failure comment # default default setting comment # # globals # # $not invert test sense # $M test variable # $m test macro # $v default macro report() # [-] [-0] [-1] status value success failure default { case $1 in -) _report_ignore=$1 shift ;; *) _report_ignore= ;; esac _report_not=$not case $1 in -0) shift ;; -1) shift case $def in ''|-) case $_report_not in 1) _report_not= ;; *) _report_not=1 ;; esac ;; esac ;; esac _report_status=$1 case $_report_ignore:$_report_status in -:*) ;; *:0) success $_report_ignore ;; *) failure $_report_ignore case $group in ?*) return ;; esac ;; esac _report_value=$2 case $_report_not in 1) case $_report_status in 0) _report_status=1 ;; *) _report_status=0 ;; esac _report_success=$4 _report_failure=$3 ;; *) _report_success=$3 _report_failure=$4 ;; esac _report_default=$5 case $_report_status in 0) case $M in *-*) ;; *) usr="$usr$nl#define $m $_report_value" case $_report_success in ''|-) ;; *) case $define in 1) echo "#define $m $_report_value /* $_report_success */" ;; n) echo "$m=$_report_value" esac ;; esac eval $m=\'$_report_value\' ;; esac ;; *) case $M in *-*) ;; *) case $_report_failure in ''|-) ;; *) case $define$all$config$undef in 1?1?|1??1)echo "#undef $m /* $_report_failure */" ;; 11??) echo "#define $m 0 /* $_report_failure */" ;; n1?1) echo "$m=" ;; n1??) echo "$m=0" ;; esac ;; esac case $_report_default in ''|-) ;; *) case $define$set in 1?*) echo "#define $v $set /* $_report_default */" ;; n?*) echo "$v=$set" ;; esac ;; esac eval $m=0 ;; esac ;; esac } noisy() { case $complete:$verbose in 1:1) suspended=1 echo >&$stderr ;; esac } copy() # "output-file" "data-that-must-not-be-processed-by-echo" { # Some ksh88 clones (pdksh, mksh) lack 'printf' as a built-in utility, so if a # ksh-type shell was detected, use the 'print' built-in for better performance. case $1 in -) case $shell in ksh) print -r - "$2" ;; *) printf '%s\n' "$2" ;; esac ;; *) case $shell in ksh) print -r - "$2" ;; *) printf '%s\n' "$2" ;; esac > "$1" ;; esac } # verify that cc is a C compiler checkcc() { # check for local package root directories case $PACKAGE_PATH in ?*) for i in $(echo $PACKAGE_PATH | sed 's,:, ,g') do if test -d $i/include then cc="$cc -I$i/include" occ="$occ -I$i/include" fi if test -d $i/lib then cc="$cc -L$i/lib" occ="$occ -L$i/lib" for y in $libpaths do eval $y=\"\$$y:\$i/lib\$${y}_default\" eval export $y done fi done ;; esac echo "int i = 1;" > $tmp.c if compile $cc -c $tmp.c <&$nullin >&$nullout then echo "(;" > $tmp.c if compile $cc -c $tmp.c <&$nullin >&$nullout then cctest="should not compile '(;'" fi else cctest="should compile 'int i = 1;'" fi case $cctest in "") cctest=0 ;; *) echo "$command: $cc: not a C compiler: $cctest" >&$stderr exit 1 ;; esac } execute() { case $verbose in 0) noteout=$nullout ;; *) noteout=$stderr ;; esac if test "" != "$cross" then crossexec $cross "$@" 9>&$noteout _execute_=$? elif test -d /NextDeveloper then "$@" <&$nullin >&$nullout 9>&$noteout _execute_=$? "$@" <&$nullin | cat else "$@" 9>&$noteout _execute_=$? fi return $_execute_ } exclude() { case $excludes in '') return 0 ;; esac for _exclude_var do eval _exclude_old=\$$_exclude_var case $_exclude_old in *" -I"*);; *) continue ;; esac _exclude_new= _exclude_sep= for _exclude_arg in $_exclude_old do _exclude_skip= for _exclude_dir in $excludes do case $_exclude_arg in -I$_exclude_dir|-I*/$_exclude_dir) _exclude_skip=1 break; ;; esac done case $_exclude_skip in '') _exclude_new="$_exclude_new$_exclude_sep$_exclude_arg" _exclude_sep=" " ;; esac done eval $_exclude_var=\$_exclude_new case $debug in 0) ;; *) echo $command: exclude $_exclude_var: "$_exclude_old => $_exclude_new" >&$stderr ;; esac done } all=0 apis= binding="-dy -dn -Bdynamic -Bstatic -Wl,-ashared -Wl,-aarchive -call_shared -non_shared '' -static" complete=0 config=0 defhdr= define=1 explicit=0 iff= usr= cross= debug=0 deflib= dir=FEATURE excludes= executable="test -x" exists="test -e" gothdr= gotlib= idno= idyes= ifs=${IFS-' '} in= includes= intrinsic= libpaths="DYLD_LIBRARY_PATH LD_LIBRARY_PATH LD_LIBRARYN32_PATH LD_LIBRARY64_PATH LIBPATH SHLIB_PATH" DYLD_LIBRARY_PATH_default=:/lib:/usr/lib LD_LIBRARY_PATH_default=:/lib:/usr/lib LD_LIBRARYN32_PATH_default=:/lib32:/usr/lib32 LD_LIBRARY64_PATH_default=:/lib64:/usr/lib64 LIBPATH_default=:/lib:/usr/lib SHLIB_PATH_default=:/shlib:/usr/shlib:/lib:/usr/lib nl=" " optimize=1 occ=cc one= out= puthdr= putlib= pragma= shell=posix case $(eval 'PATH=/dev/null && let i=93-5 && typeset -u v=ksh$i && print -r - "$v"' 2>/dev/null) in KSH88) shell=ksh ;; # also pdksh, mksh, zsh esac reallystatic= reallystatictest= regress= static=. statictest= case $COTEMP in "") case $HOSTNAME in ""|?|??|???|????|????) tmp=${HOSTNAME} ;; *) tmp=${HOSTNAME%${HOSTNAME#????}} ;; esac tmp=${tmp}$$ ;; *) tmp=x${COTEMP} ;; esac COTEMP=${tmp} export COTEMP case $tmp in ./*) ;; ??????????*) tmp=${tmp%${tmp#?????????}} ;; ?????????) ;; ????????) tmp=F$tmp ;; esac case $tmp in ./*) ;; *) tmp=./$tmp ;; esac undef=0 verbose=0 vers= # options -- `-' for output to stdout otherwise usage case $1 in -) out=-; shift ;; esac set= case $( (getopts '[-][123:xyz]' opt --xyz; echo 0$opt) 2>/dev/null ) in 0123) USAGE=$' [-? @(#)$Id: iffe (ksh 93u+m) '${version}$' $ ] [-author?Glenn Fowler ] [-author?Phong Vo ] [-author?Contributors to https://github.com/ksh93/ksh] [-copyright?(c) 1994-2012 AT&T Intellectual Property] [-copyright?(c) 2020-2024 Contributors to ksh 93u+m] [-license?https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html] [+NAME?iffe - C compilation environment feature probe] [+DESCRIPTION?\biffe\b is a command interpreter that probes the C compilation environment for features. A feature is any file, option or symbol that controls or is controlled by the C compiler. \biffe\b tests features by generating and compiling C programs and observing the behavior of the C compiler and generated programs.] [+?\biffe\b statements are line oriented. Statements may appear in the operand list with the \b:\b operand or \bnewline\b as the line delimiter. The standard input is read if there are no command line statements or if \afile\a\b.iffe\b is omitted.] [+?Though similar in concept to \bautoconf\b(1) and \bconfig\b(1), there are fundamental differences. The latter tend to generate global headers accessed by all components in a package, whereas \biffe\b is aimed at localized, self contained feature testing.] [+?Output is generated in \b'"$dir"$'/\b\atest\a by default, where \atest\a is the base name of \afile\a\b.iffe\b or the \biffe\b \brun\b file operand. Output is first generated in a temporary file; the output file is updated if it does not exist or if the temporary file is different. If the first operand is \b-\b then the output is written to the standard output and no update checks are done.] [+?Files with suffixes \b.iffe\b and \b.iff\b are assumed to contain \biffe\b statements.] [a:all?Define failed test macros \b0\b. By default only successful test macros are defined \b1\b.] [c:cc?Sets the C compiler name and flags to be used in the feature tests.]:[C-compiler-name [C-compiler-flags ...]]] [C:config?Generate \bconfig\b(1) style \aHAVE_\a* macro names. This implies \b--undef\b. Since \bconfig\b(1) has inconsistent naming conventions, the \bexp\b op may be needed to translate from the (consistent) \biffe\b names. Unless otherwise noted a \bconfig\b macro name is the \biffe\b macro name prefixed with \bHAVE\b and converted to upper case. \b--config\b is set by default if the command arguments contain a \brun\b op on an input file with the base name \bconfig\b.] [d:debug?Sets the debug level. Level 0 inhibits most error messages, level 1 shows compiler command lines and messages, and level 2 traces internal \biffe\b \bsh\b(1) actions and does not remove core dumps on exit.]#[level] [D:define?Successful test macro definitions are emitted. This is the default.] [E:explicit?Disable implicit test output.] [F:features?Sets the feature test header to \ahdr\a. This header typically defines *_SOURCE feature test macros.]:[hdr:=NONE] [i:input?Sets the input file name to \afile\a, which must contain \biffe\b statements.]:[file] [I:include?Adds \b-I\b\adir\a to the C compiler flags.]:[dir] [L:library?Adds \b-L\b\adir\a to the C compiler flags.]:[dir] [n:name-value?Output \aname\a=\avalue\a assignments only.] [N!:optimize?\b--nooptimize\b disables compiler optimization options.] [o:output?Sets the output file name to \afile\a.]:[file] [O:stdio?Sets the standard io header to \ahdr\a.]:[hdr:=stdio.h] [e:package?Obsolete; ignored.] [p:prototyped?Obsolete; ignored.] [P:pragma?Emits \b#pragma\b \atext\a at the top of the output file.]:[text] [r:regress?Massage output for regression testing.] [s:shell?Sets the internal shell name to \aname\a. Used for debugging Bourne shell compatibility (otherwise \biffe\b uses \aksh\a constructs if available). The supported names are \bksh\b, \bbsh\b, \bbash\b, and \bosh\b. \bosh\b forces the \bread -r\b compatibility read command to be compiled and used instead of \bread -r\b. The default is determined by probing the shell at startup.]:[name] [S:static?Sets the C compiler flags that force static linking. If not set then \biffe\b probes the compiler to determine the flags. \biffe\b must use static linking (no dlls) because on some systems missing library symbols are only detected when referenced at runtime from dynamically linked executables.]:[flags] [u:undef?\b#undef\b failed test macros. By default only successful test macros are defined \b1\b.] [v:verbose?Produce a message line on the standard error for each test as it is performed.] [x:cross?Some tests compile an executable (\ba.out\b) and then run it. If the C compiler is a cross compiler and the executable format is incompatible with the execution environment then the generated executables must be run in a different environment, possibly on another host. \acrosstype\a is the HOSTTYPE for generated executables (the \bpackage\b(1) command generates a consistent HOSTTYPE namespace). Generated executables are run via \bcrossexec\b(1) with \acrosstype\a as the first argument. \bcrossexec\b supports remote execution for cross-compiled executables. See \bcrossexec\b(1) for details.]:[crosstype] [X:exclude?Removes \b-I\b\adir\a and \b-I\b*/\adir\a C compiler flags.]:[dir] [ - ] [ file.iffe | statement [ : statement ... ] ] [+SYNTAX?\biffe\b input consists of a sequence of statement lines. Statements that span more than one line contain \abegin\a\b{\b as the last operand (where \abegin\a is command specific) and zero or more data lines terminated by a line containing \b}end\b as the first operand. The statement syntax is: [\aname\a \b=\b]] [\b!\b]] \atest\a[,\atest\a...]] [\b-\b]] [\aarg\a[,\aarg\a...]]]] [\aprereq\a ...]] [\abegin\a{ ... |\bend\b ...]] [= [\adefault\a]]]]. \atest\as and \aarg\as may be combined, separated by commas, to perform a set of tests on a set of arguments. \aname\a \b=\b before \atest\a overrides the default test variable and macro name, and \b-\b after \atest\a performs the test but does not define the test variable and macro values. \b!\b before \atest\a inverts the test sense for \bif\b, \belif\b, and \byes{\b and \bno{\b blocks.] [+?\aprereq\as are used when applying the features tests and may be combinations of:]{ [+compiler options?\b-D\b*, \b-L\b*, etc.] [+library references?\b-l\b*, *\b.a\b, etc. \b_LIB_\b\aname\a is defined to be 1 if \b-l\b\aname\a is a library.] [+header references?*\b.h\b. \a_dir_name\a is defined to be 1 if \adir/name\a\b.h\b is a header, or if \adir\a is omitted, \b_hdr_\b\aname\a is defined to be 1 if \aname\a\b.h\b is a header.] [+-?Prereq grouping mark; prereqs before the first \b-\b are passed to all feature tests. Subsequent groups are attempted in left-to-right order until the first successful group is found.] } [+?\abegin\a\b{\b ... \b}end\b delimit multiline code blocks that override or augment the default code provided by \biffe\b. User supplied code blocks should be compatible with the C89/C90 C language standard for maximal portability. Test code may call the function \bNOTE("...")\b to emit short text in \b--verbose\b output; only one \bNOTE()\b should be called per test for readability. In addition to all macro definitions generated by previous tests, all generated code contains the following at the top:]{ [+ ?/* AST backward compatibility macros */] [+ ?#define _NIL_(x) NULL] [+ ?#define _STD_ 1] [+ ?#define _ARG_(x) x] [+ ?#define _VOID_ void] [+ ?#define _BEGIN_EXTERNS_] [+ ?#define _END_EXTERNS_] [+ ?/* if/when available, "$INSTALLROOT/src/lib/libast/'"$dir"$'/standards" is included here */] [+ ?/* then is included, unless this was disabled using the "stdio" option */] } [+?= \adefault\a may be specified for the \bkey\b, \blib\b, \bmac\b, \bmth\b and \btyp\b tests. If the test fails for \aarg\a then \b#define\b \aarg\a \adefault\a is emitted. \bkey\b accepts multiple \b= \b\adefault\a values; the first valid one is used.] [+?Each test statement generates a portion of a C language header that contains macro definitions, comments, and other text corresponding to the feature tests. \b#ifndef _def_\b\aname\a\b_\b\adirectory\a ... \b#endif\b guards the generated header from multiple \b#include\bs, where \aname\a is determined by either the \brun\b statement input file name if any, or the first \atest\a in the first statement, and \adirectory\a is the basename component of either the \brun\b statement file, if any, or the current working directory. The output file name is determined in this order:]{ [+-?If the first command line operand is \b-\b then the output is written to the standard output.] [+--output=\afile\a?Output is \afile\a.] [+set out \afile\a?Output is \afile\a.] [+[run]] [\adirectory\a/]]\abase\a[\a.suffix\a]]?Output is \b'"$dir"$'/\b\abase\a.] } [+?Generated \biffe\b headers are often referenced in C source as: \b#include "'"$dir"$'/\b\afile\a". Note that the directories are deliberately named \b'"$dir"$'\b and \bfeatures\b to keep case-ignorant file systems happy.] [+?The feature tests are:]{ [+# \acomment\a?Comment line - ignored.] [+api \aname\a \aYYYYMMDD\a \asymbol ...\a?Emit API compatibility tests for \aname\a and \b#define\b \asymbol\a \asymbol\a_\aYYYYMMDD\a when \aNAME\a_API is >= \aYYYYMMDD\a (\aNAME\a is \aname\a converted to upper case). If \aNAME\a_API is not defined then \asymbol\a maps to the newest \aYYYYMMDD\a for \aname\a.] [+define \aname\a [ (\aarg,...\a) ]] [ \avalue\a ]]?Emit a macro \b#define\b for \aname\a if it is not already defined. The definition is passed to subsequent tests.] [+extern \aname\a \atype\a [ (\aarg,...\a) | [\adimension\a]] ]]?Emit an \bextern\b prototype for \aname\a if one is not already defined. The prototype is passed to subsequent tests.] [+header \aheader\a?Emit \b#include <\b\aheader\a\b>\b if \aheader\a exists. The \b#include\b is passed to subsequent tests.] [+print \atext\a?Copy \atext\a to the output file. \atext\a is passed to subsequent tests.] [+reference \aheader\a?If \aheader\a exists then add \b#include\b \aheader\a to subsequent tests.] [+ver \aname\a \aYYYYMMDD\a?\b#define\b \aNAME\a_VERSION \aYYYYMMDD\a (\aNAME\a is \aname\a converted to upper case).] [+cmd \aname\a?Defines \b_cmd_\b\aname\a if \aname\a is an executable in one of the standard system directories (as output by \bgetconf PATH\b). \b_\b\adirectory\a\b_\b\aname\a is defined for \adirectory\a in which \aname\a is found (with \b/\b translated to \b_\b).] [+dat \aname\a?Defines \b_dat_\b\aname\a if \aname\a is a data symbol in the default libraries.] [+def \aname\a?Equivalent to \bcmd,dat,hdr,key,lib,mth,sys,typ\b \aname\a.] [+dfn \aname\a?If \aname\a is a macro in the candidate headers then a \b#define\b \aname\a \avalue\a statement is output for the \avalue\a defined in the headers. The definition is \b#ifndef\b guarded.] [+exp \aname\a \aexpression\a?If \aexpression\a is a \"...\" string then \aname\a is defined to be the string, else if the \bexpr\b(1) evaluation of \aexpression\a is not 0 then \aname\a is defined to be 1, otherwise \aname\a is defined to be 0. Identifiers in \aexpression\a may be previously defined names from other \biffe\b tests; undefined names evaluate to 0. If \aname\a was defined in a previous successful test then the current and subsequent \bexp\b test on \aname\a are skipped. If \aname\a is \b-\b then the \aexpression\a is simply evaluated.] [+hdr \aname\a?Defines \b_hdr_\b\aname\a if the header \b<\b\aname\a\b.h>\b exists. The \b--config\b macro name is \bHAVE_\b\aNAME\a\b_H\b.] [+if \astatement\a ... | \belif\b \astatement\a ... | \belse\b | \bendif\b? Nested if-else test control.] [+iff \aname\a?The generated header \b#ifndef-#endif\b macro guard is \b_\b\aname\a\b_H\b.] [+inc \afile\a [ re ]]?Read #define macro names from \afile\a and arrange for those names to evaluate to 1 in \bexp\b expressions. If \are\a is specified then macros not matching \are\a are ignored.] [+key \aname\a?Defines \b_key_\b\aname\a if \aname\a is a reserved word (keyword).] [+lcl \aname\a?Generates a \b#include\b statement for the native version of the header \b<\b\aname\a\b.h>\b if it exists. Defines \b_lcl_\b\aname\a on success. The \b--config\b macro name is \bHAVE_\b\aNAME\a\b_H\b. The default \are\a is \b^HAVE_\b for \b--config\b and \b^_\b otherwise.] [+lib \aname\a?Defines \b_lib_\b\aname\a if \aname\a is an external symbol in the default libraries.] [+mac \aname\a?Defines \b_mac_\b\aname\a if \aname\a is a macro.] [+mem \astruct.member\a?Defines \b_mem_\b\amember\a\b_\b\astruct\a if \amember\a is a member of the structure \astruct\a.] [+mth \aname\a?Defines \b_mth_\b\aname\a if \aname\a is an external symbol in the math library.] [+nop \aname\a?If this is the first test then \aname\a may be used to name the output file and/or the output header guard macro. Otherwise this test is ignored.] [+npt \aname\a?Defines \b_npt_\b\aname\a if the \aname\a symbol requires a prototype. The \b--config\b macro name is \bHAVE_\aNAME\a\b_DECL\b with the opposite sense.] [+num \aname\a?Defines \b_num_\b\aname\a if \aname\a is a numeric constant \aenum\a or \amacro\a.] [+nxt \aname\a?Defines a string macro \b_nxt_\b\aname\a suitable for a \b#include\b statement to include the next (on the include path) or native version of the header \b<\b\aname\a\b.h>\b if it exists. Also defines the \"...\" form \b_nxt_\b\aname\a\b_str\b. The \b--config\b macro name is \bHAVE_\b\aNAME\a\b_NEXT\b.] [+one \aheader\a ...?Generates a \b#include\b statement for the first header found in the \aheader\a list.] [+opt \aname\a?Defines \b_opt_\b\aname\a if \aname\a is a space-separated token in the global environment variable \bPACKAGE_OPTIONS\b.] [+pth \afile\a [ \adir\a ... | { \ag1\a - ... - \agn\a } | < \apkg\a [\aver\a ...]] > ]]?Defines \b_pth_\b\afile\a, with embedded \b/\b chars translated to \b_\b, to the path of the first instance of \afile\a in the \adir\a directories. \b{\b ... \b}\b forms a directory list from the cross-product of \b-\b separated directory groups \ag1\a ... \agn\a. < ... > forms a directory list for the package \apkg\a with optional versions. If no operands are specified then the default PATH directories are used. The \b--config\b macro name is \aNAME\a\b_PATH\b.] [+run \afile\a?Runs the tests in \afile\a based on the \afile\a suffix:]{ [+.c?\afile\a is compiled and executed and the output is copied to the \biffe\b output file. Macros and headers supplied to \bbegin{\b ... \b}end\b are also supplied to \afile\a.] [+.sh?\afile\a is executed as a shell script and the output is copied to the \biffe\b output file.] [+.iffe \bor no suffix?\afile\a contains \biffe\b statements.] } [+set \aoption value\a?Sets option values. The options are described above.] [+siz \aname\a?Defines \b_siz_\b\aname\a to be \bsizeof\b(\aname\a) if \aname\a is a type in any of \b, , , \b. Any \b.\b characters in \aname\a are translated to space before testing and are translated to \b_\b in the output macro name.] [+sym \aname\a?Defines \b_ary_\b\aname\a if \aname\a is an array, \b_fun_\b\aname\a if \aname\a is a function pointer, \b_ptr_\b\aname\a if \aname\a is a pointer, or \b_reg_\b\aname\a if \aname\a is a scalar. In most cases \aname\a is part of a macro expansion.] [+sys \aname\a?Defines \b_sys_\b\aname\a if the header \b\b exists. The \b--config\b macro name is \bHAVE_SYS_\b\aNAME\a\b_H\b.] [+tst \aname\a?A user defined test on name. A source block must be supplied. Defines \b_\b\aname\a on success. \btst - ...\b is treated as \btst - - ...\b.] [+typ \aname\a?Defines \b_typ_\b\aname\a if \aname\a is a type in any of \b, , , \b. Any \b.\b characters in \aname\a are translated to space before testing and are translated to \b_\b in the output macro name.] [+val \aname\a?The output of \becho\b \aname\a is written to the output file.] [+var \aname\a?A user defined test on name. A source block must be supplied. Sets the \bexp\b variable \b_\b\aname\a on success but does not define a macro.] [+(\aexpression\a)?Equivalent to \bexp -\b \aexpression\a.] } [+?Code block names may be prefixed by \bno\b to invert the test sense. The block names are:]{ [+cat?The block is copied to the output file.] [+compile?The block is compiled (\bcc -c\b).] [+cross?The block is executed as a shell script using \bcrossexec\b(1) if \b--cross\b is on, or on the local host otherwise, and the output is copied to the output file. Test macros are not exported to the script.] [+execute?The block is compiled, linked, and executed. \b0\b exit status means success.] [+fail?If the test fails then the block text is evaluated by \bsh\b(1) in \biffe\b'\'$'s current shell environment. Changes in the shell state, such as variables, will survive the block. Standard input is redirected to \b/dev/null\b. Standard output is copied to the output file. Standard error may be used to log informative or error messages. The block may use \bexit\b to abort the \biffe\b run.] [+link?The block is compiled and linked (\bcc -o\b).] [+macro?The block is preprocessed (\bcc -E\b) and lines containing text bracketed by \b<<"\b ... \b">>\b (\aless-than\a \aless-than\a \adouble-quote\a ... \adouble-quote\a \agreater-than\a \agreater-than\a) are copied to the output file with the brackets omitted.] [+no?If the test fails then the block text is copied to the output file. Deprecated: use { \bif\b \belif\b \belse\b \bendif\b } with unnamed \b{\b ... \b}\b blocks.] [+note?If the test succeeds then the block is copied to the output as a \b/*\b ... \b*/\b comment.] [+output?The block is compiled, linked, and executed, and the output is copied to the output file.] [+pass?If the test succeeds then the block text is evaluated by \bsh\b(1) in the same manner as \bfail\b above.] [+preprocess?The block is preprocessed (\bcc -E\b).] [+run?The block is executed as a shell script and the output is copied to the output file. Successful test macros are also defined as shell variables with value \b1\b and are available within the block. Likewise, failed test macros are defined as shell variables with value \b0\b.] [+status?The block is compiled, linked, and executed, and the exit status is the test outcome, 0 for \afailure\a, the value otherwise.] [+yes?If the test succeeds then the block text is copied to the output file. \byes{\b ... \b}end\b is equivalent to the unnamed block \b{\b ... \b}\b. Deprecated: use { \bif\b \belif\b \belse\b \bendif\b } with unnamed \b{\b ... \b}\b blocks.] } [+SEE ALSO?\bautoconf\b(1), \bconfig\b(1), \bgetconf\b(1), \bcrossexec\b(1), \bpackage\b(1), \bsh\b(1)] ' while getopts -a "$command" "$USAGE" OPT do case $OPT in a) set="$set set all :" ;; c) set="$set set cc $OPTARG :" ;; C) set="$set set config :" ;; d) set="$set set debug $OPTARG :" ;; D) set="$set set define :" ;; E) set="$set set explicit :" ;; F) set="$set set features $OPTARG :" ;; i) set="$set set input $OPTARG :" ;; I) set="$set set include $OPTARG :" ;; L) set="$set set library $OPTARG :" ;; n) set="$set set namval $OPTARG :" ;; N) set="$set set nooptimize $OPTARG :" ;; o) set="$set set output $OPTARG :" ;; e) ;; # obsolete p) ;; # obsolete P) set="$set set pragma $OPTARG :" ;; r) set="$set set regress :" ;; s) set="$set set shell $OPTARG :" ;; S) set="$set set static $OPTARG :" ;; O) set="$set set stdio $OPTARG :" ;; u) set="$set set undef :" ;; v) set="$set set verbose :" ;; x) set="$set set cross $OPTARG :" ;; X) set="$set set exclude $OPTARG :" ;; esac done shift $((OPTIND - 1)) ;; *) while : do case $# in 0) break ;; esac case $1 in -) break ;; --) shift break ;; --a|--al|--all) REM=a ;; --cc=*) REM=c$(echo X$1 | sed 's,[^=]*=,,') ;; --co|--con|--conf|--confi|--config) REM=C ;; --cr=*|--cro=*|--cros=*|--cross=*) REM=x$(echo X$1 | sed -e 's,[^=]*=,,') ;; --d=*|--de=*|--deb=*|--debu=*|--debug=*) REM=d$(echo X$1 | sed 's,[^=]*=,,') ;; --def|--defi|--defin|--define) REM=D ;; --e=*|--ex=*|--exc=*|--excl=*|--exclu=*|--exclud=*|--exclude=*) REM=X$(echo X$1 | sed 's,[^=]*=,,') ;; --e|--ex|--exp|--expl|--expli|--explic|--explici|--explicit) REM=E ;; --f=*|--fe=*|--fea=*|--feat=*|--featu=*|--featur=*|--feature=*|--features=*) REM=F$(echo X$1 | sed 's,[^=]*=,,') ;; --inp=*|--inpu=*|--input=*) REM=i$(echo X$1 | sed 's,[^=]*=,,') ;; --inc=*|--incl=*|--inclu=*|--includ=*|--include=*) REM=I$(echo X$1 | sed 's,[^=]*=,,') ;; --l=*|--li=*|--lib=*|--libr=*|--libra=*|--librar=*|--library=*) REM=L$(echo X$1 | sed 's,[^=]*=,,') ;; --n|--na|--nam|--name|--name-v|--name-va|--name-val|--name-valu|--name-value) REM=n ;; --o=*|--ou=*|--out=*|--outp=*|--outpu=*|--output=*) REM=o$(echo X$1 | sed 's,[^=]*=,,') ;; --pa=*|--pac=*|--pack=*|--packa=*|--packag=*|--package=*) # obsolete ;; --pro|--prot|--proto|--protot|--prototy|--prototyp|--prototype|--prototyped) # obsolete ;; --pra=*|--prag=*|--pragma=*) REM=P$(echo X$1 | sed 's,[^=]*=,,') ;; --r|--re|--reg|--regre|--regres|--regress) REM=r ;; --sh=*|--she=*|--shel=*|--shell=*) REM=s$(echo X$1 | sed 's,[^=]*=,,') ;; --sta=*|--stat=*|--stati=*|--static=*) REM=S$(echo X$1 | sed 's,[^=]*=,,') ;; --std=*|--stdi=*|--stdio=*) REM=O$(echo X$1 | sed 's,[^=]*=,,') ;; --u|--un|--und|--unde|--undef) REM=u ;; --v|--ve|--ver|--verb|--verbo|--verbos|--verbose) REM=v ;; --*) echo $command: $1: unknown option >&2 exit 2 ;; -*) REM=$(echo X$1 | sed 's,X-,,') ;; *) break ;; esac shift while : do case $REM in '') break ;; esac eval $(echo $REM | sed "s,\(.\)\(.*\),OPT='\1' REM='\2',") case $OPT in [cdFiILoOePsSxX]) case $REM in '') case $# in 0) echo $command: -$OPT: option argument expected >&2 exit 1 ;; esac OPTARG=$1 shift ;; *) OPTARG=$REM REM='' ;; esac esac case $OPT in a) set="$set set all :" ;; c) set="$set set cc $OPTARG :" ;; C) set="$set set config :" ;; d) set="$set set debug $OPTARG :" ;; D) set="$set set define :" ;; E) set="$set set explicit :" ;; F) set="$set set features $OPTARG :" ;; i) set="$set set input $OPTARG :" ;; I) set="$set set include $OPTARG :" ;; L) set="$set set library $OPTARG :" ;; n) set="$set set namval $OPTARG :" ;; N) set="$set set nooptimize $OPTARG :" ;; o) set="$set set output $OPTARG :" ;; e) ;; # obsolete p) ;; # obsolete P) set="$set set pragma $OPTARG :" ;; r) set="$set set regress :" ;; s) set="$set set shell $OPTARG :" ;; S) set="$set set static $OPTARG :" ;; O) set="$set set stdio $OPTARG :" ;; u) set="$set set undef :" ;; v) set="$set set verbose :" ;; x) set="$set set cross $OPTARG :" ;; X) set="$set set exclude $OPTARG :" ;; *) echo "Usage: $command [-aCDEnpruv] [-c C-compiler-name [C-compiler-flags ...]] [-d level] [-F features-header] [-i file] [-o file] [-O stdio-header] [-e name] [-P text] [-s shell-path] [-S[flags]] [-x cross-exec-prefix] [-I dir] [-L dir] [-X dir] [ - ] [ file.iffe | statement [ : statement ... ] ]" >&2 exit 2 ;; esac done done ;; esac case $1 in -) out=-; shift ;; esac case $# in 0) in=- ;; esac set -- $set "$@" case " $* " in *' set config '*|*' run config.'*|*' run '*' config.'*|*' run '*'/config.'*) config=1 ;; esac # standard error to /dev/null unless debugging # standard output to the current output file # # stdout original standard output # stderr original standard error # nullin /dev/null input # nullout /dev/null output stdout=5 stderr=6 nullin=7 nullout=8 eval "exec $nullin/dev/null $stdout>&1 $stderr>&2" case " $* " in *" set debug "[3456789]*) ;; *) eval "exec 2>&$nullout" ;; esac # If the arguments contain a *.iffe script argument or a command of the form # run [ ] # then check if there are up-to-date results; the output file must be newer # than the script file and, if the input file is given, newer than it as well. # # We check for this early by doing a dedicated scan for a 'run' command in # the positional parameters, otherwise iffe will still run preliminary tests # before determining and opening the output file. The ( subshell ) allows # us to scan the PPs destructively, which makes life easier. ( case $1 in -) # write to stdout: no check exit 1 ;; *.iffe | *.iff) set run "$@" ;; *) # discard PPs until we find a 'run' command while test "$#" -gt 0 && test "$1" != "run" do while test "$#" -gt 0 && test "$1" != ":" do shift done shift done ;; esac test "$#" -ge 2 || exit 1 # convert script path to output path o=${2##*[\\/]} # rm base dir o=$dir/${o%.*} # prefix dest dir, rm extension # check if the results are newer than the test script test -f "$o" && test -f "$2" && test "$o" -nt "$2" && { test "$#" -lt 3 || test "$3" = ":" || { test -f "$3" && test "$o" -nt "$3" } } || exit 1 echo "$command: test results in $o are up to date" >&$stderr # update timestamp for correct dependency resolution in mamake touch "$o" || kill "$$" ) && exit 0 # tmp files cleaned up on exit # status: 0:success 1:failure 2:interrupt status=1 case $debug in 2) core= ;; *) if (ulimit -c 0) >/dev/null 2>&1 then ulimit -c 0 core= else core="core core.??*" fi ;; esac trap "(set +o noglob; exec rm -f $core $tmp*)" 0 if (:>$tmp.c) 2>/dev/null then rm -f $tmp.c else echo "$command: cannot create tmp files in current dir" >&2 exit 1 fi status=2 # standard header for c source std='/* AST backward compatibility macros */ #define _NIL_(x) NULL #define _STD_ 1 #define _ARG_(x) x #define _VOID_ void #define _BEGIN_EXTERNS_ #define _END_EXTERNS_' # To ensure the environment tested is the same as that used, add standards # compliance macros as probed by libast as soon as they are available. if test -f "${INSTALLROOT}/src/lib/libast/${dir}/standards" then std=${std}${nl}$(cat "${INSTALLROOT}/src/lib/libast/${dir}/standards") fi tst= ext="#include " # loop on op [ arg [ ... ] ] [ : op [ arg [ ... ] ] ] argx=0 cur=. can= cansep= cctest= file= hdrtest= ifelse=NONE ifstack= ini= init=1 line=0 nan= while : do case $in in "") case $argx:$* in 1:$argv);; 1:*) argx=0 set x $argv shift ;; esac ;; *) case $ini in '') if read lin then line=$((line+1)) set x $lin case $# in 1) continue ;; esac else set x fi ;; *) set x $ini ini= ;; esac shift case $init in 1) case $1 in iff) init=0 ;; print|ref|set) ;; *) init=0 ini=$* set ini ;; esac esac ;; esac case $# in 0) case $ifstack in ?*) echo "$command: $file$line: missing endif" >&$stderr exit 1 ;; esac set set out + ;; esac # if nesting while : do case $1 in "if") ifstack="$ifelse:$ifstack" case $ifelse in KEEP|NONE) ifelse=TEST ;; TEST) ;; *) ifelse=DONE ;; esac shift case $explicit in 1) set '' - "$@"; shift ;; esac ;; "elif") case $ifelse in SKIP) ifelse=TEST ;; TEST) ;; *) ifelse=DONE ;; NONE) echo "$command: $file$line: $1: no matching if" >&$stderr exit 1 ;; esac shift case $explicit in 1) set '' - "$@"; shift ;; esac ;; "else") case $ifelse in KEEP) ifelse=DONE ;; SKIP|TEST) ifelse=KEEP ;; NONE) echo "$command: $file$line: $1: no matching if" >&$stderr exit 1 ;; esac shift ;; "endif")case $ifelse in NONE) echo "$command: $file$line: $1: no matching if" >&$stderr exit 1 ;; esac ifelse=${ifstack%%:*} ifstack=${ifstack#*:} shift ;; *) break ;; esac done # check if "run xxx" is equivalent to "set in xxx" case $1 in "("*) set exp - "$@" ;; *.iffe|*.iff) set run "$@" ;; esac case $1 in :) shift continue ;; run) case ${2##*[\\/]} in *.iffe|*.iff) set set in $2 ;; *.*) ;; *) set set in $2 ;; esac ;; esac # { inc set } drop out early case $1 in ""|"#"*)continue ;; inc) case $ifelse in DONE|SKIP) set ''; shift; continue ;; esac shift case $# in 0) echo "$command: $file$line: path expected" >&$stderr exit 1 ;; esac p=$1 shift if test ! -f $p then echo "$command: $file$line: $p: file not found" >&$stderr exit 1 fi case $# in 0) case $config in 1) e="^HAVE_" ;; *) e="^_" ;; esac ;; 1) e=$1 ;; *) shift echo "$command: $file$line: warning: $*: operands ignored" >&$stderr ;; esac eval $(sed -e '/^#define[ ]/!d' -e 's/#define[ ]//' -e 's/[ (].*//' ${e:+"-e/$e/!d"} -e 's/.*/&=1/' $p | LC_ALL=C sort -u) continue ;; set) case $ifelse in DONE|SKIP) set ''; shift; continue ;; esac shift case $1 in ""|"#"*)op= ;; *) arg= op=$1 case $op in --*) op=${op#--} ;; -*) case $op in -??*) arg=${op#-?} op=${op%$arg} ;; esac case $op in a) op=all ;; c) op=cc ;; C) op=config ;; d) op=debug ;; D) op=define ;; E) op=explicit ;; F) op=features ;; i) op=input ;; I) op=include ;; L) op=library ;; n) op=namval ;; N) op=nooptimize ;; o) op=output ;; e) ;; # obsolete p) ;; # obsolete P) op=pragma ;; r) op=regress ;; s) op=shell ;; S) op=static ;; O) op=stdio ;; u) op=undef ;; v) op=verbose ;; x) op=cross ;; X) op=exclude ;; esac ;; esac shift while : do case $# in 0) break ;; esac case $1 in *" "*) shift continue ;; ""|"#"*)break ;; :) shift break ;; esac case $arg in "") arg=$1 ;; *) arg="$arg $1" ;; esac shift done ;; esac case $op in all) all=1 continue ;; cc) occ= for x in $arg do case $occ in "") case $x in *=*) export "$x" ;; -O*) case $optimize in 1) occ=$x ;; esac ;; *) occ=$x ;; esac ;; *) occ="$occ $x" ;; esac done exclude occ continue ;; config) config=1 continue ;; cross) case $arg in ""|-) cross= ;; *) cross="$arg" libpaths= ;; esac continue ;; debug) debug=$arg case $arg in 0) exec 2>&$nullout set +v +x ;; ""|1) exec 2>&$stderr set +v +x ;; 2|3) exec 2>&$stderr # Useful shell-dependent PS4 trace prompts from modernish. # The ${foo#{foo%/*/*}/} substitutions below are to trace just the last two # elements of path names, instead of the full paths which can be very long. case ${ZSH_VERSION:+Zsh}${NETBSD_SHELL:+Netsh}${KSH_VERSION:+Ksh}${BASH_VERSION:+Bash} in Zsh) typeset -F SECONDS PS4='+ [${SECONDS:+${SECONDS%????}s|}${ZSH_SUBSHELL:+S$ZSH_SUBSHELL,}${funcfiletrace:+${funcfiletrace#${funcfiletrace%/*/*}/},}${funcstack:+${funcstack#${funcstack%/*/*}/},}${LINENO:+L$LINENO,}e$?] ' ;; Netsh) PS4='+ [${ToD:+$ToD|}${LINENO:+L$LINENO,}e$?] ' ;; Ksh) case $KSH_VERSION in 'Version '*) typeset -F SECONDS PS4='+ [${SECONDS:+${SECONDS%????}s|}${.sh.pid:+P${.sh.pid},}${.sh.subshell:+S${.sh.subshell},}${.sh.file:+${.sh.file#${.sh.file%/*/*}/},}${.sh.fun:+${.sh.fun},}${LINENO:+L$LINENO,}e$?] ' ;; @\(*) PS4='+ [${EPOCHREALTIME:+${EPOCHREALTIME#???????}s|}${BASHPID:+P$BASHPID,}${LINENO:+L$LINENO,}e$?] ' ;; esac ;; Bash) case ${EPOCHREALTIME:+s} in s) PS4='+ [${EPOCHREALTIME:+${EPOCHREALTIME#???????}s|}' ;; '') PS4='+ [${SECONDS:+${SECONDS}s|}' ;; esac PS4=$PS4'${BASHPID:+P$BASHPID,}${BASH_SOURCE:+${BASH_SOURCE#${BASH_SOURCE%/*/*}/},}${FUNCNAME:+$FUNCNAME,}${LINENO:+L$LINENO,}e$?] ' ;; '') case ${SECONDS:+s} in s) PS4='+ [${SECONDS:+${SECONDS}s|}${LINENO:+L$LINENO,}e$?] ' ;; '') PS4='+ [${LINENO:+L$LINENO,}e$?] ' ;; esac ;; esac set -x ;; *) echo "$command: $arg: debug levels are 0, 1, 2, 3" >&$stderr ;; esac continue ;; define) define=1 continue ;; exclude)case $arg in ""|-) excludes= ;; *) excludes="$excludes $arg" ;; esac exclude includes occ continue ;; explicit) explicit=1 continue ;; features)case $arg in '') tst= ;; *) tst="#include \"$arg\"" ;; esac continue ;; "in"|input) case $arg in "") in=- ;; *) in=$arg if test ! -r $in then echo "$command: $in: not found" >&$stderr exit 1 fi exec < $in file=$in: case $out in "") case $in in *[.\\/]*) out=${in##*[\\/]} out=${out%.*} ;; *) out=$in ;; esac ;; esac ;; esac continue ;; include)case $arg in ""|-) includes= ;; *) includes="$includes -I$arg" ;; esac exclude includes continue ;; library)for y in $libpaths do eval $y=\"\$$y:\$arg\$${y}_default\" eval export $y done continue ;; namval) define=n continue ;; nodebug)exec 2>&$nullout set +v +x continue ;; nodefine) define=0 continue ;; nooptimize) optimize=0 case $occ in *" -O"*)occ=$(echo $occ | sed 's/ -O[^ ]*//g') cc=$occ ;; esac ;; optimize) optimize=1 ;; out|output) out=$arg defhdr= usr= deflib= one= puthdr= putlib= case $op in output) continue ;; esac def= test= ;; package)# obsolete continue ;; prototyped|noprototyped) # obsolete continue ;; pragma) pragma="$pragma $arg" continue ;; regress)regress=1 version=1995-03-19 continue ;; shell) shell=$arg continue ;; static) static=$arg continue ;; stdio) case $arg in '') ext= ;; *) ext= sep= for i in $arg do case $i in -) case $ext in '') continue ;; *) break ;; esac ;; esac echo "#include \"$i\"" > t.c if $cc -E t.c > /dev/null 2>&1 then ext="$ext$sep#include \"$arg\"" sep=$nl fi done ;; esac continue ;; undef) undef=1 continue ;; verbose)verbose=1 continue ;; *) echo "$command: $op: unknown option" >&$stderr exit 1 ;; esac ;; api|define|extern|header|include|print|reference|ver) op=$1 shift arg= ;; *) case $2 in '=') def=$1 shift shift ;; *) case $1 in '-'|'?')def=- shift ;; *) def= ;; esac ;; esac case $1 in '!') not=1 shift ;; *) not= ;; esac case $1 in *'{') op=- ;; '('*|'"'*'"'|'<'*'>') op=exp case $def in '') def=- ;; esac ;; *) op=$1 shift ;; esac arg= cc="$occ $includes" group= groups= fail= hdr= lib= mac= no= note= opt= pass= pth= run= set= src= test= yes= case $# in 0) ;; *) case $1 in "#"*) set x shift ;; *) case $op in ref) ;; *) case $1 in '-') case $op:$2 in tst:*) arg=$1 case $2 in -) shift ;; esac ;; *:-*) arg=$1 shift ;; *) def=- shift case $1 in '('*|*'{'|'"'*'"'|'<'*'>') arg=- ;; *) arg=$1 case $# in 0) ;; *) shift ;; esac ;; esac ;; esac ;; -*|+*|'('*|*'{'|'"'*'"'|'<'*'>') arg=- ;; *) arg=$1 shift ;; esac ;; esac ;; esac case $1 in '('*|'"'*'"'|'<'*'>') while : do case $# in 0) break ;; esac case $1 in *[.{}]*)break ;; esac case $test in '') test=$1 ;; *) test="$test $1" ;; esac shift done case $arg in '') arg=- ;; esac case $op in exp) case $def in ''|'-') ;; *) arg=$def ;; esac ;; esac ;; esac sline=$line while : do case $# in 0) break ;; esac case $1 in "") ;; "#"*) set x ;; "=") shift set=$* case $set in "") set=" " ;; esac while : do case $# in 0) break ;; esac shift done break ;; [abcdefghijklmnopqrstuvwxyz]*'{'|'{') v=$1 shift x= case $v in "note{") sep=" " ;; *) sep=$nl ;; esac case $v in '{') e='}' ;; *) e='}end' ;; esac n=1 SEP= while : do case $# in 0) case $in in "") echo "$command: $file$line: missing }end" >&$stderr exit 1 ;; esac while : do IFS= read -r lin eof=$? while : do lin="${lin#[' ']}" case $lin in [' ']*'#'*);; *) break ;; esac done case $eof in 0) line=$((line+1)) set x $lin case $2 in $v) n=$((n+1)) ;; $e|$e';') case $n in 1) shift break 2 ;; esac n=$((n-1)) ;; esac x="$x$SEP$lin" SEP=$sep ;; *) echo "$command: $file$line: missing $e" >&$stderr exit 1 ;; esac done ;; esac case $1 in $v) n=$((n+1)) ;; $e|$e';') case $n in 1) break ;; esac n=$((n-1)) ;; esac x="$x$SEP$1" SEP=$sep shift done case $v in 'note{');; *) x="$x$nl" # \r\n bash needs this barf # ;; esac case $v in 'fail{') fail=$x ;; 'nofail{') pass=$x v='pass{' ;; 'nopass{') fail=$x v='fail{' ;; 'no{') no=$x ;; 'note{') note=$x ;; 'pass{') pass=$x ;; 'test{') test=$x ;; 'yes{'|'{') yes=$x ;; *) src=$x run=$v ;; esac ;; :) shift break ;; *[\"\'\(\)\{\}\ \ ]*) case $op in pth) pth="$pth $1" ;; *) case $test in '') test=$1 ;; *) test="$test $1" ;; esac ;; esac ;; -) group=$group$1 case $group in -) com_hdr=$hdr com_lib=$lib com_mac=$mac com_opt=$opt com_pth=$pth com_test=$test ;; *) groups="$groups $1" ;; esac ;; -l*) case $group in --*) groups="$groups $1" ;; *) lib="$lib $1" ;; esac ;; +l*) x=-${1#+} case $group in --*) groups="$groups $x" ;; *) lib="$lib $x" ;; esac ;; -*|+*) case $op in ref) cc="$cc $1" occ="$occ $1" case $1 in -L*) x=${1#-L} for y in $libpaths do eval $y=\"\$$y:\$x\$${y}_default\" eval export $y done ;; esac ;; *) case $group in --*) groups="$groups $1" ;; *) case $op in run) opt="$opt $1" ;; *) case $1 in -D*) mac="$mac $1" ;; *) cc="$cc $1" ;; esac ;; esac ;; esac ;; esac ;; *.[aAxX]|*.[dD][lL][lL]|*.[lL][iI][bB]) case $group in --*) groups="$groups $1" ;; *) lib="$lib $1" ;; esac ;; *[.\\/]*) case $group in --*) groups="$groups $1" ;; *) case $op in pth) pth="$pth $1" ;; *) hdr="$hdr $1" ;; esac ;; esac ;; *) case $group in --*) groups="$groups $1" ;; *) case $op in pth) pth="$pth $1" ;; *) case $test in '') test=$1 ;; *) test="$test $1" ;; esac ;; esac ;; esac ;; esac shift done case $group in -) group= ;; esac ;; esac ;; esac case $ifelse in DONE|SKIP) continue ;; esac # make sure $cc compiles C case $cc in "") cc="$occ $includes" ;; esac case $cctest in "") checkcc ;; esac # some ops allow no args case $arg in '') case $op in api) arg=- case $1:$2 in [abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]*:[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]) a=$1 shift case " $apis " in *" $a "*) ;; *) apis="$apis $a" eval api_sym_${a}= api_ver_${a}= ;; esac rel= while : do case $# in 0) break ;; esac case $1 in [0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]) rel="$rel $1" ;; *) break ;; esac shift done while : do case $# in 0) break ;; esac case $1 in :) break ;; esac eval syms='$'api_sym_${a} case $syms in '') sep='' ;; *) sep=$nl ;; esac for r in $rel do syms=$syms$sep${1}:${r} sep=$nl done eval api_sym_${a}='$'syms shift done ;; *) echo "$command: $op: expected: name YYYYMMDD symbol ..." >&$stderr ;; esac while : do case $# in 0) break ;; esac case $1 in :) break ;; esac shift done ;; iff|ini)arg=- ;; comment)copy - "/* $* */" continue ;; define) x=$1 shift case $1 in '('*')') arg=$1 shift ;; esac case $in in "") v= while : do case $# in 0) break ;; esac t=$1 shift case $t in ":") break ;; esac v="$v $t" done ;; *) v=$* ;; esac is mac $x copy $tmp.c "$std $usr #ifndef $x ( #endif int x; " if compile $cc -c $tmp.c <&$nullin >&$nullout then success - else failure - copy - "#define $x$arg $v" usr="$usr${nl}#define $x$arg $v" fi continue ;; extern) x=$1 shift t=$1 shift is npt $x copy $tmp.c "$std #include $usr struct _iffe_struct { int _iffe_member; }; extern struct _iffe_struct* $x (struct _iffe_struct*); " # some compilers with -O only warn for invalid intrinsic prototypes case " $cc " in *" -O "*) xx=$(echo $cc | sed 's/ -O / /g') ;; *) xx=$cc ;; esac if compile $xx -c $tmp.c <&$nullin >&$nullout then success - while : do case $1 in ''|'('*|'['*) break ;; esac t="$t $1" shift done case $in in "") v= while : do case $# in 0) break ;; esac t=$1 shift case $t in ":") break ;; esac v="$v $t" done ;; *) v=$* ;; esac copy - "extern $t $x$v;" usr="$usr${nl}extern $t $x$v;" else failure - case $in in "") while : do case $# in 0) break ;; esac case $1 in ":") break ;; esac done ;; esac fi continue ;; header|include|reference) while : do case $# in 0) break ;; esac x=$1 shift case $x in ":") break ;; esac case " $gothdr " in *" - $x "*) ;; *" + $x "*) case $usr in *"# include <"$x">"*) ;; *) case $op in reference) ;; *) copy - "#include <$x>" ;; esac usr="$usr${nl}#include <$x>" ;; esac ;; *) copy $tmp.c "$std $usr #include <$x> int x; " if is_hdr - $x then gothdr="$gothdr + $x" case $op in reference) ;; *) copy - "#include <$x>" ;; esac usr="$usr${nl}#include <$x>" else gothdr="$gothdr - $x" fi ;; esac done continue ;; print) case $in in "") v= while : do case $# in 0) break ;; esac t=$1 shift case $t in ":") break ;; esac v="$v $t" done ;; *) v=$* ;; esac copy - "$*" usr="$usr${nl}$v" continue ;; ver) arg=- case $1:$2 in [abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]*:[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]) vers="$vers$nl$1" eval ver_$1=$2 ;; *) echo "$command: $op: expected: name YYYYMMDD" >&$stderr ;; esac while : do case $# in 0) break ;; esac case $1 in :) break ;; esac shift done ;; esac ;; esac # NOTE() support case $ext in *""*) case $ext in *"#define NOTE("*) ;; *) ext="$ext #define NOTE(s) do{write(9,\" \",1);write(9,s,strlen(s));write(9,\" ...\",4);}while(0)" ;; esac ;; esac # save $* for ancient shells argx=1 argv=$* # loop on all candidate groups while : do # check the candidate macros cc="$cc $mac" # check for global default headers (some cc -E insist on compiling) case $hdrtest in '') hdrtest=1 allinc= for x in types do case $config in 0) c=_sys_${x} ;; 1) case $shell in ksh) typeset -u u=$x ;; *) u=$(echo $x | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ) ;; esac c=HAVE_SYS_${u}_H ;; esac x=sys/$x.h echo "${allinc}#include <$x>" > $tmp.c if is_hdr $x then gothdr="$gothdr + $x" case $explicit in 0) can="$can$cansep#define $c 1 /* #include <$x> ok */" nan="$nan$cansep$c=1" cansep=$nl ;; esac eval $c=1 allinc="${allinc}#include <$x>$nl" else gothdr="$gothdr - $x" case $explicit$all$config$undef in 0?1?|0??1) can="$can$cansep#undef $c /* #include <$x> not ok */" nan="$nan$cansep$c=" cansep=$nl ;; 01??) can="$can$cansep#define $c 0 /* #include <$x> not ok */" nan="$nan$cansep$c=0" cansep=$nl ;; esac fi done ;; esac # add implicit headers/libraries before the checks case $op in npt) hdr="sys/types.h stdlib.h unistd.h $hdr" ;; siz|typ)hdr="sys/types.h time.h sys/time.h sys/times.h stddef.h stdlib.h $hdr" ;; esac # check the candidate headers case $hdr in ?*) z=$hdr hdr= dis=0 for x in $z do case $x in *.h) case " $gothdr " in *" - $x "*) continue ;; *" + $x "*) ;; *) c=${x##*[\\/]} c=${c%%.*} case $x in */*) c=${x%%[\\/]*}_${c} ;; esac case $explicit in 0) dis=0 ;; *) case $x in */*) dis=$c ;; *) dis=hdr ;; esac case ${dis}_ in ${op}_*)dis=0 ;; *) dis=1 ;; esac ;; esac case $config in 0) case $x in */*) c=_${c} ;; *) c=_hdr_${c} ;; esac ;; 1) case $shell in ksh) typeset -u u=$c ;; *) u=$(echo $c | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ) ;; esac c=HAVE_${u}_H ;; esac echo "${allinc}#include <$x>" > $tmp.c if is_hdr $x then gothdr="$gothdr + $x" case $dis in 0) can="$can$cansep#define $c 1 /* #include <$x> ok */" nan="$nan$cansep$c=1" cansep=$nl ;; esac eval $c=1 else gothdr="$gothdr - $x" case $dis$all$config$undef in 0?1?|0??1) can="$can$cansep#undef $c /* #include <$x> not ok */" nan="$nan$cansep$c=" cansep=$nl ;; 01??) can="$can$cansep#define $c 0 /* #include <$x> not ok */" nan="$nan$cansep$c=0" cansep=$nl ;; esac continue fi ;; esac ;; *) test -r $x || continue ;; esac hdr="$hdr $x" done ;; esac # check the candidate libraries case $lib in ?*) z= for p in $lib do z="$p $z" done lib= p= hit=0 echo "int main(void){return(0);}" > $tmp.c for x in $z do p=$x case " $gotlib " in *"- $p "*) failure + p= ;; *"+ $p "*) success + lib="$p $lib" ;; *) rm -f $tmp.exe is LIB $p if compile $cc -o $tmp.exe $tmp.c $p $lib <&$nullin >&$nullout then success gotlib="$gotlib + $p" lib="$p $lib" e=0 else a= e=1 for l in $z do case $l in -) a= continue ;; $p) a=$p continue ;; *) case $gotlib in *" $l "*) continue ;; esac ;; esac case $a in $p) a="$a $l" if compile $cc -o $tmp.exe $tmp.c $a <&$nullin >&$nullout then success gotlib="$gotlib + $p" lib="$p $lib" e=0 break fi ;; esac done case $e in 1) failure gotlib="$gotlib - $p" ;; esac fi y= for x in $p do c=${x#-l} case $c in *[!abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_]*) c=$(echo '' $c | sed -e 's,.*[\\/],,' -e 's,\.[^.]*$,,' -e 's,[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_],_,g' -e '/^lib./s,^lib,,') ;; esac case $config in 0) case $e$p in 0*' '*) case " $gotlib " in *[-+]" $x "*) ;; *) can="$can$cansep#define _LIB_$c 1 /* $x is a library */" nan="$nan${cansep}_LIB_$c=1" cansep=$nl eval _LIB_$c=1 ;; esac ;; esac ;; 1) case $shell in ksh) typeset -u u=$c ;; *) u=$(echo $c | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ) ;; esac c=$u case $e in 0*' '*) case " $gotlib " in *[-+]" $x "*) ;; *) can="$can$cansep#define HAVE_${c}_LIB 1 /* $x is a library */" nan="$nan${cansep}HAVE_${c}_LIB=1" cansep=$nl eval HAVE_${c}_LIB=1 ;; esac ;; esac ;; esac y=${y}_$c done case $config in 0) c=_LIB${y} ;; 1) c=HAVE${y}_LIB ;; esac case $p in *' '*) q="a library group" ;; *) q="a library" ;; esac case $e in 0) can="$can$cansep#define $c 1 /* $p is $q */" nan="$nan$cansep$c=1" cansep=$nl eval $c=1 case $hit in 1) break ;; esac ;; 1) case $all$config$undef in ?1?|??1)can="$can$cansep#undef $c /* $p is not $q */" nan="$nan$cansep$c=" cansep=$nl ;; 1??) can="$can$cansep#define $c 0 /* $p is not $q */" nan="$nan$cansep$c=0" cansep=$nl ;; esac eval $c=0 ;; esac p= ;; esac done ;; esac # last op precheck case $op in ref) deflib="$deflib $lib" defhdr="$defhdr $hdr" break ;; esac IFS=" ," eval op=\"$op\" eval arg=\"$arg\" IFS=$ifs # check for op aliases x= for o in $op do case $o in def|default) x="$x cmd dat hdr key lib mth sys typ" ;; *) x="$x $o" ;; esac done # loop on the ops o and args a result=UNKNOWN for o in $x do for a in $arg do c= case $a in *[.\\/]*) case $o in hdr|lcl|nxt|pth|sys) x=$a case $x in *.lcl|*.nxt) case $o in sys) x=sys/$x ;; esac o=${x##*.} x=${x%.${o}} v=$x ;; esac case $x in *[\\/]*) p=${x%/*} v=${x##*/} ;; *.*) p=${x%.*} v=${x##*.} ;; *) p= ;; esac case $o in lcl|nxt) c=$v.$o ;; *) c=$v ;; esac ;; *) p=${a%.*} p=${p##*[\\/]} v=${a##*.} v=${v##*[\\/]} ;; esac case $p in '') f=${v} ;; *) f=${p}/${v} ;; esac case $o in run) v=$p p= m=_${v} ;; mem) case $p in *.*) m=${p#*.} p=${p%%.*} v=${m}.${v} esac case $config in 0) m=_${v}_${p} ;; 1) m=_${v}_in_${p} ;; esac ;; *) case $p in '') m=_${v} ;; *) m=_${p}_${v} ;; esac ;; esac ;; *) p= v=$a f=$a m=_${v} ;; esac case $c in '') c=$v ;; esac M=$m case $o in out) case $a in -) a=- ;; ?*) test="$a $test" a= ;; esac ;; *) case " $idyes " in *" $m "*) i=1 ;; *) case " $idno " in *" $m "*) i=0 ;; *) case $m in *'*') m=$(echo "$m" | sed 's,\*,_ptr,g') ;; esac case $m in *[-+/\\]*) i=0 ;; *[!abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_]*) is id $m copy $tmp.c "int $m = 0;" if compile $cc -c $tmp.c then success - idyes="$idyes $m" i=1 else failure - idno="$idno $m" i=0 fi ;; *) i=1 ;; esac ;; esac case $i in 0) case $o in dat|dfn|key|lib|mac|mth|nos|npt|siz|sym|typ|val) continue ;; esac ;; esac ;; esac ;; esac case $m in *[!abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_]*) m=$(echo "X$m" | sed -e 's,^.,,' -e 's,[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_],_,g') ;; esac # check output redirection case $out in $cur) ;; *) case $cur in $a|$c) ;; *) case $cur in .) ;; *) case $vers in ?*) echo for api in $vers do API=$(echo $api | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ) eval ver='${'ver_${api}'}' echo "#define ${API}_VERSION ${ver}" done esac case $apis in ?*) for api in $apis do API=$(echo $api | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ) echo "#define ${API}API(rel) ( _BLD_${api} || !_API_${api} || _API_${api} >= rel )" map= sep= eval syms='"${'api_sym_${api}'}"' # old Solaris requires -k # set x x $(echo "$syms" | sort -t: -u -k 1,1 -k 2,2nr 2>/dev/null | sed 's/:/ /') case $# in 2) # ancient sort doesn't have -k # set x x $(echo "$syms" | sort -t: -u +0 -1 +1 -2nr 2>/dev/null | sed 's/:/ /') ;; esac sym= while : do shift 2 case $# in [01]) break ;; esac prv=$sym sym=$1 rel=$2 case $prv in $sym) echo "#elif _API_${api} >= $rel" ;; *) case $prv in '') echo echo "#if !defined(_API_${api}) && defined(_API_DEFAULT)" echo "#define _API_${api} _API_DEFAULT" echo "#endif" ;; *) echo "#endif" ;; esac echo echo "#if ${API}API($rel)" ;; esac echo "#undef ${sym}" echo "#define ${sym} ${sym}_${rel}" map=$map$sep${sym}_${rel} sep=' ' done echo "#endif" echo echo "#define _API_${api}_MAP \"$map\"" done echo ;; esac case $iff in ?*) echo "#endif" ;; esac case $cur in -) ;; *) exec >/dev/null case $cur in *[\\/]*|*.h) x=$cur ;; *) x=$dir/$cur ;; esac case $define in n) sed '/^#/d' $tmp.h > $tmp.c sed '/^#/d' $x > $tmp.t ;; *) sed 's,/\*[^/]*\*/, ,g' $tmp.h > $tmp.c sed 's,/\*[^/]*\*/, ,g' $x > $tmp.t ;; esac if cmp -s $tmp.c $tmp.t then rm -f $tmp.h case $verbose in 1) echo "$command: $x: unchanged;" \ "updating timestamp" >&$stderr ;; esac touch "$x" # needed for mamake dependency tree integrity else case $x in ${dir}[\\/]$cur) test -d $dir || mkdir $dir || exit 1 ;; esac mv $tmp.h $x fi ;; esac ;; esac case $out in +) case $status in 1) ;; *) status=0 ;; esac exit $status ;; -) eval "exec >&$stdout" ;; *) exec >$tmp.h ;; esac case $out in "") case $a in *[\\/]*|???????????????*) cur=$c ;; *) cur=$a ;; esac ;; *) cur=$out ;; esac case $in in ""|-|+) case $o in run) x=" from $a" ;; *) x= ;; esac ;; *) x=" from $in" ;; esac # output header comments case $define in n) ;; ?) echo "/* : : generated$x by $command version $version : : */" for x in $pragma do echo "#pragma $x" done case $out in ""|-|+) x=$m ;; *.*) i=$out x=_ while : do case $i in *.*) x=$x${i%%.*}_ i=${i#*.} ;; *) x=$x$i break ;; esac done ;; *) x=_$out ;; esac case $o in iff) case $M in ""|*-*) ;; *) iff=${m}_H ;; esac ;; *) case $regress in '') case $x in *-*) ;; *) x=$(pwd | sed -e 's,.*[\\/],,' -e 's,\..*,,' -e 's,^lib,,' -e 's,^,'${x}_',' -e 's,[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_],_,g') # ksh n+ bug workaround case $x in *[!_]*) ;; *) x=_$$ ;; esac iff=_def${x} ;; esac ;; *) case $x in *-*) ;; *) iff=_REGRESS ;; esac ;; esac ;; esac case $iff in ?*) echo "#ifndef $iff" echo "#define $iff 1" ;; esac ;; esac ;; esac ;; esac case $can in ?*) case $define in 1) echo "$can" ;; n) echo "$nan" ;; esac can= nan= cansep= ;; esac # set up the candidate include list pre= inc= for x in $defhdr - $hdr do case $x in -) case $pre in ?*) continue ;; esac case $v in *.*) for x in $(echo $v | sed 's,\., ,g') do pre="$pre$nl#undef $x" done ;; *) case $o in siz|typ)case $v in char|short|int|long) ;; *) pre="#undef $v" ;; esac ;; *) pre="#undef $v" ;; esac ;; esac ;; *.h) c=${x##*[\\/]} c=${c%%.*} case $x in */*) c=${x%%[\\/]*}_${c} ;; esac case $config in 0) case $x in */*) c=_${c} ;; *) c=_hdr_${c} ;; esac ;; 1) case $shell in ksh) typeset -u u=$c ;; *) u=$(echo "$c" | LC_ALL=C tr a-z A-Z) ;; esac c=HAVE_${u}_H ;; esac case " $puthdr " in *" $c "*) ;; *) puthdr="$puthdr $c" usr="$usr$nl#define $c 1" ;; esac inc="$inc$nl#include <$x>" ;; esac done # set up the candidate lib list for x in $lib $deflib do c=${x#-l} case $c in *[!abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_]*) c=$(echo '' $c | sed -e 's,.*[\\/],,' -e 's,\.[^.]*$,,' -e 's,[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_],_,g' -e '/^lib./s,^lib,,') ;; esac case $config in 0) c=_LIB_${c} ;; 1) case $shell in ksh) typeset -u u=$c ;; *) u=$(echo $c | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ) ;; esac c=HAVE_${u}_LIB ;; esac case " $putlib " in *" $c "*) ;; *) putlib="$putlib $c" usr="$usr$nl#define $c 1" ;; esac done # src overrides builtin test case $config:$def in 0:) case $o in tst|var);; *) m=_${o}${m} ;; esac ;; 1:) case $o in tst|var)m=${v} ;; esac case $shell in ksh) typeset -u u=$m ;; *) u=$(echo $m | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ) ;; esac case $o in tst|var)case $m in $u) ;; *) case $m in hdr_*|lib_*|sys_*) u=${u#????} ;; esac m=HAVE_${u} ;; esac ;; dat) m=HAVE${u}_DATA ;; hdr|lcl)m=HAVE${u}_H ;; key) m=HAVE${u}_RESERVED ;; mth) m=HAVE${u}_MATH ;; npt) m=HAVE${u}_DECL ;; pth) m=${u}_PATH m=${m#_} ;; nxt) m=HAVE${u}_NEXT ;; siz) m=SIZEOF${u} ;; sys) m=HAVE_SYS${u}_H ;; *) m=HAVE${u} ;; esac ;; *) m=$def M=$m ;; esac case $src in ?*) case $src in *[\<\"][Ss][Tt][Dd][Ii][Oo].[Hh][\"\>]* | *\* | *\* | */[*]\[*]/*) EXT= ;; *) EXT="$tst $ext" ;; esac copy $tmp.c "$std $EXT $usr $inc $src " V=1 e=0 is tst "${note:-$run}" case $run in cat*|nocat*) copy - "$src" ;; cross*|nocross*) copy $tmp.sh "$src" chmod +x $tmp.sh execute $tmp.sh <&$nullin || e=1 ;; run*|norun*) (eval "$src") <&$nullin || e=1 ;; mac*|nomac*) if compile $cc -E -P $tmp.c <&$nullin >$tmp.i then sed -e '/<<[ ]*".*"[ ]*>>/!d' -e 's/<<[ ]*"//g' -e 's/"[ ]*>>//g' $tmp.i else e=1 fi ;; p*|nop*)compile $cc -DTEST=$p -DID=$v -E $tmp.c <&$nullin >&$nullout || e=1 ;; c*|noc*)compile $cc -DTEST=$p -DID=$v -c $tmp.c <&$nullin >&$nullout || e=1 ;; *) case $run in status*)ccflags= ;; s*|nos*)case $reallystatictest in '') #UNDENT... reallystatictest=. echo "$tst$nl$ext${nl}int main(void){printf("hello");return(0);}" > ${tmp}s.c rm -f ${tmp}s.exe if compile $cc -c ${tmp}s.c <&$nullin >&$nullout && compile $cc -o ${tmp}s.exe ${tmp}s.o <&$nullin >&$nullout 2>${tmp}s.e && $executable ${tmp}s.exe then e=$(wc -l ${tmp}s.e) eval set x x $binding while : do shift shift case $# in 0) break ;; esac rm -f ${tmp}s.exe compile $cc -o ${tmp}s.exe $1 ${tmp}s.o <&$nullin >&$nullout 2>${tmp}s.e && $executable ${tmp}s.exe || continue case $(wc -l ${tmp}s.e) in $e) ;; *) continue ;; esac d=$(ls -s ${tmp}s.exe) rm -f ${tmp}s.exe compile $cc -o ${tmp}s.exe $2 ${tmp}s.o <&$nullin >&$nullout 2>${tmp}s.e && $executable ${tmp}s.exe || continue case $(wc -l ${tmp}s.e) in $e) ;; *) continue ;; esac case $(ls -s ${tmp}s.exe) in $d) ;; *) reallystatic=$2 set x shift break ;; esac done fi (set +o noglob; exec rm -f ${tmp}s.*) #...INDENT ;; esac ccflags=$reallystatic ;; *) ccflags= ;; esac set x $mac e=1 while : do o= shift while : do case $# in 0) break ;; esac case $1 in -) break ;; esac o="$o $1" shift done rm -f $tmp.exe if compile $cc $ccflags $o -DTEST=$p -DID=$v -o $tmp.exe $tmp.c $lib $deflib <&$nullin >&$nullout && $executable $tmp.exe then case $run in status*)execute $tmp.exe <&$nullin >&$nullout V=$? case $V in 0) e=1 ;; *) e=0 ;; esac break ;; no[ls]*);; [ls]*) e=0 && break ;; noo*) execute $tmp.exe <&$nullin >$tmp.out || break ;; o*) execute $tmp.exe <&$nullin >$tmp.out && e=0 && break ;; no*) execute $tmp.exe <&$nullin >&$nullout || break ;; *) execute $tmp.exe <&$nullin >&$nullout && e=0 && break ;; esac else case $run in no[els]*)e=1 && break ;; esac fi case $# in 0) case $run in no*) e=0 ;; esac break ;; esac done ;; esac o=1 case $run in no*) case $e in 0) e=1 ;; *) e=0 ;; esac ;; esac case $run in o*|noo*)case $e in 0) cat $tmp.out ;; esac rm -f $tmp.out ;; esac report $e $V "${note:-$run\ passed}" "${note:-$run} failed" continue ;; esac # initialize common builtin state case $o in dat|lib|mth|run) case $statictest in "") statictest=FoobaR copy $tmp.c "$std $tst $ext $usr extern int $statictest; int main(void){char* i = (char*)&$statictest; return ((unsigned int)i)^0xaaaa;} " rm -f $tmp.exe if compile $cc -o $tmp.exe $tmp.c <&$nullin >&$nullout && $executable $tmp.exe then case $static in .) static= copy $tmp.c "$std $tst $ext int main(void){printf("hello");return(0);} " rm -f $tmp.exe if compile $cc -c $tmp.c <&$nullin >&$nullout && compile $cc -o $tmp.exe $tmp.o <&$nullin >&$nullout && $executable $tmp.exe then e=$(wc -l $tmp.e) eval set x x $binding while : do shift shift case $# in 0) break ;; esac rm -f $tmp.exe compile $cc -o $tmp.exe $1 $tmp.o <&$nullin >&$nullout && $executable $tmp.exe || continue case $(wc -l $tmp.e) in $e) ;; *) continue ;; esac d=$(ls -s $tmp.exe) rm -f $tmp.exe compile $cc -o $tmp.exe $2 $tmp.o <&$nullin >&$nullout && $executable $tmp.exe || continue case $(wc -l $tmp.e) in $e) ;; *) continue ;; esac case $(ls -s $tmp.exe) in $d) ;; *) static=$2 set x shift break ;; esac done fi ;; esac else static= fi ;; esac ;; esac # builtin tests case $o in api) ;; cmd) case $p in ?*) continue ;; esac is $o $a k=1 pkg $pth # set system default path for d in $pth do if test -f "$d/$a" then s=$(echo "$d" | LC_ALL=C sed 's,[^0-9A-Za-z],_,g') case $k in 1) k=0 case $M in *-*) ;; *) usr="$usr$nl#define $m 1" case $define in 1) echo "#define $m 1 /* $a in $pth */" ;; n) echo "$m=1" ;; esac ;; esac ;; esac c=${s}_${v} usr="$usr$nl#define $c 1" case $define in 1) echo "#define $c 1 /* $d/$a found */" ;; n) echo "$c=1" ;; esac fi done case $k in 0) success ;; 1) failure ;; esac ;; dat) case $p in ?*) continue ;; esac { copy - "$std $tst $ext $usr $pre " case $inc in ?*) echo "$inc" ;; *) echo "extern int $v;" ;; esac echo " #ifdef _DLL #define _REF_ #else #define _REF_ & #endif int main(void){char* i = (char*) _REF_ $v; return ((unsigned int)i)^0xaaaa;}" } > $tmp.c is $o $v rm -f $tmp.exe compile $cc -c $tmp.c <&$nullin >&$nullout && compile $cc $static -o $tmp.exe $tmp.o $lib $deflib <&$nullin >&$nullout && $executable $tmp.exe report $? 1 "$v in default lib(s)" "$v not in default lib(s)" ;; dfn) case $p in ?*) continue ;; esac is dfn $v echo "$std $pre $tst $ext $inc #ifdef $v <<\"#ifndef $v\">> <<\"#define $v\">> $v <<\"/* native $v */\">> <<\"#endif\">> #endif" > $tmp.c if compile $cc -E -P $tmp.c <&$nullin >$tmp.i then sed -e '/<<[ ]*".*"[ ]*>>/!d' -e 's/<<[ ]*"//g' -e 's/"[ ]*>>//g' $tmp.i > $tmp.t if test -s $tmp.t then success cat $tmp.t else failure fi else failure fi ;; exp) case $test in '') echo "$command: $file$sline: test expression expected for $o" >&$stderr exit 1 ;; esac case $a in -|'') ;; *) eval x='$'$a case $x in 1) result=FAILURE continue ;; esac ;; esac case $test in [01]|'"'*'"'|'<'*'>') case $a in -|'') ;; *) case $define$note in 1) echo "#define $a $test" ;; 1*) echo "#define $a $test /* $note */" ;; n) echo "$a=$test" ;; esac eval $a='$test' ;; esac ;; *) case $note in '') note=$test ;; esac case $test in '') c=1 ;; *) is exp "$note" x= for i in $(echo '' $test | sed 's,[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_], & ,g') do case $i in [\ \ ]) ;; [abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_]*) eval i='${'$i'}' case $i in '') i=0 ;; '"'*'"');; *[!-+0123456789]*) case $i in *'"'*) i=1 ;; *) i='"'$i'"' ;; esac ;; esac x="$x $i" ;; '!') x="$x 0 =" ;; '&'|'|')case $x in *"$i") ;; *) x="$x \\$i" ;; esac ;; *) x="$x \\$i" ;; esac done c=$(eval expr $x 2>&$stderr) ;; esac case $c in 0) c=1 ;; *) c=0 ;; esac M=$a m=$a report $c 1 "$note is true" "$note is false" ;; esac ;; hdr|lcl|nxt|sys) case $o in lcl|nxt)case $M in *-*) continue ;; esac eval x='$'_$m case $x in ?*) continue ;; esac eval _$m=1 is $o $f echo "$std $pre $tst $ext $inc #include <$f.h>" > $tmp.c case $f in sys/*) e= ;; *) e='-e /[\\\\\/]sys[\\\\\/]'$f'\\.h"/d' ;; esac if compile $cc -E $tmp.c <&$nullin >$tmp.i then i=$(sed -e '/^#[line ]*[0123456789][0123456789]*[ ][ ]*"[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ:]*[\\\/].*[\\\/]'$f'\.h"/!d' $e -e 's/.*"\(.*\)".*/\1/' -e 's,\\,/,g' -e 's,///*,/,g' $tmp.i | sed 1q) case $i in [abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]:[\\/]*) ;; */*/*) k=$(echo "$i" | sed 's,.*/\([^/]*/[^/]*\)$,../\1,') echo "$std $pre $tst $ext $inc #include <$k>" > $tmp.c if compile $cc -E $tmp.c <&$nullin >$tmp.i then j=$(sed -e '/^#[line ]*[0123456789][0123456789]*[ ][ ]*"[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ:]*[\\\/].*[\\\/]'$f'\.h"/!d' $e -e 's/.*"\(.*\)".*/\1/' -e 's,\\,/,g' -e 's,///*,/,g' $tmp.i | sed 1q) wi=$(wc < "$i") wj=$(wc < "$j") case $wi in $wj) i=$k ;; esac fi ;; *) echo "$std $pre $tst $ext $inc #include <../include/$f.h>" > $tmp.c if compile $cc -E $tmp.c <&$nullin >&$nullout then i=../include/$f.h fi ;; esac else i= fi case $i in [abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]:[\\/]*|[\\/]*) success case $o in lcl) echo "#include <$i> /* the native <$f.h> */" echo "#undef $m" usr="$usr$nl#define $m 1" echo "#define $m 1" ;; nxt) echo "#define $m <$i> /* include path for the native <$f.h> */" echo "#define ${m}_str \"$i\" /* include string for the native <$f.h> */" usr="$usr$nl#define $m <$i>$nl#define ${m}_str \"$i\"" eval $m=\\\<$i\\\> ;; esac break ;; ../*/*) success case $o in lcl) echo "#include <$i> /* the native <$f.h> */" echo "#undef $m" usr="$usr$nl#define $m 1" echo "#define $m 1" eval $m=1 ;; nxt) echo "#define $m <$i> /* include path for the native <$f.h> */" echo "#define ${m}_str \"$i\" /* include string for the native <$f.h> */" usr="$usr$nl#define $m <$i>$nl#define ${m}_str \"$i\"" eval $m=\\\<$i\\\> ;; esac break ;; *) failure case $o in lcl) case $all$config$undef in ?1?|??1)echo "#undef $m /* no native <$f.h> */" ;; 1??) echo "#define $m 0 /* no native <$f.h> */" ;; esac eval $m=0 ;; nxt) case $all$config$undef in ?1?|??1)echo "#undef $m /* no include path for the native <$f.h> */" ;; esac ;; esac ;; esac ;; *) case $o in hdr) x=$f.h ;; sys) x=sys/$f.h ;; esac case " $gothdr " in *" - $x "*) failure + ;; *" + $x "*) success + ;; *) echo "$std $tst $ext $allinc $inc #include <$x>" > $tmp.c if is_hdr $x then gothdr="$gothdr + $x" case $M in *-*) ;; *) case " $puthdr " in *" $m "*) ;; *) puthdr="$puthdr $m" usr="$usr$nl#define $m 1" ;; esac case $define in 1) echo "#define $m 1 /* #include <$x> ok */" ;; n) echo "$m=1" ;; esac eval $m=1 ;; esac else gothdr="$gothdr - $x" case $M in *-*) ;; *) case $define$all$config$undef in 1?1?|1??1)echo "#undef $m /* #include <$x> not ok */" ;; 11??) echo "#define $m 0 /* #include <$x> not ok */" ;; n1?1) echo "$m=" ;; n1??) echo "$m=0" ;; esac eval $m=0 ;; esac fi ;; esac continue ;; esac ;; iff) ;; ini) ;; key) case $p in ?*) continue ;; esac w=$v while : do is $o $w echo "$std $pre $tst $ext int f(void){int $w = 1;return($w);}" > $tmp.c if compile $cc -c $tmp.c <&$nullin >&$nullout then failure case $set in *" ="|*" = "*) set x $set shift w= while : do case $# in 0) break ;; esac case $1 in =) break ;; esac case $w in '') w=$1 ;; *) w="$w $1" ;; esac shift done case $1 in =) shift case $# in 0) set=" " ;; *) set=$* ;; esac ;; *) set= ;; esac case $shell in ksh) typeset -u u=$w ;; *) u=$(echo $w | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ) ;; esac u=_$u M=$w case $M in *[!abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_]*) M=$(echo "X$m" | sed -e 's,^.,,' -e 's,[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_],_,g') ;; esac case $config in 1) m=HAVE${u}_RESERVED ;; *) m=_key_${w} ;; esac continue ;; esac report - 1 - - "$w is not a reserved keyword" "default for reserved keyword $v" else report 0 1 "$w is a reserved keyword" - case $M in *-*) ;; *) case $define$w in 1$v) ;; 1*) echo "#define $v $w /* alternate for reserved keyword $v */" ;; n*) echo "$v=$w" ;; esac ;; esac fi break done ;; lib|mth)case $p in ?*) continue ;; esac case $v in -) continue ;; esac is $o $v copy $tmp.c "$std $tst $ext $usr $pre $inc #ifdef _IFFE_type $v i; #else typedef int (*_IFFE_fun)(); #ifdef _IFFE_extern extern int $v(void); #endif static _IFFE_fun i=(_IFFE_fun)$v;int main(void){return ((unsigned int)i)^0xaaaa;} #endif " d=-D_IFFE_extern if compile $cc -c $tmp.c <&$nullin >&$nullout then d= elif compile $cc $d -c $tmp.c <&$nullin >&$nullout then : else d=error fi if test error != "$d" then rm -f $tmp.exe if compile $cc $d $static -o $tmp.exe $tmp.o $lib $deflib <&$nullin >&$nullout && $executable $tmp.exe then case $o in lib) c=0 ;; *) c=1 ;; esac report $c 1 "$v() in default lib(s)" "$v() not in default lib(s)" "default for function $v()" else case $o in mth) rm -f $tmp.exe compile $cc $d $static -o $tmp.exe $tmp.o -lm <&$nullin >&$nullout && $executable $tmp.exe report $? 1 "$v() in math lib" "$v() not in math lib" "default for function $v()" ;; *) report 1 1 - "$v() not in default lib(s)" "default for function $v()" ;; esac fi else if compile $cc -D_IFFE_type -c $tmp.c <&$nullin >&$nullout then c=1 else case $intrinsic in '') copy $tmp.c "$std $tst $ext $usr $pre $inc extern int foo(void); static int ((*i)())=foo;int main(void){return(i==0);} " compile $cc -c $tmp.c <&$nullin >&$nullout intrinsic=$? ;; esac c=$intrinsic fi case $o in mth) report $c 1 "$v() in math lib" "$v() not in math lib" "default for function $v()" ;; *) report $c 1 "$v() in default lib(s)" "$v() not in default lib(s)" "default for function $v()" ;; esac fi ;; mac) case $p in ?*) continue ;; esac is mac $v echo "$std $tst $ext $pre $inc #ifdef $v '$m:$v' #endif" > $tmp.c compile $cc -E $tmp.c <&$nullin | grep -c "'$m:$v'" >&$nullout report $? 1 "$v is a macro" "$v is not a macro" "default for macro $v" ;; mem) case $p in ?*) eval i='$'_iffe_typedef_$p case $i in 0|1) ;; *) echo "$std $pre $tst $ext $inc static $p i; int n = sizeof(i);" > $tmp.c is typ $p if compile $cc -c $tmp.c <&$nullin >&$nullout then success - eval _iffe_typedef_$p=1 i=1 else failure - eval _iffe_typedef_$p=0 i=0 fi ;; esac case $i in 0) i="$v is not a member of $p" p="struct $p" ;; *) i=- ;; esac is mem $v "$p" echo "$std $pre $tst $ext $inc static $p i; int n = sizeof(i.$v);" > $tmp.c compile $cc -c $tmp.c <&$nullin >&$nullout report $? 1 "$v is a member of $p" "$i" ;; *) p=$v eval i='$'_iffe_typedef_$p case $i in 0|1) ;; *) echo "$std $pre $tst $ext $inc static $p i; int n = sizeof(i);" > $tmp.c is typ $p if compile $cc -c $tmp.c <&$nullin >&$nullout then success - eval _iffe_typedef_$p=1 i=1 else failure - eval _iffe_typedef_$p=0 i=0 fi ;; esac case $i in 0) i="$p is not a non-opaque struct" p="struct $p" ;; *) i=- ;; esac is nos "$p" echo "$std $pre $tst $ext $inc static $p i; int n = sizeof(i);" > $tmp.c if compile $cc -c $tmp.c <&$nullin >&$nullout then echo "$std $pre $tst $ext $inc static $p i; unsigned long f(void) { return (unsigned long)i; }" > $tmp.c if compile $cc -c $tmp.c <&$nullin >&$nullout then c=1 else c=0 fi else c=1 fi report $c 1 "$p is a non-opaque struct" "$i" esac ;; nop) ;; npt) is npt $v copy $tmp.c "$std $tst $ext $usr $pre $inc struct _iffe_struct { int _iffe_member; }; extern struct _iffe_struct* $v(struct _iffe_struct*); " # some compilers with -O only warn for invalid intrinsic prototypes case " $cc " in *" -O "*) xx=$(echo $cc | sed 's/ -O / /g') ;; *) xx=$cc ;; esac compile $xx -c $tmp.c <&$nullin >&$nullout report -$config $? 1 "$v() needs a prototype" "$v() does not need a prototype" ;; num) is num $v copy $tmp.c "$std $tst $ext $usr $pre $inc int _iffe_int = $v / 2; " compile $cc -c $tmp.c <&$nullin >&$nullout report $? 1 "$v is a numeric constant" "$v is not a numeric constant" ;; one) for i in $a $hdr do x="#include <$i>" case " $gothdr " in *" - $i "*) continue ;; *" + $i "*) ;; *) echo "$x" > $tmp.c if is_hdr $x then gothdr="$gothdr + $x" else gothdr="$gothdr - $x" continue fi ;; esac case $one in "") one=$x ;; *"$x"*) break ;; *) echo "$one" > $tmp.c if compile $cc -E $tmp.c <&$nullin >$tmp.i then c=$i case $c in *[\\/]*) c=$(echo $c | sed 's,[\\/],[\\/],g') ;; esac case $(sed -e '/^#[line ]*1[ ][ ]*"[\\\/].*[\\\/]'$c'"/!d' $tmp.i) in ?*) break ;; esac fi one="$one$nl$x" ;; esac echo "$x" break done ;; opt) M=$m is opt $a case " $PACKAGE_OPTIONS " in *" $a "*) c=0 ;; *) c=1 ;; esac report $c 1 "$a is set in \$PACKAGE_OPTIONS" "$a is not set in \$PACKAGE_OPTIONS" ;; out|output) ;; pth) is pth $a pkg $pth tab=" " e= f= for i in $pth do case $i in '{') e="${nl}}" l= x=i v="\$${x}" t=${nl}${tab} b="fnd()${nl}{${t}for ${x} in" ;; '}') b="${b}${t}do${tab}if $exists ${v}/\${1}${t}${tab}${tab}then${tab}f=${v}/\${1}${t}${tab}${tab}${tab}return${t}${tab}${tab}fi" e="${t}done${e}" eval "${b}${e}" fnd $a case $f in ?*) break ;; esac ;; -) b="${b}${t}do${tab}test \"${v}\" = '' -o -d \"${v}\" &&${t}${tab}${tab}" x=${x}i v="${v}\$${x}" b="${b}for ${x} in" e="${t}done${e}" t="${t}${tab}${tab}" ;; *) case $e in '') if $exists ${i}/${a} then f=${i}/${a} break fi ;; *) case $i in /|.) b="${b} ''" ;; *) b="${b} /${i}" ;; esac ;; esac ;; esac done case $f in '') case $set in ' ') f=$a ;; ?*) f=$set ;; esac ;; esac case $f in '') c=1 ;; *) c=0 f="\"$f\"" ;; esac report $c "$f" "${note:-$a path}" "$a path not found" ;; run) is run $a if test ! -r $a then failure not found case $verbose in 0) echo "$command: $file$line: $a: not found" >&$stderr ;; esac exit 1 fi noisy case $a in *.c) rm -f $tmp.exe { echo "$std $tst $ext $usr $inc" cat $a } > $tmp.c compile $cc -o $tmp.exe $tmp.c $lib $deflib <&$nullin >&$stderr 2>&$stderr && $executable $tmp.exe && execute $tmp.exe $opt <&$nullin ;; *.sh) { copy - ": set \"cc='$cc' executable='$executable' id='$m' static='$static' tmp='$tmp'\" $opt $hdr $test" cat $a } > $tmp.sh chmod +x $tmp.sh ( . $tmp.sh ) <&$nullin ;; *) false ;; esac case $? in 0) success ;; *) failure cannot run case $verbose in 0) echo "$command: $file$line: $a: cannot run" >&$stderr ;; esac exit 1 ;; esac ;; siz) case $p in "") x= ;; *) x="$p " ;; esac is siz "$x$v" { case $p:$v in long:*|*:*[_0123456789]int[_0123456789]*) echo "$std $pre $tst $ext $inc static $x$v i; $x$v f(void) { $x$v v; i = 1; v = i;" echo "i = v * i; i = i / v; v = v + i; i = i - v;" case $v in float|double) ;; *) echo "v <<= 4; i = v >> 2; i = 10; i = v % i; i |= v; v ^= i; i = 123; v &= i;" ;; esac echo "return v; }" ;; *) echo "$std $pre $inc struct xxx { $x$v mem; }; static struct xxx v; struct xxx* f(void) { return &v; }" ;; esac case $x in ""|"struct "|"union ") echo "int g(void) { return 0; }" ;; *) echo "int g(void) { return sizeof($x$v)<=sizeof($v); }" ;; esac copy - " int main(void) { f(); g(); printf(\"%u\\n\", sizeof($x$v)); return 0; }" } > $tmp.c rm -f $tmp.exe $tmp.dat if compile $cc -o $tmp.exe $tmp.c $lib $deflib <&$nullin >&$nullout && $executable $tmp.exe && execute $tmp.exe > $tmp.dat then z=$(cat $tmp.dat) c=0 else z=0 c=1 fi report $c "$z" "sizeof($x$v)" "$x$v not a type with known size" ;; sym) case $test in "") x=$v ;; *) x=$test ;; esac echo "$std $pre $tst $ext $inc '=' $x '='" > $tmp.c compile $cc -E $tmp.c <&$nullin \ | sed \ -e "/'='/!d" \ -e "s/'='//g" \ -e 's/[ ]//g' \ -e 's/((([^()]*)))->/->/g' \ -e 's/(([^()]*))->/->/g' \ -e 's/([^()]*)->/->/g' \ -e 's/\([abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_][abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789]*\)\[/\ ary \1[/g' \ -e 's/\([abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_][abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789]*\)(/\ fun \1[/g' \ -e 's/\*->\([abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_]\)/->\ ptr \1/g' \ -e 's/->\([abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_]\)/->\ reg \1/g' \ -e "/^$v\$/d" \ -e 's/^[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_][abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789]*$/\ nam &/g' \ | sed \ -e '/^... /!d' \ | LC_ALL=C sort \ -u \ | sed \ -e 's/\(...\) \([abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_][abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789]*\).*/#ifndef _\1_'$v'\ #define _\1_'$v' \2\ #define _\1_'$v'_str "\2"\ #endif/' ;; typ) case $p in "") x= ;; *) x="$p " ;; esac is typ "$x$v" { case $p:$v in long:*|*:*[_0123456789]int[_0123456789]*) echo "$std $pre $tst $ext $inc static $x$v i; $x$v f(void) { $x$v v; i = 1; v = i;" echo "i = v * i; i = i / v; v = v + i; i = i - v;" case $v in float|double) ;; *) echo "v <<= 4; i = v >> 2; i = 10; i = v % i; i |= v; v ^= i; i = 123; v &= i;" ;; esac echo "return v; }" ;; *) echo "$std $pre $tst $ext $inc struct xxx { $x$v mem; }; static struct xxx v; struct xxx* f(void) { return &v; }" ;; esac case $x in ""|"struct "|"union ") echo "int main(void) { f(); return 0; }" ;; *) echo "int main(void) { f(); return sizeof($x$v)<=sizeof($v); }" ;; esac } > $tmp.c rm -f $tmp.exe compile $cc -o $tmp.exe $tmp.c $lib $deflib <&$nullin >&$nullout && $executable $tmp.exe && execute $tmp.exe report $? 1 "$x$v is a type" "$x$v is not a type" "default for type $x$v" ;; val) case $arg in '"'*'"')echo $arg=\'$val\' ;; *) echo $arg=\"$val\" ;; esac ;; ver) ;; 0) result=FAILURE ;; 1) result=SUCCESS ;; :) ;; -) ;; *) echo "$command: $file$line: $o: unknown feature test" >&$stderr status=1 ;; esac done done case $not in 1) case $result in FAILURE) result=SUCCESS ;; *) result=FAILURE ;; esac ;; esac case $result in FAILURE) user_pf=$fail user_yn=$no ;; *) user_pf=$pass user_yn=$yes ;; esac case $user_pf in ?*) # Run a pass{ or fail{ block in iffe's current environment eval "$user_pf" <&$nullin 2>&$stderr ;; esac case $user_yn in ?*) case $def in -) ;; *) case $note in ?*) case $user_yn in *$nl*) user_yn="/* $note */$nl$user_yn" ;; *) user_yn="$user_yn /* $note */" ;; esac ;; esac ;; esac copy - "$user_yn" ;; esac case $ifelse:$result in TEST:SUCCESS) ifelse=KEEP ;; TEST:*) ifelse=SKIP ;; esac case $group:$result in :*|*:SUCCESS) break ;; esac set '' $groups '' "$@" shift case $1 in '') shift; break ;; esac shift # set up and try the next group hdr=$com_hdr lib=$com_lib mac=$com_mac opt=$com_opt pth=$com_pth test=$com_test cc="$occ $includes" group= groups= while : do case $1 in '') shift; break ;; esac case $1 in *[\"\'\(\)\{\}\ \ ]*) case $op in pth) pth="$pth $1" ;; *) case $test in '') test=$1 ;; *) test="$test $1" ;; esac ;; esac ;; -) group=$group$1 groups="$groups $1" ;; -l*) case $group in -*) groups="$groups $1" ;; *) lib="$lib $1" ;; esac ;; +l*) x=-${1#+} case $group in -*) groups="$groups $x" ;; *) lib="$lib $x" ;; esac ;; -*|+*) case $group in -*) groups="$groups $1" ;; *) case $op in run) opt="$opt $1" ;; *) case $1 in -D*) mac="$mac $1" ;; *) cc="$cc $1" ;; esac ;; esac ;; esac ;; *.[aAxX]|*.[dD][lL][lL]|*.[lL][iI][bB]) case $group in -*) groups="$groups $1" ;; *) lib="$lib $1" ;; esac ;; *[.\\/]*) case $group in -*) groups="$groups $1" ;; *) case $op in pth) pth="$pth $1" ;; *) hdr="$hdr $1" ;; esac ;; esac ;; *) case $group in -*) groups="$groups $1" ;; *) case $op in pth) pth="$pth $1" ;; *) case $test in '') test=$1 ;; *) test="$test $1" ;; esac ;; esac ;; esac ;; esac shift done done done ksh-1.0.10/src/cmd/INIT/iffe.tst000066400000000000000000001272341465301102200161230ustar00rootroot00000000000000# regression tests for the iffe command TEST 01 'command line basics' EXEC -r -v - hdr stdio OUTPUT - $'/* : : generated by iffe version 1995-03-19 : : */ #ifndef _REGRESS #define _REGRESS 1 #define _sys_types 1 /* #include ok */ #define _hdr_stdio 1 /* #include ok */ #endif' ERROR - $'iffe: test: is sys/types.h a header ... yes iffe: test: is stdio.h a header ... yes' EXEC -r -v -s posix - hdr stdio EXEC -r -v - hdr stdio,limits OUTPUT - $'/* : : generated by iffe version 1995-03-19 : : */ #ifndef _REGRESS #define _REGRESS 1 #define _sys_types 1 /* #include ok */ #define _hdr_stdio 1 /* #include ok */ #define _hdr_limits 1 /* #include ok */ #endif' ERROR - $'iffe: test: is sys/types.h a header ... yes iffe: test: is stdio.h a header ... yes iffe: test: is limits.h a header ... yes' EXEC -r -v -s posix - hdr stdio,limits EXEC -r -v - hdr,lib no_foo_bar,no_bar_foo stdio.h OUTPUT - $'/* : : generated by iffe version 1995-03-19 : : */ #ifndef _REGRESS #define _REGRESS 1 #define _sys_types 1 /* #include ok */ #define _hdr_stdio 1 /* #include ok */ #endif' ERROR - $'iffe: test: is sys/types.h a header ... yes iffe: test: is stdio.h a header ... yes iffe: test: is no_foo_bar.h a header ... no iffe: test: is no_bar_foo.h a header ... no iffe: test: is no_foo_bar a library function ... no iffe: test: is no_bar_foo a library function ... no' EXEC -r -v -s posix - hdr,lib no_foo_bar,no_bar_foo stdio.h EXEC -r -v - hdr no_foo_bar,no_bar_foo stdio.h : lib no_foo_bar,no_bar_foo stdio.h EXEC -r -v -s posix - hdr no_foo_bar,no_bar_foo stdio.h : lib no_foo_bar,no_bar_foo stdio.h TEST 02 'file input basics' EXEC -r -v - t1.iffe INPUT t1.iffe $'hdr stdio' OUTPUT - $'/* : : generated from t1.iffe by iffe version 1995-03-19 : : */ #ifndef _REGRESS #define _REGRESS 1 #define _sys_types 1 /* #include ok */ #define _hdr_stdio 1 /* #include ok */ #endif' ERROR - $'iffe: test: is sys/types.h a header ... yes iffe: test: is stdio.h a header ... yes' EXEC -r -v -s posix - t1.iffe EXEC -r -v - t2.iffe INPUT t2.iffe $'hdr stdio,limits' OUTPUT - $'/* : : generated from t2.iffe by iffe version 1995-03-19 : : */ #ifndef _REGRESS #define _REGRESS 1 #define _sys_types 1 /* #include ok */ #define _hdr_stdio 1 /* #include ok */ #define _hdr_limits 1 /* #include ok */ #endif' ERROR - $'iffe: test: is sys/types.h a header ... yes iffe: test: is stdio.h a header ... yes iffe: test: is limits.h a header ... yes' EXEC -r -v -s posix - t2.iffe EXEC -r -v - t3.iffe INPUT t3.iffe $'hdr,lib no_foo_bar,no_bar_foo stdio.h' OUTPUT - $'/* : : generated from t3.iffe by iffe version 1995-03-19 : : */ #ifndef _REGRESS #define _REGRESS 1 #define _sys_types 1 /* #include ok */ #define _hdr_stdio 1 /* #include ok */ #endif' ERROR - $'iffe: test: is sys/types.h a header ... yes iffe: test: is stdio.h a header ... yes iffe: test: is no_foo_bar.h a header ... no iffe: test: is no_bar_foo.h a header ... no iffe: test: is no_foo_bar a library function ... no iffe: test: is no_bar_foo a library function ... no' EXEC -r -v -s posix - t3.iffe EXEC -r -v - t3.iffe INPUT t3.iffe $'hdr no_foo_bar,no_bar_foo stdio.h lib no_foo_bar,no_bar_foo stdio.h' EXEC -r -v -s posix - t3.iffe TEST 03 'nested if' EXEC -r -v - t.iffe INPUT t.iffe $'iff ifelse if hdr stdio if lib open { HIT 1 } elif lib close { HIT 2 } else { HIT 3 } endif elif hdr limits { HIT 4 } else { HIT 5 } endif' OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _ifelse_H #define _ifelse_H 1 #define _sys_types 1 /* #include ok */ #define _hdr_stdio 1 /* #include ok */ #define _lib_open 1 /* open() in default lib(s) */ HIT 1 #endif' ERROR - $'iffe: test: is sys/types.h a header ... yes iffe: test: is stdio.h a header ... yes iffe: test: is open a library function ... yes' EXEC -r -v -s posix - t.iffe EXEC -r -v - t.iffe INPUT t.iffe $'iff ifelse if hdr _XXX_stdio if lib open { HIT 1 } elif lib close { HIT 2 } else { HIT 3 } endif elif hdr limits { HIT 4 } else { HIT 5 } endif' OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _ifelse_H #define _ifelse_H 1 #define _sys_types 1 /* #include ok */ #define _hdr_limits 1 /* #include ok */ HIT 4 #endif' ERROR - $'iffe: test: is sys/types.h a header ... yes iffe: test: is _XXX_stdio.h a header ... no iffe: test: is limits.h a header ... yes' EXEC -r -v -s posix - t.iffe EXEC -r -v - t.iffe INPUT t.iffe $'iff ifelse if hdr _XXX_stdio if lib open { HIT 1 } elif lib close { HIT 2 } else { HIT 3 } endif elif hdr _XXX_limits { HIT 4 } else { HIT 5 } endif' OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _ifelse_H #define _ifelse_H 1 #define _sys_types 1 /* #include ok */ HIT 5 #endif' ERROR - $'iffe: test: is sys/types.h a header ... yes iffe: test: is _XXX_stdio.h a header ... no iffe: test: is _XXX_limits.h a header ... no' EXEC -r -v -s posix - t.iffe EXEC -r -v - t.iffe INPUT t.iffe $'iff ifelse if hdr stdio if lib _XXX_open { HIT 1 } elif lib close { HIT 2 } else { HIT 3 } endif elif hdr limits { HIT 4 } else { HIT 5 } endif' OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _ifelse_H #define _ifelse_H 1 #define _sys_types 1 /* #include ok */ #define _hdr_stdio 1 /* #include ok */ #define _lib_close 1 /* close() in default lib(s) */ HIT 2 #endif' ERROR - $'iffe: test: is sys/types.h a header ... yes iffe: test: is stdio.h a header ... yes iffe: test: is _XXX_open a library function ... no iffe: test: is close a library function ... yes' EXEC -r -v -s posix - t.iffe EXEC -r -v - t.iffe INPUT t.iffe $'iff ifelse if hdr stdio if lib _XXX_open { HIT 1 } elif lib _XXX_close { HIT 2 } else { HIT 3 } endif elif hdr limits { HIT 4 } else { HIT 5 } endif' OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _ifelse_H #define _ifelse_H 1 #define _sys_types 1 /* #include ok */ #define _hdr_stdio 1 /* #include ok */ HIT 3 #endif' ERROR - $'iffe: test: is sys/types.h a header ... yes iffe: test: is stdio.h a header ... yes iffe: test: is _XXX_open a library function ... no iffe: test: is _XXX_close a library function ... no' EXEC -r -v -s posix - t.iffe EXEC -r -v - t.iffe INPUT t.iffe $'iff ifelse if mem stat.st_atime sys/types.h sys/stat.h { #define ATIME 1 } elif mem stat.st_ctime sys/types.h sys/stat.h { #define CTIME 1 } elif mem stat.st_mtime sys/types.h sys/stat.h { #define MTIME 1 } else pass{ no_stat_time=1 }end { #define NOTIME 1 } endif if ( !no_stat_time ) { #define YESTIME 1 } endif' OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _ifelse_H #define _ifelse_H 1 #define _sys_types 1 /* #include ok */ #define _sys_stat 1 /* #include ok */ #define _mem_st_atime_stat 1 /* st_atime is a member of struct stat */ #define ATIME 1 #define YESTIME 1 #endif' ERROR - $'iffe: test: is sys/types.h a header ... yes iffe: test: is sys/stat.h a header ... yes iffe: test: is stat a type or typedef ... no iffe: test: is st_atime a member of struct stat ... yes iffe: test: is ( !no_stat_time ) true ... yes' EXEC -r -v -s posix - t.iffe EXEC -r -v - t.iffe INPUT t.iffe $'iff ifelse if mem foo_stat.st_atime sys/types.h sys/stat.h { #define ATIME 1 } elif mem stat.st_ctime sys/types.h sys/stat.h { #define CTIME 1 } elif mem stat.st_mtime sys/types.h sys/stat.h { #define MTIME 1 } else pass{ no_stat_time=1 }end { #define NOTIME 1 } endif if ( !no_stat_time ) { #define YESTIME 1 } endif' OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _ifelse_H #define _ifelse_H 1 #define _sys_types 1 /* #include ok */ #define _sys_stat 1 /* #include ok */ #define _mem_st_ctime_stat 1 /* st_ctime is a member of struct stat */ #define CTIME 1 #define YESTIME 1 #endif' ERROR - $'iffe: test: is sys/types.h a header ... yes iffe: test: is sys/stat.h a header ... yes iffe: test: is foo_stat a type or typedef ... no iffe: test: is st_atime a member of struct foo_stat ... no iffe: test: is stat a type or typedef ... no iffe: test: is st_ctime a member of struct stat ... yes iffe: test: is ( !no_stat_time ) true ... yes' EXEC -r -v -s posix - t.iffe EXEC -r -v - t.iffe INPUT t.iffe $'iff ifelse if mem foo_stat.st_atime sys/types.h sys/stat.h { #define ATIME 1 } elif mem foo_stat.st_ctime sys/types.h sys/stat.h { #define CTIME 1 } elif mem stat.st_mtime sys/types.h sys/stat.h { #define MTIME 1 } else pass{ no_stat_time=1 }end { #define NOTIME 1 } endif if ( !no_stat_time ) { #define YESTIME 1 } endif' OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _ifelse_H #define _ifelse_H 1 #define _sys_types 1 /* #include ok */ #define _sys_stat 1 /* #include ok */ #define _mem_st_mtime_stat 1 /* st_mtime is a member of struct stat */ #define MTIME 1 #define YESTIME 1 #endif' ERROR - $'iffe: test: is sys/types.h a header ... yes iffe: test: is sys/stat.h a header ... yes iffe: test: is foo_stat a type or typedef ... no iffe: test: is st_atime a member of struct foo_stat ... no iffe: test: is st_ctime a member of struct foo_stat ... no iffe: test: is stat a type or typedef ... no iffe: test: is st_mtime a member of struct stat ... yes iffe: test: is ( !no_stat_time ) true ... yes' EXEC -r -v -s posix - t.iffe EXEC -r -v - t.iffe INPUT t.iffe $'iff ifelse if mem foo_stat.st_atime sys/types.h sys/stat.h { #define ATIME 1 } elif mem foo_stat.st_ctime sys/types.h sys/stat.h { #define CTIME 1 } elif mem foo_stat.st_mtime sys/types.h sys/stat.h { #define MTIME 1 } else pass{ no_stat_time=1 }end { #define NOTIME 1 } endif if ( !no_stat_time ) { #define YESTIME 1 } endif' OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _ifelse_H #define _ifelse_H 1 #define _sys_types 1 /* #include ok */ #define _sys_stat 1 /* #include ok */ #define NOTIME 1 #endif' ERROR - $'iffe: test: is sys/types.h a header ... yes iffe: test: is sys/stat.h a header ... yes iffe: test: is foo_stat a type or typedef ... no iffe: test: is st_atime a member of struct foo_stat ... no iffe: test: is st_ctime a member of struct foo_stat ... no iffe: test: is st_mtime a member of struct foo_stat ... no iffe: test: is ( !no_stat_time ) true ... no' EXEC -r -v -s posix - t.iffe EXEC -r -v - t.iffe INPUT t.iffe $'set explicit iff previous hdr stdio if hdr stdio { OK } else { OK } endif' OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _previous_H #define _previous_H 1 #define _hdr_stdio 1 /* #include ok */ OK #endif' ERROR - $'iffe: test: is sys/types.h a header ... yes iffe: test: is stdio.h a header ... yes' EXEC -r -v -s posix - t.iffe TEST 04 'test variable/macro override' EXEC -r -v - t.iffe INPUT t.iffe $'iff macro HAVE_STDIO = hdr stdio' OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _macro_H #define _macro_H 1 #define _sys_types 1 /* #include ok */ #define HAVE_STDIO 1 /* #include ok */ #endif' ERROR - $'iffe: test: is sys/types.h a header ... yes iffe: test: is stdio.h a header ... yes' EXEC -r -v -s posix - t.iffe EXEC -r -v - t.iffe INPUT t.iffe $'iff macro if hdr - stdio { #define HIT 1 } endif' OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _macro_H #define _macro_H 1 #define _sys_types 1 /* #include ok */ #define HIT 1 #endif' EXEC -r -v -s posix - t.iffe EXEC -r -v - t.iffe INPUT t.iffe $'iff macro if - hdr stdio { #define HIT 1 } endif' EXEC -r -v -s posix - t.iffe EXEC -r -v - t.iffe INPUT t.iffe $'iff macro if ? hdr stdio { #define HIT 1 } endif' EXEC -r -v -s posix - t.iffe EXEC -r -v - t.iffe INPUT t.iffe $'iff macro if hdr - stdio { #define HIT 1 } endif' EXEC -r -v -s posix - t.iffe EXEC -r -v - t.iffe INPUT t.iffe $'iff macro if HAVE_STDIO = hdr stdio { #define HIT 1 } endif if ( HAVE_STDIO ) { #define TOO ALSO } endif' OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _macro_H #define _macro_H 1 #define _sys_types 1 /* #include ok */ #define HAVE_STDIO 1 /* #include ok */ #define HIT 1 #define TOO ALSO #endif' ERROR - $'iffe: test: is sys/types.h a header ... yes iffe: test: is stdio.h a header ... yes iffe: test: is ( HAVE_STDIO ) true ... yes' EXEC -r -v -s posix - t.iffe EXEC -r -v - t.iffe INPUT t.iffe $'iff macro if HAVE_STDIO = hdr stdio { #define HIT 1 } endif exp ALSO HAVE_STDIO' OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _macro_H #define _macro_H 1 #define _sys_types 1 /* #include ok */ #define HAVE_STDIO 1 /* #include ok */ #define HIT 1 #define ALSO 1 /* HAVE_STDIO is true */ #endif' ERROR - $'iffe: test: is sys/types.h a header ... yes iffe: test: is stdio.h a header ... yes iffe: test: is HAVE_STDIO true ... yes' EXEC -r -v -s posix - t.iffe EXEC -r -v - t.iffe INPUT t.iffe $'iff macro if HAVE_STDIO = hdr stdio { #define HIT 1 } endif ALSO = ( HAVE_STDIO )' OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _macro_H #define _macro_H 1 #define _sys_types 1 /* #include ok */ #define HAVE_STDIO 1 /* #include ok */ #define HIT 1 #define ALSO 1 /* ( HAVE_STDIO ) is true */ #endif' ERROR - $'iffe: test: is sys/types.h a header ... yes iffe: test: is stdio.h a header ... yes iffe: test: is ( HAVE_STDIO ) true ... yes' EXEC -r -v -s posix - t.iffe TEST 05 'test code option sequence' EXEC -r -v - t.iffe INPUT t.iffe $'iff macro tst seq - -DA=1 - -DB=1 note{ long int type }end compile{ #if A == 1 && B == 0 #define t long #else #define t error #endif t n = 0; }end' OUTPUT - '/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _macro_H #define _macro_H 1 #define _sys_types 1 /* #include ok */ #define _seq 1 /* long int type */ #endif' ERROR - 'iffe: test: is sys/types.h a header ... yes iffe: test: long int type ... yes' EXEC -r -v -s posix - t.iffe EXEC -r -v - t.iffe INPUT t.iffe $'iff macro tst seq -DG=1 - -DN=1 - -DN=2 note{ long int type }end compile{ #if G == 1 && N == 1 #define t long #else #define t error #endif t n = 0; }end' EXEC -r -v -s posix - t.iffe EXEC -r -v - t.iffe INPUT t.iffe $'iff macro tst seq - -DA=1 - -DB=1 note{ long int type }end compile{ #if A == 0 && B == 1 #define t long #else #define t error #endif t n = 0; }end' ERROR - 'iffe: test: is sys/types.h a header ... yes iffe: test: long int type ... iffe: test: long int type ... yes' EXEC -r -v -s posix - t.iffe EXEC -r -v - t.iffe INPUT t.iffe $'iff macro tst seq -DG=1 - -DN=1 - -DN=2 note{ long int type }end compile{ #if G == 1 && N == 2 #define t long #else #define t error #endif t n = 0; }end' EXEC -r -v -s posix - t.iffe EXEC -r -v - t.iffe INPUT t.iffe $'iff macro tst seq - -DA=1 - -DB=1 note{ long int type }end compile{ #if A == 0 && B == 0 #define t long #else #define t error #endif t n = 0; }end' OUTPUT - '/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _macro_H #define _macro_H 1 #define _sys_types 1 /* #include ok */ #endif' ERROR - 'iffe: test: is sys/types.h a header ... yes iffe: test: long int type ... iffe: test: long int type ... no' EXEC -r -v -s posix - t.iffe EXEC -r -v - t.iffe INPUT t.iffe $'iff macro tst seq -DG=1 - -DN=1 - -DN=2 note{ long int type }end compile{ #if G == 1 && N == 0 #define t long #else #define t error #endif t n = 0; }end' EXEC -r -v -s posix - t.iffe EXEC -r -v - t.iffe INPUT t.iffe $'iff macro if tst - -DA=1 - -DB=1 note{ long int type }end compile{ #if A == 1 && B == 0 #define t long #else #define t error #endif t n = 0; }end { #define seq 1 } endif' OUTPUT - '/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _macro_H #define _macro_H 1 #define _sys_types 1 /* #include ok */ /* long int type */ #define seq 1 #endif' ERROR - 'iffe: test: is sys/types.h a header ... yes iffe: test: long int type ... yes' EXEC -r -v -s posix - t.iffe EXEC -r -v - t.iffe INPUT t.iffe $'iff macro if tst -DG=1 - -DN=1 - -DN=2 note{ long int type }end compile{ #if G == 1 && N == 1 #define t long #else #define t error #endif t n = 0; }end { #define seq 1 } endif' EXEC -r -v -s posix - t.iffe EXEC -r -v - t.iffe INPUT t.iffe $'iff macro if tst - -DA=1 - -DB=1 note{ long int type }end compile{ #if A == 0 && B == 1 #define t long #else #define t error #endif t n = 0; }end { #define seq 1 } endif' ERROR - 'iffe: test: is sys/types.h a header ... yes iffe: test: long int type ... iffe: test: long int type ... yes' EXEC -r -v -s posix - t.iffe EXEC -r -v - t.iffe INPUT t.iffe $'iff macro if tst -DG=1 - -DN=1 - -DN=2 note{ long int type }end compile{ #if G == 1 && N == 2 #define t long #else #define t error #endif t n = 0; }end { #define seq 1 } endif' EXEC -r -v -s posix - t.iffe EXEC -r -v - t.iffe INPUT t.iffe $'iff macro if tst - -DA=1 - -DB=1 note{ long int type }end compile{ #if A == 0 && B == 0 #define t long #else #define t error #endif t n = 0; }end { #define seq 1 } endif' OUTPUT - '/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _macro_H #define _macro_H 1 #define _sys_types 1 /* #include ok */ #endif' ERROR - 'iffe: test: is sys/types.h a header ... yes iffe: test: long int type ... iffe: test: long int type ... no' EXEC -r -v -s posix - t.iffe EXEC -r -v - t.iffe INPUT t.iffe $'iff macro if tst -DG=1 - -DN=1 - -DN=2 note{ long int type }end compile{ #if G == 1 && N == 0 #define t long #else #define t error #endif t n = 0; }end { #define seq 1 } endif' EXEC -r -v -s posix - t.iffe EXEC -r -v - t.iffe INPUT t.iffe $'iff macro if tst - -DN=1 - -DN=2 - -DN=3 note{ long int type }end compile{ #if N == 1 #define t long #else #define t error #endif t n = 0; }end { #define seq 1 } endif' OUTPUT - '/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _macro_H #define _macro_H 1 #define _sys_types 1 /* #include ok */ /* long int type */ #define seq 1 #endif' ERROR - 'iffe: test: is sys/types.h a header ... yes iffe: test: long int type ... yes' EXEC -r -v -s posix - t.iffe EXEC -r -v - t.iffe INPUT t.iffe $'iff macro if tst - -DN=1 - -DN=2 - -DN=3 note{ long int type }end compile{ #if N == 2 #define t long #else #define t error #endif t n = 0; }end { #define seq 1 } endif' ERROR - 'iffe: test: is sys/types.h a header ... yes iffe: test: long int type ... iffe: test: long int type ... yes' EXEC -r -v -s posix - t.iffe EXEC -r -v - t.iffe INPUT t.iffe $'iff macro if tst - -DN=1 - -DN=2 - -DN=3 note{ long int type }end compile{ #if N == 3 #define t long #else #define t error #endif t n = 0; }end { #define seq 1 } endif' ERROR - 'iffe: test: is sys/types.h a header ... yes iffe: test: long int type ... iffe: test: long int type ... iffe: test: long int type ... yes' EXEC -r -v -s posix - t.iffe EXEC -r -v - t.iffe INPUT t.iffe $'iff macro if tst - -DN=1 - -DN=2 - -DN=3 note{ long int type }end compile{ #if N == 0 #define t long #else #define t error #endif t n = 0; }end { #define seq 1 } endif' OUTPUT - '/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _macro_H #define _macro_H 1 #define _sys_types 1 /* #include ok */ #endif' ERROR - 'iffe: test: is sys/types.h a header ... yes iffe: test: long int type ... iffe: test: long int type ... iffe: test: long int type ... no' EXEC -r -v -s posix - t.iffe TEST 06 'block side effects' EXEC -r - t.iffe INPUT t.iffe $'iff - tst output{ int main(void) { printf("HIT\\n"); return 0; } }end' OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #define _sys_types 1 /* #include ok */ HIT' EXEC -r -s posix - t.iffe EXEC -r - t.iffe INPUT t.iffe $'iff tst - output{ int main(void) { printf("HIT\\n"); return 0; } }end' EXEC -r -s posix - t.iffe EXEC -r - t.iffe INPUT t.iffe $'iff tst - output{ int main(void) { printf("HIT\\n"); return 1; } }end' OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #define _sys_types 1 /* #include ok */' EXEC -r -s posix - t.iffe EXEC -r - t.iffe INPUT t.iffe $'iff tst - nooutput{ int main(void) { printf("HIT\\n"); return 1; } }end' OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #define _sys_types 1 /* #include ok */ HIT' EXEC -r -s posix - t.iffe TEST 07 'diagnostics' EXEC -r - t.iffe INPUT t.iffe $'tst foo' OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _REGRESS #define _REGRESS 1 #define _sys_types 1 /* #include ok */ #endif' ERROR - $'iffe: t.iffe:1: tst: unknown feature test' EXIT 1 EXEC -r -s posix - t.iffe EXEC -r - t.iffe INPUT t.iffe $'if (1)' OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _REGRESS #define _REGRESS 1 #define _sys_types 1 /* #include ok */' ERROR - $'iffe: t.iffe:1: missing endif' EXIT 1 EXEC -r -s posix - t.iffe EXEC -r - t.iffe INPUT t.iffe $'if' OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _REGRESS #define _REGRESS 1 #define _sys_types 1 /* #include ok */' ERROR - $'iffe: t.iffe:1: missing endif' EXEC -r -s posix - t.iffe EXEC -r - t.iffe INPUT t.iffe $'endif' ERROR - $'iffe: t.iffe:1: endif: no matching if' EXEC -r -s posix - t.iffe EXEC -r - t.iffe INPUT t.iffe $'if { }end' ERROR - $'iffe: t.iffe:2: missing }' EXEC -r -s posix - t.iffe TEST 08 'negation consternation' EXEC -r - t.iffe INPUT t.iffe $'npt fopen,fooon stdio.h' OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _REGRESS #define _REGRESS 1 #define _sys_types 1 /* #include ok */ #define _hdr_stdlib 1 /* #include ok */ #define _hdr_unistd 1 /* #include ok */ #define _hdr_stdio 1 /* #include ok */ #define _npt_fooon 1 /* fooon() needs a prototype */ #endif' EXEC -r -u - t.iffe OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _REGRESS #define _REGRESS 1 #define _sys_types 1 /* #include ok */ #define _hdr_stdlib 1 /* #include ok */ #define _hdr_unistd 1 /* #include ok */ #define _hdr_stdio 1 /* #include ok */ #undef _npt_fopen /* fopen() does not need a prototype */ #define _npt_fooon 1 /* fooon() needs a prototype */ #endif' EXEC -r -a - t.iffe OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _REGRESS #define _REGRESS 1 #define _sys_types 1 /* #include ok */ #define _hdr_stdlib 1 /* #include ok */ #define _hdr_unistd 1 /* #include ok */ #define _hdr_stdio 1 /* #include ok */ #define _npt_fopen 0 /* fopen() does not need a prototype */ #define _npt_fooon 1 /* fooon() needs a prototype */ #endif' EXEC -r -C - t.iffe OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _REGRESS #define _REGRESS 1 #define HAVE_SYS_TYPES_H 1 /* #include ok */ #define HAVE_STDLIB_H 1 /* #include ok */ #define HAVE_UNISTD_H 1 /* #include ok */ #define HAVE_STDIO_H 1 /* #include ok */ #define HAVE_FOPEN_DECL 1 /* fopen() does not need a prototype */ #undef HAVE_FOOON_DECL /* fooon() needs a prototype */ #endif' EXEC -r - t.iffe INPUT t.iffe $'NEED_FOPEN = npt fopen stdio.h HAVE_FOPEN = ! npt fopen stdio.h NEED_FOOON = npt fooon stdio.h HAVE_FOOON = ! npt fooon stdio.h' OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _REGRESS #define _REGRESS 1 #define _sys_types 1 /* #include ok */ #define _hdr_stdlib 1 /* #include ok */ #define _hdr_unistd 1 /* #include ok */ #define _hdr_stdio 1 /* #include ok */ #define HAVE_FOPEN 1 /* fopen() does not need a prototype */ #define NEED_FOOON 1 /* fooon() needs a prototype */ #endif' EXEC -r -u - t.iffe OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _REGRESS #define _REGRESS 1 #define _sys_types 1 /* #include ok */ #define _hdr_stdlib 1 /* #include ok */ #define _hdr_unistd 1 /* #include ok */ #define _hdr_stdio 1 /* #include ok */ #undef NEED_FOPEN /* fopen() does not need a prototype */ #define HAVE_FOPEN 1 /* fopen() does not need a prototype */ #define NEED_FOOON 1 /* fooon() needs a prototype */ #undef HAVE_FOOON /* fooon() needs a prototype */ #endif' EXEC -r -C - t.iffe OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _REGRESS #define _REGRESS 1 #define HAVE_SYS_TYPES_H 1 /* #include ok */ #define HAVE_STDLIB_H 1 /* #include ok */ #define HAVE_UNISTD_H 1 /* #include ok */ #define HAVE_STDIO_H 1 /* #include ok */ #undef NEED_FOPEN /* fopen() does not need a prototype */ #define HAVE_FOPEN 1 /* fopen() does not need a prototype */ #define NEED_FOOON 1 /* fooon() needs a prototype */ #undef HAVE_FOOON /* fooon() needs a prototype */ #endif' TEST 09 'exp vs. if' EXEC -r - t.iffe INPUT t.iffe $'_tst_false = ( 0 ) _tst_true = ( 1 ) exp _tst_hit !_tst_false { ONE } exp _tst_hit !_tst_hit&_tst_true pass{ cat < ok */ #define _tst_true 1 /* ( 1 ) is true */ #define _tst_hit 1 /* !_tst_false is true */ /* !_tst_false */ ONE #endif' EXEC -r -s posix - t.iffe EXEC -r - t.iffe INPUT t.iffe $'_tst_false = ( 0 ) _tst_true = ( 1 ) exp _tst_hit !_tst_true { ONE } exp _tst_hit !_tst_hit&_tst_true pass{ cat < ok */ #define _tst_true 1 /* ( 1 ) is true */ #define _tst_hit 1 /* !_tst_hit&_tst_true is true */ TWO 0 1 #endif' EXEC -r -s posix - t.iffe EXEC -r - t.iffe INPUT t.iffe $'_tst_false = ( 0 ) _tst_true = ( 1 ) exp _tst_hit !_tst_true { ONE } exp _tst_hit !_tst_hit&_tst_false pass{ cat < ok */ #define _tst_true 1 /* ( 1 ) is true */ #define _tst_hit 1 /* !_tst_hit&_tst_true is true */ /* !_tst_hit&_tst_true */ THREE #endif' EXEC -r -s posix - t.iffe EXEC -r - t.iffe INPUT t.iffe $'_tst_false = ( 0 ) _tst_true = ( 1 ) exp _tst_hit !_tst_true { ONE } exp _tst_hit !_tst_hit&_tst_false pass{ cat < ok */ #define _tst_true 1 /* ( 1 ) is true */ #endif' EXEC -r -s posix - t.iffe EXEC -r - t.iffe INPUT t.iffe $'_tst_false = ( 0 ) _tst_true = ( 1 ) exp _tst_hit !_tst_false { ONE } exp _tst_hit !_tst_hit&&_tst_true pass{ cat < ok */ #define _tst_true 1 /* ( 1 ) is true */ #define _tst_hit 1 /* !_tst_false is true */ /* !_tst_false */ ONE #endif' EXEC -r -s posix - t.iffe EXEC -r - t.iffe INPUT t.iffe $'_tst_false = ( 0 ) _tst_true = ( 1 ) exp _tst_hit !_tst_true { ONE } exp _tst_hit !_tst_hit&&_tst_true pass{ cat < ok */ #define _tst_true 1 /* ( 1 ) is true */ #define _tst_hit 1 /* !_tst_hit&&_tst_true is true */ TWO 0 1 #endif' EXEC -r -s posix - t.iffe EXEC -r - t.iffe INPUT t.iffe $'_tst_false = ( 0 ) _tst_true = ( 1 ) exp _tst_hit !_tst_true { ONE } exp _tst_hit !_tst_hit&&_tst_false pass{ cat < ok */ #define _tst_true 1 /* ( 1 ) is true */ #define _tst_hit 1 /* !_tst_hit&&_tst_true is true */ /* !_tst_hit&&_tst_true */ THREE #endif' EXEC -r -s posix - t.iffe EXEC -r - t.iffe INPUT t.iffe $'_tst_false = ( 0 ) _tst_true = ( 1 ) exp _tst_hit !_tst_true { ONE } exp _tst_hit !_tst_hit&&_tst_false pass{ cat < ok */ #define _tst_true 1 /* ( 1 ) is true */ #endif' EXEC -r -s posix - t.iffe EXEC -r - t.iffe INPUT t.iffe $'_tst_false = ( 0 ) _tst_true = ( 1 ) if ( ! _tst_false ) { ONE } elif ( _tst_true ) pass{ cat < ok */ #define _tst_true 1 /* ( 1 ) is true */ ONE #endif' EXEC -r -s posix - t.iffe EXEC -r - t.iffe INPUT t.iffe $'_tst_false = ( 0 ) _tst_true = ( 1 ) if ( ! _tst_true ) { ONE } elif ( _tst_true ) pass{ cat < ok */ #define _tst_true 1 /* ( 1 ) is true */ TWO #endif' EXEC -r -s posix - t.iffe EXEC -r - t.iffe INPUT t.iffe $'_tst_false = ( 0 ) _tst_true = ( 1 ) if ( ! _tst_true ) { ONE } elif ( _tst_false ) pass{ cat < ok */ #define _tst_true 1 /* ( 1 ) is true */ THREE #endif' EXEC -r -s posix - t.iffe EXEC -r - t.iffe INPUT t.iffe $'_tst_false = ( 0 ) _tst_true = ( 1 ) if ( ! _tst_true ) yes{ typedef struct { int dd_fd; /* file descriptor */ } DIR; }end endif' OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _REGRESS #define _REGRESS 1 #define _sys_types 1 /* #include ok */ #define _tst_true 1 /* ( 1 ) is true */ #endif' EXEC -r -s posix - t.iffe EXEC -r - t.iffe INPUT t.iffe $'_tst_false = ( 0 ) _tst_true = ( 1 ) if ( ! _tst_true ) { typedef struct { int dd_fd; /* file descriptor */ } DIR; } else { OK } endif' OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _REGRESS #define _REGRESS 1 #define _sys_types 1 /* #include ok */ #define _tst_true 1 /* ( 1 ) is true */ OK #endif' EXEC -r -s posix - t.iffe EXEC -r - t.iffe INPUT t.iffe $'_tst_false = ( 0 ) _tst_true = ( 1 ) if ( ! _tst_true ) { typedef struct { int dd_fd; /* file descriptor */ }; } else { OK } endif' EXEC -r -s posix - t.iffe TEST 10 'exp details' EXEC -r -v - t.iffe INPUT t.iffe $'_str = "string" _hdr =
_aaa = ( 0 ) _zzz = ( 1 ) ( _str ) ( ! _str ) ( _hdr ) ( ! _hdr ) ( _aaa ) ( ! _aaa ) ( _zzz ) ( ! _zzz )' OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _REGRESS #define _REGRESS 1 #define _sys_types 1 /* #include ok */ #define _str "string" #define _hdr
#define _zzz 1 /* ( 1 ) is true */ #endif' ERROR - $'iffe: test: is sys/types.h a header ... yes iffe: test: is ( 0 ) true ... no iffe: test: is ( 1 ) true ... yes iffe: test: is ( _str ) true ... yes iffe: test: is ( ! _str ) true ... no iffe: test: is ( _hdr ) true ... yes iffe: test: is ( ! _hdr ) true ... no iffe: test: is ( _aaa ) true ... no iffe: test: is ( ! _aaa ) true ... yes iffe: test: is ( _zzz ) true ... yes iffe: test: is ( ! _zzz ) true ... no' EXEC -r -v -s posix - t.iffe TEST 11 'set [no]define' EXEC -r -v - t.iffe INPUT t.iffe $'set nodefine mem stat.st_mtime sys/types.h sys/stat.h set define mem stat.st_mode sys/types.h sys/stat.h if ( _mem_st_mtime_stat ) { 1 } endif if ( _mem_st_mode_stat ) { 2 } endif' OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _REGRESS #define _REGRESS 1 #define _mem_st_mode_stat 1 /* st_mode is a member of struct stat */ 1 2 #endif' ERROR - $'iffe: test: is sys/types.h a header ... yes iffe: test: is sys/stat.h a header ... yes iffe: test: is stat a type or typedef ... no iffe: test: is st_mtime a member of struct stat ... yes iffe: test: is st_mode a member of struct stat ... yes iffe: test: is ( _mem_st_mtime_stat ) true ... yes iffe: test: is ( _mem_st_mode_stat ) true ... yes' EXEC -r -v -s posix - t.iffe TEST 12 'non-opaque mem' EXEC -r -v - mem OPAQUE -I. t.h INPUT t.h $'typedef struct opaque OPAQUE;' OUTPUT - $'/* : : generated by iffe version 1995-03-19 : : */ #ifndef _REGRESS #define _REGRESS 1 #define _sys_types 1 /* #include ok */ #define _hdr_t 1 /* #include ok */ #endif' ERROR - $'iffe: test: is sys/types.h a header ... yes iffe: test: is t.h a header ... yes iffe: test: is OPAQUE a type or typedef ... no iffe: test: is struct OPAQUE a non-opaque struct ... no' EXEC -r -v - mem NONOPAQUE -I. t.h INPUT t.h $'struct nonopaque { int pad; }; typedef struct nonopaque NONOPAQUE;' OUTPUT - $'/* : : generated by iffe version 1995-03-19 : : */ #ifndef _REGRESS #define _REGRESS 1 #define _sys_types 1 /* #include ok */ #define _hdr_t 1 /* #include ok */ #define _mem_NONOPAQUE 1 /* NONOPAQUE is a non-opaque struct */ #endif' ERROR - $'iffe: test: is sys/types.h a header ... yes iffe: test: is t.h a header ... yes iffe: test: is NONOPAQUE a type or typedef ... yes iffe: test: is NONOPAQUE a non-opaque struct ... yes' TEST 13 'key states' EXEC -r -v - t.iffe INPUT t.iffe $'key int key const = key foo key bar = key aha = huh = int key chr = char = int' OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _REGRESS #define _REGRESS 1 #define _sys_types 1 /* #include ok */ #define _key_int 1 /* int is a reserved keyword */ #define _key_const 1 /* const is a reserved keyword */ #define bar /* default for reserved keyword bar */ #define aha int /* default for reserved keyword aha */ #define _key_char 1 /* char is a reserved keyword */ #define chr char /* alternate for reserved keyword chr */ #endif' ERROR - $'iffe: test: is sys/types.h a header ... yes iffe: test: is int a reserved keyword ... yes iffe: test: is const a reserved keyword ... yes iffe: test: is foo a reserved keyword ... no iffe: test: is bar a reserved keyword ... no iffe: test: is aha a reserved keyword ... no iffe: test: is huh a reserved keyword ... no iffe: test: is chr a reserved keyword ... no iffe: test: is char a reserved keyword ... yes' EXEC -r -v -s posix - t.iffe EXEC -u -r -v - t.iffe OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _REGRESS #define _REGRESS 1 #define _sys_types 1 /* #include ok */ #define _key_int 1 /* int is a reserved keyword */ #define _key_const 1 /* const is a reserved keyword */ #undef _key_foo /* foo is not a reserved keyword */ #undef _key_bar /* bar is not a reserved keyword */ #define bar /* default for reserved keyword bar */ #undef _key_huh /* huh is not a reserved keyword */ #define aha int /* default for reserved keyword aha */ #define _key_char 1 /* char is a reserved keyword */ #define chr char /* alternate for reserved keyword chr */ #endif' EXEC -u -r -v -s posix - t.iffe EXEC -a -r -v - t.iffe OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _REGRESS #define _REGRESS 1 #define _sys_types 1 /* #include ok */ #define _key_int 1 /* int is a reserved keyword */ #define _key_const 1 /* const is a reserved keyword */ #define _key_foo 0 /* foo is not a reserved keyword */ #define _key_bar 0 /* bar is not a reserved keyword */ #define bar /* default for reserved keyword bar */ #define _key_huh 0 /* huh is not a reserved keyword */ #define aha int /* default for reserved keyword aha */ #define _key_char 1 /* char is a reserved keyword */ #define chr char /* alternate for reserved keyword chr */ #endif' EXEC -a -r -v -s posix - t.iffe EXEC -C -r -v - t.iffe OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _REGRESS #define _REGRESS 1 #define HAVE_SYS_TYPES_H 1 /* #include ok */ #define HAVE_INT_RESERVED 1 /* int is a reserved keyword */ #define HAVE_CONST_RESERVED 1 /* const is a reserved keyword */ #undef HAVE_FOO_RESERVED /* foo is not a reserved keyword */ #undef HAVE_BAR_RESERVED /* bar is not a reserved keyword */ #define bar /* default for reserved keyword bar */ #undef HAVE_HUH_RESERVED /* huh is not a reserved keyword */ #define aha int /* default for reserved keyword aha */ #define HAVE_CHAR_RESERVED 1 /* char is a reserved keyword */ #define chr char /* alternate for reserved keyword chr */ #endif' EXEC -C -r -v -s posix - t.iffe TEST 14 'inc file' EXEC -r -v - t.iffe INPUT t.iffe $'inc t_lib.h if ( bar_foo ) { #define all 1 } elif ( _foo_bar ) { #define some 1 } endif' INPUT t_lib.h '#define bar_foo ALL #define _foo_bar SOME' OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _REGRESS #define _REGRESS 1 #define _sys_types 1 /* #include ok */ #define some 1 #endif' ERROR - $'iffe: test: is sys/types.h a header ... yes iffe: test: is ( bar_foo ) true ... no iffe: test: is ( _foo_bar ) true ... yes' EXEC -r -v - t.iffe INPUT t.iffe $'inc t_lib.h . if ( bar_foo ) { #define all 1 } elif ( _foo_bar ) { #define ok 1 } endif' OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _REGRESS #define _REGRESS 1 #define _sys_types 1 /* #include ok */ #define all 1 #endif' ERROR - $'iffe: test: is sys/types.h a header ... yes iffe: test: is ( bar_foo ) true ... yes' EXEC -r -v - t.iffe INPUT t.iffe $'inc t_lib.h . ? if ( bar_foo ) { #define all 1 } elif ( _foo_bar ) { #define ok 1 } endif' ERROR - $'iffe: test: is sys/types.h a header ... yes iffe: t.iffe:1: warning: ?: operands ignored iffe: test: is ( bar_foo ) true ... yes' EXEC -r -v - t.iffe INPUT t.iffe $'inc foo_lib.h' OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _REGRESS #define _REGRESS 1 #define _sys_types 1 /* #include ok */' ERROR - $'iffe: test: is sys/types.h a header ... yes iffe: t.iffe:1: foo_lib.h: file not found' EXIT 1 EXEC -r -v - t.iffe INPUT t.iffe $'inc' ERROR - $'iffe: test: is sys/types.h a header ... yes iffe: t.iffe:1: path expected' TEST 15 'KnR compatibility' EXEC -r -v - t.iffe INPUT t.iffe $' if ( 1 ) { #define all 1 } endif if ( 2 ) { #define some 1 } endif cat{ #define a 1 #define b 2 #define c 3 #define d 4 }end' #define _foo_bar SOME' OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _REGRESS #define _REGRESS 1 #define _sys_types 1 /* #include ok */ #define some 1 #endif' OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _REGRESS #define _REGRESS 1 #define _sys_types 1 /* #include ok */ #define all 1 #define some 1 #define a 1 #define b 2 #define c 3 #define d 4 #endif' ERROR - $'iffe: test: is sys/types.h a header ... yes iffe: test: is ( 1 ) true ... yes iffe: test: is ( 2 ) true ... yes iffe: test: cat{ ... }end ... yes' EXEC -r -v -s posix - t.iffe TEST 16 '{ define extern include print }' EXEC -r -v - t.iffe INPUT t.iffe $' print /* test header */ header stdio.h define EOF -1 define FoobaR (a,b) ((a)+(b)) define FoomaC -1 extern fopen FILE* (char*, char*) extern BarfoO struct barfoo* (int) extern Tab_lE struct barfoo* [10]' OUTPUT - $'/* test header */ /* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _REGRESS #define _REGRESS 1 #define _sys_types 1 /* #include ok */ #include #define FoobaR(a,b) ((a)+(b)) #define FoomaC -1 extern struct barfoo* BarfoO(int); extern struct barfoo* Tab_lE[10]; #endif' ERROR - $'iffe: test: is sys/types.h a header ... yes iffe: test: is stdio.h a header ... yes iffe: test: is EOF a macro ... yes iffe: test: is FoobaR a macro ... no iffe: test: is FoomaC a macro ... no iffe: test: is fopen a symbol that needs a prototype ... no iffe: test: is BarfoO a symbol that needs a prototype ... yes iffe: test: is Tab_lE a symbol that needs a prototype ... yes' TEST 17 'features/* => FEATURE/*' EXEC -r -v run features/stdio INPUT features/stdio $'header stdio.h' OUTPUT FEATURE/stdio $'/* : : generated from features/stdio by iffe version 1995-03-19 : : */ #ifndef _REGRESS #define _REGRESS 1 #define _sys_types 1 /* #include ok */ #include #endif' ERROR - $'iffe: test: is sys/types.h a header ... yes iffe: test: is stdio.h a header ... yes' TEST 18 'api + ver' EXEC -r -v - t.iffe INPUT t.iffe $'iff api ver foo 20100606 ver bar 19840919 api foo 19991231 dis dat tother api foo 20100601 dat api foo 20100606 dis api bar 19991231 moe larry shemp api bar 20020202 curly api bar 20030303 shemp api bar 20040404 joe_b api bar 20050505 joe_d ' OUTPUT - $'/* : : generated from t.iffe by iffe version 1995-03-19 : : */ #ifndef _api_H #define _api_H 1 #define _sys_types 1 /* #include ok */ #define FOO_VERSION 20100606 #define BAR_VERSION 19840919 #define FOOAPI(rel) ( _BLD_foo || !_API_foo || _API_foo >= rel ) #if !defined(_API_foo) && defined(_API_DEFAULT) #define _API_foo _API_DEFAULT #endif #if FOOAPI(20100601) #undef dat #define dat dat_20100601 #elif _API_foo >= 19991231 #undef dat #define dat dat_19991231 #endif #if FOOAPI(20100606) #undef dis #define dis dis_20100606 #elif _API_foo >= 19991231 #undef dis #define dis dis_19991231 #endif #if FOOAPI(19991231) #undef tother #define tother tother_19991231 #endif #define _API_foo_MAP "dat_20100601 dat_19991231 dis_20100606 dis_19991231 tother_19991231" #define BARAPI(rel) ( _BLD_bar || !_API_bar || _API_bar >= rel ) #if !defined(_API_bar) && defined(_API_DEFAULT) #define _API_bar _API_DEFAULT #endif #if BARAPI(20020202) #undef curly #define curly curly_20020202 #endif #if BARAPI(20040404) #undef joe_b #define joe_b joe_b_20040404 #endif #if BARAPI(20050505) #undef joe_d #define joe_d joe_d_20050505 #endif #if BARAPI(19991231) #undef larry #define larry larry_19991231 #endif #if BARAPI(19991231) #undef moe #define moe moe_19991231 #endif #if BARAPI(20030303) #undef shemp #define shemp shemp_20030303 #elif _API_bar >= 19991231 #undef shemp #define shemp shemp_19991231 #endif #define _API_bar_MAP "curly_20020202 joe_b_20040404 joe_d_20050505 larry_19991231 moe_19991231 shemp_20030303 shemp_19991231" #endif' ERROR - $'iffe: test: is sys/types.h a header ... yes' ksh-1.0.10/src/cmd/INIT/intl.c000066400000000000000000000024611465301102200155620ustar00rootroot00000000000000/*********************************************************************** * * * This software is part of the ast package * * Copyright (c) 1994-2011 AT&T Intellectual Property * * Copyright (c) 2020-2023 Contributors to ksh 93u+m * * and is licensed under the * * Eclipse Public License, Version 2.0 * * * * A copy of the License is available at * * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html * * (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) * * * * Glenn Fowler * * Martijn Dekker * * Johnothan King * * * ***********************************************************************/ #ifndef gettext #include #endif int main(void) { gettext(0); return 0; } ksh-1.0.10/src/cmd/INIT/ld.hp.pa000077500000000000000000000002071465301102200157760ustar00rootroot00000000000000: hp.pa ld wrapper for reasonable warning defaults # @(#)ld.hp.pa (AT&T Labs Research) 1998-01-23 /bin/ld +s +vnocompatwarnings "$@" ksh-1.0.10/src/cmd/INIT/ldd.cygwin.i386000077500000000000000000000005641465301102200171320ustar00rootroot00000000000000#!/bin/env sh : cygwin.i386 ldd -- how many ways does this confirm the Windows bias? for f do case $f in *.exe) ;; *) f=$f.exe ;; esac p=$(type $f) case $p in *" not found"*) ;; *) p=${p##* } case $p in ?*) f=$p ;; esac ;; esac cygcheck $(cygpath -aw $f) | for w in $(sed -e 's/^[[:space:]]*//' -e '/^$/d' -e '/^Use /d') do cygpath -u "$w" done done ksh-1.0.10/src/cmd/INIT/ldd.darwin000077500000000000000000000000351465301102200164170ustar00rootroot00000000000000: Mac OS X ldd otool -L "$@" ksh-1.0.10/src/cmd/INIT/ldd.hp.pa000077500000000000000000000004611465301102200161440ustar00rootroot00000000000000: hp.pa ldd while : do case $# in 0) break ;; esac case $1 in -*|+*) ;; *) break ;; esac shift done trap ':' 15 for cmd do case $# in 1) ;; *) echo $cmd: ;; esac _HP_DLDOPTS=-ldd "$cmd" < /dev/null 2> /dev/null | sort -u # chatr "$cmd" | # sed -e '/^[ ]*dynamic[ ][ ]*/!d' -e 's// /' done ksh-1.0.10/src/cmd/INIT/ldd.ibm.risc000077500000000000000000000003171465301102200166440ustar00rootroot00000000000000: ibm.risc ldd case $# in 1) header=0 ;; *) header=1 ;; esac for file do case $header in 1) echo "$file:" header=2 ;; 2) echo echo "$file:" ;; esac dump -H "$file" | sed '1,/\*\*\*Import/d' done ksh-1.0.10/src/cmd/INIT/ldd.lynxos000077500000000000000000000000671465301102200164740ustar00rootroot00000000000000elflook -L "$@" | sed -e '/^NEEDED:/!d' -e 's/.*: *//' ksh-1.0.10/src/cmd/INIT/ldd.mvs.390000077500000000000000000000003721465301102200162560ustar00rootroot00000000000000: mvs.390 ldd case $# in 1) header=0 ;; *) header=1 ;; esac for file do case $header in 1) echo "$file:" header=2 ;; 2) echo echo "$file:" ;; esac strings $file | sed -e '/\<[[:lower:]][[:alnum:]]*\.dll\>/!d' -e 's/^/ /' | sort -u done ksh-1.0.10/src/cmd/INIT/ldd.sgi000077500000000000000000000000361465301102200157160ustar00rootroot00000000000000: sgi.mips ldd odump -Dl "$@" ksh-1.0.10/src/cmd/INIT/m.c000066400000000000000000000035601465301102200150510ustar00rootroot00000000000000/*********************************************************************** * * * This software is part of the ast package * * Copyright (c) 1994-2011 AT&T Intellectual Property * * Copyright (c) 2020-2024 Contributors to ksh 93u+m * * and is licensed under the * * Eclipse Public License, Version 2.0 * * * * A copy of the License is available at * * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html * * (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) * * * * Glenn Fowler * * Martijn Dekker * * Johnothan King * * * ***********************************************************************/ /* * -lm test #1 * * This program is compiled and linked by mkreq-maplib.sh via INIT/Mamfile * but never actually run. It is only used to check if linking succeeds * without or with -lm. * * For that test to work correctly, we must work around compiler optimization. * The rand() call is to stop the result from being considered known at * compile time, which would cause modern compilers to optimize out the probe * calls, which would in turn cause linking to succeed where it shouldn't. */ #include #include int main(void) { double f = (double)rand(); int r = 0; r |= sin(f) != 0.0; r |= fmod(f, 11.0) != 0.0; return r; } ksh-1.0.10/src/cmd/INIT/m2.c000066400000000000000000000036161465301102200151350ustar00rootroot00000000000000/*********************************************************************** * * * This software is part of the ast package * * Copyright (c) 1994-2011 AT&T Intellectual Property * * Copyright (c) 2020-2024 Contributors to ksh 93u+m * * and is licensed under the * * Eclipse Public License, Version 2.0 * * * * A copy of the License is available at * * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html * * (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) * * * * Glenn Fowler * * Martijn Dekker * * Johnothan King * * * ***********************************************************************/ /* * -lm test #2 * * This program is compiled and linked by mkreq-maplib.sh via INIT/Mamfile * but never actually run. It is only used to check if linking succeeds * without or with -lm. * * For that test to work correctly, we must work around compiler optimization. * The rand() call is to stop the result from being considered known at * compile time, which would cause modern compilers to optimize out the probe * calls, which would in turn cause linking to succeed where it shouldn't. */ #include #include int main(void) { double value = (double)rand(); int exp = 0; int r = 0; r |= ldexp(value, exp) != 0; r |= frexp(value, &exp) != 0; return r; } ksh-1.0.10/src/cmd/INIT/m3.c000066400000000000000000000036341465301102200151360ustar00rootroot00000000000000/*********************************************************************** * * * This software is part of the ast package * * Copyright (c) 1994-2011 AT&T Intellectual Property * * Copyright (c) 2020-2024 Contributors to ksh 93u+m * * and is licensed under the * * Eclipse Public License, Version 2.0 * * * * A copy of the License is available at * * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html * * (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) * * * * Glenn Fowler * * Martijn Dekker * * Johnothan King * * * ***********************************************************************/ /* * -lm test #3 * * This program is compiled and linked by mkreq-maplib.sh via INIT/Mamfile * but never actually run. It is only used to check if linking succeeds * without or with -lm. * * For that test to work correctly, we must work around compiler optimization. * The rand() call is to stop the result from being considered known at * compile time, which would cause modern compilers to optimize out the probe * calls, which would in turn cause linking to succeed where it shouldn't. */ #include #include int main(void) { long double value = (long double)rand(); int exp = 0; int r = 0; r |= ldexpl(value, exp) != 0; r |= frexpl(value, &exp) != 0; return r; } ksh-1.0.10/src/cmd/INIT/m4.c000066400000000000000000000035021465301102200151310ustar00rootroot00000000000000/*********************************************************************** * * * This software is part of the ast package * * Copyright (c) 1994-2011 AT&T Intellectual Property * * Copyright (c) 2020-2024 Contributors to ksh 93u+m * * and is licensed under the * * Eclipse Public License, Version 2.0 * * * * A copy of the License is available at * * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html * * (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) * * * * Glenn Fowler * * Martijn Dekker * * Johnothan King * * * ***********************************************************************/ /* * -lm test #4 * * This program is compiled and linked by mkreq-maplib.sh via INIT/Mamfile * but never actually run. It is only used to check if linking succeeds * without or with -lm. * * For that test to work correctly, we must work around compiler optimization. * The rand() call is to stop the result from being considered known at * compile time, which would cause modern compilers to optimize out the probe * calls, which would in turn cause linking to succeed where it shouldn't. */ #include #include int main(void) { double value = (double)rand(); return isnan(value); } ksh-1.0.10/src/cmd/INIT/m5.c000066400000000000000000000035151465301102200151360ustar00rootroot00000000000000/*********************************************************************** * * * This software is part of the ast package * * Copyright (c) 1994-2011 AT&T Intellectual Property * * Copyright (c) 2020-2024 Contributors to ksh 93u+m * * and is licensed under the * * Eclipse Public License, Version 2.0 * * * * A copy of the License is available at * * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html * * (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) * * * * Glenn Fowler * * Martijn Dekker * * Johnothan King * * * ***********************************************************************/ /* * -lm test #5 * * This program is compiled and linked by mkreq-maplib.sh via INIT/Mamfile * but never actually run. It is only used to check if linking succeeds * without or with -lm. * * For that test to work correctly, we must work around compiler optimization. * The rand() call is to stop the result from being considered known at * compile time, which would cause modern compilers to optimize out the probe * calls, which would in turn cause linking to succeed where it shouldn't. */ #include #include int main(void) { long double value = (long double)rand(); return isnanl(value); } ksh-1.0.10/src/cmd/INIT/m6.c000066400000000000000000000035421465301102200151370ustar00rootroot00000000000000/*********************************************************************** * * * This software is part of the ast package * * Copyright (c) 1994-2011 AT&T Intellectual Property * * Copyright (c) 2020-2024 Contributors to ksh 93u+m * * and is licensed under the * * Eclipse Public License, Version 2.0 * * * * A copy of the License is available at * * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html * * (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) * * * * Glenn Fowler * * Martijn Dekker * * Johnothan King * * * ***********************************************************************/ /* * -lm test #6 * * This program is compiled and linked by mkreq-maplib.sh via INIT/Mamfile * but never actually run. It is only used to check if linking succeeds * without or with -lm. * * For that test to work correctly, we must work around compiler optimization. * The rand() call is to stop the result from being considered known at * compile time, which would cause modern compilers to optimize out the probe * calls, which would in turn cause linking to succeed where it shouldn't. */ #define _ISOC99_SOURCE 1 #include #include int main(void) { double value = -((double)rand()); return !signbit(value); } ksh-1.0.10/src/cmd/INIT/make.probe000066400000000000000000001327111465301102200164200ustar00rootroot00000000000000: ### this script contains archaic constructs that work with all sh variants ### # Glenn Fowler # AT&T Research # # @(#)make.probe (ksh 93u+m) 2024-03-23 # # C probe for make # # NOTE: C.probe must be included or .'d here # cc_dll_def=-D_BLD_DLL probe_ar_arflags="-Xany" probe_arflags="-xar" probe_ccs="strip size nm ld ar" # longest to shortest probe_debug="-g" probe_dll="'-G 0' -Wc,dll,exportall,longname,rent -Wc,exportall -dynamic $cc_dll_def" probe_export_dynamic="-rdynamic -export-dynamic -Wl,-export-dynamic -Wl,-E -bexpall -force_flat_namespace" probe_gcc_optimize="-Os" probe_gcc_version="*[Gg][Cc][Cc]*" probe_include_local="'-ignore-source-dir -iquote' -iquote -I-" probe_ldasneeded="-Wl,-as-needed -Wl,-no-as-needed" probe_ldlazy='-zlazyload -znolazyload -Wl,-zlazyload -Wl,-znolazyload' probe_ldlib="LD_LIBRARY_PATH LIBPATH LPATH" probe_ldmap="'-Wl,-M' '-Qoption ld -M' '-Wl,-m' '-m'" probe_ldorigin="-Wl,-z,origin" probe_ldrecord='-zrecord -zignore -Wl,-zrecord -Wl,-zignore' probe_ldrunpath="-Wl,-R, -R -Wl,-rpath, -L" probe_ldstrip="'-s -mr' -Wl,-s" probe_lib="a lib" probe_lib_append="/usr/lib/pa1.1" probe_lib_all_undef="-all -notall -all -none -Bwhole-archive -Bno-whole-archive -whole-archive -no-whole-archive -Wl,-whole-archive -Wl,-no-whole-archive -all_load '' -Wl,-zallextract -Wl,-zdefaultextract +forceload +noforceload" probe_lib_multiple="-Wl,-zmuldefs" probe_libdir="shlib lib" probe_nmflags="'' -p -B" probe_optimize="-Os -O" probe_pic="-Kpic -KPIC -fpic -fPIC -pic -PIC +z +Z" probe_no_protect="'-fno-stack-protector -fno-stack-protector-all' -GS-" probe_no_strict_aliasing="-fno-strict-aliasing" probe_readonly="-R -Krodata -xMerge -Wa,-r" probe_shared="'' -G -b -c -shared -Wl,dll" probe_shared_name="-Wl,-soname= -h" probe_shared_registry='"-update_registry $probe_shared_registry_file"' probe_shared_registry_file='registry.ld' probe_shared_registry_path="\$(LIBDIR)/$probe_shared_registry_file" probe_strict="'-ansi -pedantic' '-ansi -strict' -strict -ansi" probe_stripflags="'-f -s' -f -s" probe_unresolved="'-expect_unresolved \"*\"'" probe_warn="-Wall -fullwarn -w3 '-A -A' +w1" echo '#pragma pp:version' > libpp.$src echo '#define dDflag on' > dDflag.$src echo 'int main(void){return 0;}' > doti.$src echo 'int code(void){return 0;} int main(void){return code();}' > export.$src echo '#include ' > imstd.$src echo '#include "_i_.h"' > imusr.$src echo 'int x;' > _i_.h mkdir im echo '(' > im/stdio.h echo '#include "implc_x.h" int main(void){f(1);return 0;}' > implc.$src echo 'template void f(T){}' > implc_x.$src echo 'template void f(T);' > implc_x.h echo 'extern int NotalL(void) { return 0; }' > notall.$src echo '#include extern int i; int i = 1; extern int f(void) { return !i; } int main(void) { FILE* fp=stdin; return f(); }' > pic.$src echo 'int prefix(void){return 0;}' > prefix.$src echo 'template int gt(T a, T b); template int gt(T a, T b) { return a > b; } int main (void) { return gt(2,1); }' > ptr.$src echo 'int main(void){return 0;}' > require.$src echo '#if mips && !sgi || __CYGWIN__ || __HAIKU__ || __APPLE__ ( /* some systems choke on this probe */ #else #if test_const #define CONST const #else #define CONST #endif CONST char x[]={1,2,3,4,5,6,7,8,9,0}; int main(void){*(char*)x=0; return x[0];} #endif' > readonly.$src echo 'extern int sfclose(void); extern int ShareD(void) { return sfclose(); }' > shared.$src echo '#define g(a,b) a ## b volatile int a; const int g(x,y)=1; extern int c(int);' > stdc.$src echo 'extern int f(void); int main(void) { return f(); }' > sovmain.$src echo 'int f(void) { return 0; }' > sovlib.$src echo '#include int i; int main(void){int j;j = i * 10;return j;}' > strip.$src echo 'template void f(T){} int main(void){f(1);return 0;}' > toucho.$src echo 'extern type call(int); int main(void) { call(0); return 0; }' > tstlib.$src echo 'int main(void){return 0;}' > warn.$src echo 'int f(void){return 0;}' > warn1.$src echo 'int f(void){}' > warn2.$src echo 'int f(void){int i; return 0;}' > warn3.$src echo 'int f(void){int i; return i;}' > warn4.$src echo 'int f(void){return g();}' > warn5.$src warn_enum="1 2 3 4 5" chmod -w *.$src ar_arflags= arflags= cc_dll= cc_pic= cc_PIC= dDflag= debug= dialect= dll_dir='$(LIBDIR)' dll_libraries= dll_variants= doti= exectype= export_dynamic= gnu= implicitc= include_local= ldasneeded= lddynamic= ldlazy= ldnolazy= ldnorecord= ldorigin= ldrecord= ldrunpath= ldscript= ldstatic= ldstrip= Lflag= lib_dll= lib_all= lib_undef= libpath= libpp= makeoptions= nmedit= nmflags= no_protect= no_strict_aliasing= optimize= prefix_archive=lib prefix_dynamic= prefix_shared=lib ptrcopy= ptrimplicit= ptrmkdir= readonly= repository= require= runpath= shared= shared_name= shared_registry= soversion= stdc= strict= stripflags= symprefix= toucho= warn= set $probe_lib lib=$1 d= for f in $stdinclude $usrinclude do case $f in -I*) ;; *) d="$d $f" ;; esac done stdinclude=$d set x $cc cc_dir=`echo $2 | sed -e 's,/*[^/]*$,,'` for c in $probe_ccs do if $executable $cc_dir/$c then x=$cc_dir/$c else x=$c fi eval $c='$x' done ld_dir= rm -f doti.$obj if $cc -c doti.$src then eval set x $probe_verbose shift for o do $cc $o doti.$obj $cc $o doti.$obj -lF0oB@r done 2>&1 | sed -e 's/^[+ ]*//' -e 's/[ ].*//' -e '/^\//!d' -e 's/:$//' -e '/ld[a-zA-Z0-9.]*$/!d' -e 's,///*,/,g' > t for i in `cat t` do rm -f t.$obj if test -x $i && $i -r -o t.$obj doti.$obj && test -f t.$obj then case $ld in ld) ld=$i ;; esac ld_dir=`echo $i | sed 's,/[^/]*$,,'` break fi done fi IFS=: set x $PATH IFS=$ifs path=$* m= for c in $probe_ccs do eval o='$'$c case $o in $c) ;; *) continue ;; esac C='${c}' for x in $cc_dir $ld_dir do cd $x for p in "${C}" "${C}[!a-zA-Z]*" "*[!a-zA-Z]${C}" "*[!a-zA-Z]${C}[!a-zA-Z]*" do eval set x $p case $# in 2) if $executable $2 then case $2 in *$c*$c*);; *) m=$p break 3 ;; esac fi ;; esac done done done cd $tmpdir for c in $probe_ccs do eval o='$'$c case $o in $c) ;; *) continue ;; esac for x in $cc_dir $ld_dir do if $executable $x/$c then eval $c='$x/$c' continue 2 fi case $m in ?*) eval set x $x/$m case $# in 2) if $executable $2 then eval $c='$2' continue 2 fi ;; esac ;; esac done for x in $path do if $executable $x/$c then eval $c='$x/$c' break fi done done dld=$cc rm -f dynamic.$exe if $cc -o dynamic.$exe dynamic.$obj && $executable dynamic.$exe then mkdir mylib echo > mylib/libc.$lib eval set x $probe_ldlib while : do shift case $# in 0) break ;; esac rm -f dynamic.$exe if eval $1=./mylib '$'cc -o dynamic.$exe dynamic.$obj then : else libpath=$1 break fi done fi test `$cc -E libpp.$src | grep -c '^#pragma pp:version "libpp '` -eq 1 && libpp=1 $cc -E doti.$src > doti.i && $cc -c doti.i && test -s doti.$obj && doti=1 if $cc -c imusr.$src then eval set x $probe_include_local while : do shift case $# in 0) break ;; esac if $cc -c $1 imusr.$src then : "$1 should skip \"_i_.h\" in ." elif $cc -c imstd.$src then if $cc -c -Iim imstd.$src then : '-Idir should find in dir' elif $cc -c $1 -Iim imstd.$src then : "$1 -Idir should find in dir" elif $cc -c -Iim $1 imstd.$src then include_local=$1 break else : "-Idir $1 should skip in dir" fi else : should find stdio.h fi done else : 'should find "_i_.h" in .' fi if $cc -c pic.$src 2>e then e=`wc -l e` s=`$size pic.$obj; wc pic.$obj` eval set x $probe_pic shift while : do case $# in 0|1) break ;; esac pic=$1 shift PIC=$1 shift rm -f pic.$obj $cc $pic -c pic.$src 2>e && test -f pic.$obj || continue $cc $pic -o pic.$exe pic.$obj && test -f pic.$exe || { rm -f pic.$exe $cc -o pic.$exe pic.$obj && test -f pic.$exe && continue } case `wc -l e` in $e) ;; *) continue ;; esac case $pic in ???*) m=`echo " $pic" | sed -e 's/^ [-+]//g' -e 's/./-& /g' -e 's/[-+] //g'` rm -f pic.$obj pic1.$exe if $cc $m -c pic.$src 2>e && test -f pic.$obj && $cc -o pic1.$exe pic.$obj && test -f pic1.$exe then case `wc -l e` in $e) cc_pic=$m break ;; esac fi cc_pic=$pic break ;; *) case `$size pic.$obj; wc pic.$obj` in $s) ;; *) cc_pic=$pic break ;; esac ;; esac done # this works around gcc 2.95 sun4 -fpic a.out core dump after exit case $hosted:$cc_pic in 1:?*) if ./pic.$exe then # this catches lynxos.ppc gcc that dumps -fpic and not -mshared echo 'static int* f(void) { static int v; return &v; } int main(void) { f(); return 0; }' > picok.$src $cc $cc_pic -o picok.$exe picok.$src && ./picok.$exe || cc_pic= else cc_pic= fi ;; esac case $cc_pic in ?*) rm -f pic.$obj if $cc $PIC -c pic.$src 2>e && test -f pic.$obj then cc_PIC=$PIC else cc_PIC=$cc_pic fi ;; *) eval set x $probe_dll while : do shift case $# in 0) break ;; esac rm -f pic.$obj pic.$exe $cc $1 -c pic.$src 2>e && test -f pic.$obj || continue $cc $1 -o pic.$exe pic.$obj && test -f pic.$exe || { rm -f pic.$exe $cc -o pic.$exe pic.$obj && test -f pic.$exe && continue } case $1 in -Wc,*exportall*) # get specific since SGI gets this far too rm -f pic.$exe pic.x $cc -Wl,dll -o pic.$exe pic.$obj || continue test -f pic.$exe || continue test -f pic.x || continue cc_dll="-D_SHARE_EXT_VARS $1" so=.x sd=.dll dld=$cc shared=-Wl,dll prefix_shared= probe_sd= probe_shared= #unused# lddynamic=-Bdynamic #unused# ldstatic=-Bstatic lib_dll=SYMBOL break ;; esac case `wc -l e` in $e) cc_dll=$1 break ;; esac done ;; esac fi $cc -E -dD dDflag.$src > t case `grep '#define[ ][ ]*dDflag[ ][ ]*on' t` in ?*) dDflag=1 ;; esac case `grep '#define.*_GNUC_' t` in ?*) gnu=1 ;; esac $cc -c stdc.$src && stdc=1 if $cc -c pic.$src then eval set x $probe_nmflags while : do shift case $# in 0) break ;; esac case `$nm $1 pic.$obj | grep -c '[0123456789][ ][ ]*T[ ][ ]*[_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]'` in 0) ;; *) nmflags=$1 break ;; esac done case $# in 0) case `$nm -gh pic.$obj | grep -c '|\.*[TtDdBbC][EeAaSsOo][XxTtSsMm]'` in 0) ;; *) nmflags=-gh nmedit="-e '/\.*[TtDdBbC][EeAaSsOo][XxTtSsMm]/!d' -e 's/[| ].*//'" ;; esac ;; *) nmedit="-e '/[ ]T[ ][ ]*[_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]/!d' -e 's/.*[ ]T[ ][ ]*//'" ;; esac fi if $cc -c doti.$src then eval set x $probe_stripflags while : do shift case $# in 0) break ;; esac if $strip $1 doti.$obj then stripflags=$1 break fi done fi rm -f export.$obj export.exe if $cc -c export.$src then lm= if $cc -o export.exe export.$obj -lm 2>e && lm=-lm || $cc -o export.exe export.$obj 2>e then z=`wc -c < export.exe; $size export.exe 2>/dev/null` eval set x $probe_export_dynamic while : do shift case $# in 0) break ;; esac rm -f export.exe if $cc -o export.exe $1 export.$obj $lm 2>f && $executable export.exe then y=`wc -c < export.exe; $size export.exe 2>/dev/null` case $y in $z) ;; *) if cmp -s e f then export_dynamic=$1 break fi ;; esac fi done fi fi rm -f export.$obj export.exe rm -f strip.exe if $cc -o strip.exe strip.$src then z=`wc -c < strip.exe` eval set x $probe_ldstrip while : do shift case $# in 0) break ;; esac rm -f strip.exe if $cc -o strip.exe $1 strip.$src then case `wc -c < strip.exe` in $z) ;; *) ldstrip=$1 break ;; esac fi done fi rm -f strip.exe strip.$obj if $cc -c strip.$src && $cc -o strip.exe strip.$obj 2>e then eval set x x $probe_ldlazy while : do shift shift case $# in 0) break ;; esac rm -f strip.$exe $cc -o strip.$exe $1 strip.$obj $2 2>f && test -f strip.$exe || continue cmp -s e f || continue ldlazy=$1 ldnolazy=$2 break done eval set x x $probe_ldrecord while : do shift shift case $# in 0) break ;; esac rm -f strip.$exe $cc -o strip.$exe $1 strip.$obj $2 2>f && test -f strip.$exe || continue cmp -s e f || continue ldrecord=$1 ldnorecord=$2 break done eval set x x $probe_ldasneeded while : do shift shift case $# in 0) break ;; esac rm -f strip.$exe $cc -o strip.$exe $1 strip.$obj $2 2>f && test -f strip.$exe || continue cmp -s e f || continue ldasneeded=$1 ldnoasneeded=$2 break done fi case $cc_dll:$cc_pic:$so:$dynamic:$static in ::::|$cc_dll_def::::) : last chance dynamic checks while : do echo '__declspec(dllexport) int fun(void) { return 0; }' > exp.$src if $cc -c $cc_dll_def exp.$src then rm -f xxx.dll xxx.lib if $cc -shared -Wl,--enable-auto-image-base -Wl,--out-implib=xxx.lib -o xxx.dll exp.$obj && test -f xxx.lib -a -f xxx.dll then : Cygwin cc_dll=$cc_dll_def dll_dir='$(BINDIR)' sd=.dll so=.dll.a ldscript=".def .exp .ign .res" lib_dll=option lib_all=-Wl,-whole-archive lib_undef=-Wl,-no-whole-archive dld=$cc shared='-shared -Wl,--enable-auto-image-base -Wl,--out-implib=$(<:N=*'$so')' prefix_dynamic=cyg prefix_shared=lib break fi fi break done ;; *) if $cc -c $cc_dll $cc_pic shared.$src && $cc -c $cc_dll $cc_pic notall.$src then for xx in "$cc" "$ld" do eval set x $probe_shared while : do shift case $# in 0) break ;; esac rm -f xxx$dll # UNDENT ... if $xx $1 -o xxx$dll shared.$obj 2>e && test -r xxx$dll then if test -s e && grep -E -i 'unknown|invalid|option' e > /dev/null then continue fi case `PATH=/bin:/usr/bin:$PATH file xxx$dll` in *lib*|*obj*|*shared*) ;; "") $executable xxx$dll || continue ;; *ELF*|*elf*) $executable xxx$dll || continue case `strings xxx$dll | sed -e 's,.*[ |],,' | sort -u | grep -E -i '^([._](dynamic|dynstr|dynsym))$'` in [012]) continue ;; esac ;; *archive*not*stripped*|*data*dynamic*not*stripped*) $executable xxx$dll || continue ;; *) continue ;; esac dld=$xx shared=$1 case $cc_dll in "") cc_dll=$cc_dll_def ;; esac eval set x x $probe_sd while : do shift shift case $# in [01]) break ;; esac rm -f xxx xxx$1 xxx$2 if $dld $shared -o xxx shared.$obj 2>e then if test -f xxx$1 -a \( -f xxx$2 -o "$cc_dll" = "$cc_dll_def" \) then sd=$1 so=$2 lddynamic=-Bdynamic ldstatic=-Bstatic break 2 elif test -f xxx -a -f xxx$2 then sd=$1 so=$2 break 2 else case $so in '') so=$1 ;; esac break fi fi done rm -f libxxx.$lib $ar cr libxxx.$lib shared.$obj ranlib libxxx.$lib eval set x x $probe_lib_all_undef rm -f xxx$dll if $dld $shared -o xxx$dll libxxx.$lib && test -r xxx$dll then if $nm $nmflags xxx$dll | grep ShareD then lib_dll=OPTION set x x fi fi while : do shift shift case $# in 0|1) break ;; esac rm -f xxx$dll if $dld $shared -o xxx$dll $1 libxxx.$lib $2 && test -r xxx$dll then if $nm $nmflags xxx$dll | grep ShareD then lib_dll=option lib_all=$1 lib_undef=$2 break fi fi case $2 in ?*) if $dld $shared -o xxx$dll $1 libxxx.$lib && test -r xxx$dll then if $nm $nmflags xxx$dll | grep ShareD then lib_dll=option lib_all=$1 break fi fi ;; esac done case $lib_dll in OPTION) lib_dll=option ;; option) case $lib_undef in "") rm -f libyyy.$lib $ar cr libyyy.$lib notall.$obj ranlib libyyy.$lib $cc -c prefix.$src eval set x x $probe_lib_all_undef while : do shift shift case $# in 0|1) break ;; esac rm -f xxx$dll if $dld $shared -o xxx$dll prefix.$obj $lib_all libxxx.$lib $2 libyyy.$lib && test -r xxx$dll then rm -f t $nm $nmflags xxx$dll > t case `grep -c ShareD t`:`grep -c NotalL t` in 0:*) ;; *:0) lib_undef=$2 break ;; esac fi done ;; esac case $lib_undef in "") eval set x $probe_lib_multiple rm -f libyyy.$lib cp libxxx.$lib libyyy.$lib rm -f xxx$dll if $dld $shared -o xxx$dll prefix.$obj $lib_all libxxx.$lib libyyy.$lib && test -r xxx$dll then : else while : do shift case $# in 0) break ;; esac rm -f xxx$dll if $dld $shared -o xxx$dll prefix.$obj $lib_all $1 libxxx.$lib libyyy.$lib && test -r xxx$dll then rm -f t $nm $nmflags xxx$dll > t case `grep -c ShareD t` in 0) ;; *) lib_all="$lib_all $1" break ;; esac fi done fi lib_dll=symbol ;; esac ;; *) lib_dll=symbol ;; esac case `cat e` in ?*) eval set x $probe_unresolved while : do shift case $# in 0) break ;; esac rm -f xxx$dll if eval '$dld $shared' $1 '-o xxx$dll shared.$obj 2>e && test -r xxx$dll' then case `cat e` in "") shared="$shared $1"; break ;; esac fi done ;; esac r= eval set x $probe_shared_registry while : do shift r=x$r case $# in 0) break ;; esac rm -f xxx$dll if eval \$dld \$shared -o xxx\$dll $1 shared.\$obj && test -r xxx$dll -a -r $probe_shared_registry_file then probe_shared_registry_file='$(CC.SHARED.REGISTRY.PATH)' eval set x $probe_shared_registry i= while : do shift i=x$i case $i in $r) break ;; esac done shared_registry=$1 fi done break 2 fi # ... INDENT done done fi case $so in ?*) rm -f xxx* if $dld $shared -g -o xxx shared.$obj 2>e then set x $probe_sdb while : do shift case $1 in 0) break ;; esac if test -f xxx$1 then sdb=$1 break fi done fi if $cc -c require.$src then p=' /usr/proberun/lib:/local/runprobe/lib ' eval set x $probe_ldrunpath while : do shift case $# in 0) break ;; esac rm -f require.exe if $cc -o require.exe $1"$p" require.$obj && grep -c /proberun/ require.exe >/dev/null && grep -c /runprobe/ require.exe > /dev/null then ldrunpath=$1 eval set x $probe_ldorigin while : do shift case $# in 0) break ;; esac rm -f origin.exe if $cc -o origin.exe $1 $ldrunpath'$ORIGIN' require.$obj then if ./origin.exe > /dev/null 2>&1 then ldorigin="$1 $ldrunpath"'\$ORIGIN/$(BINDIR:P=R=$(DLLDIR))' fi break fi done break fi done fi rm -f libxxx$so if $cc -c sovmain.$src && $cc -c $cc_dll $cc_pic sovlib.c && $dld $shared -o libxxx$so sovlib.$obj && $cc -o sovmain.$exe -L. sovmain.$obj -lxxx then rm -f sovmain.$exe mv libxxx$so libxxx$so.5.6 if $cc -o sovmain.$exe -L. sovmain.$obj -lxxx then soversion=1 fi fi rm -f doti.$obj std64=/lib64 lcl64=/usr/local/lib64 if test -d $std64 -a -d $lcl64 && $cc -c doti.$src then for i in `cd $lcl64; ls *$so 2>/dev/null | sed 's/lib\([^.]*\).*/\1/'` do if $cc -o runpath.$exe doti.$obj -l$i >/dev/null 2>&1 then LD_LIBRARY_PATH= ./runpath.$exe >/dev/null 2>&1 && continue if LD_LIBRARY_PATH=$lcl64 ./runpath.$exe >/dev/null 2>&1 then runpath=$lcl64 break elif LD_LIBRARY_PATH=$std64 ./runpath.$exe >/dev/null 2>&1 then runpath=$std64 break elif LD_LIBRARY_PATH=$lcl64:$std64 ./runpath.$exe >/dev/null 2>&1 then runpath=$lcl64:$std64 break fi fi done fi ;; esac ;; esac rm -f shared.$obj if $cc -c shared.$src then eval set x $probe_ar_arflags while : do shift case $# in 0) break ;; esac rm -f libxxx.$lib if $ar $1 r libxxx.$lib shared.$obj && $ar $1 t libxxx.$lib 2>&1 | grep shared.$obj >/dev/null then ar_arflags=$1 break fi done eval set x $probe_arflags while : do shift case $# in 0) break ;; esac rm -f libxxx.$lib if $cc $1 -o libxxx.$lib shared.$obj && $ar t libxxx.$lib 2>&1 | grep shared.$obj >/dev/null then arflags=$1 break fi done fi case $shared in -G) case $cc_dll in "") cc_dll=$cc_dll_def ;; esac ;; *) case $lib_dll in symbol) echo 'extern int f(void); int main(void) { f(); return 0; }' > main.$src echo '#include int f(void) { printf("hello world"); return 0; }' > member.$src if $cc -c main.$src && $cc -c member.$src then echo f > lib.exp rm -f lib.$obj main.exe if $ld -o lib.$obj -L: -bexport:lib.exp -berok -bmodtype:SRE -T512 -H512 -lm -lc member.$obj && $cc -o main.exe main.$obj lib.$obj then dld=$ld shared='-T512 -H512 -L$(LIBDIR): -berok -bmodtype:SRE' lib_dll=export dll_libraries='-lm -lc' ldscript=.exp case $cc_dll in "") cc_dll=$cc_dll_def ;; esac case $so in "") so=.$obj ;; esac fi fi ;; esac ;; esac case $shared in ?*) if $cc -c $cc_dll $cc_pic shared.$src then eval set x $probe_shared_name while : do shift case $# in 0) break ;; esac rm -f xxx$dll if $dld $shared ${1}libfoo.1.2 -o xxx$dll shared.$obj 2>e && test -r xxx$dll then shared_name=$1 break fi done fi ;; esac case " $cc_dll " in *" $cc_dll_def "*) ;; " ") ;; *) cc_dll="$cc_dll_def $cc_dll" ;; esac case $hosttype in cygwin.*|os2.*) sd=.dll Lflag=1 ;; *) if $cc -c doti.$src then if $cc -L. doti.$obj -lc >/dev/null then case $cc_dll in '') ;; *) Lflag=1 ;; esac fi fi ;; esac case $lib_dll in option) case $hosttype in linux.*) dll_libraries=-lc ;; esac ;; SYMBOL) lib_dll=symbol ;; symbol) echo "#include extern int fun(void) { puts(\"fun\"); return 0; }" > dllib.$src echo "extern int fun(void); int main(void) { return fun(); }" > dlmain.$src pwd=`pwd` while : do if $cc -c $cc_dll $cc_pic dlmain.$src && $cc -c $cc_dll $cc_pic dllib.$src then rm -f libxxx$so if $dld $shared -o libxxx$so dllib.$obj && chmod 555 libxxx$so then rm -f dlmain.$exe if $cc -o dlmain.$exe dlmain.$obj $pwd/libxxx$so && (./dlmain.$exe) >/dev/null 2>&1 then break fi fi rm -f libxxx$so dlmain.$exe if $dld $shared -o libxxx$so dllib.$obj -lm -lc && chmod 555 libxxx$so && $cc -o dlmain.$exe dlmain.$obj $pwd/libxxx$so && (./dlmain.$exe) >/dev/null 2>&1 then dll_libraries='-lm -lc' fi fi break done # the dll_libraries probe is still lame case $dll_libraries in '') case $hosttype in sco.*|sol*.*|sun*) ;; *) dll_libraries='-lm -lc' ;; esac ;; esac ;; esac stdlib= a=`$cc -print-multi-directory 2>/dev/null` case $a in .) ;; *) for d in `$cc -print-search-dirs 2>/dev/null | sed -e '/^libraries:/!d' -e 's/.*=//' | tr : '\n' | grep /lib/` do if [ -d ${d}${a} ] then stdlib="$stdlib ${d}${a}" else case $d in */lib/) d=`echo '' $d | sed -e 's,/$,,'` if [ -d ${d}${a} ] then stdlib="$stdlib ${d}${a}" fi ;; esac fi done ;; esac case $stdlib in '') stdlib=`$cc -v doti.$src 2>&1 | sed 's/ */\n/g' | sed -e '/^-L/!d' -e 's/^-L//' | while read dir do if test -d "$dir" then (cd "$dir"; pwd) fi done` ;; *) eval set x $probe_verbose shift for o in "$@" do stdlib="$stdlib "`$cc $o doti.$src 2>&1 | sed 's/ */\n/g' | sed -e '/^-L/!d' -e '/\/lib64$/!d' -e 's/^-L//'` done ;; esac case $stdlib in ?*) keepstdlib=1 o=$stdlib stdlib= for dir in $o do case " $stdlib " in *" $o "*) continue ;; esac case $dir in /usr/lib64) i=/usr/local/lib64 a=/lib64 ;; /lib64) i=/usr/local/lib64 a=/usr/lib64 ;; /usr/lib) i=/usr/local/lib a=/lib ;; lib) i=/usr/local/lib a=/usr/lib ;; *) i= a= ;; esac if test "" != "$i" -a -d "$i" then case " $o " in *" $i "*) ;; *) stdlib="$stdlib $i" ;; esac fi stdlib="$stdlib $dir" if test "" != "$a" -a -d "$a" then case " $o " in *" $a "*) ;; *) stdlib="$stdlib $a" ;; esac fi done case $hosted in 1) case " $stdlib " in *" /usr/lib "*) ;; *) case " $stdlib " in *" /usr/local/lib "*) ;; *) stdlib="$stdlib /usr/local/lib" ;; esac stdlib="$stdlib /usr/lib" ;; esac case " $stdlib " in *" /lib "*) ;; *) stdlib="$stdlib /lib" ;; esac esac ;; *) keepstdlib=0 case $dir in */arch/$hosttype/lib/*) notlib=`echo $dir | sed "s,/arch/$hosttype/lib/.*,/arch/$hosttype/lib,"` ;; *) notlib=//// ;; esac tstlib= implib= if $cc -c hosted.$src then for f in `( eval set x $probe_verbose while : do shift case $# in 0) break ;; esac $cc $1 hosted.$obj done ) 2>&1 | sed -e 's/[ :]/\\ /g' -e 's/-L//g' -e 's/^P,//' -e "s/[\"']//g" -e 's,^[\\\\/]*[\\\\/],/,' | sed -e '/^\$/d' -e '/^[-+]/d' -e '/^[^\\\\\\/]/d' -e '/[\\\\\\/]tmp[\\\\\\/]/d' -e 's/:\$//' -e 's,//*$,,'` do case " $tstlib $implib " in *" $f "*) continue ;; esac case $f in $notlib) continue ;; esac if test -d $f then tstlib="$tstlib $f" elif test -f $f then d=`echo $f | sed -e 's,[\\\\/]*[^\\\\/]*\$,,'` case " $tstlib $implib " in *" $d "*) continue ;; esac case $d in *[\\/]usr[\\/]lib) x=$d d="`echo $d | sed -e 's,[\\\\/][\\\\/]*usr[\\\\/]lib\$,/lib,'`" case " $tstlib $implib " in *" $d "*) ;; *) implib="$implib $d" ;; esac implib="$implib $x" ;; *[\\/]lib) implib="$implib $d" d="`echo $d | sed -e 's,[\\\\/][\\\\/]*lib\$,/usr/lib,'`" case " $tstlib $implib " in *" $d "*) ;; *) implib="$implib $d" ;; esac ;; *) implib="$implib $d" ;; esac fi done fi tstlib="$tstlib $implib" if $cc -Dtype=void -Dcall=exit -c tstlib.$src && mv tstlib.$obj tst.$obj then probe_lxx= l= for sym in $probe_l $probe_lxx do case $l in "") l=$sym; continue ;; esac rm -f tstlib.$exe if $cc -o tstlib.$exe tst.$obj -l$l then eval set x $probe_ldmap while : do shift case $# in 0) break ;; esac d=`$cc -Dtype=int -Dcall=$sym $static $1 tstlib.$src -l$l 2>&1 | sed -e '/[\\\\\\/].*[\\\\\\/]lib[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+][abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+]*\.[^\\\\\\/]*\$/!d' -e 's,^[^\\\\\/]*,,' -e 's,[\\\\\\/]lib[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+][abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+]*\.[^\\\\\\/]*\$,,' -e '/^[\\\\\\/]/!d' | sort -u` case $d in ?*) tstlib="$tstlib $d" ;; esac done fi l= done fi libstd= libset= stdlibroot="/ /usr/" for d in $tstlib do case $d in [\\/]lib|[\\/]usr[\\/]lib) ;; *) case " $stdlib " in *\ $d\ *) ;; *) if ls $d > tmp.tmp && test -s tmp.tmp then for i in $probe_lib $obj do if grep -i "\\.$i\$" tmp.tmp >/dev/null then case " $probe_lib_append " in *\ $d\ *) libstd="$libstd $d" ;; *) stdlib="$stdlib $d" case $d in /usr/lib|/usr/lib/*) ;; /usr/lib?*) e=`echo $d | sed -e 's,/usr,,'` g=`echo $d/libc.* $e/libc.*` case "$e $g " in *".* "*);; *) stdlib="$stdlib $e" stdlibroot= ;; esac ;; esac ;; esac case $libset in "") case $i in $obj) ;; *) libset=1 lib=$i ;; esac ;; esac break fi done fi ;; esac ;; esac done for d in `$ld --verbose 2>&1 | sed -e '/SEARCH_DIR/!d' -e 's/[ ][ ][ ]*/ /g' -e 's/SEARCH_DIR(\([^ ]*\));/\1/g' -e 's, //[^ ]*,,' -e 's,",,g'` do if test -d $d then case " $stdlib $libstd " in *\ ${d}\ *) ;; *) libstd="$libstd $d" ;; esac fi done case $hosted in "") tstlib= ;; *) tstlib="$stdlibroot /usr/ccs/ /usr/local/" ;; esac case $stdlibroot in ?*) d= for f in $stdinclude do f=`echo $f | sed -e 's,[^\\\\/]*\$,,'` d="$d $f" done tstlib="$d $tstlib" ;; esac $cc -c doti.$src > all.tmp for f in $probe_libdir do for d in $stdlib $libstd $tstlib do if test -d ${d}${f} then ls ${d}${f} | while read i do for j in ${d}${f}/${i} do if test -f $j -a -r $j -a -s $j then echo $i break fi done done > tmp.tmp if test -s tmp.tmp then if grep -E -i "^${prefix_archive}[abcdefghijklmnopqrstuvwxyz0123456789_][abcdefghijklmnopqrstuvwxyz0123456789_]*\\.$lib\$" tmp.tmp >lib.tmp || grep -E -i "\\.$obj\$" tmp.tmp >/dev/null || grep -E -i "^${prefix_shared}[abcdefghijklmnopqrstuvwxyz0123456789_][abcdefghijklmnopqrstuvwxyz0123456789_]*\\$so(.[0-9]+)*\$" tmp.tmp >>lib.tmp then if test -s lib.tmp then sed -e "s,.*/,," -e 's,^'${prefix_archive}'\(.*\)\.'$lib'$,\1,g' -e 's,^'${prefix_shared}'\(.*\)\'$so'[.0-9]*,\1,g' lib.tmp | sort -u > tmp.tmp xs=`sort all.tmp all.tmp tmp.tmp | uniq -u` case $xs in '') continue ;; esac ok=0 for x in $xs do case $x in *_p) continue ;; # Linux gcc known to hang for -lc_p esac if $cc -o doti.$exe doti.$obj -l$x 2>e then ok=1 else if test -s e && grep -E -i ":.*[ ](find|found|locate|search|-l$x)[ ]" e > /dev/null then if grep -E -i ":.*[ ](access|permission)[ ]" e then : maybe else ok=0 break fi fi case $Lflag in 1) if $cc -L${d}${f} -o doti.$exe doti.$obj -l$x then ok=0 break fi ;; esac fi done case $ok in 0) continue ;; esac sort -u all.tmp tmp.tmp > lib.tmp mv lib.tmp all.tmp fi case " $stdlib $libstd " in *" ${d}${f} "*) ;; *) if test -d ${d}${f}/fsoft then stdlib="$stdlib ${d}${f}/"'$(FLOAT_OPTION)' fi stdlib="$stdlib ${d}${f}" ;; esac fi fi fi done done stdlib="$stdlib $libstd" case $stdlib in */shlib*) dy= st= for i in $stdlib $libstd do case $i in */shlib) dy="$dy $i" ;; *) st="$st $i" ;; esac done for i in /var do if test -d $i/shlib then dy="$dy $i/shlib" fi done stdlib="$dy $st" ;; esac ;; esac if $cc -c prefix.$src then eval set x $probe_symprefix while : do shift case $# in 0) break ;; esac if $nm $nmflags prefix.$obj | grep -c ${1}prefix >/dev/null then symprefix=$1 break fi done fi if $cc -c warn.$src 2>e && test -f warn.$obj then e=`wc -c < e` eval set x $probe_debug while : do shift case $# in 0) break ;; esac rm -f warn.$obj $cc $1 -c warn.$src 2>e && test -f warn.$obj || continue case `wc -c < e` in $e) debug=$1; break ;; esac done eval set x $probe_no_protect while : do shift case $# in 0) break ;; esac rm -f warn.$obj $cc $1 -c warn.$src 2>e && test -f warn.$obj || continue case `wc -c < e` in $e) no_protect=$1; break ;; esac done eval set x $probe_no_strict_aliasing while : do shift case $# in 0) break ;; esac rm -f warn.$obj $cc $1 -c warn.$src 2>e && test -f warn.$obj || continue case $(wc -c < e) in $e) no_strict_aliasing=$1; break ;; esac done case $version_string in $probe_gcc_version) probe_optimize="$probe_gcc_optimize $probe_optimize" ;; esac for i in $probe_optimize do rm -f warn.$obj $cc $i -c warn.$src 2>e && test -f warn.$obj || continue case `wc -c < e` in $e) optimize=$i; break ;; esac done eval set x $probe_strict while : do shift case $# in 0) break ;; esac rm -f warn.$obj $cc $1 -c warn.$src 2>e && test -f warn.$obj || continue n=`wc -c < e` if test $n -ge $e then strict=$1 break fi done $cc -c warn1.$src 2>e o=`wc -c < e` eval set x $probe_warn while : do shift case $# in 0) break ;; esac rm -f warn.$obj warn.$exe $cc -o warn.$exe $1 warn.$src 2>e && test -f warn.$exe || continue n=`wc -c < e` for i in $warn_enum do rm -f warn$i.$obj $cc -c $1 warn$i.$src 2>e && test -f warn$i.$obj || continue n=`wc -c < e` if test $n -gt $o then warn=$1 break 2 fi done done fi while : do case $hosted in 1) rm -f readonly.$exe eval set x '""' $probe_readonly while : do shift case $# in 0) break ;; esac for co in '' -Dtest_const do rm -f readonly.$exe if $cc -o readonly.$exe $co $1 readonly.$src && $executable readonly.$exe then if ./readonly.$exe >/dev/null 2>&1 then : else readonly=$1 break 3 fi fi done done rm -f readonly.$exe readonly.s if $cc -S readonly.$src && test -f readonly.s then if sed -e 's/^\([ ]*[.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$:]*[ ]*\.*\)data/\1text/' \ -e 's/^\([ ]*[.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$:]*[ ]*\.*\)zero[ ][ ]*/\1set .,.+/' \ -e 's/^\([ ]*[.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$:]*[ ]*\.*\)space[ ][ ]*1/\1byte 0/' \ -e 's/^\([ ]*[.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$:]*[ ]*\.*\)space[ ][ ]*2/\1byte 0,0/' \ -e 's/^\([ ]*[.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$:]*[ ]*\.*\)space[ ][ ]*3/\1byte 0,0,0/' \ -e 's/^\([ ]*[.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$:]*[ ]*\.*\)space[ ][ ]*4/\1byte 0,0,0,0/' \ readonly.s > ro.s && $cc -o readonly.$exe ro.s && $executable readonly.$exe then if ./readonly.$exe >/dev/null 2>&1 then : else readonly='-S.data' break fi fi rm -f readonly.$exe if sed -e 's/^\([ ]*[.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$:]*[ ]*\.*\)idat/\1code/' \ -e 's/^\([ ]*[.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$:]*[ ]*\.*\)zero[ ][ ]*/\1set .,.+/' \ -e 's/^\([ ]*[.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$:]*[ ]*\.*\)space[ ][ ]*1/\1byte 0/' \ -e 's/^\([ ]*[.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$:]*[ ]*\.*\)space[ ][ ]*2/\1byte 0,0/' \ -e 's/^\([ ]*[.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$:]*[ ]*\.*\)space[ ][ ]*3/\1byte 0,0,0/' \ -e 's/^\([ ]*[.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$:]*[ ]*\.*\)space[ ][ ]*4/\1byte 0,0,0,0/' \ readonly.s > ro.s && $cc -o readonly.$exe ro.s && $executable readonly.$exe then if ./readonly.$exe >/dev/null 2>&1 then : else readonly='-S.idat' break fi fi if sed -e 's/^\([ ]*[.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$:]*[ ]*\.*\)data/\1rdata/' \ readonly.s > ro.s && $cc -o readonly.$exe ro.s && $executable readonly.$exe then if ./readonly.$exe >/dev/null 2>&1 then : else readonly='-S.rdata' break fi fi fi ;; esac break done case $stdc in ?*) dialect="$dialect ANSI" ;; esac case $hosted in "") dialect="$dialect CROSS" ;; esac case $doti in ?*) dialect="$dialect DOTI" ;; esac case $gnu in ?*) dialect="$dialect GNU" ;; esac case $so:$dynamic:$static in ::) ;; *) dialect="$dialect DYNAMIC" case $soversion in ?*) dialect="$dialect VERSION" ;; esac ;; esac case $implicitc in ?*) dialect="$dialect IMPLICITC" ;; esac case $ptrcopy in ?*) dialect="$dialect PTRCOPY" ;; esac case $ptrimplicit in ?*) dialect="$dialect PTRIMPLICIT" ;; esac case $ptrmkdir in ?*) dialect="$dialect PTRMKDIR" ;; esac case $libpp in ?*) dialect="$dialect LIBPP" ;; esac case $toucho in ?*) dialect="$dialect TOUCHO" ;; esac case $dDflag in ?*) dialect="$dialect -dD" ;; esac # 2005-05-25 use $(CC.INCLUDE.LOCAL) instead case $include_local in ?*) dialect="$dialect -I-" ;; esac case $Lflag in ?*) dialect="$dialect -L" ;; esac ppcmd='$(CPP)' ppdir='$(CPP:D)' eval ppopt='"'$ppopt'"' eval ppenv='"'$ppenv'"' set x "" .$exe shift exe= for i do rm -f require$i done if $cc -o require require.$src then for i do if $executable require$i then exe=$i break fi done fi case $sa:$sd:$so in ::?*) eval set x $probe_sa while : do shift case $# in 0) break ;; esac for i in $stdlib do eval j="'" $i/lib*$1 "'" case $j in " $i/lib*$1 ") eval j="'" $i/lib*$1.[0123456789]* "'" case $j in " $i/lib*$1.[0123456789]* ") continue ;; esac ;; esac sa=$1 lddynamic=-Bdynamic ldstatic=-Bstatic break 2 done done ;; esac case $ldscript in "") case $so in .lib) ldscript=".def .exp" ;; *) ldscript=".ld" ;; esac ;; esac case $hosttype in '') hosttype=unknown ;; sgi.mips3) dll_variants='sgi.mips2:o32:-mips2 sgi.mips4:64:-mips4' ;; sgi.mips4) dll_variants='sgi.mips2:o32:-mips2 sgi.mips3:n32:-mips3' ;; esac case $hosted in "") ccnative=`echo $cc | sed -e 's,.*/,,'` ccs=$ccnative for c in cc gcc do case " $ccs " in *" $c "*) ;; *) ccs="$ccs $c" ;; esac done for p in $path do for c in $ccs do if $executable $p/$c then rm -f native.$exe if $p/$c -o native.$exe doti.$src && ./native.$exe then ccnative=$p/$c exectype=`package CC="$ccnative" || $SHELL -c "package CC='$ccnative'"` case $exectype in *[Uu][Ss][Aa][Gg][Ee]:*) exectype=`PATH=$_probe_PATH; export PATH; package CC="$ccnative" || $SHELL -c "package CC='$ccnative'"` ;; esac break 2 fi fi done done ;; *) ccnative=$cc exectype=$hosttype ;; esac # runtime shared lib exported symbol resolution case $cc_dll:$shared in :|:*|*:);; *) cat > cmd.c <<'!' #include #include typedef int (*Lib_f)(int**, int**, int**); int gbl_def = 1; int gbl_ref = 1; int gbl_ext; int main(int argc, char** argv) { void* dll; Lib_f lib; int* def; int* ref; int* ext; if (!(dll = dlopen(*++argv, RTLD_LAZY))) fprintf(stderr, "library not found\n"); else if (!((lib = (Lib_f)dlsym(dll, "lib"))) && !(lib = (Lib_f)dlsym(dll, "_lib"))) fprintf(stderr, "symbol not found\n"); else if ((*lib)(&def, &ref, &ext)) fprintf(stderr, "function failed\n"); else if (def == &gbl_def && ref == &gbl_ref && ext == &gbl_ext) printf("ALL\n"); else if (ref == &gbl_ref && ext == &gbl_ext) printf("REF\n"); else if (ext == &gbl_ext) printf("EXT\n"); return 0; } ! cat > lib.c <<'!' int gbl_def = 1; int gbl_ref; int gbl_ext; int lib(int** def, int** ref, int** ext) { *def = &gbl_def; *ref = &gbl_ref; *ext = &gbl_ext; return 0; } ! if $cc -c $cc_dll $cc_pic cmd.c && $cc -c $cc_dll $cc_pic lib.c && { $cc $cc_dll $export_dynamic -o cmd.exe cmd.o || $cc $cc_dll $export_dynamic -o cmd.exe cmd.o -ldl } && $dld $shared -o libgbl.dll lib.o then x=`./cmd.exe ./libgbl.dll` case $x in ?*) dialect="$dialect EXPORT=$x" ;; esac else case $sd:$hosttype in .dll:*win*) dialect="$dialect EXPORT=DLL" ;; esac fi ;; esac # # path cleanup # for i in ar ccnative dld ld nm size stdinclude stdlib strip do eval o='$'$i v=$o case $v in *//*) v=`echo $v | sed 's,///*,/,g'` ;; esac if (test . -ef "`pwd`") then k= for x in $v do case $x in */../*|*/..) case $x in /*) a=/ ;; *) a= ;; esac IFS=/ set '' $x IFS=$ifs r= for d do r="$d $r" done p= g= for d in $r do case $d in ..) g="$g $d" ;; *) case $g in '') case $p in '') p=$d ;; *) p=$d/$p ;; esac ;; *) set $g shift g=$* ;; esac ;; esac done case $a in '') for d in $g do p=$d/$p done ;; *) p=$a$p ;; esac case $p in /) continue ;; esac test $x -ef $p && x=$p ;; esac k="$k $x" done set '' $k shift v=$1 case $# in 0) ;; *) shift while : do case $# in 0) break ;; esac k= for d do for j in $v do test $d -ef $j && continue 2 done k="$k $d" done set '' $k case $# in 1) break ;; esac shift v="$v $1" shift done ;; esac fi case $v in $o) ;; *) eval $i='$'v ;; esac done case $keepstdlib in 1) ;; *) # # favor lib64 over lib # case $hosttype in *64|*[!0-9]64[!a-zA-Z0-9]*) o=$stdlib stdlib= for i in $o do case " $stdlib " in *" $i "*) continue ;; esac case $i in *64) stdlib="$stdlib $i" continue ;; esac case " $o " in *" ${i}64 "*) case " $stdlib " in *" ${i}64 "*) ;; *) stdlib="$stdlib ${i}64" ;; esac ;; esac stdlib="$stdlib $i" done ;; esac ;; esac # # determine the need for any API version targets to add to the compiler flags # CC_TARGET= case $hosttype in android.*) # get current default API level cat >_android_test.c <<-EOF #include int main(void) { printf("%d\n", __ANDROID_API__); return 0; } EOF $cc -o _android_test _android_test.c got=$(./_android_test) (set +f; exec rm -rf _android_test*) & # check for minimum required; we need API 26 for catopen(3) et al if test -n "$got" && test "$got" -lt 26 then CC_TARGET="--target=$(uname -m)-linux-android26" fi ;; esac # # set up for local override # CC_VERSION_STAMP=$version_stamp CC_VERSION_STRING=$version_string CC_CC=$cc CC_NATIVE=$ccnative CC_EXECTYPE=$exectype CC_HOSTTYPE=$hosttype CC_ALTPP_FLAGS=$ppopt CC_ALTPP_ENV=$ppenv CC_AR=$ar CC_AR_ARFLAGS=$ar_arflags CC_ARFLAGS=$arflags CC_DEBUG=$debug CC_DIALECT=$dialect CC_PICBIG=$cc_PIC CC_PICSMALL=$cc_pic CC_PIC=$CC_PICBIG CC_DLL_ONLY=$cc_dll case $CC_DLL_ONLY in '') CC_DLLBIG= CC_DLLSMALL= CC_DLL= ;; *) CC_DLLBIG="$CC_DLL_ONLY $CC_PICBIG" CC_DLLSMALL="$CC_DLL_ONLY $CC_PICSMALL" CC_DLL="$CC_DLL_ONLY $CC_PICBIG" ;; esac CC_DLL_DIR=$dll_dir CC_DLL_LIBRARIES=$dll_libraries CC_DLL_VARIANTS=$dll_variants CC_DYNAMIC=$dynamic CC_EXPORT_DYNAMIC=$export_dynamic CC_INCLUDE_LOCAL=$include_local CC_LD=$ld CC_LD_ASNEEDED=$ldasneeded CC_LD_NOASNEEDED=$ldnoasneeded CC_LD_DYNAMIC=$lddynamic CC_LD_LAZY=$ldlazy CC_LD_NOLAZY=$ldnolazy CC_LD_ORIGIN=$ldorigin CC_LD_RECORD=$ldrecord CC_LD_NORECORD=$ldnorecord CC_LD_RUNPATH=$ldrunpath CC_LD_STATIC=$ldstatic CC_LD_STRIP=$ldstrip CC_LIB_DLL=$lib_dll CC_LIB_ALL=$lib_all CC_LIB_UNDEF=$lib_undef CC_MAKE_OPTIONS=$makeoptions CC_NM=$nm CC_NMEDIT=$nmedit CC_NMFLAGS=$nmflags CC_NOPROTECT=$no_protect CC_NOSTRICTALIASING=$no_strict_aliasing CC_OPTIMIZE=$optimize CC_READONLY=$readonly CC_REPOSITORY=$repository CC_REQUIRE=$require CC_RUNPATH=$runpath CC_SHARED=$shared CC_SHARED_LD=$dld CC_SHARED_NAME=$shared_name CC_SHARED_REGISTRY=$shared_registry CC_SHARED_REGISTRY_PATH=$probe_shared_registry_path CC_SIZE=$size CC_STATIC=$static CC_STDINCLUDE=$stdinclude CC_STDLIB=$stdlib CC_STRICT=$strict CC_STRIP=$strip CC_STRIP_FLAGS=$stripflags CC_PREFIX_ARCHIVE=$prefix_archive CC_PREFIX_DYNAMIC=$prefix_dynamic CC_PREFIX_SHARED=$prefix_shared CC_PREFIX_SYMBOL=$symprefix CC_SUFFIX_ARCHIVE=.$lib CC_SUFFIX_COMMAND=$suffix_command CC_SUFFIX_DEBUG=$sdb CC_SUFFIX_DYNAMIC=$sd CC_SUFFIX_LD=$ldscript CC_SUFFIX_OBJECT=.$obj CC_SUFFIX_SHARED=$so CC_SUFFIX_SOURCE=.$src CC_SUFFIX_STATIC=$sa CC_VERSION=$version_flags CC_WARN=$warn CC_ATTRIBUTES=$ATTRIBUTES exec >&3 # # check for local override # all CC_* but { CC_CC CC_VERSION_STAMP CC_VERSION_STRING } may be modified # additional CC.* may be printed on stdout # if test -f "$dir/probe.lcl" then . "$dir/probe.lcl" fi # # the payoff # case $version_stamp in ?*) echo "# $version_stamp" ;; esac echo CC.CC = $cc echo CC.NATIVE = $CC_NATIVE echo CC.EXECTYPE = $CC_EXECTYPE echo CC.HOSTTYPE = $CC_HOSTTYPE echo CC.ALTPP.FLAGS = $CC_ALTPP_FLAGS echo CC.ALTPP.ENV = $CC_ALTPP_ENV echo CC.AR = $CC_AR echo CC.AR.ARFLAGS = $CC_AR_ARFLAGS echo CC.ARFLAGS = $CC_ARFLAGS echo CC.DEBUG = $CC_DEBUG echo CC.DIALECT = $CC_DIALECT echo CC.DLLBIG = $CC_DLLBIG echo CC.DLLSMALL = $CC_DLLSMALL echo CC.DLL = $CC_DLL echo CC.DLL.DEF = $cc_dll_def echo CC.DLL.DIR = $CC_DLL_DIR echo CC.DLL.LIBRARIES = $CC_DLL_LIBRARIES echo CC.DLL.VARIANTS = $CC_DLL_VARIANTS echo CC.DYNAMIC = $CC_DYNAMIC echo CC.EXPORT.DYNAMIC = $CC_EXPORT_DYNAMIC echo CC.INCLUDE.LOCAL = $CC_INCLUDE_LOCAL # # 2004-02-14 release workaround # case $CC_SHARED_LD in $CC_CC) echo if LDSHARED echo CC.LD = $CC_LD echo else echo CC.LD = $CC_CC echo end ;; *) echo CC.LD = $CC_LD ;; esac echo CC.LD.ASNEEDED = $CC_LD_ASNEEDED echo CC.LD.NOASNEEDED = $CC_LD_NOASNEEDED echo CC.LD.DYNAMIC = $CC_LD_DYNAMIC echo CC.LD.LAZY = $CC_LD_LAZY echo CC.LD.NOLAZY = $CC_LD_NOLAZY echo CC.LD.ORIGIN = $CC_LD_ORIGIN echo CC.LD.RECORD = $CC_LD_RECORD echo CC.LD.NORECORD = $CC_LD_NORECORD echo CC.LD.RUNPATH = $CC_LD_RUNPATH echo CC.LD.STATIC = $CC_LD_STATIC echo CC.LD.STRIP = $CC_LD_STRIP echo CC.LIB.DLL = $CC_LIB_DLL echo CC.LIB.ALL = $CC_LIB_ALL echo CC.LIB.UNDEF = $CC_LIB_UNDEF echo CC.MAKE.OPTIONS = $CC_MAKE_OPTIONS echo CC.NM = $CC_NM case $CC_NMEDIT in ?*) CC_NMEDIT=" $CC_NMEDIT" ;; esac echo CC.NMEDIT ="$CC_NMEDIT" echo CC.NMFLAGS = $CC_NMFLAGS echo CC.NOPROTECT = $CC_NOPROTECT echo CC.NOSTRICTALIASING = $CC_NOSTRICTALIASING echo CC.OPTIMIZE = $CC_OPTIMIZE echo CC.PICBIG = $CC_PICBIG echo CC.PICSMALL = $CC_PICSMALL echo CC.PIC = $CC_PIC echo CC.READONLY = $CC_READONLY echo CC.REPOSITORY = $CC_REPOSITORY for f in $CC_REQUIRE do echo CC.REQUIRE.$f =`cat req.$f` done echo CC.RUNPATH = $CC_RUNPATH echo CC.SHARED = $CC_SHARED echo CC.SHARED.LD = $CC_SHARED_LD echo CC.SHARED.NAME = $CC_SHARED_NAME echo CC.SHARED.REGISTRY = $CC_SHARED_REGISTRY echo CC.SHARED.REGISTRY.PATH = $CC_SHARED_REGISTRY_PATH echo CC.SIZE = $CC_SIZE echo CC.STATIC = $CC_STATIC echo CC.STDINCLUDE = $CC_STDINCLUDE echo CC.STDLIB = $CC_STDLIB echo CC.STRICT = $CC_STRICT echo CC.STRIP = $CC_STRIP echo CC.STRIP.FLAGS = $CC_STRIP_FLAGS echo CC.PREFIX.ARCHIVE = $CC_PREFIX_ARCHIVE echo CC.PREFIX.DYNAMIC = $CC_PREFIX_DYNAMIC echo CC.PREFIX.SHARED = $CC_PREFIX_SHARED echo CC.PREFIX.SYMBOL = $CC_PREFIX_SYMBOL echo CC.SUFFIX.ARCHIVE = $CC_SUFFIX_ARCHIVE echo CC.SUFFIX.COMMAND = $CC_SUFFIX_COMMAND echo CC.SUFFIX.DEBUG = $CC_SUFFIX_DEBUG echo CC.SUFFIX.DYNAMIC = $CC_SUFFIX_DYNAMIC echo CC.SUFFIX.LD = $CC_SUFFIX_LD echo CC.SUFFIX.OBJECT = $CC_SUFFIX_OBJECT echo CC.SUFFIX.SHARED = $CC_SUFFIX_SHARED echo CC.SUFFIX.SOURCE = $CC_SUFFIX_SOURCE echo CC.SUFFIX.STATIC = $CC_SUFFIX_STATIC echo CC.TARGET = $CC_TARGET echo CC.VERSION = $CC_VERSION case $CC_VERSION_STRING in *\"*) i=`echo " $CC_VERSION_STRING" | sed -e 's,",\\\\",g' -e 's,^ ,,' -e 's,.*,"&",'` ;; *\'*) i=\"$CC_VERSION_STRING\" ;; *) i=$CC_VERSION_STRING ;; esac cat < * * Martijn Dekker * * Johnothan King * * * ***********************************************************************/ #if __clang__ #pragma clang diagnostic ignored "-Wparentheses" #elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) #pragma GCC diagnostic ignored "-Wparentheses" #endif /* * mamake -- MAM make * * coded for portability */ #define RELEASE_DATE "2024-07-30" static char id[] = "\n@(#)$Id: mamake (ksh 93u+m) " RELEASE_DATE " $\0\n"; #if _PACKAGE_ast #include #include static const char usage[] = "[-?\n@(#)$Id: mamake (ksh 93u+m) " RELEASE_DATE " $\n]" "[-author?Glenn Fowler ]" "[-author?Martijn Dekker ]" "[-author?Contributors to https://github.com/ksh93/ksh]" "[-copyright?(c) 1994-2013 AT&T Intellectual Property]" "[-copyright?(c) 2020-2024 Contributors to ksh 93u+m]" "[-license?https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html]" "[+NAME?mamake - make abstract machine make]" "[+DESCRIPTION?\bmamake\b reads \amake abstract machine\a target and" " prerequisite file descriptions from a mamfile (see \b-f\b) and executes" " actions to update targets that are older than their prerequisites." " Mamfiles are portable to environments that only have" " \bsh\b(1) and \bcc\b(1).]" "[+?Mamfiles are used rather than" " old-\bmake\b makefiles because some features are not reliably supported" " across all \bmake\b variants:]{" " [+action execution?Multi-line actions are executed as a" " unit by \b$SHELL\b. There are some shell constructs" " that cannot be expressed in an old-\bmake\b makefile.]" " [+viewpathing?\bVPATH\b is properly interpreted. This allows" " source to be separate from generated files.]" " [+recursion?Ordered subdirectory recursion over unrelated" " makefiles.]" " }" "[+?\bmamprobe\b(1) is called to probe and generate system specific variable" " definitions. The probe information is regenerated when it is older" " than the \bmamprobe\b command.]" "[e:?Explain reason for triggering action. Ignored if -F is on.]" "[f:?Read \afile\a instead of the default.]:[file:=Mamfile]" "[i:?Ignore action errors.]" "[k:?Continue after error with sibling prerequisites.]" "[n:?Print actions but do not execute. Recursion actions (see \b-r\b) are still" " executed. Use \b-N\b to disable recursion actions too.]" "[r:?Recursively make leaf directories matching \apattern\a. Only leaf" " directories containing a file named \bMamfile\b" " are considered. The \abind\a commands in the Mamfile" " found in each leaf directory are scanned for leaf directory" " prerequisites; the recursion order is determined by a topological sort" " of these prerequisites.]:[pattern]" "[C:?Do all work in \adirectory\a. All messages will mention" " \adirectory\a.]:[directory]" "[D:?Set the debug trace level to \alevel\a. Higher levels produce more" " output.]#[level]" "[F:?Force all targets to be out of date.]" "[N:?Like \b-n\b but recursion actions (see \b-r\b) are also disabled.]" "[V:?Print the program version and exit.]" "[G:debug-symbols?Compile and link with debugging symbol options enabled.]" "[S:strip-symbols?Strip link-time static symbols from executables.]" "\n" "\n[ target ... ] [ name=value ... ]\n" "\n" "[+SEE ALSO?\bmamprobe\b(1), \bsh\b(1)]" ; #else #define elementsof(x) (sizeof(x)/sizeof(x[0])) #define newof(p,t,n,x) ((p)?(t*)realloc((char*)(p),sizeof(t)*(n)+(x)):(t*)calloc(1,sizeof(t)*(n)+(x))) /* * For compatibility with compiler flags such as -std=c99, feature macros * must be enabled to prevent the build from failing at the very start. * These are normally handled in src/lib/libast/features/standards; further * information can be found there. Mamake shouldn't need all that much enabled, * so not much is enabled here. */ /* macOS */ #if (defined(__APPLE__) && defined(__MACH__) && defined(NeXTBSD)) && !defined(_DARWIN_C_SOURCE) #define _DARWIN_C_SOURCE 1 /* Solaris and illumos */ #elif defined(__sun) #define _XPG7 #define _XPG6 #define _XPG5 #define _XPG4_2 #define _XPG4 #define _XPG3 #define __EXTENSIONS__ 1 #define _XOPEN_SOURCE 9900 #undef _POSIX_C_SOURCE /* * Though POSIX says it must be allowed, Solaris Studio cc dislikes NULL, a.k.a. * (void*)0, being used for function pointers. It warns, or in some cases it even * throws an error. Just use 0 for NULL, as that is always acceptable in C. */ #if __SUNPRO_C #undef NULL #define NULL 0 #endif /* __SUNPRO_C */ /* Linux and Cygwin */ #elif (defined(__linux__) || __CYGWIN__) && !defined(_GNU_SOURCE) #define _GNU_SOURCE 1 /* QNX */ #elif defined(__QNX__) && !defined(_QNX_SOURCE) #define _QNX_SOURCE 1 /* Everything else (minus BSD, as the defaults there are acceptable) */ #elif !(BSD && !__APPLE__ && !__MACH__ && !NeXTBSD) && !defined(_POSIX_C_SOURCE) #define _POSIX_C_SOURCE 21000101L #endif #endif /* _PACKAGE_ast */ #include #include #include #include #include #include #include #if !_PACKAGE_ast #include #include #include #endif /* backward compat for file offsets */ #if _POSIX_VERSION < 200112L #define off_t long #define fseeko fseek #define ftello ftell #endif #define delimiter(c) (isspace(c)||(c)==';'||(c)=='('||(c)==')'||(c)=='`'||(c)=='|'||(c)=='&'||(c)=='=') #define add(b,c) (((b)->nxt >= (b)->end) ? append(b, "") : NULL, *(b)->nxt++ = (c)) #define getsize(b) ((b)->nxt-(b)->buf) #define setsize(b,o) ((b)->nxt=(b)->buf+(o)) #define use(b) (*(b)->nxt=0,(b)->nxt=(b)->buf) #define CHUNK 4096 #define KEY(a,b,c,d) ((((unsigned long)(a))<<24)|(((unsigned long)(b))<<16)|(((unsigned long)(c))<<8)|(((unsigned long)(d)))) #define NOW ((unsigned long)time(NULL)) #define RULE_active 0x0001 /* active target */ #define RULE_dontcare 0x0002 /* ok if not found */ #define RULE_error 0x0004 /* not found or not generated */ #define RULE_exists 0x0008 /* target file exists */ #define RULE_generated 0x0010 /* generated target */ #define RULE_ignore 0x0020 /* ignore time */ #define RULE_made 0x0040 /* already made */ #define RULE_virtual 0x0080 /* not a file */ #define RULE_notrace 0x0100 /* do not xtrace shell action */ #define RULE_updated 0x0200 /* rule was outdated and remade */ #define STREAM_KEEP 0x0001 /* don't fclose() on pop() */ #define STREAM_MUST 0x0002 /* push() file must exist */ #define STREAM_PIPE 0x0004 /* pclose() on pop() */ #ifndef S_IXUSR #define S_IXUSR 0100 /* owner execute permission */ #endif #ifndef S_IXGRP #define S_IXGRP 0010 /* group execute permission */ #endif #ifndef S_IXOTH #define S_IXOTH 0001 /* other execute permission */ #endif struct Rule_s; typedef struct stat Stat_t; typedef FILE Stdio_t; typedef struct Buf_s /* buffer stream */ { struct Buf_s *old; /* next dropped buffer */ char *end; /* 1 past end of buffer */ char *nxt; /* next char to add */ char *buf; /* buffer space */ } Buf_t; typedef struct Dict_item_s /* dictionary item */ { struct Dict_item_s *left; /* left child */ struct Dict_item_s *right; /* right child */ void *value; /* user defined value */ #if __STDC_VERSION__ >= 199901L char name[]; /* 0 terminated name */ #else char name[1];/* 0 terminated name */ #endif } Dict_item_t; typedef struct Dict_s /* dictionary handle */ { Dict_item_t *root; /* root item */ } Dict_t; typedef struct List_s /* Rule_t list */ { struct List_s *next; /* next in list */ struct Rule_s *rule; /* list item */ } List_t; typedef struct Rule_s /* rule item */ { char *name; /* unbound name */ char *path; /* bound path */ List_t *prereqs; /* prerequisites */ struct Rule_s *leaf; /* recursion leaf alias */ int flags; /* RULE_* flags */ int making; /* currently make()ing */ unsigned long time; /* modification time */ unsigned long line; /* starting line in Mamfile */ } Rule_t; typedef struct Stream_s /* input file stream stack */ { Stdio_t *fp; /* read stream */ char *file; /* stream path */ unsigned long line; /* stream line */ int flags; /* stream flags */ } Stream_t; typedef struct View_s /* viewpath level */ { struct View_s *next; /* next level in viewpath */ size_t node; /* viewpath node path length */ #if __STDC_VERSION__ >= 199901L char dir[]; /* viewpath level dir prefix */ #else char dir[1]; /* viewpath level dir prefix */ #endif } View_t; static struct /* program state */ { int strict; /* strict mode activated if set */ Buf_t *old; /* dropped buffers */ Buf_t *opt; /* option buffer */ Dict_t *leaf; /* recursion leaf dictionary */ Dict_t *rules; /* rule dictionary */ Dict_t *vars; /* variable dictionary */ View_t *view; /* viewpath levels */ char *directory; /* work in this directory */ char *id; /* command name */ char *file; /* first input file */ char *pwd; /* current directory */ char *recurse; /* recursion pattern */ char *shell; /* ${SHELL} */ int active; /* targets currently active */ int debug; /* negative of debug level */ int errors; /* some error(s) occurred */ int exec; /* execute actions */ int explain; /* explain actions */ int force; /* all targets out of date */ int ignore; /* ignore command errors */ int indent; /* debug indent */ int keepgoing; /* do siblings on error */ int never; /* never execute */ int probed; /* probe already done */ int verified; /* don't bother with verify() */ Stream_t streams[4]; /* input file stream stack */ Stream_t *sp; /* input stream stack pointer */ char *shim; /* finished shim */ Buf_t *shim_buf; /* shim being built up */ } state; static unsigned long make(Rule_t *, int, unsigned long, Buf_t **); static char mamfile[] = "Mamfile"; static char sh[] = "/bin/sh"; static char empty[] = ""; static Dict_item_t *auto_making; /* ${@} - name of rule being made */ static Dict_item_t *auto_prev; /* ${<} - name of last prerequisite */ static Dict_item_t *auto_allprev; /* ${^} - space-separated names of all prerequisites */ static Dict_item_t *auto_updprev; /* ${?} - space-separated names of updated prerequisites */ extern char **environ; #if !_PACKAGE_ast /* * emit usage message and exit */ static void usage(void) { fprintf(stderr, "Usage: %s" " [-eiknFNVGS]" " [-f file]" " [-r pattern]" " [-C directory]" " [-D level]" " [ target ... ]" " [ name=value ... ]" "\n", state.id); exit(2); } #endif /* * output error message identification */ static void identify(Stdio_t * sp) { if (state.directory) fprintf(sp, "%s [%s]: ", state.id, state.directory); else fprintf(sp, "%s: ", state.id); } /* * emit error message * level: * <0 debug * 0 info * 1 warning * 2 error * >2 exit(level-2) */ static void report(int level, char *text, char *item, unsigned long stamp) { int i; if (level >= state.debug) { if (level) identify(stderr); if (level < 0) { fprintf(stderr, "debug%d: ", level); for (i = 0; i < state.indent; i++) fprintf(stderr, " "); } else { if (state.sp && state.sp->line) { if (state.sp->file) fprintf(stderr, "%s: ", state.sp->file); fprintf(stderr, "%ld: ", state.sp->line); } if (level == 1) fprintf(stderr, "warning: "); else if (level > 1) state.errors = 1; } if (item) fprintf(stderr, "%s: ", item); fprintf(stderr, "%s", text); if (stamp && state.debug <= -2) fprintf(stderr, " %10lu", stamp); fprintf(stderr, "\n"); if (level > 2) exit(level - 2); } } /* * don't know how to make or exit code making */ static void error_making(Rule_t *r, int code) { identify(stderr); if (!code) report(state.keepgoing ? 1 : 3, "missing prerequisite", r->name, 0); else { fprintf(stderr, "*** exit code %d making %s%s\n", code, r->name, state.ignore ? " ignored" : ""); unlink(r->name); if (state.ignore) return; if (!state.keepgoing) exit(1); state.errors = 1; } r->flags |= RULE_error; } /* * open a buffer stream */ static Buf_t *buffer(void) { Buf_t *buf; if (buf = state.old) state.old = state.old->old; else if (!(buf = newof(0, Buf_t, 1, 0)) || !(buf->buf = newof(0, char, CHUNK, 0))) report(3, "out of memory [buffer]", NULL, 0); buf->end = buf->buf + CHUNK; buf->nxt = buf->buf; return buf; } /* * close a buffer stream */ static void drop(Buf_t *buf) { buf->old = state.old; state.old = buf; } /* * append str length n to buffer and return the buffer base */ static char *appendn(Buf_t *buf, char *str, size_t n) { size_t m, i; if ((n + 1) >= (buf->end - buf->nxt)) { i = buf->nxt - buf->buf; m = (((buf->end - buf->buf) + n + CHUNK + 1) / CHUNK) * CHUNK; if (!(buf->buf = newof(buf->buf, char, m, 0))) report(3, "out of memory [buffer resize]", NULL, 0); buf->end = buf->buf + m; buf->nxt = buf->buf + i; } memcpy(buf->nxt, str, n + 1); buf->nxt += n; return buf->buf; } /* * append str to buffer and return the buffer base * if str==0 then next pointer reset to base */ static char *append(Buf_t *buf, char *str) { if (str) return appendn(buf, str, strlen(str)); buf->nxt = buf->buf; return buf->buf; } /* * realloc for strings (with support for non-allocated empty string): * allocate space for s and return the copy */ static char *reduplicate(char *orig, char *s) { char *t; size_t n; n = strlen(s); if (n == 0) { if (orig && orig != empty) free(orig); return empty; } if (!(t = realloc(orig == empty ? NULL : orig, n + 1))) report(3, "out of memory [duplicate]", s, 0); strcpy(t, s); return t; } static char *duplicate(char *s) { return reduplicate(NULL, s); } /* * open a new dictionary */ static Dict_t *dictionary(void) { Dict_t *dict; if (!(dict = newof(0, Dict_t, 1, 0))) report(3, "out of memory [dictionary]", NULL, 0); return dict; } /* * Return a pointer to item 'name' in dictionary 'dict'. * If create!=0, then the item is created if necessary. * Uses top-down splaying (ala Tarjan and Sleator). */ static Dict_item_t *search(Dict_t *dict, char *name, int create) { int cmp; Dict_item_t *root = dict->root, *left = NULL, *right = NULL, *lroot = NULL, *rroot = NULL; while (root) { if (!(cmp = strcmp(name, root->name))) break; else if (cmp < 0) { if (root->left && (cmp = strcmp(name, root->left->name)) <= 0) { /* rotate(left, right) */ Dict_item_t *t = root->left; root->left = t->right; t->right = root; root = t; if (!cmp) break; } if (right) right->left = root; else rroot = root; right = root; root = root->left; right->left = NULL; } else { if (root->right && (cmp = strcmp(name, root->right->name)) >= 0) { /* rotate(right, left) */ Dict_item_t *t = root->right; root->right = t->left; t->left = root; root = t; if (!cmp) break; } if (left) left->right = root; else lroot = root; left = root; root = root->right; left->right = NULL; } } if (root) { if (right) right->left = root->right; else rroot = root->right; if (left) left->right = root->left; else lroot = root->left; } else if (create) { if (!(root = newof(0, Dict_item_t, 1, strlen(name) + 1))) { report(3, "out of memory [dictionary]", name, 0); abort(); } strcpy(root->name, name); } if (root) { root->left = lroot; root->right = rroot; dict->root = root; return root; } if (left) { left->right = rroot; dict->root = lroot; } else if (right) { right->left = lroot; dict->root = rroot; } return NULL; } static void setval(Dict_t *dict, char *name, void *value) { Dict_item_t *node = search(dict, name, 1); node->value = value; } static void *getval(Dict_t *dict, char *name) { Dict_item_t *node = search(dict, name, 0); return node ? node->value : NULL; } /* * low level for walk() */ static int apply(Dict_t *dict, Dict_item_t *item, int (*func)(Dict_item_t *)) { Dict_item_t *right; do { right = item->right; if (item->left && apply(dict, item->left, func)) return -1; if ((*func)(item)) return -1; } while (item = right); return 0; } /* * apply func to each dictionary item */ static int walk(Dict_t *dict, int (*func)(Dict_item_t *)) { return dict->root ? apply(dict, dict->root, func) : 0; } /* * return a rule pointer for name */ static Rule_t *rule(char *name) { Rule_t *r; if (!(r = getval(state.rules, name))) { Dict_item_t *rnode; size_t n; if (!(r = newof(0, Rule_t, 1, 0))) report(3, "out of memory [rule]", name, 0); rnode = search(state.rules, name, 1); rnode->value = r; r->name = rnode->name; r->line = state.sp ? state.sp->line : 0; /* * Since ksh 93u+m removed proto(1) including the *.lic license * atrocities, make those prerequisites optional. This allows * testing code with old Mamfiles using the current build system. */ if (!state.strict && *name == '/' && (n = strlen(name)) > 4 && strcmp(name + n - 4, ".lic") == 0) r->flags |= RULE_dontcare; } return r; } /* * prepend p onto rule r prereqs */ static void cons(Rule_t *r, Rule_t *p) { List_t *x; for (x = r->prereqs; x && x->rule != p; x = x->next); if (!x) { if (!(x = newof(0, List_t, 1, 0))) report(3, "out of memory [list]", r->name, 0); x->rule = p; x->next = r->prereqs; r->prereqs = x; } } /* * initialize the viewpath */ static void view(void) { char *s, *t, *p; View_t *vp, *zp; int c; size_t n; Stat_t st, ts; char buf[CHUNK]; Dict_item_t *vnode; if (stat(".", &st)) report(3, "cannot stat", ".", 0); vnode = search(state.vars, "PWD", 1); if ((s = vnode->value) && !stat(s, &ts) && ts.st_dev == st.st_dev && ts.st_ino == st.st_ino) state.pwd = s; if (!state.pwd) { if (!getcwd(buf, sizeof(buf) - 1)) report(3, "cannot determine PWD", NULL, 0); state.pwd = duplicate(buf); vnode->value = state.pwd; } if ((s = getval(state.vars, "VPATH")) && *s) { p = NULL; zp = NULL; for (;;) { for (t = s; *t && *t != ':'; t++); if (c = *t) *t = 0; if (!state.view) { /* * determine the viewpath offset */ if (stat(s, &st)) report(3, "cannot stat top view", s, 0); if (stat(state.pwd, &ts)) report(3, "cannot stat", state.pwd, 0); if (ts.st_dev == st.st_dev && ts.st_ino == st.st_ino) p = "."; else { p = state.pwd + strlen(state.pwd); while (p > state.pwd) { if (*--p == '/') { if (p == state.pwd) report(3, ". not under VPATH", s, 0); *p = 0; if (stat(state.pwd, &ts)) report(3, "cannot stat", state.pwd, 0); *p = '/'; if (ts.st_dev == st.st_dev && ts.st_ino == st.st_ino) { p++; break; } } } if (p <= state.pwd) report(3, "cannot determine viewpath offset", s, 0); } } n = strlen(s); if (!p) abort(); if (!(vp = newof(0, View_t, 1, strlen(p) + n + 2))) report(3, "out of memory [view]", s, 0); vp->node = n + 1; strcpy(vp->dir, s); *(vp->dir + n) = '/'; strcpy(vp->dir + n + 1, p); report(-4, vp->dir, "view", 0); if (!state.view) state.view = zp = vp; else zp = zp->next = vp; if (!c) break; *t++ = c; s = t; } } } /* * return next '?' or '}' in nested '}' */ static char *cond(char *s) { int n; if (*s == '?') s++; n = 0; for (;;) { switch (*s++) { case 0: break; case '{': n++; continue; case '}': if (!n--) break; continue; case '?': if (!n) break; continue; default: continue; } break; } return s - 1; } /* * expand var refs from s into buf */ static void substitute(Buf_t *buf, char *s) { char *t, *q; char *v; /* variable's value */ char *b; /* beginning: the literal expansion starting at $ */ int c, n; int found_AR = 0; /* 1 if ${AR} encountered */ int valid_sh_name; /* if set, the variable name is valid in sh(1) */ int newexp; /* if set, %{...}, otherwise ${...} */ char *vnterm; /* pointer to byte following variable name */ while (c = *s++) { if ((c == '%' || (c == '$' && state.strict < 4)) && *s == '{') { newexp = (c == '%'); b = s - 1; t = ++s; n = *t == '-' ? 0 : '-'; valid_sh_name = 1; while ( (c = *s) && (c != '?' || s == t) && c != '+' && c != n && (c != ':' && c != '=' && c != '[' || newexp) && c != '}' ) { s++; if (!isalnum(c) && c != '_') valid_sh_name = 0; } vnterm = s; /* Zero-terminate the variable name */ *vnterm = 0; /* Keep unexpanded if it looks like a ksh array expansion ${var[subscript]} */ if (c == '[') { append(buf, b); *s = c; continue; } /* Obtain value */ v = getval(state.vars, t); /* * In strict >= 2, always keep ${foo:-bar}, ${foo:+bar}, ${foo:=bar}, ${foo=bar} * unexpanded for passing on to shell scripts in 'exec'. * * Before strict==2, this depends on whether the MAM variable value is nonexistent * or (if ':') empty, which does not make a lot of sense, as that is not valid MAM * expansion syntax and the feature is not actually implemented properly at all. */ if ((c == ':' || c == '=') && (state.strict >= 2 || !v || c == ':' && !*v)) { append(buf, b); *s = c; continue; } /* A really absurd hack, see check for found_AR further below */ if (!newexp && strcmp(t, "AR") == 0) found_AR = 1; /* Un-terminate the variable name */ *vnterm = c; /* Find the ending '}', dealing with nesting */ if (c && c != '}') { n = 1; for (t = ++s; *s; s++) if (*s == '{') n++; else if (*s == '}' && !--n) break; } /* Special expansion syntax */ switch (c) { case '?': /* ${variable?c?x?y?} */ q = cond(t - 1); if (v) { if (((q - t) != 1 || *t != '*') && strncmp(v, t, q - t)) v = 0; } else if (q == t) v = s; t = cond(q); if (v && *v) { if (t > q) { c = *t; *t = 0; substitute(buf, q + 1); *t = c; } } else { q = cond(t); if (q > t) { c = *q; *q = 0; substitute(buf, t + 1); *q = c; } } break; case '+': case '-': /* ${variable+x}, ${variable-x} */ if ((v == 0 || *v == 0) == (c == '-')) { c = *s; *s = 0; substitute(buf, t); *s = c; break; } if (c != '-') break; /* FALLTHROUGH */ case 0: case '=': case '}': if (v) { /* * Perform the expansion: append the value of the variable to the buffer. */ if (found_AR && strncmp(t, "mam_lib", 7) == 0 && state.strict < 2) { /* * Absurd AT&T hack from 2007. The relevant src/cmd/INIT/RELEASE entry: * 07-02-26 mamake.c: expand first of ${mam_lib*} for ${AR} * i.e.: after ${AR}, expand any ${mam_lib*} to only first word of its value. * * In the entire AST repository's history, this has only been used once, in * libcmd/Mamfile, to extract sumlib.o from libsum.a (to add it to libcmd.a): * * exec - ${AR} x ${mam_libsum} sumlib.o * * Taking the first word from ${mam_libsum} can very easily be handled * by the shell script instead, so this is disabled at strict level 2+. */ for (t = v; isspace(*t); t++); for (; *t && !isspace(*t); t++); if (*t) *t = 0; else t = 0; substitute(buf, v); if (t) *t = ' '; } else if (state.strict < 2) { /* Recursively expand variable references in values (no loop detection)! */ substitute(buf, v); } else { /* Sanity at long last. Variables expand to their literal values. */ append(buf, v); } } else if (newexp) { *vnterm = 0; report(3, "undefined variable", t, 0); } else if (valid_sh_name || state.strict >= 2) { c = *s; *s = 0; append(buf, b); *s = c; continue; } break; } if (*s) s++; } else add(buf, c); } } /* * expand var refs from s into buf and return buf base */ static char *expand(Buf_t *buf, char *s) { substitute(buf, s); return use(buf); } /* * stat() with .exe check */ static char *status(Buf_t *buf, size_t off, char *path, struct stat *st) { int r; char *s; Buf_t *tmp; if (!stat(path, st)) return path; if (!(tmp = buf)) { tmp = buffer(); off = 0; } if (off) setsize(tmp, off); else append(tmp, path); append(tmp, ".exe"); s = use(tmp); r = stat(s, st); if (!buf) { drop(tmp); s = path; } if (r) { if (off) s[off] = 0; s = 0; } return s; } /* * return path to file */ static char *find(Buf_t *buf, char *file, struct stat *st) { char *s; View_t *vp; int node, c; size_t o; if (s = status(buf, 0, file, st)) { report(-3, s, "find", 0); return s; } if (vp = state.view) { node = 0; if (*file == '/') { do { if (!strncmp(file, vp->dir, vp->node)) { file += vp->node; node = 2; break; } } while (vp = vp->next); } else vp = vp->next; if (vp) { do { if (node) { c = vp->dir[vp->node]; vp->dir[vp->node] = 0; append(buf, vp->dir); vp->dir[vp->node] = c; } else { append(buf, vp->dir); append(buf, "/"); } append(buf, file); o = getsize(buf); s = use(buf); if (s = status(buf, o, s, st)) { report(-3, s, "find", 0); return s; } } while (vp = vp->next); } } return NULL; } /* * bind r to a file and return the modify time */ static void bindfile(Rule_t *r) { char *s; Buf_t *buf; struct stat st; buf = buffer(); if (s = find(buf, r->name, &st)) { if (s != r->name) r->path = reduplicate(r->path, s); r->time = st.st_mtime; r->flags |= RULE_exists; } drop(buf); } /* * pop the current input file */ static int pop(void) { int r; if (!state.sp) report(3, "input stack underflow", NULL, 0); if (!state.sp->fp || (state.sp->flags & STREAM_KEEP)) r = 0; else if (state.sp->flags & STREAM_PIPE) r = pclose(state.sp->fp); else r = fclose(state.sp->fp); if (state.sp == state.streams) state.sp = 0; else state.sp--; return r; } /* * push file onto the input stack */ static int push(char *file, Stdio_t *fp, int flags) { char *path; Buf_t *buf; struct stat st; if (!state.sp) state.sp = state.streams; else if (++state.sp >= &state.streams[elementsof(state.streams)]) report(3, "input stream stack overflow", NULL, 0); if (state.sp->fp = fp) state.sp->file = reduplicate(state.sp->file, "pipeline"); else if (flags & STREAM_PIPE) report(3, "pipe error", file, 0); else if (!file || !strcmp(file, "-") || !strcmp(file, "/dev/stdin")) { flags |= STREAM_KEEP; state.sp->file = reduplicate(state.sp->file, "/dev/stdin"); state.sp->fp = stdin; } else { buf = buffer(); if (path = find(buf, file, &st)) { if (!(state.sp->fp = fopen(path, "r"))) report(3, "cannot read", path, 0); state.sp->file = reduplicate(state.sp->file, path); drop(buf); } else { drop(buf); pop(); if (flags & STREAM_MUST) report(3, "not found", file, 0); return 0; } } state.sp->flags = flags; state.sp->line = 0; return 1; } /* * return the next input line */ static char *input(void) { static char input[8*CHUNK]; /* input buffer */ char *e; if (!state.sp) report(3, "no input file stream", NULL, 0); if (!fgets(input, sizeof(input), state.sp->fp)) { if (ferror(state.sp->fp)) report(3, "read error", NULL, 0); return NULL; } if (*input && *(e = input + strlen(input) - 1) == '\n') *e = 0; state.sp->line++; return input; } /* * pass shell action s to ${SHELL:-/bin/sh} * the -c wrapper ensures that scripts are run in the selected shell * even on systems that otherwise demand #! magic (can you say Cygwin) */ static int execute(char *s) { int stat; pid_t pid; if (!state.shell && (!(state.shell = getval(state.vars, "SHELL")) || !strcmp(state.shell, sh))) state.shell = sh; pid = fork(); if (pid < 0) report(3, strerror(errno), "fork() failed", 0); if (pid == 0) { /* child */ report(-5, s, "exec", 0); execl(state.shell, "sh", "-c", s, (char*)0); if (errno == ENOENT) exit(127); exit(126); } /* parent */ waitpid(pid, &stat, 0); if (WIFEXITED(stat)) return WEXITSTATUS(stat); if (WIFSIGNALED(stat)) return WTERMSIG(stat) + 128; return 128; } /* * run action s to update r */ static void run(Rule_t *r, char *s) { Rule_t *q; char *t; int c, i, j, x; Stat_t st; Buf_t *buf; if (r->flags & RULE_error) return; buf = buffer(); if (!strncmp(s, "mamake -r ", 10)) { state.verified = 1; x = !state.never; } else x = state.exec; if (x) { /* stubs for backward compat */ if (!state.strict) append(buf, "alias silent=\n" "ignore() { env \"$@\" || :; }\n" ); /* find commands in the current working directory first */ append(buf, "case $PATH in\n" ".:* | :*) ;;\n" "*) PATH=.:$PATH;;\n" "esac\n" ); /* disable global pathname expansion for safer field splitting */ if (state.strict >= 2) append(buf,"set -f\n"); /* show trace for the shell action commands */ if (!(r->flags & RULE_notrace)) append(buf,"set -x\n"); /* add the shim if one was set */ if (state.shim) append(buf, state.shim); } /* * Do viewpathing */ if (state.view) { char *tofree = NULL; if (x && state.shim) { /* Also subject the user-set shim to viewpathing * (plus other code preprended above, but it should not contain anything viewpathable) */ char *pre = use(buf); size_t n = strlen(pre); if (!(tofree = malloc(n + strlen(s) + 1))) report(3, "out of memory [run]", NULL, 0); strcpy(tofree, pre); strcpy(tofree + n, s); s = tofree; } /* Find words to apply viewpathing to */ do { for (; delimiter(*s); s++) add(buf, *s); for (t = s; *s && !delimiter(*s); s++); c = *s; *s = 0; if (c == '=') { append(buf, t); continue; } /* * If the word matches the name of a non-generated prerequisite, * replace it with its canonical path within the source directory. */ if ((q = getval(state.rules, t)) && q->path && !(q->flags & RULE_generated)) append(buf, q->path); else { append(buf, t); /* * Viewpathing for -I cc flags (include path directories): * duplicate every '-Ipath' and '-I path', where 'path' is a relative * pathname (i.e. not starting with '/'). The duplicate points to the * corresponding canonical path in the source directory. */ if (*t == '-' && *(t + 1) == 'I' && (*(t + 2) || c)) { if (*(t + 2)) i = 2; else { for (i = 3; isspace(*(t + i)); i++); *s = c; for (s = t + i; *s && !isspace(*s); s++); c = *s; *s = 0; append(buf, t + 2); } if (*(t + i) && *(t + i) != '/') { View_t *v = state.view; while (v = v->next) { add(buf, ' '); for (j = 0; j < i; j++) add(buf, *(t + j)); append(buf, v->dir); if (*(t + i) != '.' || *(t + i + 1)) { add(buf, '/'); append(buf, t + i); } } } } } } while (*s = c); s = use(buf); if (tofree) free(tofree); } else if (x) { append(buf, s); s = use(buf); } if (x) { if (c = execute(s)) error_making(r, c); if (status(NULL, 0, r->name, &st)) { r->time = st.st_mtime; r->flags |= RULE_exists; } else r->time = NOW; } else { fprintf(stdout, "%s\n", s); if (state.debug) fflush(stdout); r->time = NOW; r->flags |= RULE_exists; } drop(buf); } /* * return the full path for s using buf workspace */ static char *path(Buf_t *buf, char *s, int must) { char *p, *d, *x, *e; int c, t; size_t o; Stat_t st; for (e = s; *e && !isspace(*e); e++); t = *e; if ((x = status(buf, 0, s, &st)) && (st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))) return x; if (!(p = getval(state.vars, "PATH"))) report(3, "variable not defined", "PATH", 0); do { for (d = p; *p && *p != ':'; p++); c = *p; *p = 0; if (*d && (*d != '.' || *(d + 1))) { append(buf, d); add(buf, '/'); } *p = c; if (t) *e = 0; append(buf, s); if (t) *e = t; o = getsize(buf); x = use(buf); if ((x = status(buf, o, x, &st)) && (st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))) return x; } while (*p++); if (must) report(3, "command not found", s, 0); return NULL; } /* * generate (if necessary) and read the MAM probe information * done on the first `setv CC ...' */ static void probe(void) { char *cc, *s; unsigned long h, q; Buf_t *buf, *pro, *tmp; struct stat st; static char let[] = "ABCDEFGHIJKLMNOP"; static char cmd[] = "mamprobe"; if (!(cc = getval(state.vars, "CC"))) cc = "cc"; buf = buffer(); s = path(buf, cmd, 1); q = stat(s, &st) ? 0 : (unsigned long)st.st_mtime; pro = buffer(); s = cc = path(pro, cc, 1); for (h = 0; *s; s++) h = h * 0x63c63cd9L + *s + 0x9c39c33dL; if (!(s = getval(state.vars, "INSTALLROOT"))) report(3, "variable must be defined", "INSTALLROOT", 0); append(buf, s); append(buf, "/lib/probe/C/mam/"); for (h &= 0xffffffffL; h; h >>= 4) add(buf, let[h & 0xf]); s = use(buf); h = stat(s, &st) ? 0 : (unsigned long)st.st_mtime; if (h < q || !push(s, NULL, 0)) { tmp = buffer(); append(tmp, cmd); add(tmp, ' '); append(tmp, s); add(tmp, ' '); append(tmp, cc); if (execute(use(tmp))) report(3, "cannot generate probe info", s, 0); drop(tmp); if (!push(s, NULL, 0)) report(3, "cannot read probe info", s, 0); } drop(pro); drop(buf); make(rule(""), 0, 0, NULL); pop(); } /* * add attributes in s to r */ static void attributes(Rule_t *r, char *s) { char *t; size_t n; for (;;) { int flag = 0; for (; isspace(*s); s++); for (t = s; *s && !isspace(*s); s++); if (!(n = s - t)) break; switch (*t) { case 'd': if (n == 8 && !strncmp(t, "dontcare", n)) flag = RULE_dontcare; break; case 'g': /* 'exec' assigns this attribute; ignore explicit assignment at strict level 1 */ if (n == 9 && !strncmp(t, "generated", n)) flag = state.strict ? -1 : RULE_generated; break; case 'i': if (n == 6 && !strncmp(t, "ignore", n)) flag = RULE_ignore; else if (state.strict < 4 && n == 8 && !strncmp(t, "implicit", n)) flag = RULE_dontcare; break; case 'v': if (n == 7 && !strncmp(t, "virtual", n)) flag = RULE_virtual; break; case 'a': if (n == 7 && !strncmp(t, "archive", n)) flag = -1; /* not implemented */ break; case 'j': if (n == 5 && !strncmp(t, "joint", n)) flag = -1; /* not implemented */ break; case 'n': if (n == 7 && !strncmp(t, "notrace", n)) flag = RULE_notrace; break; } if (flag > 0) r->flags |= flag; else if (flag == 0 || state.strict >= 2) { t[n] = '\0'; report(3, "unknown attribute", t, 0); } else if (state.strict) report(1, "deprecated", t, 0); } } /* * define ${mam_libX} for library reference lib * * lib is expected to be in the format "-lX" */ #define LIB_VARPREFIX "mam_lib" static char *require(char *lib, int dontcare) { char *s, *r, varname[64]; if (strlen(lib + 2) > sizeof(varname) - sizeof(LIB_VARPREFIX)) report(3, "-lname too long", lib, 0); sprintf(varname, LIB_VARPREFIX "%s", lib + 2); if (!(r = getval(state.vars, varname))) { Buf_t *buf = buffer(), *tmp = buffer(); int c, tofree = 0; FILE *f; struct stat st; s = 0; for (;;) { if (s) append(buf, s); if (r = getval(state.vars, "mam_cc_PREFIX_ARCHIVE")) append(buf, r); append(buf, lib + 2); if (r = getval(state.vars, "mam_cc_SUFFIX_ARCHIVE")) append(buf, r); r = expand(tmp, use(buf)); if (!stat(r, &st)) break; if (s) { r = lib; break; } s = "%{INSTALLROOT}/lib/"; } if (r != lib) { tofree = 1; r = duplicate(r); } setval(state.vars, varname, r); append(tmp, lib + 2); append(tmp, ".req"); if (!(f = fopen(use(tmp), "r"))) { append(tmp, "%{INSTALLROOT}/lib/lib/"); append(tmp, lib + 2); f = fopen(expand(buf, use(tmp)), "r"); } if (f) { for (;;) { while (isspace(c = fgetc(f))); if (c == EOF) break; do { add(tmp, c); } while ((c = fgetc(f)) != EOF && !isspace(c)); s = use(tmp); if (s[0] && (s[0] != '-' || s[1])) { add(buf, ' '); append(buf, require(s, 0)); } } fclose(f); if (tofree) free(r); r = use(buf); } else if (dontcare) { append(tmp, "echo 'int main(void){return 0;}' > libtest.$$.c\n" \ "%{CC} %{CCFLAGS} -o libtest.$$.x libtest.$$.c "); append(tmp, r); append(tmp, " >/dev/null 2>&1\n" "c=$?\n" "exec rm -rf libtest.$$.* &\n" /* also remove artefacts like *.dSYM dir (macOS) */ "exit $c\n"); if (execute(expand(buf, use(tmp)))) { if (tofree) free(r); r = ""; } } r = duplicate(r); setval(state.vars, varname, r); drop(tmp); drop(buf); } return r; } /* * update ${<}, ${^} and ${?} */ static void update_allprev(Rule_t *r, char *all, char *upd) { char *name = r->name; size_t n = strlen(name), nn; /* set ${<} */ auto_prev->value = reduplicate(auto_prev->value, name); /* restore ${^}, append to it */ if (nn = strlen(all)) (all = realloc(all, nn + n + 2)) && (all[nn++] = ' '); else all = malloc(n + 1); if (!all) report(3, "out of memory [upd_allprev]", NULL, 0); strcpy(all + nn, name); auto_allprev->value = all; /* restore ${?}, append to it if rule was updated */ if (r->flags & RULE_updated) { if (nn = strlen(upd)) (upd = realloc(upd, nn + n + 2)) && (upd[nn++] = ' '); else upd = malloc(n + 1); if (!upd) report(3, "out of memory [upd_allprev]", NULL, 0); strcpy(upd + nn, name); } auto_updprev->value = upd; } /* * propagate last-modified timestamp and error flag from child rule to current rule */ static void propagate(Rule_t *q, Rule_t *r, unsigned long *modtime) { if (!(q->flags & RULE_ignore) && *modtime < q->time) *modtime = q->time; if (r && (q->flags & RULE_error)) r->flags |= RULE_error; } /* * input() until `done r' * * This function is called recursively for both 'make' and 'loop'. The inloop * parameter is nonzero while processing a loop, in which case modtime and * cmd are passed on from the caller and updated in the caller upon return. * If inloop==0, modtime must be initialised to zero and parentcmd is ignored. */ static unsigned long make(Rule_t *r, int inloop, unsigned long modtime, Buf_t **parentcmd) { char *s; char *u; /* command name */ char *t; /* argument word */ char *v; /* operand string */ Rule_t *q; /* new rule */ Buf_t *buf; /* scratch buffer */ Buf_t *cmd; /* shell action */ if (inloop) cmd = *parentcmd; else { cmd = NULL; r->making++; if (r->flags & RULE_active) state.active++; if (*r->name) { if (!(r->flags & RULE_virtual)) { bindfile(r); modtime = r->time; } report(-1, r->name, "make", r->time); state.indent++; } } buf = buffer(); /* * Parse lines */ while (s = input()) { /* skip initial whitespace and empty line */ for (; isspace(*s); s++); if (!*s) continue; /* isolate command name (u), argument word (t), and the operand string (v) */ for (u = s; *s && !isspace(*s); s++); if (*s) { for (*s++ = 0; isspace(*s); s++); for (t = s; *s && !isspace(*s); s++); if (*s) for (*s++ = 0; isspace(*s); s++); v = s; } else t = v = s; /* enforce 4-letter lowercase command name */ if (u[0]<'a' || u[0]>'z' || u[1]<'a' || u[1]>'z' || u[2]<'a' || u[2]>'z' || u[3]<'a' || u[3]>'z' || u[4] && !isspace(u[4])) report(3, "not a command name", u, 0); switch (KEY(u[0], u[1], u[2], u[3])) { case KEY('b','i','n','d'): if (!(t[0] == '-' && t[1] == 'l')) report(3, "bad -lname", t, 0); s = require(t, !strcmp(v, "dontcare")); if (s && strncmp(r->name, "FEATURE/", 8) && strcmp(r->name, "configure.h")) { char *libname = t + 2; /* * bind to the *.a files that require() just derived from $INSTALLROOT/lib/lib/NAME */ for (;;) { for (t = s; *s && !isspace(*s); s++); if (*s) *s = 0; else s = 0; /* only bother if t is a path to a *.a we built (i.e. not -l...) */ if (t[0] && (t[0] != '-' || t[1] != 'l')) { q = rule(expand(buf, t)); attributes(q, v); bindfile(q); propagate(q, r, &modtime); report(-1, q->name, "bind: file", q->time); } if (!s) break; for (*s++ = ' '; isspace(*s); s++); } /* * read library header dependency rules from $INSTALLROOT/lib/mam/NAME * * ...but not for a library that was just made in the same Mamfile; its header * dependencies will already have been made as part of building that library */ append(buf, "lib"); append(buf, libname); append(buf, ".a"); if ((q = getval(state.rules, use(buf))) && (q->flags & RULE_made)) continue; /* * The _hdrdeps_libNAME_ rule is generated by mkdeps; if its * name is changed below, mkdeps.sh must be changed to match! * If it has already been made... */ append(buf, "_hdrdeps_lib"); append(buf, libname); add(buf, '_'); if ((q = getval(state.rules, use(buf))) && (q->flags & RULE_made)) { /* ...then do a 'prev _hdrdeps_libNAME_' */ propagate(q, r, &modtime); report(-2, q->name, "bind: prev", q->time); continue; } /* otherwise, include the rules file if it exists */ if (!(s = getval(state.vars, "INSTALLROOT"))) report(3, "variable must be defined", "INSTALLROOT", 0); append(buf, s); append(buf, "/lib/mam/"); append(buf, libname); s = use(buf); if (push(s, NULL, 0)) { report(-1, s, "bind: include", 0); make(rule(""), 0, 0, NULL); pop(); } } continue; case KEY('d','o','n','e'): if (inloop) { if (*t) report(3, "superflous arguments", u, 0); break; } if (*t) { /* target is optional; use it for sanity check if present */ q = rule(expand(buf, t)); if (q != r && (t[0] != '$' || state.strict)) { append(buf,q->name); append(buf," != "); append(buf,r->name); report(3, "mismatched done statement", use(buf), 0); } if (*v) { if (state.strict >= 2) report(3, "superfluous arguments", u, 0); else if (state.strict) report(1, "attributes deprecated, move to 'make'", u, 0); attributes(r, v); } } if (cmd && state.active && (state.force || r->time < modtime || !r->time && !modtime)) { char *fname = state.sp->file, *rname = r->name, *rnamepre = "", *val; size_t len; /* show a nice trace header */ /* ...mamfile path: make relative to ${PACKAGEROOT} */ if (*fname == '/' && (val = getval(state.vars, "PACKAGEROOT")) && (len = strlen(val)) && strncmp(fname, val, len) == 0 && fname[len] == '/' && fname[++len]) fname += len; /* ...rule name: change install root path prefix back to '%{INSTALLROOT}' for brevity */ if (*rname == '/' && (val = getval(state.vars, "INSTALLROOT")) && (len = strlen(val)) && strncmp(rname, val, len) == 0 && rname[len] == '/' && rname[len + 1]) rname += len, rnamepre = "%{INSTALLROOT}"; fprintf(stderr, "\n# %s: %lu-%lu: make %s%s\n", fname, r->line, state.sp->line, rnamepre, rname); /* -e option */ if (state.explain) { fprintf(stderr, "# reason: "); if (!r->time) fprintf(stderr, "target %s\n", (r->flags & RULE_virtual) ? "is virtual" : "not found"); else fprintf(stderr, "target [%lu] older than prerequisites [%lu]\n", r->time, modtime); } /* run the shell action */ run(r, use(cmd)); propagate(r, NULL, &modtime); r->flags |= RULE_updated; } r->flags |= RULE_made; if (!(r->flags & (RULE_dontcare|RULE_error|RULE_exists|RULE_generated|RULE_virtual))) error_making(r, 0); break; case KEY('e','x','e','c'): r->flags |= RULE_generated; if (r->path) { free(r->path); r->path = 0; r->time = 0; } if (state.active) { if (cmd) add(cmd, '\n'); else cmd = buffer(); /* expand MAM vars now for each line, and not for the entire script at 'done', * to avoid confusing behaviour of automatic variables such as ${<} */ append(cmd, expand(buf, v)); } /* if a shim is buffered, get it ready and reset the buffer */ if (getsize(state.shim_buf)) { state.shim = use(state.shim_buf); /* a single 'shim -' deactivates the shim */ if (*state.shim == '\n' && !state.shim[1]) state.shim = NULL; } continue; case KEY('l','o','o','p'): { off_t saveoff; char *vname, *words, *w, *nextw, *cp, *save_value; Dict_item_t *vnode; unsigned long saveline = state.sp->line; if (!*v) report(3, "syntax error", u, 0); /* remember current offset for repeated reading */ if ((saveoff = ftello(state.sp->fp)) < 0) report(3, "unseekable input", u, 0); /* iterate through one or more whitespace-separated words */ vname = duplicate(expand(buf, t)); w = words = duplicate(expand(buf, v)); vnode = search(state.vars, vname, 1); save_value = vnode->value; vnode->value = empty; for (w = words; w; w = nextw) { /* zero-terminate current word and find next word */ nextw = NULL; for (cp = w; *cp && !isspace(*cp); cp++); if (*cp) { *cp++ = '\0'; for (; *cp && isspace(*cp); cp++); if (*cp) nextw = cp; } /* set iteration variable to current word */ vnode->value = w; /* reposition input to the start of this loop block */ if (w != words) { if (fseeko(state.sp->fp, saveoff, SEEK_SET) < 0) report(3, "fseek failed", u, 0); state.sp->line = saveline; } /* (re)read the loop block until 'done', in the context of the current rule */ modtime = make(r, 1, modtime, &cmd); } vnode->value = save_value; free(words); free(vname); continue; } case KEY('m','a','k','e'): { char *save_making = auto_making->value; char *save_allprev = auto_allprev->value; char *save_updprev = auto_updprev->value; char *name = expand(buf, t); if ((q = getval(state.rules, name)) && (q->flags & RULE_made)) report(state.strict < 3 ? 1 : 3, "rule already made", name, 0); if (!q) q = rule(name); /* set ${@}; empty ${?}, ${^} and ${<} */ auto_making->value = q->name; auto_updprev->value = empty; auto_allprev->value = empty; auto_prev->value = reduplicate(auto_prev->value, empty); if (q->making) report(state.strict < 3 ? 1 : 3, "rule already being made", name, 0); else { /* make the target */ attributes(q, v); make(q, 0, 0, NULL); propagate(q, r, &modtime); } /* update ${<}, restore/update ${^} and ${?} */ if (auto_allprev->value != empty) free(auto_allprev->value); if (auto_updprev->value != empty) free(auto_updprev->value); update_allprev(q, save_allprev, save_updprev); /* restore ${@} */ auto_making->value = save_making; continue; } case KEY('m','a','k','p'): case KEY('p','r','e','v'): { const int makp = (u[0] == 'm'); char *name = expand(buf, t); q = getval(state.rules, name); if (!q && !makp && !state.strict) rule(name); /* for backward compat */ else if (!q && (makp || state.strict < 4)) { /* declare a simple source file prerequisite */ attributes(q = rule(name), v); if (!(q->flags & RULE_virtual)) { bindfile(q); if (!(q->flags & (RULE_dontcare | RULE_exists))) error_making(q, 0); propagate(q, r, &modtime); } q->flags |= RULE_made; report(-2, q->name, "makp", q->time); } else if (makp) { if (q->flags & RULE_made) report(3, name, "rule already made", 0); } else if (!q) report(3, name, "prev: rule not made", 0); else if (*v) report(3, v, "prev: attributes not allowed", 0); else if (q->making) report(state.strict < 3 && !makp ? 1 : 3, "rule already being made", name, 0); else { propagate(q, r, &modtime); report(-2, q->name, "prev", q->time); } /* update ${<}, ${^} and ${?} */ update_allprev(q, auto_allprev->value, auto_updprev->value); continue; } case KEY('s','e','t','v'): if (!getval(state.vars, t)) { if (*v == '"' && state.strict < 2) { s = v + strlen(v) - 1; if (*s == '"') { *s = 0; v++; } } v = duplicate(expand(buf, v)); setval(state.vars, t, v); if (strcmp(t, "MAMAKE_STRICT") == 0) state.strict = *v ? atoi(v) : 1; } if (!state.probed && strcmp(t, "CC") == 0) { state.probed = 1; probe(); } continue; case KEY('s','h','i','m'): state.shim = NULL; /* add line of code to shim buffer */ if (*v) append(state.shim_buf, expand(buf, v)); add(state.shim_buf, '\n'); continue; case KEY('n','o','t','e'): /* comment command */ continue; case KEY('i','n','f','o'): case KEY('m','e','t','a'): if (!state.strict) continue; /* FALLTHROUGH */ default: report(3, "unknown command", u, 0); } break; } drop(buf); if (inloop) { *parentcmd = cmd; return modtime; } if (cmd) drop(cmd); if (*r->name) { state.indent--; report(-1, r->name, "done", modtime); } if (r->flags & RULE_active) state.active--; r->making--; return r->time = modtime; } /* * verify that active targets were made */ static int verify(Dict_item_t *item) { Rule_t *r = item->value; if ((r->flags & (RULE_active|RULE_error|RULE_made)) == RULE_active) error_making(r, 0); return 0; } /* * return 1 if name is an initializer */ static int initializer(char *name) { char *s; if (s = strrchr(name, '/')) s++; else s = name; return !strncmp(s, "INIT", 4); } /* * update recursion leaf r and its prerequisites */ static int update(Rule_t *r) { List_t *x; Buf_t *buf; char *args = getval(state.vars, "MAMAKEARGS"); int testing = !strcmp(args, "test"); /* topological sort */ r->flags |= RULE_made; if (r->leaf) r->leaf->flags |= RULE_made; for (x = r->prereqs; x; x = x->next) if (x->rule->leaf && !(x->rule->flags & RULE_made)) update(x->rule); buf = buffer(); /* announce */ { char *p, *q; size_t n; append(buf, state.pwd); add(buf, '/'); append(buf, r->name); p = use(buf); /* show path relative to ${INSTALLROOT} */ q = getval(state.vars, "INSTALLROOT"); if (q && strncmp(p, q, n = strlen(q)) == 0) p += n + 1; fprintf(stderr, "\n# ... %sing %s ...\n", testing ? "test" : "mak", p); if (state.explain) fprintf(stderr, "# reason: recursion\n"); } /* do */ append(buf, "$MAMAKE_DEBUG_PREFIX "); append(buf, getval(state.vars, "MAMAKE")); append(buf, " -C "); append(buf, r->name); add(buf, ' '); append(buf, args); run(r, use(buf)); drop(buf); return 0; } /* * scan Mamfile prereqs */ static int scan(Dict_item_t *item) { Rule_t *r = item->value; char *s, *t; Rule_t *q; Buf_t *buf; /* * drop non-leaf rules */ if (!r->leaf) return 0; /* * always make initializers */ if (initializer(r->name)) { if (!(r->flags & RULE_made)) update(r); return 0; } buf = buffer(); append(buf, r->name); add(buf, '/'); append(buf, mamfile); if (push(use(buf), NULL, 0)) { while (s = input()) { for (; isspace(*s); s++); /* examine only commands of the form bind -lfoo */ if (s[0] != 'b' || s[1] != 'i' || s[2] != 'n' || s[3] != 'd' || !isspace(s[4])) continue; for (s += 5; isspace(*s); s++); if (s[0] != '-' || s[1] != 'l' || !s[2]) continue; /* construct potential leaf directory name */ append(buf, "lib"); append(buf, s + 2); t = use(buf); for (s = t; *s && !isspace(*s); s++); *s = '\0'; /* add a rule and prepend it onto the prerequisites */ if ((q = getval(state.leaf, t)) && q != r) cons(r, q); } pop(); } drop(buf); return 0; } /* * descend into op and its prereqs */ static int descend(Dict_item_t *item) { Rule_t *r = item->value; if (!state.active && (!(r->flags & RULE_active) || !(r = getval(state.leaf, r->name)))) return 0; return r->leaf && !(r->flags & RULE_made) ? update(r) : 0; } /* * append the non-leaf active targets to state.opt */ static int active(Dict_item_t *item) { Rule_t *r = item->value; if (r->flags & RULE_active) { if (r->leaf || getval(state.leaf, r->name)) state.active = 0; else { add(state.opt, ' '); append(state.opt, r->name); } } return 0; } /* * recurse on mamfiles in subdirs matching pattern */ static int recurse(char *pattern) { char *s, *t; Rule_t *r; Buf_t *buf, *tmp; struct stat st; /* * first determine the MAM subdirs */ tmp = buffer(); buf = buffer(); state.exec = !state.never; state.leaf = dictionary(); append(buf, "ls -d "); append(buf, pattern); s = use(buf); push("recurse", popen(s, "r"), STREAM_PIPE); while (s = input()) { append(buf, s); add(buf, '/'); append(buf, mamfile); if (find(tmp, use(buf), &st)) { r = rule(s); if (t = strrchr(r->name, '/')) t++; else t = r->name; r->leaf = rule(t); setval(state.leaf, t, r); } } pop(); drop(buf); drop(tmp); /* * grab the non-leaf active targets */ if (!state.active) { state.active = 1; walk(state.rules, active); } setval(state.vars, "MAMAKEARGS", duplicate(use(state.opt) + 1)); /* * scan the Mamfile and descend */ walk(state.rules, scan); while (state.view) { View_t *prev = state.view; state.view = state.view->next; free(prev); } walk(state.rules, descend); return 0; } int main(int argc, char **argv) { char **e, *s, *t, *v; Buf_t *tmp; int c; /* * initialize the state */ state.id = "mamake"; state.active = 1; state.exec = 1; state.file = mamfile; state.opt = buffer(); state.shim_buf = buffer(); state.rules = dictionary(); state.vars = dictionary(); setval(state.vars, "MAMAKE", *argv); /* * parse the options */ #if _PACKAGE_ast error_info.id = state.id; for (;;) { switch (optget(argv, usage)) { case 'e': append(state.opt, " -e"); state.explain = 1; continue; case 'i': append(state.opt, " -i"); state.ignore = 1; continue; case 'k': append(state.opt, " -k"); state.keepgoing = 1; continue; case 'N': state.never = 1; /* FALLTHROUGH */ case 'n': append(state.opt, " -n"); state.exec = 0; continue; case 'F': append(state.opt, " -F"); state.force = 1; continue; case 'V': return !(write(1, id + 10, strlen(id) - 12) > 0 && putchar('\n') == '\n'); case 'f': append(state.opt, " -f "); append(state.opt, opt_info.arg); state.file = opt_info.arg; continue; case 'r': state.recurse = opt_info.arg; continue; case 'C': state.directory = opt_info.arg; continue; case 'D': append(state.opt, " -D"); append(state.opt, opt_info.arg); state.debug = -opt_info.num; if (state.debug > 0) state.debug = 0; continue; case 'G': append(state.opt, " -G"); setval(state.vars, "-debug-symbols", "1"); continue; case 'S': append(state.opt, " -S"); setval(state.vars, "-strip-symbols", "1"); continue; case '?': error(ERROR_usage(2), "%s", opt_info.arg); UNREACHABLE(); case ':': error(2, "%s", opt_info.arg); continue; } break; } if (error_info.errors) { error(ERROR_usage(2), "%s", optusage(NULL)); UNREACHABLE(); } argv += opt_info.index; #else while ((s = *++argv) && *s == '-') { if (*(s + 1) == '-') { if (!*(s + 2)) { append(state.opt, " --"); argv++; break; } for (t = s += 2; *t && *t != '='; t++); if (!strncmp(s, "debug-symbols", t - s) && append(state.opt, " -G") || !strncmp(s, "strip-symbols", t - s) && append(state.opt, " -S")) { if (*t) { v = t + 1; if (t > s && *(t - 1) == '+') t--; c = *t; *t = 0; } else { c = 0; v = "1"; } setval(state.vars, s - 1, v); if (c) *t = c; continue; } usage(); break; } for (;;) { switch (*++s) { case 0: break; case 'e': append(state.opt, " -e"); state.explain = 1; continue; case 'i': append(state.opt, " -i"); state.ignore = 1; continue; case 'k': append(state.opt, " -k"); state.keepgoing = 1; continue; case 'N': state.never = 1; /* FALLTHROUGH */ case 'n': append(state.opt, " -n"); state.exec = 0; continue; case 'F': append(state.opt, " -F"); state.force = 1; continue; case 'G': append(state.opt, " -G"); setval(state.vars, "-debug-symbols", "1"); continue; case 'S': append(state.opt, " -S"); setval(state.vars, "-strip-symbols", "1"); continue; case 'V': return !(write(1, id + 10, strlen(id) - 12) > 0 && putchar('\n') == '\n'); case 'f': case 'r': case 'C': case 'D': t = s; if (!*++s && !(s = *++argv)) { report(2, "option value expected", t, 0); usage(); } else switch (*t) { case 'f': append(state.opt, " -f "); append(state.opt, s); state.file = s; break; case 'r': state.recurse = s; break; case 'C': state.directory = s; break; case 'D': append(state.opt, " -D"); append(state.opt, s); state.debug = -atoi(s); if (state.debug > 0) state.debug = 0; break; } break; default: report(2, "unknown option", s, 0); /* FALLTHROUGH */ case '?': usage(); break; } break; } } #endif /* * option incompatibility */ if (state.force) state.explain = 0; /* * load the environment */ for (e = environ; s = *e; e++) { for (t = s; *t; t++) { if (*t == '=') { *t = 0; setval(state.vars, s, t + 1); *t = '='; break; } } } /* * initialize the automatic variables */ auto_making = search(state.vars, "@", 1); auto_prev = search(state.vars, "<", 1); auto_allprev = search(state.vars, "^", 1); auto_updprev = search(state.vars, "?", 1); auto_making->value = auto_prev->value = auto_allprev->value = auto_updprev->value = empty; /* * grab the command line targets and variable definitions */ while (s = *argv++) { for (t = s; *t; t++) { if (*t == '=') { v = t + 1; if (t > s && *(t - 1) == '+') t--; c = *t; *t = 0; setval(state.vars, s, v); tmp = buffer(); append(tmp, s); append(tmp, ".FORCE"); setval(state.vars, use(tmp), v); drop(tmp); *t = c; break; } } if (!*t) { rule(s)->flags |= RULE_active; state.active = 0; if (state.recurse) continue; } add(state.opt, ' '); add(state.opt, '\''); append(state.opt, s); add(state.opt, '\''); } /* * initialize the views */ if (state.directory && chdir(state.directory)) report(3, "cannot change working directory", NULL, 0); view(); /* * recursion drops out here */ if (state.recurse) return recurse(state.recurse); /* * read the mamfile(s) and bring the targets up to date */ setval(state.vars, "MAMAKEARGS", duplicate(use(state.opt) + 1)); push(state.file, NULL, STREAM_MUST); make(rule(""), 0, 0, NULL); pop(); /* * verify that active targets were made */ if (!state.active && !state.verified) { state.keepgoing = 1; walk(state.rules, verify); } /* * done */ return state.errors != 0; } ksh-1.0.10/src/cmd/INIT/mamake.rt000066400000000000000000000055641465301102200162610ustar00rootroot00000000000000NOTE regression tests for the mamake command # To regenerate mamake.tst from this file: # # bin/package use # cd src/cmd/INIT # VPATH=.:. mktest mamake.rt > mamake.tst # # WARNING: the regeneration assumes mamake's output is correct, so VERIFY THE RESULTS! # Always do 'git diff mamake.tst' to check that no unexpected changes have been made. # # WARNING 2: do not use 'Mamfile' as the data file for the tests, or the # regeneration will overwrite and then delete the local Mamfile. Mamake # supports an -f option to use an alternative file name. UNIT mamake # ====== # the one original AT&T test -- changed to test both legacy and strict mode for strict in '' 'setv MAMAKE_STRICT 1' 'setv MAMAKE_STRICT 2' do TEST expansions ${strict:+at strict level ${strict##* }} DATA ._tmp_Mamfile_ <&2 make shimtest virtual notrace make looptest virtual notrace loop _iter_ een twee drie vier exec - echo ${_iter_} hoedje${_iter_?een??s} van papier >&2 done done exec - echo "nu is 't gedaan met 't ${_iter_}" >&2 done EOF EXEC -f ._tmp_Mamfile_ ksh-1.0.10/src/cmd/INIT/mamake.tst000066400000000000000000000203411465301102200164340ustar00rootroot00000000000000# : : generated from mamake.rt by mktest : : # # regression tests for the mamake command UNIT mamake TEST 01 expansions EXEC -n -f ._tmp_Mamfile_ INPUT -n - INPUT ._tmp_Mamfile_ $'info mam static 00000 1994-07-17 make (AT&T Research) 5.3 2009-05-05 setv DEFINED defined setv EMPTY make all virtual exec - echo DEFINED ${DEFINED} exec - echo DEFINED:VALUE ${DEFINED:VALUE} exec - echo DEFINED:-VALUE ${DEFINED:-VALUE} exec - echo DEFINED=VALUE ${DEFINED=VALUE} exec - echo DEFINED[VALUE] ${DEFINED[VALUE]} exec - echo DEFINED.COMPONENT ${DEFINED.COMPONENT} exec - echo DEFINED.COMPONENT[VALUE] ${DEFINED.COMPONENT[VALUE]} exec - echo EMPTY ${EMPTY} exec - echo EMPTY:VALUE ${EMPTY:VALUE} exec - echo EMPTY:-VALUE ${EMPTY:-VALUE} exec - echo EMPTY=VALUE ${EMPTY=VALUE} exec - echo EMPTY[VALUE] ${EMPTY[VALUE]} exec - echo EMPTY.COMPONENT ${EMPTY.COMPONENT} exec - echo EMPTY.COMPONENT[VALUE] ${EMPTY.COMPONENT[VALUE]} exec - echo __NoT_DeFiNeD__ ${__NoT_DeFiNeD__} exec - echo __NoT_DeFiNeD__:VALUE ${__NoT_DeFiNeD__:VALUE} exec - echo __NoT_DeFiNeD__:-VALUE ${__NoT_DeFiNeD__:-VALUE} exec - echo __NoT_DeFiNeD__=VALUE ${__NoT_DeFiNeD__=VALUE} exec - echo __NoT_DeFiNeD__[VALUE] ${__NoT_DeFiNeD__[VALUE]} exec - echo __NoT_DeFiNeD__.COMPONENT ${__NoT_DeFiNeD__.COMPONENT} exec - echo __NoT_DeFiNeD__.COMPONENT[VALUE] ${__NoT_DeFiNeD__.COMPONENT[VAL'\ $'UE]} done all' OUTPUT - $'echo DEFINED defined echo DEFINED:VALUE echo DEFINED:-VALUE echo DEFINED=VALUE defined echo DEFINED[VALUE] ${DEFINED[VALUE]} echo DEFINED.COMPONENT echo DEFINED.COMPONENT[VALUE] ${DEFINED.COMPONENT[VALUE]} echo EMPTY echo EMPTY:VALUE ${EMPTY:VALUE} echo EMPTY:-VALUE ${EMPTY:-VALUE} echo EMPTY=VALUE echo EMPTY[VALUE] ${EMPTY[VALUE]} echo EMPTY.COMPONENT echo EMPTY.COMPONENT[VALUE] ${EMPTY.COMPONENT[VALUE]} echo __NoT_DeFiNeD__ ${__NoT_DeFiNeD__} echo __NoT_DeFiNeD__:VALUE ${__NoT_DeFiNeD__:VALUE} echo __NoT_DeFiNeD__:-VALUE ${__NoT_DeFiNeD__:-VALUE} echo __NoT_DeFiNeD__=VALUE ${__NoT_DeFiNeD__=VALUE} echo __NoT_DeFiNeD__[VALUE] ${__NoT_DeFiNeD__[VALUE]} echo __NoT_DeFiNeD__.COMPONENT echo __NoT_DeFiNeD__.COMPONENT[VALUE] ${__NoT_DeFiNeD__.COMPONENT[VALUE]}' ERROR - $'\n# ._tmp_Mamfile_: 4-30: make all' TEST 02 'expansions at strict level 1' EXEC -n -f ._tmp_Mamfile_ INPUT -n - INPUT ._tmp_Mamfile_ $'setv MAMAKE_STRICT 1 setv DEFINED defined setv EMPTY make all virtual exec - echo DEFINED ${DEFINED} exec - echo DEFINED:VALUE ${DEFINED:VALUE} exec - echo DEFINED:-VALUE ${DEFINED:-VALUE} exec - echo DEFINED=VALUE ${DEFINED=VALUE} exec - echo DEFINED[VALUE] ${DEFINED[VALUE]} exec - echo DEFINED.COMPONENT ${DEFINED.COMPONENT} exec - echo DEFINED.COMPONENT[VALUE] ${DEFINED.COMPONENT[VALUE]} exec - echo EMPTY ${EMPTY} exec - echo EMPTY:VALUE ${EMPTY:VALUE} exec - echo EMPTY:-VALUE ${EMPTY:-VALUE} exec - echo EMPTY=VALUE ${EMPTY=VALUE} exec - echo EMPTY[VALUE] ${EMPTY[VALUE]} exec - echo EMPTY.COMPONENT ${EMPTY.COMPONENT} exec - echo EMPTY.COMPONENT[VALUE] ${EMPTY.COMPONENT[VALUE]} exec - echo __NoT_DeFiNeD__ ${__NoT_DeFiNeD__} exec - echo __NoT_DeFiNeD__:VALUE ${__NoT_DeFiNeD__:VALUE} exec - echo __NoT_DeFiNeD__:-VALUE ${__NoT_DeFiNeD__:-VALUE} exec - echo __NoT_DeFiNeD__=VALUE ${__NoT_DeFiNeD__=VALUE} exec - echo __NoT_DeFiNeD__[VALUE] ${__NoT_DeFiNeD__[VALUE]} exec - echo __NoT_DeFiNeD__.COMPONENT ${__NoT_DeFiNeD__.COMPONENT} exec - echo __NoT_DeFiNeD__.COMPONENT[VALUE] ${__NoT_DeFiNeD__.COMPONENT[VAL'\ $'UE]} done all' OUTPUT - $'echo DEFINED defined echo DEFINED:VALUE echo DEFINED:-VALUE echo DEFINED=VALUE defined echo DEFINED[VALUE] ${DEFINED[VALUE]} echo DEFINED.COMPONENT echo DEFINED.COMPONENT[VALUE] ${DEFINED.COMPONENT[VALUE]} echo EMPTY echo EMPTY:VALUE ${EMPTY:VALUE} echo EMPTY:-VALUE ${EMPTY:-VALUE} echo EMPTY=VALUE echo EMPTY[VALUE] ${EMPTY[VALUE]} echo EMPTY.COMPONENT echo EMPTY.COMPONENT[VALUE] ${EMPTY.COMPONENT[VALUE]} echo __NoT_DeFiNeD__ ${__NoT_DeFiNeD__} echo __NoT_DeFiNeD__:VALUE ${__NoT_DeFiNeD__:VALUE} echo __NoT_DeFiNeD__:-VALUE ${__NoT_DeFiNeD__:-VALUE} echo __NoT_DeFiNeD__=VALUE ${__NoT_DeFiNeD__=VALUE} echo __NoT_DeFiNeD__[VALUE] ${__NoT_DeFiNeD__[VALUE]} echo __NoT_DeFiNeD__.COMPONENT echo __NoT_DeFiNeD__.COMPONENT[VALUE] ${__NoT_DeFiNeD__.COMPONENT[VALUE]}' ERROR - $'\n# ._tmp_Mamfile_: 4-30: make all' TEST 03 'expansions at strict level 2' EXEC -n -f ._tmp_Mamfile_ INPUT -n - INPUT ._tmp_Mamfile_ $'setv MAMAKE_STRICT 2 setv DEFINED defined setv EMPTY make all virtual exec - echo DEFINED ${DEFINED} exec - echo DEFINED:VALUE ${DEFINED:VALUE} exec - echo DEFINED:-VALUE ${DEFINED:-VALUE} exec - echo DEFINED=VALUE ${DEFINED=VALUE} exec - echo DEFINED[VALUE] ${DEFINED[VALUE]} exec - echo DEFINED.COMPONENT ${DEFINED.COMPONENT} exec - echo DEFINED.COMPONENT[VALUE] ${DEFINED.COMPONENT[VALUE]} exec - echo EMPTY ${EMPTY} exec - echo EMPTY:VALUE ${EMPTY:VALUE} exec - echo EMPTY:-VALUE ${EMPTY:-VALUE} exec - echo EMPTY=VALUE ${EMPTY=VALUE} exec - echo EMPTY[VALUE] ${EMPTY[VALUE]} exec - echo EMPTY.COMPONENT ${EMPTY.COMPONENT} exec - echo EMPTY.COMPONENT[VALUE] ${EMPTY.COMPONENT[VALUE]} exec - echo __NoT_DeFiNeD__ ${__NoT_DeFiNeD__} exec - echo __NoT_DeFiNeD__:VALUE ${__NoT_DeFiNeD__:VALUE} exec - echo __NoT_DeFiNeD__:-VALUE ${__NoT_DeFiNeD__:-VALUE} exec - echo __NoT_DeFiNeD__=VALUE ${__NoT_DeFiNeD__=VALUE} exec - echo __NoT_DeFiNeD__[VALUE] ${__NoT_DeFiNeD__[VALUE]} exec - echo __NoT_DeFiNeD__.COMPONENT ${__NoT_DeFiNeD__.COMPONENT} exec - echo __NoT_DeFiNeD__.COMPONENT[VALUE] ${__NoT_DeFiNeD__.COMPONENT[VAL'\ $'UE]} done all' OUTPUT - $'echo DEFINED defined echo DEFINED:VALUE ${DEFINED:VALUE} echo DEFINED:-VALUE ${DEFINED:-VALUE} echo DEFINED=VALUE ${DEFINED=VALUE} echo DEFINED[VALUE] ${DEFINED[VALUE]} echo DEFINED.COMPONENT ${DEFINED.COMPONENT} echo DEFINED.COMPONENT[VALUE] ${DEFINED.COMPONENT[VALUE]} echo EMPTY echo EMPTY:VALUE ${EMPTY:VALUE} echo EMPTY:-VALUE ${EMPTY:-VALUE} echo EMPTY=VALUE ${EMPTY=VALUE} echo EMPTY[VALUE] ${EMPTY[VALUE]} echo EMPTY.COMPONENT ${EMPTY.COMPONENT} echo EMPTY.COMPONENT[VALUE] ${EMPTY.COMPONENT[VALUE]} echo __NoT_DeFiNeD__ ${__NoT_DeFiNeD__} echo __NoT_DeFiNeD__:VALUE ${__NoT_DeFiNeD__:VALUE} echo __NoT_DeFiNeD__:-VALUE ${__NoT_DeFiNeD__:-VALUE} echo __NoT_DeFiNeD__=VALUE ${__NoT_DeFiNeD__=VALUE} echo __NoT_DeFiNeD__[VALUE] ${__NoT_DeFiNeD__[VALUE]} echo __NoT_DeFiNeD__.COMPONENT ${__NoT_DeFiNeD__.COMPONENT} echo __NoT_DeFiNeD__.COMPONENT[VALUE] ${__NoT_DeFiNeD__.COMPONENT[VALUE]}' ERROR - $'\n# ._tmp_Mamfile_: 4-30: make all' TEST 04 'nested loop with notrace' EXEC -f ._tmp_Mamfile_ INPUT -n - INPUT ._tmp_Mamfile_ $'setv MAMAKE_STRICT make looptest virtual \tloop v1 one two three \t\tloop v2 four five six \t\t\tmake ${v1}_${v2} virtual notrace \t\t\t\texec - echo \'${v1}: ${v2}\' \t\t\tdone \t\tdone \tdone \texec - : the current target is ${@} \texec - : the last target was ${<} \texec - : the targets were ${^} \texec - : the updated targets were ${?} done' OUTPUT - $'one: four one: five one: six two: four two: five two: six three: four three: five three: six' ERROR - $' # ._tmp_Mamfile_: 5-7: make one_four # ._tmp_Mamfile_: 5-7: make one_five # ._tmp_Mamfile_: 5-7: make one_six # ._tmp_Mamfile_: 5-7: make two_four # ._tmp_Mamfile_: 5-7: make two_five # ._tmp_Mamfile_: 5-7: make two_six # ._tmp_Mamfile_: 5-7: make three_four # ._tmp_Mamfile_: 5-7: make three_five # ._tmp_Mamfile_: 5-7: make three_six # ._tmp_Mamfile_: 2-14: make looptest + : the current target is looptest + : the last target was three_six + : the targets were one_four one_five one_six two_four two_five two_six thr'\ $'ee_four three_five three_six + : the updated targets were one_four one_five one_six two_four two_five two'\ '_six three_four three_five three_six' TEST 05 $'shim, \'exec\' in loop' EXEC -f ._tmp_Mamfile_ INPUT -n - INPUT ._tmp_Mamfile_ $'setv MAMAKE_STRICT 2 setv _iter_ vertier shim - echo KIJK EENS HIER >&2 make shimtest virtual notrace \tmake looptest virtual notrace \t\tloop _iter_ een twee drie vier \t\t\texec - echo ${_iter_} hoedje${_iter_?een??s} van papier >&2 \t\tdone \tdone \texec - echo "nu is \'t gedaan met \'t ${_iter_}" >&2 done' OUTPUT - ERROR - $' # ._tmp_Mamfile_: 5-9: make looptest KIJK EENS HIER een hoedje van papier twee hoedjes van papier drie hoedjes van papier vier hoedjes van papier # ._tmp_Mamfile_: 4-11: make shimtest KIJK EENS HIER nu is \'t gedaan met \'t vertier' ksh-1.0.10/src/cmd/INIT/mamprobe.sh000066400000000000000000000124251465301102200166070ustar00rootroot00000000000000######################################################################## # # # This software is part of the ast package # # Copyright (c) 1994-2011 AT&T Intellectual Property # # Copyright (c) 2020-2024 Contributors to ksh 93u+m # # and is licensed under the # # Eclipse Public License, Version 2.0 # # # # A copy of the License is available at # # https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html # # (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) # # # # Glenn Fowler # # Martijn Dekker # # # ######################################################################## ### this script contains archaic constructs that work with all sh variants ### # mamprobe - generate MAM cc probe info # Glenn Fowler (command set -o posix) 2>/dev/null && set -o posix command=mamprobe bins=$(echo "$DEFPATH:$PATH" | sed 's/:/ /g') || exit # check the options opt= case `(getopts '[-][123:xyz]' opt --xyz; echo 0$opt) 2>/dev/null` in 0123) USAGE=$' [-? @(#)$Id: mamprobe (ksh 93u+m) 2024-03-05 $ ] [+NAME?mamprobe - generate MAM cc probe info] [+DESCRIPTION?\bmamprobe\b generates MAM (make abstract machine) \bcc\b(1) probe information for use by \bmamake\b(1). \acc-path\a is the absolute path of the probed compiler and \ainfo-file\a is where the information is placed. \ainfo-file\a is usually \b$INSTALLROOT/lib/probe/C/mam/\b\ahash\a, where \ahash\a is a hash of \acc-path\a. Any \ainfo-file\a directories are created if needed. If \ainfo-file\a is \b-\b then the probe information is written to the standard output.] [+?The probed variable names get a \bmam_cc_\b prefix. Additional variables are:]{ [+_hosttype_?the \bpackage\b(1) host type] [+STDCAT?command to execute for \bcat\b(1)] [+STDCHMOD?command to execute for \bchmod\b(1)] [+STDCMP?command to execute for \bcmp\b(1)] [+STDCP?command to execute for \bcp\b(1)] [+STDED?command to execute for \bed\b(1) or \bex\b(1)] [+STDEDFLAGS?flags for \bSTDED\b] [+STDLN?command to execute for \bln\b(1)] [+STDMV?command to execute for \bmv\b(1)] [+STDRM?command to execute for \brm\b(1)] } [d:debug?Enable probe script debug trace.] info-file cc-path [+SEE ALSO?\bpackage\b(1), \bmamake\b(1), \bprobe\b(1)] ' while getopts -a "$command" "$USAGE" OPT do case $OPT in d) opt=-d ;; esac done shift `expr $OPTIND - 1` ;; *) while : do case $# in 0) break ;; esac case $1 in --) shift break ;; -) break ;; -d) opt=-d ;; -*) echo $command: $1: unknown option >&2 ;; *) break ;; esac set '' break done ;; esac # check the args case $1 in -) ;; /*) ;; *) set '' ;; esac case $2 in /*) ;; *) set '' ;; esac case $# in 0|1) echo "Usage: $command info-file cc-path" >&2; exit 2 ;; esac info=$1 shift cc=$* # find the make probe script ifs=${IFS-' '} IFS=: set $PATH IFS=$ifs script=lib/probe/C/make/probe while : do case $# in 0) echo "$0: ../$script: probe script not found on PATH" >&2 exit 1 ;; esac case $1 in '') continue ;; esac makeprobe=`echo $1 | sed 's,[^/]*$,'$script,` if test -x $makeprobe then break fi shift done # create the info dir if necessary case $info in /*) i=X$info ifs=${IFS-' '} IFS=/ set $i IFS=$ifs while : do i=$1 shift case $i in X) break ;; esac done case $info in //*) path=/ ;; *) path= ;; esac while : do case $# in 0|1) break ;; esac comp=$1 shift case $comp in '') continue ;; esac path=$path/$comp if test ! -d $path then mkdir $path || exit fi done ;; esac # generate info in a tmp file and rename when finished case $info in -) ;; *) tmp=${TMPDIR:-/tmp}/mam$$ trap "exec >/dev/null; rm -f $tmp" 0 1 2 3 15 exec > $tmp echo "probing C language processor $cc for mam information" >&2 ;; esac echo "note generated by $0 for $cc" ( set '' $opt $cc shift . $makeprobe "$@" case " $CC_DIALECT " in *" -L "*) echo "CC.L = 1" ;; esac ) | sed \ -e '/^CC\./!d' \ -e 's/^CC./setv mam_cc_/' \ -e 's/^\([^=.]*\)\./\1_/' \ -e 's/^\([^=.]*\)\./\1_/' \ -e 's/ =//' \ -e 's/\$("\([^"]*\)")/\1/g' \ -e 's/\$(\([^)]*\))/${\1}/g' \ -e 's/\${CC\./${mam_cc_}/g' echo 'setv _hosttype_ ${mam_cc_HOSTTYPE}' # STD* are standard commands/flags # (Deprecated; kept for backward compatibility) if ( ed < /dev/null 2>&1 then STDED=ed else STDED=ex fi STDEDFLAGS=- set STDCAT cat STDCHMOD chmod STDCMP cmp STDCP cp STDLN ln STDMV mv STDRM rm while : do case $# in 0|1) break ;; esac p=$2 for d in $bins do if test -x $d/$p then p=$d/$p break fi done eval $1=\$p shift shift done for n in STDCAT STDCHMOD STDCMP STDCP STDED STDEDFLAGS STDLN STDMV STDRM do eval echo setv \$n \$$n done # all done case $info in -) ;; *) exec >/dev/null test -f "$info" && rm -f "$info" cp "$tmp" "$info" chmod -w "$info" ;; esac ksh-1.0.10/src/cmd/INIT/mkdeps.sh000077500000000000000000000113211465301102200162650ustar00rootroot00000000000000######################################################################## # # # This file is part of the ksh 93u+m package # # Copyright (c) 2024 Contributors to ksh 93u+m # # and is licensed under the # # Eclipse Public License, Version 2.0 # # # # A copy of the License is available at # # https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html # # (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) # # # # Martijn Dekker # # # ######################################################################## # # MAM dependency rules generator for $INSTALLROOT/include/ast headers # By Martijn Dekker , 2024-07-15 # # Greps preinstalled AST header files for '#include ' to generate header # dependency rules for a library. The 'bind' command in mamake(1) Mamfiles will # automatically include the generated dependencies in its current rule context. # # Usage: mkdeps -lLIBRARYNAME [ -lDEPENDNECYNAME ... ] [ HEADER.h ... ] # The first -l option's argument is the short name of the library to be processed. # The second and further -l options indicate its library header dependencies. # # This sh script is POSIX compliant and compatible with shell bugs. # # POSIX-ish standard mode where available. case ${ZSH_VERSION+z} in z) emulate ksh ;; *) (command set -o posix) 2>/dev/null && set -o posix ;; esac # Safe-ish mode. CCn=' ' # one linefeed set -o noglob IFS=$CCn # === Function definitions === note() { printf "$0: %s\\n" "$@" >&2 } err_out() { note "$@" exit 3 } # Output NAME for each '#include ' grep_includes() { spc=' ' # space followed by tab sed -n "s|^[$spc]*#[$spc]*include[$spc]*<\([A-Za-z0-9_]*\)\.h>.*|\1|p" "$1" } print_indent() { tabs= i=$indent while test "$i" -gt 0 do tabs=$tabs'\t' i=$((i - 1)) done printf "$tabs%s\n" "$1" } make_hdrdeps() { test -f "$1.h" || return # external header eval "state=\${state_$1}" case $state in making) print_indent "note * FIXME: circular dependency: $1.h" ;; made) # output a 'prev' (not needed at top level; outdatedness propagates upwards) if test "$indent" -gt 1 then print_indent "prev $prefix$1.h" fi ;; *) # output a 'make' with possible recursive dependent rules eval "state_$1=making" print_indent "make $prefix$1.h" indent=$((indent + 1)) f=$(grep_includes "$1.h") || exit for f in $f do make_hdrdeps "$f" done indent=$((indent - 1)) print_indent "done" eval "state_$1=made" ;; esac } # === Initialisation === # Parse options. lib= libdeps= while getopts 'l:' opt do case $opt in l) case $lib in '') lib=$OPTARG ;; *) libdeps=$libdeps${libdeps:+$CCn}$OPTARG ;; esac ;; *) exit 2 ;; esac done shift $((OPTIND - 1)) # Init state. ast=include/ast root=${INSTALLROOT?AST environment not initialised}/$ast prevar="INCLUDE_AST" prefix="%{$prevar}/" cd "$root" || error_out "cd '$root' failed" indent=1 # Process library header dependencies. for f in $libdeps do test -f "$INSTALLROOT/lib/mam/$f" || error_out "$f: header dependencies not found" # assign state_NAME=made for each dependency header, so only prev commands are generated f=$(sed -n "s|.*make $prefix\([A-Za-z0-9_]*\)\.h.*|state_\1=made|p" "$INSTALLROOT/lib/mam/$f") || exit eval "$f" done # Validate for 'eval' safety: header file names minus $root and .h must be valid variable name components. for f do test -f "$f" || error_out "$f: not found" f=${f#"$root/"} case ${f%.h} in '' | *[!A-Za-z0-9_]*) error_out "$f: invalid header file name" ;; esac done # === Main === echo "note * Library header dependency rules for lib${lib:?option -l is required}." echo "note * Generated by mkdeps(1). Included in Mamfile by 'bind -l$lib'." echo "setv $prevar %{INSTALLROOT}/$ast" # The 'bind' command in mamake(1) checks for the _hdrdeps_lib${lib}_ rule to avoid including dependencies more than once # (it does a 'prev' instead); if the name of this internal rule is changed here, mamake.c must be changed to match! wrapper_rule=_hdrdeps_lib${lib}_ echo "make $wrapper_rule virtual" # Get mamake(1) to recursively include this library's header dependencies. for f in $libdeps do print_indent "bind -l$f" done # Generate header dependencies for the headers given at the command line. for f do f=${f#"$root/"} make_hdrdeps "${f%.h}" done echo "done $wrapper_rule" ksh-1.0.10/src/cmd/INIT/mkreq-maplib.sh000066400000000000000000000054511465301102200173670ustar00rootroot00000000000000######################################################################## # # # This file is part of the ksh 93u+m package # # Copyright (c) 1984-2012 AT&T Intellectual Property # # Copyright (c) 2020-2024 Contributors to ksh 93u+m # # and is licensed under the # # Eclipse Public License, Version 2.0 # # # # A copy of the License is available at # # https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html # # (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) # # # # Glenn Fowler # # Martijn Dekker # # # ######################################################################## # Generator for INIT's *.req library dependency files. # This script is designed to be called from src/cmd/INIT/Mamfile only. # It is based on the the code generated by the nmake MAPLIB # rule from src/cmd/INIT/MAPLIB.mk, and replaces the latter. # Set options. case ${ZSH_VERSION+z} in z) emulate ksh ;; *) (command set -o posix) 2>/dev/null && set -o posix ;; esac set -o noglob -o nounset : $INSTALLROOT # error out early # Get colon-separated compiler invocation from arguments. # Like this whole build system, we assume arguments do not contain # spaces, or if they do, that they are meant to be field-split. allcc= while test "$#" -gt 0 && test "$1" != ":" do allcc=$allcc${allcc:+ }$1 shift done test "${1-}" = ":" || { echo "$0: bad arguments" >&2; exit 1; } shift # Get the .req basename. req=$1 shift test "${1-}" = ":" || { echo "$0: bad arguments" >&2; exit 1; } shift # Get the source file names. src= while test "$#" -gt 0 && test "$1" != ":" do src=$src${src:+ }$1 shift done test "${1-}" = ":" || { echo "$0: bad arguments" >&2; exit 1; } shift # Get the libraries to test. libs= while test "$#" -gt 0 do # for each lib name also add '-' libs="$libs${libs:+ }$1 -" shift done # Setup. trap 'set +o noglob; rm -rf "$req".exe*' 0 ######### Main ########## # Generate .req file. # ######################### r=' -' for i in $src do if $allcc -c $i >/dev/null 2>&1 then rm $(basename $i .c).o & g= for p in $libs do case $p in -) if $allcc -o $req.exe $i $g >/dev/null 2>&1 then if ! $allcc -o $req.exe $i >/dev/null 2>&1 then r=$g break 2 fi fi g= ;; *) g="$g -l$p" ;; esac done fi done echo "$r" > $req.req ksh-1.0.10/src/cmd/INIT/mkreq.sh000066400000000000000000000073551465301102200161320ustar00rootroot00000000000000######################################################################## # # # This file is part of the ksh 93u+m package # # Copyright (c) 1984-2012 AT&T Intellectual Property # # Copyright (c) 2020-2024 Contributors to ksh 93u+m # # and is licensed under the # # Eclipse Public License, Version 2.0 # # # # A copy of the License is available at # # https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html # # (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) # # # # Glenn Fowler # # Martijn Dekker # # # ######################################################################## # Generator for *.req library dependency files. # This script is designed to be called from Mamfiles only. # It is a heavily refactored version of the code generated # by the nmake LIBS_req rule, and replaces the latter. # Set options. case ${ZSH_VERSION+z} in z) emulate ksh ;; *) (command set -o posix) 2>/dev/null && set -o posix ;; esac set -o noglob -o nounset : $INSTALLROOT # error out early # Get colon-separated compiler and linker invocations from arguments. # Like this whole build system, we assume arguments do not contain # spaces, or if they do, that they are meant to be field-split. allcc= while test "$#" -gt 0 && test "$1" != ":" do allcc=$allcc${allcc:+ }$1 shift done test "${1-}" = ":" || { echo "$0: bad arguments" >&2; exit 1; } shift ldflags= while test "$#" -gt 0 && test "$1" != ":" do ldflags=$ldflags${ldflags:+ }$1 shift done test "${1-}" = ":" || { echo "$0: bad arguments" >&2; exit 1; } shift # Setup. trap 'set +o noglob; rm -rf mkreq.$$.*' 0 echo 'int main(void) { return 0; }' > mkreq.$$.c # Clever hack alert: obtain error message for library not found by trying to # link to a library called '*'; the * is presumed repeated in the error message # and thus serves as a wildcard for 'case' in try_to_link. This is evidently # a workaround for compilers that exit with status 0 (success) on error. # TODO: in 2023, is that still a thing at all? $allcc -c mkreq.$$.c || exit error_msg=$($allcc $ldflags -o mkreq.$$.x mkreq.$$.o -l'*' 2>&1 | sed -e 's/[][()+@?]/#/g') # Function: try to link the test program with possible extra linker flags. try_to_link() { _lib=$1 shift _out=$( { $allcc ${1+"$@"} $ldflags -o mkreq.$$.x mkreq.$$.o -l${_lib} 2>&1 || echo '' "$error_msg" } | sed -e 's/[][()+@?]/#/g') case ${_out} in *$error_msg*) return 1 ;; esac # To work around possible linker breakage, we have to # actually run the test program, not merely link it. ./mkreq.$$.x e=$? if test "$e" -gt 0 then if test "$e" -gt 128 && test "$(kill -l $e)" = "ABRT" && test "$(uname -s)" = "Darwin" then echo "$0: THE ABOVE CRASH IS APPLE'S BUG, NOT OURS." >&2 echo "$0: We have successfully worked around the bug." >&2 echo "$0: https://github.com/ksh93/ksh/issues/596" >&2 fi return 1 fi return 0 } ######### Main ########## # Generate .req file. # ######################### self=$1 shift exec >$self.req echo " -l$self" for name do if test -f $INSTALLROOT/lib/lib/$name then grep '^ -l.' $INSTALLROOT/lib/lib/$name continue elif test ! -f $INSTALLROOT/lib/lib$name.a then try_to_link $name -L$INSTALLROOT/lib || try_to_link $name || continue fi echo " -l$name" done | sort -u ksh-1.0.10/src/cmd/INIT/mktest.sh000077500000000000000000000363671465301102200163320ustar00rootroot00000000000000######################################################################## # # # This software is part of the ast package # # Copyright (c) 1994-2011 AT&T Intellectual Property # # Copyright (c) 2020-2024 Contributors to ksh 93u+m # # and is licensed under the # # Eclipse Public License, Version 2.0 # # # # A copy of the License is available at # # https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html # # (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) # # # # Glenn Fowler # # Martijn Dekker # # Johnothan King # # # ######################################################################## : mktest - generate regress or shell regression test scripts command=mktest stdin=8 stdout=9 PREFIX=test STYLE=regress WIDTH=80 eval "exec $stdout>&1" case $(getopts '[-][123:xyz]' opt --xyz 2>/dev/null; echo 0$opt) in 0123) ARGV0="-a $command" USAGE=$' [-? @(#)$Id: mktest (AT&T Labs Research) 2010-08-11 $ ] [-author?Glenn Fowler ] [-copyright?Copyright (c) 2005-2012 AT&T Intellectual Property] [-license?https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html] [+NAME?mktest - generate regression test scripts] [+DESCRIPTION?\bmktest\b generates regression test scripts from test template commands in the \aunit\a.\brt\b file. The generated test script writes temporary output to '$PREFIX$'\aunit\a.tmp and compares it to the expected output in '$PREFIX$'\aunit\a.out. Run the test script with the \b--accept\b option to (re)generate '$PREFIX$'\aunit\a.out.] [s:style?The script style:]:[style:='$STYLE$'] { [+regress?\bregress\b(1) command input.] [+shell?Standalone test shell script.] } [w:width?Set the output format width to approximately \awidth\a.]:[width:='$WIDTH$'] unit.rt [ unit [ arg ... ] ] [+INPUT FILES?The regression test command file \aunit\a\b.rt\b is a \bksh\b(1) script that makes calls to the following functions:] { [+DATA \afile\a [ - | [ options ]] data]]?Create input data \afile\a that is empty (-) or contains \adata\a subject to \bprint\b(1) \aoptions\a or that is a copy of the DATA command standard input. Set \afile\a to \b-\b to name the standard input.] [+DIAGNOSTICS?Diagnostic messages of unspecified format are expected.] [+DO \acommand\a [ \aarg\a ... ]]?Execute \acommand\a if the current test is active.] [+EXEC [ \aarg\a ... ]]?Run the command under test with optional arguments. If the standard input is not specified then the standard input of the previous EXEC is used. The standard input of the first EXEC in a TEST group is an empty regular file.] [+EXPORT \aname\a=\avalue\a ...?Export list for subsequent commands in the TEST group or for all TEST groups if before the first TEST group.] [+IGNORESPACE [ 0 | 1 ] ?Ignore space differences when comparing expected output.] [+KEEP \apattern\a ...?File match patterns of files to retain between TEST groups.] [+NOTE \acomment\a?\acomment\a is added to the current test script.] [+PROG \acommand\a [ \aarg\a ... ]]?Run \acommand\a with optional arguments.] [+TEST [ \anumber\a ]] [ \adescription\a ... ]]?Define a new test group with optional \anumber\a and \adescription\a.] [+TWD [ \adir\a ... ]]?Set the temporary test dir to \adir\a. The default is \aunit\a\b.tmp\b, where \aunit\a is the test input file sans directory and suffix. If \adir\a matches \b/*\b then it is the directory name; if \adir\a is non-null then the prefix \b${TMPDIR:-/tmp}\b is added; otherwise if \adir\a is omitted then \b${TMPDIR:-/tmp}/tst-\b\aunit\a-$$-$RANDOM.\b\aunit\a is used.] [+UMASK [ \amask\a ]]?Run subsequent tests with \bumask\b(1) \amask\a. If \amask\a is omitted then the original \bumask\b is used.] [+UNIT \acommand\a [ \aarg\a ... ]]?Define the command and optional default arguments to be tested. \bUNIT\b explicitly overrides the default command name derived from the test script file name.] [+WIDTH \awidth\a?Set the output format width to approximately \awidth\a.] } [+SEE ALSO?\bregress\b(1), \bksh\b(1)] ' ;; *) ARGV0="" USAGE='s: unit.rt [ arg ... ]' ;; esac typeset ARG SCRIPT UNIT TEMP=${TMPDIR:-/tmp}/$command.$$.tmp WORK typeset IO INPUT INPUT_N OUTPUT OUTPUT_N ERROR ERROR_N KEEP typeset -C STATE typeset -A DATA STATE.RESET REMOVE FORMAT integer KEEP_UNIT=0 SCRIPT_UNIT=0 TEST=0 CODE=0 EXIT=0 ACCEPT=0 DIAGNOSTICS=0 code while getopts $ARGV0 "$USAGE" OPT do case $OPT in s) case $OPTARG in regress|shell) STYLE=$OPTARG ;; *) print -u2 -r -- $command: --style=$OPTARG: regress or shell expected exit 1 ;; esac ;; w) WIDTH=$OPTARG ;; *) OPTIND=0 getopts $ARGV0 "$USAGE" OPT '-?' exit 2 ;; esac done shift $OPTIND-1 typeset SINGLE= quote='%${SINGLE}..${WIDTH}q' if [[ $1 == - ]] then shift fi if (( ! $# )) then print -u2 -r -- $command: test command script path expected exit 1 fi SCRIPT=$1 shift if [[ ! -r $SCRIPT ]] then print -u2 -r -- $command: $SCRIPT: cannot read exit 1 fi (ulimit -c 0) >/dev/null 2>&1 && ulimit -c 0 if (( $# )) then set -A UNIT -- "$@" KEEP_UNIT=1 else ARG=${SCRIPT##*/} set -A UNIT -- "${ARG%.*}" fi WORK=${UNIT[0]}.tmp rm -rf $WORK mkdir $WORK || exit export PATH=$PWD:$PATH function LINE { if [[ $STYLE == regress ]] then print -u$stdout fi } function NOTE { case $STYLE in regress)LINE print -u$stdout -r -- '#' "$@" ;; shell) print -u$stdout -r -f ": $QUOTE"$'\n' -- "$*" ;; esac } function UNIT { (( KEEP_UNIT )) || set -A UNIT -- "$@" case $STYLE in regress)LINE print -u$stdout -r -f $'UNIT' for ARG in "$@" do print -u$stdout -r -f " $QUOTE" -- "$ARG" done print -u$stdout ;; shell) print -u$stdout -r -f $'set x' for ARG in "$@" do print -u$stdout -r -f " $QUOTE" -- "$ARG" done print -u$stdout print -u$stdout shift ;; esac } function TEST { typeset i typeset -A REM if (( ${#STATE.RESET[@]} )) then unset ${!STATE.RESET[@]} case $STYLE in shell) print -u$stdout -r -- unset ${!STATE.RESET[@]} ;; esac unset STATE.RESET typeset -A STATE.RESET fi if (( ${#REMOVE[@]} )) then rm -f -- "${!REMOVE[@]}" case $STYLE in shell) print -u$stdout -r -f $'rm -f' for i in ${!REMOVE[@]} do print -u$stdout -r -f " $QUOTE" "$i" done print -u$stdout ;; esac for i in ${!REMOVE[@]} do unset REMOVE[$i] done fi rm -rf $WORK/* if [[ $1 == +([0-9]) ]] then TEST=${1##0} shift else ((TEST++)) fi LINE case $STYLE in regress)print -u$stdout -r -f "TEST %02d $QUOTE"$'\n' -- $TEST "$*" ;; shell) print -u$stdout -r -f ": TEST %02d $QUOTE"$'\n' -- $TEST "$*" ;; esac : > $TEMP.INPUT > $TEMP.in INPUT= INPUT_N= OUTPUT= OUTPUT_N= ERROR= ERROR_N= UMASK=$UMASK_ORIG UMASK_DONE=$UMASK CODE=0 } function TWD { case $STYLE in regress)LINE print -u$stdout -r -f $'TWD' for ARG in "$@" do print -u$stdout -r -f " $QUOTE" -- "$ARG" done print -u$stdout ;; esac } function RUN { typeset i n p op unit sep output=1 error=1 exitcode=1 op=$1 shift while : do case $1 in ++NOOUTPUT) output= ;; ++NOERROR) error= ;; ++NOEXIT) exitcode= ;; ++*) print -u2 -r -- $command: $0: $1: unknown option; exit 1 ;; *) break ;; esac shift done if [[ $op == PROG ]] then unit=$1 shift elif (( ! ${#UNIT[@]} )) then print -u2 -r -- $command: $SCRIPT: UNIT statement or operand expected exit 1 fi LINE case $STYLE in regress)if [[ $op == PROG ]] then print -u$stdout -r -f $'\t'"$op"$'\t'"$unit" sep=$' ' else print -u$stdout -r -f $'\t'"$op" sep=$'\t' fi for ARG in "$@" do LC_CTYPE=C print -u$stdout -r -f "$sep$QUOTE" -- "$ARG" sep=$' ' done print -u$stdout [[ ${DATA[-]} || /dev/fd/0 -ef /dev/fd/$stdin ]] || cat > $TEMP.in IO=$(cat $TEMP.in; print :) if [[ $IO == ?*$'\n:' ]] then IO=${IO%??} n= else IO=${IO%?} n=-n fi { [[ $UMASK != $UMASK_ORIG ]] && umask $UMASK cd $WORK if [[ $op == PROG ]] then "$unit" "$@" code=$? else "${UNIT[@]}" "$@" code=$? fi cd .. [[ $UMASK != $UMASK_ORIG ]] && umask $UMASK_ORIG } < $TEMP.in > $TEMP.out 2> $TEMP.err if [[ $IO != "$INPUT" || $n != "$INPUT_N" ]] then INPUT=$IO INPUT_N=$n if [[ ${FORMAT[-]} ]] then print -u$stdout -n -r -- $'\t\tINPUT' print -u$stdout -r -f " $QUOTE" -- "${FORMAT[-]}" print -u$stdout -r -f " $QUOTE" -- - unset FORMAT[-] else print -u$stdout -n -r -- $'\t\tINPUT' $n - [[ $IO ]] && LC_CTYPE=C print -u$stdout -r -f " $QUOTE" -- "$IO" fi print -u$stdout unset DATA[-] fi for i in ${!DATA[@]} do if [[ ${FORMAT[$i]} ]] then print -u$stdout -n -r -- $'\t\tINPUT' print -u$stdout -r -f " $QUOTE" -- "${FORMAT[$i]}" print -u$stdout -r -f " $QUOTE" -- "$i" unset FORMAT[$i] else case $i in -) p=$TEMP.in ;; *) p=$WORK/$i ;; esac IO=$(cat $p; print :) if [[ $IO == ?*$'\n:' ]] then IO=${IO%??} n= else IO=${IO%?} n=-n fi print -u$stdout -n -r -- $'\t\tINPUT' $n print -u$stdout -r -f " $QUOTE" -- "$i" [[ $IO ]] && LC_CTYPE=C print -u$stdout -r -f " $QUOTE" -- "$IO" fi print -u$stdout unset DATA[$i] done IO=$(cat $TEMP.out; print :) if [[ $IO == ?*$'\n:' ]] then IO=${IO%??} n= else IO=${IO%?} n=-n fi if [[ $IO != "$OUTPUT" || $n != "$OUTPUT_N" ]] then OUTPUT=$IO OUTPUT_N=$n if [[ $output ]] then if [[ ! -s $TEMP.out ]] then print -u$stdout -n -r -- $'\t\tOUTPUT' - elif cmp -s $TEMP.in $TEMP.out then OUTPUT=not-$OUTPUT print -u$stdout -n -r -- $'\t\tSAME OUTPUT INPUT' else print -u$stdout -n -r -- $'\t\tOUTPUT' $n - [[ $IO ]] && LC_CTYPE=C print -u$stdout -r -f " $QUOTE" -- "$IO" fi print -u$stdout fi fi IO=$(cat $TEMP.err; print :) IO=${IO//$command\[*([0-9])\]:\ .\[*([0-9])\]:\ @(EXEC|PROG)\[*([0-9])\]:\ /} if [[ $IO == ?*$'\n:' ]] then IO=${IO%??} n= else IO=${IO%?} n=-n fi if [[ $IO != "$ERROR" || $n != "$ERROR_N" ]] then ERROR=$IO ERROR_N=$n if [[ $error ]] then print -u$stdout -n -r -- $'\t\tERROR' $n - [[ $IO ]] && LC_CTYPE=C print -u$stdout -r -f " $QUOTE" -- "$IO" print -u$stdout fi fi case $output:$error in :) OUTPUT= OUTPUT_N= ERROR= ERROR_N= print -u$stdout -r -- $'\t\tIGNORE OUTPUT ERROR' ;; :1) OUTPUT= OUTPUT_N= print -u$stdout -r -- $'\t\tIGNORE OUTPUT' ;; 1:) ERROR= ERROR_N= print -u$stdout -r -- $'\t\tIGNORE ERROR' ;; esac if [[ $UMASK_DONE != $UMASK ]] then UMASK_DONE=$UMASK print -u$stdout -r -f $'\t\tUMASK %s\n' $UMASK fi if (( code != CODE )) then (( CODE=code )) if [[ $exitcode ]] then print -u$stdout -r -f $'\t\tEXIT %d\n' $CODE fi fi ;; shell) [[ $UMASK != $UMASK_ORIG ]] && print -u$stdout -r -f "{ umask $UMASK; " if [[ $op == PROG ]] then print -u$stdout -r -f $'"'"$unit"$'"' else print -u$stdout -r -f $'"$@"' fi for ARG in "$@" do print -u$stdout -r -f " $QUOTE" -- "$ARG" done [[ $UMASK != $UMASK_ORIG ]] && print -u$stdout -r -f "umask $UMASK_ORIG; } " if [[ ! $output ]] then print -u$stdout -r -f " >/dev/null" fi if [[ ! $error ]] then if [[ ! $output ]] then print -u$stdout -r -f " 2>&1" else print -u$stdout -r -f " 2>/dev/null" fi fi IO=$(cat) if [[ $IO ]] then print -u$stdout -r -- "<<'!TEST-INPUT!'" print -u$stdout -r -- "$IO" print -u$stdout -r -- !TEST-INPUT! else print -u$stdout fi if [[ $exitcode ]] then print -u$stdout -r -- $'CODE=$?\ncase $CODE in\n0) ;;\n*) echo exit status $CODE ;;\nesac' fi ;; esac } function DO { LINE print -r $'\t'DO "$@" } function EXEC { RUN EXEC "$@" } function DATA { typeset f p o f=$1 shift case $f in -) p=$TEMP.in ;; *) p=$WORK/$f ;; esac case $1 in '') cat ;; -) ;; *) print -r "$@" ;; esac > $p DATA[$f]=1 if (( $# == 1 )) && [[ $1 == -?* ]] then FORMAT[$f]=$1 else FORMAT[$f]= fi if [[ $f != $KEEP ]] then REMOVE[$f]=1 fi if [[ $STYLE == shell ]] then { print -r -f "cat > $QUOTE <<'!TEST-INPUT!'"$'\n' -- "$f" cat "$p" print -r -- !TEST-INPUT! } >&$stdout fi } function KEEP { typeset p for p do if [[ $KEEP ]] then KEEP=$KEEP'|' fi KEEP=$KEEP$p done } function DIAGNOSTICS { LINE case $STYLE in regress) print -u$stdout -r $'DIAGNOSTICS' ;; shell) DIAGNOSTICS=1 ;; esac } function EXPORT { typeset x n v LINE case $STYLE in regress) print -u$stdout -r -f $'EXPORT' ;; shell) print -u$stdout -r -f $'export' ;; esac for x do n=${x%%=*} v=${x#*=} export "$x" print -u$stdout -r -f " %s=$QUOTE" "$n" "$v" (( TEST )) && STATE.RESET["$n"]=1 done print -u$stdout } function PROG { RUN PROG "$@" } function WIDTH { WIDTH=${1:-80} eval QUOTE='"'$quote'"' } function IGNORESPACE { IGNORESPACE=-b LINE print -u$stdout -r IGNORESPACE } function UMASK # [ mask ] { [[ $UMASK_ORIG ]] || UMASK_ORIG=$(umask) UMASK=$1 [[ $UMASK ]] || UMASK=$UMASK_ORIG } trap 'CODE=$?; rm -rf $TEMP.* $WORK; exit $CODE' 0 1 2 3 15 typeset IGNORESPACE UMASK UMASK_ORIG UMASK_DONE UMASK_ORIG=$(umask) IFS=$IFS$'\n' print -u$stdout -r "# : : generated from $SCRIPT by $command : : #" case $STYLE in shell) cat <&2 <&2 exit 1 ;; *) break ;; esac shift done export COLUMNS=80 { ! ;; esac export COLUMNS=80 case $STYLE in shell) SINGLE='#' eval QUOTE='"'$quote'"' . $SCRIPT < /dev/null | sed -e $'s,\\\\n,\n,g' -e $'s,\\\\t,\t,g' -e $'s,\\$\',\',g' ;; *) eval QUOTE='"'$quote'"' : > $TEMP.INPUT > $TEMP.in eval "exec $stdin<$TEMP.INPUT" . $SCRIPT <&$stdin ;; esac case $STYLE in shell) cat < $PREFIX${UNIT[0]}.tmp 2>&1 < /dev/null case \$ACCEPT in 0) if grep ' $' $PREFIX${UNIT[0]}.tmp >/dev/null then mv $PREFIX${UNIT[0]}.tmp $PREFIX${UNIT[0]}.junk sed 's/ $//' < $PREFIX${UNIT[0]}.junk > $PREFIX${UNIT[0]}.tmp rm -f $PREFIX${UNIT[0]}.junk fi if cmp -s $PREFIX${UNIT[0]}.tmp $PREFIX${UNIT[0]}.out then echo ${UNIT[0]} tests PASSED rm -f $PREFIX${UNIT[0]}.tmp else echo ${UNIT[0]} tests FAILED diff $IGNORESPACE $PREFIX${UNIT[0]}.tmp $PREFIX${UNIT[0]}.out fi ;; *) mv $PREFIX${UNIT[0]}.tmp $PREFIX${UNIT[0]}.out ;; esac ! ;; esac ksh-1.0.10/src/cmd/INIT/mprobe.sh000066400000000000000000000024111465301102200162630ustar00rootroot00000000000000######################################################################## # # # This software is part of the ast package # # Copyright (c) 1994-2011 AT&T Intellectual Property # # Copyright (c) 2020-2022 Contributors to ksh 93u+m # # and is licensed under the # # Eclipse Public License, Version 2.0 # # # # A copy of the License is available at # # https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html # # (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) # # # # Glenn Fowler # # Martijn Dekker # # # ######################################################################## : mam probe script opt= while : do case $1 in -d) opt=-d ;; -*) ;; *) break ;; esac shift done mamprobe $opt - "$1" ksh-1.0.10/src/cmd/INIT/nsl.c000066400000000000000000000024771465301102200154170ustar00rootroot00000000000000/*********************************************************************** * * * This software is part of the ast package * * Copyright (c) 1994-2011 AT&T Intellectual Property * * Copyright (c) 2020-2023 Contributors to ksh 93u+m * * and is licensed under the * * Eclipse Public License, Version 2.0 * * * * A copy of the License is available at * * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html * * (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) * * * * Glenn Fowler * * Martijn Dekker * * Johnothan King * * * ***********************************************************************/ /* * small test for -lnsl */ #include int main(void) { return gethostbyname(0) == 0; } ksh-1.0.10/src/cmd/INIT/p.c000066400000000000000000000023621465301102200150530ustar00rootroot00000000000000/*********************************************************************** * * * This software is part of the ast package * * Copyright (c) 1994-2011 AT&T Intellectual Property * * Copyright (c) 2020-2022 Contributors to ksh 93u+m * * and is licensed under the * * Eclipse Public License, Version 2.0 * * * * A copy of the License is available at * * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html * * (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) * * * * Glenn Fowler * * Martijn Dekker * * * ***********************************************************************/ /* * small test for prototyping cc */ int main(int argc, char** argv) { return argc || argv; } ksh-1.0.10/src/cmd/INIT/proto.sh000066400000000000000000000031711465301102200161460ustar00rootroot00000000000000######################################################################## # # # This file is part of the ksh 93u+m package # # Copyright (c) 2021-2024 Contributors to ksh 93u+m # # and is licensed under the # # Eclipse Public License, Version 2.0 # # # # A copy of the License is available at # # https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html # # (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) # # # # Martijn Dekker # # # ######################################################################## # proto(1) has been removed. This is a backward compatibility stub that allows # compiling older AST code (with Mamfiles containing proto commands) using the # current INIT system. This stub ignores all options, then invokes 'cat'. usage() { echo 'Usage: proto [-dfhinprstvzP+S] [-C directory] [-e package] [-l file]' echo ' [-o "name='\''value'\'' ..."] [-L file] file ...' exit 2 } >&2 while getopts ':dfhinprstvzPSC:e:l:o:L:' opt do case $opt in :) usage ;; \?) case $OPTARG in +) ;; *) echo "proto: $OPTARG: unknown option" >&2 usage ;; esac ;; esac done shift $((OPTIND - 1)) exec cat -- "$@" ksh-1.0.10/src/cmd/INIT/regress.sh000066400000000000000000001033061465301102200164560ustar00rootroot00000000000000######################################################################## # # # This software is part of the ast package # # Copyright (c) 1994-2012 AT&T Intellectual Property # # Copyright (c) 2020-2024 Contributors to ksh 93u+m # # and is licensed under the # # Eclipse Public License, Version 2.0 # # # # A copy of the License is available at # # https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html # # (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) # # # # Glenn Fowler # # Martijn Dekker # # Johnothan King # # # ######################################################################## : regress - run regression tests in command.tst command=regress case $(getopts '[-][123:xyz]' opt --xyz 2>/dev/null; echo 0$opt) in 0123) USAGE=$' [-? @(#)$Id: regress (ksh 93u+m) 2024-02-13 $ ] [-author?Glenn Fowler ] [-copyright?(c) 1995-2012 AT&T Intellectual Property] [-copyright?(c) 2020-2024 Contributors to ksh 93u+m] [-license?https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html] [+NAME?regress - run regression tests] [+DESCRIPTION?\bregress\b runs the tests in \aunit\a, or \aunit\a\b.tst\b if \aunit\a does not exist. If \acommand\a is omitted then it is assumed to be the base name of \aunit\a. All testing is done in the temporary directory \aunit\a\b.tmp\b.] [+?Default test output lists the \anumber\a and \adescription\a for each active \bTEST\b group and the \anumber\a:\aline\a for each individual \bEXEC\b test. Each test that fails results in a diagnostic that contains the word \bFAILED\b; no other diagnostics contain this word.] [b:ignore-space?Ignore space differences when comparing expected output.] [i:pipe-input?Repeat each test with the standard input redirected through a pipe.] [k:keep?Enable \bcore\b dumps, exit after the first test that fails, and do not remove the temporary directory \aunit\a\b.tmp\b.] [l:local-fs?Force \aunit\a\b.tmp\b to be in a local filesystem.] [o:pipe-output?Repeat each test with the standard output redirected through a pipe.] [p:pipe-io?Repeat each test with the standard input and standard output redirected through pipes.] [q:quiet?Output information on \bFAILED\b tests only.] [r!:regular?Run each test with the standard input and standard output redirected through regular files.] [t:test?Run only tests matching \apattern\a. Tests are numbered and consist of at least two digits (0 filled if necessary). Tests matching \b+(0)\b are always run.]:[pattern] [x:trace?Enable debug tracing.] [v:verbose?List differences between actual (<) and expected (>) output, errors and exit codes. Also disable long output line truncation.] unit [ command [ arg ... ] ] [+INPUT FILES?The regression test file \aunit\a\b.tst\b is a \bksh\b(1) script that is executed in an environment with the following functions defined:] { [+BODY \b{ ... }?Defines the test body; used for complex tests.] [+CD \b\adirectory\a?Create and change to working directory for one test.] [+CLEANUP?Called at exit time to remove the temporary directory \aunit\a\b.tmp\b, list the tests totals via \bTALLY\b, and exit with the number of test failures or 125, whichever is lower, as the exit status.] [+COMMAND \b\aarg\a ...?Runs the current command under test with \aarg\a ... appended to the default args.] [+CONTINUE?The background job must be running.] [+COPY \b\afrom to\a?Copy file \afrom\a to \ato\a. \afrom\a may be a regular file or \bINPUT\b, \bOUTPUT\b or \bERROR\b. Post test comparisons are still done for \afrom\a.] [+DIAGNOSTICS \b[ \b1\b | \b0\b | \apattern\a ]]?No argument or an argument of \b1\b declares that diagnostics are to expected for the remainder of the current \bTEST\b; \b0\b reverts to the default state that diagnostics are not expected; otherwise the argument is a \bksh\b(1) pattern that must match the non-empty contents of the standard error.] [+DO \b\astatement\a?Defines additional statements to be executed for the current test. \astatement\a may be a { ... } group.] [+EMPTY \bINPUT|OUTPUT|ERROR|SAME?The corresponding file is expected to be empty.] [+ERROR \b[ \b-e\b \afilter\a ]] [ \b-n\b ]] \afile\a | - \adata\a ...?The standard error is expected to match either the contents of \afile\a or the line \adata\a. \bERROR -n\b does not append a newline to \adata\a. \afilter\a is a shell command or pipeline that reads standard input and writes standard output that is applied to ERROR before comparison with the expected contents.] [+EXEC \b[ \aarg\a ... ]]?Runs the command under test with optional arguments. \bINPUT\b, \bOUTPUT\b, \bERROR\b, \bEXIT\b and \bSAME\b calls following this \bEXEC\b up until the next \bEXEC\b or the end of the script provide details for the expected results. If no arguments are specified then the arguments from the previous \bEXEC\b in the current \bTEST\b group are used, or no arguments if this is the first \bEXEC\b in the group.] [+EXIT \b\astatus\a?The command exit status is expected to match the pattern \astatus\a.] [+EXITED?The background job must have exited.] [+EXPORT \b[-]] \aname\a=\avalue\a ...?Export environment variables for one test.] [+FATAL \b\amessage\a ...?\amessage\a is printed on the standard error and \bregress\b exits with status \b1\b.] [+FIFO \bINPUT|OUTPUT|ERROR\b [ \b-n\b ]] \afile\a | - \adata\a ...?The \bIO\B file is a fifo.] [+IF \b\acommand\a [\anote\a]]?If the \bsh\b(1) \acommand\a exits 0 then tests until the next \bELIF\b, \bELSE\b or \bFI\b are enabled. Otherwise those tests are skipped. \bIF\b ... \bFI\b may be nested, but must not cross \bTEST\b boundaries. \anote\a is listed on the standard error if the corresponding test block is enabled; \bIF\b, \bELIF\b, \bELSE\b may nave a \anote\a operand.] [+IGNORE \b\afile\a ...?\afile\a is ignored for subsequent result comparisons. \afile\a may be \bOUTPUT\b or \bERROR\b.] [+IGNORESPACE?Ignore space differences when comparing expected output.] [+INCLUDE \b\afile\a ...?One or more \afile\a operands are read via the \bksh\b(1) \b.\b(1) command. \bVIEW\b is used to locate the files.] [+INFO \b\adescription\a?\adescription\a is printed on the standard error.] [+INITIALIZE?Called by \bregress\b to initialize each \bTEST\b group.] [+INPUT \b[ \b-e\b \afilter\a ]] [ \b-n\b ]] \afile\a | - \adata\a ...?The standard input is set to either the contents of \afile\a or the line \adata\a. \bINPUT -n\b does not append a newline to \adata\a. \afilter\a is a shell command or pipeline that reads standard input and writes standard output that is applied to OUTPUT before comparison with the expected contents.] [+INTRO?Called by \bregress\b to introduce all \bTEST\b groups.] [+IO \b[ \bFIFO\b | \bPIPE\b ]] \bINPUT|OUTPUT|ERROR\b [ \b-e\b \afilter\a ]] [ \b-n\b ]] \afile\a | - \adata\a ...?Internal support for the \bINPUT\b, \bOUTPUT\b and \bERROR\b functions.] [+JOB \b\aop\a [ ... ]]?Like \bEXEC\b except the command is run as a background job for the duration of the group or until it is killed via \bKILL\b.] [+KEEP \b\apattern\a ...?The temporary directory is cleared for each test. Files matching \apattern\a are retained between tests.] [+KILL \b[ \asignal\a ]]?Kill the background job with \asignal\a [ \bSIGKILL\b ]].] [+MOVE \b\afrom to\a?Rename file \afrom\a to \ato\a. \afrom\a may be a regular file or \bINPUT\b, \bOUTPUT\b or \bERROR\b. Post test comparisons are ignored for \afrom\a.] [+NOTE \b\acomment\a?\acomment\a is added to the current test trace output.] [+OUTPUT \b[ \b-e\b \afilter\a ]] [ \b-n\b ]] \afile\a | - \adata\a ...?The standard output is expected to match either the contents of \afile\a or the line \adata\a. \bOUTPUT -n\b does not append a newline to \adata\a. \afilter\a is a shell command or pipeline that reads standard input and writes standard output that is applied to ERROR before comparison with the expected contents.] [+PIPE \bINPUT|OUTPUT|ERROR\b [ \b-n\b ]] \afile\a | - \adata\a ...?The \bIO\B file is a pipe.] [+PROG \b\acommand\a [ \aarg\a ... ]]?\acommand\a is run with optional arguments.] [+REMOVE \b\afile\a ...?\afile\a ... are removed after the current test is done.] [+RUN?Called by \bregress\b to run the current test.] [+SAME \b\anew old\a?\anew\a is expected to be the same as \aold\a after the current test completes.] [+SET \b[\bno\b]]\aname\a[=\avalue\a]]?Set the command line option --\aname\a. The setting is in effect for all tests until the next explicit \bSET\b.] [+TALLY?Called by \bregress\b display the \bTEST\b results.] [+TEST \b\anumber\a [ \adescription\a ... ]]?Define a new test group labelled \anumber\a with optional \adescription\a.] [+TITLE \b[+]] \atext\a?Set the \bTEST\b output title to \atext\a. If \b+\b is specified then \atext\a is appended to the default title. The default title is the test file base name, and, if different from the test file base name, the test unit base name.] [+TWD \b[ \adir\a ... ]]?Set the temporary test dir to \adir\a. The default is \aunit\a\b.tmp\b, where \aunit\a is the test input file sans directory and suffix. If \adir\a matches \b/*\b then it is the directory name; if \adir\a is non-null then the prefix \b${TMPDIR:-/tmp}\b is added; otherwise if \adir\a is omitted then \b${TMPDIR:-/tmp}/tst-\b\aunit\a-$$-$RANDOM.\b\aunit\a is used.] [+UMASK \b[ \amask\a ]]?Run subsequent tests with \bumask\b(1) \amask\a. If \amask\a is omitted then the original \bumask\b is used.] [+UNIT \b\acommand\a [ \aarg\a ... ]]?Define the command and optional default arguments to be tested. \bUNIT\b explicitly overrides the default command name derived from the test script file name. A \acommand\a operand with optional arguments overrides the \bUNIT\b \acommand\a and arguments, with the exception that if the \bUNIT\b \acommand\a is \b-\b or \b+\b the \bUNIT\b arguments are appended to the operand or default unit command and arguments.] [+VIEW \b\avar\a [ \afile\a ]]?\avar\a is set to the full pathname of \avar\a [ \afile\a ]] in the current \b$VPATH\b view if defined.] } [+SEE ALSO?\bnmake\b(1), \bksh\b(1)] ' ;; *) USAGE='ko:[[no]name[=value]]t:[test]v unit [path [arg ...]]' ;; esac function FATAL # message { print -r -u2 "$command: $*" GROUP=FINI exit 1 } function EMPTY { typeset i typeset -n ARRAY=$1 for i in ${!ARRAY[@]} do unset ARRAY[$i] done } function INITIALIZE # void { typeset i j cd "$TWD" case $KEEP in "") RM * ;; *) for i in * do case $i in !($KEEP)) j="$j $i" ;; esac done case $j in ?*) RM $j ;; esac ;; esac : >INPUT >OUTPUT.ex >ERROR.ex BODY="" COPY="" DIAGNOSTICS="" DONE="" ERROR="" EXIT=0 IGNORE="" INIT="" INPUT="" MOVE="" OUTPUT="" EMPTY FILE EMPTY FILTER EMPTY SAME EMPTY TYPE } function INTRO { typeset base command if [[ ! $TEST_quiet ]] then base=${REGRESS##*/} base=${base%.tst} command=${COMMAND##*/} command=${command%' '*} set -- $TITLE TITLE= case $1 in ''|+) if [[ $command == $base ]] then TITLE=$COMMAND else TITLE="$COMMAND, $base" fi if (( $# )) then shift fi ;; esac while (( $# )) do if [[ $TITLE ]] then TITLE="$TITLE, $1" else TITLE="$1" fi shift done print -u2 "TEST $TITLE" fi } function TALLY # extra message text { typeset msg case $GROUP in INIT) ;; *) msg="TEST $TITLE, $TESTS test" case $TESTS in 1) ;; *) msg=${msg}s ;; esac msg="$msg, $ERRORS error" case $ERRORS in 1) ;; *) msg=${msg}s ;; esac if (( $# )) then msg="$msg, $*" fi print -u2 "$msg" GROUP=INIT TESTS=0 ;; esac } function TITLE # text { TITLE=$@ } function UNWIND { while (( COND > 1 )) do print -r -u2 "$command: line $LINE: no matching FI for IF on line ${COND_LINE[COND]}" (( COND-- )) done if (( COND > 0 )) then (( COND = 0 )) FATAL "line $LINE: no matching FI for IF on line ${COND_LINE[COND+1]}" fi if [[ $JOBPID ]] then if [[ $JOBPID != 0 ]] then kill -KILL $JOBPID 2>/dev/null wait fi JOBPID= fi JOBSTATUS= JOBOP= wait } function CLEANUP # status { typeset note if [[ $GROUP != INIT ]] then if [[ ! $TEST_keep ]] then cd $SOURCE if [[ $TEST_local ]] then RM ${TEST_local} fi RM "$TWD" fi if (( $1 )) && [[ $GROUP != FINI ]] then note=terminated fi fi TALLY $note [[ $TEST_keep ]] || UNWIND exit $((ERRORS < 125 ? ERRORS : 125)) } function RUN # [ op ] { typeset i r=1 [[ $UMASK != $UMASK_ORIG ]] && umask $UMASK_ORIG #print -u2 AHA#$LINENO $0 GROUP=$GROUP ITEM=$ITEM FLUSHED=$FLUSHED JOBOP=$JOBOP case $GROUP in INIT) RM "$TWD" if [[ $TEST_local ]] then TEST_local=${TMPDIR:-/tmp}/rt-$$/${TWD##*/} mkdir -p "$TEST_local" && ln -s "$TEST_local" "$TWD" || FATAL "$TWD": cannot create directory TEST_local=${TEST_local%/*} else mkdir "$TWD" || FATAL "$TWD": cannot create directory fi cd "$TWD" TWD=$PWD : > rmu if rm -u rmu >/dev/null 2>&1 then TEST_rmu=-u else rm rmu fi if [[ $UNIT ]] then set -- "${ARGV[@]}" case $1 in ""|[-+]*) UNIT $UNIT "${ARGV[@]}" ;; *) UNIT "${ARGV[@]}" ;; esac fi INTRO ;; FINI) ;; $TEST_select) if [[ $ITEM == $FLUSHED ]] then return 0 fi FLUSHED=$ITEM if (( COND_SKIP[COND] )) then return 1 fi ((COUNT++)) if (( $ITEM <= $LASTITEM )) then LABEL=$TEST#$COUNT else LASTITEM=$ITEM LABEL=$TEST:$ITEM fi TEST_file="" exec >/dev/null for i in $INPUT do case " $OUTPUT " in *" $i "*) if [[ -f $i.sav ]] then cp $i.sav $i COMPARE="$COMPARE $i" elif [[ -f $i ]] then cp $i $i.sav COMPARE="$COMPARE $i" fi ;; esac done for i in $OUTPUT do case " $COMPARE " in *" $i "*) ;; *) COMPARE="$COMPARE $i" ;; esac done for i in $INIT do $i $TEST INIT done #print -u2 AHA#$LINENO $0 GROUP=$GROUP ITEM=$ITEM JOBOP=$JOBOP JOBPID=$JOBPID JOBSTATUS=$JOBSTATUS if [[ $JOBPID != 0 && ( $JOBPID || $JOBSTATUS ) ]] then if [[ ! $TEST_quiet ]] then print -nu2 "$LABEL" fi RESULTS elif [[ $BODY ]] then SHOW=$NOTE if [[ ! $TEST_quiet ]] then print -r -u2 " $SHOW" fi for i in $BODY do $i $TEST BODY done else SHOW= if [[ ${TYPE[INPUT]} == PIPE ]] then if [[ ${TYPE[OUTPUT]} == PIPE ]] then if [[ ! $TEST_quiet ]] then print -nu2 "$LABEL" fi cat <$TWD/INPUT | COMMAND "${ARGS[@]}" | cat >$TWD/OUTPUT RESULTS 'pipe input' else if [[ ! $TEST_quiet ]] then print -nu2 "$LABEL" fi cat <$TWD/INPUT | COMMAND "${ARGS[@]}" >$TWD/OUTPUT RESULTS 'pipe io' fi elif [[ ${TYPE[OUTPUT]} == PIPE ]] then if [[ ! $TEST_quiet ]] then print -nu2 "$LABEL" fi COMMAND "${ARGS[@]}" <$TWD/INPUT | cat >$TWD/OUTPUT RESULTS 'pipe output' else if [[ $TEST_regular ]] then if [[ ! $TEST_quiet ]] then print -nu2 "$LABEL" fi if [[ ${TYPE[INPUT]} == FIFO ]] then COMMAND "${ARGS[@]}" >$TWD/OUTPUT else COMMAND "${ARGS[@]}" <$TWD/INPUT >$TWD/OUTPUT fi RESULTS fi if [[ $TEST_pipe_input ]] then if [[ ! $TEST_quiet ]] then print -nu2 "$LABEL" fi (trap '' PIPE; cat <$TWD/INPUT 2>/dev/null; exit 0) | COMMAND "${ARGS[@]}" >$TWD/OUTPUT STATUS=$? RESULTS 'pipe input' fi if [[ $TEST_pipe_output ]] then if [[ ! $TEST_quiet ]] then print -nu2 "$LABEL" fi COMMAND "${ARGS[@]}" <$TWD/INPUT | cat >$TWD/OUTPUT STATUS=$? RESULTS 'pipe output' fi if [[ $TEST_pipe_io ]] then if [[ ! $TEST_quiet ]] then print -nu2 "$LABEL" fi (trap '' PIPE; cat <$TWD/INPUT 2>/dev/null; exit 0) | COMMAND "${ARGS[@]}" | cat >$TWD/OUTPUT STATUS=$? RESULTS 'pipe io' fi fi set -- $COPY COPY="" while : do case $# in 0|1) break ;; *) cp $1 $2 ;; esac shift 2 done set -- $MOVE MOVE="" while (( $# > 1 )) do mv $1 $2 shift 2 done fi for i in $DONE do $i $TEST DONE $STATUS done COMPARE="" r=0 ;; esac if [[ $COMMAND_ORIG ]] then COMMAND=$COMMAND_ORIG COMMAND_ORIG= ARGS=(${ARGS_ORIG[@]}) fi return $r } function DO # cmd ... { [[ $GROUP == $TEST_select ]] || return 1 (( COND_SKIP[COND] )) && return 1 [[ $UMASK != $UMASK_ORIG ]] && umask $UMASK return 0 } function UNIT # cmd arg ... { typeset cmd=$1 case $cmd in [-+]) shift if (( UNIT_READONLY )) then COMMAND="$COMMAND $*" else #BUG# ARGV=("${ARGV[@]}" "$@") set -- "${ARGV[@]}" "$@" ARGV=("$@") fi return ;; esac (( UNIT_READONLY )) && return if [[ $UNIT ]] && (( $# <= 1 )) then set -- "${ARGV[@]}" case $1 in "") set -- "$cmd" ;; [-+]*) set -- "$cmd" "${ARGV[@]}" ;; *) cmd=$1 ;; esac fi UNIT= COMMAND=$cmd shift typeset cmd=$(whence $COMMAND) if [[ ! $cmd ]] then FATAL $COMMAND: not found elif [[ ! $cmd ]] then FATAL $cmd: not found fi case $# in 0) ;; *) COMMAND="$COMMAND $*" ;; esac } function TWD # [ dir ] { case $1 in '') TWD=${TWD##*/}; TWD=${TMPDIR:-/tmp}/tst-${TWD%.*}-$$-$RANDOM ;; /*) TWD=$1 ;; *) TWD=${TMPDIR:-/tmp}/$1 ;; esac } function TEST # number description arg ... { RUN LINE=$TESTLINE UNWIND COUNT=0 LASTITEM=0 case $1 in -) ((LAST++)); TEST=$LAST ;; +([0123456789])) LAST=$1 TEST=$1 ;; *) LAST=0${1/[!0123456789]/} TEST=$1 ;; esac NOTE= if [[ ! $TEST_quiet && $TEST == $TEST_select ]] && (( ! COND_SKIP[COND] )) then print -r -u2 "$TEST $2" fi unset ARGS unset EXPORT EXPORTS=0 TEST_file="" if [[ $TEST != ${GROUP}* ]] then GROUP=${TEST%%+([abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ])} if [[ $GROUP == $TEST_select ]] && (( ! COND_SKIP[COND] )) then INITIALIZE fi fi ((SUBTESTS=0)) [[ $TEST == $TEST_select ]] && (( ! COND_SKIP[COND] )) } function EXEC # arg ... { if [[ $GROUP != $TEST_select ]] || (( COND_SKIP[COND] )) then return fi if ((SUBTESTS++)) then RUN fi case $# in 0) set -- "${ARGS[@]}" ;; esac ITEM=$LINE NOTE="$(print -r -f '%q ' -- $COMMAND_ORIG "$@")${JOBPID:+&}" ARGS=("$@") } function JOB # arg ... { JOBPID=0 EXEC "$@" } function CONTINUE { RUN || return JOBOP=CONTINUE ITEM=$LINE NOTE="$(print -r -f '%q ' -- $JOBOP)" #print -u2 AHA#$LINENO JOBOP=$JOBOP ITEM=$ITEM NOTE=$NOTE } function EXITED { RUN || return JOBOP=EXITED ITEM=$LINE NOTE="$(print -r -f '%q ' -- $JOBOP)" #print -u2 AHA#$LINENO JOBOP=$JOBOP ITEM=$ITEM NOTE=$NOTE } function KILL # [ signal ] { RUN || return JOBOP=$2 [[ $JOBOP ]] || JOBOP=KILL ITEM=$LINE NOTE="$(print -r -f '%q ' -- $JOBOP)" } function CD { RUN if [[ $GROUP == $TEST_select ]] && (( ! COND_SKIP[COND] )) then mkdir -p "$@" && cd "$@" || FATAL cannot initialize working directory "$@" fi } function EXPORT { typeset x n v if [[ $GROUP == INIT ]] then for x do n=${x%%=*} v=${x#*=} ENVIRON[ENVIRONS++]=$n="'$v'" done else RUN if [[ $GROUP != $TEST_select ]] || (( COND_SKIP[COND] )) then return fi for x do n=${x%%=*} v=${x#*=} EXPORT[EXPORTS++]=$n="'$v'" done fi } function FLUSH { if [[ $GROUP != $TEST_select ]] || (( COND_SKIP[COND] )) then return fi if ((SUBTESTS++)) then RUN fi } function PROG # cmd arg ... { typeset command args if [[ $GROUP != $TEST_select ]] || (( COND_SKIP[COND] )) then return fi ITEM=$LINE NOTE="$(print -r -f '%q ' -- "$@")" COMMAND_ORIG=$COMMAND COMMAND=$1 shift ARGS_ORIG=(${ARGS[@]}) ARGS=("$@") } function NOTE # description { NOTE=$* } function IO # [ PIPE ] INPUT|OUTPUT|ERROR [-f*|-n] file|- data ... { typeset op i v f file type x if [[ $GROUP != $TEST_select ]] || (( COND_SKIP[COND] )) then return fi [[ $UMASK != $UMASK_ORIG ]] && umask $UMASK_ORIG while : do case $1 in FIFO|PIPE) type=$1; shift ;; *) break ;; esac done op=$1 shift [[ $type ]] && TYPE[$op]=$type FILTER[$op]= file=$TWD/$op while : do case $1 in -x) x=1 shift ;; -e) (( $# > 1 )) && shift FILTER[$op]=$1 shift ;; -e*) FILTER[$op]=${1#-e} shift ;; -f*|-n) f=$1 shift ;; *) break ;; esac done case $# in 0) ;; *) case $1 in -) ;; *) file=$1 eval i='$'$op case " $i " in *" $file "*) ;; *) eval $op='"$'$op' $file"' ;; esac ;; esac shift ;; esac case " $IGNORE " in *" $file "*) for i in $IGNORE do case $i in $file) ;; *) v="$v $i" ;; esac done IGNORE=$v ;; esac FILE[$op]=$file case $op in OUTPUT|ERROR) file=$file.ex if [[ $file != /* ]] then file=$TWD/$file fi ;; esac #unset SAME[$op] SAME[$op]= if [[ $file == /* ]] then RM $file.sav else RM $TWD/$file.sav fi if [[ $file == */* ]] then mkdir -p ${file%/*} fi if [[ $file != */ ]] then if [[ $type == FIFO ]] then rm -f $file mkfifo $file fi if [[ ${TYPE[$op]} != FIFO ]] then if [[ $JOBOP ]] then case $#:$f in 0:) ;; *:-f) printf -- "$@" ;; *:-f*) printf -- "${f#-f}""$@" ;; *) print $f -r -- "$@" ;; esac >> $file else case $#:$f in 0:) ;; *:-f) printf -- "$@" ;; *:-f*) printf -- "${f#-f}""$@" ;; *) print $f -r -- "$@" ;; esac > $file fi elif [[ $#:$f != 0: ]] then case $#:$f in *:-f) printf -- "$@" ;; *:-f*) printf -- "${f#-f}""$@" ;; *) print $f -r -- "$@" ;; esac >> $file & fi if [[ $x ]] then chmod +x $file fi fi } function INPUT # file|- data ... { IO $0 "$@" } function COPY # from to { if [[ $GROUP != $TEST_select ]] || (( COND_SKIP[COND] )) then return fi COPY="$COPY $@" } function MOVE # from to { typeset f if [[ $GROUP != $TEST_select ]] || (( COND_SKIP[COND] )) then return fi for f do case $f in INPUT|OUTPUT|ERROR) f=$TWD/$f ;; /*) ;; *) f=$PWD/$f ;; esac MOVE="$MOVE $f" done } function SAME # new old { typeset i file v if [[ $GROUP != $TEST_select ]] || (( COND_SKIP[COND] )) then return fi case $# in 2) case $1 in INPUT) cat $2 > $1; return ;; esac SAME[$1]=$2 file=$1 COMPARE="$COMPARE $1" ;; 3) SAME[$2]=$3 file=$2 eval i='$'$1 case " $i " in *" $2 "*) ;; *) eval $1='"$'$1' $2"' ;; esac COMPARE="$COMPARE $2" ;; esac case " $IGNORE " in *" $file "*) for i in $IGNORE do case $i in $file) ;; *) v="$v $i" ;; esac done IGNORE=$v ;; esac } function OUTPUT # file|- data ... { IO $0 "$@" } function ERROR # file|- data ... { IO $0 "$@" } function RM # rm(1) args { if [[ ! $TEST_rmu ]] then chmod -R u+rwx "$@" >/dev/null 2>&1 fi rm $TEST_rmu $TEST_rmflags "$@" } function REMOVE # file ... { typeset i for i do RM $i $i.sav done } function IGNORE # file ... { typeset i for i do case $i in INPUT|OUTPUT|ERROR) i=$TWD/$i ;; esac case " $IGNORE " in *" $i "*) ;; *) IGNORE="$IGNORE $i" ;; esac done } function KEEP # pattern ... { typeset i for i do case $KEEP in "") KEEP="$i" ;; *) KEEP="$KEEP|$i" ;; esac done } function DIAGNOSTICS # [ 1 | 0 ] { case $#:$1 in 0:|1:1) DIAGNOSTICS=1 EXIT='*' ;; 1:|1:0) DIAGNOSTICS="" EXIT=0 ;; *) DIAGNOSTICS=$1 EXIT='*' ;; esac } function IGNORESPACE { : ${IGNORESPACE=-b} } function EXIT # status { EXIT=$1 } function INFO # info description { typeset -R15 info=$1 if [[ ! $1 ]] then info=no fi shift if [[ ! $TEST_quiet ]] then print -r -u2 "$info " "$@" fi } function COMMAND # arg ... { typeset input ((TESTS++)) case " ${ENVIRON[*]} ${EXPORT[*]}" in *' 'LC_ALL=*) ;; *' 'LC_+([A-Z])=*) EXPORT[EXPORTS++]="LC_ALL=" ;; esac if [[ $TEST_keep ]] then ( PS4='' set -x print -r -- "${ENVIRON[@]}" "${EXPORT[@]}" "PATH=$PATH" $COMMAND "$@" ) 2>&1 >/dev/null | sed -e 's,^print -r -- ,,' -e 's,$, "$@",' >$TWD/COMMAND chmod +x $TWD/COMMAND fi if [[ $UMASK != $UMASK_ORIG ]] then : >$TWD/ERROR umask $UMASK fi if [[ ${TYPE[INPUT]} == FIFO && ${FILE[INPUT]} == */INPUT ]] then input="< ${FILE[INPUT]}" fi if [[ $TEST_trace ]] then set +x eval print -u2 "$PS4" "${ENVIRON[@]}" "${EXPORT[@]}" PATH='$PATH' '$'COMMAND '"$@"' '$input' '"2>$TWD/ERROR"' '"${JOBPID:+&}"' fi eval "${ENVIRON[@]}" "${EXPORT[@]}" PATH='$PATH' '$'COMMAND '"$@"' $input "2>$TWD/ERROR" "${JOBPID:+&}" STATUS=$? [[ $TEST_trace ]] && set -x if [[ $JOBPID ]] then JOBPID=$! fi [[ $UMASK != $UMASK_ORIG ]] && umask $UMASK_ORIG return $STATUS } function RESULTS # pipe* { typeset i j k s failed ignore io op if [[ $1 ]] then io="$1 " fi [[ $JOBOP || $JOBPID || $JOBSTATUS ]] && sleep 1 for i in $COMPARE $TWD/OUTPUT $TWD/ERROR do case " $IGNORE $ignore $MOVE " in *" $i "*) continue ;; esac ignore="$ignore $i" op=${i##*/} if [[ ${FILTER[$op]} ]] then eval "{ ${FILTER[$op]} ;} < $i > $i.fi" mv $i.fi $i fi j=${SAME[$op]} if [[ ! $j ]] then if [[ $i == /* ]] then k=$i else k=$TWD/$i fi for s in ex sav err do [[ -f $k.$s ]] && break done j=$k.$s fi if [[ "$DIAGNOSTICS" && $i == */ERROR ]] then if [[ $STATUS == 0 && ! -s $TWD/ERROR || $DIAGNOSTICS != 1 && $(<$i) != $DIAGNOSTICS ]] then failed=$failed${failed:+,}DIAGNOSTICS if [[ $TEST_verbose && $DIAGNOSTICS != 1 ]] then print -u2 " ===" "diagnostic pattern '$DIAGNOSTICS' did not match" ${i#$TWD/} "===" cat $i >&2 fi fi continue fi diff -u $IGNORESPACE $i $j >$i.diff 2>&1 if [[ -s $i.diff ]] then failed=$failed${failed:+,}${i#$TWD/} if [[ $TEST_verbose ]] then print -u2 " ===" diff $IGNORESPACE ${i#$TWD/} "('-': actual; '+': expected) ===" cat $i.diff >&2 fi fi done if [[ $JOBOP ]] then if [[ $JOBPID ]] && ! kill -0 $JOBPID 2>/dev/null then wait $JOBPID JOBSTATUS=$? JOBPID= fi #print -u2 AHA#$LINENO JOBOP=$JOBOP JOBPID=$JOBPID JOBSTATUS=$JOBSTATUS case $JOBOP in CONTINUE) if [[ ! $JOBPID ]] then failed=$failed${failed:+,}EXITED fi ;; EXITED) if [[ $JOBPID ]] then failed=$failed${failed:+,}RUNNING fi ;; *) if [[ ! $JOBPID ]] then failed=$failed${failed:+,}EXITED fi if ! kill -$JOBOP $JOBPID 2>/dev/null then failed=$failed${failed:+,}KILL-$JOBOP fi ;; esac JOBOP= fi if [[ ! $failed && $STATUS != $EXIT ]] then failed="exit code $EXIT expected -- got $STATUS" fi if [[ $failed ]] then ((ERRORS++)) if [[ ! $TEST_quiet ]] then SHOW="FAILED ${io}[ $failed ] $NOTE" print -r -u2 " $SHOW" fi if [[ $TEST_keep ]] then GROUP=FINI exit fi elif [[ ! $TEST_quiet ]] then SHOW=$NOTE print -r -u2 " $SHOW" fi } function SET # [no]name[=value] { typeset i r if [[ $TEST ]] then RUN fi for i do if [[ $i == - ]] then r=1 elif [[ $i == + ]] then r= else if [[ $i == no?* ]] then i=${i#no} v= elif [[ $i == *=* ]] then v=${i#*=} if [[ $v == 0 ]] then v= fi i=${i%%=*} else v=1 fi i=${i//-/_} if [[ $r ]] then READONLY[$i]=1 elif [[ ${READONLY[$i]} ]] then continue fi eval TEST_$i=$v fi done } function VIEW # var [ file ] { nameref var=$1 typeset i bwd file pwd view root offset if [[ $var ]] then return 0 fi case $# in 1) file=$1 ;; *) file=$2 ;; esac pwd=${TWD%/*} bwd=${PMP%/*} if [[ -r $file ]] then if [[ ! -d $file ]] then var=$PWD/$file return 0 fi for i in $file/* do if [[ -r $i ]] then var=$PWD/$file return 0 fi break done fi for view in ${VIEWS[@]} do case $view in /*) ;; *) view=$pwd/$view ;; esac case $offset in '') case $pwd in $view/*) offset=${pwd#$view} ;; *) offset=${bwd#$view} ;; esac ;; esac if [[ -r $view$offset/$file ]] then if [[ ! -d $view$offset/$file ]] then var=$view$offset/$file return 0 fi for i in $view$offset/$file/* do if [[ -f $i ]] then var=$view$offset/$file return 0 fi break done fi done var= return 1 } function INCLUDE # file ... { typeset f v x for f do if VIEW v $f || [[ $PREFIX && $f != /* ]] && VIEW v $PREFIX$f then x=$x$'\n'". $v" else FATAL $f: not found fi done [[ $x ]] && trap "$x" 0 } function UMASK # [ mask ] { if (( $# )) then UMASK=$1 else UMASK=$UMASK_ORIG fi } function PIPE # INPUT|OUTPUT|ERROR file|- data ... { IO $0 "$@" } function FIFO # INPUT|OUTPUT|ERROR file|- data ... { IO $0 "$@" } function IF # command(s) [note] { [[ $GROUP == $TEST_select ]] || return RUN (( COND++ )) COND_LINE[COND]=$LINE if (( COND > 1 && COND_SKIP[COND-1] )) then (( COND_KEPT[COND] = 1 )) (( COND_SKIP[COND] = 1 )) elif eval "{ $1 ;} >/dev/null 2>&1" then (( COND_KEPT[COND] = 1 )) (( COND_SKIP[COND] = 0 )) [[ $2 && ! $TEST_quiet ]] && print -u2 "NOTE $2" else (( COND_KEPT[COND] = 0 )) (( COND_SKIP[COND] = 1 )) fi } function ELIF # command(s) [note] { [[ $GROUP == $TEST_select ]] || return RUN if (( COND <= 0 )) then FATAL line $LINE: no matching IF for ELIF fi if (( COND_KEPT[COND] )) then (( COND_SKIP[COND] = 0 )) elif eval "$* > /dev/null 2>&1" then (( COND_KEPT[COND] = 1 )) (( COND_SKIP[COND] = 0 )) [[ $2 && ! $TEST_quiet ]] && print -u2 "NOTE $2" else (( COND_SKIP[COND] = 1 )) fi } function ELSE # [note] { [[ $GROUP == $TEST_select ]] || return RUN if (( COND <= 0 )) then FATAL line $LINE: no matching IF for ELSE fi if (( COND_KEPT[COND] )) then (( COND_SKIP[COND] = 1 )) else (( COND_KEPT[COND] = 1 )) (( COND_SKIP[COND] = 0 )) [[ $1 && ! $TEST_quiet ]] && print -u2 "NOTE $1" fi } function FI { [[ $GROUP == $TEST_select ]] || return RUN if (( COND <= 0 )) then FATAL line $LINE: no matching IF for FI on line $LINE fi (( ! COND_KEPT[COND] )) && [[ $1 && ! $TEST_quiet ]] && print -u2 "NOTE $1" (( COND-- )) } # main integer ERRORS=0 ENVIRONS=0 EXPORTS=0 TESTS=0 SUBTESTS=0 LINE=0 TESTLINE=0 integer ITEM=0 LASTITEM=0 COND=0 UNIT_READONLY=0 COUNT typeset ARGS COMMAND COPY DIAGNOSTICS ERROR EXEC FLUSHED=0 GROUP=INIT typeset IGNORE INPUT KEEP OUTPUT TEST SOURCE MOVE NOTE UMASK UMASK_ORIG typeset ARGS_ORIG COMMAND_ORIG TITLE UNIT ARGV PREFIX OFFSET IGNORESPACE typeset COMPARE MAIN JOBPID='' JOBSTATUS='' typeset TEST_file TEST_keep TEST_pipe_input TEST_pipe_io TEST_pipe_output TEST_local typeset TEST_quiet TEST_regular=1 TEST_rmflags='-rf --' TEST_rmu TEST_select typeset -A SAME VIEWS FILE TYPE READONLY FILTER typeset -a COND_LINE COND_SKIP COND_KEPT ENVIRON EXPORT typeset -Z LAST=00 unset FIGNORE while getopts -a $command "$USAGE" OPT do case $OPT in b) (( $OPTARG )) && IGNORESPACE=-b ;; i) SET - pipe-input=$OPTARG ;; k) SET - keep=$OPTARG ;; l) SET - local ;; o) SET - pipe-output=$OPTARG ;; p) SET - pipe-io=$OPTARG ;; q) SET - quiet=$OPTARG ;; r) SET - regular=$OPTARG ;; t) if [[ $TEST_select ]] then TEST_select="$TEST_select|${OPTARG//,/\|}" else TEST_select="${OPTARG//,/\|}" fi ;; x) SET - trace=$OPTARG ;; v) SET - verbose=$OPTARG ;; *) GROUP=FINI exit 2 ;; esac done shift $OPTIND-1 case $# in 0) FATAL test unit name omitted ;; esac export COLUMNS=80 SOURCE=$PWD PATH=$SOURCE:${PATH#?(.):} PATH=${PATH%%:?(.)}:/bin:/usr/bin UNIT=$1 shift if [[ -f $UNIT && ! -x $UNIT ]] then REGRESS=$UNIT else REGRESS=${UNIT%.tst} REGRESS=$REGRESS.tst [[ -f $REGRESS ]] || FATAL $REGRESS: regression tests not found fi UNIT=${UNIT##*/} UNIT=${UNIT%.tst} MAIN=$UNIT if [[ $VPATH ]] then set -A VIEWS ${VPATH//:/' '} OFFSET=${SOURCE#${VIEWS[0]}} if [[ $OFFSET ]] then OFFSET=${OFFSET#/}/ fi fi if [[ $REGRESS == */* ]] then PREFIX=${REGRESS%/*} if [[ ${#VIEWS[@]} ]] then for i in ${VIEWS[@]} do PREFIX=${PREFIX#$i/} done fi PREFIX=${PREFIX#$OFFSET} if [[ $PREFIX ]] then PREFIX=$PREFIX/ fi fi TWD=$PWD/$UNIT.tmp PMP=$(pwd -P)/$UNIT.tmp UMASK_ORIG=$(umask) UMASK=$UMASK_ORIG ARGV=("$@") if [[ ${ARGV[0]} && ${ARGV[0]} != [-+]* ]] then UNIT "${ARGV[@]}" UNIT_READONLY=1 fi trap 'CLEANUP' EXIT if [[ ! $TEST_select ]] then TEST_select="[0123456789]*" fi TEST_select="@($TEST_select|+(0))" if [[ $TEST_trace ]] then export PS4=':$LINENO: ' typeset -ft $(typeset +f) set -x fi if [[ $TEST_verbose ]] then typeset SHOW else typeset -L70 SHOW fi if [[ ! $TEST_keep ]] && (ulimit -c 0) >/dev/null 2>&1 then ulimit -c 0 fi set --pipefail # some last minute shenanigans alias BODY='BODY=BODY; function BODY' alias CONTINUE='LINE=$LINENO; CONTINUE' alias DO='(( $ITEM != $FLUSHED )) && RUN DO; DO &&' alias DONE='DONE=DONE; function DONE' alias EXEC='LINE=$LINENO; EXEC' alias EXITED='LINE=$LINENO; EXITED' alias INIT='INIT=INIT; function INIT' alias JOB='LINE=$LINENO; JOB' alias KILL='LINE=$LINENO; KILL' alias PROG='LINE=$LINENO; FLUSH; PROG' alias TEST='TESTLINE=$LINENO; TEST' alias IF='LINE=$LINENO; FLUSH; IF' alias ELIF='LINE=$LINENO; FLUSH; ELIF' alias ELSE='LINE=$LINENO; FLUSH; ELSE' alias FI='LINE=$LINENO; FLUSH; FI' # do the tests . $REGRESS RUN GROUP=FINI ksh-1.0.10/src/cmd/INIT/socket.c000066400000000000000000000025571465301102200161120ustar00rootroot00000000000000/*********************************************************************** * * * This software is part of the ast package * * Copyright (c) 1994-2011 AT&T Intellectual Property * * Copyright (c) 2020-2023 Contributors to ksh 93u+m * * and is licensed under the * * Eclipse Public License, Version 2.0 * * * * A copy of the License is available at * * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html * * (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) * * * * Glenn Fowler * * Martijn Dekker * * Johnothan King * * * ***********************************************************************/ /* * small test for -lnsl */ #ifndef socket #include #include #endif int main(void) { return socket(0, 0, 0) < 0; } ksh-1.0.10/src/cmd/INIT/utils/000077500000000000000000000000001465301102200156055ustar00rootroot00000000000000ksh-1.0.10/src/cmd/INIT/utils/Mamfile_indent000077500000000000000000000014331465301102200204470ustar00rootroot00000000000000origIFS=$IFS IFS=''; set -fCu # safe mode: no split/glob = no quoting headaches let() { return $((!($1))); } # Automatically (re-)indent make...done blocks in a Mamfile. # Usage: Mamfile_indent Mamfile.new # # Should work on all current POSIX compliant shells. # By Martijn Dekker , 2021, 2024. Public domain. # Spacing per indentation level. Edit to change style. indent=' ' # one tab # Remove existing indentation, add new indentation. indentlvl=0 sed 's/^[[:space:]]*//' \ | while IFS=$origIFS read -r line do case $line in '') printf '\n'; continue ;; done*) let "indentlvl -= 1" ;; esac spc= i=0 while let "(i += 1) <= indentlvl" do spc=$indent$spc done printf '%s\n' $spc$line case $line in make* | loop*) let "indentlvl += 1" ;; esac done ksh-1.0.10/src/cmd/INIT/utils/Mamfile_rm_unused_vars000077500000000000000000000020051465301102200222160ustar00rootroot00000000000000IFS=''; set -fCu # safe mode: no split/glob = no quoting headaches CCn=' ' # newline let() { return $((!($1))); } # Remove unused variable definitions from a Mamfile. # Usage: Mamfile_rm_unused_vars Mamfile.new # # Should work on all current POSIX compliant shells. # By Martijn Dekker , 2021, 2024. Public domain. # # All variables are declared with 'setv' and they are used if an expansion # of the form ${varname} exists (the braces are mandatory in Mamfiles). mamfile=$(let $# && cat "$1" || cat) vars=$(printf '%s\n' $mamfile | awk '$1 == "setv" { print $2; }') rm_unused_ere= IFS=$CCn; for varname in $vars; do IFS= case $varname in MAMAKE_STRICT) continue ;; esac case $mamfile in *"\${$varname}"* ) ;; * ) # add with '|' separator for Extended Regular Expression rm_unused_ere="${rm_unused_ere:+$rm_unused_ere|}setv[[:blank:]]+$varname([[:blank:]]|$)" ;; esac done case $rm_unused_ere in '') printf '%s\n' $mamfile ;; *) printf '%s\n' $mamfile | grep -vE $rm_unused_ere ;; esac ksh-1.0.10/src/cmd/INIT/w.c000066400000000000000000000025301465301102200150570ustar00rootroot00000000000000/*********************************************************************** * * * This software is part of the ast package * * Copyright (c) 1994-2011 AT&T Intellectual Property * * Copyright (c) 2020-2023 Contributors to ksh 93u+m * * and is licensed under the * * Eclipse Public License, Version 2.0 * * * * A copy of the License is available at * * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html * * (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) * * * * Glenn Fowler * * Martijn Dekker * * Johnothan King * * * ***********************************************************************/ #ifndef DONTCARE #include #include #endif int main(void) { wchar_t w = ' '; return iswspace(w) == 0; } ksh-1.0.10/src/cmd/INIT/w2.c000066400000000000000000000025001465301102200151360ustar00rootroot00000000000000/*********************************************************************** * * * This software is part of the ast package * * Copyright (c) 1994-2011 AT&T Intellectual Property * * Copyright (c) 2020-2023 Contributors to ksh 93u+m * * and is licensed under the * * Eclipse Public License, Version 2.0 * * * * A copy of the License is available at * * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html * * (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) * * * * Glenn Fowler * * Martijn Dekker * * Johnothan King * * * ***********************************************************************/ #include #include int main(void) { wchar_t w = ' '; return iswspace(w) == 0; } ksh-1.0.10/src/cmd/Mamfile000066400000000000000000000004461465301102200152030ustar00rootroot00000000000000note * note * This build script is in an extended Make Abstract Machine (MAM) note * language. Documentation is at: src/cmd/INIT/README-mamake.md note * setv MAMAKE_STRICT 4 make test virtual make install virtual make all virtual exec - %{MAMAKE} -r '*' %{MAMAKEARGS} done done done ksh-1.0.10/src/cmd/builtin/000077500000000000000000000000001465301102200153505ustar00rootroot00000000000000ksh-1.0.10/src/cmd/builtin/Mamfile000066400000000000000000000035471465301102200166560ustar00rootroot00000000000000note * note * This build script is in an extended Make Abstract Machine (MAM) note * language. Documentation is at: src/cmd/INIT/README-mamake.md note * setv MAMAKE_STRICT 4 setv INSTALLROOT ../../.. setv CC cc setv mam_cc_FLAGS %{mam_cc_TARGET} %{mam_cc_DLL} %{-debug-symbols?1?%{mam_cc_DEBUG} -D_BLD_DEBUG?%{mam_cc_OPTIMIZE}?} setv CCFLAGS setv CCLDFLAGS %{-strip-symbols?1?%{mam_cc_LD_STRIP}??} setv IFFEFLAGS setv LDFLAGS make install virtual bind -lcmd bind -lutil dontcare note * note * Build pty note * make pty make pty.o make pty.c make FEATURE/pty makp features/pty exec - iffe %{IFFEFLAGS} -v -c "%{CC} %{mam_cc_FLAGS} %{CCFLAGS} %{LDFLAGS}" ref \ exec - -I%{INCLUDE_AST} -I%{INSTALLROOT}/include %{mam_libast} %{mam_libcmd} : run %{<} done prev %{INCLUDE_AST}/ast_time.h prev %{INCLUDE_AST}/regex.h prev %{INCLUDE_AST}/proc.h prev %{INCLUDE_AST}/error.h prev %{INCLUDE_AST}/cmd.h done pty.c exec - %{CC} %{mam_cc_FLAGS} %{CCFLAGS} -I. -I%{INCLUDE_AST} \ exec - -DERROR_CATALOG=\""builtin"\" -DCMD_STANDALONE=b_pty -c %{<} done pty.o exec - %{CC} %{CCLDFLAGS} %{mam_cc_FLAGS} %{CCFLAGS} %{mam_cc_NOSTRICTALIASING} %{LDFLAGS} \ exec - -o pty pty.o %{mam_libutil} %{mam_libast} %{mam_libcmd} done pty note * note * Dynamically linked version, if supported note * make %{INSTALLROOT}/dyn/bin/pty dontcare prev pty makp %{INSTALLROOT}/lib/lib/cmd exec - export LDFLAGS='%{LDFLAGS} %{CCLDFLAGS} %{mam_cc_LD_NOASNEEDED}' exec - dylink -e pty %{mam_libutil} $(cat %{<}) pty.o done note * note * Pre-install note * make %{INSTALLROOT}/bin exec - mkdir -p %{@} done make %{INSTALLROOT}/bin/pty prev pty note * macOS throws code signature error if 'cp' overwrites Mach-O binary; must remove first exec - rm -f %{@} && cp %{<} %{@} done done install make test dontcare virtual done test ksh-1.0.10/src/cmd/builtin/RELEASE000066400000000000000000000012211465301102200163470ustar00rootroot00000000000000This file is of historical interest only. For recent changes in both ksh 93u+m and the accompanying libraries, see the file NEWS in the top-level directory. ____ 12-02-28 pty.c: change --verbose[=level] to --debug=level 12-01-26 pty.c: fix --man docs 10-06-21 pty.c: add 4 sec timeout for initial handshake -- fix me!! 10-04-12 pty: fix sfpoll() result read/write bug 10-04-01 pty: add --tty='stty-settings' 10-03-19 pty: add --dialogue 10-03-15 pty: fix select() fd management 09-03-31 features/pty,Makefile: add pty.h and -lutil refs for Linux -- great, another util library 09-01-30 pty.c: add (for fd_set!! on mvs.390) 06-07-20 pty.c: add ksh-1.0.10/src/cmd/builtin/features/000077500000000000000000000000001465301102200171665ustar00rootroot00000000000000ksh-1.0.10/src/cmd/builtin/features/pty000066400000000000000000000024611465301102200177300ustar00rootroot00000000000000header sys/types.h header pty.h header libutil.h header sys/pty.h header sys/ptyio.h header sys/vty.h header sys/ioctl.h header stropts.h lib openpty,_getpty,ptsname -lutil lib grantpt,unlockpt,posix_openpt stdlib.h lib cfmakeraw termios.h tst output{ #include #if _lib_ptsname #include #endif #include #include #include #include int main(void) { int i; struct stat statb; static char* pty[] = { "/dev/ptyp0000", "/dev/ptym/ptyp0", "/dev/ptyp0" }; #if _lib_ptsname int fd; static char* ptc[] = { "/dev/ptmx", "/dev/ptc", "/dev/ptmx_bsd" }; for (i = 0; i < sizeof(ptc) / sizeof(ptc[0]); i++) if((fd = open(ptc[i], 2))>=0) { if (ptsname(fd)) { sfprintf(sfstdout, "#define _pty_clone\t\"%s\"\n", ptc[i]); close(fd); break; } close(fd); } #endif for (i = 0;; i++) if(i >= (sizeof(pty) / sizeof(pty[0]) - 1) || stat(pty[i], &statb)>=0) { sfprintf(sfstdout, "#define _pty_first\t\"%s\"\n", pty[i]); break; } return 0; } }end fail{ echo "$0: Output block failed to compile. Export IFFEFLAGS=-d1 to debug." >&2 exit 1 }end extern _getpty char* (int*, int, mode_t, int) extern openpty int (int*, int*, char*, struct termios*, struct winsize*) extern ptsname char* (int) ksh-1.0.10/src/cmd/builtin/pty.c000066400000000000000000000632171465301102200163410ustar00rootroot00000000000000/*********************************************************************** * * * This software is part of the ast package * * Copyright (c) 1992-2013 AT&T Intellectual Property * * Copyright (c) 2020-2024 Contributors to ksh 93u+m * * and is licensed under the * * Eclipse Public License, Version 2.0 * * * * A copy of the License is available at * * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html * * (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) * * * * Glenn Fowler * * David Korn * * Martijn Dekker * * Johnothan King * * * ***********************************************************************/ static const char usage[] = "[-?\n@(#)pty (ksh 93u+m) 2024-07-27\n]" "[-author?Glenn Fowler ]" "[-author?David Korn ]" "[-copyright?Copyright (c) 2001-2013 AT&T Intellectual Property]" "[-license?https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html]" "[--catalog?builtin]" "[+NAME?pty - create pseudo terminal and run command]" "[+DESCRIPTION?\bpty\b creates a pseudo pty and then runs \bcommand\b " "with arguments given by \aarg\a and the standard input, standard " "output, and standard error connected to the pseudo terminal. By " "default, the \bpty\b creates a new session.]" "[+?If \bcommand\b does not contain a \b/\b, the \bPATH\b variable will " "be used to locate the \bcommand\b.]" "[+?Input to \bpty\b will be written to the standard input of this " "command. The standard output and standard error from the command will " "be written to the standard output of \bpty\b.]" "[+?The \bpty\b command terminates when the command completes.]" "[d:dialogue?Execute the dialogue on the standard input. A dialogue is a " "sequence of commands, one command per line. All \are\a patterns are " "extended regular expressions. The \are\a \b?1\b will print the subject " "string on the standard error and match the string; the \are\a \b?0\b " "will print the subject string on the standard error and not match the " "string. The \are\a \b?.\b matches EOF. The commands are:]" "{" "[\b#\b \acomment\a?comment line]" "[c \atext\a?write \atext\a to the master; C style escapes " "in text are converted, including \\E for ESC and \\cX for " "control-X]" "[d \amilliseconds\a?set the delay before each master write to " "\amilliseconds\a; the default is no delay]" "[i \are\a?read a line from the master; if it matches \are\a " "then execute lines until matching \be\b or \bf\b]" "[e [re]]?else [if match re]] then execute lines until matching " "\be\b or \bf\b]" "[f?end of \bi\b/\be\b block]" "[m \atext\a?write \atext\a to the standard error]" "[p \atext\a?peek input until \atext\a is found at the beginning " "of a line; input is not consumed]" "[r [\are\a]]?read a line from the master [and it should match " "re]]]" "[s \amilliseconds\a?sleep for \amilliseconds\a]" "[t \amilliseconds\a?set the master read timeout to " "\amilliseconds\a; the default is \b1000\b]" "[u \are\a?read lines from the master until one matches \are\a]" "[v \alevel\a?set the verbose trace \alevel\a, more output for " "higher levels, disabled for level 0]" "[w \atext\a?write \atext\a\\r\\n to the master; C style escapes " "in text are converted, including \\E for ESC and \\cX for " "control-X]" "[x [\acode\a]]" "?exit \bpty\b with exit code \b0\b [\acode\a]]]" "[I \are\a?ignore master lines matching \are\a]" "[L \alabel\a?prefix all diagnostics with \alabel\a:]" "[P \atext\a?delay each master write until the beginning of " "an unread input line exactly matches \atext\a]" "}" "[D:debug?Set the debug trace \alevel\a, higher levels produce more " "output, disabled for level 0.]#[level]" "[l:log?Log the master stdout and stderr to \afile\a.]:[file]" "[m:messages?Redirect diagnostic message output to \afile\a.]:[file]" "[s!:session?Create a separate session for the process started by " "\bpty\b.]" "[t:timeout?Set the master read timeout to " "\amilliseconds\a.]#[milliseconds:=1000]" "[T:tty?Pass \astty\a to the \bstty\b(1) command to initialize the " "pty.]:[stty]" "[w:delay?Set the delay before each master write to " "\amilliseconds\a.]#[milliseconds:=0]" "\n" "\ncommand [arg ...]\n" "\n" "[+EXIT STATUS?If the command determined by \bcommand\b is run the exit " "status of \bpty\b is that of this command. Otherwise, the exit status " "is one of the following:]" "{" "[+127?The command is found but cannot be executed.]" "[+128?The command could not be found.]" "}" "[+SEE ALSO?\bcommand\b(1), \bexec\b(1)]" ; #include #include #include #include #include #include #include #include #include #include #include #include "FEATURE/pty" #define MODE_666 (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) #define MAXNAME 64 #ifndef CMIN #define CMIN 1 #endif static noreturn void outofmemory(void) { error(ERROR_SYSTEM|ERROR_PANIC, "out of memory"); UNREACHABLE(); } #if !_lib_openpty && !_lib__getpty && !defined(_pty_clone) # if !_lib_grantpt || !_lib_unlock # if !_lib_ptsname static char *minionname(const char *name) { static char sname[MAXNAME]; char *last; strncpy(sname,name,sizeof(sname)); last = strrchr(sname,'/'); last[1] = 't'; return sname; } # endif static char *master_name(char *name) { static char sname[MAXNAME]; int n; if(!name) { strcpy(sname,_pty_first); return sname; } n = strlen(_pty_first); if(name[n-1]=='9') name[n-1]='a'; else if(name[n-1]=='f') { if(_pty_first[n-2]=='0' && name[n-2]=='9') { name[n-2]='0'; if(name[n-3]=='9' || name[n-3]=='z') return NULL; name[n-3]++; } if(_pty_first[n-2]=='p' && (name[n-2]=='z' || name[n-2]=='Z')) { if(name[n-2]=='z') name[n-2]='P'; else return NULL; } else name[n-2]++; name[n-1]='0'; } else name[n-1]++; return name; } #endif #if !_lib_openpty static char *ptymopen(int *master) { char *minion=0; # if _lib__getpty return _getpty(master,O_RDWR,MODE_666,0); # else # if defined(_pty_clone) *master = open(_pty_clone,O_RDWR|O_CREAT,MODE_666); if(*master>=0) minion = ptsname(*master); # else int fdm; char *name=0; while(name=master_name(name)) { fdm = open(name,O_RDWR|O_CREAT,MODE_666); if(fdm >= 0) { *master = fdm; # if _lib_ptsname minion = ptsname(fdm); # else minion = minionname(name); # endif break; } } # endif # endif return minion; } # endif #endif static int mkpty(int* master, int* minion) { struct termios tty; struct termios* ttyp; #ifdef TIOCGWINSZ struct winsize win; struct winsize* winp; #endif #if !_lib_openpty char* sname; #endif #ifdef SIGTTOU sigset_t blckttou, oldset; (void)sigemptyset(&blckttou); (void)sigaddset(&blckttou, SIGTTOU); sigprocmask(SIG_BLOCK, &blckttou, &oldset); #endif alarm(6); if (tcgetattr(sffileno(sfstderr), &tty) < 0) { if (errno != ENOTTY) error(-1, "unable to get standard error terminal attributes"); #if _lib_cfmakeraw cfmakeraw(&tty); #else tty.c_iflag |= IGNPAR; tty.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF); tty.c_oflag &= ~OPOST; tty.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL); #endif /* _lib_cfmakeraw */ ttyp = 0; } tty.c_lflag |= ICANON | IEXTEN | ISIG | ECHO | ECHOE | ECHOK; #ifdef ECHOKE tty.c_lflag |= ECHOKE; #endif tty.c_oflag |= (ONLCR | OPOST); #ifdef OCRNL tty.c_oflag &= ~OCRNL; #endif #ifdef ONLRET tty.c_oflag &= ~ONLRET; #endif tty.c_iflag |= BRKINT; tty.c_iflag &= ~IGNBRK; tty.c_cc[VTIME] = 0; tty.c_cc[VMIN] = CMIN; #ifdef B115200 cfsetispeed(&tty, B115200); cfsetospeed(&tty, B115200); #elif defined(B57600) cfsetispeed(&tty, B57600); cfsetospeed(&tty, B57600); #elif defined(B38400) cfsetispeed(&tty, B38400); cfsetospeed(&tty, B38400); #endif ttyp = &tty; #ifdef TIOCGWINSZ if (ioctl(sffileno(sfstderr), TIOCGWINSZ, &win) < 0) { if (errno != ENOTTY) error(-1, "unable to get standard error window size"); win.ws_row = 0; win.ws_col = 0; winp = 0; } if (win.ws_row < 24) win.ws_row = 24; if (win.ws_col < 80) win.ws_col = 80; winp = &win; #endif #ifdef __linux__ # if !_lib_openpty # undef _lib_openpty # define _lib_openpty 1 # endif #endif #if _lib_openpty if (openpty(master, minion, NULL, ttyp, winp) < 0) return -1; #else #if _lib_grantpt && _lib_unlockpt #if !_lib_posix_openpt #ifndef _pty_clone #define _pty_clone "/dev/ptmx" #endif #define posix_openpt(m) open(_pty_clone,m) #endif if ((*master = posix_openpt(O_RDWR)) < 0) return -1; if (grantpt(*master) || unlockpt(*master) || !(sname = ptsname(*master)) || (*minion = open(sname, O_RDWR|O_cloexec)) < 0) { close(*master); return -1; } #else if (!(sname = ptymopen(master)) || (*minion = open(sname, O_RDWR|O_cloexec)) < 0) return -1; #endif #ifdef I_PUSH { struct termios tst; if (tcgetattr(*minion, &tst) < 0 && (ioctl(*minion, I_PUSH, "ptem") < 0 || ioctl(*minion, I_PUSH, "ldterm") < 0)) { close(*minion); close(*master); return -1; } } #endif #endif if (ttyp && tcsetattr(*minion, TCSANOW, ttyp) < 0) error(ERROR_warn(0), "unable to set pty terminal attributes"); #ifdef TIOCSWINSZ if (winp && ioctl(*minion, TIOCSWINSZ, winp) < 0) error(ERROR_warn(0), "unable to set pty window size"); #endif fcntl(*master, F_SETFD, FD_CLOEXEC); #if !O_cloexec fcntl(*minion, F_SETFD, FD_CLOEXEC); #endif #ifdef SIGTTOU sigprocmask(SIG_SETMASK, &oldset, NULL); #endif alarm(0); return 0; } static Proc_t* runcmd(char** argv, int minion, int session) { long ops[4]; if (session) { ops[0] = PROC_FD_CTTY(minion); ops[1] = 0; } else { ops[0] = PROC_FD_DUP(minion, 0, PROC_FD_CHILD); ops[1] = PROC_FD_DUP(minion, 1, PROC_FD_CHILD); ops[2] = PROC_FD_DUP(minion, 2, PROC_FD_CHILD); ops[3] = 0; } return procopen(argv[0], argv, NULL, ops, 0); } /* * default master dance */ static int process(Sfio_t* mp, Sfio_t* lp, int delay, int timeout) { int i; int n; int t; ssize_t r; char* s; Sfio_t* ip; Sfio_t* sps[2]; struct stat dst; struct stat fst; ip = sfstdin; if (!fstat(sffileno(ip), &dst) && !stat("/dev/null", &fst) && dst.st_dev == fst.st_dev && dst.st_ino == fst.st_ino) ip = 0; do { i = 0; t = timeout; if (mp) sps[i++] = mp; if (ip) { sps[i++] = ip; t = -1; } if (!i) break; if ((n = sfpoll(sps, i, t)) <= 0) { if (n < 0) error(ERROR_SYSTEM|2, "poll failed"); break; } for (i = t = 0; i < n; i++) { if (!(sfvalue(sps[i]) & SFIO_READ)) /*skip*/; else if (sps[i] == mp) { t++; if (!(s = (char*)sfreserve(mp, SFIO_UNBOUND, -1))) { sfclose(mp); mp = 0; } else if ((r = sfvalue(mp)) > 0 && (sfwrite(sfstdout, s, r) != r || sfsync(sfstdout))) { error(ERROR_SYSTEM|2, "output write failed"); goto done; } } else { t++; if (!(s = sfgetr(ip, '\n', 1))) ip = 0; else if (sfputr(mp, s, '\r') < 0 || sfsync(mp)) { error(ERROR_SYSTEM|2, "write failed"); goto done; } } } } while (t); done: if (mp) sfclose(mp); return error_info.errors != 0; } /* * return 1 is extended re pattern matches text */ static int match(char* pattern, char* text, int must) { regex_t* re; int code; char buf[64]; if (!pattern[0]) return 1; if (pattern[0] == '?' && pattern[1] && !pattern[2]) { switch (pattern[1]) { case '0': case '1': if (text) error(2, "got \"%s\"", fmtesq(text, "\"")); else error(2, "got EOF"); return pattern[1] == '1'; case '.': if (!text) return 1; if (must) error(2, "expected EOF, got \"%s\"", fmtesq(text, "\"")); return 0; } } if (!text) { if (must) error(2, "expected \"%s\", got EOF", pattern); return 0; } if (!(re = regcache(pattern, REG_EXTENDED, &code))) { regerror(code, re, buf, sizeof(buf)); error(2, "%s: %s", pattern, buf); return 0; } if (regexec(re, text, 0, NULL, 0)) { if (must) error(2, "expected \"%s\", got \"%s\"", pattern, fmtesq(text, "\"")); return 0; } return 1; } typedef struct Master_s { char* ignore; /* ignore master lines matching this re */ char* peek; /* peek buffer pointer */ char* cur; /* current line */ char* nxt; /* next line */ char* end; /* end of lines */ char* max; /* end of buf */ char* bufunderflow; /* FIXME: kludge to cope with underflow */ char* buf; /* current buffer */ char* prompt; /* peek prompt */ int cursor; /* cursor in buf, 0 if fresh line */ int line; /* prompt line number */ int restore; /* previous line save char */ } Master_t; #define BUFUNDERFLOW 128 /* bytes of buffer underflow to allow */ /* * read one line from the master */ #define MASTER_EOF (-1) #define MASTER_TIMEOUT (-2) static char* masterline(Sfio_t* mp, Sfio_t* lp, char* prompt, int must, int timeout, Master_t* bp) { char* r; char* s; char* t; ssize_t n; size_t promptlen = 0; ptrdiff_t d; char promptbuf[64]; if (prompt) promptlen = sfsprintf(promptbuf, sizeof(promptbuf), prompt, ++bp->line); again: if (prompt) { if (bp->cur < bp->end && bp->restore >= 0) *bp->cur = bp->restore; if (strneq(bp->cur, promptbuf, promptlen)) r = bp->cur; else r = 0; if (bp->cur < bp->end && bp->restore >= 0) *bp->cur = 0; if (r) { error(-1, "p \"%s\"", fmtnesq(promptbuf, "\"", promptlen)); return r; } if (r = bp->nxt) { if (strneq(r, promptbuf, promptlen)) { error(-1, "p \"%s\"", fmtnesq(promptbuf, "\"", promptlen)); return r; } while (r = memchr(r, '\n', bp->end - r)) { if (strneq(r, promptbuf, promptlen)) { error(-1, "p \"%s\"", fmtnesq(promptbuf, "\"", promptlen)); return r; } r++; } } *bp->cur = 0; } else if (bp->nxt) { if (bp->restore >= 0) *bp->cur = bp->restore; r = bp->cur; bp->restore = *bp->nxt; *bp->nxt = 0; if (bp->nxt >= bp->end) { bp->cur = bp->end = bp->buf; bp->nxt = 0; } else { bp->cur = bp->nxt; if (bp->nxt = memchr(bp->nxt + 1, '\n', bp->end - bp->nxt - 1)) bp->nxt++; } goto done; } if ((n = sfpoll(&mp, 1, timeout)) <= 0 || !((int)sfvalue(mp) & SFIO_READ)) { if (n < 0) { if (must) error(ERROR_SYSTEM|2, "poll failed"); else error(-1, "r poll failed"); } else if (bp->cur < bp->end) { if (bp->restore >= 0) { *bp->cur = bp->restore; bp->restore = -1; } r = bp->cur; *bp->end = 0; bp->nxt = 0; if (prompt && strneq(r, promptbuf, promptlen)) { error(-1, "p \"%s\"", fmtnesq(promptbuf, "\"", promptlen)); return r; } bp->cur = bp->end = bp->buf; goto done; } else if (must >= 0) error(2, "read timeout"); else { errno = 0; error(-1, "r EOF"); } return NULL; } if (!(s = sfreserve(mp, SFIO_UNBOUND, -1))) { if (!prompt) { if (bp->cur < bp->end) { if (bp->restore >= 0) { *bp->cur = bp->restore; bp->restore = -1; } r = bp->cur; *bp->end = 0; bp->cur = bp->end = bp->buf; bp->nxt = 0; goto done; } else { errno = 0; error(-1, "r EOF"); } } return NULL; } n = sfvalue(mp); error(-2, "b \"%s\"", fmtnesq(s, "\"", n)); if ((bp->max - bp->end) < n) { size_t old_buf_size, new_buf_size; r = bp->buf; old_buf_size = bp->max - bp->buf + 1; new_buf_size = roundof(old_buf_size + n, SFIO_BUFSIZE); bp->bufunderflow = realloc(bp->bufunderflow, new_buf_size + BUFUNDERFLOW); if (!bp->bufunderflow) outofmemory(); bp->buf = bp->bufunderflow + BUFUNDERFLOW; memset(bp->buf + old_buf_size, 0, new_buf_size - old_buf_size); bp->max = bp->buf + new_buf_size - 1; if (bp->buf != r) { d = bp->buf - r; bp->cur += d; bp->end += d; } } memcpy(bp->end, s, n); bp->end += n; if ((r = bp->cur) > bp->buf && bp->restore >= 0) *r = bp->restore; if (bp->cur = memchr(bp->cur, '\n', bp->end - bp->cur)) { bp->restore = *++bp->cur; *bp->cur = 0; if (bp->cur >= bp->end) { bp->cur = bp->end = bp->buf; bp->nxt = 0; } else if (bp->nxt = memchr(bp->cur + 1, '\n', bp->end - bp->cur - 1)) bp->nxt++; if (prompt) goto again; } else { bp->restore = -1; bp->cur = r; bp->nxt = 0; must = 0; goto again; } done: error(-3, "Q \"%s\"", fmtesq(r, "\"")); s = r; if (bp->cursor) { r -= bp->cursor; /* FIXME: r may now be before bp->buf */ if (r < bp->bufunderflow) error(ERROR_PANIC, "pty.c:%d: internal error: r is %d bytes before bp->bufunderflow", __LINE__, bp->bufunderflow - r); bp->cursor = 0; } for (t = 0, n = 0; *s; s++) if (*s == '\n') { if (t) { *t++ = '\n'; *t = 0; t = 0; n = 0; } } else if (*s == '\r' && *(s + 1) != '\n') { if (t = strchr(s + 1, '\r')) n += t - s; else n += strlen(s); t = r; } else if (*s == '\a') { if (!t) t = s; *t = ' '; n++; } else if (*s == '\b') { if (!t) t = s; if (t > r) t--; else n++; } else if (t) *t++ = *s; if (t) error(-3, "R \"%s\"", fmtesq(r, "\"")); if (n) *(r + strlen(r) - n) = 0; error(-1, "r \"%s\"", fmtesq(r, "\"")); if (lp) sfputr(lp, fmtesq(r, "\""), '\n'); if (t) bp->cursor = t - r; if (bp->ignore && match(bp->ignore, r, 0)) goto again; return r; } /* * execute dialogue script on stdin */ #define NESTING 64 #define ELSE 0x01 #define IF 0x02 #define KEPT 0x04 #define SKIP 0x08 struct Cond_s; typedef struct Cond_s Cond_t; struct Cond_s { Cond_t* next; Cond_t* prev; char* text; int flags; }; static int dialogue(Sfio_t* mp, Sfio_t* lp, int delay, int timeout) { int op; int line; int n; char* s; char* m; char* e; char* id; Cond_t* cond; Master_t* master; int status = 0; if (!(cond = calloc(1, sizeof(*cond))) || !(master = calloc(1, sizeof(*master))) || !(master->bufunderflow = calloc(2 * SFIO_BUFSIZE + BUFUNDERFLOW, sizeof(char)))) outofmemory(); master->buf = master->bufunderflow + BUFUNDERFLOW; master->cur = master->end = master->buf; master->max = master->buf + 2 * SFIO_BUFSIZE - 1; master->restore = -1; errno = 0; id = error_info.id; error_info.id = 0; line = error_info.line; error_info.line = 0; while (s = sfgetr(sfstdin, '\n', 1)) { error_info.line++; while (isspace(*s)) s++; if ((op = *s++) && isspace(*s)) s++; switch (op) { case 0: case '#': break; case 'c': case 'w': if (cond->flags & SKIP) continue; if (master->prompt && !masterline(mp, lp, master->prompt, 0, timeout, master)) goto done; if (delay) usleep((unsigned long)delay * 1000); if (op == 'w') error(-1, "w \"%s\\r\"", s); else error(-1, "w \"%s\"", s); if ((n = stresc(s)) >= 0) s[n] = 0; if (sfputr(mp, s, op == 'w' ? '\n' : -1) < 0 || sfsync(mp)) { error(ERROR_SYSTEM|2, "write failed"); goto done; } if (delay) usleep((unsigned long)delay * 1000); break; case 'd': delay = (int)strtol(s, &e, 0); if (*e) error(2, "%s: invalid delay -- milliseconds expected", s); break; case 'i': if (!cond->next && !(cond->next = calloc(1, sizeof(Cond_t)))) outofmemory(); cond = cond->next; cond->flags = IF; if ((cond->prev->flags & SKIP) && !(cond->text = 0) || !(cond->text = masterline(mp, lp, 0, 0, timeout, master))) cond->flags |= KEPT|SKIP; else if (match(s, cond->text, 0)) cond->flags |= KEPT; else cond->flags |= SKIP; break; case 'e': if (!(cond->flags & IF)) { error(2, "no matching i for e"); goto done; } if (!*s) { if (cond->flags & ELSE) { error(2, "i block already has a default e"); goto done; } cond->flags |= ELSE; if (cond->flags & KEPT) cond->flags |= SKIP; else { cond->flags |= KEPT; cond->flags &= ~SKIP; } } else if ((cond->flags & KEPT) || !match(s, cond->text, 0)) cond->flags |= SKIP; else cond->flags |= KEPT; break; case 'f': if (!(cond->flags & IF)) { error(2, "no matching i for f"); goto done; } cond = cond->prev; break; case 'm': if (cond->flags & SKIP) continue; if (sfputr(sfstderr, s, '\n') < 0 || sfsync(sfstderr)) { error(ERROR_SYSTEM|2, "standard error write failed"); goto done; } break; case 'p': if (cond->flags & SKIP) continue; if (!(m = masterline(mp, lp, s, 1, timeout, master))) goto done; break; case 'r': if (cond->flags & SKIP) continue; if (!(m = masterline(mp, lp, 0, s[0] == '?' && s[1] == '.' ? -1 : 1, timeout, master))) goto done; match(s, m, 1); break; case 's': n = (int)strtol(s, &e, 0); if (*e) error(2, "%s: invalid delay -- milliseconds expected", s); if (n) usleep((unsigned long)n * 1000); break; case 't': timeout = (int)strtol(s, &e, 0); if (*e) error(2, "%s: invalid timeout -- milliseconds expected", s); break; case 'u': if (cond->flags & SKIP) continue; do { if (!(m = masterline(mp, lp, 0, -1, timeout, master))) { match(s, m, 1); goto done; } } while (!match(s, m, 0)); break; case 'v': error_info.trace = -(int)strtol(s, &e, 0); if (*e) error(2, "%s: invalid verbose level -- number expected", s); break; case 'x': status = (int)strtol(s, &e, 0); if (*e) error(2, "%s: invalid exit code", s); break; case 'I': if (master->ignore) { free(master->ignore); master->ignore = 0; } if (*s && !(master->ignore = strdup(s))) outofmemory(); break; case 'L': if (error_info.id) { free(error_info.id); error_info.id = 0; } if (*s && !(error_info.id = strdup(s))) outofmemory(); break; case 'P': if (master->prompt) { free(master->prompt); master->prompt = 0; } if (*s && !(master->prompt = strdup(s))) outofmemory(); break; default: if (cond->flags & SKIP) continue; error(2, "'%c': unknown op", op); goto done; } } if (cond->prev) error(2, "missing 1 or more f statements"); done: if (mp) sfclose(mp); error_info.id = id; error_info.line = line; return status ? status : error_info.errors != 0; } typedef struct Argv_s { char** argv; char* args; int argc; } Argv_t; int b_pty(int argc, char** argv, Shbltin_t* context) { int master; int minion; int fd; int drop; int n; char* s; Proc_t* proc; Sfio_t* mp; Sfio_t* lp; Argv_t* ap; char buf[64]; int delay = 0; char* log = 0; char* messages = 0; char* stty = 0; int session = 1; int timeout = 1000; int (*fun)(Sfio_t*,Sfio_t*,int,int) = process; cmdinit(argc, argv, context, ERROR_CATALOG, 0); for (;;) { switch (optget(argv, usage)) { case 'd': if (opt_info.num) fun = dialogue; continue; case 'D': error_info.trace = -(int)opt_info.num; continue; case 'l': log = opt_info.arg; /* FALLTHROUGH */ case 'm': messages = opt_info.arg; continue; case 's': session = !!opt_info.num; continue; case 't': timeout = (int)opt_info.num; continue; case 'T': stty = opt_info.arg; continue; case 'w': delay = (int)opt_info.num; continue; case ':': break; case '?': error(ERROR_usage(2), "%s", opt_info.arg); UNREACHABLE(); } break; } argv += opt_info.index; if (!argv[0]) { error(ERROR_exit(1), "command must be specified"); UNREACHABLE(); } if (mkpty(&master, &minion) < 0) { error(ERROR_system(1), "unable to create pty"); UNREACHABLE(); } if (!(mp = sfnew(NULL, 0, SFIO_UNBOUND, master, SFIO_READ|SFIO_WRITE))) { error(ERROR_system(1), "cannot open master stream"); UNREACHABLE(); } if (stty) { n = 2; for (s = stty; *s; s++) if (isspace(*s)) n++; if (!(ap = newof(0, Argv_t, 1, (n + 2) * sizeof(char*) + (s - stty + 1)))) outofmemory(); ap->argc = n + 1; ap->argv = (char**)(ap + 1); ap->args = (char*)(ap->argv + n + 2); strcpy(ap->args, stty); ap->argv[0] = "stty"; sfsprintf(ap->argv[1] = buf, sizeof(buf), "--fd=%d", minion); ap->argv[2] = s = ap->args; for (n = 2; *s; s++) if (isspace(*s)) { *s = 0; ap->argv[++n] = s + 1; } ap->argv[n + 1] = 0; b_stty(ap->argc, ap->argv, 0); } if (!log) lp = 0; else if (!(lp = sfopen(NULL, log, "w"))) { error(ERROR_system(1), "%s: cannot write", log); UNREACHABLE(); } if (!(proc = runcmd(argv, minion, session))) { error(ERROR_system(1), "unable run %s", argv[0]); UNREACHABLE(); } close(minion); if (messages) { drop = 1; if (strneq(messages, "/dev/fd/", 8)) fd = atoi(messages + 8); else if (streq(messages, "/dev/stdout")) fd = 1; else if ((fd = open(messages, O_CREAT|O_WRONLY, MODE_666)) >= 0) drop = 0; else { error(ERROR_system(1), "%s: cannot redirect messages", messages); UNREACHABLE(); } close(2); dup(fd); if (drop) close(fd); } minion = (*fun)(mp, lp, delay, timeout); master = procclose(proc); if (lp && sfclose(lp)) { error(ERROR_system(1), "%s: write error", log); UNREACHABLE(); } return minion ? minion : master; } ksh-1.0.10/src/cmd/ksh93/000077500000000000000000000000001465301102200146435ustar00rootroot00000000000000ksh-1.0.10/src/cmd/ksh93/COMPATIBILITY000066400000000000000000000405141465301102200166030ustar00rootroot00000000000000 ksh 93u+m/1.0.9 vs. ksh 93u+ The following is a list of changes between ksh 93u+ 2012-08-01 and the new ksh 93u+m reboot that could cause incompatibilities in rare corner cases. Fixes of clear bugs in ksh 93u+ are not included here, even though any bugfix could potentially cause an incompatibility in a script that relies on the bug. For more details, see the NEWS file and for complete details, see the git log. 0. A new '-o posix' shell option has been added to ksh 93u+m that makes the ksh language more compatible with other shells by following the POSIX standard more closely. See the manual page for details. It is enabled by default if ksh is invoked as sh. 1. Bytecode compiled by shcomp 93u+m will not run on older ksh versions. (However, bytecode compiled by older shcomp will run on ksh 93u+m.) 2. Pathname expansion (a.k.a. filename generation, a.k.a. globbing) now never matches the special navigational names '.' (current directory) and '..' (parent directory). This change makes a pattern like .* useful; it now matches all hidden 'dotfiles' in the current directory. 3. The bash-style &>foo redirection operator (shorthand for >foo 2>&1) can now always be used if -o posix is off, and not only in profile scripts. 4. Redirections that store a file descriptor > 9 in a variable, such as {var}>file, now continue to work if brace expansion is turned off. 5. Most predefined aliases have been converted to regular built-in commands that work the same way. 'unalias' no longer removes these. To remove a built-in command, use 'builtin -d'. The 'history' and 'r' predefined aliases remain, but are now only set on interactive shells. There are some minor changes in behavior in some former aliases: - 'redirect' now checks if all arguments are valid redirections before performing them. If an error occurs, it issues an error message instead of terminating the shell. - 'suspend' now refuses to suspend a login shell, as there is probably no parent shell to return to and the login session would freeze. If you really want to suspend a login shell, use 'kill -s STOP $$'. - 'times' now gives high precision output in a POSIX compliant format. 6. 'command' and 'nohup' no longer expand aliases in their first argument, as this is no longer required after the foregoing change. In the unlikely event that you still need this behavior, you can set: alias command='command ' alias nohup='nohup ' 7. The 'login' and 'newgrp' special built-in commands have been removed, so it is no longer an error to define shell functions by these names. These built-ins replaced your shell session with the external commands by the same name, as in 'exec'. If an error occurred (e.g. due to a typo), you would end up immediately logged out, except on a few commercial Unix systems whose 'login' and 'newgrp' cope with this by starting a new shell session upon error. If you do want the old behavior, you can restore it by setting: alias login='exec login' alias newgrp='exec newgrp' 8. 'case' no longer retries to match patterns as literal strings if they fail to match as patterns. This undocumented behaviour broke validation use cases that are expected to work. For example: n='[0-9]' case $n in [0-9]) echo "$n is a digit" ;; esac would output "[0-9] is a digit". In the unlikely event that a script does rely on this behavior, it can be fixed like this: case $n in [0-9] | "[0-9]") echo "$n is a digit or the digit pattern" ;; esac 9. If 'set -u'/'set -o nounset' is active, then the shell now errors out if a nonexistent positional parameter such as $1, $2, ... is accessed. (This does *not* apply to "$@" and "$*".) 10. If 'set -u'/'set -o nounset' is active, then the shell now errors out if $! is accessed before the shell has launched any background process. 11. The 'print', 'printf' and 'echo' built-in commands now return a nonzero exit status if an input/output error occurs. 12. Four obsolete date format specifiers for 'printf %(format)T' were changed to make them compatible with modern date(1) commands: - %k and %l now return a blank-padded hour (24-hour and 12-hour clock). - %f now returns a date with the format '%Y.%m.%d-%H:%M:%S'. - %q now returns the quarter of the current year. 13. The 'typeset' built-in now properly detects and reports options that cannot be used together if they are given as part of the same command. 14. The DEBUG trap has reverted to pre-93t behavior. It is now once again reset like other traps upon entering a subshell or ksh-style function, as documented, and it is no longer prone to crash or get corrupted. A new --functrace shell option has been added that, when turned on, makes subshells and functions correctly inherit the DEBUG trap. 15. 'command -x' now always runs an external command, bypassing built-ins. 16. Unbalanced quotes and backticks now correctly produce a syntax error in -c scripts, 'eval', and backtick-style command substitutions. 17. -G/--globstar: Symbolic links to directories are now followed if they match a normal (non-**) glob pattern. For example, if '/lnk' is a symlink to a directory, '/lnk/**' and '/l?k/**' now work as expected. 18. The variable name search expansions ${!prefix@} and ${!prefix*} now also include the variable 'prefix' itself in the possible results. 19. [[ -v var ]] is now properly equivalent to [[ -n ${var+set} ]]. Undocumented special-casing for numeric types has been removed. For example, the following no longer produces an unexpected error: $ ksh -o nounset -c 'float n; [[ -v n ]] && echo $n' 20. If the HOME variable is unset, the bare tilde ~ now expands to the current user's system home directory instead of merely the username. 21. On Windows/Cygwin, globbing is no longer case-insensitive by default. Turning on the new --globcasedetect shell option restores case-insensitive globbing for case-insensitive file systems. 22. If $PWD or $OLDPWD are passed as invocation-local assignments to cd, their values are no longer altered in the outer scope when cd finishes. For example: ksh -c 'OLDPWD=/bin; OLDPWD=/tmp cd - > /dev/null; echo $OLDPWD' ksh -c 'cd /var; PWD=/tmp cd /usr; echo $PWD' now prints '/bin' followed by '/var'. 23. Path-bound built-ins (such as /opt/ast/bin/cat) can now be executed by invoking the canonical path, so the following will now work: $ /opt/ast/bin/cat --version version cat (AT&T Research) 2012-05-31 $ (PATH=/opt/ast/bin:$PATH; "$(whence -p cat)" --version) version cat (AT&T Research) 2012-05-31 In the event an external command by that path exists, the path-bound built-in will now override it when invoked using the canonical path. To invoke a possible external command at that path, you can still use a non-canonical path, e.g.: /opt//ast/bin/cat or /opt/ast/./bin/cat 24. The readonly attribute of ksh variables is no longer imported from or exported to other ksh shell instances through the environment. 25. Subshells (even if non-forked) now keep a properly separated state of the pseudorandom generator used for $RANDOM, so that using $RANDOM in a non-forked subshell no longer influences a reproducible $RANDOM sequence in the parent environment. In addition, upon invoking a subshell, $RANDOM is now reseeded (as mksh and bash do). 26. The built-in arithmetic function int() has changed to round towards zero instead of negative infinity. Previously, int() was an alias to floor(), but now it behaves like trunc(). 27. The '!' logical negation operator in the '[[' compound command now correctly negates another '!', e.g., [[ ! ! 1 -eq 1 ]] now returns 0/true. Note that this has always been the case for 'test'/'['. 28. By default, arithmetic expressions in ksh no longer interpret a number with a leading zero as octal in any context. Use 8#octalnumber instead. Before, ksh would arbitrarily recognize the leading octal zero in some contexts but not others. One of several examples is: x=010; echo "$((x)), $(($x))" would output '10, 8'. This now outputs '10, 10'. Arithmetic expressions now also behave identically within and outside ((...)) and $((...)). Setting the --posix compliance option turns on the recognition of the leading octal zero for all arithmetic contexts. 29. It is now an error for arithmetic expressions to assign an out-of-range index value to a variable of an enumeration type created with 'enum'. 30. For the 'return' built-in command, you can now freely specify any return value that fits in a signed integer, typically a 32-bit value. Note that $? is truncated to 8 bits when the current (sub)shell exits. 31. The 'enum' and 'typeset -T' commands are no longer allowed to override and replace special built-in commands, except for type definition commands previously created by these commands. 32. The .sh.level variable is now read-only except inside a DEBUG trap. The current level/scope is now restored when the DEBUG trap run ends. 33. The -e option of test/[/[[ no longer returns true for pseudodevices that are only supported by the shell and do not in fact exist in the file system, such as /dev/tcp/*. (Post-1.0 fix introduced in ksh 93u+m/1.0.4) 34. Single and double quotes now work like backslashes to quote '!', '^' and '-' in bracket expressions in shell glob patterns, e.g., the glob pattern ["!a-z"] now matches !, a, - or z and is no longer misparsed as [!a-z]. This restores compatibility with ksh88 and non-ksh shells. (Post-1.0 fix introduced in ksh 93u+m/1.0.4) 35. In the ${parameter/pattern/string} search-and-replace expansion, an anchored empty pattern will now match the beginning or the end of the string, so that ${parameter/#/string} will prefix the string to the parameter value and ${parameter/%/string} will append it. Previously, these operations were no-ops (equivalent to ${parameter}). (Post-1.0 fix introduced in ksh 93u+m/1.0.5) 36. An assignment within an arithmetic expression no longer triggers both of the variable's 'set' and 'get' discipline functions (if set). Only the 'set' discipline is now triggered, as it was always documented. (Post-1.0 fix introduced in ksh 93u+m/1.0.9) 37. Non-base-10 signed negative integer values are now output as negative numbers and no longer incorrectly treated as unsigned long integers regardless of their type length. For example, 'typeset -i16 n=-12; echo $n' now correctly prints -16#c instead of 16#fffffffffffffff4. (Post-1.0 fix introduced in ksh 93u+m/1.0.9) ____________________________________________________________________________ KSH-93 VS. KSH-88 (Written by David Korn for ksh 93u+ 2012-08-01) The following is a list of known incompatibilities between ksh-93 and ksh-88. I have not included cases that are clearly bugs in ksh-88. I also have omitted features that are completely upward compatible. 1. Functions, defined with name() with ksh-93 are compatible with the POSIX standard, not with ksh-88. No local variables are permitted, and there is no separate scope. Functions defined with the function name syntax have local variables as in ksh-88, but are statically scoped as in C so that a function does not automatically have access to local variables of the caller. This change also affects function traces. 2. ! is now a reserved word. As a result, any command by that name will no longer work with ksh-93. 3. The -x attribute of alias and typeset -f is no longer effective and the ENV file is only read for interactive shells. You need to use FPATH to make function definitions visible to scripts. 4. A built-in command named command has been added which is always found before the PATH search. Any script which uses this name as the name of a command (or function) will not be compatible. 5. The output format for some built-ins has changed. In particular the output format for set, typeset and alias now have single quotes around values that have special characters. The output for trap without arguments has a format that can be used as input. 6. With ksh-88, a dollar sign ($') followed by a single quote was interpreted literally. Now it is an ANSI C string. You must quote the dollar sign to get the previous behavior. Also, a $ in front of a " indicates that the string needs to be translated for locales other than C or POSIX. The $ is ignored in the C and POSIX locale. 7. With ksh-88, tilde expansion did not take place inside ${...}. with ksh-93, ${foo-~} will cause tilde expansion if foo is not set. You need to escape the ~ for the previous behavior. 8. Some changes in the tokenizing rules were made that might cause some scripts with previously ambiguous use of quoting to produce syntax errors. 9. Programs that rely on specific exit values for the shell, (rather than 0 or non-zero) may not be compatible. The exit status for many shell failures has been changed. 10. Built-ins in ksh-88 were always executed before looking for the command in the PATH variable. This is no longer true. Thus, with ksh-93, if you have the current directory first in your PATH, and you have a program named test in your directory, it will be executed when you type test; the built-in version will be run at the point /bin is found in your PATH. 11. Some undocumented combinations of argument passing to ksh builtins no longer works since ksh-93 is getopts conforming with respect to its built-ins. For example, typeset -8i previously would work as a synonym for typeset -i8. 12. Command substitution and arithmetic expansion are now performed on PS1, PS3, and ENV when they are expanded. Thus, ` and $( as part of the value of these variables must be preceded by a \ to preserve their previous behavior. 13. The ERRNO variable has been dropped. 14. If the file name following a redirection symbol contain pattern characters they will only be expanded for interactive shells. 15. The arguments to a dot script will be restored when it completes. 16. The list of tracked aliases is not displayed with alias unless the -t option is specified. 17. The POSIX standard requires that test "$arg" have exit status of 0, if and only if $arg is null. However, since this breaks programs that use test -t, ksh-93 treats an explicit test -t as if the user had entered test -t 1. 18. The ^T directive of emacs mode has been changed to work the way it does in gnu-emacs. 19. ksh-88 allowed unbalanced parentheses within ${name op val} whereas ksh-93 does not. Thus, ${foo-(} needs to be written as ${foo-\(} which works with both versions. [2021 UPDATE: This is now once again allowed in ksh 93u+m. Note that balanced parentheses ${foo-()} were also broken and are now fixed.] 20. kill -l in ksh-93 lists only the signal names, not their numerical values. 21. Local variables defined by typeset are statically scoped in ksh-93. In ksh-88 they were dynamically scoped although this behavior was never documented. 22. The value of the variable given to getopts is set to ? when the end-of-options is reached to conform to the POSIX standard. 23. Since the POSIX standard requires that octal constants be recognized, doing arithmetic on typeset -Z variables can yield different results that with ksh-88. Most of these differences were eliminated in ksh-93o. Starting in ksh-93u+, the let command no longer recognizes octal constants starting with 0 for compatibility with ksh-88 unless the option letoctal is on. 24. Starting after ksh-93l, If you run ksh name, where name does not contain a /, the current directory will be searched before doing a path search on name as required by the POSIX shell standard. 25. In ksh-93, cd - will output the directory that it changes to on standard output as required by X/Open. With ksh-88, this only happened for interactive shells. 26. As an undocumented feature of ksh-88, a leading 0 to an assignment of an integer variable caused that variable to be treated as unsigned. This behavior was removed starting in ksh-93p. 27. The getopts builtin in ksh-93 requires that optstring contain a leading + to allow options to begin with a +. 28. In emacs/gmacs mode, control-v will not display the version when the stty lnext character is set to control-v or is unset. The sequence escape control-v will display the shell version. 29. In ksh-88, DEBUG traps were executed after each command. In ksh-93 DEBUG traps are executed before each command. 30. In ksh-88, a redirection to a file name given by an empty string was ignored. In ksh-93, this is an error. I am interested in expanding this list so please let me know if you uncover any others. ksh-1.0.10/src/cmd/ksh93/DESIGN000066400000000000000000000160521465301102200155430ustar00rootroot00000000000000Here is an overview of the source code organization for ksh93. Directory layout: The directory include contains header files for ksh93. The files nval.h and shell.h are intended to be public headers and can be used to add runtime builtin command. The remainder are private. The directory data contains readonly data files for ksh93. The man pages for built-ins are in builtins.c rather than included as statics with the implementations in the bltins directory because some systems don't make static const data readonly and we want these to be shared by all running shells. The directory edit contains the code for command line editing and history. The fun directory contains some shell function such as pushd, popd, and dirs. The directory features contains files that are used to generate header files in the FEATURE directory. Most of these files are in a format that is processed by iffe. The directory bltins contains code for most of the built-in commands. Additional built-in commands are part of libcmd. The directory sh contains most of the code for ksh93. The directory tests contains a number of regression tests. In most cases, when a bug gets fixed, a test is added to one of these files. The ksh regression tests can be run by invoking the shtests script in the top-level bin directory; see 'bin/shtests --man' for documentation about the options. They are also run with default options via 'bin/package tests' as part of a complete test suite run that also includes tests for the build system itself. The top level directory contains the mamake Mamfile, the ksh93 manual page (sh.1) and the nval.3 and shell.3 documentation files. The file COMPATIBILITY is a list of all known incompatibilities with previous AT&T releases. Include directory: 1. argnod.h contains the type definitions for command nodes, io nodes, argument nodes, and for positional parameters. It defines the prototypes for all the positional parameters functions. 2. builtins.h contains prototypes for builtins as well as symbolic constants that refer to the name-pairs that are associated with some of the built-ins. It also contains prototypes for many of the strings. 3. defs.h is the catch all for all definitions that don't fit elsewhere and it includes several other headers. It defines a structure that contains ksh global data, sh, and a structure that contains per function data, sh.st. 4. edit.h contains definitions that are common to both vi and emacs edit modes. 5. fault.h contains prototypes for signal related functions and trap and fault handling. 6. fcin.h contains macro and function definitions for reading from a file or string. 7. history.h contains macros and functions definitions related to history file processing. 8. jobs.h contains the definitions relating to job processing and control. 9. lexstates.h contains the states associated with lexical processing. 10. name.h contains the internal definitions related to name-value pair processing. 11. national.h contains a few I18N definitions, mostly obsolete. 12. nval.h is the public interface to the name-value pair library that is documented with nval.3. 13. path.h contains the interface for pathname processing and pathname searching. 14. shell.h is the public interface for shell functions that are documented int shell.3. 15. shlex.h contains the lexical token definitions and interfaces for lexical analysis. 16. shnodes.h contains the definition of the structures for each of the parse nodes and flags for the attributes. 17. shtable.h contains some interfaces and functions for table lookup. 18. streval.h contains the interface to the arithmetic functions. 19. terminal.h is a header file that includes the appropriate terminal include. 20. test.h contains the definitions for the test and [[ ... ]] commands. 21. timeout.h contains the define constant for the maximum shell timeout. 22. ulimit.h includes the appropriate resource header. 23. variables.h contains symbolic constants for the built-in shell variables. 24. version.h contains the version string for this release. sh directory: 1. args.c contains functions for parsing shell options and for processing positional parameters. 2. arith.c contains callback functions for the streval.c library and the interface to shell arithmetic. 3. array.c contains the code for indexed and associative arrays. 4. defs.c contains the data definitions for global symbols. 5. (removed) 6. expand.c contains code for file name expansion and pathname expansion. 7. fault.c contains code for signal processing, trap handling and termination. 8. fcin.c contains code for reading and writing a character at a time from a file or string. 9. init.c contains initialization code and callbacks for get and set functions for built-in variables. 10. io.o contains code for redirections and managing file descriptors and file streams. 11. jobs.c contains the code for job management. 12. lex.c contains the code for the lexical analyzer. 13. macro.c contains code for the $ macro expansions, including here-documents. 14. main.c contains the calls to initialization, profile processing and the main evaluation loop as well as mail processing. 15. name.c contains the name-value pair routines that are built on the hash library in libast. 16. nvdisc.c contains code related to name-value pair disciplines. 17. nvtree.c contains code for compound variables and for walking the namespace. 18. nvtype.c contains most of the code related to types that are created with typeset -T. 19. parse.c contains the code for the shell parser. 20. path.c contains the code for pathname lookup and some path functions. It also contains the code that executes commands and scripts. 21. pmain.c is just a calls sh_main() so that all of the rest of the shell can be in a shared library. 22. shcomp.c contains the main program to the shell compiler. This program parses a script and creates a file that the shell can read containing the parse tree. 23. streval.c is an C arithmetic evaluator. 24. string.c contains some string related functions. 25. subshell.c contains the code to save and restore environments so that subshells can run without creating a new process. 26. tdump.c contains the code to dump a parse tree into a file. 27. timers.c contains code for multiple event timeouts. 28. trestore contains the code for restoring the parse tree from the file created by tdump. 29. waitevent.c contains the sh_waitnotify function so that builtins can handle processing events when the shell is waiting for input or for process completion. 30. xec.c is the main shell execution loop. edit directory: 1. completion.c contains code for command and file generation and completion. 2. edit.c contains common editing and terminal code for vi and emacs. 3. emacs.c contains code for the emacs editor. 4. hexpand.c contains code for C-shell style history expansions. 5. history.c contains code for creating managing the history file. 6. vi.c contains the code for the vi editor. ksh-1.0.10/src/cmd/ksh93/Mamfile000066400000000000000000000620431465301102200161450ustar00rootroot00000000000000note * note * This build script is in an extended Make Abstract Machine (MAM) note * language. Documentation is at: src/cmd/INIT/README-mamake.md note * setv MAMAKE_STRICT 4 setv INSTALLROOT ../../.. setv CC cc setv AR %{mam_cc_AR} %{mam_cc_AR_ARFLAGS} setv mam_cc_FLAGS %{mam_cc_TARGET} %{mam_cc_DLL} %{-debug-symbols?1?%{mam_cc_DEBUG} -D_BLD_DEBUG?%{mam_cc_OPTIMIZE}?} setv CCFLAGS setv CCLDFLAGS %{-strip-symbols?1?%{mam_cc_LD_STRIP}??} setv IFFEFLAGS setv LDFLAGS setv SH_DICT \"libshell\" setv DYLIB_PRE %{mam_cc_SUFFIX_DYNAMIC?*?%{mam_cc_PREFIX_DYNAMIC}?%{mam_cc_PREFIX_SHARED}?} setv DYLIB_SUF %{mam_cc_SUFFIX_DYNAMIC-%{mam_cc_SUFFIX_SHARED}} setv DYLIB_VERSION 2.0 make install virtual note * note * Library dependencies note * bind -ldll bind -lcmd bind -last bind -lm dontcare bind -lnsl dontcare make shell.req makp %{INSTALLROOT}/bin/mkreq exec - mkreq %{CC} %{mam_cc_FLAGS} %{CCFLAGS} %{mam_cc_NOSTRICTALIASING} : %{LDFLAGS} : \ exec - shell dll cmd ast m jobs i socket nsl secdb network done note * note * Feature tests note * setv iffe_run iffe %{IFFEFLAGS} -v -c '%{CC} %{mam_cc_FLAGS} %{CCFLAGS} %{mam_cc_NOSTRICTALIASING} %{LDFLAGS}' ref -I%{INCLUDE_AST} -I%{INSTALLROOT}/include %{mam_libdll} %{mam_libcmd} %{mam_libast} %{mam_libm} %{mam_libnsl} : run make FEATURE/time make features/time prev %{INCLUDE_AST}/times.h done exec - %{iffe_run} %{<} done make FEATURE/dynamic make features/dynamic prev %{INCLUDE_AST}/dlldefs.h done exec - %{iffe_run} %{<} done loop F options externs sigfeatures locale cmds poll rlimits make FEATURE/%{F} makp features/%{F} exec - %{iffe_run} %{<} done done make FEATURE/math make features/math.sh prev %{INCLUDE_AST}/ast_float.h makp data/math.tab done exec - %{iffe_run} %{<} data/math.tab done note * note * Generate a shopt.h compile-time options header from SHOPT.sh and probe results. note * make shopt.h notrace prev FEATURE/options makp SHOPT.sh makp Mamfile note * note * the SHOPT.sh file calls the SHOPT function once for each option note * exec - writedef() exec - { exec - echo "${3:-#ifndef SHOPT_$1}" exec - echo "# define SHOPT_$1 $2" exec - echo "#endif" exec - echo exec - } exec - exec - SHOPT() exec - { exec - n=${1%%=*} # name exec - v=${1#*=} # value exec - # probe certain options if they don't have a value configured exec - case $1 in exec - 'MULTIBYTE=') exec - # by default, SHOPT_MULTIBYTE is the opposite of AST_NOMULTIBYE exec - writedef MULTIBYTE 1 '#if !defined(SHOPT_MULTIBYTE) && !AST_NOMULTIBYTE' ;; exec - 'DEVFD=') exec - # if /dev/fd/n exposes file descriptor n, make SHOPT_DEVFD use this for exec - # process substitutions instead of FIFOs, which are not as secure exec - # WARNING: do not use 'test -e' for this test (too many shells break it exec - # by failing to test for the physical existence of /dev/fd/9 in the FS) exec - ls -d /dev/fd/9 9<&0 >/dev/null 2>&1 && writedef DEVFD 1 ;; exec - 'TEST_L=') exec - # if external 'test' supports lowercase -l as equivalent to -L, enable exec - # SHOPT_TEST_L so ksh supports it for compatibility with local scripts exec - ln -s /dev/null "$EXECROOT/link$$" exec - if env test -l "$EXECROOT/link$$" && env test ! -l . exec - then writedef TEST_L 1 exec - fi 2>/dev/null exec - rm -f "$EXECROOT/link$$" ;; exec - 'PRINTF_LEGACY=') exec - # if external 'printf' allows POSIX-ignorant syntax (i.e., a format operand exec - # starting with '-' without prior '--'), enable code for backward compat exec - case $(env printf '-zut%s\n' alors 2>/dev/null) in exec - -zutalors) exec - writedef PRINTF_LEGACY 1 ;; exec - esac ;; exec - 'SYSRC=') exec - # if one of these exists, make SHOPT_SYSRC load /etc/ksh.kshrc by default exec - if test -f /etc/ksh.kshrc || test -f /etc/bash.bashrc exec - then writedef SYSRC 1 exec - fi ;; exec - # some other SHOPTs may be probed for using feature tests in features/options exec - *=?*) exec - writedef "$n" "$v" ;; exec - esac exec - echo "* SHOPT_$n = ${v:-(probe)}" >&2 # show in make.out exec - } exec - exec - exec > %{@} exec - echo '/* Generated from ksh93/SHOPT.sh by ksh93/Mamfile */' exec - echo exec - . "$PACKAGEROOT/src/cmd/ksh93/SHOPT.sh" exec - cat <<-EOF exec - #include "FEATURE/options" exec - exec - /* overrides */ exec - #if SHOPT_SCRIPTONLY exec - # undef SHOPT_ACCT exec - # undef SHOPT_AUDIT exec - # undef SHOPT_ESH exec - # undef SHOPT_HISTEXPAND exec - # undef SHOPT_SYSRC exec - # undef SHOPT_VSH exec - #endif exec - #if !_sys_acct exec - # undef SHOPT_ACCT exec - #endif exec - EOF done shopt.h note * note * ksh93 C header (*.h) dependencies note * make include/fault.h prev FEATURE/sigfeatures prev %{INCLUDE_AST}/sfio.h prev %{INCLUDE_AST}/error.h prev %{INCLUDE_AST}/sig.h done make include/history.h prev %{INCLUDE_AST}/ast.h done make include/nval.h prev %{INCLUDE_AST}/option.h prev %{INCLUDE_AST}/cdt.h prev %{INCLUDE_AST}/ast.h done make include/name.h prev include/nval.h prev %{INCLUDE_AST}/cdt.h prev %{INCLUDE_AST}/ast.h done make include/shell.h prev include/fault.h prev %{INCLUDE_AST}/stk.h prev include/history.h prev %{INCLUDE_AST}/cmd.h prev %{INCLUDE_AST}/shcmd.h prev include/nval.h prev include/name.h prev %{INCLUDE_AST}/cdt.h prev %{INCLUDE_AST}/ast.h done make include/shtable.h done make include/builtins.h prev include/shtable.h prev FEATURE/dynamic prev %{INCLUDE_AST}/option.h done make include/regress.h done make include/argnod.h done make include/defs.h prev include/regress.h prev include/shtable.h prev include/shell.h prev %{INCLUDE_AST}/endian.h prev include/name.h prev include/argnod.h prev %{INCLUDE_AST}/cdt.h prev FEATURE/externs prev %{INCLUDE_AST}/error.h prev %{INCLUDE_AST}/sfio.h prev %{INCLUDE_AST}/ast.h done make include/test.h prev include/shtable.h prev include/defs.h done make include/path.h prev include/defs.h prev include/nval.h done make include/variables.h prev FEATURE/dynamic prev %{INCLUDE_AST}/option.h prev include/nval.h done make include/shnodes.h prev include/argnod.h prev %{INCLUDE_AST}/ast.h done make include/national.h done make include/terminal.h prev %{INCLUDE_AST}/ast_tty.h done make include/edit.h prev include/national.h prev include/terminal.h prev %{INCLUDE_AST}/sig.h prev FEATURE/locale prev FEATURE/cmds done make include/io.h prev %{INCLUDE_AST}/sfio.h prev %{INCLUDE_AST}/ast.h done make include/jobs.h prev include/terminal.h prev %{INCLUDE_AST}/aso.h prev %{INCLUDE_AST}/sfio.h prev %{INCLUDE_AST}/ast.h done make include/streval.h prev %{INCLUDE_AST}/ast_float.h prev include/defs.h prev %{INCLUDE_AST}/ast.h done make include/lexstates.h prev %{INCLUDE_AST}/wctype.h prev %{INCLUDE_AST}/wchar.h prev FEATURE/locale done make include/ulimit.h prev FEATURE/rlimits prev FEATURE/time done make include/shlex.h prev include/lexstates.h prev include/shtable.h prev include/shnodes.h prev %{INCLUDE_AST}/cdt.h done make include/fcin.h prev %{INCLUDE_AST}/sfio.h done make include/version.h prev %{INCLUDE_AST}/releaseflags.h done make include/timeout.h done note * note * ksh93 C source (*.c) dependencies note * make sh/pmain.c prev FEATURE/externs prev include/shell.h prev shopt.h done make bltins/cd_pwd.c prev include/test.h prev %{INCLUDE_AST}/ls.h prev include/builtins.h prev include/name.h prev include/path.h prev include/variables.h prev %{INCLUDE_AST}/error.h prev include/defs.h prev shopt.h done make bltins/cflow.c prev include/builtins.h prev include/shnodes.h prev %{INCLUDE_AST}/error.h prev %{INCLUDE_AST}/ast.h prev include/defs.h prev shopt.h done make bltins/enum.c prev include/defs.h prev shopt.h done make bltins/getopts.c prev include/builtins.h prev include/nval.h prev %{INCLUDE_AST}/error.h prev include/variables.h prev include/defs.h prev shopt.h done make bltins/hist.c prev include/edit.h prev include/builtins.h prev include/history.h prev include/name.h prev include/io.h prev include/variables.h prev %{INCLUDE_AST}/error.h prev %{INCLUDE_AST}/ls.h prev include/defs.h prev shopt.h done make bltins/misc.c prev %{INCLUDE_AST}/times.h prev FEATURE/time prev FEATURE/locale prev include/jobs.h prev include/builtins.h prev include/history.h prev include/name.h prev include/io.h prev include/path.h prev include/shnodes.h prev include/variables.h prev include/defs.h prev shopt.h done make bltins/mkservice.c prev %{INCLUDE_AST}/cmd.h prev %{INCLUDE_AST}/error.h prev include/nval.h prev include/defs.h prev shopt.h done make bltins/print.c prev %{INCLUDE_AST}/ccode.h prev %{INCLUDE_AST}/tmx.h prev include/streval.h prev include/builtins.h prev include/history.h prev include/name.h prev include/io.h prev %{INCLUDE_AST}/error.h prev include/defs.h prev shopt.h done make bltins/read.c prev include/edit.h prev include/terminal.h prev include/history.h prev include/builtins.h prev include/name.h prev include/io.h prev include/lexstates.h prev include/variables.h prev include/defs.h prev %{INCLUDE_AST}/error.h prev %{INCLUDE_AST}/ast.h prev shopt.h done make bltins/sleep.c prev FEATURE/poll prev FEATURE/time prev include/builtins.h prev %{INCLUDE_AST}/tmx.h prev %{INCLUDE_AST}/error.h prev include/defs.h prev shopt.h done make bltins/trap.c prev include/builtins.h prev include/jobs.h prev include/defs.h prev shopt.h done make bltins/test.c prev %{INCLUDE_AST}/tmx.h prev FEATURE/poll prev FEATURE/externs prev include/builtins.h prev include/test.h prev include/terminal.h prev include/io.h prev %{INCLUDE_AST}/regex.h prev %{INCLUDE_AST}/ls.h prev %{INCLUDE_AST}/error.h prev include/defs.h prev shopt.h done make bltins/typeset.c prev FEATURE/dynamic prev include/variables.h prev include/builtins.h prev include/history.h prev include/name.h prev include/path.h prev %{INCLUDE_AST}/error.h prev include/defs.h prev shopt.h done make bltins/ulimit.c prev include/ulimit.h prev include/name.h prev include/builtins.h prev include/defs.h prev %{INCLUDE_AST}/error.h prev %{INCLUDE_AST}/sfio.h prev %{INCLUDE_AST}/ast.h prev shopt.h done make bltins/umask.c prev include/builtins.h prev include/shell.h prev %{INCLUDE_AST}/ls.h prev %{INCLUDE_AST}/error.h prev %{INCLUDE_AST}/sfio.h prev %{INCLUDE_AST}/ast.h prev shopt.h done make bltins/whence.c prev include/builtins.h prev include/shlex.h prev include/path.h prev include/name.h prev include/shtable.h prev %{INCLUDE_AST}/error.h prev include/defs.h prev shopt.h done make sh/main.c prev FEATURE/externs prev FEATURE/time prev include/timeout.h prev include/history.h prev include/shnodes.h prev include/shlex.h prev include/jobs.h prev include/io.h prev include/path.h prev include/variables.h prev include/defs.h prev include/fcin.h prev %{INCLUDE_AST}/ls.h prev %{INCLUDE_AST}/sfio.h prev %{INCLUDE_AST}/ast.h prev shopt.h done make sh/nvdisc.c prev include/shlex.h prev include/io.h prev include/path.h prev include/builtins.h prev include/variables.h prev include/defs.h prev shopt.h done make sh/nvtype.c prev include/builtins.h prev include/variables.h prev include/io.h prev include/defs.h prev shopt.h done make sh/arith.c prev include/builtins.h prev include/variables.h prev include/streval.h prev include/name.h prev include/lexstates.h prev include/defs.h prev shopt.h done make sh/args.c prev include/io.h prev include/shlex.h prev FEATURE/poll prev include/edit.h prev include/terminal.h prev include/builtins.h prev include/jobs.h prev include/path.h prev include/defs.h prev shopt.h done make sh/array.c prev include/name.h prev include/defs.h prev shopt.h done make edit/completion.c prev include/history.h prev include/edit.h prev include/io.h prev include/path.h prev include/lexstates.h prev %{INCLUDE_AST}/ast_wchar.h prev include/defs.h prev shopt.h done make sh/defs.c prev include/timeout.h prev include/edit.h prev include/shlex.h prev include/jobs.h prev include/defs.h prev shopt.h done make edit/edit.c prev include/shlex.h prev include/edit.h prev include/history.h prev include/terminal.h prev include/io.h prev include/variables.h prev include/defs.h prev %{INCLUDE_AST}/ls.h prev FEATURE/time prev include/fault.h prev %{INCLUDE_AST}/ccode.h prev %{INCLUDE_AST}/ast.h prev shopt.h done make sh/expand.c prev include/path.h prev include/io.h prev %{INCLUDE_AST}/ast_dir.h prev %{INCLUDE_AST}/ls.h prev %{INCLUDE_AST}/glob.h prev %{INCLUDE_AST}/ast.h prev include/test.h prev include/variables.h prev include/defs.h prev shopt.h done make bltins/regress.c prev %{INCLUDE_AST}/tmx.h prev include/builtins.h prev include/io.h prev %{INCLUDE_AST}/ls.h prev %{INCLUDE_AST}/error.h prev include/defs.h prev shopt.h done make sh/fault.c prev include/ulimit.h prev include/builtins.h prev include/path.h prev include/jobs.h prev include/variables.h prev include/shlex.h prev include/history.h prev include/io.h prev include/fcin.h prev include/defs.h prev shopt.h done make sh/fcin.c prev include/fcin.h prev %{INCLUDE_AST}/error.h prev %{INCLUDE_AST}/sfio.h prev %{INCLUDE_AST}/ast.h prev shopt.h done make edit/history.c prev %{INCLUDE_AST}/stdio.h prev include/history.h prev include/io.h prev include/builtins.h prev include/path.h prev include/variables.h prev include/defs.h prev %{INCLUDE_AST}/ls.h prev %{INCLUDE_AST}/error.h prev FEATURE/time prev %{INCLUDE_AST}/sfio.h prev %{INCLUDE_AST}/ast.h prev shopt.h done make sh/init.c prev %{INCLUDE_AST}/wctype.h prev %{INCLUDE_AST}/ast_wchar.h prev include/version.h prev include/lexstates.h prev FEATURE/externs prev FEATURE/dynamic prev FEATURE/time prev include/builtins.h prev include/shlex.h prev include/io.h prev include/jobs.h prev include/edit.h prev include/name.h prev include/fault.h prev include/path.h prev include/variables.h prev %{INCLUDE_AST}/regex.h prev %{INCLUDE_AST}/tmx.h prev %{INCLUDE_AST}/ccode.h prev include/defs.h prev shopt.h done make sh/io.c prev %{INCLUDE_AST}/endian.h prev FEATURE/poll prev FEATURE/dynamic prev FEATURE/externs prev include/timeout.h prev include/edit.h prev include/history.h prev include/shnodes.h prev include/shlex.h prev include/jobs.h prev include/io.h prev include/path.h prev include/variables.h prev %{INCLUDE_AST}/regex.h prev %{INCLUDE_AST}/ls.h prev include/fcin.h prev include/defs.h prev shopt.h done make sh/jobs.c prev include/history.h prev include/jobs.h prev include/io.h prev %{INCLUDE_AST}/wait.h prev include/defs.h prev shopt.h done make sh/lex.c prev include/shlex.h prev include/io.h prev include/lexstates.h prev include/test.h prev include/argnod.h prev include/shell.h prev include/defs.h prev include/nval.h prev include/fcin.h prev %{INCLUDE_AST}/releaseflags.h prev %{INCLUDE_AST}/ast.h prev shopt.h done make sh/macro.c prev include/streval.h prev include/national.h prev include/path.h prev include/shnodes.h prev include/jobs.h prev include/io.h prev include/shlex.h prev include/variables.h prev include/name.h prev %{INCLUDE_AST}/regex.h prev include/fcin.h prev include/defs.h prev shopt.h done make sh/name.c prev include/builtins.h prev include/shnodes.h prev include/streval.h prev FEATURE/externs prev include/timeout.h prev include/lexstates.h prev include/path.h prev include/variables.h prev include/defs.h prev shopt.h done make sh/nvtree.c prev include/lexstates.h prev include/argnod.h prev include/name.h prev include/defs.h prev shopt.h done make sh/parse.c prev include/path.h prev include/test.h prev include/builtins.h prev include/history.h prev include/shlex.h prev %{INCLUDE_AST}/error.h prev include/fcin.h prev include/shell.h prev include/defs.h prev include/version.h prev shopt.h done make sh/path.c prev FEATURE/time prev %{INCLUDE_AST}/endian.h prev FEATURE/dynamic prev include/test.h prev include/history.h prev include/jobs.h prev include/io.h prev include/path.h prev include/variables.h prev include/nval.h prev %{INCLUDE_AST}/ls.h prev include/fcin.h prev include/defs.h prev shopt.h done make sh/string.c prev %{INCLUDE_AST}/wctype.h prev include/national.h prev include/lexstates.h prev include/shtable.h prev %{INCLUDE_AST}/ccode.h prev include/defs.h prev %{INCLUDE_AST}/lc.h prev %{INCLUDE_AST}/ast_wchar.h prev %{INCLUDE_AST}/ast.h prev shopt.h done make sh/streval.c prev FEATURE/externs prev %{INCLUDE_AST}/error.h prev include/streval.h prev shopt.h done make sh/subshell.c prev include/path.h prev include/variables.h prev include/jobs.h prev include/shlex.h prev include/shnodes.h prev include/fault.h prev include/io.h prev %{INCLUDE_AST}/ls.h prev include/defs.h prev shopt.h done make sh/tdump.c prev %{INCLUDE_AST}/ccode.h prev include/io.h prev include/path.h prev include/shnodes.h prev include/defs.h prev shopt.h done make sh/timers.c prev FEATURE/time prev FEATURE/sigfeatures prev include/defs.h prev include/fault.h prev %{INCLUDE_AST}/error.h prev %{INCLUDE_AST}/sig.h prev %{INCLUDE_AST}/ast.h prev shopt.h done make sh/trestore.c prev %{INCLUDE_AST}/ccode.h prev include/io.h prev include/path.h prev include/shnodes.h prev include/defs.h prev shopt.h done make sh/waitevent.c prev include/defs.h prev shopt.h done make sh/xec.c prev include/streval.h prev FEATURE/locale prev FEATURE/externs prev FEATURE/time prev include/builtins.h prev include/test.h prev include/jobs.h prev include/shnodes.h prev include/io.h prev include/name.h prev include/path.h prev include/variables.h prev include/fcin.h prev include/defs.h prev shopt.h done make data/limits.c prev include/ulimit.h prev %{INCLUDE_AST}/ast.h prev shopt.h done make data/msg.c prev include/edit.h prev include/jobs.h prev include/builtins.h prev include/history.h prev include/timeout.h prev include/shlex.h prev include/io.h prev include/path.h prev include/defs.h prev %{INCLUDE_AST}/ast.h prev shopt.h done make data/strdata.c prev FEATURE/math prev include/streval.h prev %{INCLUDE_AST}/ast_standards.h prev shopt.h done make data/testops.c prev include/test.h prev include/defs.h prev %{INCLUDE_AST}/ast.h prev shopt.h done make data/keywords.c prev include/shlex.h prev include/shell.h prev shopt.h done make data/options.c prev include/shtable.h prev include/name.h prev include/defs.h prev shopt.h done make data/signals.c prev include/jobs.h prev include/defs.h prev shopt.h done make data/aliases.c prev FEATURE/dynamic prev include/defs.h prev shopt.h done make data/builtins.c prev FEATURE/poll prev FEATURE/cmds prev include/jobs.h prev include/builtins.h prev include/version.h prev include/name.h prev include/ulimit.h prev include/shtable.h prev include/defs.h prev shopt.h done make data/variables.c prev include/builtins.h prev include/variables.h prev include/defs.h prev include/name.h prev include/shtable.h prev include/shell.h prev FEATURE/dynamic prev %{INCLUDE_AST}/ast.h prev shopt.h done make data/lexstates.c prev include/lexstates.h prev %{INCLUDE_AST}/ast.h prev shopt.h done make edit/emacs.c prev include/terminal.h prev include/edit.h prev include/history.h prev include/io.h prev include/defs.h prev %{INCLUDE_AST}/releaseflags.h prev %{INCLUDE_AST}/ast.h prev shopt.h done make edit/vi.c prev include/lexstates.h prev FEATURE/time prev include/terminal.h prev include/edit.h prev include/history.h prev include/io.h prev %{INCLUDE_AST}/ast.h prev include/defs.h prev shopt.h done make edit/hexpand.c prev include/edit.h prev include/defs.h prev shopt.h done make sh/shcomp.c prev include/terminal.h prev include/shnodes.h prev include/path.h prev include/defs.h prev include/shell.h prev include/version.h prev shopt.h done note * note * Set common compiler invocation arguments note * setv compile %{CC} %{mam_cc_FLAGS} %{CCFLAGS} %{mam_cc_NOSTRICTALIASING} %{DEBUG+-DDEBUG=%{DEBUG}} -DSH_DICT=%{SH_DICT} %{SH_CMDLIB_DIR+-DSH_CMDLIB_DIR=%{SH_CMDLIB_DIR}} -I. -Iinclude -I%{INCLUDE_AST} -D_API_ast=20100309 -DERROR_CONTEXT_T=Error_context_t -c note * note * Build the library note * make libshell.a loop OBJ args arith array defs expand fault fcin init io jobs lex macro main name nvdisc nvtree nvtype parse path streval string subshell tdump timers trestore waitevent xec make %{OBJ}.o prev sh/%{OBJ}.c exec - %{compile} %{<} done done loop OBJ cd_pwd cflow enum getopts hist misc mkservice print read regress sleep test trap typeset ulimit umask whence make %{OBJ}.o prev bltins/%{OBJ}.c exec - %{compile} %{<} done done loop OBJ completion edit emacs hexpand history vi make %{OBJ}.o prev edit/%{OBJ}.c exec - %{compile} %{<} done done loop OBJ aliases builtins keywords lexstates limits msg options signals strdata testops variables make %{OBJ}.o prev data/%{OBJ}.c exec - %{compile} %{<} done done note * note * Link the library note * exec - if test -f %{@} exec - then %{AR} rc %{@} %{?} # add changed *.o exec - else %{AR} rc %{@} %{^} # add all *.o exec - fi || exit exec - ranlib %{@} >/dev/null 2>&1 || true note * save for dylink setv _libshell_object_files_ %{^} done libshell.a note * note * Pre-install public headers & dependency rules early (before 'bind -lshell') note * loop DIR bin include/ast lib/lib man/man1 man/man3 fun etc make %{INSTALLROOT}/%{DIR} exec - mkdir -p %{@} done done make %{INSTALLROOT}/lib/mam/shell loop HDR nval shell history make %{INCLUDE_AST}/%{HDR}.h prev include/%{HDR}.h exec - cp -f %{<} %{@} done done note * generate header dependency rules exec - mkdeps -lshell -last -ldll -lcmd %{^} > %{@} makp %{INSTALLROOT}/bin/mkdeps prev shell.req done %{INSTALLROOT}/lib/mam/shell note * note * Set the mam_libshell variable note * bind -lshell note * note * Link binaries note * shim - link_binary() shim - { shim - %{CC} %{CCLDFLAGS} %{mam_cc_FLAGS} %{CCFLAGS} %{LDFLAGS} \ shim - -o "$@" %{mam_libshell} %{mam_libnsl} %{mam_libast} %{mam_libm} shim - } make ksh bind -lshell make pmain.o prev sh/pmain.c exec - %{compile} %{<} done exec - link_binary ksh pmain.o done ksh make shcomp bind -lshell make shcomp.o prev sh/shcomp.c exec - %{compile} %{<} done exec - link_binary shcomp shcomp.o done shcomp note * note * Dynamically linked version, if supported note * make %{INSTALLROOT}/dyn/lib/%{DYLIB_PRE}shell%{DYLIB_SUF} dontcare prev libshell.a prev shell.req exec - export LDFLAGS='%{LDFLAGS} %{CCLDFLAGS} %{mam_cc_LD_NOASNEEDED}' exec - dylink -m shell -v %{DYLIB_VERSION} -p '%{DYLIB_PRE}' -s '%{DYLIB_SUF}' $(sed 1d %{<}) %{_libshell_object_files_} done make %{INSTALLROOT}/dyn/bin/ksh dontcare prev ksh prev shell.req exec - export LDFLAGS='%{LDFLAGS} %{CCLDFLAGS} %{mam_cc_LD_NOASNEEDED} %{mam_cc_EXPORT_DYNAMIC}' exec - dylink -e ksh $(cat %{<}) %{mam_libnsl} %{mam_libm} pmain.o done make %{INSTALLROOT}/dyn/bin/shcomp dontcare prev shcomp prev shell.req exec - export LDFLAGS='%{LDFLAGS} %{CCLDFLAGS} %{mam_cc_LD_NOASNEEDED} %{mam_cc_EXPORT_DYNAMIC}' exec - dylink -e shcomp $(cat %{<}) %{mam_libnsl} %{mam_libm} shcomp.o done note * note * Pre-install the rest note * loop EXE ksh shcomp make %{INSTALLROOT}/bin/%{EXE} prev %{EXE} note * macOS throws code signature error if 'cp' overwrites Mach-O binary; must remove first exec - rm -f %{@} && cp %{<} %{@} done done make %{INSTALLROOT}/man/man1/sh.1 makp sh.1 exec - cp -f %{<} %{@} done make %{INSTALLROOT}/lib/libshell.a prev libshell.a exec - cp -f %{<} %{@} || exit exec - ranlib %{@} >/dev/null 2>&1 || true done loop MAN3PG shell nval make %{INSTALLROOT}/man/man3/%{MAN3PG}.3 makp %{MAN3PG}.3 exec - cp -f %{<} %{@} done done make %{INSTALLROOT}/lib/lib/shell prev shell.req exec - cp -f %{<} %{@} done loop FUN autocd cd dirs man mcd popd pushd make %{INSTALLROOT}/fun/%{FUN} makp fun/%{FUN} exec - cp -f %{<} %{@} && chmod ugo+x %{@} done done make %{INSTALLROOT}/etc/kshrc makp kshrc.sh exec - cp -f %{<} %{@} done done install note * note * Run regression tests. note * make test dontcare virtual prev install make test.ksh virtual makp tests/shtests exec - cd "$PACKAGEROOT/src/cmd/ksh93/tests" && ./shtests done done test ksh-1.0.10/src/cmd/ksh93/OBSOLETE000066400000000000000000000055601465301102200160100ustar00rootroot00000000000000.sp 3 .tl ''Ksh Features That Are Obsolete in Ksh93'' .sp 2 .AL 1 .LI Using a pair of grave accents \^\fB\(ga\fR ... \fB\(ga\fR\^ for command substitution. Use \fB$(\fR ... \fB)\fR instead. .LI .B FCEDIT is an obsolete name for the default editor name for the .B hist command. .B FCEDIT is not used when .B HISTEDIT is set. Use .B HISTEDIT instead. .LI The newtest (\fB[[\fR ... \fB]]\fR) operator \fB\-a\fP \fIfile\fP is obsolete. Use \fB\-e\fP instead. .LI The newtest (\fB[[\fR ... \fB]]\fR) operator .BR = , as used in \fIstring\fP \fB=\fP \fIpattern\fP is obsolete. Use \fB==\fP instead. .LI The following obsolete arithmetic comparisons are also permitted: .in +5 .VL 20 .LI "\fIexp1\fP \fB\-eq\fP \fIexp2\fP" True, if .I exp1 is equal to .IR exp2 . .LI "\fIexp1\fP \fB\-ne\fP \fIexp2\fP" True, if .I exp1 is not equal to .IR exp2 . .LI "\fIexp1\fP \fB\-lt\fP \fIexp2\fP" True, if .I exp1 is less than .IR exp2 . .LI "\fIexp1\fP \fB\-gt\fP \fIexp2\fP" True, if .I exp1 is greater than .IR exp2 . .LI "\fIexp1\fP \fB\-le\fP \fIexp2\fP" True, if .I exp1 is less than or equal to .IR exp2 . .LI "\fIexp1\fP \fB\-ge\fP \fIexp2\fP" True, if .I exp1 is greater than or equal to .IR exp2 . .LE \" End .VL .in -5 .LI Using test -t or [ -t ] without specifying the file unit number. .LI The .B \-k option to the \fBset\fR builtin is obsolete. It causes .I all\^ variable assignment arguments are placed in the environment, even if they occur after the command name. The following first prints .B "a=b c" and then .BR c : There is no alternative. .LI The obsolete .B \-xf option of the .B typeset command allows a function to be exported to scripts that are executed without a separate invocation of the shell. Functions that need to be defined across separate invocations of the shell should be placed in a directory and the .B FPATH variable should contains the name of this directory. They may also be specified in the .B ENV file with the .B \-xf option of .BR typeset . .LI The shell environment variable .B FCEDIT is obsolete. Use .B HISTEDIT instead. .LI In the .B \-s option (to \fBfc\fR or \fBhist\fR command???) ( and in obsolete versions, the editor name .B \- ) is used to skip the editing phase and to re-execute the command. .LI The .B \-t option to \fBalias\fR builtin is obsolete. It is used to set and list tracked aliases. There is no replacement. .LI The shell command line option .B \-t is obsolete. This option causes the shell to exit after reading and executing one command. There is no replacement (although ending \&"command" with the exit builtin should have the same effect). .LI As an obsolete feature of the "set" builtin, if the first .I arg\^ is .B \- then the .B \-x and .B \-v options are turned off and the next .I arg is treated as the first argument. Using .B \+ rather than .B \- causes these options to be turned off. These options can also be used upon invocation of the shell. .LE ksh-1.0.10/src/cmd/ksh93/PROMO.mm000066400000000000000000000133031465301102200160720ustar00rootroot00000000000000.H 1 ksh93 KSH-93 is the most recent version of the KornShell Language described in "The KornShell Command and Programming Language," by Morris Bolsky and David Korn of AT&T Bell Laboratories, ISBN 0-13-182700-6. The KornShell is a shell programming language, which is upward compatible with "sh" (the Bourne Shell), and is intended to conform to the IEEE P1003.2/ISO 9945.2 Shell and Utilities standard. KSH-93 provides an enhanced programming environment in addition to the major command-entry features of the BSD shell "csh". With KSH-93, medium-sized programming tasks can be performed at shell-level without a significant loss in performance. In addition, "sh" scripts can be run on KSH-93 without modification. .P The code should conform to the IEEE POSIX 1003.1 standard and to the proposed ANSI C standard so that it should be portable to all such systems. Like the previous version, KSH-88, it is designed to accept eight bit character sets transparently, thereby making it internationally compatible. It can support multi-byte characters sets with some characteristics of the character set given at run time. .P KSH-93 provides the following features, many of which were also inherent in KSH-88: .BL .LI Enhanced Command Re-entry Capability: The KSH-93 history function records commands entered at any shell level and stores them, up to a user-specified limit, even after you log off. This allows you to re-enter long commands with a few keystrokes - even those commands you entered yesterday. The history file allows for eight bit characters in commands and supports essentially unlimited size histories. .LI In-line Editing: In "sh", the only way to fix mistyped commands is to backspace or retype the line. KSH-93 allows you to edit a command line using a choice of EMACS-TC or "vi" functions. You can use the in-line editors to complete filenames as you type them. You may also use this editing feature when entering command lines from your history file. A user can capture keystrokes and rebind keys to customize the editing interface. .LI Extended I/O Capabilities: KSH-93 provides several I/O capabilities not available in "sh", including the ability to: .BL .LI specify a file descriptor for input and output .LI start up and run co-processes .LI produce a prompt at the terminal before a read .LI easily format and interpret responses to a menu .LI echo lines exactly as output without escape processing .LI format output using printf formats. .LI read and echo lines ending in "\e". .LE .LI Improved performance: KSH-93 executes many scripts faster than the System V Bourne shell. A major reason for this is that many of the standard utilities are built-in. To reduce the time to initiate a command, KSH-93 allows commands to be added as built-ins at run time on systems that support dynamic loading such as System V Release 4. .LI Arithmetic: KSH-93 allows you to do integer arithmetic in any base from two to sixty-four. You can also do double precision floating point arithmetic. Almost the complete set of C language operators are available with the same syntax and precedence. Arithmetic expressions can be used to as an argument expansion or as a separate command. In addition there is an arithmetic for command that works like the for statement in C. .LI Arrays: KSH-93 supports both indexed and associative arrays. The subscript for an indexed array is an arithmetic expression, whereas, the subscript for an associative array is a string. .LI Shell Functions and Aliases: Two mechanisms - functions and aliases - can be used to assign a user-selected identifier to an existing command or shell script. Functions allow local variables and provide scoping for exception handling. Functions can be searched for and loaded on first reference the way scripts are. .LI Substring Capabilities: KSH-93 allows you to create a substring of any given string either by specifying the starting offset and length, or by stripping off leading or trailing substrings during parameter expansion. You can also specify attributes, such as upper and lower case, field width, and justification to shell variables. .LI More pattern matching capabilities: KSH-93 allows you to specify extended regular expressions for file and string matches. .LI KSH-93 uses a hierarchical name space for variables. Compound variables can be defined and variables can be passed by reference. In addition, each variable can have one or more disciplines associated with it to intercept assignments and references. .LI Improved debugging: KSH-93 can generate line numbers on execution traces. Also, I/O redirections are now traced. There is a DEBUG trap that gets evaluated before each command so that errors can be localized. .LI Job Control: On systems that support job control, including System V Release 4, KSH-93 provides a job-control mechanism almost identical to that of the BSD "csh", version 4.1. This feature allows you to stop and restart programs, and to move programs between the foreground and the background. .LI Added security: KSH-93 can execute scripts which do not have read permission and scripts which have the setuid and/or setgid set when invoked by name, rather than as an argument to the shell. It is possible to log or control the execution of setuid and/or setgid scripts. The noclobber option prevents you from accidentally erasing a file by redirecting to an existing file. .LI KSH-93 can be extended by adding built-in commands at run time. In addition, KSH-93 can be used as a library that can be embedded into an application to allow scripting. .LE Documentation for KSH-93 consists of an "Introduction to KSH-93", "Compatibility with the Bourne Shell" and a manual page and a README file. In addition, the "New KornShell Command and Programming Language" book is available from Prentice Hall. ksh-1.0.10/src/cmd/ksh93/README000066400000000000000000000340301465301102200155230ustar00rootroot00000000000000\This directory, and its subdirectories contain the source code for ksh-93; the language described in the second edition of the book, "The KornShell Command and Programming Language," by Morris Bolsky and David Korn which is published by Prentice Hall. ksh-93 has been compiled and run on several machines with several operating systems. The end of this file contains a partial list of operating systems and machines that ksh-93 has been known to run on. Most of the source code for ksh is in the src/cmd/ksh93/sh directory. For information on what's where, see the file DESIGN. #### COMPILE-TIME OPTIONS #### The SHOPT.sh file contains several compilation options that can be set before compiling ksh. Options are of the form SHOPT_option and become #define inside the code. These options are set to their recommended value and some of these may disappear as options in future releases. A value of 0 represents off, 1 represents on, no value means probe. For options where no feature probe is available, probe is the same as off. The options have the following defaults and meanings: ACCT off Shell accounting. Noted by "L" in the version string when enabled. See README-AUDIT.md. ACCTFILE off Enable per user accounting info. See README-AUDIT.md. ALL_LIBCMD off Enables all of the available /opt/ast/bin builtin commands in src/lib/libcmd. AUDIT on For auditing specific users. Noted by "A" in the version string when enabled. See README-AUDIT.md. AUDITFILE "/etc/ksh_audit" See README-AUDIT.md. BGX on Enables background job extensions. Noted by "J" in the version string when enabled. (1) JOBMAX=n limits the number of concurrent background jobs to n; the (n+1)th background job will block until a running background job completes. (2) SIGCHLD traps are queued so that each completing background job gets its own trap; $! is set to the job PID and $? is set to the job exit status at the beginning of the trap. BRACEPAT on Brace expansion. Expands abc{d,e}f to abcdf abcef. This feature was inspired by the C shell. CMDLIB_HDR "" The header in which you can provide a custom list of libcmd commands to provide as path-bound built-ins. CMDLIB_DIR "\"/opt/ast/bin\"" The default virtual directory prefix for path-bound built-ins. The value must include double quotes. CRNL off treated as in shell grammar. DEVFD Use the more secure /dev/fd mechanism instead of FIFOs for process substitutions. On by default on OSs with /dev/fd. DYNAMIC off Dynamic loading of builtins. Requires dlopen() interface and dynamic libshell, libdll and libast libraries. ECHOPRINT off Make echo equivalent to print. EDPREDICT off Enables history pattern search menu. As you begin a line with a #, the following characters are treated as a shell pattern and cause matching lines from the history file to be displayed as a numbered list as you type. You can scroll up and down this list or you can use nTAB to make this the current line (n defaults to 1 if omitted). Experimental. Bugs: https://github.com/ksh93/ksh/issues/233 ESH on Compile with emacs command line editing. The original emacs line editor code was provided by Mike Veach at IH. FILESCAN on Allows fast reading of files using: while < file; do ...; done Each line is stored in $REPLY and fields in each line can be accessed as positional parameters. FIXEDARRAY on When using typeset, a name in the format NAME[N] creates a fixed-size array and any attempt to access a subscript N or higher is an error. Multidimensional fixed-size arrays NAME[N1][N2]... are also supported. GLOBCASEDET Adds the 'globcasedetect' shell option. When this shell option is turned on, pathname expansion (globbing) and file name listing and completion automatically become case-insensitive on file systems where the difference between upper- and lowercase is ignored for file names. This compile-time option is enabled by default on operating systems that can support case-insensitive file systems. HISTEXPAND on Enable !-style history expansion similar to csh(1). This is turned on by the -H/--histexpand shell option and can be modified using --histreedit and --histverify. KIA off Allow generation of shell cross-reference database with -R. As of 2021-05-10, no tool that can parse this database is known. If you know of any, please contact us. MULTIBYTE Multibyte character handling. This is on by default unless the flag -DAST_NOMULTIBYTE is passed to the compiler via CCFLAGS. The UTF-8 character set is fully supported. NAMESPACE on Adds a 'namespace' reserved word that allows defining name spaces. Variables and functions defined within a block like namespace ExampleSpace { commandlist; } all have their names automatically prefixed with '.ExampleSpace.' when defining or using them, creating a separate space of names unique to the block. Outside of the namespace block, they can be accessed using .ExampleSpace.function or ${.ExampleSpace.variable}. Name spaces within name spaces are also supported. MKSERVICE off Enables the 'mkservice' builtin which creates a TCP or UDP server that is implemented by shell functions, and the 'eloop' builtin which causes the shell to block waiting for events to process. Experimental and probably insecure. NOECHOE off Disable the '-e' option to the 'echo' command, unless SHOPT_ECHOPRINT is enabled. OPTIMIZE on Optimize loop invariants in 'for' and 'while' loops. PRINTF_LEGACY The printf built-in accepts a format operand that starts with '-' without the standard preceding '--' options terminator. This is for compatibility with local scripts. Enabled by default if the OS's printf(1) is POSIX-ignorant. P_SUID 0 If set, all real UIDs greater than or equal to this value will require the -p option to run the shell setuid/setgid. REGRESS off Enable the __regress__ built-in command and instrumented intercepts for testing. REMOTE off Set --rc (read profile scripts) even if ksh was invoked with standard input on a socket, i.e. as a remote shell. SCRIPTONLY off Compile out the interactive shell, resulting in a smaller ksh binary that can only run scripts. Noted by "s" in the version string when enabled. The option makes it an error to invoke ksh as an interactive shell. The command history mechanism, the fc/hist built-in, and the '-s' options to the 'read' and 'print' built-ins are also compiled out. SPAWN on Use posix_spawn(3) as combined fork/exec if job control is not active. Improves speed. STATS on Add .sh.stats compound variable. SYSRC Source /etc/ksh.kshrc on initializing an interactive shell. This is on by default if /etc/ksh.kshrc or /etc/bash.bashrc exists at compile time. TEST_L Add 'test -l' as an alias for 'test -L'. This is on by default if the OS's external 'test' command supports it. TIMEOUT off Set this to the number of seconds for timing out and exiting the shell when you don't enter a command. If non-zero, TMOUT can not be set larger than this value. VSH on Compile with vi command line editing. The original vi line editor code was provided by Pat Sullivan at CB. #### BUILDING KSH 93U+M #### To build ksh (as well as libcmd and libast libraries on which ksh depends), cd to the top directory and run: bin/package make The compiled binaries are stored in the arch directory, in a subdirectory that corresponds to your architecture. The command 'bin/package host type' outputs the name of this subdirectory. If you have trouble or want to tune the binaries, you may pass additional compiler and linker flags. It is usually best to export these as environment variables before running bin/package as they could change the name of the build subdirectory of the arch directory, so exporting them is a convenient way to keep them consistent between build and test commands. Note that this system uses CCFLAGS instead of the usual CFLAGS. An example that makes Solaris Studio cc produce a 64-bit binary: export CCFLAGS="-m64 -O" LDFLAGS="-m64" bin/package make Alternatively you can append these to the command, and they will only be used for that command. You can also specify an alternative shell in which to run the build scripts this way. For example: bin/package make SHELL=/bin/bash CCFLAGS="-O2 -I/opt/local/include" \ LDFLAGS="-L/opt/local/lib" Note: Do not add compiler flags that cause the compiler to emit terminal escape codes, such as -fdiagnostics-color=always; this will cause the build to fail as the probing code greps compiler diagnostics. If you are certain that you don't need support for UTF-8 and other multibyte character locales and really want to save some memory and CPU cycles, add '-DAST_NOMULTIBYTE' to CCFLAGS to compile out all multibyte character handling in ksh and supporting libraries. Not recommended for most users. To install, use: bin/package install DESTINATION_DIRECTORY [ COMMAND ... ] Any command from the arch directory can be installed. If no COMMAND is specified, ksh and shcomp are assumed. The DESTINATION_DIRECTORY is created if it does not exist. Commands are installed in its bin subdirectory and each command's manual page, if available, is installed in share/man. Destination directories with whitespace or shell pattern characters in their pathnames are not yet supported. For more information, run: bin/package help Many other commands in this repo self-document via the --help, --man and --html options; those that do have no separate manual page. The build should also generate shcomp, a program that will precompile a script. ksh93 is able to recognize files in this format and process them as scripts. You can use shcomp to send out scripts when you don't want to give away the original script source. #### TESTING KSH #### The tests subdirectory contains a number of regression tests for ksh. To run all these tests with the shell you just built, run the command bin/shtests For help and more options, type bin/shtests --man #### OTHER DOCUMENTATION #### The file PROMO.mm is an advertisement that extolls the virtues of ksh. The file sh.1 contains the troff (man) description of this Shell. The file nval.3 contains the troff (man) description of the name-value pair library that is needed for writing built-ins that need to access shell variables. The file sh.memo contains a draft troff (mm) memo describing ksh. The file builtins.mm is a draft troff (mm) memo describing how to write built-in commands that can be loaded at run time. The file NEWS in the top-level directory contains bug fixes and other changes made in the ksh 93u+m fork and supporting libraries. The file COMPATIBILITY contains a list of potential incompatibilities. #### TESTED SYSTEMS #### ksh 93u+m/1.0.5 has been compiled and tested on the following. An asterisk signifies minor regression test failures (one or two minor things amiss), two asterisks signify moderate regression test failures (some functionality does not work), and three asterisks signify serious failures (crashes, and/or important functionality does not work). ** DragonFly BSD 6.2.2 on x86_64 FreeBSD 12.2 on x86_64 FreeBSD 13.0 on x86_64 FreeBSD 12.2 on arm64 (thanks to hyenias for donating access to a Pi) FreeBSD 13.1 on arm64 GNU/Linux: ArchLinux 6.2.8-1 on arm64 GNU/Linux: Alpine 3.16.1 (musl C library) on x86_64 * GNU/Linux: Alpine 3.18.0 (musl C library) on arm64 GNU/Linux: CentOS 7 on x86_64 GNU/Linux: Debian 11 (bullseye) on arm64 GNU/Linux: Fedora 36 on x86_64 GNU/Linux: Gentoo 2.8 on i386 GNU/Linux: NixOS 22.11 on arm64 GNU/Linux: Slackware 14.2 on x86_64 GNU/Linux: Slackware 15.0 on i386 * GNU/Linux: Ubuntu 20.04.6 on armv7l (32-bit) GNU/Linux: Void Linux (musl C library) on x86_64 *** Haiku R1/beta3 on x86_64 ** illumos: OmniOS r151044 (gcc) on x86_64 macOS 10.14.6 (Mojave) on x86_64 macOS 12.6.3 (Monterey) on arm64 MidnightBSD 2.2.0 on x86_64 * NetBSD 9.1 on x86_64 * NetBSD 9.3 on x86_64 * OpenBSD 7.0 on x86_64 ** OpenBSD 7.0 on i386 *** QNX Neutrino 6.5.0 on i386 Solaris 10.1 (gcc) on i386 Solaris 10.1 (gcc) on x86_64 Solaris 11.4 (Solaris Studio 12.5 cc) on x86_64 *** Windows 7 using Cygwin on i386 #### REPORTING BUGS #### Please report any problems or suggestions by opening an issue at: https://github.com/ksh93/ksh Alternatively, email martijn@inlv.org (timely response *not* promised). Good luck!! The ksh 93u+m contributors https://github.com/ksh93/ksh Originally written by: David Korn dgk@research.att.com ksh-1.0.10/src/cmd/ksh93/README-AUDIT.md000066400000000000000000000221111465301102200167630ustar00rootroot00000000000000# Korn Shell 93 Auditing and Accounting # This documentation was adapted from a 2008 blog post by Finnbarr P. Murphy and was added to the ksh 93u+m distribution under the same license as ksh by permission from the author, given on 24th Jan 2021. [Original](https://blog.fpmurphy.com/2008/12/ksh93-auditing-and-accounting.html). The responsibility for any errors in this file lies with the current ksh 93u+m maintainers and not with the original author. ## Introduction ## Korn Shell 93 (ksh93) is the only UNIX or GNU/Linux shell that I am aware of that, with proper setup, supports a modicum of per-user accounting and auditing. This post attempts to explain these facilities and show you how to access and manipulate the resulting accounting and auditing records. Per-user accounting has been a feature of ksh93 since the earliest days of this shell. It is a fairly primitive facility which writes out a record for each user command that is executed. By default, it is not compiled in to the shell. An auditing facility was added in July 2008. This is somewhat more sophisticated than the accounting facility in that it is configurable and writes out a more detailed record either locally or to a remote system for each user command that is executed. This facility can be used to monitor, track, record, and audit the activities of one or more users on an system, including system administrators. As of ksh 93u+ 2012-06-12, this is compiled in to the shell by default. Both facilities only work for interactive users. To enable or disable one or both facilities, you need to modify the compile time options in `src/cmd/ksh93/SHOPT.sh` as follows. Use `0` to disable and `1` to enable (except for `SHOPT_AUDITFILE`). Then recompile the sources; see `README` for building instructions. SHOPT ACCT=1 # accounting SHOPT ACCTFILE=1 # per-user accounting info SHOPT AUDIT=1 # enable auditing per SHOPT_AUDITFILE SHOPT AUDITFILE='\"/etc/ksh_audit\"' # auditing file After you have recompiled the sources, the new ksh executable is located in the `arch/`...`/bin` subdirectory. To see what options have actually been compiled into a particular executable, just print out the shell version string. $ arch/darwin.i386-64/bin/ksh -c 'echo ${.sh.version}' Version AJLM 93u+m/1.1.0-alpha+dev 2022-01-20 $ arch/darwin.i386-64/bin/ksh -c 'echo $KSH_VERSION' Version AJLM 93u+m/1.1.0-alpha+dev 2022-01-20 The option string AJLM means that (A) auditing is supported (`SHOPT_AUDIT`), (J) one SIGCHLD trap per completed job is supported (`SHOPT_BGX`), (L) accounting is supported (`SHOPT_ACCT`), and (M) multibyte characters are supported (`SHOPT_MULTIBYTE`). ## Accounting ## After recompiling the shell to enable this facility, per-user accounting is enabled using the `SHACCT` environment variable. To turn on per-user accounting, simply set `SHACCT` to the name of the file where you wish to store the accounting records. export SHACCT="/tmp/ksh_acctfile" Here is part of the resulting file. Note that the time is stored as hexadecimal seconds since the Unix epoch (00:00:00 UTC on 1 January 1970). $ cat /tmp/ksh_acctfile echo ${.sh.version} fpm 495990d8 pwd fpm 495990da id fpm 495990dd date fpm 495990e3 exit fpm 495990e5 The following shell script can be used to access the records in this file and output them in a more useful format. #!/bin/ksh93 ACCTFILE="/tmp/ksh_acctfile" printf "DATE TIME LOGIN COMMAMD\n\n" # set IFS to TAB only while IFS=$'\t' read cmdstr name hexseconds do printf -v longsecs "%ld" "0x${hexseconds}" printf "%(%Y-%m-%d %H:%M:%S)T, %s, %s\n" "#${longsecs}" "$name" "$cmdstr" done < $ACCTFILE Invoking this script gives the following output for the above accounting records. $ ./parse_acctfile DATE TIME LOGIN COMMAMD 2008-12-29 22:09:12, fpm, echo ${.sh.version} 2008-12-29 22:09:14, fpm, pwd 2008-12-29 22:09:17, fpm, id 2008-12-29 22:09:23, fpm, date 2008-12-29 22:09:25, fpm, exit ## Auditing ## Next we turn our attention to the auditing facility. Assuming ksh has been compiled with the `SHOPT_AUDIT` option (the default), you must create an audit configuration file on each system to tell ksh93 where to store the audit records and to specify which users are to be audited. The configuration file must be readable by the users whose activities are audited. Its default location is `/etc/ksh_audit` but that can be changed in the `SHOPT.sh` file. The configuration file should contain a line that defines the file to write the audit records to, followed by the UID of each user whose commands are to generate audit records. Here is the configuration file used to generate the audit records for this part of this post. $ cat /etc/ksh_audit /tmp/ksh_auditfile;500 This configuration file specifies that audit records are to be written to `/tmp/ksh_auditfile` for the user whose UID is 500. Note that the field delimiter is a semicolon. Here are the audit records stored in `/tmp/ksh_auditfile` which match the accounting records shown previously in this post. The field separator is a semicolon. The first field is the UID of the user executing the command. The second field is the time in seconds since the Epoch. The third field is the terminal device on which the command was executed, and the final field is the actual command executed by the user. 500;1230606552;/dev/pts/2; echo ${.sh.version} 500;1230606554;/dev/pts/2; pwd 500;1230606557;/dev/pts/2; id 500;1230606563;/dev/pts/2; date 500;1230606565;/dev/pts/2; exit As before, here is a simple ksh93 script which parses this audit file, replaces the UID with the actual user's name and seconds since the Epoch with the actual date and time, and outputs the enhanced records in a comma separated value (CSV) format. #!/bin/ksh93 AUDITFILE="/tmp/ksh_auditfile" while IFS=";" read uid sec tty cmdstr do printf '%(%Y-%m-%d %H:%M:%S)T, %s, %d, %s, %s\n' \ "#$sec" "$(id -un $uid)" "$uid" "$tty" "$cmdstr" done < $AUDITFILE Here is the output for the above audit records. 2008-12-29 22:09:12, fpm, 500, /dev/pts/2, echo ${.sh.version} 2008-12-29 22:09:14, fpm, 500, /dev/pts/2, pwd 2008-12-29 22:09:17, fpm, 500, /dev/pts/2, id 2008-12-29 22:09:23, fpm, 500, /dev/pts/2, date 2008-12-29 22:09:25, fpm, 500, /dev/pts/2, exit The audit file must be writable by all users whose activities are audited, presenting an obvious security problem. However, the Korn shell supports networking using the `/dev/udp/`*host*`/`*port* or `/dev/tcp/`*host*`/`*port* syntax, so audit records can be sent across a network to another system. This mechanism could be used to store audit records on a secured centralized system to which only specific personnel have access. As an example, the following audit configuration file line designates that audit records for the user whose UID is 500 should be sent using UDP to the syslog network port (514) on a remote system whose IP is 192.168.0.99. /dev/udp/192.168.0.99/514;500 Here are the same audit records stored by the syslog daemon on the remote system. 2008-12-29 22:09:12 192,169.0.115 500;1230606552;/dev/pts/2; echo ${.sh.version} 2008-12-29 22:09:14 192.169.0.115 500;1230606554;/dev/pts/2; pwd 2008-12-29 22:09:17 192.169.0.115 500;1230606557;/dev/pts/2; id 2008-12-29 22:09:23 192.169.0.115 500;1230606563;/dev/pts/2; date 2008-12-29 22:09:25 192.169.0.115 500;1230606565;/dev/pts/2; exit Depending on the configuration of the syslog daemon on your particular system, the first part of the record may contain more or less information or be formatted differently but the final part of the record, i.e. the audit record sent by ksh93 should be in the standard audit record format. ## Afterword ## Note that while the auditing and accounting facilities within ksh93 can provide you with much useful information regarding the actions of one or more users on a system or systems, these facilities should not be regarded as providing enhanced security akin to the Trusted Computing Base (TCB). There are many ways of circumventing these facilities. For example, a knowledgeable user could switch to a different shell such as bash where their actions will not be recorded. There are a number of other ways but I will not discuss them here. Most of the information provided in this post is not documented in a single place anywhere that I can find by searching the Internet. The ksh93 man page does not mention either the accounting or auditing facilities. Even the ksh93 source code is somewhat vague. I gleaned most of this information by studying the code in [`src/cmd/ksh93/edit/history.c`](https://github.com/ksh93/ksh/blob/dev/src/cmd/ksh93/edit/history.c). *Martijn Dekker adds:* I would like to thank the author Finnbarr P. Murphy for his permission to use his ksh93-related blog posts in the ksh 93u+m distribution. As of 2022, this is still the only documentation available for the facilities described. If you find any errors or omissions, please [file an issue](https://github.com/ksh93/ksh). ksh-1.0.10/src/cmd/ksh93/RELEASE000066400000000000000000005430171465301102200156600ustar00rootroot00000000000000This file is of historical interest only. For recent changes in both ksh 93u+m and the accompanying libraries, see the file NEWS in the top-level directory. ____ 12-08-01 --- Release ksh93u+ --- 12-08-01 A bug that ignored interrupts for some builtins (e.g. cmdtst::grep) that read from stdin has been fixed. 12-08-01 A bug that interpreted "cd .foo" as "cd foo" has been fixed. 12-07-30 Added automatic restart for EINTR for ioctl, tcgetattr, and tcsetattr. 12-07-23 A scoping error with namrefs to compound associative arrays has been fixed. 12-07-20 A bug where builtin -d /path/foo deleted foo has been fixed. 12-07-18 A bug in which /dev/stdout did not work in command substitution on some systems has been fixed. 12-07-17 A bug in which the restricted option set in a subshell prevented some variables from getting restored when the subshell completed has been fixed. 12-07-09 A bug in which the directory is not restored after a subshell changes the name of the directory for subshells executed in the same process has been fixed. 12-07-09 A bug in which file descriptors created with {n}< file were not being closed has been fixed. 12-07-09 The 12-04-04 fix for cd .. was not correct causing cd /etc;cd .. to remain in /etc. This has been fixed. 12-07-02 A bug in which builtin name did now work for builtins found in a library added by builtin -f lib has been fixed. 12-07-02 A bug in the edit modes which after a directory did not refresh the input line has been fixed. 12-07-02 A bug in which an exit status > 256 corresponding to a signal was not returned by a function to indicate a signal exit has been fixed. 12-06-28 Fix ulimit -a to list (Kibytes) instead of (kbytes). 12-06-27 Fix uninitialized data reference for as first char in --vi mode. 12-06-26 The formatting of printf "%q" for multibyte locales has changed to output using \u[xxx] format for valid wide characters. 12-06-25 The size limit for read -N and read -n has been raised to INT_MAX. 12-06-22 A bug in which an exit trap set in a subshell might not be triggered when the last command was a simple executable has been fixed. 12-06-22 A bug which could cause the shell to hang when a coprocess exits while a command inside a command substitution is reading from it has been fixed. 12-06-21 +ksh new accepts for commands of the form for i; do;...;done 12-06-19 Tab completion after a / when there is only one match not completes with that match rather than generating a menu of matches. 12-06-19 A bug in which patterns containing {...} where not processed correctly inside ${var/pattern/string} has been fixed. 12-06-18 Code modified to eliminate fts_notify variable. 12-06-15 Change the .paths plugin/builtin library variable name from BUILTIN_LIB to PLUGIN_LIB to prevent new plugin_version() aware -lcmd from causing older non-plugin_version() aware ksh to dump core. 12-06-14 builtin without argument no longer lists .sh.tilde as a built-in. 12-06-12 For assignments if the form x=(foo bar), foo is only check for an alias if it is float, integer, compound, or nameref. 12-06-12 +The shell supports 64 bit i-nodes even for 32 bit binaries. 12-06-11 A bug with >; redirection systems for which vfork() was the same a fork() has been fixed. 12-06-11 A bug in path lookup that ignored buffer boundaries has been fixed. 12-06-08 typeset -a var and typeset -A var, first unset var when var is a compound variable. 12-06-08 A bug in which running shcomp on a program containing namespace could core dump has been fixed. 12-06-06 A bug in which unset of an associative array of compound variables did not completely unset the variable has been fixed. 12-06-06 A bug in which exporting left or right justified fields could lose the field width has been fixed. 12-06-06 A bug on Solaris 11 in which >; did not work for /dev/null was fixed. 12-06-05 A race condition which occurred when stopping a builtin command invoked from a subshell has been fixed. 12-06-05 A bug with appending elements to an empty indexed array has been fixed. 12-06-04 A bug in which continuing a stopped builtin could cause it to terminate has been fixed. 12-06-04 By default, builtins added at runtime will restore the current directory if they are killed or stopped. 12-06-04 A bug in handling \\ in read has been fixed. 12-05-31 Use getrlimit64/setrlimit64 on systems that support it. 12-05-31 Fix 64 bit big-endian arithmetic bug that mishandled NaN and Inf. 12-05-31 Handle ECONNRESET like EPIPE. 12-05-31 Change .paths parse to use only the last BUILTIN_LIB from the top and treat BUILTIN_LIB value as a ':' separated list of lib names. 12-05-29 Fix BUILTIN_LIB binding bug that ignored subsequent lookups. 12-05-29 shtests: --nocompile omits the compile test and --compile does only the compile test. 12-05-25 A command substitution containing a here-document that itself contains a here-document no longer hangs. 12-05-24 When the redirection operator >; is directed to a symlink, it now overwrites the file named by the link rather than the link. 12-05-21 +Added printf formats %(type)q where type can be html, url, pattern, ere, or csv. 12-05-18 A bug with appending elements to an indexed array has been fixed. 12-05-18 The exit status from getopts --man interactively was 0 instead of 2 and has been fixed. 12-05-18 Another bug with SHOPT_EDPREDICT which could cause a core dump has been fixed. 12-05-17 A bug with fixed size arrays which could cause a core dump has been fixed. 12-05-17 A bug in which the here-document <<< $(^V, the terminal was not restored to insert mode after a character is entered has been fixed. 12-04-27 A bug in which old attributes were not cleared when assigning a value using typeset has been fixed. 12-04-26 +Enabled multiline editing by default. set +o multiline can disable. 12-04-25 The 12-04-17 PATH fix created a new bug which was fixed. 12-04-25 Fixed a big memory leak problem in which unsetting compound variables did not free all the space. 12-04-25 A bug in which test ! ! ! was treated as an error has been fixed. 12-04-24 A bug with print -v for a compound variable that contained fixed arrays which prevented the output from being used again as input has been fixed. 12-04-23 +kill provides the STKFLT signal on systems that support it. 12-04-23 +The -L option was added to kill. The -L option is the same as -l except that without arguments the output format is in the form of a select menu. 12-04-23 A bug in which the exit status for an interactive shell was always 0 has been fixed. 12-04-20 Entering blank lines interactively no longer resets the exit status. 12-04-18 A bug in file completion in which the second tab completion on a file would list the completion rather than inserting the completion has been fixed. 12-04-18 A bug in which "${arr[@]:i:j}" and "${@:i:j}" generated the empty string when i was a valid subscript and j was <=0 rather than generating nothing has been fixed. 12-04-17 A bug in which read -d delim from a terminal did not respond to interrupt and did not terminate when the delimiter was entered has been fixed. 12-04-17 A bug in which a directory in PATH containing a .paths file that contains a line with FPATH=dir, where dir does not exist could cause the path search to fail has been fixed. 12-04-16 A bug in which $(trap -p) did not display traps such as ERR and DEBUG that are not associated with signals has been fixed. 12-04-11 A bug in which unsetting a variable did not unset attributes when the variable did not have a value has been fixed. 12-04-11 A bug in which read -A for an array whose index is an enumeration type, lost the enumeration type has been fixed. 12-04-10 Shared libraries loaded from a library named by a BUILTIN_LIB= found in a .paths file found in a directory on PATH now add builtins that are associated with the directory in PATH containing the .paths file. 12-04-09 Increased I/O buffer sizes for better performance. 12-04-09 A bug in which the leading 0 was stripped from $x, when $x contained a hexadecimal constant inside an arithmetic expression inside a for or while loop. 12-04-06 Modified namespaces to hand variables FPATH, PATH, and OPTIND that are defined in name spaces appropriately. This also fixed OPTIND and OPTARG processing for functions. 12-04-04 A bug in which cd .. fails when the current directory has been renamed has been fixed. 12-04-02 Made some namespace changes and added a regression test. 12-03-30 A bug with namespaces in which PATH and FPATH set in a namespace was not restored when leaving the namespace has been fixed. 12-03-29 A bug in which appending an indexed array onto an array without elements caused the first element to be 1 rather than 0 has been fixed. 12-03-29 A bug which could cause a core dump when copying a large indexed array has been fixed. 12-03-28 The shell now generates an error message when the sizes with L, Z, and R are > 32767 on 32 bit binaries instead of generating a core dump. 12-03-28 A bug in left and right justification in which the width of invalid characters was not taken as zero has been fixed. 12-03-26 A bug in which typeset -p ref, when ref is a reference to an index array element did not display the subscript has been fixed. 12-03-23 A bug in lowercase and uppercase fields when expanding ${name:=val} when name is the empty string has been fixed. 12-03-22 A namespace bug in which a type t defined in namespace foo could not be referenced outside the namespace as .foo.t has been fixed. 12-03-22 A bug in name reference scoping in which a name function called from another function is pass a name reference to a compound variable instance to be created and the compound variable is in the global scope. 12-03-22 A bug in which ${ref[@}} did not behave like ${arr[i][@]} when ref is a name reference to arr[i] has been fixed. 12-03-21 A bug in which assigning a compound variable into arr[i], where arr[i] is an array variable did not work correctly has been fixed. 12-03-21 A bug with multidimensional indexed arrays in which ${arr[i][j]} could generate a bogus error message when i was > 9 has been fixed. 12-03-21 A bug in which typeset v=foo, typeset -p v[0] generated a core dump has been fixed. 12-03-20 A bug in vi edit mode in which the sequence bar0il left the cursor on the b rather than the a has been fixed. 12-03-20 A bug which caused a core dump when defining a type with a field as ' integer -a data=([0]=0)' has been fixed. 12-03-19 Using typeset -a array when array is an associative array not generated an error message. 12-03-19 typeset +a, typeset +A, and typeset +C not displays the variables with the attributes a, A, and C respectively instead of an error. 12-03-19 A bug in which typeset -pC, typeset -pa, and typeset -pA output all variables rather than those of type C, a, or A only has been fixed. 12-03-18 A bug in which unset foo where foo is a name reference to a compound variable defined inside a function is not unset has been fixed. 12-03-18 A bug with SHOPT_EDPREDICT which could cause a core dump when the list of matches became empty has been fixed. 12-03-15 The assignment, typeset -C foo=(a b c) now generates a syntax error since a is not an assignment command. 12-03-16 A bug in which an unset discipline from a variable defined in a subshell is not invoked in the subshell has been fixed. 12-03-08 The assignment typeset -a (x=1 y=2) now creates an indexed array of two elements rather than an array of one element which is a compound variable. 12-03-02 +The vi and emacs edit modes now list all the entries in a directory when entering a for completion after a /. 12-03-02 A bug in which a program that exits with value 12 when called from a command substitution in which standard output has been redirected caused the shell to hang has been fixed. 12-03-01 A bug in which the shell could not parse [[ ']' == ~(E)[]] ]] has been fixed. 12-02-29 --- Release ksh93u+ --- 12-02-29 A bug in which ~user expanded first in a subshell prevented it from expanding later in a program has been fixed. 12-02-29 A bug which could lead to a core dump when more than four shared libraries were added with the builtin command has been fixed. 12-02-29 Fixed a few bugs which caused SIGCHLD to be blocked preventing background jobs from being reaped until a foreground job was run. 12-02-27 A bug in which sh -c for a simple command caused a fork() has been fixed. 12-02-27 A timing bug on systems such as AIX that doesn't support vfork() that could cause the exist status to get lost has been fixed. 12-02-22 A private file descriptor that was not close-on-exec for a command substitution and has been fixed. 12-02-14 A bug in which ^Z did not stop a pipeline when the last component was a shell built-in has been fixed. 12-02-14 getconf("PATH") used to initialize ed(1) path. 12-02-13 +In earlier version read from standard input would fail when called from the KEYBD trap. Now read options -N, -n, and -t should work when called from a KEYBD trap. 12-02-13 If FCEDIT is not set and fc is invoked without the -e option, ed will be invoked if found instead of /bin/ed. 12-02-10 Another bug in the saving and restoring of IFS in a subshell that caused a core dump has been fixed. 12-02-08 A bug in which .sh.fun disciplines could be cleared after a function completes has been fixed. 12-02-08 A bug in job control in which the foreground process group was not set correctly after restarting a stopped pipeline has been fixed. 12-02-07 A bug in which numbers with leading zeros could be treated as octal constants outside of ((...)) has been fixed. 12-02-06 A bug in arithmetic with compound variables containing multiple array elements has been fixed. 12-02-02 A bug in the ulimit option table was fixed. 12-01-26 A bug in which a set command that did not change monitor could affect the behavior of the monitor when monitor mode is on is fixed. 12-01-21 +You can now test whether the shell implements a math function using typeset -f .sh.math.name, where name is the name of the function. 12-01-21 A bug in which typeset -L and typeset -R did not handle multibyte characters correctly has been fixed. 12-01-20 A bug that could cause the shell to hang waiting for an incorrect job PID has been fixed. 12-01-19 A memory leak which occurred for a nested command substitution has been fixed. 12-01-17 A bug in which typeset -u PS1 could enable the uppercase attribute for some other variables, for example, HISTFILE has been fixed. 12-01-16 A bug in which .sh.match was not correct after a substring match when the replacement string contained a substring match has been fixed. 12-01-12 +Files that are sourced from profile files are now read and executed one command at a time so that alias definitions take effect as they do for profile files. 12-01-12 A bug in which whence -p would find a function if one existed and there was no command of that name on PATH. 12-01-11 Change b_* prototype (int, char**, void*) => (int, char**, Shbltin_t*). 12-01-05 A bug in which read was not terminating for a signal that had a trap set has been fixed. 12-01-01 A timing problem with >; has been fixed. 12-01-01 A macro expansion memory leak has been fixed. 11-12-26 A bug in array assignments of the form arr=( $arr[i] ...) in which arr was not unset before the assignment has been fixed. 11-12-20 A number of code changes were made based on the results of errors indicated by static code analysis. 11-12-13 In vi edit mode a literal can now be entered by preceding it with a backslash. 11-12-13 When tab is entered for completion after a ' or ", the ' and " characters are no longer deleted. 11-12-07 A bug in which a program in the current directory with a . in the name could fail to execute when both PATH and FPATH end with :. has been fixed. 11-12-07 I fixed a bug in which a variable expansion in a large here-document could be expanded to a null string. 11-12-06 An optimization to read was added in the case the read command was redirected from a file. 11-12-06 Changes were made to make the line limit for read unlimited by default. 11-12-05 A bug in which unsetting an array variable did not completely clear the variable in some cases has been fixed. 11-12-02 +The printf alternative character # when applied to the %q format will quote argument in a form suitable for a field in a .csv format file. 11-12-02 +A -S option was added to read to be able to read .csv format files. 11-11-28 A bug in which redirection of standard error in a function called from command substitution caused standard error to be lost has been fixed. 11-11-21 [[ (-n foo) ]] no longer requires a space before (. 11-11-11 The readonly attribute for a variable now applies to compound assignments to that variable. 11-11-07 Changes were made to reduce the stack size to allow deeper function recursion. 11-10-10 +Added alternate flag to printf %H for encoding of URI's. 11-10-10 A bug which could lead to a core dump when the shell was invoked with more than twenty-five open files has been fixed. 11-10-06 A bug in the scoping of name references in functions called by other functions has been fixed. 11-10-05 A bug in which wait on a PID may return the exit status of an earlier background job with that PID instead has been fixed. 11-09-22 A bug in which a read timed out with TMOUT did not always restore the terminal state has been fixed. 11-09-21 An optimization that allowed the last command in a script to use the same process ID as the script has been eliminated. 11-09-21 Added letoctal option that enables the let command to recognize octal constants starting with 0. 11-09-20 A bug in which ${var.} could cause a core dump has been fixed. 11-09-20 A bug with SHOPT_EDPREDICT when neither vi nor emacs was enabled for lines beginning with # when in a multibyte locale has been fixed. 11-09-20 A bug in emacs edit mode with SHOPT_EDPREDICT that would cause history searches matching comments lines to generate predictions has been fixed. Only user typed comment lines generate predictions. 11-09-20 A bug in emacs edit mode with a search that matches a comment line that could cause a core dump has been fixed. 11-09-16 A bug in which a command name ending in .. could cause the shell to abort has been fixed. 11-09-16 The characters ! + - % and @ in file names are no longer escaped with file name completion. 11-09-13 The let command no longer treats numbers starting with 0 as octal constants. 11-09-08 A bug in which printf "%R" could cause a core dump for invalid shell patterns has been fixed. 11-08-09 With set -u, ${var#pattern} reported that var was unset for special variables. 11-08-03 A bug in which the shell did not preserve the exit status for a coprocess has been fixed. 11-08-02 A bug in the saving and restoring of IFS in command substitution that caused a core dump has been fixed. 11-07-21 Modified the 10-08-27 bug fix so that background jobs started in for and while loops created interactively generate completion messages. 11-07-20 I fixed a bug in here documents in which multi-byte characters that crossed buffer boundaries were not processed correctly. 11-06-22 The shell compiler now supports process substitution. 11-06-22 +Added code to support process substitution on systems that do not supply the /dev/fd directory. 11-06-21 Fixed extraneous jobs Done messages when builtin is at the end of a pipeline. 11-06-20 Fixed two regression tests. 11-06-20 Fixed a bug introduced on last update. 11-06-14 A bug with pipefail in which the shell would wait for background jobs to complete has been fixed. 11-06-09 A bug which caused the options.sh regression test to fail on OS390 Linux has been fixed. The bug could also have affected other systems. 11-06-07 +A number of changes to support the still undocumented namespace option have been added. 11-06-06 A bug in which command substitution of eval would hang when it had standard error redirected to standard output has been fixed. 11-06-01 A bug in case statement fall through (;&) ignoring set -e was fixed. 11-06-01 A bug in which creating a left or right justified upper or lowercase variable with an empty string has been fixed. 11-06-01 A bug in which the .paths directory wasn't read when a subshell was executed before any other command has been fixed. 11-05-31 The shell now gives an error when a type variable is assigned to an array instance when the array has been declared a compound variable array. 11-05-31 A bug in which typeset -m of an array instance did not remove the original instance has been fixed. 11-05-28 A bug in which typeset -m dest=src fails when src and are passed as name references was fixed. 11-05-28 A bug in which typeset -m "c.board[1][i]=el", where el is a compound variable core dumps has been fixed. 11-05-28 Two bugs in the display of arrays of compound variables with print -v have been fixed. 11-05-27 A bug with command substitution in the Shift JIS locale has been fixed. 11-05-25 A bug in which unset -f foo, called within function foo could cause the shell to core dump has been fixed. 11-05-24 A bug in unsetting arrays of compound variables that could lead to a core dump has been fixed. 11-05-24 A scoping bug in with typeset -m for variables passed as references has been fixed. 11-05-09 A bug in which 'typeset +p array[$i]' in a subshell could cause an exception has been fixed. 11-05-03 Two more scoping bugs with name references and read -C were fixed. 11-05-03 A potential race condition which occurs when here-documents are processed in asynchronous blocks has been eliminated. 11-05-02 Another scoping bug with name references defined in a function has been fixed. 11-05-02 A bug in which the shell discards saved exit status of a job if it is followed by a subshell execution has been fixed. 11-04-28 The shell now checks for numerical overflows with process IDs. 11-04-28 Another scoping bug with compound variables defined by name references inside a function has been fixed. 11-04-28 A bug which caused a core dump on 32 bit systems with the basic.sh regression test has been fixed. 11-04-27 A scope binding error for name references has been fixed. 11-04-27 Assignment of compound variable to compound array element by name is now working. 11-04-26 I fixed a bug with SHOPT_FIXEDARRAY compilation that could cause an a core dump for not fixed arrays. 11-04-25 A bug in the references to two dimensional compound arrays has been fixed. 11-04-20 A bug in which a name reference to a multidimensional indexed array index, nameref x=foo[3][4], did not work correctly has been fixed. 11-04-18 Changes were added to allow fixed size arrays of variable sized objects when the SHOPT_FIXEDARRAY compile option defined on 10-09-28. 11-04-18 A bug in which name references to array elements could fail has been fixed. 11-04-15 +A compile option, SHOPT_2DMATCH, has been added which causes .sh.match to be a two dimensional array after ${var//pat/str} where the first dimension is the pattern number and the second is the match instance. 11-04-11 A bug in which readonly var, where var is exported could cause var to be unset has been fixed. 11-04-06 A tokenizer bug in which ${x/{3}(\d)/ } would cause an infinite loop has been fixed. 11-04-05 A bug in which ${!x.} could cause a core dump has been fixed. 11-04-04 A bug in which cleaning out the history file could terminate before keeping all the recent history events has been fixed. 11-03-29 A bug in which ${#array[@]} was 1 rather than 0 after issuing typeset array[7] has been fixed. 11-03-29 The subscript out or range message for fixed arrays has been fixed. 11-03-29 A bug in which suspend could cause a core dump has been fixed. 11-03-24 For the showme option added 09-09-09, commands beginning with a ; inside an arithmetic for loop, no longer produce syntax errors. 11-03-18 A bug in _WINIX ~domain/user expansion has been fixed. 11-03-16 A bug in the pipefail option which could cause a script to hang has been fixed. 11-03-12 The shell no longer treats ${##pattern} as a syntax error. 11-03-11 A bug in typeset -u on systems that don't supply the towctrans() function has been fixed. 11-03-11 A bug in which a compound assignment of the form var[sub]=(...) would evaluate sub for each assignment has been fixed. 11-03-07 A bug in which reassigning a compound variable to an associative array index could incorrectly increase the count of the number of elements has been fixed. 11-03-04 +The tilde expansion on Windows has been modified to handle user names of the form domain/user so that ~domain/user now expands to the home directory of that domain user. 11-03-03 A bug in which the width of the prompt was calculated incorrectly which cause the wrong line length for edit commands has been fixed. 11-03-02 A bug in which a global variables set from within a function inside a subshell can leave side effects in parent shell has been fixed. 11-03-01 A bug in which whence -a could dump core when the first match was due to : in PATH and the program was in the current directory. 11-02-28 A bug in emacs mode with SHOPT_EDPREDICT (added on 10-05-20) which disabled prediction on a line starting with # when the cursor was not at the end of line has been fixed. 11-02-28 The output format for compound variables with set has been fixed. 11-02-25 A bug which could lead to a core dump occurred when a shell script without #! is invoked by name from a parent shell that has name references defined and the script creates name references of the same name. 11-02-21 The shell now fails with a syntax error when a here-document in a command substitution is not completed before the closing ), for example, $( foobar <&- doesn't work has been fixed. 11-02-07 A bug on some systems for which a command substitution could hang has been fixed. 11-01-28 A bug in file name completion for files containing both multibyte characters shell special characters has been fixed. 11-01-18 The .sh.match variable now shows elements that do not match as as not set rather than an empty string. 11-01-18 A bug with typeset -m of an array into an element of an indexed array has been fixed. 11-01-13 A bug in handling of arrays of compound variables inside ((...)) which reported a syntax error been fixed. 11-01-10 A bug in arithmetic assignment operators of the form op= for array variables when the same array was referenced on the left and the right hand side with different indices has been fixed. 11-01-10 A bug in which the output of time was lost when { time...;} 2>&1 occurred inside command substitution has been fixed. 11-01-07 [[ -v sh.match[i] ]] was returning false when sh.match[i] was set. 11-01-05 Added and modified warning messages with sh -n. 11-01-02 Fixed bugs with typeset -l/-u/-M and arrays. 10-12-28 Fixed a bug with typeset -l/-u/-M values in arithmetic expressions. 10-12-26 Fixed a time parsing bug in sleep and localeconv() initialization. 10-12-23 Prevented the shell from generating a core dump when it sends itself a termination signal because the last command terminated with that signal. This prevents a core dump to be overwritten by the shell. 10-12-22 A bug in the expansion of ${A[@]} ${B[@]}, introduced in 10-12-01 when A="" B=B has been fixed. 10-12-21 +Use MS_3D in b_vpath() for setting Win32 WoW mount defaults. 10-12-17 A bug in the expansion of ${var:i:j} which caused a core dump when i > ${#var} has been fixed. 10-12-16 +sleep now treats . as decimal point even in locales that use comma. 10-12-16 +typeset -M mapname was added to generalize on toupper and tolowwer mapping as provided with wctrans(). 10-12-10 A bug in which typeset -l displayed namespaces as well as lower case variables has been fixed. 10-12-06 A bug in which a pipeline could terminate prematurely for a pipeline whose right hand side is a builtin, and whose left hand side ends in a simple command that has standard output redirected has been fixed. 10-12-06 A bug in hexfloat assignments when the right hand side is a string variable starting with 0x has been fixed. 10-12-01 A bug in the expansion of ${$1+"$@"} which causes the last positional parameter to disappear when it is empty has been fixed. 10-12-01 A number of changes were made to reduce the startup time. 10-11-29 When wait is interrupted by a signal that is caught, it now exits with a non-zero exit status. 10-11-29 When a variable is used directly in an arithmetic expression, leading zeros no longer cause the value to be treated as an octal constant. This was true in previous versions for justified variables. 10-11-29 An incorrect warning message was eliminated with the -n option for arithmetic expressions with associative arrays. 10-11-29 Some changes were made to slightly reduce startup time. 10-11-24 A bug in which a name reference is make to arr[0] when arr is not an array has been fixed. 10-11-23 If a type definition is made without a compound variable assignment it produces an error message and no longer shows up as a defined type. 10-11-22 The handling of \ inside [...] for shell and ~(E) patterns has been fixed. 10-11-22 A patch was made to pfsh to handle an error case. 10-11-22 +Modified types defined in namespace so that they do not clash with types in other namespaces. Types can be referenced using .namespace.typename. 10-11-22 A bug which caused functions addressed as .namespace.funct to not work has been fixed. 10-11-22 A bug in which if nr was a name reference to an unset associative array subscript, then ${!nr} did not output the subscript correctly has been fixed. 10-11-18 A bug in which shcomp -n was not processing double quotes correctly has been fixed. 10-11-18 Fixed a bug in which typeset -T foo; typeset -T could cause a core dump. 10-11-17 Fixed a bug in which the error message for set -u could come out garbled. 10-11-17 Modified the parser so that typeset -a var=(...) no longer checks the first index for aliases and reserved words. 10-11-17 A bug in which a subshell command consisted of only a for or until command has been fixed. 10-11-16 Fixed a bug in which typeset -u would display namespace variables as well as upper case variables. 10-11-16 A bug which could cause a core dump when unsetting a type variable when there are references to type elements has been fixed. 10-11-15 A bug which could cause a core dump when unsetting a compound array variable when there are references to array subscripts has been fixed. 10-11-15 A bug in which using typeset -m to move an indexed array instance to another array could cause the array to display incorrectly has been fixed. 10-11-12 A bug in which the unset discipline function for a type is called when the type is initialized has been fixed. 10-11-12 The sequences \< and \> are now preserved after patterns containing ~(E) in ${var/pattern/string} expansions. 10-11-11 A bug in typeset -m when the variables were compound array instances has been fixed. 10-11-10 A bug in output of a compound variable with types containing types has been fixed. 10-11-10 Fixed ``name=value export [-p]'' to list environment. 10-11-09 shtests resets SIGPIPE to SIG_DFL for all tests. 10-11-09 Fixed a bug in expansion of $"..." when used in assignments. 10-11-09 Fixed a getaddrinfo() memory leak that didn't call freeaddrinfo() after an interrupt. 10-11-08 Modified the behavior of set -u so that the shell terminates with error message when when var is unset with ${!var} and ${#var}. 10-11-02 Fix a bug in which a signal received while in a subshell could be ignored. 10-10-26 Fix a bug where terminal interrupt was ignored while in vi/emacs edit search mode. 10-10-26 Fix $'a\0b'c to expand to 'ac'. 10-10-26 Provide user defined round() if not in . 10-10-26 Fix bug where $((undefined_function(1))) dumped core. 10-10-22 Provide user defined iszero() if not in . 10-10-22 Fixed a bug with BGX compile option that could cause the shell to hang. 10-10-22 Fixed a bug with user define math function on systems for which char is unsigned. 10-10-21 A bug in which function autoloaded in a function leaves a file open has been fixed. 10-10-20 Modified the behavior of set -u so that the shell terminates when when var is unset with ${var op string} when op is #, % or /. 10-10-20 Fixed a bug with the AUDIT option in which the audit file was not not close-on-exec. 10-10-20 +Made a number of changes and fixes for the NAMESPACE compile option which as added on 10-06-09 but some problems still remain. 10-10-15 Fixed a bug in which arithmetic functions (added on 10-03-24) did not work when the function definition was in the same compound command in which the function was referenced. 10-10-13 A bug in which creating an associative array of compound variables with no members as an element of a compound variable did not work has been fixed. 10-10-08 A bug in which killing the last command in a function defined with function name, terminated the calling script has been fixed. 10-10-08 A bug which could cause a core dump if IFS is unset inside a function has been fixed. 10-10-07 +To reduce unwanted side effects, invoking typeset without the export option and without an assignment now causes the variables to be unset if the variable is inherited from the environment. 10-10-06 The closing brace for ${ command } is now a token no matter what character follows it. 10-10-04 The change for $'...' expansion on 10-08-09 did not expand parameters contained in the error message and this has been fixed. 10-10-04 A bug in which a declaration of indexed array (-a) in a type definition would be displayed as a compound indexed array (-C -a) has been fixed. 10-09-30 The C99 math function ldexp has been added. 10-09-30 A bug with two dimensional arrays with expansion of the form ${ref[0..5]} where ref is a nameref to array[i] has been fixed. 10-09-29 A bug in which an eval with redirections invoked from a dot script would not restore the file has been fixed. 10-09-29 A bug in which loading a function from FPATH could leave a file descriptor open has been fixed. 10-09-28 +A new compile option SHOPT_FIXEDARRAY has been added and is being evaluated. It allows fixed-size indexed arrays be to defined using "typeset array[dim1][dim2]...[dimn]". Fixed-size arrays are used the same way indexed arrays are. Currently, only fixed arrays of fixed objects (float, int, and justified objects) are supported. 10-09-22 A bug which could cause an exception when a function with static variables was redefined has been fixed. 10-09-21 A bug in the processing of (command&) which created a job in the parent process has been fixed. 10-09-21 A for loop optimization bug with arithmetic expression evaluation has been fixed. 10-09-21 A bug in which a recursive function containing a pipeline could lead to an exception fixed after 8 levels of recursion has been fixed. 10-09-18 A bug in which the count of elements in an array was wrong leading to an exception has been fixed. 10-09-13 A bug which occurred when both xtrace and showme options where specified in which the xtrace option disabled showme has been fixed. 10-09-13 A bug in which creating a reference to an array variable with any elements could cause subsequent array elements to be treated as compound variables has been fixed. 10-09-09 A bug which caused ((c.ar[x][y])) to be treated as a syntax error has been fixed. 10-09-08 A bug in the processing of references to multidimensional arrays in arithmetic expressions has been fixed. 10-09-08 A bug in the handling of multidimensional arrays which caused the number of elements in each dimension to be incorrect has been fixed. 10-09-07 The change for messages on 10-08-09 did not handle message in assignments and this has been fixed. 10-09-07 A bug in the indentation of compound variables in arrays when output with print -v has been fixed. 10-09-07 A rare bug with indexed arrays when assigned a null string that could cause a core dump has been fixed. 10-09-03 A number of changes were made for jobs pools. 10-08-31 typeset -p was modified to output name references after other variables so that the output could be used as input. 10-08-31 A bug with typeset -p in which variables with attributes but without attributes were not displayed correctly has been fixed. 10-08-27 +When running a subshell, the current pool is unset. 10-08-27 A bug in which jobs started from within for or while lists in interactive shells could generate completion messages has been fixed. 10-08-25 Fixed a couple of bugs related to job pools. 10-08-24 +[[ -e /dev/xxx/ ]] can be used to check whether special files of those names are handled by the shell. 10-08-24 A bug in the running of a compiled dot script in which only the first command was executed has been fixed. 10-08-23 A bug which sometimes caused a core dump with a configure script has been fixed. 10-08-20 A bug in command substitution which caused a configure script to hang has been fixed. 10-08-19 Eliminated unnecessary ; from output of compound variable with typeset -p. 10-08-17 Fixed a bug in command substitution in which under certain circumstances a file whose size is a power of 2 plus one, and the last character was not a new-line, could cause memory corruption. 10-08-13 +Added static discipline functions to type similar to C++ static class functions. 10-08-11 A bug in time when applied to a pipeline in which the shell did not wait for all elements of the pipeline to complete has been fixed. 10-08-11 Restored sh_fmtq() quoting to not quote NAME= in NAME=VALUE. 10-08-09 +Modified the expansion of message strings, $"...", so that they are expanded each time they are referenced rather than expanding them when the script is compiled or read in. 10-08-06 +The process ID for jobs in job pools is now of the form poolname.n where n is the jobid in that pool. Commands that accept job names or numbers now understand names in this format. 10-08-05 A bug in which an assignment from within an arithmetic expression inside a function would create a local variable has been fixed. 10-08-04 A bug in the expanding of variables whose names contain multibyte characters has been fixed. 10-08-04 A bug which caused an exception when processing scripts compiled with shcomp -n has been fixed. 10-08-02 Tests using very small buffer sizes uncovered a number of bug most connected with here documents which have been fixed. 10-07-27 The format modifier , used for digit grouping with d and f formats has been documented. 10-07-26 cd '' now produces and error rather than changing to the current directory. 10-07-26 A bug in multi-byte locales which the last character of a multi-byte character is a \ or pattern character which could occur when the character was the last character of a command substitution has been fixed. 10-07-23 Another bug in the processing of ${var:offset;len} in multi-byte locales when len is larger than the number of characters has been fixed. 10-07-23 Many coding changes have been made to eliminate most of the uses of global variables in the shell code. 10-07-22 Fixed a bug in which discipline functions were not being invoked when it was invoked as ref.discipline where ref was a name reference to an array instance. 10-07-22 Fixed a bug in which discipline functions were not being invoked it was invoked on a two dimensional array, i.e., arr[5][9].discipline. 10-07-19 Fixed a buffering problem which occurred when running a script with ssh and the parent ssh process is killed. 10-07-14 Modified the parser to treat ((...)) inside [[ ... ]] as ( (...) ) so that it is a nested (...). 10-07-09 A bug in the handling of process substitution inside command substitution as part of a pipeline has been fixed. 10-07-07 A bug in the output for compound variables containing multidimensional arrays has been fixed. 10-07-06 ksh now recovers from changes made by bash to the history file without losing history commands. 10-06-25 A bug in which a large here document containing command substitutions of a dynamically loaded function that contained a here document could get truncated has been fixed. 10-06-24 If after executing a script found in FPATH, if a function, builtin, or type name corresponding to that script is not defined, the shell now outputs an error message and returns value 126. 10-06-23 Floating point functions that happened to return integer values were being treated as if the function returned integers so that integer division could be used instead of floating point division. 10-06-22 Fixed a bug in earlier ksh93u in which an arithmetic assignment to a variable in the global scope would instead create a local variable if the variable had an attribute but did not have a value. 10-06-18 Modified trap handling so that if the same signal is received when executing the handler, it is deferred until the handler completes. 10-06-16 Fixed a bug in which ulimit -v was setting the CPU limit on Linux. 10-06-14 +The command 'typeset -T' now generates the list of type definitions in a format that can be used as input to the shell. 10-06-09 Put in patch from Solaris for output quoting with %q. 10-06-09 +Made changes to the NAMESPACE compile option so that it now seems to work. With this option, namespace { command;} will run command in the namespace .name so that all variables and functions created by command are accessible outside the name space via .name.var and .name.fun. Variables and functions that are not in the namespace are not modified when running command. 10-06-07 Change most internal interfaces to take Sh_t* argument. 10-06-03 +Types can be loaded on first reference by putting definitions in PFPATH. 10-06-03 +The shell is now able to parse commands which use type statements before the typeset -T command to define the type executes. 10-06-03 A bug in the quoting for name reference declarations which did not properly handle [ and ] in subscripts for associative arrays. 10-06-02 A bug in which a discipline function defined by a type instance to override the default was not being registered has been fixed. 10-06-02 A bug in which read -C of an associative array of compound variables was not working has been fixed. 10-06-02 A bug in which the error message for an unset parameter with set -u did not contain the name of the variable has been fixed. 10-06-01 A bug in typeset -m for moving an indexed array instance to a variable has been fixed. 10-06-01 A bug in which caused memory to be freed twice when unset was called for an indexed array that had get or set disciplines has been fixed. 10-06-01 A bug in which the %b format of printf was not preserving NUL bytes with \0 has been fixed. 10-06-01 A bug in the handling of name references to array variables in arithmetic expressions has been fixed. 10-05-28 Fixed bugs in changing attributes for two dimensional arrays. 10-05-28 Eliminated a few unreferenced variables and a reference to uninitialized memory. 10-05-27 Rewrote the subshell code to avoid using pipes an many cases. 10-05-24 Fixed a bug which cause an exception when both -l and -s were specified with typeset -i. 10-05-21 Inputting of three dimensional indexed arrays with ( ( (...)...)...) was not working and has been fixed. 10-05-21 A bug in which adding the attributes -Ai to a variable via a name reference could cause the value to display incorrectly has been fixed. 10-05-21 A bug in which using $var inside ((...)) did not work when var was a hex float variable. 10-05-20 +The compile option SHOPT_EDPREDICT has been added. When this option is on, as you type a line beginning with a # the following characters are treated as a shell pattern and cause matching lines from the history file to be displayed as a numbered list as you type. You can scroll up and down this list or you can use nTAB to make this the current line (n defaults to 1 of omitted) or n to execute. 10-05-20 A bug which caused an exception when multiple levels of composite functions in arithmetic expressions has been fixed. 10-05-19 <<< with an empty string no longer gives an error. 10-05-19 A bug in arithmetic evaluation when a name reference to an array instance was used has been fixed. 10-05-14 A bug in which the shell treats a valid indexed array assignment, typeset -a x=(foo (x=3;y=4) bar) as a syntax error has been fixed. 10-05-13 A bug in creating name references to associative array variable after a lookup of one of its elements has been fixed. 10-05-12 Two bugs in the handling of function static type variables in subshells have been fixed. One could cause an exception and the other would leave side effects in the parent shell. 10-05-10 A bug in which static variables in functions were not being saved and restored properly when running subshells has been fixed. 10-05-05 A bug in which print -v did not work correctly when an operand was an indexed array element referring to a compound variable has been fixed. 10-05-05 A change to improve performance by special casing empty string assignments to avoid repeated malloc() and free(). 10-05-05 A bug in which creating a name reference to a non-existent associative array element would create the array element has been fixed. 10-05-04 A bug in which name references to static variables in the static scope were not found has been fixed. 10-04-30 Do not use socketpair() on systems that implement ioctl(I_PEEK) on pipes. 10-04-29 +When the current job pool is set, coprocess are run in a job pool. 10-04-28 A type defined with a member foo that is an associative array without elements followed by an expansion ${bar.foo[a]} and an assignment bar.foo[a]=b, no longer indicates that ${#bar.foo[@]} has 0 members. 10-04-27 Another bug in which a nested command substitution could hang if it generated too much data has been fixed. 10-04-26 A type defined with a member that is an indexed array without elements would behave as if the 0th element of each instance was defined after a non-zero element was specified and this has been fixed. 10-04-26 A bug in which types defined in a subshell were not undefined when the subshell completed has been fixed. 10-04-23 For file completion in command line editing, file names starting with # are now escaped so that they are not treated as comments. 10-04-23 A bug in which ${t.var:=value}, where t is an instance of a type variable, could assign value to the type variable rather than to the type instance has been fixed. 10-04-23 +Added &| which can be used in place of | to have portions of a pipeline executed in the pool. 10-04-22 +The .sh.pool variable was added for use with job pools. 10-04-22 A bug in which a nested command substitution could hang if it generated too much data has been fixed. 10-04-20 A bug which corrupted one byte of memory when read was called with reads that did not use a delimiter has been fixed. 10-04-19 The display of a compound variable with an embedded array with attributes was sometimes not working correctly and has been fixed. 10-04-16 A bug in which attributes were not be propagated to elements in an associative array has been fixed. 10-04-15 A bug which caused scripts containing user defined math functions to fail to compile with shcomp has been fixed. 10-04-15 +Job pools have been added with the SHOPT_COSHELL compilation option. A job pool allows a collection of background jobs to run either locally or remotely and to be managed as a unit. The command '& name ...' creates or uses a named job pool for subsequent background jobs. kill, wait, and jobs allow the pool name as operands. 10-04-14 A bug in which a coprocess connection could terminate prematurely when running a nested subshell has been fixed. 10-04-12 +Enumeration constants can be used in arithmetic expressions with the ==, != and = operators when the left hand side is an enum variable and the right hand side is an enumeration constant. 10-04-07 A bug in which setting the trap on CHLD to ignore could cause an incorrect exit status has been fixed. 10-04-06 A bug in which LINENO was not incremented for a here-document when the here-document word was followed by a comment has been fixed. 10-04-06 The optimization that execs the last process of a script rather than creating a new process has been removed when a trap on interrupt has been set. 10-04-06 Unsetting the 'C', 'A' or 'a' typeset attribute now produces an error message rather than generating an exception. 10-04-06 A bug in which .sh.name contained the subscript and .sh.subscript was empty in some cases with discipline functions on array instances has been fixed. 10-04-05 A bug in the edit modes where preceding the interrupt character with the literal next character did not work has been fixed. 10-04-05 A bug in the creation of type instances of arrays which could cause an exception has been fixed. 10-03-30 A bug in the display of a compound variable containing an indexed array of compound variables has been fixed. 10-03-24 +Arithmetic functions can be defined using the shell function syntax, 'function .sh.math.name x y z{...}' , where name is the function name invoked within ((...)) and x y z are long double arguments passed as name references. y and z are used for functions with two and three arguments respectively. The value of the function is the value of the long double .sh.value variable when the function returns. 10-03-24 A bug in which integer division was mistakenly used when the numerator was a binary operator with the first operand floating point and the second integer, e.g. (.1**3)/3, has been fixed. 10-03-24 The >; file operator was modified so that the temporary file is created in the same physical directory as file. 10-03-23 A warning message was added to sh -n when $var was used inside ((...)) instead of var. 10-03-19 fmin was added to the list of math function on the man page. 10-03-19 Fixed the return value for unalias when the alias did not exist. 10-03-19 A bug in which the SHLVL variable exported the value it had on input rather than the incremented value has been fixed. 10-03-19 A bug which causes whence -q to go into an infinite loop has been fixed. 10-03-19 Removed space between Stopped message and (SIGTTIN) and (SIGTTOUT). 10-03-17 Modified profile shell execution so that when builtins that correspond to executable have extended attributes, they are executed by pfksh instead of being treated as built-ins. 10-03-16 A bug in whence -a which produced duplicate lines of output has been fixed. 10-03-16 A bug in the handling of process groups in monitor mode for command substitutions has been fixed. 10-03-15 Fixed a bug in which read -u[fd] could cause the shell to core dump when fd was greater than open_max. 10-03-15 +Modified the shell I/O so that the shell will not fail if the ulimit for open_max is increased as part of the script. 10-03-12 A bug in which a here-document containing command substitutions that contained here-documents did not process correctly has been fixed. 10-03-12 A bug in which the terminal is not restored to canonical mode after read times out when in a multibyte locale with no edit mode enabled has been fixed. 10-03-05 --- Release ksh93t+ --- 10-03-05 A variable unset memory leak has been fixed and tests/leaks.sh has been added to verify the fix. 10-03-04 Documentation, comment, and diagnostic spelling typos corrected. 10-02-14 Fix sh_getenv() initialization to cooperate with the 3d fs. 10-02-12 A bug in which the get discipline function was not invoked for associative array subscripts for unset array elements has been fixed. 10-02-12 A bug which could occur if the last line of a script was an eval that executed multiple commands has been fixed. 10-02-02 A buffer overflow in read and another in binary type base64 encoding were fixed. 10-01-20 A bug in the evaluation of arithmetic expression in which the subscript was evaluated twice for $((foo[x++]++)) has been fixed. 10-01-19 A workaround for a double-free of a trap in both a subshell and its parent has been added. 10-01-18 A bug in type handling of typeset -H has been fixed. 10-01-15 The "adding empty subscript" warning now only emitted with -x set. 10-01-01 A bug in the parser in which '$((case i in i):;esac);:))' was not parsed correctly was fixed. 10-01-01 A bug in the parser in which '$(( 2 , 3.6 ))' dumped core for locales with radix char , and thousands separator . has been fixed. 09-12-28 A bug in the handling of SIGCLD on systems that generated SIGCLD while blocked waiting for process to complete has been fixed. 09-12-24 AST setlocale() reworked to differentiate env var changes from user override. 09-12-18 A bug with the SHOPT_BGX option set which disabled traps for signals < SIGCHLD when a trap for a signal > SIGCHLD was set has been fixed. 09-12-18 A bug where [[ -v var ]] was incorrect for some variables (including LC_* vars) has been fixed. 09-12-15 A bug that produced a syntax error when a multibyte character straddled a buffer boundary has been fixed. 09-12-11 A bug where the subscript of an unset variable was not evaluated has been fixed. 09-12-09 A bug where shcomp dumped core on certain syntax errors has been fixed. 09-12-07 A bug where a parent shell environment var reset in a subshell removed the value in subsequent children of the parent shell has been fixed. 09-12-04 A bug in which in some cases a trap in a function executed in a subshell could trigger twice has been fixed. 09-12-03 A bug in which SHLVL exported with some attributes could cause the shell to abort at startup has been fixed. 09-12-02 A bug with pipefail in which the shell could hang waiting for the writer to complete before the last reader command has been fixed. 09-11-30 A bug in which a trap could be inherited by the first element of a pipeline when the command had more than 63 arguments that did not contain any macro expansions has been fixed. 09-11-19 When read was called in a terminal from within a while or for loop and an edit mode was on, a backspace or erase will no longer overwrite the prompt. 09-11-17 +Change .paths parse to handle BUILTIN_LIB=foo BUILTIN_LIB=foo-1.2. 09-11-17 Inside a function, typeset foo.bar will bind foo to global variable foo if local variable foo does not exist, instead of creating a local variable. 09-11-17 "read -n1" from the terminal has been fixed to read exactly one character. 09-11-11 Job control now works for subshell commands, (...). 09-11-11 If set -e is on for an interactive shell errors in special builtins now cause the shell to exit. 09-11-11 A bug in which an interrupt handler processed during the read builtin when IFS did not contain a new line has been fixed. 09-11-09 A bug in which a variable that has been unset in a subshell and then exported from that subshell does not show up in the environment has been fixed. 09-11-02 ``,2'' is now a valid numeric constant for locales with decimal_point=','. 09-11-02 A bug where "return" in .profile did not restore the shell state has been fixed. 09-10-31 A bug that corrupted saved exit status when PIDs wrapped around has been fixed. 09-10-26 A bug in { LANG LC_ALL LC_category } ordering has been fixed in -last. 09-10-16 A bug where notification to libast that the environment has changed has been fixed. 09-10-12 A bug in which a function loaded in a subshell could leave side effects in the parent shell has been fixed. 09-10-12 A bug in converting a printf %d operand to a number when the operand contains multiple subscripts for the same variable has been fixed. 09-10-09 A bug in the handling of the escape character \ in directory prefixes in command completion has been fixed. 09-10-09 $PATH processing has been changed to delay dir stat() and .paths lookup until the directory is needed in the path search. 09-09-28 Call the AST setlocale() intercept on unset too. 09-09-24 A bug in which LANG=foo; LC_ALL=foo; unset LC_ALL; did not revert LC_CTYPE etc. to the LANG value has been fixed. 09-09-17 A bug in which unsetting SVLVL could cause a script invoked by name without #! to core dump has been fixed. 09-09-16 A bug in which a pipeline in a here-document could hang when the pipefail option was on has been fixed. 09-09-09 A bug in the processing of line joining in here documents which occurred when a buffer began with has been fixed. 09-09-09 +A leading ; with commands in a brace group or parenthesis group no longer causes an error. It now is used for the "showme" option. 09-09-09 A bug in which a subshell containing a background process could block until the background process completed has been fixed. 09-09-04 A bug in handling ${var[sub]}, where var is a nameref has been fixed. 09-09-03 A bug which caused an indexed array to have the wrong number of elements when it was converted from a compound variable by adding an another element has been fixed. 09-09-03 Specifying export for a compound variable now generates an error. 09-09-02 $"..." localizations strings are no longer recognized inside `...`. 09-09-01 A bug in the for loop optimizer in the handling of type static variables has been fixed. 09-09-01 An error message is not displayed when * and @ are used as subscripts. 09-09-01 Several bugs in the processing for types that included an associative array of another type has been fixed. 09-09-01 A bug in the tracing of [[ a < b ]] and [[ a > b ]] has been fixed. 09-08-26 The .sh.file variable was not being set for a script that was run by name and didn't start with #! and this has been fixed. 09-08-25 A bug in which a function called to deeply from command substitution did not display an error message has been fixed. 09-08-24 +When processing profiles, ksh93 now violates the POSIX standard and treats &> as a redirection operator similar to bash. 09-08-23 A bug in the handling of the trap on SIGPIPE that could lead to a memory fault has been fixed. 09-08-21 A bug in the handling of the comma operator in arithmetic expressions that could cause a core dump on some systems has been fixed. 09-08-20 A bug in which a compound variable containing an array of a type that doesn't have any elements now expands correctly. 09-08-19 A bug which disabled function tracing inside a function after a call to another function has been fixed. 09-08-19 A bug in which initializing a compound variable instance to another compound variable by name has been fixed. 09-08-18 A bug in which compound variable instances could be lost after an instance that invoked a type method discipline has been fixed. 09-08-18 A bug in which a discipline function for a type applied to an array instance when invoked in a function ignored the subscript has been fixed. 09-08-18 A scoping error with variables in arithmetic expression with type variables when reference with a name reference has been fixed. 09-08-10 Several memory leaks were fixed primarily related to subshells. 09-08-06 A bug in which setting the trap on CHLD to ignore could cause a script to hang has been fixed. 09-07-08 A bug in the processing of name reference assignments when it contained pattern expansions with quoting has been fixed. 09-06-22 +The default width for typeset -X has been changed so that there should be no loss of precision when converting to a string. 09-06-19 A bug in the printing of array elements for binary variables with printf %B has been fixed. 09-06-19 A bug which caused a core dump with trap DEBUG set with an array assignment with no elements has been fixed. 09-06-19 A bug with read with typeset -b -Z has been fixed. 09-06-19 Two bugs related to read -b for array variables has been fixed. 09-06-19 A bug with typeset for compound variables containing arrays of compound variables has been fixed. 09-06-18 A bug in appending a compound variable to an indexed array of compound variables has been fixed. 09-06-18 A bug which occurs when appending a compound variable to an indexed array element has been fixed. 09-06-18 Setting VISUAL to a value other than one ending in vi or emacs will no longer unset the edit mode. 09-06-17 A bug in typeset -m when moving a local compound variable to a global compound variable via a name reference has been fixed. 09-06-17 A bug in appending to nodes of an array of compound variables when addressing them via nameref has been fixed. 09-06-17 A bug in typeset -p var, when var is an array of compound variables in which the output only contained on array element has been fixed. 09-06-17 The prefix expansion ${!y.@} now works when y is a name reference to an element of an array. 09-06-16 Traps on signals that are ignored when the shell is invoked no longer display. Previously they were ignored as required but would be listed with trap -p. 09-06-12 A bug in vi edit mode in which hitting the up arrow key at the end of a line longer than 40 characters which caused a core dump has been fixed. 09-06-11 A bug in which "eval non-builtin &" would create two processes, one for the & and another for non-builtin has been fixed. 09-06-08 When var is an identifier and is unset, ${var} no longer tries to run command substitution on the command var. 09-06-08 +Process substitution arguments of the form <(command) can now be used following the < redirection operator to redirect from command. 09-05-13 A bug in which redirections of the form 2>&1 1>&5 inside command substitution could cause the command substitution to hang has been fixed. 09-05-12 To conform with POSIX, the -u option only checks for unset variables and subscript elements rather than checking for all parameters. 09-05-12 A bug which could cause a core dump when a variable whose name begins with a . was referenced as part of a name reference inside a function has been fixed. 09-05-01 A bug that caused a core dump when SIGWINCH was received and both vi and emacs mode were off has been fixed. 09-04-22 +Default alias compound='typeset -C' added. 09-04-15 A bug that caused ${...;} to hang for large files has been fixed. 09-04-08 A change was made in the -n option which printed out an incorrect warning with <>. 09-04-07 The emacs edit command M-_ and M_. and the vi command _ was fixed to handle the case there there is no history file. 09-04-05 A bug in handling new-lines with read -n has been fixed. 09-04-05 The ENV variable defaults to the file named by $HOME/.kshrc rather then to the string $HOME/.kshrc. 09-03-31 A bug in which a nested command substitution with redirections could leave a file descriptor open has been fixed. 09-03-24 +ksh now only uses the value of the _ variable on startup if it can verify that it was set by the invoking process rather than being inherited by some other ancestor. 09-03-24 +When ksh is invoked without -p and RUID != EUID, and the shell is compiled without SHOPT_P_UID or RUID < SHOPT_P_UID, the shell now enables the -p option. The previous version instead set the EUID to the RUID as it does for set +p. 09-03-24 +When SHOPT_P_UID is defined at compile time and the shell is started without -p and RUID != EUID and RUID >= SHOPT_P_UID then EUID is set to RUID. A bug that did the wrong test (RUID < SHOPT_P_UID) was fixed. 09-03-17 +The sleep(1) builtin now accepts an ISO 8601 PnYnMnDTnHnMnS duration or date(1) compatible date/time operand. 09-03-10 If a variable that was left or right justified or zero-filled was changed with a typeset statement that was left or right justified or zero-filled, then the original justification no longer affects the result. 09-03-10 A bug in the handling of traps when the last command in a script is a subshell grouping command has been fixed. 09-03-03 A bug in which an expansion of the form ${!prefix@} could generate an exception after the return from a function has been fixed. 09-02-02 A bug in restricted mode in which the value of ENV could be changed from within a function has been fixed. 09-02-02 A bug in which an erroneous message indicating that a process terminated with a coredump has been fixed. 09-02-02 The exit status when exit was called without an argument from a signal handler was incorrect and has been fixed. 09-02-02 A bug in which a function autoloaded in a subshell could cause a core dump when the subshell completed has been fixed. 09-02-02 A bug in which 2>&1 inside a command substitution wasn't working correctly has been fixed. 09-02-02 A bug in the call stack of arithmetic function with 2 args returning int has been fixed. 09-01-30 A bug in which 'eval print \$0' inside a function was giving the wrong value for $0 has been fixed. 09-01-28 A bug in which a command substitution could return an exit status of 127 when the pipefail option is enabled has been fixed. 09-01-26 ksh93 now generates an error message if you attempt to create a global name reference to a local variable. 09-01-26 +The [[ -v var ]] operator was modified to test for array elements. 09-01-23 +The redirection operator <>; was added. It is similar to <> except that if the command it is applied to succeeds, the file is truncated to the offset at the command completion. 09-01-23 The default file descriptor for <> was changed to 1. 09-01-20 A bug in which the exit status specified in an exit trap was not used when a process terminated with a signal has been fixed. 09-01-19 A bug in which a signal whose default action is to terminate a process could be ignored when the process is running a subshell has been fixed. 09-01-19 A bug in which sending SIGWINCH to a process that reads from a pipe could cause a memory fault has been fixed. 09-01-16 +The -R unary operator was added to [[ ... ]] and test to check whether a variable is a name reference. 09-01-16 +The -v unary operator was added to [[ ... ]] and test to check whether a variable is set. 09-01-14 The unset built-in was modified to return 0 exit status when unsetting a variable that was unset to conform with the POSIX standard. 09-01-14 The unset built-in was modified to continue to unset variables after encountering a variable that it could not unset to conform to the POSIX standard. 09-01-14 The parameter expansion ${x+value} no longer expands the value of the variable x when determining whether x is set or not. 09-01-13 A bug in which background jobs and pipelines that were not waited for could, in rare instances, cause the shell to go into an infinite loop or fail has been fixed. 09-01-06 A bug in indexed arrays of compound variables in which referencing non-existent sub-variable in an arithmetic expression could cause the sub-variable to be created has been fixed. 09-01-05 A bug in which the \ character did not escape extended regular expression pattern characters has been fixed. 08-12-24 A bug in which killing the last element of a pipe did not cause a write to the pipe to generate a SIGPIPE has been fixed. 08-12-19 A bug which could cause command substitution to hang when the last element of a pipeline in a command substitution was a built-in and the output was more that PIPE_BUFF. 08-12-18 A bug which occurs when a here documented marker embedded in a command substitution occurs on a buffer boundary has been fixed. 08-12-17 A bug in the output of typeset -p for variables that had attributes but did not have a value has been fixed. 08-12-16 A bug in which a name reference to a name reference variable that references an array element has been fixed. 08-12-16 A bug in which a variable given both the -A and -C attribute along with an initial assignment didn't work correctly has been fixed. 08-12-10 The [[ -t fd ]] test was fixed to handle fd>9. 08-12-10 A bug where function stack misalignment could cause a bus error has been fixed. 08-12-09 Command completion was changed to use \ to quote special characters instead of quoting the argument in single quotes. 08-12-07 A bug in typeset -m which occurred when the target node was an associative array element has been fixed. 08-12-07 A timing bug on some systems (for example Darwin), that could cause the last process of a pipeline entered interactively to fail with an "Exec format error" has been fixed. 08-12-04 +SHOPT_BGX enables background job extensions. Noted by "J" in the version string when enabled. (1) JOBMAX=n limits the number of concurrent & jobs to n; the n+1 & job will block until a running background job completes. (2) SIGCHLD traps are queued so that each completing background job gets its own trap; $! is set to the job PID and $? is set to the job exit status at the beginning of the trap. (3) sleep -s added to sleep until the time expires or until a signal is delivered. 08-12-04 The sign of floating point zero is preserved across arithmetic function calls. 08-12-04 A bug that caused print(1) to produce garbled stdout/stderr output has been fixed. 08-12-04 A bug in which printf "%d\n" "''" did not output the numerical value of the EURO symbol, 8354, has been fixed. 08-11-24 + /dev/fd* and /dev/std* redirections are first attempted with open() to preserve seek semantics; failing that the corresponding file descriptors are dup()'d. 08-11-20 A bug which could cause a core dump if a function compiled with shcomp was found has been fixed. 08-11-20 A bug in which jobs were not cleared from the jobs table for interactive shells when the pipefail option is on has been fixed. 08-11-11 A bug in which a field that was unset in a type definition and later set for an instance could appear twice when displaying the variable has been fixed. 08-11-11 A bug in which running a simple command & inside a function would not return the correct process ID has been fixed. 08-11-10 A bug in which the exit status of a command could be lost if the PID was that of the most recent command substitution that had completed has been fixed. 08-11-10 The maximum depth for subshells has been increased from 256 to 65536. 08-11-06 A bug which could cause a core dump when the _ reference variable was used as an embedded type with a compound assignment has been fixed. 08-10-31 --- Release ksh93t --- 08-10-31 Variable scoping/initialization bugs that could dump core were fixed. 08-10-24 The lexer now accepts all RE characters for patterns prefixed with a ksh ~(...) option expression. 08-10-24 +For ${var/pat/sub} \0 in sub expands to the text matched by pat. 08-10-18 A bug in array scoping that could dump core has been fixed. 08-10-10 read -n and -N fixed to count characters in multibyte locales. 08-10-10 A bug that mishandled _.array[] type references has been fixed. 08-10-09 +${.sh.version} now contains a concatenation of the following (after 'Version') denoting compile time features: A SHOPT_AUDIT B SHOPT_BASH L SHOPT_ACCT M SHOPT_MULTIBYTE 08-10-09 A bug that caused subshell command substitution with redirection to hang has been fixed. 08-10-08 Output errors, other than to stderr, now result in a diagnostic. 08-10-08 ksh93 now supports types that contain arrays of other types as members. Earlier versions core dumped in this case. 08-10-05 A bug which caused the shell to emit a syntax error for an arithmetic statement of the form (( var.name[sub] = value)) has been fixed. 08-10-01 A bug that caused subshell command substitution to hang has been fixed. 08-09-29 When the -p export option of typeset is used with other options, only those variables matching the specified options are displayed. 08-09-29 When the shell reads the environment and finds variables that are not valid shell assignments, it now passes these on to subsequent commands rather than deleting them. 08-09-29 A bug in the display of compound variables containing an indexed array of compound variables has been fixed. 08-09-29 A bug in the display of compound variables containing an associative array with a subscript containing a . in the name has been fixed. 08-09-26 A core dump in the subshell environment restore has been fixed. 08-09-24 $(...) has been fixed to properly set the exit status in $?. 08-09-23 $(<...) with IFS=$'\n\n' has been fixed to retain all but the last of multiple trailing newlines. 08-09-23 The -p option to typeset when used with other attributes, restricts the output to variables with the specified attributes. 08-09-22 A bug that sometimes lost the exit status of a job has been fixed. 08-09-21 A bug that retained trailing command substitution newlines in cases where the command caused the shell to fork has been fixed. 08-09-19 type, whence -v, and command -v were fixed to comply with POSIX by writing 'not found' diagnostics to the standard error. 08-09-18 test and [ ... ] were fixed to comply with POSIX in the case of test '(' binop ')' where binop is a valid binary test operator. 08-09-16 +If a method discipline named create is specified when defining a type, this function will be called when an instance is created. 08-09-15 +The variable _ is now set as a reference to the compound variable when defining a compound variable or a type. 08-09-10 The shell now prints an error message when the type name specified for an indexed array subscript is not an enumeration type. 08-09-10 A bug in which a subshell that spawned a background process could lose output that was produced after the foreground completed has been fixed. 08-09-10 A timing bug on some systems that could cause coprocesses started by a subshell to not clean up and prevent other coprocesses has been fixed. 08-09-09 The typeset -m option is now able to rename array elements from the same array. 08-09-09 The exit status of 2 from the DEBUG trap causes the next command to be skipped. An exit value of 255 from a DEBUG trap called from a function causes the function to return. 08-09-08 A bug in which a coprocess created in a subshell that did not complete when the subshell terminated could prevent a coprocess from being created in the parent shell has been fixed. 08-09-05 An assignment of the form name1=name2 where name1 and name2 are both compound variables causes name1 to get a copy of name2. name1+=name2 causes name2 sub-variables to be appended to name1. 08-09-05 A bug in which unsetting a compound variable did not unset all the sub-variables has been fixed. 08-09-01 A bug in the subshell cleanup code that could cause SIGSEGV has been fixed. 06-08-26 +The SHLVL variable which is an environment variable used by bash and zsh that gets incremented when the shell starts. 08-08-25 +For an indexed array, a negative subscript now refers to offsets from the end so that -1 refers to the last element. 08-08-24 An alignment error for shorts on 64 bit architectures has been fixed. 08-08-22 If oldvar is a compound variable, typeset -C newvar=oldvar creates newvar as a copy of oldvar. 08-08-19 +The ALRM signal no longer cause the sleep builtin to terminate. 08-08-13 When used in an arithmetic expression, the .sh.version variable now produces a number that will be increasing for each release. 08-08-11 A bug in which type instantiation with a compound assignment in a dot script in which the type is defined has been fixed. 08-08-07 +The -m option has been added to typeset to move or rename a variable. Not documented yet. 08-08-06 A bug in read when used in a loop when a prompt was specified when reading from a terminal has been fixed. 08-08-01 A bug with the pipefail option in which a nested pipeline could cause an asynchronous command to block has been fixed. 08-08-01 A for loop optimizer bug that treats .sh.lineno as an invariant has been fixed. 08-07-30 A bug in which expanding compound variable that had a get discipline from within a here document could cause a syntax error has been fixed. 08-07-18 A bug in which a nameref caused a local variable to be created rather than binding to an existing variable in the global scope has been fixed. 08-07-17 A bug which occurred when a nameref was created from within a function that was part of a pipeline has been fixed. 08-07-14 +The compile option SHOPT_STATS was added. With this option the compound variable .sh.stats keeps usage statistics that could help with performance tuning. 08-07-10 +The output of set now always uses a single line for each variable. For array variables, the complete set of values is now displayed. 08-07-09 +The typeset -C option can be used with arrays to indicate that each element should default to a compound variable. 08-07-08 +The %B format now outputs compound variables and arrays. The alternate flag # can be used to cause output into a single line. 08-07-03 When the window change signal, WINCH, is received, the current edit line is redrawn in place. 08-07-01 A bug in the handling of shared variables when inside an embedded type has been fixed. 08-06-29 A bug in multiline edit mode which occurred when the prompt length was three characters or less has been fixed. 08-06-23 A bug in which the SIGCLD was not be triggered when background jobs completed has been fixed. 08-06-23 +Added KSH_VERSION as a name reference to .sh.version. 08-06-20 type now outputs 'special builtin' for special builtins. 08-06-19 A couple of bugs in multidimensional arrays have been fixed. 08-06-19 A bug in which a syntax error in a dot script could generate a syntax error in the next subsequent command has been fixed. 08-06-17 Reduced the maximum function call depth to 2048 to avoid exceptions on some architectures. 08-06-16 A bug in which printf "%B" could generate an exception when the specified variable was not set has been fixed. 08-06-16 +When typeset -p is followed by variable names, it now displays the attributes names and values for the specific names. 08-06-14 A bug that could affect the drawing of the screen from multiline emacs or gmacs mode when walking up the history file has been fixed. 08-06-13 A bug in which a compound variable defined in a subshell could have side effects into the parent shell has been fixed. 08-06-13 A number of bugs related to using .sh.level to set the stack from for DEBUG traps have been fixed. 08-06-13 +The .sh.lineno variable has been added. When .sh.level is changed inside a DEBUG trap, the .sh.lineno contains the calling line number for the specified stack frame. 08-06-13 The .sh.level variable has been documented and now works. 08-06-11 +The -C option has been added to read for reading compound command definitions from a file. 08-06-11 +The . command is now permitted inside a compound command definition. The dot script can contain declaration commands and dot commands. 08-06-09 +Add -C option to typeset so that typeset -C foo, is equivalent to foo=(). 08-06-09 Added -n warning message for typeset option orderings that are valid with ksh88 but not valid with ksh93, for example Lx5. 08-06-09 A bug in which the return value for an assignment command containing a command substitution with that failed was zero when the assignment contained redirections has been fixed. 08-06-09 A bug in the quoting of $ inside an ERE pattern ~(E)(pattern) has been fixed. 08-06-06 A bug when processing `` command substitution with the character sequence \$' has been fixed. 08-06-02 +When defining a type, the typeset -r attribute causes this field to be required to be specified for each instance of the type and does not allow a default value. 08-06-02 Several bugs in which compound variables were modified by subshells have been fixed. 08-05-22 +The ceil function has been added to the math functions. 08-05-21 A bug in which a name reference defined in a function and passed as an argument to another function could cause an incorrect binding. 08-05-21 A bug in freeing compound variables that are local to functions has been fixed. 08-05-19 +The array expansions ${array[sub1..sub2]} and ${!array[sub1..sub2]} to expand to the value (or subscripts) for array between sub1 and sub2 inclusive. For associative arrays, the range is based on location in the POSIX locale. The .. must be explicit and cannot result from an expansion. 08-05-15 The trap on SIGCLD is no longer triggered by the completion of the foreground job as with ksh88. 08-05-14 A bug in the implementation of the editing feature added on 07-09-19 in emacs mode has been fixed. 08-05-12 A bug in processing the test built-in with parenthesis has been fixed. 08-05-12 The unset built-in now returns non-zero when deleting an array subscript that is not set. 08-05-08 +Changing the value of HISTFILE or HISTSIZE will cause the old history file to be close and reopened with the new name or size. 08-05-08 When FPATH is changed functions that were found via a path search will be searched for again. 08-05-08 A parser bug in which reserved words and labels were recognized inside compound indexed array assignment after a new-line has been fixed. 08-05-07 A bug in getopts when handling numerical option arguments has been fixed. 08-05-07 +The typeset -S option was added for variables outside type definitions to provide a storage class similar to C static inside a function defined with function name. When outside type definitions and outside a function, the -S option cause the specified variable so be unset before the assignment and before the remaining attributes are supplied. 08-05-07 A bug that affected the cursor movement in multiline mode when a character was deleted from near the beginning of the any line other than the first. 08-05-01 In multiline edit mode, the refresh operation will now clear the remaining portion of the last line. 08-05-01 A bug in computing prompt widths for the edit modes for prompts with multibyte characters has been fixed. 08-05-01 A bug in the multiline edit mode which could cause the current line to be displayed incorrectly when moving backwards from third or higher line to the previous line has been fixed. 08-05-01 A bug in which options set in functions declared with the function name syntax were carried across into functions invoked by these functions has been fixed. 08-04-30 A bug which could cause a coprocess to hang when the read end is a builtin command has been fixed. 08-04-30 +The emacs and vi editors have been modified to handle window change commands as soon as they happen rather than waiting for the next command. 08-04-28 A bug in which ${!x} did not expand to x when x was unset has been fixed. 08-04-27 A bug in which the assignment x=(typeset -a foo=([0]=abc)) created x.foo as an associative array has been fixed. 08-04-25 A bug in which $# did not report correctly when there were more than 32K positional parameters has been fixed. 08-04-04 Choose the name _ as the sub-variable that holds type or instance specific data used by discipline functions. 08-03-27 A bug in which the terminal group was not given back to the parent shell when the last part of a pipeline was handled by the parent shell and the other parts of the pipeline complete has been fixed. The symptom was that the pipeline became uninterruptible. 08-03-25 A bug in restricted mode introduced in ksh93s that caused scripts that did not use #! to executed in restricted mode has been fixed. 08-03-25 A bug in which the pipefail option did not work for a pipeline within a pipeline has been fixed. 08-03-24 A bug in which OPTIND was not set correctly in subshells has been fixed. 08-03-24 A bug which could cause a memory exception when a compound variable containing an indexed array with only element 0 defined was expanded. 08-03-20 A bug in which ${!var[sub].*} was treated as an error has been fixed. 08-03-20 Associative array assignments of the form ([name]=value ...) now allow ; as well as space tab and new line to separate elements. 08-03-18 A buffering problem in which standard error was sometimes not flushed before sleep has been fixed. 08-03-17 A bug in which a signal sent to $$ while in a subshell would be sent to the subshell rather than the parent has been fixed. 08-03-17 +Added a --default option to set(1) to handle set +o POSIX semantics. set --state added as a long name alias for set +o. 08-03-14 A bug in which using monitor mode from within a script could cause the terminal group to change has been fixed. 08-03-10 The new ${...} command substitution will treat the trailing } as a reserved word even if it is not at the beginning of a command, for example, ${ date }. 08-03-10 If the name of the ENV begins with /./ or ././ then the /etc/ksh.kshrc file will not be executed on systems that support this interactive initialization file. 08-03-07 A bug in which ksh -i did not run the ENV file has been fixed. 08-03-07 A bug in which ulimit did not always produce the same output as ulimit -fS has been fixed. 08-03-04 A bug in multiline mode in emacs and vi mode which could cause the cursor to be on the wrong line when interrupt was hit has been fixed. 08-03-03 The change made in ksh93s+ on 07-06-18 in which braces became optional for ${a[i]} inside [[ ... ]] was restored in the case where the argument can be a pattern. 08-03-03 A bug in which creating a name reference to an associative array instance would fail when the subscript contained characters [ or ] has been fixed. 08-02-29 +The redirection operator >; has been added which for non-special files, generates the output in a temporary file and writes the specified file only of the command has completed successfully. 08-02-15 A bug in ${var/pattern/string} for patterns of the form ?(*) and +(*) has been fixed. 08-02-07 A bug in which test \( ! -e \) produced an error has been fixed. 08-02-14 +The typeset -a option can now optionally be followed by the name of an enumeration type which allows subscripts to be enumerations. 08-02-14 +The enum builtin which creates enumeration types has been added. 08-02-12 The backoff logic when there are no more processes has been fixed. 08-02-07 The -X option has been added to typeset. The -X option creates a double precision number that gets displayed using the C99 %a format. It can be used along with -l for long double. 08-01-31 The -T option to typeset has been added for creating typed variables. Also the -h and -S options have been added to typeset that are only applicable when defining a type. 08-01-31 The prefix expansion operator @ has been added. ${@name} expands to the type of name or yields the attributes. 07-11-15 A bug in the macro expander for multibyte characters in which part of the character contains a file pattern byte has been fixed. 07-10-03 A bug in which : was not allowed as part of an alias name has been fixed. 07-09-26 A bug in which appending a compound variable to a compound variable or to an indexed array didn't work has been fixed. 07-09-19 In both emacs and vi edit mode, the escape sequence \E[A (usually cursor up, when the cursor is at the end of the line will fetch the most recent line starting with the current line. 07-09-18 The value of ${!var} was correct when var was a reference to an array instance. 07-09-18 The value of ${!var[sub]} was not expanding to var[sub] and this was fixed. It also fixed ${name} where name is a name reference to var[sub]. 07-09-18 +It is now legal to create a name reference without an initialization. It will be bound to a variable on the first assignment. 07-08-30 +A discipline function can be invoked as ${x.foo} and is equivalent to ${ x.foo;} and can be invoked as x.foo inside ((...)). 07-07-09 A bug in which typeset -a did not list indexed arrays has been fixed. 07-07-03 +The command substitution ${ command;} has been added. It behaves like $(command) except that command is executed in the current shell environment. The ${ must be followed by a blank or an operator. 08-04-17 --- Release ksh93s+ --- 08-04-17 A bug in which umask was not being restored correctly after a subshell has been fixed. 08-04-15 A bug in which sending a STOP signal to a job control shell started from within a shell function caused cause the invoking shell to terminate has been fixed. 08-04-11 A bug which caused $(exec > /dev/null) to go into an infinite loop has been fixed. 08-03-27 A bug in which typeset -LZ was being treated as -RZ has been fixed. 08-03-06 A bug with ksh -P on systems that support the profile shell, in which it would exit after running a non-builtin has been fixed. 08-01-31 A bug in which command substitution inside ((...)) could cause syntax errors or lead to core dumps has been fixed. 08-01-17 A bug in which discipline functions could be deleted when invoked from a subshell has been fixed. 08-01-17 A bug in which a command substitution consisting only of assignments was treated as a noop has been fixed. 08-01-17 A bug in which discipline functions invoked from within a compound assignment could fail has been fixed. 08-01-16 Incomplete arithmetic assignments, for example ((x += )), now generate an error message. 08-01-16 A bug in which a set discipline defined for a variable before an array assignment could cause a core dump has been fixed. 08-01-03 A bug in on some systems in which exit status 0 is incorrectly returned by a process that catches the SIGCONT signal is stopped and then continued. 07-12-13 A race condition in which a program that has been stopped and then continued could lose its exit status has been fixed. 07-12-12 Code to check for file system out of space write errors for all writes has been added. 07-12-11 A bug in the macro expander for multibyte characters in which part of the character contains a file pattern byte has been fixed. 07-12-06 A bug in the emacs edit mode when multiline was set that output a backspace before the newline to the screen has been fixed. 07-12-04 A bug in which using TAB after a variable name listing expansion in the edit modes would cause the $ to disappear has been fixed. 07-11-28 A bug in which setting IFS to readonly could cause a subsequent command substitution to fail has been fixed. 07-11-27 A work around for a gcc 4.* C99 "feature" that could cause a job control shell to go into an infinite loop by adding the volatile attribute to some auto vars in functions that call setjmp(). 07-11-27 A bug in which the shell could read ahead on a pipe causing the standard input to be incorrectly positioned has been fixed. 07-11-27 A bug in which compound variable UTF-8 multibyte values were not expanded or traced properly has been fixed. 07-11-21 A bug where an unbalanced '[' in a command argument was not treated properly has been fixed. 07-11-15 A bug in which compatibility mode (no long option names) getopts(1) incorrectly set the value of OPTARG for flag options has been fixed. 07-11-15 A bug in which "hash -- name" treated "--" as an invalid name operand has been fixed. 07-11-15 typeset now handles "-t -- [-r] [--]" for s5r4 hash(1) compatibility. 07-11-15 A bug in which the umask builtin mishandled symbolic mode operands has been fixed. 07-11-15 Bugs in which shell arithmetic and the printf builtin mishandled the signs of { -NaN -Inf -0.0 } have been fixed. 07-11-15 +The full { SIGRTMIN SIGRTMIN+1 ... SIGRTMAX-1 SIGRTMAX } range of signals, determined at runtime, are now supported. 07-11-15 A bug in which creating an indexed array with only subscript 0 created only a simple variable has been fixed. 07-11-14 A bug in which appending to an indexed array using the form name+=([sub]=value) could cause the array to become an associative array has been fixed. 07-11-14 A bug in which typeset without arguments could coredump if a variable is declared as an indexed array and has no elements has been fixed. 07-11-14 A bug in which creating a local SECONDS variable with typeset in a function could corrupt memory has been fixed. 07-11-14 A bug which could cause a core dump when a script invoked by name from a function used compound variables has been fixed. 07-11-05 A bug in which printf %d "'AB" did not diagnose unconverted characters has been fixed. 07-11-05 printf %g "'A" support added for all floating point formats. 07-11-01 A bug in which typeset -f fun did not display the function definition when invoked in a subshell has been fixed. 07-10-29 The sleep builtin was fixed so that all floating point constants are valid operands. 07-10-10 A bug in which the locale was not being restored after LANG=value command has been fixed. 07-09-20 A bug in which a nameref to a compound variable that was local to the calling function would not expand correctly when displaying its value has been fixed. 07-09-19 A bug which could cause a core dump if .sh.edchar returned 80 characters or more from a keyboard trap has been fixed. 07-09-14 A bug in which could cause a core dump when more than 8 file descriptors were in use has been fixed. 07-09-10 A bug in which creating a name reference to an instance of an array when the array name is itself a reference has been fixed. 07-09-10 The file completion code has been modified so that after an = in any word, each : will be considered a path delimiter. 07-09-06 A bug in which subprocess cleanup could corrupt the malloc() heap has been fixed. 07-08-26 A bug in which a name reference to an associative array instance could cause the subscript to be evaluated as an arithmetic expression has been fixed. 07-08-22 A bug in which the value of an array instance was of a compound variable was not expanded correctly has been fixed. 07-08-14 A bug which could cause a core dump when a compound assignment was made to a compound variable element with a typeset -a attribute has been fixed. 07-08-08 A bug in which a trap ignored in a subshell caused it to be ignored by the parent has been fixed. 07-08-07 A bug in which the set command would generate erroneous output for a variable with the -RZ attribute if the variable name had been passed to a function has been fixed. 07-08-02 A bug in which read x[1] could core dump has been fixed. 07-08-02 A second bug in which after read x[sub] into an associative array of an element that hasn't been assigned could lead to a core dump has been fixed. 07-07-31 A bug in which a pipeline that completed correctly could have an exit status of 127 when pipefail was enabled has been fixed. 07-07-09 +The SHOPT_AUDIT compile option has been added for keyboard logging. 07-06-25 In vi insert mode, ksh no longer emits a backspace character before the carriage return when the newline is entered. 07-06-25 A bug in which pipefail would cause a command to return 0 when the pipeline was the last command and the failure happened on a component other than the last has been fixed. 07-06-25 A bug in the expansion of ${var/pattern/rep} when pattern or rep contained a left parenthesis in single quotes has been fixed. 07-06-18 The braces for a subscripted variable with ${var[sub]} are now optional when inside [[ ... ]], ((...)) or as a subscript. 07-05-28 A bug in brace expansion in which single and double quotes did not treat the comma as a literal character has been fixed. 07-05-24 The -p option of whence now disables -v. 07-05-23 Several bug fixes in compound variables and arrays of arrays have been made. 07-05-15 A bug in which the %B format of printf was affected by the locale has been fixed. 07-05-14 A bug in which \ was not removed in the replacement pattern with ${var/pattern/rep} when it was not followed by \ or a digit has been fixed. 07-05-10 A bug in which ksh -R file core dumped if no script was specified has been fixed. It now displays an error message. 07-05-07 Added additional Solaris signals to signal table. 07-04-30 A bug in which a pipeline with command substitution inside a function could cause a pipeline that invokes this function to hang when the pipefail option is on has been fixed. 07-04-30 +Added -q to whence. 07-04-18 A small memory leak with each redirection of a non-builtin has been fixed. 07-03-08 A bug in which set +o output command line options has been fixed. 07-03-08 A bug in which an error in read (for example, an invalid variable name), could leave the terminal in raw mode has been fixed. 07-03-06 A bug in which read could core dump when specified with an array variable with a subscript that is an arithmetic expression has been fixed. 07-03-06 Several serious bugs with the restricted shell were reported and fixed. 07-03-02 If a job is stopped, and subsequently restarted with a CONT signal and exits normally, ksh93 was incorrectly exiting with the exit status of the stop signal number. 07-02-26 +M-^L added to emacs mode to clear the screen. 07-02-26 A bug in which setting a variable readonly in a subshell would cause an unset error when the subshell completed has been fixed. 07-02-19 +The format with printf uses the new = flag to center the output. 07-02-19 A bug in which ksh93 did not allow multibyte characters in identifier names has been fixed. 07-02-19 A bug introduced in ksh93 that causes global compound variable definitions inside functions to exit with "no parent" has been fixed. 07-02-19 A bug in which using compound commands in process redirection arguments would give syntax errors <(...) and >(...) has been fixed. 07-01-29 A bug which caused the shell to core dump which can occur when a built-in exits without closing files that it opens has been fixed. 07-01-26 A bug in which ~(E) in patterns containing \ that are not inside () has been fixed. 06-12-29 --- Release ksh93s --- 06-12-29 A bug in which the value of IFS could be changed after a command substitution has been fixed. 06-12-22 +/dev/(tcp|udp|sctp)/HOST/SEVRICE now handles IPv6 addresses on systems that provide getaddrinfo(3). 06-12-19 +A -v option was added to read. With this option the value of the first variable name argument will become the default value when read from a terminal device. 06-11-20 A bug in which "${foo[@]:1}}" expands a null argument (instead of no argument), when foo[0] is not empty has been fixed. 06-11-16 The discipline functions have been modified to allow each subscript to act independently. Currently, the discipline function will not be called when called from a discipline function of the same variable. 06-11-14 A bug which could cause a core dump if a file descriptor for an internal file was closed from within a subshell has been fixed. 06-10-30 +The redirections <# pattern, and <## pattern have been added. Both seek forward to the beginning of the next line that contains the pattern. The <## form copies the skipped portion to standard output. 06-10-26 +On systems that support stream control transport, the virtual file name /dev/sctp/host/port can now be used to establish connections. 06-10-26 +The printf modifier # when used with d produces units in thousands with a single letter suffix added. The modifier # when used with the i specification provides units of 1024 with a two letter suffix. 06-10-24 The value of $! is now set to the process ID of a job put into the background with the bg command as required by POSIX. 06-10-23 A bug in which the value of $! was affected by a background job started from a subshell has been fixed. 06-10-23 A bug in ${var:offset:len} in multibyte locales has been fixed. 06-10-15 +The remaining math functions from C99 were added for any system that supports them. 06-10-13 The klockwork.com software detected a few coding errors that have been fixed. 06-10-12 A bug when skipping over `...` with ${x:=`...`} when x is set has been fixed. 06-10-11 A bug in process floating constants produced by the %a format of printf has been fixed. 06-10-06 A bug in which IFS was not being restored correctly in some cases after a subshell has been fixed. 06-10-06 A bug in which pipefail was not detecting some failures in pipelines with 3 or more states has been fixed. 06-10-03 A bug in the processing of >(...) with builtins which could cause the builtin to hang has been fixed. 06-10-03 A bug in the for loop optimizer which causes >(...) process substitution to be ignored has been fixed. 06-09-17 +The -a option was added to typeset for indexed arrays. This is only needed when using the ([subscript]=value ...) form. 06-09-06 +The showme option was added. Each simple command not beginning with a redirection and not occurring with in the while, until, if, select condition can be preceded by a semicolon which will be ignored when showme is off. When showme is on, any command preceded by a colon will be traced but not executed. 06-08-16 +As a new feature, a leading ~(N) on a pattern has no effect except when used for file expansion. In this case if not matches are found, the pattern is replaced by nothing rather than itself. 06-08-11 A bug in the expansion of ${.sh.match[i]:${#.shmatch[i]}} has been fixed. 06-08-10 +The read builtin options -n and -N have been modified to treat the size as characters rather than bytes unless storing into a binary (typeset -B) variable. 06-07-27 +When the here document operator << is followed directly by a # rather than a -, the first line of the here-document determines how much whitespace is removed for each line. 06-07-26 A bug in the C-shell history (enabled with set -H) in which the history event !$ was not processed has been fixed. 06-07-21 A bug on some systems in which assigning PATH on a command line would not take effect has been fixed. 06-07-20 Add ksh93 and rksh93 as allowable names for ksh binaries. 06-07-20 Removed the SHOPT_OO compilation option which was only partially implemented. 06-07-20 The ability to use egrep, grep, and fgrep expressions within shell patterns has been documented. 06-07-17 A bug with arithmetic command expressions for locales in which the comma is a thousands separator has been fixed. 06-07-13 +The default HISTSIZE was increased from 128 to 512. 06-07-13 A multibyte problem with locales that use shift codes has been fixed. 06-06-23 A number of bug fixes for command, file, and variable completion have been mode. 06-06-20 +Floating point division by zero now yields the constant Inf or -Inf and floating functions with invalid arguments yield NaN. 06-06-20 +The floating point constants Inf and NaN can be used in arithmetic expressions. 06-06-20 +The functions isinf(), isnan(), tanhl() have been added for arithmetic expressions. 06-06-13 Internal change to use ordering for variables instead of hashing to speed up prefix matching. 06-06-13 A window between fork/exec in which a signal could get lost and cause a program to hang has been eliminated 06-06-13 A bug in edit completion with quoted strings has been fixed. 06-06-07 The restricted options can now be enabled by set as well as on the command line. Once set, it can not be disabled. 06-06-04 Modified built-in binding so that for systems for which /bin and /usr/bin are the same, a builtin bound to /bin will get selected when either /bin or /usr/bin is scanned. 06-06-04 +Added literal-next character processing for emacs/gmacs mode. This change is not compatible with earlier versions of ksh93 and ksh88 when the stty lnext is control-v. The sequence escape-control-v will display the shell version. 06-05-31 +Modified emacs and vi mode so that entering a TAB after a partial TAB completion, generates a listing of possible completions. After the second TAB, a number followed by a TAB will perform the completion with the corresponding item. 06-05-19 +Modified arithmetic so that conversions to strings default to the maximum number of precision digits. 06-05-16 Bug fixes for multibyte locales. 06-05-10 The =~ operator was added to [[ ... ]] and [[ string ~= ERE ]] is equivalent to [[ string == ~(E)ERE ]]. 06-04-25 A bug in the vi edit mode which could cause the shell to core dump when switching from emacs mode. 06-04-17 A bug in which using LANG or LC_ in assignment lists with builtins did not restore the locale correctly has been fixed. 06-04-04 A bug in which discipline functions could not be added to variables whose names started with .sh has been fixed. 06-03-28 +The -s option to typeset was added to modify -i to indicate short integers. 06-03-28 A bug in which variables assignment lists before functions defined with function name were not passed on the functions invoked by this function has been fixed. 06-03-28 A bug in which name references defined within a function defined with function name could not be used with compound variables has been fixed. 06-03-27 A bug in which read <&p (print >&p) would cause the coprocess input (output) pipe to close before reading from (after writing to) it has been fixed. 06-02-28 A bug in which stopping a job created with the hist builtin command would create a job that could not be restarted has been fixed. 06-01-24 --- Release ksh93r --- 06-01-24 A bug in which running commands with standard output closed would not work as expected has been fixed. 06-01-23 A bug in which print -u could fail when file descriptor was open for writing has been fixed. 06-01-19 The ?: arithmetic operator fixed to work when the operation after the colon was an assignment. 05-12-24 A bug which could lead to a core dump when elements of a compound variable were array elements, i.e. foo=(bar=(1 2)), has been fixed. 05-12-13 An arithmetic bug in which x+=y+=z was not working has been fixed. 05-12-13 An arithmetic bug in which x||y was returning x when x was non-zero rather than 1 has been fixed. 05-12-07 +The aliases for integer and float have been changed to use attributes -li and -lE to handle long long and long double types. 05-12-07 +The histexpand (-H) option has been added which allows C-shell style history expansions using the history character !. 05-12-07 +The multiline option was added which changes that way the edit modes handle lines longer than the window width. Instead of horizontal scrolling, multiple lines on the screen are used. 05-12-05 The whence builtin now returns an absolute pathname when the command is found in the current directory. 05-11-29 A bug which caused ksh -c '[[ ! ((' to core dump rather than report a syntax error has been fixed. 05-11-29 A bug when reading fixed length records into typeset -b variables which caused a zero byte to terminate the value has been fixed. 05-11-22 +The ability to seek to an offset within a file has been added with the new I/O redirection operators, <# and >#. Currently, these redirection operators must be followed by ((expr)) but in a future release, it should be able to used to seek forward to the specified shell pattern. In addition $(n<#) expands to the current byte offset for file descriptor n. 05-11-22 +The .sh.match array variable is now set after each [[ ... ]] pattern match. Previously it was only set for substring matches. 05-10-17 A bug in which the library path variable could be prefixed with a directory when a .path file was not encountered in the directory of the executable has been fixed. 05-09-15 A for/while loop optimizer bug in which $OPTIND was not correctly expanded has been fixed. 05-09-05 A bug in which a history command that invoked a history command could go into an infinite loop has been fixed. 05-08-31 +In the case that IFS contains to adjacent new-lines so that new-line is not treated as a space delimiter, only a single new-line is deleted at the end of a command substitution. 05-08-19 +When a tilde expansion expands to the / directory and is followed by a /, it is replaced by the empty string. 05-08-16 A bug in which n<&m did not synchronize m has been fixed. 05-08-16 A bug in which process substitution ( <() and >() ) was not working within for and while loops has been fixed. 05-07-24 A bug in which the pattern ~(E)(foo|bar) was treated as a syntax error has been fixed. 05-07-24 A bug in completion with =, where n was the one of the previous selection choices has been fixed. 05-07-21 A bug with multibyte input when no edit mode was specified which caused the input line to shift left/right has been fixed. 05-06-24 A race condition which could cause the exit status to get lost on some fast systems has been fixed. 05-06-21 A bug in which nested patterns of the form {m,n}(pat) would cause syntax errors has been fixed. 05-06-21 A bug in the macro expander has been fixed which could cause a syntax error for an expansion of the form ${x-$(...)} when x is set and the command substitution contained certain strings. 05-06-08 +On systems for which echo does not do System V style \ expansions, the -e option was added to enable these expansion. 05-06-08 A bug in which ${var op pattern} to not work when inside an arithmetic expression has been fixed. 05-05-23 +An extension to shell patterns that allows matching of nested groups while skipping over quoted strings has been added. 05-05-18 A bug in which the line number for errors was not correct for functions loaded from FPATH has been fixed. 05-04-18 A bug in which the exit status $? is not set when a trap triggered by the [[ ... ]] command is executed has been fixed. 05-04-08 +Redirection operators can be directly preceded with {varname} with no intervening space, where varname is a variable name which allows the shell to select a file descriptor > 10 and store it into varname. 05-04-08 +SHOPT_CMDLIB_BLTIN=1 now includes generated table. 05-04-07 +[[ -o ?option ]] is true if "option" is a supported option. 05-04-05 A bug in handling file completion with spaces in the names has been fixed. 05-03-25 +The SIGWINCH signal is caught by default to keeps the LINES and COLUMNS variables in sync with the actual window size. 05-03-25 +Building ksh with SHOPT_REMOTE=1 causes ksh to set --rc if stdin is a socket (presumably part of a remote shell invocation.) 05-03-25 +Building ksh with SHOPT_SYSRC=1 causes interactive ksh to source /etc/ksh.kshrc (if it exists) before sourcing the $ENV file. 05-03-25 +{first..last[..incr][%fmt]} sequences added to brace expansions when braceexpand is enabled. 05-03-03 A bug where a SIGCHLD interrupt could cause a fifo open to fail has been fixed. 05-02-25 A bug in which a builtin command run in the background could keep a file descriptor open which could cause a foreground process to hang has been fixed. 05-02-24 A bug where builtin library commands (e.g., date and TZ) failed to detect environment variable changes has been fixed. 05-02-22 +The read builtin and word splitting are now consistent with respect to IFS -- both treat IFS as field delimiters. 05-02-22 +The read builtin no longer strips off trailing delimiters that are not space characters when there are fewer variables than fields. 05-02-17 A builtin bug on systems where dlsym(libcmd) returns link-time bindings has been fixed. 05-02-12 A bug in which the lib_init() function for .paths BUILTIN_LIB libraries was not called has been fixed. 05-02-06 A bug on some systems in which moving the write end of a co-process to a numbered file descriptor could cause it to close has been fixed. 05-02-06 A bug in the vi-edit mode in which the character under the cursor was not deleted in some cases with the d% directive has been fixed. 05-02-06 A bug where external builtin stdout/stderr redirection corrupted stdout has been fixed. 05-02-04 A bug where times formatting assumed CLK_TCK==60 has been fixed. 05-01-11 --- Release ksh93q --- 05-01-11 A bug in the integral divide by zero check has been fixed. 05-01-11 +The -l option has been added to read /etc/profile and $HOME/.profile, if they exist, before the first command. 05-01-11 An argument parsing bug that caused `kill -s x -- n' to fail has been fixed. 05-01-11 +The .paths file, introduced in ksh93m, which can appear in any directory in PATH, now allows a line of the form 'BUILTIN_LIB=.' When a command is searched for this directory, and the full path matches the path of the built-in version of the command (listed by the 'builtin' command) then the built-in version of the command is used. When ksh is built with SHOPT_CMDLIB_DIR=1 then all libcmd functions become builtins with the '/opt/ast/bin/' directory prefix. 05-01-10 A bug in which a nameref to a compound name caused a core dump has been fixed. 05-01-09 A bug in which some SIGCHLD interrupts (from child processes exiting) caused a fatal print/echo error diagnostic has been fixed. 04-12-24 A bug in which some SIGCHLD interrupts (from child processes exiting) corrupted the internal process/job list, sometimes causing the shell to hang, has been fixed. 04-12-01 A bug in which typeset -Fn truncated less than n digits for large numbers has been fixed. 04-11-25 A bug in which standard error could be closed after a redirection to /dev/stderr has been fixed. 04-11-17 A bug in which an expansion of the form ${array[@]:3} could expand to ${array[0]} when ${array[3]} was not set has been fixed. 04-10-22 +The -E or -orc command line option reads ${ENV-$HOME/.kshrc} file. 04-10-22 +`-o foo' equivalent to `+o nofoo', `-o nobar' equivalent to `+o bar'. `--foo' equivalent to `-o foo', `--nofoo' equivalent to `+o foo' 04-10-05 +The .paths file, introduced in ksh93m, which can appear in any directory in PATH, now allows a line of the form 'BUILTIN_LIB=libname'. When a command is searched for this directory, the shared library named by libname will first be searched for a built-in version of the command. 04-09-03 <<< here documents now handle quotes in the word token correctly. 04-08-08 +The maximum size for read -n and read -N was increased from 4095 to 32M. 04-08-04 +printf %q was modified so that if an no operand was supplied, no no output would be generated rather than a quoted empty string. 04-08-01 +The -n and -N options of the read builtin has been modified when reading variables with the binary attribute so that the data is stored directly rather than through assignment. 04-08-01 +The shcomp command has been modified to process alias commands under some conditions. 04-07-31 +The .sh.match variable added in ksh93l, now works like other indexed arrays. 04-07-08 A loop optimizer bug which occurs when typeset is used in a for or while loop inside a function has been fixed. 04-06-24 +The number of subexpressions in a pattern was increased to 64 from the current number of 20. 04-06-17 +The -t option to read was modified to allow seconds to be specified as any arithmetic expression rather than just an integral number of seconds, for example even -t 'sin(.5)' is now valid. 04-06-16 Two small memory leak problems were fixed. 04-06-15 A bug in ${var/pattern/"string"} which occurred when string contained pattern matching characters has been fixed. 04-05-08 printf $'%d\n' produced an erroneous error message and has been fixed. 04-05-24 A bug in which an associative array without any elements could cause a core dump when a script with an associative array with the same name was declared in a script invoked by name has been fixed. 04-05-11 A bug in which an exec statement could close the script that is being processed in a script that is run by name causing a failure has been fixed. 04-04-28 +If the first character of assignment to an integer variable was 0, the variable had been treated as unsigned. This behavior was undocumented and has been removed. 04-04-05 A bug in which the positioning of standard input could be incorrect after reading from standard input from a subshell has been fixed. 04-03-30 A bug in the for loop optimizer which in rare cases could cause memory corruption has been fixed. 04-03-29 +The preset alias source='command .' has been added. 04-03-29 A bug introduced in ksh93p on some systems in which invoked by name with #! on the first line would not get the signals handling initialized correctly has been fixed. 04-03-29 A bug introduced in ksh93p in which a HUP signal received by a shell that is a session group leader was not passed down to its children has been fixed. 04-02-28 --- Release ksh93p --- 04-02-28 +The ability to apply an append discipline to any variable has been added. 04-02-14 A bug in which the exportall option (set -a) would cause incorrect results for arrays has been fixed. 04-02-02 A bug in which an exported array would pass more than the first element to a script invoked by name has been fixed. 04-02-02 A bug on some systems in which name=value pairs preceding a script invoked by name was not getting passed to the script has been fixed. 04-01-20 A bug in which an unset discipline function could cause a core dump on some systems has been fixed. 04-01-12 A bug in which a continue or break called outside a loop from inside a function defined with name() syntax could affect the invoking function has been fixed. 04-01-08 If a command name begins with ~, only filename completion will be attempted rather than pathname completion using the builtin editors. 04-01-08 A bug in the vi edit mode in which the wrong repeat count on multiple word replacements with the . directive has been fixed. 04-01-06 Backspace characters are now handled correctly in prompt strings. 04-01-06 +The getopts builtin has been modified to accept numerical arguments of size long long on systems that support this. 04-01-06 A bug in which unsetting all elements of an associative array would cause it to be treated as an indexed array has been fixed. 03-12-15 A bug in which a quoted string ending with an unescaped $ would delete the ending $ in certain cases has been fixed. 03-12-05 A bug in which the shell could hang when set -x tracing a command when an invalid multibyte character is encountered has been fixed. 03-12-05 On some systems, if the KEYBD trap is set, then commands that use the meta key were not processed until return was hit. This has been fixed. 03-12-05 A problem which occurred when the login shell was not a group leader that could cause it to fail has been fixed. 03-12-05 A problem in which a shell could core dump after receiving a signal that should cause it to terminate while it was in the process of acquiring more space has been fixed. 03-12-05 +If ENV is not specified, the shell will default to $HOME/.kshrc for interactive shells. 03-11-21 A bug introduced in ksh93o in which the DEBUG trap could get disabled after it triggered has been fixed. 03-11-04 A bug in which using arithmetic prefix operators ++ or -- on a non-lvalue could cause a core dump has been fixed. 03-11-04 A bug in which leading zeros were stripped from variable expansions within arithmetic computation to avoid being treated as octal constants when they should not have, has been fixed. 03-10-08 A bug introduced in ksh93o in which a large here document inside a function definition could get corrupted has been fixed. 03-09-22 A bug in which the .get discipline function was not being called when a string variable was implicitly referenced from within a numerical expression has been fixed. 03-09-22 A bug in which a script without a leading #! could get executed by /bin/sh rather than the current shell on some systems has been fixed. 03-09-12 +To improve conformance with ksh88, leading zeros will be ignored when getting the numerical value of a string variable so that they will not be treated as octal constants. 03-09-03 +The builtin kill command now processes obsolete invocations such as kill -1 -pid. 03-09-02 The restriction on modifying FPATH in a restricted shell (sh -r) has been documented. 03-09-02 +The restricted shell (sh -r) has been modified to disallow executing command -p. 03-08-07 A bug in which the KEYBD trap was not being invoked when characters with the 8th bit set has been fixed. 03-08-02 A parser bug introduced in ksh93o which caused the character after () in a POSIX function definition to be skipped when reading from standard input has been fixed. 03-08-01 A bug in which "${foo#pattern}(x)" treated (x) as if it were part of the pattern has been fixed. 03-08-01 +The command -x option has been modified so that any trailing arguments that do expand to a single word will be included on each invocation, so that commands like command -x mv * dir work as expected. 03-07-20 --- Release ksh93o+ --- 03-07-20 A bug in which could cause memory corruption when a POSIX function invoked another one has been fixed. 03-07-15 A bug in which a file descriptor>2 could be closed before executing a script has been fixed. 03-07-15 A parsing error for <() and >() process substitutions inside command substitution has been fixed. 03-07-15 A parsing error for patterns of the form {...}(...) when used inside ${...} has been fixed. 03-07-15 An error in which expanding an indexed array inside a compound variable could cause a core dump has been fixed. 03-07-15 A bug in which on rare occasions a job completion interrupt could cause to core dump has been fixed. 03-06-26 A bug in which process substitution embedded within command substitution would generate a syntax error has been fixed. 03-06-23 A bug in which ${@:offset:len} could core dump when there were no arguments has been fixed. 03-06-23 A bug in which ${X[@]:offset:len} could core dump when X was unset has been fixed. 03-06-22 +The -x option was added to the command builtin. If this option is on, and the number of arguments would exceed ARG_MAX, the command will be invoked multiple times with a subset of the arguments. For example, with alias grep='command -x grep, any number of arguments can be specified. 03-06-14 A bug in which could cause a core dump on some systems with vi and emacs editors with the MULTIBYTE option has been fixed. 03-06-06 A bug in which the shell could core dump when a script was run from its directory, and the script name a symlink to a file beginning with .., has been fixed. 03-06-05 A bug in which the shell could core dump when a child process that it is unaware of terminates while it is calling malloc() has been fixed. 03-06-02 +An option named globstar (set -G) has been added. When enabled, during pathname expansion, any component that consists only of ** is matches all files and any number of directory levels. 03-05-30 A bug in which the PATH search could give incorrect results when run from directory foo and PATH contained .:foo:xxx has been fixed. 03-05-29 +Some changes were made to the code that displays the prompt in edit mode to better handle escape sequences in the prompt. 03-05-27 I added = to the list of characters that mark the beginning of a word for edit completion so that filenames in assignments can be completed. 03-05-20 A bug in which read -N could hang on some systems when reading from a terminal or a pipe has been fixed. 03-05-19 A bug in which the output of uname from a command substitution would go to the standard output of the invoking command when uname was invoked with a non-standard option has been fixed. 03-05-19 A job control bug which would cause the shell to exit because it hadn't taken back the terminal has been fixed. The bug could occur when running a function that contained a pipeline whose last element was a function. 03-05-19 A job control timing bug introduced in ksh93o on some systems which could cause a pipeline to hang if the first component completed quickly has been fixed. 03-05-13 +The read builtin has been modified so that the builtin editors will not overwrite output from a previous incomplete line. 03-05-13 A bug in which the name of an identifier could have the string .sh. prefixed to it after expanding a variable whose name begins with .sh. has been fixed. 03-05-13 A bug in the expansion of $var for compound variables in which some elements would not be output when the name was a prefix of another name in the compound variable has been fixed. 03-05-08 The last item in the ksh93o release on 03-01-02 has been altered slightly to preserve the leading 0's when the preceding character is a digit. Thus, with typeset -LZ3 x=10, $(( 1$x)) will be 1010 whereas $(( $x) will be 10. 03-04-25 A bug in which if x is a name reference, then nameref y=x.foo did not follow x has been fixed. 03-03-18 --- Release ksh93o --- 03-03-18 +A -N unary operator was added to test and [[ ... ]] which returns true if the file exists and the file has been modified since it was last read. 03-03-18 +The TIMEFORMAT variable was added to control the format for the time compound command. The formatting description is described in the man page. 03-03-06 +A -N n option was added to read which causes exactly n bytes to be read unlike -n n which causes at most n bytes to be read. 03-03-03 +Three new shell variables were added. The variable .sh.file stores the full pathname of the file that the current command was found in. The variable .sh.fun names the current function that is running. The variable .sh.subshell contains the depth of the current subshell or command substitution. 03-03-03 +When the DEBUG trap is executed, the current command line after expansions is placed in the variable .sh.command. The trap is also now triggered before each iteration of a for, select, and case command and before each assignment and redirection. 03-02-28 +Function definitions are no longer stored in the history file so that set -o nolog no longer has any meaning. 03-02-28 +All function definitions can be displayed with typeset -f not just those stored in the history file. In addition, typeset +f displays the function name followed by a comment containing the line number and the path name for the file that defined this function. 03-02-28 A bug in which the value of $LINENO was not correct when executing command contained inside multi-line command substitutions has been fixed. 03-02-19 +Since some existing ksh88 scripts use the undocumented and unintended ability to insert a : in front of the % and # parameter expansion operators, ksh93 was modified to accept :% as equivalent to % and :# as equivalent to # with ${name op word}. 03-02-14 A bug which could cause a core dump when reading from standard error when standard error was a pty has been fixed. 03-02-14 +The shell arithmetic was modified to use long double on systems that provide this data type. 03-02-09 A bug in which a function located in the first directory in FPATH would not be found when the last component of PATH was . and the current directory was one of the directories in PATH has been fixed. 03-02-07 +The trap and kill builtin commands now accept a leading SIG prefix on the signal names as documented. 03-02-05 A bug in the expansion of ${var/$pattern}, when pattern contained \[ has been fixed. 03-02-05 A bug in which .sh.match[n], n>0, was not being set for substring matches with % and %% has been fixed. 03-01-15 A bug in which getopts did not work for numerical arguments specified as n#var in the getopts string has been fixed. 03-01-09 A bug in which using ${.sh.match} multiple times could lead to a memory exception has been fixed. 03-01-06 A bug in the expansion of ${var/pattern/$string} in the case that $string contains \digit has been fixed. 03-01-02 +A -P option was added for systems such as Solaris 8 that support profile shell. 03-01-02 For backward compatibility with ksh88, arithmetic expansion with ((...)) and let has been modified so that if x is a zero-filled variable, $x will not be treated as an octal constant. 02-12-05 --- Release ksh93n+ --- 02-11-30 A bug that can show up in evaluating arithmetic statements that are in an autoloaded function when the function is autoload from another function has been fixed. 02-11-30 An optimization bug in which an expansion of the form ${!name.@}, which occurred inside a for or a while loop, when name is a name reference, has been fixed. 02-11-18 A bug in which modifying array variables in a subshell could leave side effects in the parent shell environment has been fixed. 02-11-18 A memory leak when unsetting an associative array has been fixed. 02-11-14 +The code to display compound objects was rewritten to make it easier for runtime extensions to reuse this code. 02-11-14 +A change was made to allow runtime builtins to be notified when a signal is received so that cleanup can be performed. 02-10-31 +User applications can now trap the ALRM signal. Previously, the ALRM signal was used internally and could not be used by applications. 02-10-31 A bug in which signals received while reading from a coprocess for which traps were set was not handled correctly has been fixed. 02-10-31 A bug in which a file opened with exec inside a subshell could be closed before the subshell completed has been fixed. 02-10-21 A bug in which setting PATH or FPATH inside a function might not take effect has been fixed. 02-10-21 A bug which could cause a core dump when a local SECONDS variable is defined in a function has been fixed. 02-10-15 A bug in which the associative array name operator ${!array[@]} could return the same name multiple times has been fixed. 02-10-15 A bug in which the zero'th element of an associative array was not getting set when an assignment was made without a subscript specified has been fixed. 02-09-30 --- Release ksh93n --- 02-09-30 +The maximum indexed array size was increased to 16Megs. 02-09-30 A bug which could cause a core dump when changing attributes of associative array has been fixed. 02-09-30 A bug in which exporting an array variable would not export the 0-th element has been fixed. 02-09-30 A bug in which an array assignment of the form a=($a ...) would unset 'a' before the right hand side was evaluated has been fixed. 02-09-27 A bug in which the error message for ${var?message} when var was null or unset did not contain the variable name var has been fixed. 02-09-27 A bug in which closing file descriptors 0 through 2 could cause a subsequent here document to fail has been fixed. 02-09-14 A bug in whence which occurs when the specified name contained a / has been fixed. 02-09-14 A bug in the parser for strings of the form name$((expr))=value has been fixed. 02-09-14 A for loop optimization bug in which the number of elements in an array was treated as an invariant has been fixed. 02-09-09 A bug in which redirection or closing of a file descriptor between 3 and 9 could cause a subsequent here document to fail has been fixed. 02-09-09 A bug in which a background job was not removed from the job list when a subshell completed has been fixed, for example (prog&). 02-09-03 A bug in which an assignment of the form name=(integer x=3) could be interpreted as an array assignment rather than a compound variable assignment has been fixed. 02-08-19 A command completion bug which occurred on file systems that are case insensitive has been fixed. 02-08-19 A bug which could lead to an exception on some systems (for example FREEBSD) which occurred when setting PATH has been fixed. 02-08-11 A bug in arithmetic rounding in which a value input as a decimal string would output as a rounded version of the string has been fixed. 02-08-11 A bug in which the last character could be deleted from shell traces and from whence when called from a multibyte locale has been fixed. 02-08-01 A bug which could cause a core dump to occur when a shell script is executed while a coprocess is running that has closed the output pipe has been fixed. 02-08-01 A bug in which command completion in multibyte mode could corrupt memory for long command lines has been fixed. 02-06-17 --- Release ksh93n- --- 02-06-17 A bug in which user defined macros could cause a core dump in with MULTIBYTE mode has been fixed. 02-06-17 A bug in which printf format specifiers of the form %2$s were causing a core dump has been fixed. 02-06-17 A bug in which setting stty to noecho mode did not prevent the echoing of characters by ksh when emacs or viraw mode was enabled has been fixed. 02-06-17 A bug in which background job completion could cause the sleep builtin to terminate prematurely has been fixed. 02-06-17 A bug in which the shell could core dump if getopts was called when the OPTIND variable contained a negative value has been fixed. 02-06-10 +The edit mode prompt has been modified to handle escape sequences. 02-06-10 A bug which occurred for interactive shells in which the builtin cat command was used in command substitution on a file whose size was larger than PIPE_BUF has been fixed. 02-06-10 A bug in which the trap on ERR was not being processed when set inside a function has been fixed. 02-06-07 A bug in which function definitions could cause the history count to be decremented by one (and even become negative) has been fixed. 02-06-05 A bug in read in which share mode could be enabled has been fixed. 02-05-28 A bug which could occur when the last command of a script was a case statement and the action selected ended in ;& instead of ;; has been fixed. 02-05-23 A bug with unary + introduced in ksh93k has been fixed. 02-05-07 A bug in substitutions of the form ${var/pattern/string} in which a backslash was inserted in the replacement string when it contained a special pattern character has been fixed. 02-05-01 A bug in the emacs edit mode which occurred in versions compiled for multibyte character sets which occurred when a repeated search was requested after a long line had been returned for the previous search has been fixed. 02-04-02 +vi and emacs edit modes were modified so that tab completion is disabled when invoked from the read built-in. 02-03-26 --- Release ksh93m+ --- 02-03-26 A bug in which \ was not handled correctly when used in file expansion has been fixed. 02-02-18 A bug in which lines beginning with a # were deleted from here documents when the here-document delimiter was followed by a comment has been fixed. 02-12-06 An optimization bug in which ${!x[@]) was treated as invariant in a for loop has been fixed. 02-02-06 A bug in which the ERR trap is not cleared for a script invoked by name from within a function has been fixed. 02-01-08 A bug in which a shell script executed from within a subshell could cause this script to have an invalid pointer leading to a memory fault has been fixed. 02-01-07 +Added here documents of the form <<< word (as per zsh) which is equivalent to << delim\nword\ndelim. 02-01-07 A bug in which the first word of a compound assignment, x=(word ...), was treated as a reserved word has been fixed. 02-01-07 A bug in the handling of \ when noglob was enabled and a substitution of the form ${word op pattern} occurred in the same word has been fixed. 02-01-07 +A compilation option, CMDLIB_BLTIN in the file OPTION, has been added. When this options is set, all commands implemented in libcmd become shell builtin commands by default. 02-01-07 A bug in which builtin foo, where foo is already a builtin would result in the builtin foo getting removed has been fixed. 02-01-07 A bug which the shell executed a command found in the current directory when PATH have no valid directories has been fixed. 01-11-28 The value of $? was not being set when called with exit. 01-11-28 If the last command was of the form (...) and a trap on EXIT or ERR was set, and the command inside () modified the trap, then the original trap wasn't executed. 01-11-26 +The value for 0 is now preceded by the base number when the base was not 10. 01-11-26 +The default compilation mode has been changed so that viraw mode will always be on. 01-10-31 --- Release ksh93m --- 01-10-31 A for loop optimizer bug for subshells contained within for loops has been fixed. 01-10-16 typeset without arguments no longer outputs variable names that do not have any attributes that are set. 01-10-16 A bug introduced in ksh93l in which assignments specified with the exec built-in were not being expanded properly has been fixed. 01-10-11 An optimization bug in which ${!x) was treated as invariant in a for loop has been fixed. 01-10-11 Unsigned integer variables in bases other than 10 are printed now expand in that base with the base prefix. 01-10-10 A number of typos in the self generating man pages for shell built-ins have been fixed. 01-10-04 The self generated man pages for hist and fc were not working correctly and have been fixed. 01-10-03 Yet another optimizer bug in which shell patterns were treated as invariants has been fixed. 01-09-27 Two bugs relating to multibyte history searches and to find have been fixed. 01-09-27 A bug introduced in ksh93k in which the PATH searching was not restored after running a command with an assignment list has been fixed. 01-09-26 A bug in which a zero filled field was treated as octal when converted to integer has been fixed. 01-09-26 Yet another bug in the optimization of for loops related to recursive functions with break or continue statements has been fixed. 01-09-25 +The exponentiation operator ** was added to the shell arithmetic evaluation. It has higher precedence than * and is left associative. 01-09-25 The code was modified to use the AST multibyte macros and functions for handling multibyte locales. 01-09-25 +The expansion ${parameter:offset:length} now handles negative offsets which cause offsets to be measured from the end. 01-09-25 Some spelling errors in the documentation were corrected. 01-09-24 +The /dev/tcp/host/port and /dev/udp/host/port now allow the ports to be specified by service name. 01-09-24 +The change starting with ksh93g in which the appropriate library path variable is prepended with a corresponding library directory has been modified. With the new method, only the library path defined in the file named .paths in the directory where the executable is found will be modified. See the man page for more details. 01-09-23 +The .fpath file (see ksh93h) is no longer looked for in each directory on the path to locate function directories. The file named .paths is used instead. 01-09-23 A bug in which IFS was not being restored after being changed in a subshell has been fixed. 01-09-16 +With the vi and emacs edit modes, after a list of command or functions is generated with = or M-= respectively, any element from the list can be pasted on the command line by preceding the = or M-= with a numeric parameter specifying the position on the list. 01-09-16 A bug in ksh93l caused command completion not to find aliases and functions. Command listing from the edit mode was presented in reverse order. This has been fixed. 01-09-13 Another bug in the optimization of for loops related to subshells when traps were set has been fixed. 01-09-07 A change in ksh93l caused brace expansion to stop working and this has been fixed. 01-09-04 A bug introduced in ksh93k in which an arithmetic statement within a function that used name references did not follow the reference has been fixed. 01-09-04 A bug introduced in ksh93l in which export -p did not prefix each export with the word export has been fixed. 01-08-29 A bug in multibyte input which occurred when a partial multibyte character was received has been fixed. 01-08-29 A bug introduced in ksh93l which could cause a core dump when an assignment list containing PATH is specified inside command substitution has been fixed. 01-08-09 Another bug in the optimization of for loops in ksh93l caused errors in recursive functions using local variables that contained for loops has been fixed. 01-07-27 A bug in which IFS would be unset after a command substitution inside a here document has been fixed. 01-07-26 To conform to the POSIX standard, if you invoked ksh name, and name does not contain a /, it will first try to run one in the current directory whether it is executable or not before doing a path search for an executable script. Earlier versions first checked for an executable script using the PATH variable. 01-07-23 A bug in which unset -f invoked in a subshell could unset a function defined in the parent has been fixed. 01-07-16 A bug in the optimization of for loops in ksh93l caused name references to be treated as invariants has been fixed. 01-07-09 A bug in which a discipline function applied to a local variable could cause a shell exception has been fixed. Discipline functions can only be specified for global variables. 01-06-18 --- Release ksh93l --- 01-06-18 A bug in assigning integers larger than can be represented as long integers to floating point variables has been fixed. 01-06-18 A bug in the handling of unsigned integers (typeset -ui) has been fixed. 01-06-04 The evaluation of the PS1 prompt no longer affects the value of the $? variable. 01-06-01 A small memory leak from subshells has been fixed. 01-05-22 A bug in which attributes for variables that did not have values would be lost after a subshell has been fixed. 01-05-22 +The %R format has been added to convert a shell pattern into an extended regular expression. 01-05-22 +The escape sequences \e, \cX, \C[.collating-element.], and \x{hex} have been added to ASCII-C strings and to printf format strings. 01-05-20 +Patterns of the form {n}(pattern) and {m,n}(pattern) are now recognized. The first form matches exactly n of pattern whereas, the second form matches from m to n instances of pattern. 01-05-20 +The shell allows *-(pattern), +-(pattern), ?-(pattern), {m,n}-(pattern}, and @-(pattern) to cause the minimal match of pattern to be selected whenever possible rather than the maximal (greedy) match. 01-05-20 +The character class [:word:] has been added to patterns. The word class is the union of [:alnum:] and the character _. 01-05-20 +Inside (...) pattern groups, the \ character is now treated specially even when in an enclosing character class. The sequences, \w, \d, \s are equivalent to the character classes word, digit, and space respectively. The sequences \W, \D, and \S are their complement sets. 01-05-20 +The shell now recognizes pattern groups of the form ~(options:pattern) where options or :pattern can be omitted. Options use the letters + and - to enable and disable options respectively. The option letters g (greedy), i (ignore case) are used to cause maximal matching and to cause case insensitive matching respectively. If :pattern is also specified, these options are only in effect while this pattern is being processed. Otherwise, these options remain in effect until the end of the pattern group that they are contained in or until another ~(...) is encountered. These pattern groups are not counted with respect to group numbering. 01-05-14 When edit completion, expansion, or listing occurs in the middle of a quoted string, the leading quote is ignored when performing the completion, expansion, or listing. 01-05-14 A small memory leak from subshells has been fixed. 01-05-10 A bug in which open files were not restored after a subshell that had used exec to replace a file has been fixed. 01-05-10 +Redirection to a null file name now generates an error message. 01-05-09 The shell now rejects some invalid parameter substitutions that were previously processed in undefined ways. 01-05-09 A bug in which the output of select was not flushed before the read when input did not come from the terminal has been fixed. 01-05-08 A bug in which job IDs would not be freed for interactive shells when subshells ran built-ins in the background has been fixed. 01-05-08 +The FPATH variable now requires an explicit . to cause the current directory to be treated as a function directory. 01-05-08 A bug in read -n when echo mode was disabled has been fixed. 01-05-07 A bug in which function definitions could be listed as part of the history has been fixed. 01-04-30 +This release uses a new and often much faster pattern matcher than earlier releases. 01-04-30 +An optimizer now eliminates invariant parameter expansions from for while and until loops. 01-04-30 +The variable .sh.match is set after each pattern match (# % or /) in a variable substitution. The variable .sh.match is an indexed array with element 0 being the complete match. The array is only valid until the next subsequent pattern match or until the value of the variable changes which ever comes first. 01-04-30 +A self generating man page has been added to shcomp. Also, shcomp now stops compiling when it finds an exit or exec command and copies the remainder so that it can be used for standard input. 01-04-30 +The shcomp command was modified so that it can work in an EBCDIC environment and that binary scripts are portable across environments. 01-04-30 A bug in the handling of a trailing : in PATH has been fixed. 01-04-30 A bug in which the builtin version of a command would get invoked even though the full pathname for the command was specified has been fixed. 01-04-30 A bug in which read would lose the last character when reading the last line of a file that did not contain a new-line character has been fixed. 01-04-23 A bug on some systems in which in vi mode the end of file character and end of line character could be swapped has been fixed. 01-04-23 A bug on some systems in which invoking a shell script that did not have execute permission could set the exit value to 127 rather than 126 has been fixed. 01-04-20 A bug in which read -n from a pipe would block if fewer than n characters was received has been fixed. 01-04-09 A bug in which invalid patterns, for example, ) by itself, was not treated as a string has been fixed so that if i=')', then [[ $i == $i ]] is true. 01-04-09 +The shell arithmetic now interprets C character constants. 01-04-09 A bug in which a non-zero return from a function defined with the function reserved word did not trigger the ERR trap or exit with set -e has been fixed. 01-04-02 A bug on some systems, in which characters above 127 were not displayed correctly in vi or emacs edit mode has been fixed. 01-04-02 A bug on some systems, introduced in the 'k' point release, in which the erase character in viraw mode was moving the cursor to the left without erasing the character has been fixed. 01-04-02 On some systems the wcwith() function was returning a wrong value for characters and caused characters to be displayed incorrectly from the shell edit modes. A work around for this problem has been added. 01-03-26 A bug in which valid scripts could produce syntax errors when run with locales that considered characters such as "'" to be space characters has been fixed. 01-03-20 A bug in which an syntax error in an arithmetic expression entered interactively could cause the shell to go into an infinite loop outputting the error message has been fixed. 01-03-10 +ksh93 accepts -l as a synonym for -L in test on systems for which /bin/test -l tests for symbolic links. 01-03-10 A bug in parsing scripts in which { and } are used in place of in and esac in case statements embedded in compound commands has been fixed. Use of { and } for in and esac is obsolete. 01-03-06 A bug in which an argument of the form foo=bar was not being passed correctly to a traced function whose name was foo has been fixed. 01-03-02 Using $(trap -p name) did not print the name of the current trap setting for trap name. 01-02-26 Exported floating point variables gave incorrect results when passing them to ksh88. This has been fixed. 01-02-25 A race condition in which a coprocess which completed too quickly would not allow subsequent coprocesses to start has been fixed. 01-02-25 The 'g' format specifier is now handled by printf. It had inadvertently been omitted. 01-02-20 The + was not being displayed during an execution trace with the += assignment operator. 01-02-19 The error message which occurs when the interpreter name defined on the #! line does not exist is more informative. 01-02-19 A bug in which $0 would not be set correctly when a script with #! was invoked by full pathname from the directory of the script has been fixed. 01-02-19 A shell script did not always pick up tty mode changes made by external commands such as stty which could affect the behavior of read. 01-02-19 The -u, -g, and -k unary tests did not give the correct results when used with negation and this has been fixed. 01-02-05 --- Release ksh93k+ --- 01-02-05 The sequence \ inside $'...' was not incrementing the line count and this has been fixed. 01-02-05 +Modified expansion of "${@-}" so that if no arguments are set it results in null string rather than nothing. 01-02-02 memory leak problem with local variables in functions fixed. 01-01-25 +allow arithmetic expressions with float%int and treat them as ((int)float)%int rather than as an error. 01-01-19 read -n1 was not working and has been fixed. 01-01-17 +ksh now handles the case in which a here document in command substitution $() is terminated by the trailing ). Previously, a new-line was needed at the end of the delimiter word. 01-01-02 A bug in which a KEYBD trap would cause a multi-line token to be processed incorrectly has been fixed. 00-12-10 +Arithmetic integer constants can now have L and U suffices. 00-12-10 A bug in the processing of arithmetic expressions with compound variables when the -n option is on has been fixed. 00-12-08 A bug in M-f and M-b from emacs mode has been fixed. This bug only occurs when ksh93 is compiled without MULTIBYTE enabled. 00-11-29 A bug in which jobs -p would yield 0 for background jobs run in a script has been fixed. 00-11-21 A bug in integer arrays in which the number of elements is incorrect when the ++ operator is applied to a non-existing element has been fixed. For example, integer x; ((x[3]++)). 00-11-20 A timing bug in which the shell could reset the terminal group to the wrong value in the case that the a new process changes the terminal group during startup has been fixed. 00-10-27 --- Release ksh93k --- 00-10-27 Using tab for completion now works only when applied after a non-blank character at the end of the current line. In other case a tab is inserted. 00-10-27 A bug in the emacs edit mode for ^X^E has been fixed. The ^X^E sequence is supposed to invoke the full editor on the current command. 00-10-18 A bug in which expansions of the form ${var//pattern/string} did not work correctly when pattern was '/' or "/" has been fixed. 00-10-18 +The output format for indexed arrays in compound variables has been modified so that it can be used as input. 00-10-18 Assignments with name references (typeset -n) will now implicitly unreference an existing name reference. 00-10-17 A bug the += append operator when a single array element is appended to a variable that is not an array has been fixed. 00-10-16 A bug in which the SIGCONT signal was being sent to each process will kill -0 or kill -n 0 has been fixed. 00-10-12 +The arithmetic evaluation portion has been rewritten to perform a number of optimizations. 00-10-10 A bug in which name prefix matching ${!name.*} was not checking name to see if it was a name reference has been fixed. 00-09-26 A bug in the multibyte version in which the width of for non-printing characters was not correct has been fixed. 00-09-12 +Made changes to get multibyte editing work on UWIN for Windows. 00-09-12 A bug in which multibyte characters would be displayed incorrectly has been fixed. 00-08-08 Removed build dependency on iswprint() and iswalph(). 00-07-20 In some cases the read builtin would read more than a single line from a pipe on standard input and therefore leave the seek position in the wrong location. 00-07-05 +If the directory / is on the path, a / will not be inserted between the directory and the file name during path searching to avoid searching // for systems that treat this specially. 00-06-26 A bug in which on rare occasions wait could return before all jobs have completed has been fixed. 00-06-21 A bug in which backspace did not work correctly during the R replace directive in vi-mode has been fixed. 00-06-12 +Added variable name completion/expansion/listing to the set of completions. Variable name completions begin with $ or "$ followed by a letter. 00-05-09 --- Release ksh93j --- 00-05-09 Modified command substitution to avoid using /tmp files when run on read-only file systems. 00-04-17 +Modified printf to handle '%..Xc' and '%..Xs' options where X is not an alpha character. Previous versions core dumped with this. 00-04-10 +Changes to multibyte editing code were made to use standard ISO C functions rather than methods devised before the standard. 00-04-09 Add %H options to printf to output strings with <"'&\t> properly converted for use in HTML and XML documents. 00-04-07 +Modified getopts builtin to handle \f...\f in usage string by invoking specified function. 00-04-04 Added self generating man pages for bg, fc, fg, disown, jobs, hist, let, ., and ulimit. 00-03-30 +The append operator += has been added and can be used for all assignments, strings, arrays, and compound variables. 00-03-30 +Code was modified in several places to support automatic generation of C locale dictionaries. 00-03-28 A bug in which the set and trap commands invoked with --name type arguments would terminate the invoking script has been fixed. 00-03-27 A bug in which the library path variable was not updated correctly on some systems as described in the 'g' point release has been fixed. 00-03-07 printf now returns a non-zero exit status when one of its arguments cannot be converted to the given type. 00-03-05 The return value and error message for a command that was found on the path but was not executable was set incorrectly. 00-03-05 A prototype for ioctl() was removed from the vi edit mode. 00-01-28 --- Release ksh93i --- 00-01-28 +Most of the built-in commands and ksh itself are now self documenting. Running command --man will produce screen output. Running command --html produces the man page in html format. 00-01-28 +The getopts builtin can process command description strings to produce man pages. 00-01-28 A bug in which a script could terminate when getopts encountered an error when invoked inside a function has been fixed. 00-01-28 When a symbolic link was specified as the name of the script to invoke by name, the value of $0 was set to the real file name rather than the link name in some cases and this has been fixed. 00-01-28 A bug in which the precision given as an argument to printf was not working has been fixed. 99-03-31 --- Release ksh93h --- 99-03-31 +The PATH search algorithm has been modified to look for a file named .fpath in each bin directory and if found, to search for functions in this directory if it cannot find the command in that directory. 99-03-31 +When performing pathname expansion, the shell checks to see whether each directory it reads is case sensitive or not, and performs the matching accordingly. 99-03-31 +The %T format for printing formatted date/time. 99-03-31 +The emacs and vi modes now handle arrow keys when they use standard ANSI escape sequences. 99-03-31 +The TAB key can be used for completion in emacs and viraw mode. 99-03-31 A bug in setting .sh.editchar during the KEYBD trap for the MULTIBYTE option was fixed in release ksh93h. 99-03-31 A bug in shcomp for compilation of unary operators with [[ ... ]] has been fixed. 99-03-31 A bug in which the value of $? was changed when executing a keyboard trap has been fixed. 99-03-31 The handling of SIGCHLD has been changed so that the trap is not triggered while executing trap commands to avoid recursive trap calls. 99-03-31 A bug in which a local variable in a function declared readonly would generate an error when the function went out of scope has been fixed. 99-03-31 A bug in which \ entered from the keyboard with the KEYBD trap enabled has been fixed. 99-03-31 The error message for a misplaced ((, for example print ((3), was often garbled and has been fixed. 99-03-31 A bug in the KEYBD trap in which escape sequences of the form [#~ were not being handled as a unit has been fixed. 99-03-31 A bug in which ksh would consider expressions like [[ (a) ]] as syntax errors has been fixed. 99-03-31 A function defined as foo() without a function body was not reported as a syntax error. 99-03-31 A bug in which ksh could run out of file descriptors when a stream was repeatedly opened with exec and read from has been fixed. 98-04-30 --- Release ksh93g --- 98-04-30 +The pipefail option has been added. With pipefail enabled, a pipeline will not complete until all commands are complete, and the return value will be that of the last command to fail, or zero if all complete successfully. 98-04-30 +The name-value pair library uses the cdt library rather than the hash library. This change should be transparent to applications. 98-04-30 +On the U/WIN version for Window 95 and Windows NT, when a directory beginning with a letter followed by a colon is given to cd, it is assumed to be an absolute directory 98-04-30 +When an executable is found on a given path, the appropriate library path variable is prepended with a corresponding library directory. 98-04-30 A bug in which a name reference could be created to itself and later cause the shell to get into an infinite loop has been fixed. 98-04-30 A bug in shcomp relating to compound variables was fixed. 98-04-30 A bug introduced in ksh93e in which leading 0's in -Z fields caused the value to be treated as octal for arithmetic evaluation has been fixed. 98-04-30 A bug when a name reference with a shorter name than the variable it references was the subject of a compound assignment has been fixed. 98-04-30 A bug which in which assignment to array variables in a subshell could affect the parent shell has been fixed. 98-04-30 read name?prompt was putting a 0 byte at the end of the prompt on standard error. 98-04-30 A bug in [[ string1 > string2 ]] when ksh was run with -x has been fixed. 98-04-30 A bug in which the escape character was not processed correctly inside {...} when brace expansion is enabled has been fixed, for example {\$foo}. 98-04-30 A bug in line continuation in here-documents has been fixed. 98-04-30 The default base when not specified with typeset -i is 10 in accordance with the documentation. Previously, the value was determined by the first assignment. 98-04-30 A parsing bug in which a # preceded alphanumeric characters inside a command substitution caused a syntax error to be reported has been fixed. 98-04-30 A bug in which a decimal constant represented as 10#ddd where ddd was more than five digits generated a syntax error has been fixed. 98-04-30 A bug in here document expansion in which ${...} expansions were split across buffer boundaries has been fixed. 98-04-30 +The sh_fun() function now takes third argument which is an argument list for the invoked discipline function or built-in. 98-04-30 +A callback function can be installed which will give notification of file duplications and file closes. 98-04-30 When ksh is compiled on systems that do not use fork() current option settings where not propagated to subshells. 97-06-30 --- Release ksh93f --- 97-06-30 +Hostnames in addition to host addresses can be given in /dev/tcp/host/port virtual file names. 97-06-30 File name completion and expansion now quotes special characters in file names from both emacs and vi edit modes. 97-06-30 An empty for list behave like a for list with null expansions. It produces a warning message with sh -n. 97-06-30 +The code has been modified to work with EBCDIC as well as ASCII. 97-06-30 A bug which would cause the secondary prompt to be displayed when a user entered a literal carriage return has been fixed. 97-06-30 A bug which caused ksh read -s name to core dump was fixed. 97-06-30 A bug with the expansion of \} and \] inside double quoted strings that also contained variable expansions has been fixed 97-06-30 Changes in the ksh93e point release caused autoload functions invoked from within command substitution to fail. This has been fixed. 97-06-30 A bug in the processing of here-documents that could prevent variable substitution to occur after $(...) command substitution for long here documents has been fixed. 97-06-30 A bug caused by a race condition that could cause SIGTERM to be ignored by a child process has been fixed. 97-06-30 A bug which prevented the startup of a coprocess immediately after killing a running coprocess has been fixed. 97-06-30 ulimit foobar, where foobar is not an arithmetic expression, now gives an error message as it did with ksh88 instead of setting the file size limit to 0. 97-06-30 A bug which could cause an interactive shell to terminate when the last process of a pipeline was a POSIX function was fixed. 97-06-30 A bug which could cause command substitution of a shell script to core dump has been fixed. 97-06-30 A security hole was fixed in suid_exec. 97-06-30 Arithmetic functions such as pow() that take more than one argument, did not work if arguments other than the first contained parenthesized sub-expression. 97-06-30 The error message from a script containing an incomplete arithmetic expression has been corrected. 97-06-30 A bug which caused a core dump on some machines when the value of a name reference contained a positional parameter and the name reference was not defined inside a function has been fixed. 97-06-30 Arithmetic expressions now correctly handle hexadecimal constants. 97-06-30 A bug in which integer variables could be expanded with a leading 10# when declared with typeset -i multiple times has been corrected. 97-06-30 A bug in which IFS wasn't correctly restored when set within command substitution has been fixed. 97-06-30 The _ character is now considered as part of a word with the M-f and M-b emacs directives as it was in ksh88. 97-06-30 A bug in brace pattern expansions that caused expressions such as {foo\,bar,bam} to expand incorrectly have been fixed. 96-07-31 --- Release ksh93e --- 96-07-31 +The math functions, atan2, hypot, fmod, and pow were added. 96-07-31 +When a shared library is loaded, if the function lib_init() is defined in the library, it is invoked the first time that the library is loaded with builtin -f library. 96-07-31 The k-shell information abstraction database option, KIA, has been revamped. 96-07-31 Empty command substitutions of the form $() now work. whence -v foo now gives the correct result after calling builtin -d foo. 96-07-31 A bug in right to left arithmetic assignment for which the arithmetic expression (( y = x = 1.5 )) did not yield 1 for y when x was declared typeset -i was fixed. 96-07-31 printf has been fixed to handle format containing \0 and/or \0145 correctly. In addition, characters following %b in the format string are no longer displayed when the operand contains \c. 96-07-31 A bug in printf that could cause the %E format to produce unnormalized results has been fixed. 96-07-31 A bug which causes some arithmetic expressions to be incorrectly evaluated as integer expressions rather than floating point has been fixed. 96-07-31 Functions defined inside a subshell no longer remain defined when the subshell completes. 96-07-31 The error message from sh -c ';echo foo' has been corrected. 96-07-31 The format for umask -S has been changed to agree with the specification in the POSIX standard. 96-07-31 A bug that caused side effects in subscript evaluation when tracing was enabled for subscripts using ++ or -- has been fixed. 96-07-31 To conform to the POSIX standard getopts has been changed so that the option char is set to ? when it returns with a non-zero exit status. 96-07-31 The handling of \} inside ${name...} has been fixed so that the \ quotes the }. 96-07-31 A bug that caused the read builtin to resume execution after processing a trap has been fixed. 96-07-31 [[ -s file ]] has been fixed so that if file is open by ksh, it is flushed first. 96-07-31 In some cases attributes and sizes for non exported variables weren't being reset before running a script. 96-07-31 The value of TMOUT was affected by changes make to it in a subshell. 96-07-31 The jobs command did not reflect changes make by sending the CONT signal to a command. 96-07-31 The error message for ksh -o unknown was incorrect. 96-07-31 Functions invoked as name=value name, did not use values from the calling scope when evaluating value. 96-07-31 A bug in which the shell would re-execute previously executed code when a shell script or coprocess was run in the background has been fixed. 96-07-31 A bug in which an empty here-document would leave a file descriptor open has been fixed. 96-07-31 A bug in which $(set -A array ...) would leave a side effect has been fixed. 96-07-31 A discipline function for a global variable defined within a function defined with the function keyword, incorrectly created a local variable of the same name and applied the discipline to it. 95-08-28 --- Release ksh93d --- 95-08-28 The \ character was not handled correctly in replacement patterns with ${x/pattern/replace}. 95-08-28 A bug with read in which the line did not end with a new-line has been fixed. 95-08-28 A bug in file name generation which sometimes appended a . for filenames that ended in / has been fixed. 95-08-28 +If a process is waited for after a status has been returned by a previous wait, wait now returns 127. 95-08-28 A bug with hist (fc) -e which prevented a command to re-executed after it had been edited has been fixed. 95-08-28 A bug which prevented quoting from removing the meaning of unary test operators has been fixed. 95-08-28 A bug with typeahead and KEYBOARD traps with the MULTIBYTE option set has been fixed. 95-08-28 +Builtin functions can take a third argument which is a void*. 95-08-28 The nv_scan() function can restrict the scope of a walk to the top scope. 95-04-31 --- Release ksh93c --- 95-04-31 The expansion of "$@" was incorrect when $1 was the null string. 95-04-31 A bug which could incorrectly report a syntax error in a backquoted expression when a $ was preceded by \\ has been fixed. 95-04-31 A bug which prevented the shell from exiting after reporting an error when failing to open a script has been fixed. 95-04-31 A bug that could lead to memory corruption when a large here document that required parameter or command substitution was expanded has been fixed. 95-04-31 A bug that could cause a core dump on some systems after ksh detected an error when reading a function has been fixed. 95-04-31 A bug which could cause a coprocess to hang when reading from a process that has terminated has been fixed. 95-04-31 A bug which caused a script to terminate when set -e was on and the first command of and && or || list failed has been fixed. 95-04-31 A bug with here documents inside $(...) when the delimiter word is an identifier has been fixed. 95-04-31 A bug which caused $0 to display the wrong value when a script was invoked as an argument to the . command and the eval command has been fixed. 95-04-31 A bug that could cause the built-in sleep to hang has been fixed. 95-04-31 A bug introduces in 12/28/93b which caused the backslash to be removed when it was followed by digit inside double quotes in some instances has been fixed. 95-04-31 A bug which could cause a core dump if ksh was invoked with standard input closed has been fixed. 95-04-31 A bug which could cause a core dump if typeset -A was specified for an existing variable has been fixed. 95-04-31 Variables that were unset but had attributes such as readonly and export were not listed with readonly, export and typeset. 95-04-31 Several problems with signals have been fixed. 95-04-31 A bug which prevented ulimit -t from working has been fixed. Also, a bug in which failed ulimits could cause a core dump has also been fixed. 95-04-31 A bug in expansion of the form ${name/#pattern/string} and ${name/%pattern/string} has been fixed. 95-04-31 A bug which caused read -r on a line that contained only blanks to get a non-null value has been fixed. 95-04-31 A bug introduced in the 'a' point release in which ${x='\\'} expanded to \ when x was unset has been fixed. 95-04-31 A bug which prevented a trap on EXIT from being executed when the last command in a script was a function invocation has been fixed. 95-04-31 A bug which caused an interactive shell ignore input when standard error was redirected to a file with exec, and then restored with exec 2>&1 has been fixed. 95-04-31 An interactive shell turns on monitor mode even when standard error has been redirected to a file. 95-04-31 A bug which could cause standard input to be incorrectly positioned for the last command of a script has been fixed. 95-04-31 A bug in the edit modes which allowed walking back in the history file for more than HISTSIZE commands has been fixed. 95-04-31 A bug which could cause a core dump if variable TMPDIR was changed between two command substitutions has been fixed. 95-04-31. A bug which prevented a trap on EXIT from being cleared has been fixed. 95-04-31 A bug fixed for the v directive in vi MULTIBYTE has been fixed. 95-04-31 Code to for IFS handling of multibyte characters has been added. 95-04-31 The displaying of multibyte strings in export, readonly, typeset, and execution traces has been fixed. 95-04-31 Variables inside functions are now statically scoped. The previous behavior was never documented. 95-04-31 Variables inside functions are now statically scoped. The previous behavior was never documented. 95-04-31 A few changes have been made to the name-value library that affect built-ins that use disciplines. The changes allow disciplines to be shared by variables and should make it possible to add new disciplines without recompilation. 95-04-31 +The name-value library interface has undergone significant change for this revision. See the new nval.3 man page. 94-12-31 --- Release ksh93b --- 94-12-31 +Variables inside functions are now statically scoped. The previous behavior was never documented. 94-12-31 +If IFS contains two consecutive identical characters belonging to the [:space:] class, then this character is treated as a non-space delimiter so that each instance will delimit a field. For example, IFS=$'\t\t' will cause two consecutive tabs to delimit a null field. 94-12-31 +The getopts command has a -a name option that specifies a name that will be used for usage messages. 94-12-31 A bug which caused unset RANDOM to dump core has been fixed. 94-12-31 A bug which prevented return for terminating a profile or ENV file has been fixed. 94-12-31 A bug which prevented standard input from being directed to /dev/null for background jobs when monitor mode was turned off has been fixed. 94-12-31 Statements of the form typeset -options var[expr]=value did not perform substitutions on expr as expected. 94-12-31 A bug which prevented the shell from sending a HUP signal to some background jobs that were not disowned has been fixed. 94-12-31 A bug which allowed a script to trap signals that are ignored at the time that the shell was invoked by exec has been fixed. 94-12-31 A bug which could cause a core dump when a discipline function was unset within a discipline was fixed. 94-12-31 The typeset builtin now accepts a first argument of + or - for compatibility with ksh88. 94-12-31 For compatibility with ksh88, the results of expansions of command arguments will treat the extended character match characters ()|& as ordinary characters. 94-12-31 A bug which caused read to fail on a file that was open for read/write with <> when the first operation was print or printf has been fixed. 94-12-31 When a job is suspended, it is put on the top of the job list as required by the POSIX standard. 94-12-31 The value of OPTARG when an option that required an argument but didn't have one was incorrect in the case the option string began with a :. 94-12-31 A bug which caused the terminal to get into a bad state with some KEYBD traps in vi-mode has been fixed. 94-12-31 A bug which caused an invalid trap to cause a script to terminate, rather than just return an error, has been fixed. 94-12-31 Backreferencing sub-expressions in patterns and replacement strings now works. 94-12-31 A bug in chmod which caused the -R option to fail has been fixed. 94-12-31 +More signal names have been added for Solaris 94-06-30 --- Release ksh93a --- 94-06-30 An expansion bug which causes portions of a word after a $((...)) expansion that contains a nested $var expansion to be lost has been fixed. 94-06-30 A bug that caused a core dump when a script that did not have PWD set and did a cd inside command substitution has been fixed. 94-06-30 A bug which caused a core dump on some machines when the LANG variable was assigned to has been fixed. 94-06-30 A bug which incorrectly handled set disciplines that performed arithmetic evaluation when the discipline was called from the arithmetic evaluator has been fixed. 94-06-30 A bug caused by an EXIT trap inside a function that was executed in a subshell was fixed. 94-06-30 If foo is a function, and not a program, then command foo now reports that foo isn't found rather than invoking foo. 94-06-30 The previous version incorrectly listed -A as an invocation option. The -A option is only for set. 94-06-30 A bug was fixed which caused ksh to loop when execution trace was enabled and the PS4 prompt required command substitution. 94-06-30 A bug which could cause the job control switch character to be disabled when a script that enabled monitor mode terminated was fixed. 94-06-30 A bug in the macro expansion global replacement operator //, when the pattern began with a [ or +( has been fixed. 94-06-30 A bug which prevented ~ expansion from occurring when it was terminated with a colon inside an assignment has been fixed. 94-06-30 A bug in the dot command which prevented autoload functions from working has been fixed. 94-06-30 A bug which caused a variable to be unset if the its value were expanded inside a set discipline has been fixed. 94-06-30 Whence -a now longer reports that a defined function is undefined. 94-06-30 A bug on some systems in which $0 would be incorrect in scripts invoked by name has been fixed. 94-06-30 Here documents with an empty body now work. 94-06-30 A bug which disabled argument passing and resetting of options for a script invoked by name inside a function has been fixed. 94-06-30 A bug in which an EXIT trap set the caller of a function would be executed if a command called inside a function was not found has been fixed. 94-06-30 A bug which allowed a script to trap signals that are ignored at the time that the shell was invoked has been fixed. 94-06-30 A bug which caused 2<&1- when applied to a shell built-in to leave standard input closed has been fixed. 94-06-30 A bug which caused the shell to incorrectly parse $() command substitutions with nested case statements has been fixed. ksh-1.0.10/src/cmd/ksh93/RELEASE88000066400000000000000000000472311465301102200160350ustar00rootroot00000000000000This file is of historical interest only. For recent changes in both ksh 93u+m and the accompanying libraries, see the file NEWS in the top-level directory. ____ This is a list of changes that have been made since the 11/16/88 version of ksh. 1. New features in 12/28/93 a. Associative arrays. The new version of ksh supports both associative arrays and the older indexed arrays with the same array syntax. A new -A option of typeset is used to declare an array to be associative. As with indexed arrays, $name is equivalent to ${name[0]}. The prefix operator ! was added to the parameter expansion syntax to expand to the list of indices. For example, ${!name[@]} expands to the list of array indices for variable name. b. Several additions have been made to shell arithmetic: 1. The shell now performs floating point arithmetic. The typeset options -F and -E have been added for floating point and scientific notation respectively. 2. The prefix and postfix ++ and -- operators. 3. The comma and ?: operators. 4. The math library functions. 5. An arithmetic for statement of the form for ((expr1; expr2; expr3)) do ... done 6. Integer arithmetic extended up to base 64. c. Some additions to the macro expansion syntax have been made to specify substrings and sub-arrays: 1. ${name:expr} expands to the substring of ${name} starting at the character position defined by arithmetic expression expr. 2. ${name:expr1:expr2} expands to the substring of ${name} starting at expr1 and consisting of at most expr2 characters. 3. ${name[@]:expr} expands to the values of ${name[@]} starting at the element defined by arithmetic expression expr. 4. ${name[@]:expr1:expr2} expands to at most expr2 values of ${name} starting at expr1. 5. ${@:expr} expands the positional parameters starting at expr. 6. ${@:expr1:expr2} expands to at most expr2 positional parameters starting at expr1. 7. ${!name} expands to the name of the variable named by name. It will expand to name unless name is a reference variable. 8. ${!name[sub]} expands to the name of the subscript of the given variable. If sub is @ or * the list of subscripts is generated. 9. ${!prefix*} and ${!prefix@} expand to the list of variable names beginning with prefix. 10. The substring operators, # and % can be now be applied with aggregates (@ or *) and are applied to each. 11. ${name/pattern/string} expands to the value of name with the first occurrence of pattern replaced by string. With aggregates (@ or *) this operation is applied to each. 12. ${name/#pattern/string} Same as above but the pattern to be replaced must match at the beginning. 13. ${name/%pattern/string} Same as above but the pattern to be replaced must match at the end. 14. ${name//pattern/string} expands to the value of name with each occurrence of pattern replaced by string. With aggregates (@ or *) this operation is applied to each. d. The name space for variables has been extended. The character '.' can be used at the beginning of a name, and to separate identifiers within a name. However, to create a name of the form, foo.bar, the variable foo must exist. The namespace starting with .sh is reserved for shell implementation variables. Exported variables cannot contain a '.'. e. Compound assignments. The assignment syntax, varname=value, has been extended to allow assignments of the form varname=(assignment_list). As elsewhere in the shell spaces or tabs are optional around the parentheses, and no space is permitted between the varname and the =. The assignment_list can be one of the following: 1. A list of words. In this case each word is expanded as in a for list and the resulting items become elements of the indexed array varname. 2. A list of subscript assignments in the form [subscript]=value. In this, these elements become elements of the associative array varname. 3. A list of assignments; simple or compound. In this case, each assignment is made to varname.name, where name is the name of the enclosed assignment. 4. Assignments in the form of readonly or typeset statements. In this case each assignment is made as in 3 above, and the attributes are given to the corresponding variable. In case 3 and 4 above, the value of "$varname" after the above assignment is (assignment_list), where the assignment_list produced would reproduce all of the variables under varname.*. f. Function names of the form variable.action (called discipline functions) can be defined where variable is any valid variable name and action is get, set, or unset. The function variable.get is invoked each time the variable is referenced. The set discipline is invoked each time the variable is assigned to. The unset discipline is invoked when a variable is unset. The new variables .sh.name, .sh.subscript, and .sh.value are defined inside the function body. Other shell extensions may have their own set of discipline functions. g. The compound command !, which negates the return value of the following pipeline, has been added. h. On systems that support dynamic loading with dlopen(), it is now possible to add built-in commands at runtime with the builtin command named 'builtin'. i. The following builtins have been added: 1. command name [ ... ] 2. sleep [decimal-seconds] 3. builtin [-ds] [-f file] [name...] 4. getconf name [pathname] 5. disown [job...] j. An addition format for literal strings, $'....' can be used where ever literal strings are valid. The string inside the single quotes will be converted using the ANSI C escape conventions. Additionally, the escape sequence \E expands to the escape character (default \033) whenever ANSI C escape sequences are recognized. k. A typeset -n option has been added which causes the value of a variable to be treated as a reference to another variable so that variables can be indirectly named. For example, if $1 contains the name of a variable, then typeset -n foo=$1 causes the variable foo to be synonymous with the variable whose name is $1. A builtin alias, nameref='typeset -n' has been added to aid mnemonics. Reference names cannot contain a '.'. Whenever that portion of a variable up to the first '.' matches a reference name, the reference value is substituted. For example, with nameref foo=.top, then ${foo.bar} is equivalent to ${.top.bar}. When used as the index of a for or select loop, each assignment causes a new name reference to occur. l. The KEYBD trap has been added which is triggered when a key or escape sequence is typed while reading from the keyboard in an edit mode. This, combined with some new variables makes it possible to program your key bindings in ksh. m. New variables have been added: 1. FIGNORE defines a set of file names to be ignored in each directory when performing pathname expansion, replacing the rule that requires that a leading . be matched explicitly. 2. Variable sh.edchar contains the value of the keyboard character that has been entered when processing a KEYBD trap. If the value is changed as part of the trap action, then the new value replaces the key or keys that caused the trap. 3. Variable sh.edcol is set to the character position of the cursor within the input buffer during a KEYBD trap. 4. Variable sh.edmode is set to the escape character when in vi insert mode. 5. Variable sh.edtext is set to the contents of the input buffer during a KEYBD trap. 6. HISTEDIT is checked before FCEDIT. FCEDIT is obsolete. 7. HISTCMD is the number of the current command in the history file. 8. Variable .sh.version is set to the version string for this shell. 9. Variable .sh.name is set to the name of the variable that was referenced or assigned to when executing a get or set discipline function. 10. Variable .sh.subscript is set to the subscript for the variable that was referenced or assign to when executing a get or set discipline function. 11. Variable .sh.value is set to the new value for the variable that was assigned to when executing the set discipline function. n. New invocation and set -o options have been added: 1. set -o notify (or set -b) causes background completion messages to be displayed as soon as the job completes. 2. There is a compile time option named KIA which enables creation of a relational database for commands, variables and functions defined and referenced by a script. The option -I , causes the database to be generated in . The database format can be queried via the cql command. o. ksh93 can read and evaluate pre-compiled scripts generated by a separate program called shcomp. p. More work on internationalization has been added: 1. The decimal point character is processed per locale 2. A $ can be placed in front of each string to indicate that the string needs translation but is otherwise ignored. This means that if a message catalog of all $"..." strings is generated, then a program such as print $"hello world" could display "bonjour monde" in the French locale. q. Backreferences have been added to pattern matching. The sequence \d, where d is a digit from 1-9, matches the same string as the d-th previous parenthesis group. Backreferences can be used within patterns, and within replacement strings with any of the ${name/...} operators. 2. Changes made in 12/28/93 a. The output format of many commands has changed as follows: 1. System error messages are displayed whenever a failure is caused by a system call. 2. The exit status has changed in many cases: a. USAGE messages cause an exit status of 2. b. Commands not found cause exit - 127. c. Command found, but not executable - 126. d. Terminated because of signal - 256+sig 3. The output of values from built-ins that contain special characters are quoted in a manner that then can be re-input. 4. The trace output puts quotes around the output so that it can be reused as input. 5. The output for trap is in a format that can be reinput to the shell to restore the traps. 6. kill -l lists the signal names without numbers as required by the POSIX standard. b. The following changes have been made to shell functions: 1. The semantics of functions declared with name() has changed to conform with the IEEE-POSIX 1003.2 standard. In particular, these functions are executed in a dot script environment rather than a separated function environment so that there are no local variables and no scoping for traps. 2. Functions declared as function name, preserve the old ksh semantics can be also used as the first argument to the dot (.) command to have them executed in a dot script environment. c. The command search rules have changed as follows: 1. Special built-ins (those with a dagger in front of them) are executed first. 2. Functions are executed next. 3. Other built-ins that do not require an executable version (for example cd and read) come next. 4. If the command name contains a slash, the pathname corresponding to the command name is executed. 5. If name corresponds to a previously encountered pathname on the PATH variable, the corresponding command is executed. 6. If the command name does not contain a slash, then the PATH variable is used to find an executable by that name. If the directory that the command is found is also contained in the FPATH variable, then the command treated as a function. If the shell has a built-in version of the command corresponding to this command, then the built-in version of this command is executed. Otherwise, the shell remembers that pathname corresponding to this command name and executes this pathname. 7. If the name is not found on PATH, then the directories in FPATH are searched. If found, then the command is executed as a function. d. Built-in commands options now conform to the IEEE-POSIX 1003.2 conventions with some additions. In particular, name -? will now print a Usage line for name, except for true, false, colon, login, newgrp, echo, [, and command. e. Tilde expansion is now performed as part of the word expansions. The effect of this is that if word begins with ~ in ${name op word}, it will be expanded unless escaped. f. Pathname expansion is no longer performed on redirection words unless the shell is interactive. g. Changes to shell and options: 1. The -n option has been enhanced to produce more warning and portability messages. 2. The -C option is equivalent to -o noclobber. Files are created with O_EXCL when -C is on. h. The following changes have been made to [[ ... ]]: 1. A string by itself is equivalent to -n string. 2. -e has been added as equivalent to -a. 3. == has been added as equivalent =. 4. -a and = are now considered obsolete. 5. Arithmetic comparisons are now considered obsolete. i. kill has been changed as follows: 1. Signal names can be upper case or lower case. 2. Numerical arguments to kill -l cause the given signal names to be displayed. 3. String arguments to kill -l cause the given signal numbers to be displayed. 4. Synopsis changed for getopts conformance. j. print has a -f format option which is equivalent to the IEEE POSIX printf. Both print -f format, and printf have the following extensions from IEEE POSIX: 1. Floating point formats are supported. 2. Size and precision specifications can be *. 3. The %d option can take an argument after precision to specify the base that the number will be displayed. 4. A %q format can be used to output a string quoted so that it can be re-input to the shell. 5. A %P format can be used to output the shell pattern which corresponds to the give extended regular expression. 6. For numerical fields, the arguments can be arithmetic expressions which will be evaluated. 7. The %n format works as described in ANSI C. k. The following changes have been made to fc: 1. It has been renamed hist. fc is now a predefined alias. 2. hist uses ${HISTEDIT:-$FCEDIT}. FCEDIT is obsolete. 3. A new -s option is equivalent to the obsolete -e -. 4. If the first argument refers to a command earlier than the first accessible command, it now implies the first accessible command, so that hist -l 1 lists all accessible history commands. l. The dot command (.) has changed as follows: 1. The argument can be the name of a function declared as function name. The function will execute without creating a new scope. 2. If there are arguments to the given script or function, the positional parameters are restored to their original value when . completes. m. The read built-in has been changed as follows: 1. A -A option to read has been added to allow the fields to be read into an indexed array. 2. A -t n option has been added which causes read to timeout after n seconds when reading from a slow device. 3. A -d char option has been added which causes the read to terminate at char rather than at new-line. n. The trap command has been changed as follows: 1. Trap names can be either upper case or lower case. 2. Trap -p only causes the specified trap values to be displayed. 3. The value of trap in a subshell will be the value in the parent shell until a call to trap which changes the trap settings has been made. Thus, savetraps=$(trap) works as required by the POSIX standard. o. The exec command has been extended as follows: 1. The -c option clears the environment first. 2. The -a name option sets argv[0] to name for the program. p. true and false are built-ins, not aliases to built-ins. q. test has been modified to conform to the IEEE-POSIX 1003.2 standard when there are three or less arguments. r. umask -S option displays the mask in a symbolic format. s. wait now returns the correct exit status of any previous background job that has not been waited for, not just the most recent one. t. The whence built-in has an option -a which causes all uses for the given command name to be reported. u. unalias has -a option to clear all the aliases. v. The times built-in command has been removed. The time reserved word, without a command, gives time cumulative time for the shell and its children. A built-in alias for times should enable scripts using times to continue to run. w. Command substitution and arithmetic substitution will now be performed for PS1, ENV, and PS4 evaluation in addition to parameter expansion. x. The SECONDS variable now displays elapsed time in floating point seconds with 3 places after the decimal point by default. y. The getopts built-in now handles the complete libast optget functionality. If any errors have occurred with getopts when it has reached the end of arguments, then the Usage message will be generated from the option string and the exit status from getopts will be 2 rather than 1. The usage message will be stored in the OPTARG variable if the option string contains a leading colon; otherwise it will be printed on standard error automatically. z. THE ENV file is only processed for interactive shell invocations. In addition, the -x attributes for aliases and functions is ignored. aa. The built-in edit modes have been changed as follows: 1. The pathname completion and pathname listing options now perform command completion and command listing when applied to a word in the command position. 2. In emacs mode ^N as the first related command after the prompt will move to the next command relative to the last known history position. 3. In emacs mode, successive kill and delete commands will accumulate their data in the kill buffer, by appending or prepending as appropriate. This mode will be reset by any command not adding something to the kill buffer. 4. The control-T of emacs mode has been changed to behave like control-T in gnu-emacs. bb. The TMOUT variable also sets a limit for select timeouts and default timeouts for read. 4. The source code has undergone significant modification. a. Much of the code has been rewritten, In many cases this has resulted in significant performance improvement. b. The code is organized differently. See the README files for more details. c. Most configuration parameters now get generated using the FEATURE mechanism of nmake. Other options are set in the OPTIONS file. c. There are several new compile time options. See the README file for details. Some of the old ones have been removed. d. The install script is a Mamfile that is generated by nmake and processed by a script that comes with the distribution. e. There are far fewer global names. This should make it must easier to add built-in commands without worrying about conflicts. f. The code uses the sfio library which makes it possible to mix with stdio. g. The code is written in ANSI C with full prototypes. The code is based on the IEEE POSIX 1003.1 standard. The code can be compiled with K&R C and with C++ by using the ANSI cpp that comes with nmake or running the code through the proto filter before pre-processing. This happens automatically with our shipping system. h. There is a programming interface for capturing references and assignment to shell variables. It is also possible to intercept variable creation and supply the array processing function for that variable. See nval.3 for a description. ksh-1.0.10/src/cmd/ksh93/RELEASE93000066400000000000000000000536601465301102200160340ustar00rootroot00000000000000This file is of historical interest only. For recent changes in both ksh 93u+m and the accompanying libraries, see the file NEWS in the top-level directory. ____ This is a list of changes that have been made since the 12/28/93 version of ksh. 1. New features in 12/28/93b a. If IFS contains two consecutive identical characters belonging to the [:space:] class, then this character is treated as a non-space delimiter so that each instance will delimit a field. For example, IFS=$'\t\t' will cause two consecutive tabs to delimit a null field. b. The getopts command has a -a name option that specifies a name that will be used for usage messages. 2. New features in 12/28/93e a. The math functions, atan2, hypot, fmod, and pow were added. b. When a shared library is loaded, if the function lib_init() is defined in the library, it is invoked the first time that the library is loaded with builtin -f library. 3. New features in 12/28/93f a. Hostnames in addition to host addresses can be given in /dev/tcp/host/port virtual file names. b. File name completion and expansion now quotes special characters in file names from both emacs and vi edit modes. 4. New features in 12/28/93g a. The pipefail option has been added. With pipefail enabled, a pipeline will not complete until all commands are complete, and the return value will be that of the last command to fail, or zero if all complete successfully. b. When an executable is found on a given path, the appropriate library path variable is prepended with a corresponding library directory. 5. New features in 12/28/93h a. The PATH search algorithm has been modified to look for a file named .fpath in each bin directory and if found, to search for functions in this directory if it cannot find the command in that directory. b. When performing pathname expansion, the shell checks to see whether each directory it reads is case sensitive or not, and performs the matching accordingly. c. The %T format for printing formatted date/time. 6. New features in 12/28/93i a. Most of the built-in commands and ksh itself are now self documenting. Running command --man will produce screen output. Running command --html produces the man page in html format. b. The getopts builtin can process command description strings to produce man pages. 7. Bugs fixed in 12/28/93a for default OPTIONS a. An expansion bug which causes portions of a word after a $((...)) expansion that contains a nested $var expansion to be lost has been fixed. b. A bug that caused a core dump when a script that did not have PWD set and did a cd inside command substitution has been fixed. c. A bug which caused a core dump on some machines when the LANG variable was assigned to has been fixed. d. A bug which incorrectly handled set disciplines that performed arithmetic evaluation when the discipline was called from the arithmetic evaluator has been fixed. e. A bug caused by an EXIT trap inside a function that was executed in a subshell was fixed. f. If foo is a function, and not a program, then command foo now reports that foo isn't found rather than invoking foo. g. The previous version incorrectly listed -A as an invocation option. The -A option is only for set. h. A bug was fixed which caused ksh to loop when execution trace was enabled and the PS4 prompt required command substitution. i. A bug which could cause the job control switch character to be disabled when a script that enabled monitor mode terminated was fixed. j. A bug in the macro expansion global replacement operator //, when the pattern began with a [ or +( has been fixed. k. A bug which prevented ~ expansion from occurring when it was terminated with a colon inside an assignment has been fixed. l. A bug in the dot command which prevented autoload functions from working has been fixed. m. A bug which caused a variable to be unset if the its value were expanded inside a set discipline has been fixed. n. Whence -a now longer reports that a defined function is undefined. o. A bug on some systems in which $0 would be incorrect in scripts invoked by name has been fixed. p. Here documents with an empty body now work. 1. A bug which disabled argument passing and resetting of options for a script invoked by name inside a function has been fixed. r. A bug in which an EXIT trap set the caller of a function would be executed if a command called inside a function was not found has been fixed. s. A bug which allowed a script to trap signals that are ignored at the time that the shell was invoked has been fixed. t. A bug which caused 2<&1- when applied to a shell built-in to leave standard input closed has been fixed. u. A bug which caused the shell to incorrectly parse $() command substitutions with nested case statements has been fixed. 8. Bugs fixed in 12/28/93b for default OPTIONS a. A bug which caused unset RANDOM to dump core has been fixed. b. A bug which prevented return for terminating a profile or ENV file has been fixed. c. A bug which prevented standard input from being directed to /dev/null for background jobs when monitor mode was turned off has been fixed. d. Statements of the form typeset -options var[expr]=value did not perform substitutions on expr as expected. e. A bug which prevented the shell from sending a HUP signal to some background jobs that were not disowned has been fixed. f. A bug which allowed a script to trap signals that are ignored at the time that the shell was invoked by exec has been fixed. g. A bug which could cause a core dump when a discipline function was unset within a discipline was fixed. h. The typeset builtin now accepts a first argument of + or - for compatibility with ksh88. i. For compatibility with ksh88, the results of expansions of command arguments will treat the extended character match characters ()|& as ordinary characters. j. A bug which caused read to fail on a file that was open for read/write with <> when the first operation was print or printf has been fixed. k. When a job is suspended, it is put on the top of the job list as required by the POSIX standard. l. The value of OPTARG when an option that required an argument but didn't have one was incorrect in the case the option string began with a :. m. A bug which caused the terminal to get into a bad state with some KEYBD traps in vi-mode has been fixed. n. A bug which caused an invalid trap to cause a script to terminate, rather than just return an error, has been fixed. o. Backreferencing sub-expressions in patterns and replacement strings now works. p. A bug in chmod which caused the -R option to fail has been fixed. 9. Bugs fixed in 12/28/93c for default OPTIONS a. The expansion of "$@" was incorrect when $1 was the null string. b. A bug which could incorrectly report a syntax error in a backquoted expression when a $ was preceded by \\ has been fixed. c. A bug which prevented the shell from exiting after reporting an error when failing to open a script has been fixed. d. A bug that could lead to memory corruption when a large here document that required parameter or command substitution was expanded has been fixed. e. A bug that could cause a core dump on some systems after ksh detected an error when reading a function has been fixed. f. A bug which could cause a coprocess to hang when reading from a process that has terminated has been fixed. g. A bug which caused a script to terminate when set -e was on and the first command of and && or || list failed has been fixed. h. A bug with here documents inside $(...) when the delimiter word is an identifier has been fixed. i. A bug which caused $0 to display the wrong value when a script was invoked as an argument to the . command and the eval command has been fixed. j. A bug that could cause the built-in sleep to hang has been fixed. k. A bug introduces in 12/28/93b which caused the backslash to be removed when it was followed by digit inside double quotes in some instances has been fixed. l. A bug which could cause a core dump if ksh was invoked with standard input closed has been fixed. m. A bug which could cause a core dump if typeset -A was specified for an existing variable has been fixed. n. Variables that were unset but had attributes such as readonly and export were not listed with readonly, export and typeset. o. Several problems with signals have been fixed. p. A bug which prevented ulimit -t from working has been fixed. Also, a bug in which failed ulimits could cause a core dump has also been fixed. q. A bug in expansion of the form ${name/#pattern/string} and ${name/%pattern/string} has been fixed. r. A bug which caused read -r on a line that contained only blanks to get a non-null value has been fixed. s. A bug introduced in the 'a' point release in which ${x='\\'} expanded to \ when x was unset has been fixed. t. A bug which prevented a trap on EXIT from being executed when the last command in a script was a function invocation has been fixed. u. A bug which caused an interactive shell ignore input when standard error was redirected to a file with exec, and then restored with exec 2>&1 has been fixed. v. An interactive shell turns on monitor mode even when standard error has been redirected to a file. w. A bug which could cause standard input to be incorrectly positioned for the last command of a script has been fixed. y. A bug in the edit modes which allowed walking back in the history file for more than HISTSIZE commands has been fixed. z. A bug which could cause a core dump if variable TMPDIR was changed between two command substitutions has been fixed. aa. A bug which prevented a trap on EXIT from being cleared has been fixed. 10. Bugs fixed in 12/28/93d for default OPTIONS a. The \ character was not handled correctly in replacement patterns with ${x/pattern/replace}. b. A bug with read in which the line did not end with a new-line has been fixed. c. A bug in file name generation which sometimes appended a . for filenames that ended in / has been fixed. d. If a process is waited for after a status has been returned by a previous wait, wait now returns 127. e. A bug with hist (fc) -e which prevented a command to re-executed after it had been edited has been fixed. f. A bug which prevented quoting from removing the meaning of unary test operators has been fixed. 11. Bugs fixed in 12/28/93e for default OPTIONS a. Empty command substitutions of the form $() now work. b. whence -v foo now gives the correct result after calling builtin -d foo. c. A bug in right to left arithmetic assignment for which the arithmetic expression (( y = x = 1.5 )) did not yield 1 for y when x was declared typeset -i was fixed. d. printf has been fixed to handle format containing \0 and/or \0145 correctly. In addition, characters following %b in the format string are no longer displayed when the operand contains \c. e. A bug in printf that could cause the %E format to produce unnormalized results has been fixed. f. A bug which causes some arithmetic expressions to be incorrectly evaluated as integer expressions rather that floating point has been fixed. g. Functions defined inside a subshell no longer remain defined when the subshell completes. h. The error message from sh -c ';echo foo' has been corrected. i. The format for umask -S has been changed to agree with the specification in the POSIX standard. j. A bug that caused side effects in subscript evaluation when tracing was enabled for subscripts using ++ or -- has been fixed. k. To conform to the POSIX standard getopts has been changed so that the option char is set to ? when it returns with a non-zero exit status. l. The handling of \} inside ${name...} has been fixed so that the \ quotes the }. m. A bug that caused the read builtin to resume execution after processing a trap has been fixed. n. [[ -s file ]] has been fixed so that if file is open by ksh, it is flushed first. o. In some cases attributes and sizes for non exported variables weren't being reset before running a script. p. The value of TMOUT was affected by changes make to it in a subshell. q. The jobs command did not reflect changes make by sending the CONT signal to a command. r. The error message for ksh -o unknown was incorrect. s. Functions invoked as name=value name, did not use values from the calling scope when evaluating value. t. A bug in which the shell would re-execute previously executed code when a shell script or coprocess was run in the background has been fixed. u. A bug in which an empty here-document would leave a file descriptor open has been fixed. v. A bug in which $(set -A array ...) would leave a side effect has been fixed. w. A discipline function for a global variable defined within a function defined with the function keyword, incorrectly created a local variable of the same name and applied the discipline to it. 12. Bugs fixed in 12/28/93f for default OPTIONS a. A bug which would cause the secondary prompt to be displayed when a user entered a literal carriage return has been fixed. b. I bug which caused ksh read -s name to core dump was fixed. c. I bug with the expansion of \} and \] inside double quoted strings that also contained variable expansions has been fixed d. Changes in the 'e' point release caused autoload functions invoked from within command substitution to fail. This has been fixed. e. A bug in the processing of here-documents that could prevent variable substitution to occur after $(...) command substitution for long here documents has been fixed. f. A bug caused by a race condition that could cause SIGTERM to be ignored by a child process has been fixed. g. A bug which prevented the startup of a coprocess immediately after killing a running coprocess has been fixed. h. ulimit foobar, where foobar is not an arithmetic expression, now gives an error message as it did with ksh88 instead of setting the file size limit to 0. i. A bug which could cause an interactive shell to terminate when the last process of a pipeline was a POSIX function was fixed. j. A bug which could cause command substitution of a shell script to core dump has been fixed. k. A security hole was fixed in suid_exec. l. Arithmetic functions such as pow() that take more than one argument, did not work if arguments other than the first contained parenthesized sub-expression. m. The error message from a script containing an incomplete arithmetic expression has been corrected. n. A bug which caused a core dump on some machines when the value of a name reference contained a positional parameter and the name reference was not defined inside a function has been fixed. o. Arithmetic expressions now correctly handle hexadecimal constants. p. A bug in which integer variables could be expanded with a leading 10# when declared with typeset -i multiple times has been corrected. q. A bug in which IFS wasn't correctly restored when set within command substitution has been fixed. r. The _ character is now considered as part of a word with the M-f and M-b emacs directives as it was in ksh88. 13. Bugs fixed in 12/28/93g for default OPTIONS a. A bug in which a name reference could be created to itself and later cause the shell to get into an infinite loop has been fixed. b. A bug in shcomp relating to compound variables was fixed. c. A bug introduced in 'e' in which leading 0's in -Z fields caused the value to be treated as octal for arithmetic evaluation has been fixed. d. A bug when a name reference with a shorter name than the variable it references was the subject of a compound assignment has been fixed. e. A bug which in which assignment to array variables in a subshell could affect the parent shell has been fixed. f. read name?prompt was putting a 0 byte at the end of the prompt on standard error. g. A bug in [[ string1 > string2 ]] when ksh was run with -x has been fixed. k. A bug in which the escape character was not processed correctly inside {...} when brace expansion is enabled has been fixed, for example {\$foo}. l. A bug in line continuation in here-documents has been fixed. m. The default base when not specified with typeset -i is 10 in accordance with the documentation. Previously, the value was determined by the first assignment. n. A parsing bug in which a # preceded alphanumeric characters inside a command substitution caused a syntax error to be reported has been fixed. o. A bug in which a decimal constant represented as 10#ddd where ddd was more than five digits generated a syntax error has been fixed. p. A bug in here document expansion in which ${...} expansions were split across buffer boundaries has been fixed. 14. Bugs fixed in 12/28/93h for default OPTIONS a. I bug in shcomp for compilation of unary operators with [[ ... ]] has been fixed. b. A bug in which the value of $? was changed when executing a keyboard trap has been fixed. c. The handling of SIGCHLD has been changed so that the trap is not triggered while executing trap commands to avoid recursive trap calls. d. I bug in which a local variable in a function declared readonly would generated an error when the function went out of scope has been fixed. e. I bug in which \ entered from the keyboard with the KEYBD trap enabled has been fixed. f. The error message for a misplaced ((, for example print ((3), was often garbled and has been fixed. g. I bug in the KEYBD trap in which escape sequences of the form [#~ were not being handled as a unit has been fixed. h. A bug in which ksh would consider expressions like [[ (a) ]] as syntax errors has been fixed. i. A function defined as foo() without a function body was not reported as a syntax error. j. A bug in which ksh could run out of file descriptors when a stream was repeatedly opened with exec and read from has been fixed. k. A bug introduced when fixing item n from the 'g' point release has been fixed. 15. Bugs fixed in 12/28/93i for default OPTIONS a. A bug in which a script could terminate when getopts encountered an error when invoked inside a function has been fixed. b. When a symbolic link was specified as the name of the script to invoke by name, the value of $0 was set to the real file name rather than the link name in some cases and this has been fixed. 16. Bug fixes for specific non-default option combinations. a. More signal names have been added for Solaris b. A bug fixed for the v directive in vi MULTIBYTE has been fixed. c. Code to for IFS handling of multibyte characters has been added. d. The displaying of multibyte strings in export, readonly, typeset, and execution traces has been fixed. e. A bug with type ahead and KEYBOARD traps with the MULTIBYTE option set has been fixed. f. The k-shell information abstraction database option, KIA, has been revamped for the 'e' point release. g. A bug in brace pattern expansions that caused expressions such as {foo\,bar,bam} to expand incorrectly have been fixed. h. On the U/WIN version for Window 95 and Windows NT, when a directory beginning with a letter followed by a colon is given to cd, it is assumed to be an absolute directory. i. There was a bug in the compile option that does not use fork() in which the current option settings where not propagated to subshells. j. A bug in setting .sh.editchar during the KEYBD trap for the MULTIBYTE option was fixed in release 'h'. k. A bug in which the precision given as an argument to printf was not working has been fixed. 17. Other changes to 12/28/93[abcdefghi] a. A couple of minor changes to make adding built-ins easier. b. Variables inside functions are now statically scoped. The previous behavior was never documented. c. A few changes have been made to the name-value library that affect built-ins that use disciplines. The changes allow disciplines to be shared by variables and should make it possible to add new disciplines without recompilation. d. The name-value library interface has undergone significant change for this revision. See the new nval.3 man page. e. Builtin functions can take a third argument which is a void*. f. The nv_scan() function can restrict the scope of a walk to the top scope. Starting in 'f', nv_scan() has an additional pointer argument that is passed to each invoked function. g. Starting with release 'f', an empty for list behave like a for list with null expansions. It produces a warning message with sh -n. h. Starting with release 'f' the code has been modified to work with EBCDIC as well as ASCII. i. Starting with the release 'g', the name-value pair library uses the cdt library rather than the hash library. j. The sh_fun() function now takes third argument which is an argument list for the invoked discipline function or built-in. k. A callback function can be installed which will give notification of file duplications and file closes. 18. Incompatibilities with 12/28/93 version. None intentional. ksh-1.0.10/src/cmd/ksh93/SHOPT.sh000066400000000000000000000047011465301102200160760ustar00rootroot00000000000000# # Compile-time SHOPT_* options for ksh93. # 1 to enable, 0 to disable, empty value to probe. # # For a more complete description of the options, see src/cmd/ksh93/README. # SHOPT ACCT=0 # accounting SHOPT ACCTFILE=0 # per-user accounting info SHOPT ALL_LIBCMD=0 # enable all available builtins in src/lib/libcmd SHOPT AUDIT=1 # enable auditing per SHOPT_AUDITFILE SHOPT AUDITFILE='"/etc/ksh_audit"' # auditing file SHOPT BGX=1 # one SIGCHLD trap per completed job SHOPT BRACEPAT=1 # C-shell {...,...} expansions (, required) SHOPT CMDLIB_HDR= # '' # custom -lcmd list for path-bound builtins SHOPT CMDLIB_DIR= # '"/opt/ast/bin"' # virtual directory prefix for path-bound builtins SHOPT CRNL= # accept MS Windows newlines () for SHOPT DEVFD= # use /dev/fd instead of FIFOs for process substitutions SHOPT DYNAMIC=1 # dynamic loading for builtins SHOPT ECHOPRINT= # make echo equivalent to print SHOPT EDPREDICT=0 # History pattern search menu (type #, then ESC TAB). Experimental. SHOPT ESH=1 # emacs/gmacs edit mode SHOPT FILESCAN=1 # fast file scan: while