summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKiyoshi Aman <kiyoshi.aman+adelie@gmail.com>2019-03-15 13:08:45 -0500
committerKiyoshi Aman <kiyoshi.aman+adelie@gmail.com>2019-03-15 13:08:45 -0500
commit09cff699a514e452eccc6420f1213967b767cb3e (patch)
treee9888cd55d03c840b20d080af4e472453c910835
parentffeabdfb18fd21102159641f5258e8b1c473dec2 (diff)
downloaduserland-09cff699a514e452eccc6420f1213967b767cb3e.tar.gz
userland-09cff699a514e452eccc6420f1213967b767cb3e.tar.bz2
userland-09cff699a514e452eccc6420f1213967b767cb3e.tar.xz
userland-09cff699a514e452eccc6420f1213967b767cb3e.zip
rm bin/sh usr.bin/make: utilities provided by other packages
-rw-r--r--bin/sh/TOUR357
-rw-r--r--bin/sh/USD.doc/Makefile12
-rw-r--r--bin/sh/USD.doc/Rv7man405
-rw-r--r--bin/sh/USD.doc/referargs8
-rw-r--r--bin/sh/USD.doc/t.mac69
-rw-r--r--bin/sh/USD.doc/t1553
-rw-r--r--bin/sh/USD.doc/t2971
-rw-r--r--bin/sh/USD.doc/t3976
-rw-r--r--bin/sh/USD.doc/t4180
-rw-r--r--bin/sh/alias.c314
-rw-r--r--bin/sh/alias.h48
-rw-r--r--bin/sh/arith_token.c262
-rw-r--r--bin/sh/arith_tokens.h120
-rw-r--r--bin/sh/arithmetic.c502
-rw-r--r--bin/sh/arithmetic.h42
-rw-r--r--bin/sh/bltin/bltin.h105
-rw-r--r--bin/sh/bltin/echo.1109
-rw-r--r--bin/sh/bltin/echo.c122
-rw-r--r--bin/sh/builtins.def98
-rw-r--r--bin/sh/cd.c463
-rw-r--r--bin/sh/cd.h34
-rw-r--r--bin/sh/error.c378
-rw-r--r--bin/sh/error.h120
-rw-r--r--bin/sh/eval.c1680
-rw-r--r--bin/sh/eval.h87
-rw-r--r--bin/sh/exec.c1183
-rw-r--r--bin/sh/exec.h78
-rw-r--r--bin/sh/expand.c2125
-rw-r--r--bin/sh/expand.h71
-rw-r--r--bin/sh/funcs/cmv43
-rw-r--r--bin/sh/funcs/dirs67
-rw-r--r--bin/sh/funcs/kill43
-rw-r--r--bin/sh/funcs/login32
-rw-r--r--bin/sh/funcs/newgrp31
-rw-r--r--bin/sh/funcs/popd67
-rw-r--r--bin/sh/funcs/pushd67
-rw-r--r--bin/sh/funcs/suspend35
-rw-r--r--bin/sh/histedit.c576
-rw-r--r--bin/sh/init.h39
-rw-r--r--bin/sh/input.c695
-rw-r--r--bin/sh/input.h69
-rw-r--r--bin/sh/jobs.c1812
-rw-r--r--bin/sh/jobs.h105
-rw-r--r--bin/sh/machdep.h47
-rw-r--r--bin/sh/mail.c144
-rw-r--r--bin/sh/mail.h37
-rw-r--r--bin/sh/main.c393
-rw-r--r--bin/sh/main.h42
-rw-r--r--bin/sh/memalloc.c334
-rw-r--r--bin/sh/memalloc.h79
-rw-r--r--bin/sh/miscbltin.c458
-rw-r--r--bin/sh/miscbltin.h31
-rw-r--r--bin/sh/mkbuiltins136
-rwxr-xr-xbin/sh/mkinit.sh224
-rwxr-xr-xbin/sh/mknodenames.sh69
-rwxr-xr-xbin/sh/mknodes.sh242
-rw-r--r--bin/sh/mkoptions.sh198
-rw-r--r--bin/sh/mktokens99
-rw-r--r--bin/sh/myhistedit.h48
-rw-r--r--bin/sh/mystring.c140
-rw-r--r--bin/sh/mystring.h45
-rw-r--r--bin/sh/nodes.c.pat210
-rw-r--r--bin/sh/nodetypes149
-rw-r--r--bin/sh/option.list79
-rw-r--r--bin/sh/options.c631
-rw-r--r--bin/sh/options.h72
-rw-r--r--bin/sh/output.c755
-rw-r--r--bin/sh/output.h109
-rw-r--r--bin/sh/parser.c2756
-rw-r--r--bin/sh/parser.h169
-rw-r--r--bin/sh/redir.c982
-rw-r--r--bin/sh/redir.h55
-rw-r--r--bin/sh/sh.14549
-rw-r--r--bin/sh/shell.h224
-rw-r--r--bin/sh/show.c1175
-rw-r--r--bin/sh/show.h46
-rw-r--r--bin/sh/syntax.c111
-rw-r--r--bin/sh/syntax.h98
-rw-r--r--bin/sh/trap.c837
-rw-r--r--bin/sh/trap.h52
-rw-r--r--bin/sh/var.c1587
-rw-r--r--bin/sh/var.h151
-rw-r--r--bin/sh/version.h36
-rw-r--r--usr.bin/make/Makefile.boot45
-rw-r--r--usr.bin/make/PSD.doc/Makefile10
-rw-r--r--usr.bin/make/PSD.doc/tutorial.ms3794
-rw-r--r--usr.bin/make/arch.c1369
-rw-r--r--usr.bin/make/buf.c291
-rw-r--r--usr.bin/make/buf.h119
-rw-r--r--usr.bin/make/compat.c778
-rw-r--r--usr.bin/make/cond.c1436
-rw-r--r--usr.bin/make/config.h160
-rw-r--r--usr.bin/make/dir.c1849
-rw-r--r--usr.bin/make/dir.h108
-rw-r--r--usr.bin/make/for.c496
-rw-r--r--usr.bin/make/hash.c466
-rw-r--r--usr.bin/make/hash.h149
-rw-r--r--usr.bin/make/job.c3070
-rw-r--r--usr.bin/make/job.h274
-rw-r--r--usr.bin/make/lst.h189
-rw-r--r--usr.bin/make/lst.lib/Makefile10
-rw-r--r--usr.bin/make/lst.lib/lstAppend.c122
-rw-r--r--usr.bin/make/lst.lib/lstAtEnd.c79
-rw-r--r--usr.bin/make/lst.lib/lstAtFront.c76
-rw-r--r--usr.bin/make/lst.lib/lstClose.c86
-rw-r--r--usr.bin/make/lst.lib/lstConcat.c185
-rw-r--r--usr.bin/make/lst.lib/lstDatum.c77
-rw-r--r--usr.bin/make/lst.lib/lstDeQueue.c87
-rw-r--r--usr.bin/make/lst.lib/lstDestroy.c101
-rw-r--r--usr.bin/make/lst.lib/lstDupl.c107
-rw-r--r--usr.bin/make/lst.lib/lstEnQueue.c78
-rw-r--r--usr.bin/make/lst.lib/lstFind.c74
-rw-r--r--usr.bin/make/lst.lib/lstFindFrom.c90
-rw-r--r--usr.bin/make/lst.lib/lstFirst.c77
-rw-r--r--usr.bin/make/lst.lib/lstForEach.c76
-rw-r--r--usr.bin/make/lst.lib/lstForEachFrom.c125
-rw-r--r--usr.bin/make/lst.lib/lstInit.c85
-rw-r--r--usr.bin/make/lst.lib/lstInsert.c122
-rw-r--r--usr.bin/make/lst.lib/lstInt.h105
-rw-r--r--usr.bin/make/lst.lib/lstIsAtEnd.c87
-rw-r--r--usr.bin/make/lst.lib/lstIsEmpty.c75
-rw-r--r--usr.bin/make/lst.lib/lstLast.c77
-rw-r--r--usr.bin/make/lst.lib/lstMember.c77
-rw-r--r--usr.bin/make/lst.lib/lstNext.c120
-rw-r--r--usr.bin/make/lst.lib/lstOpen.c87
-rw-r--r--usr.bin/make/lst.lib/lstPrev.c79
-rw-r--r--usr.bin/make/lst.lib/lstRemove.c136
-rw-r--r--usr.bin/make/lst.lib/lstReplace.c78
-rw-r--r--usr.bin/make/lst.lib/lstSucc.c79
-rw-r--r--usr.bin/make/main.c2189
-rw-r--r--usr.bin/make/make.12413
-rw-r--r--usr.bin/make/make.c1555
-rw-r--r--usr.bin/make/make.h535
-rw-r--r--usr.bin/make/make_malloc.c119
-rw-r--r--usr.bin/make/make_malloc.h41
-rw-r--r--usr.bin/make/meta.c1641
-rw-r--r--usr.bin/make/meta.h56
-rw-r--r--usr.bin/make/metachar.c88
-rw-r--r--usr.bin/make/metachar.h61
-rw-r--r--usr.bin/make/nonints.h198
-rw-r--r--usr.bin/make/parse.c3357
-rw-r--r--usr.bin/make/pathnames.h53
-rw-r--r--usr.bin/make/sprite.h116
-rw-r--r--usr.bin/make/str.c526
-rw-r--r--usr.bin/make/strlist.c93
-rw-r--r--usr.bin/make/strlist.h62
-rw-r--r--usr.bin/make/suff.c2676
-rw-r--r--usr.bin/make/targ.c846
-rw-r--r--usr.bin/make/trace.c116
-rw-r--r--usr.bin/make/trace.h49
-rw-r--r--usr.bin/make/unit-tests/Makefile139
-rw-r--r--usr.bin/make/unit-tests/comment.exp5
-rw-r--r--usr.bin/make/unit-tests/comment.mk31
-rw-r--r--usr.bin/make/unit-tests/cond1.exp23
-rw-r--r--usr.bin/make/unit-tests/cond1.mk109
-rw-r--r--usr.bin/make/unit-tests/cond2.exp7
-rw-r--r--usr.bin/make/unit-tests/cond2.mk29
-rw-r--r--usr.bin/make/unit-tests/doterror.exp9
-rw-r--r--usr.bin/make/unit-tests/doterror.mk20
-rw-r--r--usr.bin/make/unit-tests/dotwait.exp30
-rw-r--r--usr.bin/make/unit-tests/dotwait.mk61
-rw-r--r--usr.bin/make/unit-tests/error.exp4
-rw-r--r--usr.bin/make/unit-tests/error.mk10
-rw-r--r--usr.bin/make/unit-tests/escape.exp104
-rw-r--r--usr.bin/make/unit-tests/escape.mk246
-rw-r--r--usr.bin/make/unit-tests/export-all.exp12
-rw-r--r--usr.bin/make/unit-tests/export-all.mk23
-rw-r--r--usr.bin/make/unit-tests/export-env.exp11
-rw-r--r--usr.bin/make/unit-tests/export-env.mk27
-rw-r--r--usr.bin/make/unit-tests/export.exp6
-rw-r--r--usr.bin/make/unit-tests/export.mk22
-rw-r--r--usr.bin/make/unit-tests/forloop.exp19
-rw-r--r--usr.bin/make/unit-tests/forloop.mk45
-rw-r--r--usr.bin/make/unit-tests/forsubst.exp2
-rw-r--r--usr.bin/make/unit-tests/forsubst.mk10
-rw-r--r--usr.bin/make/unit-tests/hash.exp9
-rw-r--r--usr.bin/make/unit-tests/hash.mk18
-rw-r--r--usr.bin/make/unit-tests/impsrc.exp13
-rw-r--r--usr.bin/make/unit-tests/impsrc.mk43
-rw-r--r--usr.bin/make/unit-tests/misc.exp1
-rw-r--r--usr.bin/make/unit-tests/misc.mk16
-rw-r--r--usr.bin/make/unit-tests/moderrs.exp16
-rw-r--r--usr.bin/make/unit-tests/moderrs.mk31
-rw-r--r--usr.bin/make/unit-tests/modmatch.exp20
-rw-r--r--usr.bin/make/unit-tests/modmatch.mk34
-rw-r--r--usr.bin/make/unit-tests/modmisc.exp10
-rw-r--r--usr.bin/make/unit-tests/modmisc.mk38
-rw-r--r--usr.bin/make/unit-tests/modorder.exp11
-rw-r--r--usr.bin/make/unit-tests/modorder.mk22
-rw-r--r--usr.bin/make/unit-tests/modts.exp39
-rw-r--r--usr.bin/make/unit-tests/modts.mk44
-rw-r--r--usr.bin/make/unit-tests/modword.exp122
-rw-r--r--usr.bin/make/unit-tests/modword.mk151
-rw-r--r--usr.bin/make/unit-tests/order.exp4
-rw-r--r--usr.bin/make/unit-tests/order.mk20
-rw-r--r--usr.bin/make/unit-tests/phony-end.exp6
-rw-r--r--usr.bin/make/unit-tests/phony-end.mk9
-rw-r--r--usr.bin/make/unit-tests/posix.exp23
-rw-r--r--usr.bin/make/unit-tests/posix.mk24
-rw-r--r--usr.bin/make/unit-tests/posix1.exp186
-rw-r--r--usr.bin/make/unit-tests/posix1.mk184
-rw-r--r--usr.bin/make/unit-tests/qequals.exp2
-rw-r--r--usr.bin/make/unit-tests/qequals.mk8
-rw-r--r--usr.bin/make/unit-tests/suffixes.exp35
-rw-r--r--usr.bin/make/unit-tests/suffixes.mk89
-rw-r--r--usr.bin/make/unit-tests/sunshcmd.exp4
-rw-r--r--usr.bin/make/unit-tests/sunshcmd.mk10
-rw-r--r--usr.bin/make/unit-tests/sysv.exp7
-rw-r--r--usr.bin/make/unit-tests/sysv.mk26
-rw-r--r--usr.bin/make/unit-tests/ternary.exp10
-rw-r--r--usr.bin/make/unit-tests/ternary.mk8
-rw-r--r--usr.bin/make/unit-tests/unexport-env.exp2
-rw-r--r--usr.bin/make/unit-tests/unexport-env.mk14
-rw-r--r--usr.bin/make/unit-tests/unexport.exp4
-rw-r--r--usr.bin/make/unit-tests/unexport.mk8
-rw-r--r--usr.bin/make/unit-tests/varcmd.exp11
-rw-r--r--usr.bin/make/unit-tests/varcmd.mk60
-rw-r--r--usr.bin/make/unit-tests/varmisc.exp25
-rw-r--r--usr.bin/make/unit-tests/varmisc.mk62
-rw-r--r--usr.bin/make/unit-tests/varquote.exp3
-rw-r--r--usr.bin/make/unit-tests/varquote.mk14
-rw-r--r--usr.bin/make/unit-tests/varshell.exp12
-rw-r--r--usr.bin/make/unit-tests/varshell.mk18
-rw-r--r--usr.bin/make/util.c494
-rw-r--r--usr.bin/make/var.c4355
225 files changed, 0 insertions, 74181 deletions
diff --git a/bin/sh/TOUR b/bin/sh/TOUR
deleted file mode 100644
index 30cee04..0000000
--- a/bin/sh/TOUR
+++ /dev/null
@@ -1,357 +0,0 @@
-# $NetBSD: TOUR,v 1.11 2016/10/25 13:01:59 abhinav Exp $
-# @(#)TOUR 8.1 (Berkeley) 5/31/93
-
-NOTE -- This is the original TOUR paper distributed with ash and
-does not represent the current state of the shell. It is provided anyway
-since it provides helpful information for how the shell is structured,
-but be warned that things have changed -- the current shell is
-still under development.
-
-================================================================
-
- A Tour through Ash
-
- Copyright 1989 by Kenneth Almquist.
-
-
-DIRECTORIES: The subdirectory bltin contains commands which can
-be compiled stand-alone. The rest of the source is in the main
-ash directory.
-
-SOURCE CODE GENERATORS: Files whose names begin with "mk" are
-programs that generate source code. A complete list of these
-programs is:
-
- program input files generates
- ------- ------------ ---------
- mkbuiltins builtins builtins.h builtins.c
- mkinit *.c init.c
- mknodes nodetypes nodes.h nodes.c
- mksignames - signames.h signames.c
- mksyntax - syntax.h syntax.c
- mktokens - token.h
- bltin/mkexpr unary_op binary_op operators.h operators.c
-
-There are undoubtedly too many of these. Mkinit searches all the
-C source files for entries looking like:
-
- INIT {
- x = 1; /* executed during initialization */
- }
-
- RESET {
- x = 2; /* executed when the shell does a longjmp
- back to the main command loop */
- }
-
- SHELLPROC {
- x = 3; /* executed when the shell runs a shell procedure */
- }
-
-It pulls this code out into routines which are when particular
-events occur. The intent is to improve modularity by isolating
-the information about which modules need to be explicitly
-initialized/reset within the modules themselves.
-
-Mkinit recognizes several constructs for placing declarations in
-the init.c file.
- INCLUDE "file.h"
-includes a file. The storage class MKINIT makes a declaration
-available in the init.c file, for example:
- MKINIT int funcnest; /* depth of function calls */
-MKINIT alone on a line introduces a structure or union declara-
-tion:
- MKINIT
- struct redirtab {
- short renamed[10];
- };
-Preprocessor #define statements are copied to init.c without any
-special action to request this.
-
-INDENTATION: The ash source is indented in multiples of six
-spaces. The only study that I have heard of on the subject con-
-cluded that the optimal amount to indent is in the range of four
-to six spaces. I use six spaces since it is not too big a jump
-from the widely used eight spaces. If you really hate six space
-indentation, use the adjind (source included) program to change
-it to something else.
-
-EXCEPTIONS: Code for dealing with exceptions appears in
-exceptions.c. The C language doesn't include exception handling,
-so I implement it using setjmp and longjmp. The global variable
-exception contains the type of exception. EXERROR is raised by
-calling error. EXINT is an interrupt. EXSHELLPROC is an excep-
-tion which is raised when a shell procedure is invoked. The pur-
-pose of EXSHELLPROC is to perform the cleanup actions associated
-with other exceptions. After these cleanup actions, the shell
-can interpret a shell procedure itself without exec'ing a new
-copy of the shell.
-
-INTERRUPTS: In an interactive shell, an interrupt will cause an
-EXINT exception to return to the main command loop. (Exception:
-EXINT is not raised if the user traps interrupts using the trap
-command.) The INTOFF and INTON macros (defined in exception.h)
-provide uninterruptible critical sections. Between the execution
-of INTOFF and the execution of INTON, interrupt signals will be
-held for later delivery. INTOFF and INTON can be nested.
-
-MEMALLOC.C: Memalloc.c defines versions of malloc and realloc
-which call error when there is no memory left. It also defines a
-stack oriented memory allocation scheme. Allocating off a stack
-is probably more efficient than allocation using malloc, but the
-big advantage is that when an exception occurs all we have to do
-to free up the memory in use at the time of the exception is to
-restore the stack pointer. The stack is implemented using a
-linked list of blocks.
-
-STPUTC: If the stack were contiguous, it would be easy to store
-strings on the stack without knowing in advance how long the
-string was going to be:
- p = stackptr;
- *p++ = c; /* repeated as many times as needed */
- stackptr = p;
-The following three macros (defined in memalloc.h) perform these
-operations, but grow the stack if you run off the end:
- STARTSTACKSTR(p);
- STPUTC(c, p); /* repeated as many times as needed */
- grabstackstr(p);
-
-We now start a top-down look at the code:
-
-MAIN.C: The main routine performs some initialization, executes
-the user's profile if necessary, and calls cmdloop. Cmdloop
-repeatedly parses and executes commands.
-
-OPTIONS.C: This file contains the option processing code. It is
-called from main to parse the shell arguments when the shell is
-invoked, and it also contains the set builtin. The -i and -j op-
-tions (the latter turns on job control) require changes in signal
-handling. The routines setjobctl (in jobs.c) and setinteractive
-(in trap.c) are called to handle changes to these options.
-
-PARSING: The parser code is all in parser.c. A recursive des-
-cent parser is used. Syntax tables (generated by mksyntax) are
-used to classify characters during lexical analysis. There are
-three tables: one for normal use, one for use when inside single
-quotes, and one for use when inside double quotes. The tables
-are machine dependent because they are indexed by character vari-
-ables and the range of a char varies from machine to machine.
-
-PARSE OUTPUT: The output of the parser consists of a tree of
-nodes. The various types of nodes are defined in the file node-
-types.
-
-Nodes of type NARG are used to represent both words and the con-
-tents of here documents. An early version of ash kept the con-
-tents of here documents in temporary files, but keeping here do-
-cuments in memory typically results in significantly better per-
-formance. It would have been nice to make it an option to use
-temporary files for here documents, for the benefit of small
-machines, but the code to keep track of when to delete the tem-
-porary files was complex and I never fixed all the bugs in it.
-(AT&T has been maintaining the Bourne shell for more than ten
-years, and to the best of my knowledge they still haven't gotten
-it to handle temporary files correctly in obscure cases.)
-
-The text field of a NARG structure points to the text of the
-word. The text consists of ordinary characters and a number of
-special codes defined in parser.h. The special codes are:
-
- CTLVAR Variable substitution
- CTLENDVAR End of variable substitution
- CTLBACKQ Command substitution
- CTLBACKQ|CTLQUOTE Command substitution inside double quotes
- CTLESC Escape next character
-
-A variable substitution contains the following elements:
-
- CTLVAR type name '=' [ alternative-text CTLENDVAR ]
-
-The type field is a single character specifying the type of sub-
-stitution. The possible types are:
-
- VSNORMAL $var
- VSMINUS ${var-text}
- VSMINUS|VSNUL ${var:-text}
- VSPLUS ${var+text}
- VSPLUS|VSNUL ${var:+text}
- VSQUESTION ${var?text}
- VSQUESTION|VSNUL ${var:?text}
- VSASSIGN ${var=text}
- VSASSIGN|VSNUL ${var=text}
-
-In addition, the type field will have the VSQUOTE flag set if the
-variable is enclosed in double quotes. The name of the variable
-comes next, terminated by an equals sign. If the type is not
-VSNORMAL, then the text field in the substitution follows, ter-
-minated by a CTLENDVAR byte.
-
-Commands in back quotes are parsed and stored in a linked list.
-The locations of these commands in the string are indicated by
-CTLBACKQ and CTLBACKQ+CTLQUOTE characters, depending upon whether
-the back quotes were enclosed in double quotes.
-
-The character CTLESC escapes the next character, so that in case
-any of the CTL characters mentioned above appear in the input,
-they can be passed through transparently. CTLESC is also used to
-escape '*', '?', '[', and '!' characters which were quoted by the
-user and thus should not be used for file name generation.
-
-CTLESC characters have proved to be particularly tricky to get
-right. In the case of here documents which are not subject to
-variable and command substitution, the parser doesn't insert any
-CTLESC characters to begin with (so the contents of the text
-field can be written without any processing). Other here docu-
-ments, and words which are not subject to splitting and file name
-generation, have the CTLESC characters removed during the vari-
-able and command substitution phase. Words which are subject
-splitting and file name generation have the CTLESC characters re-
-moved as part of the file name phase.
-
-EXECUTION: Command execution is handled by the following files:
- eval.c The top level routines.
- redir.c Code to handle redirection of input and output.
- jobs.c Code to handle forking, waiting, and job control.
- exec.c Code to do path searches and the actual exec sys call.
- expand.c Code to evaluate arguments.
- var.c Maintains the variable symbol table. Called from expand.c.
-
-EVAL.C: Evaltree recursively executes a parse tree. The exit
-status is returned in the global variable exitstatus. The alter-
-native entry evalbackcmd is called to evaluate commands in back
-quotes. It saves the result in memory if the command is a buil-
-tin; otherwise it forks off a child to execute the command and
-connects the standard output of the child to a pipe.
-
-JOBS.C: To create a process, you call makejob to return a job
-structure, and then call forkshell (passing the job structure as
-an argument) to create the process. Waitforjob waits for a job
-to complete. These routines take care of process groups if job
-control is defined.
-
-REDIR.C: Ash allows file descriptors to be redirected and then
-restored without forking off a child process. This is accom-
-plished by duplicating the original file descriptors. The redir-
-tab structure records where the file descriptors have been dupli-
-cated to.
-
-EXEC.C: The routine find_command locates a command, and enters
-the command in the hash table if it is not already there. The
-third argument specifies whether it is to print an error message
-if the command is not found. (When a pipeline is set up,
-find_command is called for all the commands in the pipeline be-
-fore any forking is done, so to get the commands into the hash
-table of the parent process. But to make command hashing as
-transparent as possible, we silently ignore errors at that point
-and only print error messages if the command cannot be found
-later.)
-
-The routine shellexec is the interface to the exec system call.
-
-EXPAND.C: Arguments are processed in three passes. The first
-(performed by the routine argstr) performs variable and command
-substitution. The second (ifsbreakup) performs word splitting
-and the third (expandmeta) performs file name generation. If the
-"/u" directory is simulated, then when "/u/username" is replaced
-by the user's home directory, the flag "didudir" is set. This
-tells the cd command that it should print out the directory name,
-just as it would if the "/u" directory were implemented using
-symbolic links.
-
-VAR.C: Variables are stored in a hash table. Probably we should
-switch to extensible hashing. The variable name is stored in the
-same string as the value (using the format "name=value") so that
-no string copying is needed to create the environment of a com-
-mand. Variables which the shell references internally are preal-
-located so that the shell can reference the values of these vari-
-ables without doing a lookup.
-
-When a program is run, the code in eval.c sticks any environment
-variables which precede the command (as in "PATH=xxx command") in
-the variable table as the simplest way to strip duplicates, and
-then calls "environment" to get the value of the environment.
-There are two consequences of this. First, if an assignment to
-PATH precedes the command, the value of PATH before the assign-
-ment must be remembered and passed to shellexec. Second, if the
-program turns out to be a shell procedure, the strings from the
-environment variables which preceded the command must be pulled
-out of the table and replaced with strings obtained from malloc,
-since the former will automatically be freed when the stack (see
-the entry on memalloc.c) is emptied.
-
-BUILTIN COMMANDS: The procedures for handling these are scat-
-tered throughout the code, depending on which location appears
-most appropriate. They can be recognized because their names al-
-ways end in "cmd". The mapping from names to procedures is
-specified in the file builtins, which is processed by the mkbuil-
-tins command.
-
-A builtin command is invoked with argc and argv set up like a
-normal program. A builtin command is allowed to overwrite its
-arguments. Builtin routines can call nextopt to do option pars-
-ing. This is kind of like getopt, but you don't pass argc and
-argv to it. Builtin routines can also call error. This routine
-normally terminates the shell (or returns to the main command
-loop if the shell is interactive), but when called from a builtin
-command it causes the builtin command to terminate with an exit
-status of 2.
-
-The directory bltins contains commands which can be compiled in-
-dependently but can also be built into the shell for efficiency
-reasons. The makefile in this directory compiles these programs
-in the normal fashion (so that they can be run regardless of
-whether the invoker is ash), but also creates a library named
-bltinlib.a which can be linked with ash. The header file bltin.h
-takes care of most of the differences between the ash and the
-stand-alone environment. The user should call the main routine
-"main", and #define main to be the name of the routine to use
-when the program is linked into ash. This #define should appear
-before bltin.h is included; bltin.h will #undef main if the pro-
-gram is to be compiled stand-alone.
-
-CD.C: This file defines the cd and pwd builtins. The pwd com-
-mand runs /bin/pwd the first time it is invoked (unless the user
-has already done a cd to an absolute pathname), but then
-remembers the current directory and updates it when the cd com-
-mand is run, so subsequent pwd commands run very fast. The main
-complication in the cd command is in the docd command, which
-resolves symbolic links into actual names and informs the user
-where the user ended up if he crossed a symbolic link.
-
-SIGNALS: Trap.c implements the trap command. The routine set-
-signal figures out what action should be taken when a signal is
-received and invokes the signal system call to set the signal ac-
-tion appropriately. When a signal that a user has set a trap for
-is caught, the routine "onsig" sets a flag. The routine dotrap
-is called at appropriate points to actually handle the signal.
-When an interrupt is caught and no trap has been set for that
-signal, the routine "onint" in error.c is called.
-
-OUTPUT: Ash uses its own output routines. There are three out-
-put structures allocated. "Output" represents the standard out-
-put, "errout" the standard error, and "memout" contains output
-which is to be stored in memory. This last is used when a buil-
-tin command appears in backquotes, to allow its output to be col-
-lected without doing any I/O through the UNIX operating system.
-The variables out1 and out2 normally point to output and errout,
-respectively, but they are set to point to memout when appropri-
-ate inside backquotes.
-
-INPUT: The basic input routine is pgetc, which reads from the
-current input file. There is a stack of input files; the current
-input file is the top file on this stack. The code allows the
-input to come from a string rather than a file. (This is for the
--c option and the "." and eval builtin commands.) The global
-variable plinno is saved and restored when files are pushed and
-popped from the stack. The parser routines store the number of
-the current line in this variable.
-
-DEBUGGING: If DEBUG is defined in shell.h, then the shell will
-write debugging information to the file $HOME/trace. Most of
-this is done using the TRACE macro, which takes a set of printf
-arguments inside two sets of parenthesis. Example:
-"TRACE(("n=%d0, n))". The double parenthesis are necessary be-
-cause the preprocessor can't handle functions with a variable
-number of arguments. Defining DEBUG also causes the shell to
-generate a core dump if it is sent a quit signal. The tracing
-code is in show.c.
diff --git a/bin/sh/USD.doc/Makefile b/bin/sh/USD.doc/Makefile
deleted file mode 100644
index 55b7203..0000000
--- a/bin/sh/USD.doc/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-# $NetBSD: Makefile,v 1.4 2014/07/05 19:23:00 dholland Exp $
-# @(#)Makefile 8.1 (Berkeley) 8/14/93
-
-SECTION=reference/ref1
-ARTICLE=sh
-SRCS= referargs t.mac t1 t2 t3 t4
-MACROS=-ms
-ROFF_REFER=yes
-#REFER_ARGS=-e -p Rv7man
-EXTRAHTMLFILES=sh1.png sh2.png sh3.png sh4.png sh5.png
-
-.include <bsd.doc.mk>
diff --git a/bin/sh/USD.doc/Rv7man b/bin/sh/USD.doc/Rv7man
deleted file mode 100644
index 628c67f..0000000
--- a/bin/sh/USD.doc/Rv7man
+++ /dev/null
@@ -1,405 +0,0 @@
-%A L. P. Deutsch
-%A B. W. Lampson
-%T An online editor
-%J Comm. Assoc. Comp. Mach.
-%V 10
-%N 12
-%D December 1967
-%P 793-799, 803
-%K qed
-
-.[
-%r 17
-%K cstr
-%R Comp. Sci. Tech. Rep. No. 17
-%I Bell Laboratories
-%C Murray Hill, New Jersey
-%A B. W. Kernighan
-%A L. L. Cherry
-%T A System for Typesetting Mathematics
-%d May 1974, revised April 1977
-%J Comm. Assoc. Comp. Mach.
-%K acm cacm
-%V 18
-%P 151-157
-%D March 1975
-.]
-
-%T U\s-2NIX\s0 Time-Sharing System: Document Preparation
-%K unix bstj
-%A B. W. Kernighan
-%A M. E. Lesk
-%A J. F. Ossanna
-%J Bell Sys. Tech. J.
-%V 57
-%N 6
-%P 2115-2135
-%D 1978
-
-%A T. A. Dolotta
-%A J. R. Mashey
-%T An Introduction to the Programmer's Workbench
-%J Proc. 2nd Int. Conf. on Software Engineering
-%D October 13-15, 1976
-%P 164-168
-
-%T U\s-2NIX\s0 Time-Sharing System: The Programmer's Workbench
-%A T. A. Dolotta
-%A R. C. Haight
-%A J. R. Mashey
-%J Bell Sys. Tech. J.
-%V 57
-%N 6
-%P 2177-2200
-%D 1978
-%K unix bstj
-
-%T U\s-2NIX\s0 Time-Sharing System: U\s-2NIX\s0 on a Microprocessor
-%K unix bstj
-%A H. Lycklama
-%J Bell Sys. Tech. J.
-%V 57
-%N 6
-%P 2087-2101
-%D 1978
-
-%T The C Programming Language
-%A B. W. Kernighan
-%A D. M. Ritchie
-%I Prentice-Hall
-%C Englewood Cliffs, New Jersey
-%D 1978
-
-%T Computer Recreations
-%A Aleph-null
-%J Software Practice and Experience
-%V 1
-%N 2
-%D April-June 1971
-%P 201-204
-
-%T U\s-2NIX\s0 Time-Sharing System: The U\s-2NIX\s0 Shell
-%A S. R. Bourne
-%K unix bstj
-%J Bell Sys. Tech. J.
-%V 57
-%N 6
-%P 1971-1990
-%D 1978
-
-%A L. P. Deutsch
-%A B. W. Lampson
-%T \*sSDS\*n 930 time-sharing system preliminary reference manual
-%R Doc. 30.10.10, Project \*sGENIE\*n
-%C Univ. Cal. at Berkeley
-%D April 1965
-
-%A R. J. Feiertag
-%A E. I. Organick
-%T The Multics input-output system
-%J Proc. Third Symposium on Operating Systems Principles
-%D October 18-20, 1971
-%P 35-41
-
-%A D. G. Bobrow
-%A J. D. Burchfiel
-%A D. L. Murphy
-%A R. S. Tomlinson
-%T \*sTENEX\*n, a Paged Time Sharing System for the \*sPDP\*n-10
-%J Comm. Assoc. Comp. Mach.
-%V 15
-%N 3
-%D March 1972
-%K tenex
-%P 135-143
-
-%A R. E. Griswold
-%A D. R. Hanson
-%T An Overview of SL5
-%J SIGPLAN Notices
-%V 12
-%N 4
-%D April 1977
-%P 40-50
-
-%A E. W. Dijkstra
-%T Cooperating Sequential Processes
-%B Programming Languages
-%E F. Genuys
-%I Academic Press
-%C New York
-%D 1968
-%P 43-112
-
-%A J. A. Hawley
-%A W. B. Meyer
-%T M\s-2UNIX\s0, A Multiprocessing Version of U\s-2NIX\s0
-%K munix unix
-%R M.S. Thesis
-%I Naval Postgraduate School
-%C Monterey, Cal.
-%D 1975
-
-%T The U\s-2NIX\s0 Time-Sharing System
-%K unix bstj
-%A D. M. Ritchie
-%A K. Thompson
-%J Bell Sys. Tech. J.
-%V 57
-%N 6
-%P 1905-1929
-%D 1978
-
-%A E. I. Organick
-%T The M\s-2ULTICS\s0 System
-%K multics
-%I M.I.T. Press
-%C Cambridge, Mass.
-%D 1972
-
-%T UNIX for Beginners
-%A B. W. Kernighan
-%D 1978
-
-%T U\s-2NIX\s0 Programmer's Man\&ual
-%A K. Thompson
-%A D. M. Ritchie
-%K unix
-%I Bell Laboratories
-%O Seventh Edition.
-%D 1978
-
-%A K. Thompson
-%T The U\s-2NIX\s0 Command Language
-%B Structured Programming\(emInfotech State of the Art Report
-%I Infotech International Ltd.
-%C Nicholson House, Maidenhead, Berkshire, England
-%D March 1975
-%P 375-384
-%K unix
-%X pwb
-Brief description of shell syntax and semantics, without much
-detail on implementation.
-Much on pipes and convenience of hooking programs together.
-Includes SERMONETTE:
-"Many familiar computing `concepts' are missing from UNIX.
-Files have no records. There are no access methods.
-There are no file types. These concepts fill a much-needed gap.
-I sincerely hope that when future systems are designed by
-manufacturers the value of some of these ingrained notions is re-examined.
-Like the politician and his `common man', manufacturers have
-their `average user'.
-
-%A J. R. Mashey
-%T PWB/UNIX Shell Tutorial
-%D September 30, 1977
-
-%A D. F. Hartley (Ed.)
-%T The Cambridge Multiple Access System \- Users Reference Manual
-%I University Mathematical Laboratory
-%C Cambridge, England
-%D 1968
-
-%A P. A. Crisman (Ed.)
-%T The Compatible Time-Sharing System
-%I M.I.T. Press
-%K whole ctss book
-%C Cambridge, Mass.
-%D 1965
-
-%T LR Parsing
-%A A. V. Aho
-%A S. C. Johnson
-%J Comp. Surveys
-%V 6
-%N 2
-%P 99-124
-%D June 1974
-
-%T Deterministic Parsing of Ambiguous Grammars
-%A A. V. Aho
-%A S. C. Johnson
-%A J. D. Ullman
-%J Comm. Assoc. Comp. Mach.
-%K acm cacm
-%V 18
-%N 8
-%P 441-452
-%D August 1975
-
-%A A. V. Aho
-%A J. D. Ullman
-%T Principles of Compiler Design
-%I Addison-Wesley
-%C Reading, Mass.
-%D 1977
-
-.[
-%r 65
-%R Comp. Sci. Tech. Rep. No. 65
-%K CSTR
-%A S. C. Johnson
-%T Lint, a C Program Checker
-%D December 1977
-%O updated version TM 78-1273-3
-%D 1978
-.]
-
-%T A Portable Compiler: Theory and Practice
-%A S. C. Johnson
-%J Proc. 5th ACM Symp. on Principles of Programming Languages
-%P 97-104
-%D January 1978
-
-.[
-%r 39
-%K CSTR
-%R Comp. Sci. Tech. Rep. No. 39
-%I Bell Laboratories
-%C Murray Hill, New Jersey
-%A M. E. Lesk
-%T Lex \(em A Lexical Analyzer Generator
-%D October 1975
-.]
-
-.[
-%r 32
-%K CSTR
-%R Comp. Sci. Tech. Rep. No. 32
-%I Bell Laboratories
-%C Murray Hill, New Jersey
-%A S. C. Johnson
-%T Yacc \(em Yet Another Compiler-Compiler
-%D July 1975
-.]
-
-%T U\s-2NIX\s0 Time-Sharing System: Portability of C Programs and the U\s-2NIX\s0 System
-%K unix bstj
-%A S. C. Johnson
-%A D. M. Ritchie
-%J Bell Sys. Tech. J.
-%V 57
-%N 6
-%P 2021-2048
-%D 1978
-
-%T Typing Documents on UNIX and GCOS: The -ms Macros for Troff
-%A M. E. Lesk
-%D 1977
-
-%A K. Thompson
-%A D. M. Ritchie
-%T U\s-2NIX\s0 Programmer's Manual
-%K unix
-%I Bell Laboratories
-%O Sixth Edition
-%D May 1975
-
-%T The Network U\s-2NIX\s0 System
-%K unix
-%A G. L. Chesson
-%J Operating Systems Review
-%V 9
-%N 5
-%P 60-66
-%D 1975
-%O Also in \f2Proc. 5th Symp. on Operating Systems Principles.\f1
-
-%T Spider \(em An Experimental Data Communications System
-%Z ctr127
-%A A. G. Fraser
-%J Proc. IEEE Conf. on Communications
-%P 21F
-%O IEEE Cat. No. 74CH0859-9-CSCB.
-%D June 1974
-
-%T A Virtual Channel Network
-%A A. G. Fraser
-%J Datamation
-%P 51-56
-%D February 1975
-
-.[
-%r 41
-%K CSTR
-%R Comp. Sci. Tech. Rep. No. 41
-%I Bell Laboratories
-%C Murray Hill, New Jersey
-%A J. W. Hunt
-%A M. D. McIlroy
-%T An Algorithm for Differential File Comparison
-%D June 1976
-.]
-
-%A F. P. Brooks, Jr.
-%T The Mythical Man-Month
-%I Addison-Wesley
-%C Reading, Mass.
-%D 1975
-%X pwb
-Readable, classic reference on software engineering and
-problems of large projects, from someone with experience in them.
-Required reading for any software engineer, even if conclusions may not
-always be agreed with.
-%br
-"The second is the most dangerous system a man ever designs." p.55.
-%br
-"Hence plan to throw one away; you will, anyhow." p.116.
-%br
-"Cosgrove has perceptively pointed out that the programmer delivers
-satisfaction of a user need rather than any tangible product.
-And both the actual need and the user's perception of that need
-will change as programs are built, tested, and used." p.117.
-%br
-"The total cost of maintaining a widely used program is typically 40 percent
-or more of the cost of developing it." p.121.
-%br
-"As shown above, amalgamating prose and program reduces the total
-number of characters to be stored." p.175.
-
-%T A Portable Compiler for the Language C
-%A A. Snyder
-%I Master's Thesis, M.I.T.
-%C Cambridge, Mass.
-%D 1974
-
-%T The C Language Calling Sequence
-%A M. E. Lesk
-%A S. C. Johnson
-%A D. M. Ritchie
-%D 1977
-
-%T Optimal Code Generation for Expression Trees
-%A A. V. Aho
-%A S. C. Johnson
-%D 1975
-%J J. Assoc. Comp. Mach.
-%K acm jacm
-%V 23
-%N 3
-%P 488-501
-%O Also in \f2Proc. ACM Symp. on Theory of Computing,\f1 pp. 207-217, 1975.
-
-%A R. Sethi
-%A J. D. Ullman
-%T The Generation of Optimal Code for Arithmetic Expressions
-%J J. Assoc. Comp. Mach.
-%K acm jacm
-%V 17
-%N 4
-%D October 1970
-%P 715-728
-%O Reprinted as pp. 229-247 in \fICompiler Techniques\fR, ed. B. W. Pollack, Auerbach, Princeton NJ (1972).
-%X pwb
-Optimal approach for straight-line, fixed
-number of regs.
-
-%T Code Generation for Machines with Multiregister
-Operations
-%A A. V. Aho
-%A S. C. Johnson
-%A J. D. Ullman
-%J Proc. 4th ACM Symp. on Principles of Programming Languages
-%P 21-28
-%D January 1977
-
diff --git a/bin/sh/USD.doc/referargs b/bin/sh/USD.doc/referargs
deleted file mode 100644
index 3bb6284..0000000
--- a/bin/sh/USD.doc/referargs
+++ /dev/null
@@ -1,8 +0,0 @@
-.\" $NetBSD: referargs,v 1.1 2014/07/05 19:22:02 dholland Exp $
-.\"
-.\" Arguments for refer; these were previously passed on the refer(1)
-.\" command line: -e -p Rv7man
-.R1
-accumulate
-database Rv7man
-.R2
diff --git a/bin/sh/USD.doc/t.mac b/bin/sh/USD.doc/t.mac
deleted file mode 100644
index 9bf65c8..0000000
--- a/bin/sh/USD.doc/t.mac
+++ /dev/null
@@ -1,69 +0,0 @@
-.\" $NetBSD: t.mac,v 1.2 2010/08/22 02:19:07 perry Exp $
-.\"
-.\" Copyright (C) Caldera International Inc. 2001-2002. All rights reserved.
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions are
-.\" met:
-.\"
-.\" Redistributions of source code and documentation must retain the above
-.\" copyright notice, this list of conditions and the following
-.\" disclaimer.
-.\"
-.\" Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in the
-.\" documentation and/or other materials provided with the distribution.
-.\"
-.\" All advertising materials mentioning features or use of this software
-.\" must display the following acknowledgement:
-.\"
-.\" This product includes software developed or owned by Caldera
-.\" International, Inc. Neither the name of Caldera International, Inc.
-.\" nor the names of other contributors may be used to endorse or promote
-.\" products derived from this software without specific prior written
-.\" permission.
-.\"
-.\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
-.\" INTERNATIONAL, INC. 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 CALDERA INTERNATIONAL, INC. 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) RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
-.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-.\"
-.\" @(#)t.mac 8.1 (Berkeley) 8/14/93
-.\"
-.ds ZZ \fB.\|.\|.\fP
-.ds ST \v'.3m'\s+2*\s0\v'-.3m'
-.ds DO \h'\w'do 'u'
-.ds Ca \h'\w'case 'u'
-.ds WH \h'\w'while 'u'
-.ds VT \|\fB\(or\fP\|
-.ds TH \h'\w'then 'u'
-.ds DC \*(DO\*(Ca
-.ds AP >\h'-.2m'>
-.ds HE <\h'-.2m'<
-. \" macros for algol 68c reference manual
-.ds DA 1977 November 1
-.ds md \v'.25m'
-.ds mu \v'-.25m'
-.ds U \*(mu\s-3
-.ds V \s0\*(md
-.ds L \*(md\s-3
-.ds M \s0\*(mu
-.ds S \s-1
-.ds T \s0
-. \" small 1
-.ds O \*S1\*T
-.ds h \|
-.ds s \|\|
-. \" ellipsis
-.ds e .\|.\|.
-. \" subscripts
-.ds 1 \*(md\s-41\s0\*(mu
-.ds 2 \*(md\s-42\s0\*(mu
diff --git a/bin/sh/USD.doc/t1 b/bin/sh/USD.doc/t1
deleted file mode 100644
index 075511f..0000000
--- a/bin/sh/USD.doc/t1
+++ /dev/null
@@ -1,553 +0,0 @@
-.\" $NetBSD: t1,v 1.3 2010/08/22 02:19:07 perry Exp $
-.\"
-.\" Copyright (C) Caldera International Inc. 2001-2002. All rights reserved.
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions are
-.\" met:
-.\"
-.\" Redistributions of source code and documentation must retain the above
-.\" copyright notice, this list of conditions and the following
-.\" disclaimer.
-.\"
-.\" Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in the
-.\" documentation and/or other materials provided with the distribution.
-.\"
-.\" All advertising materials mentioning features or use of this software
-.\" must display the following acknowledgment:
-.\"
-.\" This product includes software developed or owned by Caldera
-.\" International, Inc. Neither the name of Caldera International, Inc.
-.\" nor the names of other contributors may be used to endorse or promote
-.\" products derived from this software without specific prior written
-.\" permission.
-.\"
-.\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
-.\" INTERNATIONAL, INC. 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 CALDERA INTERNATIONAL, INC. 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) RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
-.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-.\"
-.\" @(#)t1 8.1 (Berkeley) 8/14/93
-.\"
-.EH 'USD:3-%''An Introduction to the UNIX Shell'
-.OH 'An Introduction to the UNIX Shell''USD:3-%'
-.\".RP
-.TL
-An Introduction to the UNIX Shell
-.AU
-S. R. Bourne
-.AI
-Murray Hill, NJ
-.AU
-(Updated for 4.3BSD by Mark Seiden)
-.AU
-(Further updated by Perry E. Metzger)\(dg
-.AB
-.FS
-\(dg This paper was updated in 2010 to reflect most features of modern
-POSIX shells, which all follow the design of S.R. Bourne's original v7
-Unix shell.
-Among these are ash, bash, ksh and others.
-Typically one of these will be installed as /bin/sh on a modern system.
-It does not describe the behavior of the c shell (csh).
-If it's the c shell (csh) you're interested in, a good place to
-begin is William Joy's paper "An Introduction to the C shell" (USD:4).
-.FE
-.LP
-The
-.ul
-shell
-is a command programming language that provides an interface
-to the
-.UX
-operating system.
-Its features include
-control-flow primitives, parameter passing, variables and
-string substitution.
-Constructs such as
-.ul
-while, if then else, case
-and
-.ul
-for
-are available.
-Two-way communication is possible between the
-.ul
-shell
-and commands.
-String-valued parameters, typically file names or flags, may be
-passed to a command.
-A return code is set by commands that may be used to determine control-flow,
-and the standard output from a command may be used
-as shell input.
-.LP
-The
-.ul
-shell
-can modify the environment
-in which commands run.
-Input and output can be redirected
-to files, and processes that communicate through `pipes'
-can be invoked.
-Commands are found by
-searching directories
-in the file system in a
-sequence that can be defined by the user.
-Commands can be read either from the terminal or from a file,
-which allows command procedures to be
-stored for later use.
-.AE
-.ds ST \v'.3m'\s+2*\s0\v'-.3m'
-.SH
-1.0\ Introduction
-.LP
-The shell is both a command language
-and a programming language
-that provides an interface to the UNIX
-operating system.
-This memorandum describes, with
-examples, the UNIX shell.
-The first section covers most of the
-everyday requirements
-of terminal users.
-Some familiarity with UNIX
-is an advantage when reading this section;
-see, for example,
-"UNIX for beginners".
-.[
-unix beginn kernigh 1978
-.]
-Section 2 describes those features
-of the shell primarily intended
-for use within shell procedures.
-These include the control-flow
-primitives and string-valued variables
-provided by the shell.
-A knowledge of a programming language
-would be a help when reading this section.
-The last section describes the more
-advanced features of the shell.
-References of the form "see \fIpipe\fP (2)"
-are to a section of the UNIX manual.
-.[
-seventh 1978 ritchie thompson
-.]
-.SH
-1.1\ Simple\ commands
-.LP
-Simple commands consist of one or more words
-separated by blanks.
-The first word is the name of the command
-to be executed; any remaining words
-are passed as arguments to the command.
-For example,
-.DS
- who
-.DE
-is a command that prints the names
-of users logged in.
-The command
-.DS
- ls \(mil
-.DE
-prints a list of files in the current
-directory.
-The argument \fI\(mil\fP tells \fIls\fP
-to print status information, size and
-the creation date for each file.
-.SH
-1.2\ Input\ output\ redirection
-.LP
-Most commands produce output on the standard output
-that is initially connected to the terminal.
-This output may be sent to a file
-by writing, for example,
-.DS
- ls \(mil >file
-.DE
-The notation \fI>file\fP
-is interpreted by the shell and is not passed
-as an argument to \fIls.\fP
-If \fIfile\fP does not exist then the
-shell creates it;
-otherwise the original contents of
-\fIfile\fP are replaced with the output
-from \fIls.\fP
-Output may be appended to a file
-using the notation
-.DS
- ls \(mil \*(APfile
-.DE
-In this case \fIfile\fP is also created if it does not already
-exist.
-.LP
-The standard input of a command may be taken
-from a file instead of the terminal by
-writing, for example,
-.DS
- wc <file
-.DE
-The command \fIwc\fP reads its standard input
-(in this case redirected from \fIfile\fP)
-and prints the number of characters, words and
-lines found.
-If only the number of lines is required
-then
-.DS
- wc \(mil <file
-.DE
-could be used.
-.\" I considered adding the following, but have thought better of it
-.\" for now.
-.\" -- Perry Metzger
-.\"
-.\" .LP
-.\" Error messages are typically printed by commands on a different
-.\" channel, called standard error, which may also be redirected using the
-.\" notation 2>\|.
-.\" For example
-.\" .DS
-.\" command some args >out 2>errors
-.\" .DE
-.\" will redirect standard output to the file `out' but standard error
-.\" (and thus all error messages) to `errors'.
-.\" The notation 2>&1 sets standard error pointing to the same
-.\" place as standard out.
-.\" Thus:
-.\" .DS
-.\" command some args 2>&1 >everything
-.\" .DE
-.\" will put both standard out and standard error into the file `everything'.
-.\" See section 3.7 below for more details.
-.SH
-1.3\ Pipelines\ and\ filters
-.LP
-The standard output of one command may be
-connected to the standard input of another
-by writing
-the `pipe' operator,
-indicated by \*(VT,
-as in,
-.DS
- ls \(mil \*(VT wc
-.DE
-Two commands connected in this way constitute
-a \fIpipeline\fP and
-the overall effect is the same as
-.DS
- ls \(mil >file; wc <file
-.DE
-except that no \fIfile\fP is used.
-Instead the two \fIprocesses\fP are connected
-by a pipe (see \fIpipe\fP(2)) and are
-run in parallel.
-Pipes are unidirectional and
-synchronization is achieved by
-halting \fIwc\fP when there is
-nothing to read and halting \fIls\fP
-when the pipe is full.
-.LP
-A \fIfilter\fP is a command
-that reads its standard input,
-transforms it in some way,
-and prints the result as output.
-One such filter, \fIgrep,\fP
-selects from its input those lines
-that contain some specified string.
-For example,
-.DS
- ls \*(VT grep old
-.DE
-prints those lines, if any, of the output
-from \fIls\fP that contain
-the string \fIold.\fP
-Another useful filter is \fIsort\fP.
-For example,
-.DS
- who \*(VT sort
-.DE
-will print an alphabetically sorted list
-of logged in users.
-.LP
-A pipeline may consist of more than two commands,
-for example,
-.DS
- ls \*(VT grep old \*(VT wc \(mil
-.DE
-prints the number of file names
-in the current directory containing
-the string \fIold.\fP
-.SH
-1.4\ Background\ commands
-.LP
-To execute a command (or pipeline) the shell normally
-creates the new \fIprocesses\fP
-and waits for them to finish.
-A command may be run without waiting
-for it to finish.
-For example,
-.DS
- cc pgm.c &
-.DE
-calls the C compiler to compile
-the file \fIpgm.c\|.\fP
-The trailing \fB&\fP is an operator that instructs the shell
-not to wait for the command to finish.
-To help keep track of such a process
-the shell reports its job number (see below) and process
-id following its creation.
-Such a command is said to be running in the \fIbackground\fP.
-By contrast, a command executed without the \fB&\fP is said to be
-running in the \fIforeground\fP.\(dg
-.FS
-\(dg Even after execution, one may move commands from the foreground
-to the background, or temporarily suspend their execution (which is
-known as \fIstopping\fP a command.
-This is described in detail in section 3.10 on \fIJob Control\fB.
-.FE
-.LP
-A list of currently active processes, including ones not associated
-with the current shell, may be obtained using the \fIps\fP(1) command.
-.SH
-1.5\ File\ name\ generation
-.LP
-Many commands accept arguments
-which are file names.
-For example,
-.DS
- ls \(mil main.c
-.DE
-prints information relating to the file \fImain.c\fP\|.
-.LP
-The shell provides a mechanism
-for generating a list of file names
-that match a pattern.
-For example,
-.DS
- ls \(mil \*(ST.c
-.DE
-generates, as arguments to \fIls,\fP
-all file names in the current directory that end in \fI.c\|.\fP
-The character \*(ST is a pattern that will match any string
-including the null string.
-In general \fIpatterns\fP are specified
-as follows.
-.RS
-.IP \fB\*(ST\fR 8
-Matches any string of characters
-including the null string.
-.IP \fB?\fR 8
-Matches any single character.
-.IP \fB[\*(ZZ]\fR 8
-Matches any one of the characters
-enclosed.
-A pair of characters separated by a minus will
-match any character lexically between
-the pair.
-.RE
-.LP
-For example,
-.DS
- [a\(miz]\*(ST
-.DE
-matches all names in the current directory
-beginning with
-one of the letters \fIa\fP through \fIz.\fP
-.DS
- /usr/fred/test/?
-.DE
-matches all names in the directory
-\fB/usr/fred/test\fP that consist of a single character.
-If no file name is found that matches
-the pattern then the pattern is passed,
-unchanged, as an argument.
-.LP
-This mechanism is useful both to save typing
-and to select names according to some pattern.
-It may also be used to find files.
-For example,
-.DS
- echo /usr/fred/\*(ST/core
-.DE
-finds and prints the names of all \fIcore\fP files in sub-directories
-of \fB/usr/fred\|.\fP
-(\fIecho\fP is a standard UNIX command that prints
-its arguments, separated by blanks.)
-This last feature can be expensive,
-requiring a scan of all
-sub-directories of \fB/usr/fred\|.\fP
-.LP
-There is one exception to the general
-rules given for patterns.
-The character `\fB.\fP'
-at the start of a file name must be explicitly
-matched.
-.DS
- echo \*(ST
-.DE
-will therefore echo all file names in the current
-directory not beginning
-with `\fB.\fP'\|.
-.DS
- echo \fB.\fP\*(ST
-.DE
-will echo all those file names that begin with `\fB.\fP'\|.
-This avoids inadvertent matching
-of the names `\fB.\fP' and `\fB..\fP'
-which mean `the current directory'
-and `the parent directory'
-respectively.
-(Notice that \fIls\fP suppresses
-information for the files `\fB.\fP' and `\fB..\fP'\|.)
-.LP
-Finally, the tilde character, `\fB\(ap\fP', may be used to indicate the
-home directory of a user.
-The `\fB\(ap\fP' at the beginning of a path name followed by a
-non-alphabetic character expands to the current user's home
-directory.
-If the `\fB\(ap\fP' is followed by a login name, it expands to the named
-user's home directory.
-For example:
-.DS
- ls \(ap
- cd \(apegbert/
-.DE
-will list the contents of the user's home directory and then change
-to the home directory of the user ``egbert''.
-.SH
-1.6\ Quoting
-.LP
-Characters that have a special meaning
-to the shell, such as \fB< > \*(ST ? \*(VT &\|,\fR
-are called metacharacters.
-A complete list of metacharacters is given
-in appendix B.
-Any character preceded by a \fB\\\fR is \fIquoted\fP
-and loses its special meaning, if any.
-The \fB\\\fP is elided so that
-.DS
- echo \\?
-.DE
-will echo a single \fB?\|,\fP
-and
-.DS
- echo \\\\
-.DE
-will echo a single \fB\\\|.\fR
-To allow long strings to be continued over
-more than one line
-the sequence \fB\\newline\fP
-is ignored.
-.LP
-\fB\\\fP is convenient for quoting
-single characters.
-When more than one character needs
-quoting the above mechanism is clumsy and
-error prone.
-A string of characters may be quoted
-by enclosing the string between single quotes.
-For example,
-.DS
- echo xx\'\*(ST\*(ST\*(ST\*(ST\'xx
-.DE
-will echo
-.DS
- xx\*(ST\*(ST\*(ST\*(STxx
-.DE
-The quoted string may not contain
-a single quote
-but may contain newlines, which are preserved.
-This quoting mechanism is the most
-simple and is recommended
-for casual use.
-.LP
-A third quoting mechanism using double quotes
-is also available
-that prevents interpretation of some but not all
-metacharacters.
-Discussion of the
-details is deferred
-to section 3.5\|.
-.SH
-1.7\ Prompting
-.LP
-When the shell is used from a terminal it will
-issue a prompt before reading a command.
-By default this prompt is `\fB$\ \fR'\|.
-It may be changed by saying,
-for example,
-.DS
- \s-1PS1\s0="yesdear$ "
-.DE
-that sets the prompt to be the string \fIyesdear$\|.\fP
-If a newline is typed and further input is needed
-then the shell will issue the prompt `\fB>\ \fR'\|.
-Sometimes this can be caused by mistyping
-a quote mark.
-If it is unexpected then entering the interrupt character
-(typically \s-1CONTROL-C\s0)
-will return the shell to read another command.
-This prompt may be changed by saying, for example,
-.DS
- \s-1PS2\s0=more
-.DE
-Entering the interrupt character may also be used to terminate most
-programs running as the current foreground job.
-.LP
-(\s-1PS1\s0 and \s-1PS2\s0 are \fIshell variables\fP, which will be
-described in section 2.4 below.)
-.SH
-1.8\ The\ shell\ and\ login
-.LP
-Following \fIlogin\fP(1)
-the shell is called to read and execute
-commands typed at the terminal.
-If the user's login directory
-contains the file \fB.profile\fP
-then it is assumed to contain commands
-and is read by the shell before reading
-any commands from the terminal.
-.LP
-(Most versions of the shell also specify a file that is read and
-executed on start-up whether or not the shell is invoked by login.
-The \s-1ENV\s0 shell variable, described in section 2.4 below, can be
-used to override the name of this file.
-See the shell manual page for further information.)
-.SH
-1.9\ Summary
-.sp
-.RS
-.IP \(bu
-\fBls\fP
-.br
-Print the names of files in the current directory.
-.IP \(bu
-\fBls >file\fP
-.br
-Put the output from \fIls\fP into \fIfile.\fP
-.IP \(bu
-\fBls \*(VT wc \(mil\fR
-.br
-Print the number of files in the current directory.
-.IP \(bu
-\fBls \*(VT grep old\fR
-.br
-Print those file names containing the string \fIold.\fP
-.IP \(bu
-\fBls \*(VT grep old \*(VT wc \(mil\fR
-.br
-Print the number of files whose name contains the string \fIold.\fP
-.IP \(bu
-\fBcc pgm.c &\fR
-.br
-Run \fIcc\fP in the background.
-.RE
diff --git a/bin/sh/USD.doc/t2 b/bin/sh/USD.doc/t2
deleted file mode 100644
index d49747e..0000000
--- a/bin/sh/USD.doc/t2
+++ /dev/null
@@ -1,971 +0,0 @@
-.\" $NetBSD: t2,v 1.3 2010/08/22 02:19:07 perry Exp $
-.\"
-.\" Copyright (C) Caldera International Inc. 2001-2002. All rights reserved.
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions are
-.\" met:
-.\"
-.\" Redistributions of source code and documentation must retain the above
-.\" copyright notice, this list of conditions and the following
-.\" disclaimer.
-.\"
-.\" Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in the
-.\" documentation and/or other materials provided with the distribution.
-.\"
-.\" All advertising materials mentioning features or use of this software
-.\" must display the following acknowledgment:
-.\"
-.\" This product includes software developed or owned by Caldera
-.\" International, Inc. Neither the name of Caldera International, Inc.
-.\" nor the names of other contributors may be used to endorse or promote
-.\" products derived from this software without specific prior written
-.\" permission.
-.\"
-.\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
-.\" INTERNATIONAL, INC. 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 CALDERA INTERNATIONAL, INC. 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) RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
-.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-.\"
-.\" @(#)t2 8.1 (Berkeley) 6/8/93
-.\"
-.SH
-2.0\ Shell\ scripts
-.LP
-The shell may be used to read and execute commands
-contained in a file.
-For example,
-.DS
- sh file [ args \*(ZZ ]
-.DE
-calls the shell to read commands from \fIfile.\fP
-Such a file is called a \fIshell script.\fP
-Arguments may be supplied with the call
-and are referred to in \fIfile\fP
-using the positional parameters
-\fB$1, $2, \*(ZZ\|.\fR
-.LP
-For example, if the file \fIwg\fP contains
-.DS
- who \*(VT grep $1
-.DE
-then
-.DS
- sh wg fred
-.DE
-is equivalent to
-.DS
- who \*(VT grep fred
-.DE
-.LP
-UNIX files have three independent attributes,
-\fIread,\fP \fIwrite\fP and \fIexecute.\fP
-The UNIX command \fIchmod\fP(1) may be used
-to make a file executable.
-For example,
-.DS
- chmod +x wg
-.DE
-will ensure that the file \fIwg\fP has execute status.
-Following this, the command
-.DS
- wg fred
-.DE
-is equivalent to
-.DS
- sh wg fred
-.DE
-This allows shell scripts and other programs
-to be used interchangeably.
-In either case a new process is created to
-run the command.
-.LP
-The `\fB#\fP' character is used as a comment character by the shell.
-All characters following the `#' on a line are ignored.
-.LP
-A typical modern system has several different shells, some with differing
-command syntax, and it is desirable to specify which one should be
-invoked when an executable script is invoked.
-If the special comment
-.DS
- #!/\fIpath\fP/\fIto\fP/\fIinterpreter\fP
-.DE
-appears as the first line in a script, it is used to specify the
-absolute pathname of the shell (or other interpreter) that should be
-used to execute the file.
-(Without such a line, \fB/bin/sh\fP is assumed.)
-It is best if a script explicitly states
-what shell it is intended for in this manner.
-.LP
-As well as providing names for the positional
-parameters,
-the number of positional parameters to a script
-is available as \fB$#\|.\fP
-The name of the file being executed
-is available as \fB$0\|.\fP
-.LP
-A special shell parameter \fB$\*(ST\fP
-is used to substitute for all positional parameters
-except \fB$0\|.\fP
-A typical use of this is to provide
-some default arguments,
-as in,
-.DS
- nroff \(miT450 \(mims $\*(ST
-.DE
-which simply prepends some arguments
-to those already given.
-(The variable \fB$@\fP also expands to ``all positional
-parameters'', but is subtly different when expanded inside quotes.
-See section 3.5, below.)
-.SH
-2.1\ Control\ flow\ -\ for
-.LP
-A frequent use of shell scripts is to loop
-through the arguments (\fB$1, $2, \*(ZZ\fR)
-executing commands once for each argument.
-An example of such a script is
-\fItel\fP that searches the file
-\fB/usr/share/telnos\fR
-that contains lines of the form
-.DS
- \*(ZZ
- fred mh0123
- bert mh0789
- \*(ZZ
-.DE
-The text of \fItel\fP is
-.DS
- #!/bin/sh
-
- for i
- do
- grep $i /usr/share/telnos
- done
-.DE
-The command
-.DS
- tel fred
-.DE
-prints those lines in \fB/usr/share/telnos\fR
-that contain the string \fIfred\|.\fP
-.DS
- tel fred bert
-.DE
-prints those lines containing \fIfred\fP
-followed by those for \fIbert.\fP
-.LP
-The \fBfor\fP loop notation is recognized by the shell
-and has the general form
-.DS
- \fBfor\fR \fIname\fR \fBin\fR \fIw1 w2 \*(ZZ\fR
- \fBdo\fR \fIcommand-list\fR
- \fBdone\fR
-.DE
-A \fIcommand-list\fP is a sequence of one or more
-simple commands separated or terminated by a newline or semicolon.
-Furthermore, reserved words
-like \fBdo\fP and \fBdone\fP are only
-recognized following a newline or
-semicolon.
-\fIname\fP is a shell variable that is set
-to the words \fIw1 w2 \*(ZZ\fR in turn each time the \fIcommand-list\fP
-following \fBdo\fP
-is executed.
-If \fBin\fR \fIw1 w2 \*(ZZ\fR
-is omitted then the loop
-is executed once for each positional parameter;
-that is, \fBin\fR \fI$\*(ST\fR is assumed.
-.LP
-Another example of the use of the \fBfor\fP
-loop is the \fIcreate\fP command
-whose text is
-.DS
- for i do >$i; done
-.DE
-The command
-.DS
- create alpha beta
-.DE
-ensures that two empty files
-\fIalpha\fP and \fIbeta\fP exist
-and are empty.
-The notation \fI>file\fP may be used on its
-own to create or clear the contents of a file.
-Notice also that a semicolon (or newline) is required before \fBdone.\fP
-.SH
-2.2\ Control\ flow\ -\ case
-.LP
-A multiple way branch is provided for by the
-\fBcase\fP notation.
-For example,
-.DS
- case $# in
- \*(Ca1) cat \*(AP$1 ;;
- \*(Ca2) cat \*(AP$2 <$1 ;;
- \*(Ca\*(ST) echo \'usage: append [ from ] to\' ;;
- esac
-.DE
-is an \fIappend\fP command.
-When called
-with one argument as
-.DS
- append file
-.DE
-\fB$#\fP is the string \fI1\fP and
-the standard input is copied onto the
-end of \fIfile\fP
-using the \fIcat\fP command.
-.DS
- append file1 file2
-.DE
-appends the contents of \fIfile1\fP
-onto \fIfile2.\fP
-If the number of arguments supplied to
-\fIappend\fP is other than 1 or 2
-then a message is printed indicating
-proper usage.
-.LP
-The general form of the \fBcase\fP command
-is
-.DS
- \fBcase \fIword \fBin
- \*(Ca\fIpattern\|\fB)\ \fIcommand-list\fB\|;;
- \*(Ca\*(ZZ
- \fBesac\fR
-.DE
-The shell attempts to match
-\fIword\fR with each \fIpattern,\fR
-in the order in which the patterns
-appear.
-If a match is found the
-associated \fIcommand-list\fP is
-executed and execution
-of the \fBcase\fP is complete.
-Since \*(ST is the pattern that matches any
-string it can be used for the default case.
-.LP
-A word of caution:
-no check is made to ensure that only
-one pattern matches
-the case argument.
-The first match found defines the set of commands
-to be executed.
-In the example below the commands following
-the second \*(ST will never be executed.
-.DS
- case $# in
- \*(Ca\*(ST) \*(ZZ ;;
- \*(Ca\*(ST) \*(ZZ ;;
- esac
-.DE
-.LP
-Another example of the use of the \fBcase\fP
-construction is to distinguish
-between different forms
-of an argument.
-The following example is a fragment of a \fIcc\fP command.
-.DS
- for i
- do case $i in
- \*(DC\(mi[ocs]) \*(ZZ ;;
- \*(DC\(mi\*(ST) echo "unknown flag $i" ;;
- \*(DC\*(ST.c) /lib/c0 $i \*(ZZ ;;
- \*(DC\*(ST) echo "unexpected argument $i" ;;
- \*(DOesac
- done
-.DE
-.LP
-To allow the same commands to be associated
-with more than one pattern
-the \fBcase\fP command provides
-for alternative patterns
-separated by a \*(VT\|.
-For example,
-.DS
- case $i in
- \*(Ca\(mix\*(VT\(miy) \*(ZZ
- esac
-.DE
-is equivalent to
-.DS
- case $i in
- \*(Ca\(mi[xy]) \*(ZZ
- esac
-.DE
-.LP
-The usual quoting conventions apply
-so that
-.DS
- case $i in
- \*(Ca\\?) \*(ZZ
-.DE
-will match the character \fB?\|.\fP
-.SH
-2.3\ Here\ documents
-.LP
-The shell script \fItel\fP
-in section 2.1 uses the file \fB/usr/share/telnos\fR
-to supply the data
-for \fIgrep.\fP
-An alternative is to include this
-data
-within the shell script as a \fIhere\fP document, as in,
-.DS
- for i
- do grep $i \*(HE!
- \*(DO\*(ZZ
- \*(DOfred mh0123
- \*(DObert mh0789
- \*(DO\*(ZZ
- !
- done
-.DE
-In this example
-the shell takes the lines between \fB\*(HE!\fR and \fB!\fR
-as the standard input for \fIgrep.\fP
-The string \fB!\fR is arbitrary, the document
-being terminated by a line that consists
-of the string following \*(HE\|.
-.LP
-Parameters are substituted in the document
-before it is made available to \fIgrep\fP
-as illustrated by the following script
-called \fIedg\|.\fP
-.DS
- ed $3 \*(HE%
- g/$1/s//$2/g
- w
- %
-.DE
-The call
-.DS
- edg string1 string2 file
-.DE
-is then equivalent to the command
-.DS
- ed file \*(HE%
- g/string1/s//string2/g
- w
- %
-.DE
-and changes all occurrences of \fIstring1\fP
-in \fIfile\fP to \fIstring2\|.\fP
-Substitution can be prevented using \\
-to quote the special character \fB$\fP
-as in
-.DS
- ed $3 \*(HE+
- 1,\\$s/$1/$2/g
- w
- +
-.DE
-(This version of \fIedg\fP is equivalent to
-the first except that \fIed\fP will print
-a \fB?\fR if there are no occurrences of
-the string \fB$1\|.\fP)
-Substitution within a \fIhere\fP document
-may be prevented entirely by quoting
-the terminating string,
-for example,
-.DS
- grep $i \*(HE'end'
- \*(ZZ
- end
-.DE
-The document is presented
-without modification to \fIgrep.\fP
-If parameter substitution is not required
-in a \fIhere\fP document this latter form
-is more efficient.
-.SH
-2.4\ Shell\ variables\(dg
-.LP
-.FS
-Also known as \fIenvironment variables\fB, see \fIenvironment\fB(7).
-.FE
-The shell
-provides string-valued variables.
-Variable names begin with a letter
-and consist of letters, digits and
-underscores.
-Variables may be given values by writing, for example,
-.DS
- user=fred\ box=m000\ acct=mh0000
-.DE
-which assigns values to the variables
-\fBuser, box\fP and \fBacct.\fP
-A variable may be set to the null string
-by saying, for example,
-.DS
- null=
-.DE
-The value of a variable is substituted
-by preceding its name with \fB$\|\fP;
-for example,
-.DS
- echo $user
-.DE
-will echo \fIfred.\fP
-.LP
-Variables may be used interactively
-to provide abbreviations for frequently
-used strings.
-For example,
-.DS
- b=/usr/fred/bin
- mv pgm $b
-.DE
-will move the file \fIpgm\fP
-from the current directory to the directory \fB/usr/fred/bin\|.\fR
-A more general notation is available for parameter
-(or variable)
-substitution, as in,
-.DS
- echo ${user}
-.DE
-which is equivalent to
-.DS
- echo $user
-.DE
-and is used when the parameter name is
-followed by a letter or digit.
-For example,
-.DS
- tmp=/tmp/ps
- ps a >${tmp}a
-.DE
-will direct the output of \fIps\fR
-to the file \fB/tmp/psa,\fR
-whereas,
-.DS
- ps a >$tmpa
-.DE
-would cause the value of the variable \fBtmpa\fP
-to be substituted.
-.LP
-Except for \fB$?\fP the following
-are set initially by the shell.
-\fB$?\fP is set after executing each command.
-.RS
-.IP \fB$?\fP 8
-The exit status (return code)
-of the last command executed
-as a decimal string.
-Most commands return a zero exit status
-if they complete successfully,
-otherwise a non-zero exit status is returned.
-Testing the value of return codes is dealt with
-later under \fBif\fP and \fBwhile\fP commands.
-.IP \fB$#\fP 8
-The number of positional parameters
-(in decimal).
-Used, for example, in the \fIappend\fP command
-to check the number of parameters.
-.IP \fB$$\fP 8
-The process number of this shell (in decimal).
-Since process numbers are unique among
-all existing processes, this string is
-frequently used to generate
-unique
-temporary file names.
-For example,
-.DS
- ps a >/tmp/ps$$
- \*(ZZ
- rm /tmp/ps$$
-.DE
-.IP \fB$\|!\fP 8
-The process number of the last process
-run in the background (in decimal).
-.IP \fB$\(mi\fP 8
-The current shell flags, such as
-\fB\(mix\fR and \fB\(miv\|.\fR
-.RE
-.LP
-Some variables have a special meaning to the
-shell and should be avoided for general
-use.
-.RS
-.IP \fB$\s-1MAIL\s0\fP 8
-When used interactively
-the shell looks at the file
-specified by this variable
-before it issues a prompt.
-If the specified file has been modified
-since it
-was last looked at the shell
-prints the message
-\fIyou have mail\fP before prompting
-for the next command.
-This variable is typically set
-in the file \fB.profile,\fP
-in the user's login directory.
-For example,
-.DS
- \s-1MAIL\s0=/usr/spool/mail/fred
-.DE
-.IP \fB$\s-1HOME\s0\fP 8
-The default argument
-for the \fIcd\fP command.
-The current directory is used to resolve
-file name references that do not begin with
-a \fB/\|,\fR
-and is changed using the \fIcd\fP command.
-For example,
-.DS
- cd /usr/fred/bin
-.DE
-makes the current directory \fB/usr/fred/bin\|.\fR
-.DS
- cat wn
-.DE
-will print on the terminal the file \fIwn\fP
-in this directory.
-The command
-\fIcd\fP with no argument
-is equivalent to
-.DS
- cd $\s-1HOME\s0
-.DE
-This variable is also typically set in the
-the user's login profile.
-.IP \fB$\s-1PWD\s0\fP 8
-The current working directory. Set by the \fIcd\fB command.
-.IP \fB$\s-1PATH\s0\fP 8
-A list of directories that contain commands (the \fIsearch path\fR\|).
-Each time a command is executed by the shell
-a list of directories is searched
-for an executable file.
-.ne 5
-If \fB$\s-1PATH\s0\fP is not set
-then the current directory,
-\fB/bin\fP, and \fB/usr/bin\fP are searched by default.
-.ne 5
-Otherwise \fB$\s-1PATH\s0\fP consists of directory
-names separated by \fB:\|.\fP
-For example,
-.DS
- \s-1PATH\s0=\fB:\fP/usr/fred/bin\fB:\fP/bin\fB:\fP/usr/bin
-.DE
-specifies that the current directory
-(the null string before the first \fB:\fP\|),
-\fB/usr/fred/bin, /bin \fRand\fP /usr/bin\fR
-are to be searched in that order.
-In this way individual users
-can have their own `private' commands
-that are accessible independently
-of the current directory.
-If the command name contains a \fB/\fR then this directory search
-is not used; a single attempt
-is made to execute the command.
-.IP \fB$\s-1PS1\s0\fP 8
-The primary shell prompt string, by default, `\fB$\ \fR'.
-.IP \fB$\s-1PS2\s0\fP 8
-The shell prompt when further input is needed,
-by default, `\fB>\ \fR'.
-.IP \fB$\s-1IFS\s0\fP 8
-The set of characters used by \fIblank
-interpretation\fR (see section 3.5).
-.IP \fB$\s-1ENV\s0\fP 8
-The shell reads and executes the commands in the file
-specified by this variable when it is initially started.
-Unlike the \fB.profile\fP file, these commands are executed by all
-shells, not just the one started at login.
-(Most versions of the shell specify a filename that is used if
-\s-1ENV\s0 is not explicitly set. See the manual page for your shell.)
-.RE
-.SH
-2.5\ The\ test\ command
-.LP
-The \fItest\fP command, although not part of the shell,
-is intended for use by shell programs.
-For example,
-.DS
- test \(mif file
-.DE
-returns zero exit status if \fIfile\fP
-exists and non-zero exit status otherwise.
-In general \fItest\fP evaluates a predicate
-and returns the result as its exit status.
-Some of the more frequently used \fItest\fP
-arguments are given here, see \fItest\fP(1)
-for a complete specification.
-.DS
- test s true if the argument \fIs\fP is not the null string
- test \(mif file true if \fIfile\fP exists
- test \(mir file true if \fIfile\fP is readable
- test \(miw file true if \fIfile\fP is writable
- test \(mid file true if \fIfile\fP is a directory
-.DE
-The \fItest\fP command is known as `\fB[\fP' and may be invoked as
-such.
-For aesthetic reasons, the command ignores a close bracket `\fB]\fP' given
-at the end of a command so
-.DS
- [ -f filename ]
-.DE
-and
-.DS
- test -f filename
-.DE
-are completely equivalent.
-Typically, the bracket notation is used when \fItest\fP is invoked inside
-shell control constructs.
-.SH
-2.6\ Control\ flow\ -\ while
-.LP
-The actions of
-the \fBfor\fP loop and the \fBcase\fP
-branch are determined by data available to the shell.
-A \fBwhile\fP or \fBuntil\fP loop
-and an \fBif then else\fP branch
-are also provided whose
-actions are determined by the exit status
-returned by commands.
-A \fBwhile\fP loop has the general form
-.DS
- \fBwhile\fP \fIcommand-list\*1\fP
- \fBdo\fP \fIcommand-list\*2\fP
- \fBdone\fP
-.DE
-.LP
-The value tested by the \fBwhile\fP command
-is the exit status of the last simple command
-following \fBwhile.\fP
-Each time round the loop
-\fIcommand-list\*1\fP is executed;
-if a zero exit status is returned then
-\fIcommand-list\*2\fP
-is executed;
-otherwise, the loop terminates.
-For example,
-.DS
- while [ $1 ]
- do \*(ZZ
- \*(DOshift
- done
-.DE
-is equivalent to
-.DS
- for i
- do \*(ZZ
- done
-.DE
-\fIshift\fP is a shell command that
-renames the positional parameters
-\fB$2, $3, \*(ZZ\fR as \fB$1, $2, \*(ZZ\fR
-and loses \fB$1\|.\fP
-.LP
-Another kind of use for the \fBwhile/until\fP
-loop is to wait until some
-external event occurs and then run
-some commands.
-In an \fBuntil\fP loop
-the termination condition is reversed.
-For example,
-.DS
- until [ \(mif file ]
- do sleep 300; done
- \fIcommands\fP
-.DE
-will loop until \fIfile\fP exists.
-Each time round the loop it waits for
-5 minutes before trying again.
-(Presumably another process
-will eventually create the file.)
-.LP
-The most recent enclosing loop may be exited with the \fBbreak\fP
-command, or the rest of the body skipped and the next iteration begun
-with the \fBcontinue\fP command.
-.LP
-The commands \fItrue\fP(1) and \fIfalse\fP(1) return 0 and non-zero
-exit statuses respectively. They are sometimes of use in control flow,
-e.g.:
-.DS
- while true
- do date; sleep 5
- done
-.DE
-is an infinite loop that prints the date and time every five seconds.
-.SH
-2.7\ Control\ flow\ -\ if
-.LP
-Also available is a
-general conditional branch
-of the form,
-.DS
- \fBif\fP \fIcommand-list
- \fBthen \fIcommand-list
- \fBelse \fIcommand-list
- \fBfi\fR
-.DE
-that tests the value returned by the last simple command
-following \fBif.\fP
-.LP
-The \fBif\fP command may be used
-in conjunction with the \fItest\fP command
-to test for the existence of a file as in
-.DS
- if [ \(mif file ]
- then \fIprocess file\fP
- else \fIdo something else\fP
- fi
-.DE
-.LP
-An example of the use of \fBif, case\fP
-and \fBfor\fP constructions is given in
-section 2.10\|.
-.LP
-A multiple test \fBif\fP command
-of the form
-.DS
- if \*(ZZ
- then \*(ZZ
- else if \*(ZZ
- then \*(ZZ
- else if \*(ZZ
- \*(ZZ
- fi
- fi
- fi
-.DE
-may be written using an extension of the \fBif\fP
-notation as,
-.DS
- if \*(ZZ
- then \*(ZZ
- elif \*(ZZ
- then \*(ZZ
- elif \*(ZZ
- \*(ZZ
- fi
-.DE
-.LP
-The following example is an implementation of the \fItouch\fP command
-which changes the `last modified' time for a list
-of files.
-The command may be used in conjunction
-with \fImake\fP(1) to force recompilation of a list
-of files.
-.DS
- #!/bin/sh
-
- flag=
- for i
- do case $i in
- \*(DC\(mic) flag=N ;;
- \*(DC\*(ST) if [ \(mif $i ]
- \*(DC then cp $i junk$$; mv junk$$ $i
- \*(DC elif [ $flag ]
- \*(DC then echo file \\'$i\\' does not exist
- \*(DC else >$i
- \*(DC fi
- \*(DO esac
- done
-.DE
-The \fB\(mic\fP flag is used in this command to
-force subsequent files to be created if they do not already exist.
-Otherwise, if the file does not exist, an error message is printed.
-The shell variable \fIflag\fP
-is set to some non-null string if the \fB\(mic\fP
-argument is encountered.
-The commands
-.DS
- cp \*(ZZ; mv \*(ZZ
-.DE
-copy the file and then overwrite it with the copy,
-thus causing the last modified date to be updated.
-.LP
-The sequence
-.DS
- if command1
- then command2
- fi
-.DE
-may be written
-.DS
- command1 && command2
-.DE
-Conversely,
-.DS
- command1 \*(VT\*(VT command2
-.DE
-executes \fIcommand2\fP only if \fIcommand1\fP
-fails.
-In each case the value returned
-is that of the last simple command executed.
-.LP
-Placing a `\fB!\fP' in front of a pipeline inverts its exit
-status, almost in the manner of the C operator of the same name.
-Thus:
-.DS
- if ! [ -d $1 ]
- then
- echo $1 is not a directory
- fi
-.DE
-will print a message only if $1 is not a directory.
-.SH
-2.8\ Command\ grouping
-.LP
-Commands may be grouped in two ways,
-.DS
- \fB{\fI command-list\fB ; }\fR
-.DE
-and
-.DS
- \fB(\fI command-list\fB )\fR
-.DE
-.LP
-In the first \fIcommand-list\fP is simply executed.
-The second form executes \fIcommand-list\fP
-as a separate process.
-For example,
-.DS
- (cd x; rm junk )
-.DE
-executes \fIrm junk\fP in the directory
-\fBx\fP without changing the current
-directory of the invoking shell.
-.LP
-The commands
-.DS
- cd x; rm junk
-.DE
-have the same effect but leave the invoking
-shell in the directory \fBx.\fP
-.SH
-2.9\ Shell\ Functions
-.LP
-A function may be defined by the syntax
-.DS
- \fIfuncname\fP() \fB{\fI command-list\fB ; }\fR
-.DE
-Functions are invoked within a script as though they were separate
-commands of the same name.
-While they are executed, the
-positional parameters \fB$1, $2, \*(ZZ\fR are temporarily set to the
-arguments passed to the function. For example:
-.DS
- count() {
- echo $2 : $#
- }
-
- count a b c
-.DE
-would print `b : 3'.
-.SH
-2.10\ Debugging\ shell\ scripts
-.LP
-The shell provides two tracing mechanisms
-to help when debugging shell scripts.
-The first is invoked within the script
-as
-.DS
- set \(miv
-.DE
-(\fBv\fP for verbose) and causes lines of the
-script to be printed as they are read.
-It is useful to help isolate syntax errors.
-It may be invoked without modifying the script
-by saying
-.DS
- sh \(miv \fIscript\fP \*(ZZ
-.DE
-where \fIscript\fP is the name of the shell script.
-This flag may be used in conjunction
-with the \fB\(min\fP flag which prevents
-execution of subsequent commands.
-(Note that saying \fIset \(min\fP at a terminal
-will render the terminal useless
-until an end-of-file is typed.)
-.LP
-The command
-.DS
- set \(mix
-.DE
-will produce an execution
-trace.
-Following parameter substitution
-each command is printed as it is executed.
-(Try these at the terminal to see
-what effect they have.)
-Both flags may be turned off by saying
-.DS
- set \(mi
-.DE
-and the current setting of the shell flags is available as \fB$\(mi\|\fR.
-.SH
-2.11\ The\ man\ command
-.LP
-The following is a simple implementation of the \fIman\fP command,
-which is used to display sections of the UNIX manual on your terminal.
-It is called, for example, as
-.DS
- man sh
- man \(mit ed
- man 2 fork
-.DE
-In the first the manual section for \fIsh\fP
-is displayed..
-Since no section is specified, section 1 is used.
-The second example will typeset (\fB\(mit\fP option)
-the manual section for \fIed.\fP
-The last prints the \fIfork\fP manual page
-from section 2, which covers system calls.
-.sp 2
-.DS
- #!/bin/sh
-
- cd /usr/share/man
-
- # "#" is the comment character
- # default is nroff ($N), section 1 ($s)
- N=n\ s=1
-
- for i
- do case $i in
-.sp .5
- \*(DC[1\(mi9]\*(ST) s=$i ;;
-.sp .5
- \*(DC\(mit) N=t ;;
-.sp .5
- \*(DC\(min) N=n ;;
-.sp .5
- \*(DC\(mi\*(ST) echo unknown flag \\'$i\\' ;;
-.sp .5
- \*(DC\*(ST) if [ \(mif man$s/$i.$s ]
- \*(DC then
- \*(DC ${N}roff \(miman man$s/$i.$s
- \*(DC else # look through all manual sections
- \*(DC found=no
- \*(DC for j in 1 2 3 4 5 6 7 8 9
- \*(DC do
- \*(DC \*(DOif [ \(mif man$j/$i.$j ]
- \*(DC \*(DOthen
- \*(DC \*(DO\*(THman $j $i
- \*(DC \*(DO\*(THfound=yes
- \*(DC \*(DO\*(THbreak
- \*(DC \*(DOfi
- \*(DC done
- \*(DC case $found in
- \*(DC \*(Cano) echo \\'$i: manual page not found\\'
- \*(DC esac
- \*(DC fi
- \*(DOesac
- done
-.DE
-.ce
-.ft B
-Figure 1. A version of the man command
-.ft R
diff --git a/bin/sh/USD.doc/t3 b/bin/sh/USD.doc/t3
deleted file mode 100644
index aab53ee..0000000
--- a/bin/sh/USD.doc/t3
+++ /dev/null
@@ -1,976 +0,0 @@
-.\" $NetBSD: t3,v 1.3 2010/08/22 02:19:07 perry Exp $
-.\"
-.\" Copyright (C) Caldera International Inc. 2001-2002. All rights reserved.
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions are
-.\" met:
-.\"
-.\" Redistributions of source code and documentation must retain the above
-.\" copyright notice, this list of conditions and the following
-.\" disclaimer.
-.\"
-.\" Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in the
-.\" documentation and/or other materials provided with the distribution.
-.\"
-.\" All advertising materials mentioning features or use of this software
-.\" must display the following acknowledgement:
-.\"
-.\" This product includes software developed or owned by Caldera
-.\" International, Inc. Neither the name of Caldera International, Inc.
-.\" nor the names of other contributors may be used to endorse or promote
-.\" products derived from this software without specific prior written
-.\" permission.
-.\"
-.\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
-.\" INTERNATIONAL, INC. 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 CALDERA INTERNATIONAL, INC. 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) RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
-.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-.\"
-.\" @(#)t3 8.1 (Berkeley) 6/8/93
-.\"
-.SH
-3.0\ Keyword\ parameters
-.LP
-Shell variables may be given values
-by assignment
-or when a shell script is invoked.
-An argument to a command of the form
-\fIname=value\fP
-that precedes the command name
-causes \fIvalue\fP
-to be assigned to \fIname\fP
-before execution of the command begins.
-The value of \fIname\fP in the invoking
-shell is not affected.
-For example,
-.DS
- user=fred\ command
-.DE
-will execute \fIcommand\fP with
-\fBuser\fP set to \fIfred\fP.
-.\" Removed by Perry Metzger because -k is not in POSIX
-.\"
-.\" The \fB\(mik\fR flag causes arguments of the form
-.\" \fIname=value\fP to be interpreted in this way
-.\" anywhere in the argument list.
-.\" Such \fInames\fP are sometimes
-.\" called keyword parameters.
-.\" If any arguments remain they
-.\" are available as positional
-.\" parameters \fB$1, $2, \*(ZZ\|.\fP
-.LP
-The \fIset\fP command
-may also be used to set positional parameters
-from within a script.
-For example,
-.DS
- set\ \(mi\(mi\ \*(ST
-.DE
-will set \fB$1\fP to the first file name
-in the current directory, \fB$2\fP to the next,
-and so on.
-Note that the first argument, \(mi\(mi, ensures correct treatment
-when the first file name begins with a \(mi\|.
-.LP
-.SH
-3.1\ Parameter\ transmission
-.LP
-When a command is executed both positional parameters
-and shell variables may be set on invocation.
-Variables are also made available implicitly
-to a command
-by specifying in advance that such parameters
-are to be exported from the invoking shell.
-For example,
-.DS
- export\ user\ box=red
-.DE
-marks the variables \fBuser\fP and \fBbox\fP
-for export (setting \fBbox\fP to ``red'' in the process).
-When a command is invoked
-copies are made of all exportable variables
-(also known as \fIenvironment variables\fP)
-for use within the invoked program.
-Modification of such variables
-within an invoked command does not
-affect the values in the invoking shell.
-It is generally true of
-a shell script or other program
-that it
-cannot modify the state
-of its caller without explicit
-actions on the part of the caller.
-.\" Removed by Perry Metzger because this is confusing to beginners.
-.\"
-.\" (Shared file descriptors are an
-.\" exception to this rule.)
-.LP
-Names whose value is intended to remain
-constant may be declared \fIreadonly\|.\fP
-The form of this command is the same as that of the \fIexport\fP
-command,
-.DS
- readonly name[=value] \*(ZZ
-.DE
-Subsequent attempts to set readonly variables
-are illegal.
-.SH
-3.2\ Parameter\ substitution
-.LP
-If a shell parameter is not set
-then the null string is substituted for it.
-For example, if the variable \fBd\fP
-is not set
-.DS
- echo $d
-.DE
-or
-.DS
- echo ${d}
-.DE
-will echo nothing.
-A default string may be given
-as in
-.DS
- echo ${d:\(mi\fB.\fR}
-.DE
-which will echo
-the value of the variable \fBd\fP
-if it is set and not null and `\fB.\fP' otherwise.
-The default string is evaluated using the usual
-quoting conventions so that
-.DS
- echo ${d:\(mi\'\*(ST\'}
-.DE
-will echo \fB\*(ST\fP if the variable \fBd\fP
-is not set or null.
-Similarly
-.DS
- echo ${d:\(mi$1}
-.DE
-will echo the value of \fBd\fP if it is set and not null
-and the value (if any) of \fB$1\fP otherwise.
-.LP
-The notation ${d:+\fB.\fR} performs the inverse operation. It
-substitutes `\fB.\fP' if \fBd\fP is set or not null, and otherwise
-substitutes null.
-.LP
-A variable may be assigned a default value
-using
-the notation
-.DS
- echo ${d:=\fB.\fR}
-.DE
-which substitutes the same string as
-.DS
- echo ${d:\(mi\fB.\fR}
-.DE
-and if \fBd\fP were not previously set or null
-then it will be set to the string `\fB.\fP'\|.
-.LP
-If there is no sensible default then
-the notation
-.DS
- echo ${d:?\fImessage\fP}
-.DE
-will echo the value of the variable \fBd\fP if it is set and not null,
-otherwise \fImessage\fP is printed by the shell and
-execution of the shell script is abandoned.
-If \fImessage\fP is absent then a standard message
-is printed.
-A shell script that requires some variables
-to be set might start as follows:
-.DS
- :\ ${user:?}\ ${acct:?}\ ${bin:?}
- \*(ZZ
-.DE
-Colon (\fB:\fP) is a command
-that is
-built in to the shell and does nothing
-once its arguments have been evaluated.
-If any of the variables \fBuser, acct\fP
-or \fBbin\fP are not set then the shell
-will abandon execution of the script.
-.SH
-3.3\ Command\ substitution
-.LP
-The standard output from a command can be
-substituted in a similar way to parameters.
-The command \fIpwd\fP prints on its standard
-output the name of the current directory.
-For example, if the current directory is
-\fB/usr/fred/bin\fR
-then the commands
-.DS
- d=$(pwd)
-.DE
-(or the older notation d=\`pwd\`)
-is equivalent to
-.DS
- d=/usr/fred/bin
-.DE
-.LP
-The entire string inside $(\*(ZZ)\| (or between grave accents \`\*(ZZ\`)
-is taken as the command
-to be executed
-and is replaced with the output from
-the command.
-(The difference between the $(\*(ZZ) and \`\*(ZZ\` notations is that
-the former may be nested, while the latter cannot be.)
-.LP
-The command is written using the usual quoting conventions,
-except that inside \`\*(ZZ\`
-a \fB\`\fR must be escaped using
-a \fB\\\|\fR.
-For example,
-.DS
- ls $(echo "$HOME")
-.DE
-is equivalent to
-.DS
- ls $HOME
-.DE
-Command substitution occurs in all contexts
-where parameter substitution occurs (including \fIhere\fP documents) and the
-treatment of the resulting text is the same
-in both cases.
-This mechanism allows string
-processing commands to be used within
-shell scripts.
-An example of such a command is \fIbasename\fP
-which removes a specified suffix from a string.
-For example,
-.DS
- basename main\fB.\fPc \fB.\fPc
-.DE
-will print the string \fImain\|.\fP
-Its use is illustrated by the following
-fragment from a \fIcc\fP command.
-.DS
- case $A in
- \*(Ca\*(ZZ
- \*(Ca\*(ST\fB.\fPc) B=$(basename $A \fB.\fPc)
- \*(Ca\*(ZZ
- esac
-.DE
-that sets \fBB\fP to the part of \fB$A\fP
-with the suffix \fB.c\fP stripped.
-.LP
-Here are some composite examples.
-.RS
-.IP \(bu
-.ft B
-for i in \`ls \(mit\`; do \*(ZZ
-.ft R
-.br
-The variable \fBi\fP is set
-to the names of files in time order,
-most recent first.
-.IP \(bu
-.ft B
-set \(mi\(mi\| \`date\`; echo $6 $2 $3, $4
-.ft R
-.br
-will print, e.g.,
-.ft I
-1977 Nov 1, 23:59:59
-.ft R
-.RE
-.SH
-3.4\ Arithmetic\ Expansion
-.LP
-Within a $((\*(ZZ)) construct, integer arithmetic operations are
-evaluated.
-(The $ in front of variable names is optional within $((\*(ZZ)).
-For example:
-.DS
- x=5; y=1
- echo $(($x+3*2))
- echo $((y+=x))
- echo $y
-.DE
-will print `11', then `6', then `6' again.
-Most of the constructs permitted in C arithmetic operations are
-permitted though some (like `++') are not universally supported \(em
-see the shell manual page for details.
-.SH
-3.5\ Evaluation\ and\ quoting
-.LP
-The shell is a macro processor that
-provides parameter substitution, command substitution and file
-name generation for the arguments to commands.
-This section discusses the order in which
-these evaluations occur and the
-effects of the various quoting mechanisms.
-.LP
-Commands are parsed initially according to the grammar
-given in appendix A.
-Before a command is executed
-the following
-substitutions occur.
-.RS
-.IP \(bu
-parameter substitution, e.g. \fB$user\fP
-.IP \(bu
-command substitution, e.g. \fB$(pwd)\fP or \fB\`pwd\`\fP
-.IP \(bu
-arithmetic expansion, e.g. \fB$(($count+1))\fP
-.RS
-.LP
-Only one evaluation occurs so that if, for example, the value of the variable
-\fBX\fP
-is the string \fI$y\fP
-then
-.DS
- echo $X
-.DE
-will echo \fI$y\|.\fP
-.RE
-.IP \(bu
-blank interpretation
-.RS
-.LP
-Following the above substitutions
-the resulting characters
-are broken into non-blank words (\fIblank interpretation\fP).
-For this purpose `blanks' are the characters of the string
-\fB$\s-1IFS\s0\fP.
-By default, this string consists of blank, tab and newline.
-The null string
-is not regarded as a word unless it is quoted.
-For example,
-.DS
- echo \'\'
-.DE
-will pass on the null string as the first argument to \fIecho\fP,
-whereas
-.DS
- echo $null
-.DE
-will call \fIecho\fR with no arguments
-if the variable \fBnull\fP is not set
-or set to the null string.
-.RE
-.IP \(bu
-file name generation
-.RS
-.LP
-Each word
-is then scanned for the file pattern characters
-\fB\*(ST, ?\fR and \fB[\*(ZZ]\fR
-and an alphabetical list of file names
-is generated to replace the word.
-Each such file name is a separate argument.
-.RE
-.RE
-.LP
-The evaluations just described also occur
-in the list of words associated with a \fBfor\fP
-loop.
-Only substitution occurs
-in the \fIword\fP used
-for a \fBcase\fP branch.
-.LP
-As well as the quoting mechanisms described
-earlier using \fB\\\fR and \fB\'\*(ZZ\'\fR
-a third quoting mechanism is provided using double quotes.
-Within double quotes parameter and command substitution
-occurs but file name generation and the interpretation
-of blanks does not.
-The following characters
-have a special meaning within double quotes
-and may be quoted using \fB\\\|.\fP
-.DS
- \fB$ \fPparameter substitution
- \fB$()\fP command substitution
- \fB\`\fP command substitution
- \fB"\fP ends the quoted string
- \fB\e\fP quotes the special characters \fB$ \` " \e\fP
-.DE
-For example,
-.DS
- echo "$x"
-.DE
-will pass the value of the variable \fBx\fP as a
-single argument to \fIecho.\fP
-Similarly,
-.DS
- echo "$\*(ST"
-.DE
-will pass the positional parameters as a single
-argument and is equivalent to
-.DS
- echo "$1 $2 \*(ZZ"
-.DE
-The notation \fB$@\fP
-is the same as \fB$\*(ST\fR
-except when it is quoted.
-.DS
- echo "$@"
-.DE
-will pass the positional parameters, unevaluated, to \fIecho\fR
-and is equivalent to
-.DS
- echo "$1" "$2" \*(ZZ
-.DE
-.LP
-The following table gives, for each quoting mechanism,
-the shell metacharacters that are evaluated.
-.DS
-.ce
-.ft I
-metacharacter
-.ft
-.in 1.5i
- \e $ * \` " \'
-\' n n n n n t
-\` y n n t n n
-" y y n y t n
-
- t terminator
- y interpreted
- n not interpreted
-
-.in
-.ft B
-.ce
-Figure 2. Quoting mechanisms
-.ft
-.DE
-.LP
-In cases where more than one evaluation of a string
-is required the built-in command \fIeval\fP
-may be used.
-For example,
-if the variable \fBX\fP has the value
-\fI$y\fP, and if \fBy\fP has the value \fIpqr\fP
-then
-.DS
- eval echo $X
-.DE
-will echo the string \fIpqr\|.\fP
-.LP
-In general the \fIeval\fP command
-evaluates its arguments (as do all commands)
-and treats the result as input to the shell.
-The input is read and the resulting command(s)
-executed.
-For example,
-.DS
- wg=\'eval who\*(VTgrep\'
- $wg fred
-.DE
-is equivalent to
-.DS
- who\*(VTgrep fred
-.DE
-In this example,
-\fIeval\fP is required
-since there is no interpretation
-of metacharacters, such as \fB\*(VT\|\fR, following
-substitution.
-.SH
-3.6\ Error\ handling
-.LP
-The treatment of errors detected by
-the shell depends on the type of error
-and on whether the shell is being
-used interactively.
-An interactive shell is one whose
-input and output are connected
-to a terminal.
-.\" Removed by Perry Metzger, obsolete and excess detail
-.\"
-.\" (as determined by
-.\" \fIgtty\fP (2)).
-A shell invoked with the \fB\(mii\fP
-flag is also interactive.
-.LP
-Execution of a command (see also 3.7) may fail
-for any of the following reasons.
-.IP \(bu
-Input output redirection may fail.
-For example, if a file does not exist
-or cannot be created.
-.IP \(bu
-The command itself does not exist
-or cannot be executed.
-.IP \(bu
-The command terminates abnormally,
-for example, with a "bus error"
-or "memory fault".
-See Figure 2 below for a complete list
-of UNIX signals.
-.IP \(bu
-The command terminates normally
-but returns a non-zero exit status.
-.LP
-In all of these cases the shell
-will go on to execute the next command.
-Except for the last case an error
-message will be printed by the shell.
-All remaining errors cause the shell
-to exit from a script.
-An interactive shell will return
-to read another command from the terminal.
-Such errors include the following.
-.IP \(bu
-Syntax errors.
-e.g., if \*(ZZ then \*(ZZ done
-.IP \(bu
-A signal such as interrupt.
-The shell waits for the current
-command, if any, to finish execution and
-then either exits or returns to the terminal.
-.IP \(bu
-Failure of any of the built-in commands
-such as \fIcd.\fP
-.LP
-The shell flag \fB\(mie\fP
-causes the shell to terminate
-if any error is detected.
-.DS
-1 hangup
-2 interrupt
-3* quit
-4* illegal instruction
-5* trace trap
-6* IOT instruction
-7* EMT instruction
-8* floating point exception
-9 kill (cannot be caught or ignored)
-10* bus error
-11* segmentation violation
-12* bad argument to system call
-13 write on a pipe with no one to read it
-14 alarm clock
-15 software termination (from \fIkill\fP (1))
-
-.DE
-.ft B
-.ce
-Figure 3. UNIX signals\(dg
-.ft
-.FS
-\(dg Additional signals have been added in modern Unix.
-See \fIsigvec\fP(2) or \fIsignal\fP(3) for an up-to-date list.
-.FE
-Those signals marked with an asterisk
-produce a core dump
-if not caught.
-However,
-the shell itself ignores quit which is the only
-external signal that can cause a dump.
-The signals in this list of potential interest
-to shell programs are 1, 2, 3, 14 and 15.
-.SH
-3.7\ Fault\ handling
-.LP
-shell scripts normally terminate
-when an interrupt is received from the
-terminal.
-The \fItrap\fP command is used
-if some cleaning up is required, such
-as removing temporary files.
-For example,
-.DS
- trap\ \'rm\ /tmp/ps$$; exit\'\ 2
-.DE
-sets a trap for signal 2 (terminal
-interrupt), and if this signal is received
-will execute the commands
-.DS
- rm /tmp/ps$$; exit
-.DE
-\fIexit\fP is
-another built-in command
-that terminates execution of a shell script.
-The \fIexit\fP is required; otherwise,
-after the trap has been taken,
-the shell will resume executing
-the script
-at the place where it was interrupted.
-.LP
-UNIX signals can be handled in one of three ways.
-They can be ignored, in which case
-the signal is never sent to the process.
-They can be caught, in which case the process
-must decide what action to take when the
-signal is received.
-Lastly, they can be left to cause
-termination of the process without
-it having to take any further action.
-If a signal is being ignored
-on entry to the shell script, for example,
-by invoking it in the background (see 3.7) then \fItrap\fP
-commands (and the signal) are ignored.
-.LP
-The use of \fItrap\fP is illustrated
-by this modified version of the \fItouch\fP
-command (Figure 4).
-The cleanup action is to remove the file \fBjunk$$\fR\|.
-.DS
- #!/bin/sh
-
- flag=
- trap\ \'rm\ \(mif\ junk$$;\ exit\'\ 1 2 3 15
- for i
- do\ case\ $i\ in
- \*(DC\(mic) flag=N ;;
- \*(DC\*(ST) if\ test\ \(mif\ $i
- \*(DC then cp\ $i\ junk$$;\ mv\ junk$$ $i
- \*(DC elif\ test\ $flag
- \*(DC then echo\ file\ \\'$i\\'\ does\ not\ exist
- \*(DC else >$i
- \*(DC fi
- \*(DOesac
- done
-.DE
-.sp
-.ft B
-.ce
-Figure 4. The touch command
-.ft
-.sp
-The \fItrap\fP command
-appears before the creation
-of the temporary file;
-otherwise it would be
-possible for the process
-to die without removing
-the file.
-.LP
-Since there is no signal 0 in UNIX
-it is used by the shell to indicate the
-commands to be executed on exit from the
-shell script.
-.LP
-A script may, itself, elect to
-ignore signals by specifying the null
-string as the argument to trap.
-The following fragment is taken from the
-\fInohup\fP command.
-.DS
- trap \'\' 1 2 3 15
-.DE
-which causes \fIhangup, interrupt, quit \fRand\fI kill\fR
-to be ignored both by the
-script and by invoked commands.
-.LP
-Traps may be reset by saying
-.DS
- trap 2 3
-.DE
-which resets the traps for signals 2 and 3 to their default values.
-A list of the current values of traps may be obtained
-by writing
-.DS
- trap
-.DE
-.LP
-The script \fIscan\fP (Figure 5) is an example
-of the use of \fItrap\fP where there is no exit
-in the trap command.
-\fIscan\fP takes each directory
-in the current directory, prompts
-with its name, and then executes
-commands typed at the terminal
-until an end of file or an interrupt is received.
-Interrupts are ignored while executing
-the requested commands but cause
-termination when \fIscan\fP is
-waiting for input.
-.DS
- d=\`pwd\`
- for\ i\ in\ \*(ST
- do\ if\ test\ \(mid\ $d/$i
- \*(DOthen\ cd\ $d/$i
- \*(DO\*(THwhile\ echo\ "$i:"
- \*(DO\*(TH\*(WHtrap\ exit\ 2
- \*(DO\*(TH\*(WHread\ x
- \*(DO\*(THdo\ trap\ :\ 2;\ eval\ $x;\ done
- \*(DOfi
- done
-.DE
-.sp
-.ft B
-.ce
-Figure 5. The scan command
-.ft
-.sp
-\fIread x\fR is a built-in command that reads one line from the
-standard input
-and places the result in the variable \fBx\|.\fP
-It returns a non-zero exit status if either
-an end-of-file is read or an interrupt
-is received.
-.SH
-3.8\ Command\ execution
-.LP
-To run a command (other than a built-in) the shell first creates
-a new process using the system call \fIfork.\fP
-The execution environment for the command
-includes input, output and the states of signals, and
-is established in the child process
-before the command is executed.
-The built-in command \fIexec\fP
-is used in the rare cases when no fork
-is required
-and simply replaces the shell with a new command.
-For example, a simple version of the \fInohup\fP
-command looks like
-.DS
- trap \\'\\' 1 2 3 15
- exec $\*(ST
-.DE
-The \fItrap\fP turns off the signals specified
-so that they are ignored by subsequently created commands
-and \fIexec\fP replaces the shell by the command
-specified.
-.LP
-Most forms of input output redirection have already been
-described.
-In the following \fIword\fP is only subject
-to parameter and command substitution.
-No file name generation or blank interpretation
-takes place so that, for example,
-.DS
- echo \*(ZZ >\*(ST.c
-.DE
-will write its output into a file whose name is \fB\*(ST.c\|.\fP
-Input output specifications are evaluated left to right
-as they appear in the command.
-.IP >\ \fIword\fP 12
-The standard output (file descriptor 1)
-is sent to the file \fIword\fP which is
-created if it does not already exist.
-.IP \*(AP\ \fIword\fP 12
-The standard output is sent to file \fIword.\fP
-If the file exists then output is appended
-(by seeking to the end);
-otherwise the file is created.
-.IP <\ \fIword\fP 12
-The standard input (file descriptor 0)
-is taken from the file \fIword.\fP
-.IP \*(HE\ \fIword\fP 12
-The standard input is taken from the lines
-of shell input that follow up to but not
-including a line consisting only of \fIword.\fP
-If \fIword\fP is quoted then no interpretation
-of the document occurs.
-If \fIword\fP is not quoted
-then parameter and command substitution
-occur and \fB\\\fP is used to quote
-the characters \fB\\\fP \fB$\fP \fB\`\fP and the first character
-of \fIword.\fP
-In the latter case \fB\\newline\fP is ignored (c.f. quoted strings).
-.IP >&\ \fIdigit\fP 12
-The file descriptor \fIdigit\fP is duplicated using the system
-call \fIdup\fP (2)
-and the result is used as the standard output.
-.IP <&\ \fIdigit\fP 12
-The standard input is duplicated from file descriptor \fIdigit.\fP
-.IP <&\(mi 12
-The standard input is closed.
-.IP >&\(mi 12
-The standard output is closed.
-.LP
-Any of the above may be preceded by a digit in which
-case the file descriptor created is that specified by the digit
-instead of the default 0 or 1.
-For example,
-.DS
- \*(ZZ 2>file
-.DE
-runs a command with message output (file descriptor 2)
-directed to \fIfile.\fP
-.DS
- \*(ZZ 2>&1
-.DE
-runs a command with its standard output and message output
-merged.
-(Strictly speaking file descriptor 2 is created
-by duplicating file descriptor 1 but the effect is usually to
-merge the two streams.)
-.\" Removed by Perry Metzger, most of this is now obsolete
-.\"
-.\" .LP
-.\" The environment for a command run in the background such as
-.\" .DS
-.\" list \*(ST.c \*(VT lpr &
-.\" .DE
-.\" is modified in two ways.
-.\" Firstly, the default standard input
-.\" for such a command is the empty file \fB/dev/null\|.\fR
-.\" This prevents two processes (the shell and the command),
-.\" which are running in parallel, from trying to
-.\" read the same input.
-.\" Chaos would ensue
-.\" if this were not the case.
-.\" For example,
-.\" .DS
-.\" ed file &
-.\" .DE
-.\" would allow both the editor and the shell
-.\" to read from the same input at the same time.
-.\" .LP
-.\" The other modification to the environment of a background
-.\" command is to turn off the QUIT and INTERRUPT signals
-.\" so that they are ignored by the command.
-.\" This allows these signals to be used
-.\" at the terminal without causing background
-.\" commands to terminate.
-.\" For this reason the UNIX convention
-.\" for a signal is that if it is set to 1
-.\" (ignored) then it is never changed
-.\" even for a short time.
-.\" Note that the shell command \fItrap\fP
-.\" has no effect for an ignored signal.
-.SH
-3.9\ Invoking\ the\ shell
-.LP
-The following flags are interpreted by the shell
-when it is invoked.
-If the first character of argument zero is a minus,
-then commands are read from the file \fB.profile\|.\fP
-.IP \fB\(mic\fP\ \fIstring\fP
-.br
-If the \fB\(mic\fP flag is present then
-commands are read from \fIstring\|.\fP
-.IP \fB\(mis\fP
-If the \fB\(mis\fP flag is present or if no
-arguments remain
-then commands are read from the standard input.
-Shell output is written to
-file descriptor 2.
-.IP \fB\(mii\fP
-If the \fB\(mii\fP flag is present or
-if the shell input and output are attached to a terminal (as told by \fIgtty\fP)
-then this shell is \fIinteractive.\fP
-In this case TERMINATE is ignored (so that \fBkill 0\fP
-does not kill an interactive shell) and INTERRUPT is caught and ignored
-(so that \fBwait\fP is interruptable).
-In all cases QUIT is ignored by the shell.
-.SH
-3.10\ Job\ Control
-.LP
-When a command or pipeline (also known as a \fIjob\fP) is running in
-the foreground, entering the stop character (typically
-\s-1CONTROL-Z\s0 but user settable with the \fIstty\fP(1) command)
-will usually cause the job to stop.
-.LP
-The jobs associated with the current shell may be listed by entering
-the \fIjobs\fP command.
-Each job has an associated \fIjob number\fP.
-Jobs that are stopped may be continued by entering
-.DS
- bg %\fIjobnumber\fP
-.DE
-and jobs may be moved to the foreground by entering
-.DS
- fg %\fIjobnumber\fP
-.DE
-If there is a sole job with a particular name (say only one instance
-of \fIcc\fP running), \fIfg\fP and \fIbg\fP may also use name of the
-command in place of the number, as in:
-.DS
- bg %cc
-.DE
-If no `\fB%\fP' clause is entered, most recently stopped job
-(indicated with a `+' by the \fIjobs\fP command) will be assumed.
-See the manual page for the shell for more details.
-.SH
-3.11\ Aliases
-.LP
-The \fIalias\fP command creates a so-called shell alias, which is an
-abbreviation that macro-expands at run time into some other command.
-For example:
-.DS
- alias ls="ls -F"
-.DE
-would cause the command sequence \fBls -F\fP to be executed whenever
-the user types \fBls\fP into the shell.
-Note that if the user types \fBls -a\fP, the shell will in fact
-execute \fBls -F -a\fP.
-The command \fBalias\fP on its own prints out all current aliases.
-The \fIunalias\fP command, as in:
-.DS
- unalias ls
-.DE
-will remove an existing alias.
-Aliases can shadow pre-existing commands, as in the example above.
-They are typically used to override the interactive behavior of
-commands in small ways, for example to always invoke some program with
-a favorite option, and are almost never found in scripts.
-.SH
-3.12\ Command\ Line\ Editing\ and\ Recall
-.LP
-When working interactively with the shell, it is often tedious to
-retype previously entered commands, especially if they are complicated.
-The shell therefore maintains a so-called \fIhistory\fP, which is
-stored in the file specified by the \fB\s-1HISTFILE\s0\fP environment
-variable if it is set.
-Users may view, edit, and re-enter previous lines of input using
-a small subset of the commands of the \fIvi\fP(1) or
-\fIemacs\fP(1)\(dg editors.
-.FS
-Technically, vi command editing is standardized by POSIX while emacs
-is not.
-However, all modern shells support both styles.
-.FE
-Emacs style editing may be selected by entering
-.DS
- set -o emacs
-.DE
-and vi style editing may be selected with
-.DS
- set -o vi
-.DE
-The details of how command line editing works are beyond the scope of
-this document.
-See the shell manual page for details.
-.SH
-Acknowledgements
-.LP
-The design of the shell is
-based in part on the original UNIX shell
-.[
-unix command language thompson
-.]
-and the PWB/UNIX shell,
-.[
-pwb shell mashey unix
-.]
-some
-features having been taken from both.
-Similarities also exist with the
-command interpreters
-of the Cambridge Multiple Access System
-.[
-cambridge multiple access system hartley
-.]
-and of CTSS.
-.[
-ctss
-.]
-.LP
-I would like to thank Dennis Ritchie
-and John Mashey for many
-discussions during the design of the shell.
-I am also grateful to the members of the Computing Science Research Center
-and to Joe Maranzano for their
-comments on drafts of this document.
-.SH
-.[
-$LIST$
-.]
diff --git a/bin/sh/USD.doc/t4 b/bin/sh/USD.doc/t4
deleted file mode 100644
index 7719d6c..0000000
--- a/bin/sh/USD.doc/t4
+++ /dev/null
@@ -1,180 +0,0 @@
-.\" $NetBSD: t4,v 1.3 2010/08/22 02:19:07 perry Exp $
-.\"
-.\" Copyright (C) Caldera International Inc. 2001-2002. All rights reserved.
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions are
-.\" met:
-.\"
-.\" Redistributions of source code and documentation must retain the above
-.\" copyright notice, this list of conditions and the following
-.\" disclaimer.
-.\"
-.\" Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in the
-.\" documentation and/or other materials provided with the distribution.
-.\"
-.\" All advertising materials mentioning features or use of this software
-.\" must display the following acknowledgement:
-.\"
-.\" This product includes software developed or owned by Caldera
-.\" International, Inc. Neither the name of Caldera International, Inc.
-.\" nor the names of other contributors may be used to endorse or promote
-.\" products derived from this software without specific prior written
-.\" permission.
-.\"
-.\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
-.\" INTERNATIONAL, INC. 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 CALDERA INTERNATIONAL, INC. 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) RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
-.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-.\"
-.\" @(#)t4 8.1 (Berkeley) 8/14/93
-.\"
-.bp
-.SH
-Appendix\ A\ -\ Grammar
-.LP
-Note: This grammar needs updating, it is obsolete.
-.LP
-.LD
-\fIitem: word
- input-output
- name = value
-.sp 0.7
-simple-command: item
- simple-command item
-.sp 0.7
-command: simple-command
- \fB( \fIcommand-list \fB)
- \fB{ \fIcommand-list \fB}
- \fBfor \fIname \fBdo \fIcommand-list \fBdone
- \fBfor \fIname \fBin \fIword \*(ZZ \fBdo \fIcommand-list \fBdone
- \fBwhile \fIcommand-list \fBdo \fIcommand-list \fBdone
- \fBuntil \fIcommand-list \fBdo \fIcommand-list \fBdone
- \fBcase \fIword \fBin \fIcase-part \*(ZZ \fBesac
- \fBif \fIcommand-list \fBthen \fIcommand-list \fIelse-part \fBfi
-.sp 0.7
-\fIpipeline: command
- pipeline \fB\*(VT\fI command
-.sp 0.7
-andor: pipeline
- andor \fB&&\fI pipeline
- andor \fB\*(VT\*(VT\fI pipeline
-.sp 0.7
-command-list: andor
- command-list \fB;\fI
- command-list \fB&\fI
- command-list \fB;\fI andor
- command-list \fB&\fI andor
-.sp 0.7
-input-output: \fB> \fIfile
- \fB< \fIfile
- \fB\*(AP \fIword
- \fB\*(HE \fIword
-.sp 0.7
-file: word
- \fB&\fI digit
- \fB&\fI \(mi
-.sp 0.7
-case-part: pattern\fB ) \fIcommand-list\fB ;;
-.sp 0.7
-\fIpattern: word
- pattern \fB\*(VT\fI word
-.sp 0.7
-\fIelse-part: \fBelif \fIcommand-list\fB then\fI command-list else-part\fP
- \fBelse \fIcommand-list\fI
- empty
-.sp 0.7
-empty:
-.sp 0.7
-word: \fRa sequence of non-blank characters\fI
-.sp 0.7
-name: \fRa sequence of letters, digits or underscores starting with a letter\fI
-.sp 0.7
-digit: \fB0 1 2 3 4 5 6 7 8 9\fP
-.DE
-.LP
-.bp
-.SH
-Appendix\ B\ -\ Meta-characters\ and\ Reserved\ Words
-.LP
-a) syntactic
-.RS
-.IP \fB\*(VT\fR 6
-pipe symbol
-.IP \fB&&\fR 6
-`andf' symbol
-.IP \fB\*(VT\*(VT\fR 6
-`orf' symbol
-.IP \fB;\fP 8
-command separator
-.IP \fB;;\fP 8
-case delimiter
-.IP \fB&\fP 8
-background commands
-.IP \fB(\ )\fP 8
-command grouping
-.IP \fB<\fP 8
-input redirection
-.IP \fB\*(HE\fP 8
-input from a here document
-.IP \fB>\fP 8
-output creation
-.IP \fB\*(AP\fP 8
-output append
-.sp 2
-.RE
-.LP
-b) patterns
-.RS
-.IP \fB\*(ST\fP 8
-match any character(s) including none
-.IP \fB?\fP 8
-match any single character
-.IP \fB[...]\fP 8
-match any of the enclosed characters
-.sp 2
-.RE
-.LP
-c) substitution
-.RS
-.IP \fB${...}\fP 8
-substitute shell variable
-.IP \fB$(...)\fP 8
-substitute command output
-.IP \fB\`...\`\fP 8
-substitute command output
-.IP \fB$((...))\fP 8
-substitute arithmetic expression
-.sp 2
-.RE
-.LP
-d) quoting
-.RS
-.IP \fB\e\fP 8
-quote the next character
-.IP \fB\'...\'\fP 8
-quote the enclosed characters except for \'
-.IP \fB"\&..."\fP 8
-quote the enclosed characters except
-for \fB$ \` \e "\fP
-.sp 2
-.RE
-.LP
-e) reserved words
-.DS
-.ft B
-if then else elif fi
-case in esac
-for while until do done
-! { }
-.ft
-.DE
diff --git a/bin/sh/alias.c b/bin/sh/alias.c
deleted file mode 100644
index 2848b52..0000000
--- a/bin/sh/alias.c
+++ /dev/null
@@ -1,314 +0,0 @@
-/* $NetBSD: alias.c,v 1.20 2018/12/03 06:40:26 kre Exp $ */
-
-/*-
- * Copyright (c) 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- */
-
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)alias.c 8.3 (Berkeley) 5/4/95";
-#else
-__RCSID("$NetBSD: alias.c,v 1.20 2018/12/03 06:40:26 kre Exp $");
-#endif
-#endif /* not lint */
-
-#include <stdlib.h>
-#include "shell.h"
-#include "input.h"
-#include "output.h"
-#include "error.h"
-#include "memalloc.h"
-#include "mystring.h"
-#include "alias.h"
-#include "options.h" /* XXX for argptr (should remove?) */
-#include "builtins.h"
-#include "var.h"
-
-#define ATABSIZE 39
-
-struct alias *atab[ATABSIZE];
-
-STATIC void setalias(char *, char *);
-STATIC int by_name(const void *, const void *);
-STATIC void list_aliases(void);
-STATIC int unalias(char *);
-STATIC struct alias **freealias(struct alias **, int);
-STATIC struct alias **hashalias(const char *);
-STATIC size_t countaliases(void);
-
-STATIC
-void
-setalias(char *name, char *val)
-{
- struct alias *ap, **app;
-
- (void) unalias(name); /* old one (if any) is now gone */
- app = hashalias(name);
-
- INTOFF;
- ap = ckmalloc(sizeof (struct alias));
- ap->name = savestr(name);
- ap->flag = 0;
- ap->val = savestr(val);
- ap->next = *app;
- *app = ap;
- INTON;
-}
-
-STATIC struct alias **
-freealias(struct alias **app, int force)
-{
- struct alias *ap = *app;
-
- if (ap == NULL)
- return app;
-
- /*
- * if the alias is currently in use (i.e. its
- * buffer is being used by the input routine) we
- * just null out the name instead of discarding it.
- * If we encounter it later, when it is idle,
- * we will finish freeing it then.
- *
- * Unless we want to simply free everything (INIT)
- */
- if (ap->flag & ALIASINUSE && !force) {
- *ap->name = '\0';
- return &ap->next;
- }
-
- INTOFF;
- *app = ap->next;
- ckfree(ap->name);
- ckfree(ap->val);
- ckfree(ap);
- INTON;
-
- return app;
-}
-
-STATIC int
-unalias(char *name)
-{
- struct alias *ap, **app;
-
- app = hashalias(name);
- while ((ap = *app) != NULL) {
- if (equal(name, ap->name)) {
- (void) freealias(app, 0);
- return 0;
- }
- app = &ap->next;
- }
-
- return 1;
-}
-
-#ifdef mkinit
-MKINIT void rmaliases(int);
-
-SHELLPROC {
- rmaliases(1);
-}
-#endif
-
-void
-rmaliases(int force)
-{
- struct alias **app;
- int i;
-
- INTOFF;
- for (i = 0; i < ATABSIZE; i++) {
- app = &atab[i];
- while (*app)
- app = freealias(app, force);
- }
- INTON;
-}
-
-struct alias *
-lookupalias(const char *name, int check)
-{
- struct alias *ap = *hashalias(name);
-
- while (ap != NULL) {
- if (equal(name, ap->name)) {
- if (check && (ap->flag & ALIASINUSE))
- return NULL;
- return ap;
- }
- ap = ap->next;
- }
-
- return NULL;
-}
-
-const char *
-alias_text(void *dummy __unused, const char *name)
-{
- struct alias *ap;
-
- ap = lookupalias(name, 0);
- if (ap == NULL)
- return NULL;
- return ap->val;
-}
-
-STATIC int
-by_name(const void *a, const void *b)
-{
-
- return strcmp(
- (*(const struct alias * const *)a)->name,
- (*(const struct alias * const *)b)->name);
-}
-
-STATIC void
-list_aliases(void)
-{
- size_t i, j, n;
- const struct alias **aliases;
- const struct alias *ap;
-
- INTOFF;
- n = countaliases();
- aliases = ckmalloc(n * sizeof aliases[0]);
-
- j = 0;
- for (i = 0; i < ATABSIZE; i++)
- for (ap = atab[i]; ap != NULL; ap = ap->next)
- if (ap->name[0] != '\0')
- aliases[j++] = ap;
- if (j != n)
- error("Alias count botch");
- INTON;
-
- qsort(aliases, n, sizeof aliases[0], by_name);
-
- for (i = 0; i < n; i++) {
- out1fmt("alias %s=", aliases[i]->name);
- print_quoted(aliases[i]->val);
- out1c('\n');
- }
-
- ckfree(aliases);
-}
-
-/*
- * Count how many aliases are defined (skipping any
- * that have been deleted, but don't know it yet).
- * Use this opportunity to clean up any of those
- * zombies that are no longer needed.
- */
-STATIC size_t
-countaliases(void)
-{
- struct alias *ap, **app;
- size_t n;
- int i;
-
- n = 0;
- for (i = 0; i < ATABSIZE; i++)
- for (app = &atab[i]; (ap = *app) != NULL;) {
- if (ap->name[0] != '\0')
- n++;
- else {
- app = freealias(app, 0);
- continue;
- }
- app = &ap->next;
- }
-
- return n;
-}
-
-int
-aliascmd(int argc, char **argv)
-{
- char *n, *v;
- int ret = 0;
- struct alias *ap;
-
- if (argc == 1) {
- list_aliases();
- return 0;
- }
-
- while ((n = *++argv) != NULL) {
- if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
- if ((ap = lookupalias(n, 0)) == NULL) {
- outfmt(out2, "alias: %s not found\n", n);
- ret = 1;
- } else {
- out1fmt("alias %s=", n);
- print_quoted(ap->val);
- out1c('\n');
- }
- } else {
- *v++ = '\0';
- setalias(n, v);
- }
- }
-
- return ret;
-}
-
-int
-unaliascmd(int argc, char **argv)
-{
- int i;
-
- while ((i = nextopt("a")) != '\0') {
- if (i == 'a') {
- rmaliases(0);
- return 0;
- }
- }
-
- (void)countaliases(); /* delete any dead ones */
- for (i = 0; *argptr; argptr++)
- i |= unalias(*argptr);
-
- return i;
-}
-
-STATIC struct alias **
-hashalias(const char *p)
-{
- unsigned int hashval;
-
- hashval = *(const unsigned char *)p << 4;
- while (*p)
- hashval += *p++;
- return &atab[hashval % ATABSIZE];
-}
diff --git a/bin/sh/alias.h b/bin/sh/alias.h
deleted file mode 100644
index 390df6d..0000000
--- a/bin/sh/alias.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* $NetBSD: alias.h,v 1.9 2018/12/03 06:40:26 kre Exp $ */
-
-/*-
- * Copyright (c) 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- *
- * @(#)alias.h 8.2 (Berkeley) 5/4/95
- */
-
-#define ALIASINUSE 1
-
-struct alias {
- struct alias *next;
- char *name;
- char *val;
- int flag;
-};
-
-struct alias *lookupalias(const char *, int);
-const char *alias_text(void *, const char *);
-void rmaliases(int);
diff --git a/bin/sh/arith_token.c b/bin/sh/arith_token.c
deleted file mode 100644
index cd91857..0000000
--- a/bin/sh/arith_token.c
+++ /dev/null
@@ -1,262 +0,0 @@
-/* $NetBSD: arith_token.c,v 1.7 2017/12/17 04:06:03 kre Exp $ */
-
-/*-
- * Copyright (c) 2002
- * Herbert Xu.
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- *
- * From FreeBSD, from dash
- */
-
-#include <sys/cdefs.h>
-
-#ifndef lint
-__RCSID("$NetBSD: arith_token.c,v 1.7 2017/12/17 04:06:03 kre Exp $");
-#endif /* not lint */
-
-#include <inttypes.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "shell.h"
-#include "arith_tokens.h"
-#include "expand.h"
-#include "error.h"
-#include "memalloc.h"
-#include "parser.h"
-#include "syntax.h"
-#include "show.h"
-
-#if ARITH_BOR + ARITH_ASS_GAP != ARITH_BORASS || \
- ARITH_ASS + ARITH_ASS_GAP != ARITH_EQ
-#error Arithmetic tokens are out of order.
-#endif
-
-/*
- * Scan next arithmetic token, return its type,
- * leave its value (when applicable) in (global) a_t_val.
- *
- * Input text is in (global) arith_buf which is updated to
- * refer to the next char after the token returned, except
- * on error (ARITH_BAD returned) where arith_buf is not altered.
- */
-int
-arith_token(void)
-{
- int token;
- const char *buf = arith_buf;
- char *end;
- const char *p;
-
- for (;;) {
- token = *buf;
-
- if (isdigit(token)) {
- /*
- * Numbers all start with a digit, and nothing
- * else does, the number ends wherever
- * strtoimax() stops...
- */
- a_t_val.val = strtoimax(buf, &end, 0);
- if (is_in_name(*end)) {
- token = *end;
- while (is_in_name(*++end))
- continue;
- error("arithmetic: unexpected '%c' "
- "(out of range) in numeric constant: "
- "%.*s", token, (int)(end - buf), buf);
- }
- arith_buf = end;
- VTRACE(DBG_ARITH, ("Arith token ARITH_NUM=%jd\n",
- a_t_val.val));
- return ARITH_NUM;
-
- } else if (is_name(token)) {
- /*
- * Variable names all start with an alpha (or '_')
- * and nothing else does. They continue for the
- * longest unbroken sequence of alphanumerics ( + _ )
- */
- arith_var_lno = arith_lno;
- p = buf;
- while (buf++, is_in_name(*buf))
- ;
- a_t_val.name = stalloc(buf - p + 1);
- memcpy(a_t_val.name, p, buf - p);
- a_t_val.name[buf - p] = '\0';
- arith_buf = buf;
- VTRACE(DBG_ARITH, ("Arith token ARITH_VAR=\"%s\"\n",
- a_t_val.name));
- return ARITH_VAR;
-
- } else switch (token) {
- /*
- * everything else must be some kind of
- * operator, white space, or an error.
- */
- case '\n':
- arith_lno++;
- VTRACE(DBG_ARITH, ("Arith: newline\n"));
- /* FALLTHROUGH */
- case ' ':
- case '\t':
- buf++;
- continue;
-
- default:
- error("arithmetic: unexpected '%c' (%#x) in expression",
- token, token);
- /* NOTREACHED */
-
- case '=':
- token = ARITH_ASS;
- checkeq:
- buf++;
- checkeqcur:
- if (*buf != '=')
- goto out;
- token += ARITH_ASS_GAP;
- break;
-
- case '>':
- switch (*++buf) {
- case '=':
- token = ARITH_GE;
- break;
- case '>':
- token = ARITH_RSHIFT;
- goto checkeq;
- default:
- token = ARITH_GT;
- goto out;
- }
- break;
-
- case '<':
- switch (*++buf) {
- case '=':
- token = ARITH_LE;
- break;
- case '<':
- token = ARITH_LSHIFT;
- goto checkeq;
- default:
- token = ARITH_LT;
- goto out;
- }
- break;
-
- case '|':
- if (*++buf != '|') {
- token = ARITH_BOR;
- goto checkeqcur;
- }
- token = ARITH_OR;
- break;
-
- case '&':
- if (*++buf != '&') {
- token = ARITH_BAND;
- goto checkeqcur;
- }
- token = ARITH_AND;
- break;
-
- case '!':
- if (*++buf != '=') {
- token = ARITH_NOT;
- goto out;
- }
- token = ARITH_NE;
- break;
-
- case 0:
- goto out;
-
- case '(':
- token = ARITH_LPAREN;
- break;
- case ')':
- token = ARITH_RPAREN;
- break;
-
- case '*':
- token = ARITH_MUL;
- goto checkeq;
- case '/':
- token = ARITH_DIV;
- goto checkeq;
- case '%':
- token = ARITH_REM;
- goto checkeq;
-
- case '+':
- if (buf[1] == '+') {
- buf++;
- token = ARITH_INCR;
- break;
- }
- token = ARITH_ADD;
- goto checkeq;
- case '-':
- if (buf[1] == '-') {
- buf++;
- token = ARITH_DECR;
- break;
- }
- token = ARITH_SUB;
- goto checkeq;
- case '~':
- token = ARITH_BNOT;
- break;
- case '^':
- token = ARITH_BXOR;
- goto checkeq;
-
- case '?':
- token = ARITH_QMARK;
- break;
- case ':':
- token = ARITH_COLON;
- break;
- case ',':
- token = ARITH_COMMA;
- break;
- }
- break;
- }
- buf++;
- out:
- arith_buf = buf;
- VTRACE(DBG_ARITH, ("Arith token: %d\n", token));
- return token;
-}
diff --git a/bin/sh/arith_tokens.h b/bin/sh/arith_tokens.h
deleted file mode 100644
index f655aa9..0000000
--- a/bin/sh/arith_tokens.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/* $NetBSD: arith_tokens.h,v 1.3 2017/07/24 13:21:14 kre Exp $ */
-
-/*-
- * Copyright (c) 1993
- * The Regents of the University of California. All rights reserved.
- * Copyright (c) 2007
- * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- *
- * From FreeBSD who obtained it from dash (modified both times.)
- */
-
-/*
- * Tokens returned from arith_token()
- *
- * Caution, values are not arbitrary.
- */
-
-#define ARITH_BAD 0
-
-#define ARITH_ASS 1
-
-#define ARITH_OR 2
-#define ARITH_AND 3
-#define ARITH_NUM 5
-#define ARITH_VAR 6
-#define ARITH_NOT 7
-
-#define ARITH_BINOP_MIN 8
-
-#define ARITH_LE 8
-#define ARITH_GE 9
-#define ARITH_LT 10
-#define ARITH_GT 11
-#define ARITH_EQ 12 /* Must be ARITH_ASS + ARITH_ASS_GAP */
-
-#define ARITH_ASS_BASE 13
-
-#define ARITH_REM 13
-#define ARITH_BAND 14
-#define ARITH_LSHIFT 15
-#define ARITH_RSHIFT 16
-#define ARITH_MUL 17
-#define ARITH_ADD 18
-#define ARITH_BOR 19
-#define ARITH_SUB 20
-#define ARITH_BXOR 21
-#define ARITH_DIV 22
-
-#define ARITH_NE 23
-
-#define ARITH_BINOP_MAX 24
-
-#define ARITH_ASS_MIN ARITH_BINOP_MAX
-#define ARITH_ASS_GAP (ARITH_ASS_MIN - ARITH_ASS_BASE)
-
-#define ARITH_REMASS (ARITH_ASS_GAP + ARITH_REM)
-#define ARITH_BANDASS (ARITH_ASS_GAP + ARITH_BAND)
-#define ARITH_LSHIFTASS (ARITH_ASS_GAP + ARITH_LSHIFT)
-#define ARITH_RSHIFTASS (ARITH_ASS_GAP + ARITH_RSHIFT)
-#define ARITH_MULASS (ARITH_ASS_GAP + ARITH_MUL)
-#define ARITH_ADDASS (ARITH_ASS_GAP + ARITH_ADD)
-#define ARITH_BORASS (ARITH_ASS_GAP + ARITH_BOR)
-#define ARITH_SUBASS (ARITH_ASS_GAP + ARITH_SUB)
-#define ARITH_BXORASS (ARITH_ASS_GAP + ARITH_BXOR)
-#define ARITH_DIVASS (ARITH_ASS_GAP + ARITH_BXOR)
-
-#define ARITH_ASS_MAX 34
-
-#define ARITH_LPAREN 34
-#define ARITH_RPAREN 35
-#define ARITH_BNOT 36
-#define ARITH_QMARK 37
-#define ARITH_COLON 38
-#define ARITH_INCR 39
-#define ARITH_DECR 40
-#define ARITH_COMMA 41
-
-/*
- * Globals shared between arith parser, and lexer
- */
-
-extern const char *arith_buf;
-
-union a_token_val {
- intmax_t val;
- char *name;
-};
-
-extern union a_token_val a_t_val;
-
-extern int arith_lno, arith_var_lno;
-
-int arith_token(void);
diff --git a/bin/sh/arithmetic.c b/bin/sh/arithmetic.c
deleted file mode 100644
index f9c91a4..0000000
--- a/bin/sh/arithmetic.c
+++ /dev/null
@@ -1,502 +0,0 @@
-/* $NetBSD: arithmetic.c,v 1.5 2018/04/21 23:01:29 kre Exp $ */
-
-/*-
- * Copyright (c) 1993
- * The Regents of the University of California. All rights reserved.
- * Copyright (c) 2007
- * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- *
- * From FreeBSD, who obtained it from dash, modified both times...
- */
-
-#include <sys/cdefs.h>
-
-#ifndef lint
-__RCSID("$NetBSD: arithmetic.c,v 1.5 2018/04/21 23:01:29 kre Exp $");
-#endif /* not lint */
-
-#include <limits.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "shell.h"
-#include "arithmetic.h"
-#include "arith_tokens.h"
-#include "expand.h"
-#include "error.h"
-#include "memalloc.h"
-#include "output.h"
-#include "options.h"
-#include "var.h"
-#include "show.h"
-#include "syntax.h"
-
-#if ARITH_BOR + ARITH_ASS_GAP != ARITH_BORASS || \
- ARITH_ASS + ARITH_ASS_GAP != ARITH_EQ
-#error Arithmetic tokens are out of order.
-#endif
-
-static const char *arith_startbuf;
-
-const char *arith_buf;
-union a_token_val a_t_val;
-
-static int last_token;
-
-int arith_lno, arith_var_lno;
-
-#define ARITH_PRECEDENCE(op, prec) [op - ARITH_BINOP_MIN] = prec
-
-static const char prec[ARITH_BINOP_MAX - ARITH_BINOP_MIN] = {
- ARITH_PRECEDENCE(ARITH_MUL, 0),
- ARITH_PRECEDENCE(ARITH_DIV, 0),
- ARITH_PRECEDENCE(ARITH_REM, 0),
- ARITH_PRECEDENCE(ARITH_ADD, 1),
- ARITH_PRECEDENCE(ARITH_SUB, 1),
- ARITH_PRECEDENCE(ARITH_LSHIFT, 2),
- ARITH_PRECEDENCE(ARITH_RSHIFT, 2),
- ARITH_PRECEDENCE(ARITH_LT, 3),
- ARITH_PRECEDENCE(ARITH_LE, 3),
- ARITH_PRECEDENCE(ARITH_GT, 3),
- ARITH_PRECEDENCE(ARITH_GE, 3),
- ARITH_PRECEDENCE(ARITH_EQ, 4),
- ARITH_PRECEDENCE(ARITH_NE, 4),
- ARITH_PRECEDENCE(ARITH_BAND, 5),
- ARITH_PRECEDENCE(ARITH_BXOR, 6),
- ARITH_PRECEDENCE(ARITH_BOR, 7),
-};
-
-#define ARITH_MAX_PREC 8
-
-int expcmd(int, char **);
-
-static void __dead
-arith_err(const char *s)
-{
- error("arithmetic expression: %s: \"%s\"", s, arith_startbuf);
- /* NOTREACHED */
-}
-
-static intmax_t
-arith_lookupvarint(char *varname)
-{
- const char *str;
- char *p;
- intmax_t result;
- const int oln = line_number;
-
- VTRACE(DBG_ARITH, ("Arith var lookup(\"%s\") with lno=%d\n", varname,
- arith_var_lno));
-
- line_number = arith_var_lno;
- str = lookupvar(varname);
- line_number = oln;
-
- if (uflag && str == NULL)
- arith_err("variable not set");
- if (str == NULL || *str == '\0')
- str = "0";
- errno = 0;
- result = strtoimax(str, &p, 0);
- if (errno != 0 || *p != '\0') {
- if (errno == 0) {
- while (*p != '\0' && is_space(*p))
- p++;
- if (*p == '\0')
- return result;
- }
- arith_err("variable contains non-numeric value");
- }
- return result;
-}
-
-static inline int
-arith_prec(int op)
-{
-
- return prec[op - ARITH_BINOP_MIN];
-}
-
-static inline int
-higher_prec(int op1, int op2)
-{
-
- return arith_prec(op1) < arith_prec(op2);
-}
-
-static intmax_t
-do_binop(int op, intmax_t a, intmax_t b)
-{
-
- VTRACE(DBG_ARITH, ("Arith do binop %d (%jd, %jd)\n", op, a, b));
- switch (op) {
- default:
- arith_err("token error");
- case ARITH_REM:
- case ARITH_DIV:
- if (b == 0)
- arith_err("division by zero");
- if (a == INTMAX_MIN && b == -1)
- arith_err("divide error");
- return op == ARITH_REM ? a % b : a / b;
- case ARITH_MUL:
- return (uintmax_t)a * (uintmax_t)b;
- case ARITH_ADD:
- return (uintmax_t)a + (uintmax_t)b;
- case ARITH_SUB:
- return (uintmax_t)a - (uintmax_t)b;
- case ARITH_LSHIFT:
- return (uintmax_t)a << (b & (sizeof(uintmax_t) * CHAR_BIT - 1));
- case ARITH_RSHIFT:
- return a >> (b & (sizeof(uintmax_t) * CHAR_BIT - 1));
- case ARITH_LT:
- return a < b;
- case ARITH_LE:
- return a <= b;
- case ARITH_GT:
- return a > b;
- case ARITH_GE:
- return a >= b;
- case ARITH_EQ:
- return a == b;
- case ARITH_NE:
- return a != b;
- case ARITH_BAND:
- return a & b;
- case ARITH_BXOR:
- return a ^ b;
- case ARITH_BOR:
- return a | b;
- }
-}
-
-static intmax_t assignment(int, int);
-static intmax_t comma_list(int, int);
-
-static intmax_t
-primary(int token, union a_token_val *val, int op, int noeval)
-{
- intmax_t result;
- char sresult[DIGITS(result) + 1];
-
- VTRACE(DBG_ARITH, ("Arith primary: token %d op %d%s\n",
- token, op, noeval ? " noeval" : ""));
-
- switch (token) {
- case ARITH_LPAREN:
- result = comma_list(op, noeval);
- if (last_token != ARITH_RPAREN)
- arith_err("expecting ')'");
- last_token = arith_token();
- return result;
- case ARITH_NUM:
- last_token = op;
- return val->val;
- case ARITH_VAR:
- result = noeval ? val->val : arith_lookupvarint(val->name);
- if (op == ARITH_INCR || op == ARITH_DECR) {
- last_token = arith_token();
- if (noeval)
- return val->val;
-
- snprintf(sresult, sizeof(sresult), ARITH_FORMAT_STR,
- result + (op == ARITH_INCR ? 1 : -1));
- setvar(val->name, sresult, 0);
- } else
- last_token = op;
- return result;
- case ARITH_ADD:
- *val = a_t_val;
- return primary(op, val, arith_token(), noeval);
- case ARITH_SUB:
- *val = a_t_val;
- return -primary(op, val, arith_token(), noeval);
- case ARITH_NOT:
- *val = a_t_val;
- return !primary(op, val, arith_token(), noeval);
- case ARITH_BNOT:
- *val = a_t_val;
- return ~primary(op, val, arith_token(), noeval);
- case ARITH_INCR:
- case ARITH_DECR:
- if (op != ARITH_VAR)
- arith_err("incr/decr require var name");
- last_token = arith_token();
- if (noeval)
- return val->val;
- result = arith_lookupvarint(a_t_val.name);
- snprintf(sresult, sizeof(sresult), ARITH_FORMAT_STR,
- result += (token == ARITH_INCR ? 1 : -1));
- setvar(a_t_val.name, sresult, 0);
- return result;
- default:
- arith_err("expecting primary");
- }
- return 0; /* never reached */
-}
-
-static intmax_t
-binop2(intmax_t a, int op, int precedence, int noeval)
-{
- union a_token_val val;
- intmax_t b;
- int op2;
- int token;
-
- VTRACE(DBG_ARITH, ("Arith: binop2 %jd op %d (P:%d)%s\n",
- a, op, precedence, noeval ? " noeval" : ""));
-
- for (;;) {
- token = arith_token();
- val = a_t_val;
-
- b = primary(token, &val, arith_token(), noeval);
-
- op2 = last_token;
- if (op2 >= ARITH_BINOP_MIN && op2 < ARITH_BINOP_MAX &&
- higher_prec(op2, op)) {
- b = binop2(b, op2, arith_prec(op), noeval);
- op2 = last_token;
- }
-
- a = noeval ? b : do_binop(op, a, b);
-
- if (op2 < ARITH_BINOP_MIN || op2 >= ARITH_BINOP_MAX ||
- arith_prec(op2) >= precedence)
- return a;
-
- op = op2;
- }
-}
-
-static intmax_t
-binop(int token, union a_token_val *val, int op, int noeval)
-{
- intmax_t a = primary(token, val, op, noeval);
-
- op = last_token;
- if (op < ARITH_BINOP_MIN || op >= ARITH_BINOP_MAX)
- return a;
-
- return binop2(a, op, ARITH_MAX_PREC, noeval);
-}
-
-static intmax_t
-and(int token, union a_token_val *val, int op, int noeval)
-{
- intmax_t a = binop(token, val, op, noeval);
- intmax_t b;
-
- op = last_token;
- if (op != ARITH_AND)
- return a;
-
- VTRACE(DBG_ARITH, ("Arith: AND %jd%s\n", a, noeval ? " noeval" : ""));
-
- token = arith_token();
- *val = a_t_val;
-
- b = and(token, val, arith_token(), noeval | !a);
-
- return a && b;
-}
-
-static intmax_t
-or(int token, union a_token_val *val, int op, int noeval)
-{
- intmax_t a = and(token, val, op, noeval);
- intmax_t b;
-
- op = last_token;
- if (op != ARITH_OR)
- return a;
-
- VTRACE(DBG_ARITH, ("Arith: OR %jd%s\n", a, noeval ? " noeval" : ""));
-
- token = arith_token();
- *val = a_t_val;
-
- b = or(token, val, arith_token(), noeval | !!a);
-
- return a || b;
-}
-
-static intmax_t
-cond(int token, union a_token_val *val, int op, int noeval)
-{
- intmax_t a = or(token, val, op, noeval);
- intmax_t b;
- intmax_t c;
-
- if (last_token != ARITH_QMARK)
- return a;
-
- VTRACE(DBG_ARITH, ("Arith: ?: %jd%s\n", a, noeval ? " noeval" : ""));
-
- b = assignment(arith_token(), noeval | !a);
-
- if (last_token != ARITH_COLON)
- arith_err("expecting ':'");
-
- token = arith_token();
- *val = a_t_val;
-
- c = cond(token, val, arith_token(), noeval | !!a);
-
- return a ? b : c;
-}
-
-static intmax_t
-assignment(int var, int noeval)
-{
- union a_token_val val = a_t_val;
- int op = arith_token();
- intmax_t result;
- char sresult[DIGITS(result) + 1];
-
-
- if (var != ARITH_VAR)
- return cond(var, &val, op, noeval);
-
- if (op != ARITH_ASS && (op < ARITH_ASS_MIN || op >= ARITH_ASS_MAX))
- return cond(var, &val, op, noeval);
-
- VTRACE(DBG_ARITH, ("Arith: %s ASSIGN %d%s\n", val.name, op,
- noeval ? " noeval" : ""));
-
- result = assignment(arith_token(), noeval);
- if (noeval)
- return result;
-
- if (op != ARITH_ASS)
- result = do_binop(op - ARITH_ASS_GAP,
- arith_lookupvarint(val.name), result);
- snprintf(sresult, sizeof(sresult), ARITH_FORMAT_STR, result);
- setvar(val.name, sresult, 0);
- return result;
-}
-
-static intmax_t
-comma_list(int token, int noeval)
-{
- intmax_t result = assignment(token, noeval);
-
- while (last_token == ARITH_COMMA) {
- VTRACE(DBG_ARITH, ("Arith: comma discarding %jd%s\n", result,
- noeval ? " noeval" : ""));
- result = assignment(arith_token(), noeval);
- }
-
- return result;
-}
-
-intmax_t
-arith(const char *s, int lno)
-{
- struct stackmark smark;
- intmax_t result;
- const char *p;
- int nls = 0;
-
- setstackmark(&smark);
-
- arith_lno = lno;
-
- CTRACE(DBG_ARITH, ("Arith(\"%s\", %d) @%d\n", s, lno, arith_lno));
-
- /* check if it is possible we might reference LINENO */
- p = s;
- while ((p = strchr(p, 'L')) != NULL) {
- if (p[1] == 'I' && p[2] == 'N') {
- /* if it is possible, we need to correct airth_lno */
- p = s;
- while ((p = strchr(p, '\n')) != NULL)
- nls++, p++;
- VTRACE(DBG_ARITH, ("Arith found %d newlines\n", nls));
- arith_lno -= nls;
- break;
- }
- p++;
- }
-
- arith_buf = arith_startbuf = s;
-
- result = comma_list(arith_token(), 0);
-
- if (last_token)
- arith_err("expecting end of expression");
-
- popstackmark(&smark);
-
- CTRACE(DBG_ARITH, ("Arith result=%jd\n", result));
-
- return result;
-}
-
-/*
- * The let(1)/exp(1) builtin.
- */
-int
-expcmd(int argc, char **argv)
-{
- const char *p;
- char *concat;
- char **ap;
- intmax_t i;
-
- if (argc > 1) {
- p = argv[1];
- if (argc > 2) {
- /*
- * Concatenate arguments.
- */
- STARTSTACKSTR(concat);
- ap = argv + 2;
- for (;;) {
- while (*p)
- STPUTC(*p++, concat);
- if ((p = *ap++) == NULL)
- break;
- STPUTC(' ', concat);
- }
- STPUTC('\0', concat);
- p = grabstackstr(concat);
- }
- } else
- p = "";
-
- i = arith(p, line_number);
-
- out1fmt(ARITH_FORMAT_STR "\n", i);
- return !i;
-}
diff --git a/bin/sh/arithmetic.h b/bin/sh/arithmetic.h
deleted file mode 100644
index 51808d3..0000000
--- a/bin/sh/arithmetic.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* $NetBSD: arithmetic.h,v 1.2 2017/06/07 05:08:32 kre Exp $ */
-
-/*-
- * Copyright (c) 1995
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 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.
- * 4. 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.
- *
- * @(#)arith.h 1.1 (Berkeley) 5/4/95
- *
- * From FreeBSD, from dash
- */
-
-#include "shell.h"
-
-#define DIGITS(var) (3 + (2 + CHAR_BIT * sizeof((var))) / 3)
-
-#define ARITH_FORMAT_STR "%" PRIdMAX
-
-intmax_t arith(const char *, int);
diff --git a/bin/sh/bltin/bltin.h b/bin/sh/bltin/bltin.h
deleted file mode 100644
index b5669f1..0000000
--- a/bin/sh/bltin/bltin.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/* $NetBSD: bltin.h,v 1.15 2017/06/26 22:09:16 kre Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- *
- * @(#)bltin.h 8.1 (Berkeley) 5/31/93
- */
-
-/*
- * This file is included by programs which are optionally built into the
- * shell.
- *
- * We always define SHELL_BUILTIN, to allow other included headers to
- * hide some of their symbols if appropriate.
- *
- * If SHELL is defined, we try to map the standard UNIX library routines
- * to ash routines using defines.
- */
-
-#define SHELL_BUILTIN
-#include "../shell.h"
-#include "../mystring.h"
-#ifdef SHELL
-#include "../output.h"
-#include "../error.h"
-#include "../var.h"
-#undef stdout
-#undef stderr
-#undef putc
-#undef putchar
-#undef fileno
-#undef ferror
-#define FILE struct output
-#define stdout out1
-#define stderr out2
-#ifdef __GNUC__
-#define _RETURN_INT(x) ({(x); 0;}) /* map from void foo() to int bar() */
-#else
-#define _RETURN_INT(x) ((x), 0) /* map from void foo() to int bar() */
-#endif
-#define fprintf(...) _RETURN_INT(outfmt(__VA_ARGS__))
-#define printf(...) _RETURN_INT(out1fmt(__VA_ARGS__))
-#define putc(c, file) _RETURN_INT(outc(c, file))
-#define putchar(c) _RETURN_INT(out1c(c))
-#define fputs(...) _RETURN_INT(outstr(__VA_ARGS__))
-#define fflush(f) _RETURN_INT(flushout(f))
-#define fileno(f) ((f)->fd)
-#define ferror(f) ((f)->flags & OUTPUT_ERR)
-#define INITARGS(argv)
-#define err sh_err
-#define verr sh_verr
-#define errx sh_errx
-#define verrx sh_verrx
-#define warn sh_warn
-#define vwarn sh_vwarn
-#define warnx sh_warnx
-#define vwarnx sh_vwarnx
-#define exit sh_exit
-#define setprogname(s)
-#define getprogname() commandname
-#define setlocate(l,s) 0
-
-#define getenv(p) bltinlookup((p),0)
-
-#else /* ! SHELL */
-#undef NULL
-#include <stdio.h>
-#undef main
-#define INITARGS(argv) if ((commandname = argv[0]) == NULL) {fputs("Argc is zero\n", stderr); exit(2);} else
-#endif /* ! SHELL */
-
-pointer stalloc(int);
-
-int echocmd(int, char **);
-
-
-extern const char *commandname;
diff --git a/bin/sh/bltin/echo.1 b/bin/sh/bltin/echo.1
deleted file mode 100644
index 13b3c6a..0000000
--- a/bin/sh/bltin/echo.1
+++ /dev/null
@@ -1,109 +0,0 @@
-.\" $NetBSD: echo.1,v 1.14 2017/07/03 21:33:24 wiz Exp $
-.\"
-.\" Copyright (c) 1991, 1993
-.\" The Regents of the University of California. All rights reserved.
-.\"
-.\" This code is derived from software contributed to Berkeley by
-.\" Kenneth Almquist.
-.\" Copyright 1989 by Kenneth Almquist
-.\"
-.\" 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.
-.\"
-.\" @(#)echo.1 8.1 (Berkeley) 5/31/93
-.\"
-.Dd May 31, 1993
-.Dt ECHO 1
-.Os
-.Sh NAME
-.Nm echo
-.Nd produce message in a shell script
-.Sh SYNOPSIS
-.Nm
-.Op Fl n | Fl e
-.Ar args ...
-.Sh DESCRIPTION
-.Nm
-prints its arguments on the standard output, separated by spaces.
-Unless the
-.Fl n
-option is present, a newline is output following the arguments.
-The
-.Fl e
-option causes
-.Nm
-to treat the escape sequences specially, as described in the following
-paragraph.
-The
-.Fl e
-option is the default, and is provided solely for compatibility with
-other systems.
-Only one of the options
-.Fl n
-and
-.Fl e
-may be given.
-.Pp
-If any of the following sequences of characters is encountered during
-output, the sequence is not output. Instead, the specified action is
-performed:
-.Bl -tag -width indent
-.It Li \eb
-A backspace character is output.
-.It Li \ec
-Subsequent output is suppressed. This is normally used at the end of the
-last argument to suppress the trailing newline that
-.Nm
-would otherwise output.
-.It Li \ef
-Output a form feed.
-.It Li \en
-Output a newline character.
-.It Li \er
-Output a carriage return.
-.It Li \et
-Output a (horizontal) tab character.
-.It Li \ev
-Output a vertical tab.
-.It Li \e0 Ns Ar digits
-Output the character whose value is given by zero to three digits.
-If there are zero digits, a nul character is output.
-.It Li \e\e
-Output a backslash.
-.El
-.Sh HINTS
-Remember that backslash is special to the shell and needs to be escaped.
-To output a message to standard error, say
-.Pp
-.D1 echo message >&2
-.Sh BUGS
-The octal character escape mechanism
-.Pq Li \e0 Ns Ar digits
-differs from the
-C language mechanism.
-.Pp
-There is no way to force
-.Nm
-to treat its arguments literally, rather than interpreting them as
-options and escape sequences.
diff --git a/bin/sh/bltin/echo.c b/bin/sh/bltin/echo.c
deleted file mode 100644
index 440e01b..0000000
--- a/bin/sh/bltin/echo.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/* $NetBSD: echo.c,v 1.14 2008/10/12 01:40:37 dholland Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- *
- * @(#)echo.c 8.1 (Berkeley) 5/31/93
- */
-
-/*
- * Echo command.
- *
- * echo is steeped in tradition - several of them!
- * netbsd has supported 'echo [-n | -e] args' in spite of -e not being
- * documented anywhere.
- * Posix requires that -n be supported, output from strings containing
- * \ is implementation defined
- * The Single Unix Spec requires that \ escapes be treated as if -e
- * were set, but that -n not be treated as an option.
- * (ksh supports 'echo [-eEn] args', but not -- so that it is actually
- * impossible to actually output '-n')
- *
- * It is suggested that 'printf "%b" "string"' be used to get \ sequences
- * expanded. printf is now a builtin of netbsd's sh and csh.
- */
-
-#include <sys/cdefs.h>
-__RCSID("$NetBSD: echo.c,v 1.14 2008/10/12 01:40:37 dholland Exp $");
-
-#define main echocmd
-
-#include "bltin.h"
-
-int
-main(int argc, char **argv)
-{
- char **ap;
- char *p;
- char c;
- int count;
- int nflag = 0;
- int eflag = 0;
-
- ap = argv;
- if (argc)
- ap++;
-
- if ((p = *ap) != NULL) {
- if (equal(p, "-n")) {
- nflag = 1;
- ap++;
- } else if (equal(p, "-e")) {
- eflag = 1;
- ap++;
- }
- }
-
- while ((p = *ap++) != NULL) {
- while ((c = *p++) != '\0') {
- if (c == '\\' && eflag) {
- switch (*p++) {
- case 'a': c = '\a'; break; /* bell */
- case 'b': c = '\b'; break;
- case 'c': return 0; /* exit */
- case 'e': c = 033; break; /* escape */
- case 'f': c = '\f'; break;
- case 'n': c = '\n'; break;
- case 'r': c = '\r'; break;
- case 't': c = '\t'; break;
- case 'v': c = '\v'; break;
- case '\\': break; /* c = '\\' */
- case '0':
- c = 0;
- count = 3;
- while (--count >= 0 && (unsigned)(*p - '0') < 8)
- c = (c << 3) + (*p++ - '0');
- break;
- default:
- /* Output the '/' and char following */
- p--;
- break;
- }
- }
- putchar(c);
- }
- if (*ap)
- putchar(' ');
- }
- if (! nflag)
- putchar('\n');
- fflush(stdout);
- if (ferror(stdout))
- return 1;
- return 0;
-}
diff --git a/bin/sh/builtins.def b/bin/sh/builtins.def
deleted file mode 100644
index d702707..0000000
--- a/bin/sh/builtins.def
+++ /dev/null
@@ -1,98 +0,0 @@
-#!/bin/sh -
-# $NetBSD: builtins.def,v 1.25 2017/05/15 20:00:36 kre Exp $
-#
-# Copyright (c) 1991, 1993
-# The Regents of the University of California. All rights reserved.
-#
-# This code is derived from software contributed to Berkeley by
-# Kenneth Almquist.
-#
-# 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.
-#
-# @(#)builtins.def 8.4 (Berkeley) 5/4/95
-
-#
-# This file lists all the builtin commands. The first column is the name
-# of a C routine.
-# The -j flag specifies that this command is to be excluded from systems
-# without job control.
-# The -h flag specifies that this command is to be excluded from systems
-# based on the SMALL compile-time symbol.
-# The -s flag specifies that this is a posix 'special builtin' command.
-# The -u flag specifies that this is a posix 'standard utility'.
-# The rest of the line specifies the command name or names used to run
-# the command.
-
-bltincmd -u command
-bgcmd -j -u bg
-breakcmd -s break -s continue
-cdcmd -u cd chdir
-dotcmd -s .
-echocmd echo
-evalcmd -s eval
-execcmd -s exec
-exitcmd -s exit
-expcmd exp let
-exportcmd -s export -s readonly
-falsecmd -u false
-histcmd -h -u fc
-inputrc inputrc
-fgcmd -j -u fg
-fgcmd_percent -j -u %
-getoptscmd -u getopts
-hashcmd hash
-jobidcmd jobid
-jobscmd -u jobs
-localcmd local
-#ifndef TINY
-printfcmd printf
-#endif
-pwdcmd -u pwd
-readcmd -u read
-returncmd -s return
-setcmd -s set
-fdflagscmd fdflags
-setvarcmd setvar
-shiftcmd -s shift
-timescmd -s times
-trapcmd -s trap
-truecmd -s : -u true
-typecmd type
-umaskcmd -u umask
-unaliascmd -u unalias
-unsetcmd -s unset
-waitcmd -u wait
-aliascmd -u alias
-ulimitcmd ulimit
-testcmd test [
-killcmd -u kill # mandated by posix for 'kill %job'
-wordexpcmd wordexp
-#newgrp -u newgrp # optional command in posix
-
-#ifdef DEBUG
-debugcmd debug
-#endif
-
-#exprcmd expr
diff --git a/bin/sh/cd.c b/bin/sh/cd.c
deleted file mode 100644
index 2b1046d..0000000
--- a/bin/sh/cd.c
+++ /dev/null
@@ -1,463 +0,0 @@
-/* $NetBSD: cd.c,v 1.50 2017/07/05 20:00:27 kre Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- */
-
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)cd.c 8.2 (Berkeley) 5/4/95";
-#else
-__RCSID("$NetBSD: cd.c,v 1.50 2017/07/05 20:00:27 kre Exp $");
-#endif
-#endif /* not lint */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-
-/*
- * The cd and pwd commands.
- */
-
-#include "shell.h"
-#include "var.h"
-#include "nodes.h" /* for jobs.h */
-#include "jobs.h"
-#include "options.h"
-#include "builtins.h"
-#include "output.h"
-#include "memalloc.h"
-#include "error.h"
-#include "exec.h"
-#include "redir.h"
-#include "mystring.h"
-#include "show.h"
-#include "cd.h"
-
-STATIC int docd(const char *, int);
-STATIC char *getcomponent(void);
-STATIC void updatepwd(const char *);
-STATIC void find_curdir(int noerror);
-
-char *curdir = NULL; /* current working directory */
-char *prevdir; /* previous working directory */
-STATIC char *cdcomppath;
-
-int
-cdcmd(int argc, char **argv)
-{
- const char *dest;
- const char *path, *cp;
- char *p;
- char *d;
- struct stat statb;
- int print = cdprint; /* set -o cdprint to enable */
-
- while (nextopt("P") != '\0')
- ;
-
- /*
- * Try (quite hard) to have 'curdir' defined, nothing has set
- * it on entry to the shell, but we want 'cd fred; cd -' to work.
- */
- getpwd(1);
- dest = *argptr;
- if (dest == NULL) {
- dest = bltinlookup("HOME", 1);
- if (dest == NULL)
- error("HOME not set");
- } else if (argptr[1]) {
- /* Do 'ksh' style substitution */
- if (!curdir)
- error("PWD not set");
- p = strstr(curdir, dest);
- if (!p)
- error("bad substitution");
- d = stalloc(strlen(curdir) + strlen(argptr[1]) + 1);
- memcpy(d, curdir, p - curdir);
- strcpy(d + (p - curdir), argptr[1]);
- strcat(d, p + strlen(dest));
- dest = d;
- print = 1;
- } else if (dest[0] == '-' && dest[1] == '\0') {
- dest = prevdir ? prevdir : curdir;
- print = 1;
- }
- if (*dest == '\0')
- dest = ".";
-
- cp = dest;
- if (*cp == '.' && *++cp == '.')
- cp++;
- if (*cp == 0 || *cp == '/' || (path = bltinlookup("CDPATH", 1)) == NULL)
- path = nullstr;
- while ((p = padvance(&path, dest, 0)) != NULL) {
- stunalloc(p);
- if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
- int dopr = print;
-
- if (!print) {
- /*
- * XXX - rethink
- */
- if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
- dopr = strcmp(p + 2, dest);
- else
- dopr = strcmp(p, dest);
- }
- if (docd(p, dopr) >= 0)
- return 0;
-
- }
- }
- error("can't cd to %s", dest);
- /* NOTREACHED */
-}
-
-
-/*
- * Actually do the chdir. In an interactive shell, print the
- * directory name if "print" is nonzero.
- */
-
-STATIC int
-docd(const char *dest, int print)
-{
-#if 0 /* no "cd -L" (ever) so all this is just a waste of time ... */
- char *p;
- char *q;
- char *component;
- struct stat statb;
- int first;
- int badstat;
-
- CTRACE(DBG_CMDS, ("docd(\"%s\", %d) called\n", dest, print));
-
- /*
- * Check each component of the path. If we find a symlink or
- * something we can't stat, clear curdir to force a getcwd()
- * next time we get the value of the current directory.
- */
- badstat = 0;
- cdcomppath = stalloc(strlen(dest) + 1);
- scopy(dest, cdcomppath);
- STARTSTACKSTR(p);
- if (*dest == '/') {
- STPUTC('/', p);
- cdcomppath++;
- }
- first = 1;
- while ((q = getcomponent()) != NULL) {
- if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0'))
- continue;
- if (! first)
- STPUTC('/', p);
- first = 0;
- component = q;
- while (*q)
- STPUTC(*q++, p);
- if (equal(component, ".."))
- continue;
- STACKSTRNUL(p);
- if (lstat(stackblock(), &statb) < 0) {
- badstat = 1;
- break;
- }
- }
-#endif
-
- INTOFF;
- if (chdir(dest) < 0) {
- INTON;
- return -1;
- }
- updatepwd(NULL); /* only do cd -P, no "pretend" -L mode */
- INTON;
- if (print && iflag == 1 && curdir)
- out1fmt("%s\n", curdir);
- return 0;
-}
-
-
-/*
- * Get the next component of the path name pointed to by cdcomppath.
- * This routine overwrites the string pointed to by cdcomppath.
- */
-
-STATIC char *
-getcomponent(void)
-{
- char *p;
- char *start;
-
- if ((p = cdcomppath) == NULL)
- return NULL;
- start = cdcomppath;
- while (*p != '/' && *p != '\0')
- p++;
- if (*p == '\0') {
- cdcomppath = NULL;
- } else {
- *p++ = '\0';
- cdcomppath = p;
- }
- return start;
-}
-
-
-
-/*
- * Update curdir (the name of the current directory) in response to a
- * cd command. We also call hashcd to let the routines in exec.c know
- * that the current directory has changed.
- */
-
-STATIC void
-updatepwd(const char *dir)
-{
- char *new;
- char *p;
-
- hashcd(); /* update command hash table */
-
- /*
- * If our argument is NULL, we don't know the current directory
- * any more because we traversed a symbolic link or something
- * we couldn't stat().
- */
- if (dir == NULL || curdir == NULL) {
- if (prevdir)
- ckfree(prevdir);
- INTOFF;
- prevdir = curdir;
- curdir = NULL;
- getpwd(1);
- INTON;
- if (curdir) {
- setvar("OLDPWD", prevdir, VEXPORT);
- setvar("PWD", curdir, VEXPORT);
- } else
- unsetvar("PWD", 0);
- return;
- }
- cdcomppath = stalloc(strlen(dir) + 1);
- scopy(dir, cdcomppath);
- STARTSTACKSTR(new);
- if (*dir != '/') {
- p = curdir;
- while (*p)
- STPUTC(*p++, new);
- if (p[-1] == '/')
- STUNPUTC(new);
- }
- while ((p = getcomponent()) != NULL) {
- if (equal(p, "..")) {
- while (new > stackblock() && (STUNPUTC(new), *new) != '/');
- } else if (*p != '\0' && ! equal(p, ".")) {
- STPUTC('/', new);
- while (*p)
- STPUTC(*p++, new);
- }
- }
- if (new == stackblock())
- STPUTC('/', new);
- STACKSTRNUL(new);
- INTOFF;
- if (prevdir)
- ckfree(prevdir);
- prevdir = curdir;
- curdir = savestr(stackblock());
- setvar("OLDPWD", prevdir, VEXPORT);
- setvar("PWD", curdir, VEXPORT);
- INTON;
-}
-
-/*
- * Posix says the default should be 'pwd -L' (as below), however
- * the 'cd' command (above) does something much nearer to the
- * posix 'cd -P' (not the posix default of 'cd -L').
- * If 'cd' is changed to support -P/L then the default here
- * needs to be revisited if the historic behaviour is to be kept.
- */
-
-int
-pwdcmd(int argc, char **argv)
-{
- int i;
- char opt = 'L';
-
- while ((i = nextopt("LP")) != '\0')
- opt = i;
- if (*argptr)
- error("unexpected argument");
-
- if (opt == 'L')
- getpwd(0);
- else
- find_curdir(0);
-
- setvar("OLDPWD", prevdir, VEXPORT);
- setvar("PWD", curdir, VEXPORT);
- out1str(curdir);
- out1c('\n');
- return 0;
-}
-
-
-
-void
-initpwd(void)
-{
- getpwd(1);
- if (curdir)
- setvar("PWD", curdir, VEXPORT);
- else
- sh_warnx("Cannot determine current working directory");
-}
-
-#define MAXPWD 256
-
-/*
- * Find out what the current directory is. If we already know the current
- * directory, this routine returns immediately.
- */
-void
-getpwd(int noerror)
-{
- char *pwd;
- struct stat stdot, stpwd;
- static int first = 1;
-
- if (curdir)
- return;
-
- if (first) {
- first = 0;
- pwd = getenv("PWD");
- if (pwd && *pwd == '/' && stat(".", &stdot) != -1 &&
- stat(pwd, &stpwd) != -1 &&
- stdot.st_dev == stpwd.st_dev &&
- stdot.st_ino == stpwd.st_ino) {
- curdir = savestr(pwd);
- return;
- }
- }
-
- find_curdir(noerror);
-
- return;
-}
-
-STATIC void
-find_curdir(int noerror)
-{
- int i;
- char *pwd;
-
- /*
- * Things are a bit complicated here; we could have just used
- * getcwd, but traditionally getcwd is implemented using popen
- * to /bin/pwd. This creates a problem for us, since we cannot
- * keep track of the job if it is being ran behind our backs.
- * So we re-implement getcwd(), and we suppress interrupts
- * throughout the process. This is not completely safe, since
- * the user can still break out of it by killing the pwd program.
- * We still try to use getcwd for systems that we know have a
- * c implementation of getcwd, that does not open a pipe to
- * /bin/pwd.
- */
-#if defined(__NetBSD__) || defined(__SVR4)
-
- for (i = MAXPWD;; i *= 2) {
- pwd = stalloc(i);
- if (getcwd(pwd, i) != NULL) {
- curdir = savestr(pwd);
- stunalloc(pwd);
- return;
- }
- stunalloc(pwd);
- if (errno == ERANGE)
- continue;
- if (!noerror)
- error("getcwd() failed: %s", strerror(errno));
- return;
- }
-#else
- {
- char *p;
- int status;
- struct job *jp;
- int pip[2];
-
- pwd = stalloc(MAXPWD);
- INTOFF;
- if (pipe(pip) < 0)
- error("Pipe call failed");
- jp = makejob(NULL, 1);
- if (forkshell(jp, NULL, FORK_NOJOB) == 0) {
- (void) close(pip[0]);
- movefd(pip[1], 1);
- (void) execl("/bin/pwd", "pwd", (char *)0);
- error("Cannot exec /bin/pwd");
- }
- (void) close(pip[1]);
- pip[1] = -1;
- p = pwd;
- while ((i = read(pip[0], p, pwd + MAXPWD - p)) > 0
- || (i == -1 && errno == EINTR)) {
- if (i > 0)
- p += i;
- }
- (void) close(pip[0]);
- pip[0] = -1;
- status = waitforjob(jp);
- if (status != 0)
- error((char *)0);
- if (i < 0 || p == pwd || p[-1] != '\n') {
- if (noerror) {
- INTON;
- return;
- }
- error("pwd command failed");
- }
- p[-1] = '\0';
- INTON;
- curdir = savestr(pwd);
- stunalloc(pwd);
- return;
- }
-#endif
-}
diff --git a/bin/sh/cd.h b/bin/sh/cd.h
deleted file mode 100644
index 7600955..0000000
--- a/bin/sh/cd.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/* $NetBSD: cd.h,v 1.6 2011/06/18 21:18:46 christos Exp $ */
-
-/*-
- * Copyright (c) 1995
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 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.
- *
- */
-
-void initpwd(void);
-void getpwd(int);
diff --git a/bin/sh/error.c b/bin/sh/error.c
deleted file mode 100644
index db42926..0000000
--- a/bin/sh/error.c
+++ /dev/null
@@ -1,378 +0,0 @@
-/* $NetBSD: error.c,v 1.42 2019/01/21 14:29:12 kre Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- */
-
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)error.c 8.2 (Berkeley) 5/4/95";
-#else
-__RCSID("$NetBSD: error.c,v 1.42 2019/01/21 14:29:12 kre Exp $");
-#endif
-#endif /* not lint */
-
-/*
- * Errors and exceptions.
- */
-
-#include <signal.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "shell.h"
-#include "eval.h" /* for commandname */
-#include "main.h"
-#include "options.h"
-#include "output.h"
-#include "error.h"
-#include "show.h"
-
-
-/*
- * Code to handle exceptions in C.
- */
-
-struct jmploc *handler;
-int exception;
-volatile int suppressint;
-volatile int intpending;
-
-
-static void exverror(int, const char *, va_list) __dead;
-
-/*
- * Called to raise an exception. Since C doesn't include exceptions, we
- * just do a longjmp to the exception handler. The type of exception is
- * stored in the global variable "exception".
- */
-
-void
-exraise(int e)
-{
- CTRACE(DBG_ERRS, ("exraise(%d)\n", e));
- if (handler == NULL)
- abort();
- exception = e;
- longjmp(handler->loc, 1);
-}
-
-
-/*
- * Called from trap.c when a SIGINT is received. (If the user specifies
- * that SIGINT is to be trapped or ignored using the trap builtin, then
- * this routine is not called.) Suppressint is nonzero when interrupts
- * are held using the INTOFF macro. The call to _exit is necessary because
- * there is a short period after a fork before the signal handlers are
- * set to the appropriate value for the child. (The test for iflag is
- * just defensive programming.)
- */
-
-void
-onint(void)
-{
- sigset_t nsigset;
-
- if (suppressint) {
- intpending = 1;
- return;
- }
- intpending = 0;
- sigemptyset(&nsigset);
- sigprocmask(SIG_SETMASK, &nsigset, NULL);
- if (rootshell && iflag)
- exraise(EXINT);
- else {
- signal(SIGINT, SIG_DFL);
- raise(SIGINT);
- }
- /* NOTREACHED */
-}
-
-static __printflike(2, 0) void
-exvwarning(int sv_errno, const char *msg, va_list ap)
-{
- /* Partially emulate line buffered output so that:
- * printf '%d\n' 1 a 2
- * and
- * printf '%d %d %d\n' 1 a 2
- * both generate sensible text when stdout and stderr are merged.
- */
- if (output.buf != NULL && output.nextc != output.buf &&
- output.nextc[-1] == '\n')
- flushout(&output);
- if (commandname)
- outfmt(&errout, "%s: ", commandname);
- else
- outfmt(&errout, "%s: ", getprogname());
- if (msg != NULL) {
- doformat(&errout, msg, ap);
- if (sv_errno >= 0)
- outfmt(&errout, ": ");
- }
- if (sv_errno >= 0)
- outfmt(&errout, "%s", strerror(sv_errno));
- out2c('\n');
- flushout(&errout);
-}
-
-/*
- * Exverror is called to raise the error exception. If the second argument
- * is not NULL then error prints an error message using printf style
- * formatting. It then raises the error exception.
- */
-static __printflike(2, 0) void
-exverror(int cond, const char *msg, va_list ap)
-{
- CLEAR_PENDING_INT;
- INTOFF;
-
-#ifdef DEBUG
- if (msg) {
- CTRACE(DBG_ERRS, ("exverror(%d, \"", cond));
- CTRACEV(DBG_ERRS, (msg, ap));
- CTRACE(DBG_ERRS, ("\") pid=%d\n", getpid()));
- } else
- CTRACE(DBG_ERRS, ("exverror(%d, NULL) pid=%d\n", cond,
- getpid()));
-#endif
- if (msg)
- exvwarning(-1, msg, ap);
-
- flushall();
- exraise(cond);
- /* NOTREACHED */
-}
-
-
-void
-error(const char *msg, ...)
-{
- va_list ap;
-
- /*
- * On error, we certainly never want exit(0)...
- */
- if (exerrno == 0)
- exerrno = 1;
- va_start(ap, msg);
- exverror(EXERROR, msg, ap);
- /* NOTREACHED */
- va_end(ap);
-}
-
-
-void
-exerror(int cond, const char *msg, ...)
-{
- va_list ap;
-
- va_start(ap, msg);
- exverror(cond, msg, ap);
- /* NOTREACHED */
- va_end(ap);
-}
-
-/*
- * error/warning routines for external builtins
- */
-
-void
-sh_exit(int rval)
-{
- exerrno = rval & 255;
- exraise(EXEXEC);
-}
-
-void
-sh_err(int status, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- exvwarning(errno, fmt, ap);
- va_end(ap);
- sh_exit(status);
-}
-
-void
-sh_verr(int status, const char *fmt, va_list ap)
-{
- exvwarning(errno, fmt, ap);
- sh_exit(status);
-}
-
-void
-sh_errx(int status, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- exvwarning(-1, fmt, ap);
- va_end(ap);
- sh_exit(status);
-}
-
-void
-sh_verrx(int status, const char *fmt, va_list ap)
-{
- exvwarning(-1, fmt, ap);
- sh_exit(status);
-}
-
-void
-sh_warn(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- exvwarning(errno, fmt, ap);
- va_end(ap);
-}
-
-void
-sh_vwarn(const char *fmt, va_list ap)
-{
- exvwarning(errno, fmt, ap);
-}
-
-void
-sh_warnx(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- exvwarning(-1, fmt, ap);
- va_end(ap);
-}
-
-void
-sh_vwarnx(const char *fmt, va_list ap)
-{
- exvwarning(-1, fmt, ap);
-}
-
-
-/*
- * Table of error messages.
- */
-
-struct errname {
- short errcode; /* error number */
- short action; /* operation which encountered the error */
- const char *msg; /* text describing the error */
-};
-
-
-#define ALL (E_OPEN|E_CREAT|E_EXEC)
-
-STATIC const struct errname errormsg[] = {
- { EINTR, ALL, "interrupted" },
- { EACCES, ALL, "permission denied" },
- { EIO, ALL, "I/O error" },
- { EEXIST, ALL, "file exists" },
- { ENOENT, E_OPEN, "no such file" },
- { ENOENT, E_CREAT,"directory nonexistent" },
- { ENOENT, E_EXEC, "not found" },
- { ENOTDIR, E_OPEN, "no such file" },
- { ENOTDIR, E_CREAT,"directory nonexistent" },
- { ENOTDIR, E_EXEC, "not found" },
- { EISDIR, ALL, "is a directory" },
-#ifdef EMFILE
- { EMFILE, ALL, "too many open files" },
-#endif
- { ENFILE, ALL, "file table overflow" },
- { ENOSPC, ALL, "file system full" },
-#ifdef EDQUOT
- { EDQUOT, ALL, "disk quota exceeded" },
-#endif
-#ifdef ENOSR
- { ENOSR, ALL, "no streams resources" },
-#endif
- { ENXIO, ALL, "no such device or address" },
- { EROFS, ALL, "read-only file system" },
- { ETXTBSY, ALL, "text busy" },
-#ifdef EAGAIN
- { EAGAIN, E_EXEC, "not enough memory" },
-#endif
- { ENOMEM, ALL, "not enough memory" },
-#ifdef ENOLINK
- { ENOLINK, ALL, "remote access failed" },
-#endif
-#ifdef EMULTIHOP
- { EMULTIHOP, ALL, "remote access failed" },
-#endif
-#ifdef ECOMM
- { ECOMM, ALL, "remote access failed" },
-#endif
-#ifdef ESTALE
- { ESTALE, ALL, "remote access failed" },
-#endif
-#ifdef ETIMEDOUT
- { ETIMEDOUT, ALL, "remote access failed" },
-#endif
-#ifdef ELOOP
- { ELOOP, ALL, "symbolic link loop" },
-#endif
-#ifdef ENAMETOOLONG
- { ENAMETOOLONG, ALL, "file name too long" },
-#endif
- { E2BIG, E_EXEC, "argument list too long" },
-#ifdef ELIBACC
- { ELIBACC, E_EXEC, "shared library missing" },
-#endif
- { 0, 0, NULL },
-};
-
-
-/*
- * Return a string describing an error. The returned string may be a
- * pointer to a static buffer that will be overwritten on the next call.
- * Action describes the operation that got the error.
- */
-
-const char *
-errmsg(int e, int action)
-{
- struct errname const *ep;
- static char buf[12];
-
- for (ep = errormsg ; ep->errcode ; ep++) {
- if (ep->errcode == e && (ep->action & action) != 0)
- return ep->msg;
- }
- fmtstr(buf, sizeof buf, "error %d", e);
- return buf;
-}
diff --git a/bin/sh/error.h b/bin/sh/error.h
deleted file mode 100644
index 8dcf737..0000000
--- a/bin/sh/error.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/* $NetBSD: error.h,v 1.21 2018/08/19 23:50:27 kre Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- *
- * @(#)error.h 8.2 (Berkeley) 5/4/95
- */
-
-#include <stdarg.h>
-
-/*
- * Types of operations (passed to the errmsg routine).
- */
-
-#define E_OPEN 01 /* opening a file */
-#define E_CREAT 02 /* creating a file */
-#define E_EXEC 04 /* executing a program */
-
-
-/*
- * We enclose jmp_buf in a structure so that we can declare pointers to
- * jump locations. The global variable handler contains the location to
- * jump to when an exception occurs, and the global variable exception
- * contains a code identifying the exeception. To implement nested
- * exception handlers, the user should save the value of handler on entry
- * to an inner scope, set handler to point to a jmploc structure for the
- * inner scope, and restore handler on exit from the scope.
- */
-
-#include <setjmp.h>
-
-struct jmploc {
- jmp_buf loc;
-};
-
-extern struct jmploc *handler;
-extern int exception;
-extern int exerrno; /* error for EXEXEC */
-
-/* exceptions */
-#define EXINT 0 /* SIGINT received */
-#define EXERROR 1 /* a generic error */
-#define EXSHELLPROC 2 /* execute a shell procedure */
-#define EXEXEC 3 /* command execution failed */
-#define EXEXIT 4 /* shell wants to exit(exitstatus) */
-
-
-/*
- * These macros allow the user to suspend the handling of interrupt signals
- * over a period of time. This is similar to SIGHOLD to or sigblock, but
- * much more efficient and portable. (But hacking the kernel is so much
- * more fun than worrying about efficiency and portability. :-))
- */
-
-extern volatile int suppressint;
-extern volatile int intpending;
-
-#define INTOFF suppressint++
-#define INTON do { if (--suppressint == 0 && intpending) onint(); } while (0)
-#define FORCEINTON do { suppressint = 0; if (intpending) onint(); } while (0)
-#define CLEAR_PENDING_INT (intpending = 0)
-#define int_pending() intpending
-
-#if ! defined(SHELL_BUILTIN)
-void exraise(int) __dead;
-void onint(void);
-void error(const char *, ...) __dead __printflike(1, 2);
-void exerror(int, const char *, ...) __dead __printflike(2, 3);
-const char *errmsg(int, int);
-#endif /* ! SHELL_BUILTIN */
-
-void sh_err(int, const char *, ...) __dead __printflike(2, 3);
-void sh_verr(int, const char *, va_list) __dead __printflike(2, 0);
-void sh_errx(int, const char *, ...) __dead __printflike(2, 3);
-void sh_verrx(int, const char *, va_list) __dead __printflike(2, 0);
-void sh_warn(const char *, ...) __printflike(1, 2);
-void sh_vwarn(const char *, va_list) __printflike(1, 0);
-void sh_warnx(const char *, ...) __printflike(1, 2);
-void sh_vwarnx(const char *, va_list) __printflike(1, 0);
-
-void sh_exit(int) __dead;
-
-
-/*
- * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
- * so we use _setjmp instead.
- */
-
-#if defined(BSD) && !defined(__SVR4)
-#define setjmp(jmploc) _setjmp(jmploc)
-#define longjmp(jmploc, val) _longjmp(jmploc, val)
-#endif
diff --git a/bin/sh/eval.c b/bin/sh/eval.c
deleted file mode 100644
index 2bda702..0000000
--- a/bin/sh/eval.c
+++ /dev/null
@@ -1,1680 +0,0 @@
-/* $NetBSD: eval.c,v 1.170 2019/01/21 14:18:59 kre Exp $ */
-
-/*-
- * Copyright (c) 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- */
-
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)eval.c 8.9 (Berkeley) 6/8/95";
-#else
-__RCSID("$NetBSD: eval.c,v 1.170 2019/01/21 14:18:59 kre Exp $");
-#endif
-#endif /* not lint */
-
-#include <stdbool.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <limits.h>
-#include <unistd.h>
-#include <sys/fcntl.h>
-#include <sys/stat.h>
-#include <sys/times.h>
-#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/sysctl.h>
-
-/*
- * Evaluate a command.
- */
-
-#include "shell.h"
-#include "nodes.h"
-#include "syntax.h"
-#include "expand.h"
-#include "parser.h"
-#include "jobs.h"
-#include "eval.h"
-#include "builtins.h"
-#include "options.h"
-#include "exec.h"
-#include "redir.h"
-#include "input.h"
-#include "output.h"
-#include "trap.h"
-#include "var.h"
-#include "memalloc.h"
-#include "error.h"
-#include "show.h"
-#include "mystring.h"
-#include "main.h"
-#ifndef SMALL
-#include "nodenames.h"
-#include "myhistedit.h"
-#endif
-
-
-STATIC struct skipsave s_k_i_p;
-#define evalskip (s_k_i_p.state)
-#define skipcount (s_k_i_p.count)
-
-STATIC int loopnest; /* current loop nesting level */
-STATIC int funcnest; /* depth of function calls */
-STATIC int builtin_flags; /* evalcommand flags for builtins */
-/*
- * Base function nesting level inside a dot command. Set to 0 initially
- * and to (funcnest + 1) before every dot command to enable
- * 1) detection of being in a file sourced by a dot command and
- * 2) counting of function nesting in that file for the implementation
- * of the return command.
- * The value is reset to its previous value after the dot command.
- */
-STATIC int dot_funcnest;
-
-
-const char *commandname;
-struct strlist *cmdenviron;
-int exitstatus; /* exit status of last command */
-int back_exitstatus; /* exit status of backquoted command */
-
-
-STATIC void evalloop(union node *, int);
-STATIC void evalfor(union node *, int);
-STATIC void evalcase(union node *, int);
-STATIC void evalsubshell(union node *, int);
-STATIC void expredir(union node *);
-STATIC void evalredir(union node *, int);
-STATIC void evalpipe(union node *);
-STATIC void evalcommand(union node *, int, struct backcmd *);
-STATIC void prehash(union node *);
-
-STATIC char *find_dot_file(char *);
-
-/*
- * Called to reset things after an exception.
- */
-
-#ifdef mkinit
-INCLUDE "eval.h"
-
-RESET {
- reset_eval();
-}
-
-SHELLPROC {
- exitstatus = 0;
-}
-#endif
-
-void
-reset_eval(void)
-{
- evalskip = SKIPNONE;
- dot_funcnest = 0;
- loopnest = 0;
- funcnest = 0;
-}
-
-static int
-sh_pipe(int fds[2])
-{
- int nfd;
-
- if (pipe(fds))
- return -1;
-
- if (fds[0] < 3) {
- nfd = fcntl(fds[0], F_DUPFD, 3);
- if (nfd != -1) {
- close(fds[0]);
- fds[0] = nfd;
- }
- }
-
- if (fds[1] < 3) {
- nfd = fcntl(fds[1], F_DUPFD, 3);
- if (nfd != -1) {
- close(fds[1]);
- fds[1] = nfd;
- }
- }
- return 0;
-}
-
-
-/*
- * The eval commmand.
- */
-
-int
-evalcmd(int argc, char **argv)
-{
- char *p;
- char *concat;
- char **ap;
-
- if (argc > 1) {
- p = argv[1];
- if (argc > 2) {
- STARTSTACKSTR(concat);
- ap = argv + 2;
- for (;;) {
- while (*p)
- STPUTC(*p++, concat);
- if ((p = *ap++) == NULL)
- break;
- STPUTC(' ', concat);
- }
- STPUTC('\0', concat);
- p = grabstackstr(concat);
- }
- evalstring(p, builtin_flags & EV_TESTED);
- } else
- exitstatus = 0;
- return exitstatus;
-}
-
-
-/*
- * Execute a command or commands contained in a string.
- */
-
-void
-evalstring(char *s, int flag)
-{
- union node *n;
- struct stackmark smark;
- int last;
- int any;
-
- last = flag & EV_EXIT;
- flag &= ~EV_EXIT;
-
- setstackmark(&smark);
- setinputstring(s, 1, line_number);
-
- any = 0; /* to determine if exitstatus will have been set */
- while ((n = parsecmd(0)) != NEOF) {
- XTRACE(DBG_EVAL, ("evalstring: "), showtree(n));
- if (n && nflag == 0) {
- if (last && at_eof())
- evaltree(n, flag | EV_EXIT);
- else
- evaltree(n, flag);
- any = 1;
- if (evalskip)
- break;
- }
- rststackmark(&smark);
- }
- popfile();
- popstackmark(&smark);
- if (!any)
- exitstatus = 0;
- if (last)
- exraise(EXEXIT);
-}
-
-
-
-/*
- * Evaluate a parse tree. The value is left in the global variable
- * exitstatus.
- */
-
-void
-evaltree(union node *n, int flags)
-{
- bool do_etest;
- int sflags = flags & ~EV_EXIT;
- union node *next;
- struct stackmark smark;
-
- do_etest = false;
- if (n == NULL || nflag) {
- VTRACE(DBG_EVAL, ("evaltree(%s) called\n",
- n == NULL ? "NULL" : "-n"));
- if (nflag == 0)
- exitstatus = 0;
- goto out2;
- }
-
- setstackmark(&smark);
- do {
-#ifndef SMALL
- displayhist = 1; /* show history substitutions done with fc */
-#endif
- next = NULL;
- CTRACE(DBG_EVAL, ("pid %d, evaltree(%p: %s(%d), %#x) called\n",
- getpid(), n, NODETYPENAME(n->type), n->type, flags));
- if (n->type != NCMD && traps_invalid)
- free_traps();
- switch (n->type) {
- case NSEMI:
- evaltree(n->nbinary.ch1, sflags);
- if (nflag || evalskip)
- goto out1;
- next = n->nbinary.ch2;
- break;
- case NAND:
- evaltree(n->nbinary.ch1, EV_TESTED);
- if (nflag || evalskip || exitstatus != 0)
- goto out1;
- next = n->nbinary.ch2;
- break;
- case NOR:
- evaltree(n->nbinary.ch1, EV_TESTED);
- if (nflag || evalskip || exitstatus == 0)
- goto out1;
- next = n->nbinary.ch2;
- break;
- case NREDIR:
- evalredir(n, flags);
- break;
- case NSUBSHELL:
- evalsubshell(n, flags);
- do_etest = !(flags & EV_TESTED);
- break;
- case NBACKGND:
- evalsubshell(n, flags);
- break;
- case NIF: {
- evaltree(n->nif.test, EV_TESTED);
- if (nflag || evalskip)
- goto out1;
- if (exitstatus == 0)
- next = n->nif.ifpart;
- else if (n->nif.elsepart)
- next = n->nif.elsepart;
- else
- exitstatus = 0;
- break;
- }
- case NWHILE:
- case NUNTIL:
- evalloop(n, sflags);
- break;
- case NFOR:
- evalfor(n, sflags);
- break;
- case NCASE:
- evalcase(n, sflags);
- break;
- case NDEFUN:
- CTRACE(DBG_EVAL, ("Defining fn %s @%d%s\n",
- n->narg.text, n->narg.lineno,
- fnline1 ? " LINENO=1" : ""));
- defun(n->narg.text, n->narg.next, n->narg.lineno);
- exitstatus = 0;
- break;
- case NNOT:
- evaltree(n->nnot.com, EV_TESTED);
- exitstatus = !exitstatus;
- break;
- case NDNOT:
- evaltree(n->nnot.com, EV_TESTED);
- if (exitstatus != 0)
- exitstatus = 1;
- break;
- case NPIPE:
- evalpipe(n);
- do_etest = !(flags & EV_TESTED);
- break;
- case NCMD:
- evalcommand(n, flags, NULL);
- do_etest = !(flags & EV_TESTED);
- break;
- default:
-#ifdef NODETYPENAME
- out1fmt("Node type = %d(%s)\n",
- n->type, NODETYPENAME(n->type));
-#else
- out1fmt("Node type = %d\n", n->type);
-#endif
- flushout(&output);
- break;
- }
- n = next;
- rststackmark(&smark);
- } while(n != NULL);
- out1:
- popstackmark(&smark);
- out2:
- if (pendingsigs)
- dotrap();
- if (eflag && exitstatus != 0 && do_etest)
- exitshell(exitstatus);
- if (flags & EV_EXIT)
- exraise(EXEXIT);
-}
-
-
-STATIC void
-evalloop(union node *n, int flags)
-{
- int status;
-
- loopnest++;
- status = 0;
-
- CTRACE(DBG_EVAL, ("evalloop %s:", NODETYPENAME(n->type)));
- VXTRACE(DBG_EVAL, (" "), showtree(n->nbinary.ch1));
- VXTRACE(DBG_EVAL, ("evalloop do: "), showtree(n->nbinary.ch2));
- VTRACE(DBG_EVAL, ("evalloop done\n"));
- CTRACE(DBG_EVAL, ("\n"));
-
- for (;;) {
- evaltree(n->nbinary.ch1, EV_TESTED);
- if (nflag)
- break;
- if (evalskip) {
- skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
- evalskip = SKIPNONE;
- continue;
- }
- if (evalskip == SKIPBREAK && --skipcount <= 0)
- evalskip = SKIPNONE;
- break;
- }
- if (n->type == NWHILE) {
- if (exitstatus != 0)
- break;
- } else {
- if (exitstatus == 0)
- break;
- }
- evaltree(n->nbinary.ch2, flags & EV_TESTED);
- status = exitstatus;
- if (evalskip)
- goto skipping;
- }
- loopnest--;
- exitstatus = status;
-}
-
-
-
-STATIC void
-evalfor(union node *n, int flags)
-{
- struct arglist arglist;
- union node *argp;
- struct strlist *sp;
- struct stackmark smark;
- int status;
-
- status = nflag ? exitstatus : 0;
-
- setstackmark(&smark);
- arglist.lastp = &arglist.list;
- for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
- expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
- if (evalskip)
- goto out;
- }
- *arglist.lastp = NULL;
-
- loopnest++;
- for (sp = arglist.list ; sp ; sp = sp->next) {
- if (xflag) {
- outxstr(expandstr(ps4val(), line_number));
- outxstr("for ");
- outxstr(n->nfor.var);
- outxc('=');
- outxshstr(sp->text);
- outxc('\n');
- flushout(outx);
- }
-
- setvar(n->nfor.var, sp->text, 0);
- evaltree(n->nfor.body, flags & EV_TESTED);
- status = exitstatus;
- if (nflag)
- break;
- if (evalskip) {
- if (evalskip == SKIPCONT && --skipcount <= 0) {
- evalskip = SKIPNONE;
- continue;
- }
- if (evalskip == SKIPBREAK && --skipcount <= 0)
- evalskip = SKIPNONE;
- break;
- }
- }
- loopnest--;
- exitstatus = status;
- out:
- popstackmark(&smark);
-}
-
-
-
-STATIC void
-evalcase(union node *n, int flags)
-{
- union node *cp, *ncp;
- union node *patp;
- struct arglist arglist;
- struct stackmark smark;
- int status = 0;
-
- setstackmark(&smark);
- arglist.lastp = &arglist.list;
- line_number = n->ncase.lineno;
- expandarg(n->ncase.expr, &arglist, EXP_TILDE);
- for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
- for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
- line_number = patp->narg.lineno;
- if (casematch(patp, arglist.list->text)) {
- while (cp != NULL && evalskip == 0 &&
- nflag == 0) {
- if (cp->type == NCLISTCONT)
- ncp = cp->nclist.next;
- else
- ncp = NULL;
- line_number = cp->nclist.lineno;
- evaltree(cp->nclist.body, flags);
- status = exitstatus;
- cp = ncp;
- }
- goto out;
- }
- }
- }
- out:
- exitstatus = status;
- popstackmark(&smark);
-}
-
-
-
-/*
- * Kick off a subshell to evaluate a tree.
- */
-
-STATIC void
-evalsubshell(union node *n, int flags)
-{
- struct job *jp= NULL;
- int backgnd = (n->type == NBACKGND);
-
- expredir(n->nredir.redirect);
- if (xflag && n->nredir.redirect) {
- union node *rn;
-
- outxstr(expandstr(ps4val(), line_number));
- outxstr("using redirections:");
- for (rn = n->nredir.redirect; rn; rn = rn->nfile.next)
- (void) outredir(outx, rn, ' ');
- outxstr(" do subshell ("/*)*/);
- if (backgnd)
- outxstr(/*(*/") &");
- outxc('\n');
- flushout(outx);
- }
- if ((!backgnd && flags & EV_EXIT && !have_traps()) ||
- forkshell(jp = makejob(n, 1), n, backgnd?FORK_BG:FORK_FG) == 0) {
- INTON;
- if (backgnd)
- flags &=~ EV_TESTED;
- redirect(n->nredir.redirect, REDIR_KEEP);
- evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
- } else if (!backgnd) {
- INTOFF;
- exitstatus = waitforjob(jp);
- INTON;
- } else
- exitstatus = 0;
-
- if (!backgnd && xflag && n->nredir.redirect) {
- outxstr(expandstr(ps4val(), line_number));
- outxstr(/*(*/") done subshell\n");
- flushout(outx);
- }
-}
-
-
-
-/*
- * Compute the names of the files in a redirection list.
- */
-
-STATIC void
-expredir(union node *n)
-{
- union node *redir;
-
- for (redir = n ; redir ; redir = redir->nfile.next) {
- struct arglist fn;
-
- fn.lastp = &fn.list;
- switch (redir->type) {
- case NFROMTO:
- case NFROM:
- case NTO:
- case NCLOBBER:
- case NAPPEND:
- expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
- redir->nfile.expfname = fn.list->text;
- break;
- case NFROMFD:
- case NTOFD:
- if (redir->ndup.vname) {
- expandarg(redir->ndup.vname, &fn, EXP_TILDE | EXP_REDIR);
- fixredir(redir, fn.list->text, 1);
- }
- break;
- }
- }
-}
-
-/*
- * Perform redirections for a compound command, and then do it (and restore)
- */
-STATIC void
-evalredir(union node *n, int flags)
-{
- struct jmploc jmploc;
- struct jmploc * const savehandler = handler;
- volatile int in_redirect = 1;
- const char * volatile PS4 = NULL;
-
- expredir(n->nredir.redirect);
-
- if (xflag && n->nredir.redirect) {
- union node *rn;
-
- outxstr(PS4 = expandstr(ps4val(), line_number));
- outxstr("using redirections:");
- for (rn = n->nredir.redirect; rn != NULL; rn = rn->nfile.next)
- (void) outredir(outx, rn, ' ');
- outxstr(" do {\n"); /* } */
- flushout(outx);
- }
-
- if (setjmp(jmploc.loc)) {
- int e;
-
- handler = savehandler;
- e = exception;
- popredir();
- if (PS4 != NULL) {
- outxstr(PS4);
- /* { */ outxstr("} failed\n");
- flushout(outx);
- }
- if (e == EXERROR || e == EXEXEC) {
- if (in_redirect) {
- exitstatus = 2;
- return;
- }
- }
- longjmp(handler->loc, 1);
- } else {
- INTOFF;
- handler = &jmploc;
- redirect(n->nredir.redirect, REDIR_PUSH | REDIR_KEEP);
- in_redirect = 0;
- INTON;
- evaltree(n->nredir.n, flags);
- }
- INTOFF;
- handler = savehandler;
- popredir();
- INTON;
-
- if (PS4 != NULL) {
- outxstr(PS4);
- /* { */ outxstr("} done\n");
- flushout(outx);
- }
-}
-
-
-/*
- * Evaluate a pipeline. All the processes in the pipeline are children
- * of the process creating the pipeline. (This differs from some versions
- * of the shell, which make the last process in a pipeline the parent
- * of all the rest.)
- */
-
-STATIC void
-evalpipe(union node *n)
-{
- struct job *jp;
- struct nodelist *lp;
- int pipelen;
- int prevfd;
- int pip[2];
-
- CTRACE(DBG_EVAL, ("evalpipe(%p) called\n", n));
- pipelen = 0;
- for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
- pipelen++;
- INTOFF;
- jp = makejob(n, pipelen);
- prevfd = -1;
- for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
- prehash(lp->n);
- pip[1] = -1;
- if (lp->next) {
- if (sh_pipe(pip) < 0) {
- if (prevfd >= 0)
- close(prevfd);
- error("Pipe call failed: %s", strerror(errno));
- }
- }
- if (forkshell(jp, lp->n,
- n->npipe.backgnd ? FORK_BG : FORK_FG) == 0) {
- INTON;
- if (prevfd > 0)
- movefd(prevfd, 0);
- if (pip[1] >= 0) {
- close(pip[0]);
- movefd(pip[1], 1);
- }
- evaltree(lp->n, EV_EXIT);
- }
- if (prevfd >= 0)
- close(prevfd);
- prevfd = pip[0];
- close(pip[1]);
- }
- if (n->npipe.backgnd == 0) {
- INTOFF;
- exitstatus = waitforjob(jp);
- CTRACE(DBG_EVAL, ("evalpipe: job done exit status %d\n",
- exitstatus));
- INTON;
- } else
- exitstatus = 0;
- INTON;
-}
-
-
-
-/*
- * Execute a command inside back quotes. If it's a builtin command, we
- * want to save its output in a block obtained from malloc. Otherwise
- * we fork off a subprocess and get the output of the command via a pipe.
- * Should be called with interrupts off.
- */
-
-void
-evalbackcmd(union node *n, struct backcmd *result)
-{
- int pip[2];
- struct job *jp;
- struct stackmark smark; /* unnecessary (because we fork) */
-
- result->fd = -1;
- result->buf = NULL;
- result->nleft = 0;
- result->jp = NULL;
-
- if (nflag || n == NULL)
- goto out;
-
- setstackmark(&smark);
-
-#ifdef notyet
- /*
- * For now we disable executing builtins in the same
- * context as the shell, because we are not keeping
- * enough state to recover from changes that are
- * supposed only to affect subshells. eg. echo "`cd /`"
- */
- if (n->type == NCMD) {
- exitstatus = oexitstatus; /* XXX o... no longer exists */
- evalcommand(n, EV_BACKCMD, result);
- } else
-#endif
- {
- INTOFF;
- if (sh_pipe(pip) < 0)
- error("Pipe call failed");
- jp = makejob(n, 1);
- if (forkshell(jp, n, FORK_NOJOB) == 0) {
- FORCEINTON;
- close(pip[0]);
- movefd(pip[1], 1);
- eflag = 0;
- evaltree(n, EV_EXIT);
- /* NOTREACHED */
- }
- close(pip[1]);
- result->fd = pip[0];
- result->jp = jp;
- INTON;
- }
- popstackmark(&smark);
- out:
- CTRACE(DBG_EVAL, ("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
- result->fd, result->buf, result->nleft, result->jp));
-}
-
-const char *
-syspath(void)
-{
- static char *sys_path = NULL;
- static int mib[] = {CTL_USER, USER_CS_PATH};
- static char def_path[] = "PATH=/usr/bin:/bin:/usr/sbin:/sbin";
- size_t len;
-
- if (sys_path == NULL) {
- if (sysctl(mib, 2, 0, &len, 0, 0) != -1 &&
- (sys_path = ckmalloc(len + 5)) != NULL &&
- sysctl(mib, 2, sys_path + 5, &len, 0, 0) != -1) {
- memcpy(sys_path, "PATH=", 5);
- } else {
- ckfree(sys_path);
- /* something to keep things happy */
- sys_path = def_path;
- }
- }
- return sys_path;
-}
-
-static int
-parse_command_args(int argc, char **argv, int *use_syspath)
-{
- int sv_argc = argc;
- char *cp, c;
-
- *use_syspath = 0;
-
- for (;;) {
- argv++;
- if (--argc == 0)
- break;
- cp = *argv;
- if (*cp++ != '-')
- break;
- if (*cp == '-' && cp[1] == 0) {
- argv++;
- argc--;
- break;
- }
- while ((c = *cp++)) {
- switch (c) {
- case 'p':
- *use_syspath = 1;
- break;
- default:
- /* run 'typecmd' for other options */
- return 0;
- }
- }
- }
- return sv_argc - argc;
-}
-
-int vforked = 0;
-extern char *trap[];
-
-/*
- * Execute a simple command.
- */
-
-STATIC void
-evalcommand(union node *cmd, int flgs, struct backcmd *backcmd)
-{
- struct stackmark smark;
- union node *argp;
- struct arglist arglist;
- struct arglist varlist;
- volatile int flags = flgs;
- char ** volatile argv;
- volatile int argc;
- char **envp;
- int varflag;
- struct strlist *sp;
- volatile int mode;
- int pip[2];
- struct cmdentry cmdentry;
- struct job * volatile jp;
- struct jmploc jmploc;
- struct jmploc *volatile savehandler = NULL;
- const char *volatile savecmdname;
- volatile struct shparam saveparam;
- struct localvar *volatile savelocalvars;
- struct parsefile *volatile savetopfile;
- volatile int e;
- char * volatile lastarg;
- const char * volatile path = pathval();
- volatile int temp_path;
- const int savefuncline = funclinebase;
- const int savefuncabs = funclineabs;
- volatile int cmd_flags = 0;
-
- vforked = 0;
- /* First expand the arguments. */
- CTRACE(DBG_EVAL, ("evalcommand(%p, %d) called [%s]\n", cmd, flags,
- cmd->ncmd.args ? cmd->ncmd.args->narg.text : ""));
- setstackmark(&smark);
- back_exitstatus = 0;
-
- line_number = cmd->ncmd.lineno;
-
- arglist.lastp = &arglist.list;
- varflag = 1;
- /* Expand arguments, ignoring the initial 'name=value' ones */
- for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
- if (varflag && isassignment(argp->narg.text))
- continue;
- varflag = 0;
- line_number = argp->narg.lineno;
- expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
- }
- *arglist.lastp = NULL;
-
- expredir(cmd->ncmd.redirect);
-
- /* Now do the initial 'name=value' ones we skipped above */
- varlist.lastp = &varlist.list;
- for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
- line_number = argp->narg.lineno;
- if (!isassignment(argp->narg.text))
- break;
- expandarg(argp, &varlist, EXP_VARTILDE);
- }
- *varlist.lastp = NULL;
-
- argc = 0;
- for (sp = arglist.list ; sp ; sp = sp->next)
- argc++;
- argv = stalloc(sizeof (char *) * (argc + 1));
-
- for (sp = arglist.list ; sp ; sp = sp->next) {
- VTRACE(DBG_EVAL, ("evalcommand arg: %s\n", sp->text));
- *argv++ = sp->text;
- }
- *argv = NULL;
- lastarg = NULL;
- if (iflag && funcnest == 0 && argc > 0)
- lastarg = argv[-1];
- argv -= argc;
-
- /* Print the command if xflag is set. */
- if (xflag) {
- char sep = 0;
- union node *rn;
-
- outxstr(expandstr(ps4val(), line_number));
- for (sp = varlist.list ; sp ; sp = sp->next) {
- char *p;
-
- if (sep != 0)
- outxc(sep);
-
- /*
- * The "var=" part should not be quoted, regardless
- * of the value, or it would not represent an
- * assignment, but rather a command
- */
- p = strchr(sp->text, '=');
- if (p != NULL) {
- *p = '\0'; /*XXX*/
- outxshstr(sp->text);
- outxc('=');
- *p++ = '='; /*XXX*/
- } else
- p = sp->text;
- outxshstr(p);
- sep = ' ';
- }
- for (sp = arglist.list ; sp ; sp = sp->next) {
- if (sep != 0)
- outxc(sep);
- outxshstr(sp->text);
- sep = ' ';
- }
- for (rn = cmd->ncmd.redirect; rn; rn = rn->nfile.next)
- if (outredir(outx, rn, sep))
- sep = ' ';
- outxc('\n');
- flushout(outx);
- }
-
- /* Now locate the command. */
- if (argc == 0) {
- /*
- * the empty command begins as a normal builtin, and
- * remains that way while redirects are processed, then
- * will become special before we get to doing the
- * var assigns.
- */
- cmdentry.cmdtype = CMDBUILTIN;
- cmdentry.u.bltin = bltincmd;
- } else {
- static const char PATH[] = "PATH=";
-
- /*
- * Modify the command lookup path, if a PATH= assignment
- * is present
- */
- for (sp = varlist.list; sp; sp = sp->next)
- if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0)
- path = sp->text + sizeof(PATH) - 1;
-
- do {
- int argsused, use_syspath;
-
- find_command(argv[0], &cmdentry, cmd_flags, path);
-#if 0
- /*
- * This short circuits all of the processing that
- * should be done (including processing the
- * redirects), so just don't ...
- *
- * (eventually this whole #if'd block will vanish)
- */
- if (cmdentry.cmdtype == CMDUNKNOWN) {
- exitstatus = 127;
- flushout(&errout);
- goto out;
- }
-#endif
-
- /* implement the 'command' builtin here */
- if (cmdentry.cmdtype != CMDBUILTIN ||
- cmdentry.u.bltin != bltincmd)
- break;
- cmd_flags |= DO_NOFUNC;
- argsused = parse_command_args(argc, argv, &use_syspath);
- if (argsused == 0) {
- /* use 'type' builtin to display info */
- cmdentry.u.bltin = typecmd;
- break;
- }
- argc -= argsused;
- argv += argsused;
- if (use_syspath)
- path = syspath() + 5;
- } while (argc != 0);
- if (cmdentry.cmdtype == CMDSPLBLTIN && cmd_flags & DO_NOFUNC)
- /* posix mandates that 'command <splbltin>' act as if
- <splbltin> was a normal builtin */
- cmdentry.cmdtype = CMDBUILTIN;
- }
-
- /*
- * When traps are invalid, we permit the following:
- * trap
- * command trap
- * eval trap
- * command eval trap
- * eval command trap
- * without zapping the traps completely, in all other cases we do.
- *
- * The test here permits eval "anything" but when evalstring() comes
- * back here again, the "anything" will be validated.
- * This means we can actually do:
- * eval eval eval command eval eval command trap
- * as long as we end up with just "trap"
- *
- * We permit "command" by allowing CMDBUILTIN as well as CMDSPLBLTIN
- *
- * trapcmd() takes care of doing free_traps() if it is needed there.
- */
- if (traps_invalid &&
- ((cmdentry.cmdtype!=CMDSPLBLTIN && cmdentry.cmdtype!=CMDBUILTIN) ||
- (cmdentry.u.bltin != trapcmd && cmdentry.u.bltin != evalcmd)))
- free_traps();
-
- /* Fork off a child process if necessary. */
- if (cmd->ncmd.backgnd || (have_traps() && (flags & EV_EXIT) != 0)
- || ((cmdentry.cmdtype == CMDNORMAL || cmdentry.cmdtype == CMDUNKNOWN)
- && (flags & EV_EXIT) == 0)
- || ((flags & EV_BACKCMD) != 0 &&
- ((cmdentry.cmdtype != CMDBUILTIN && cmdentry.cmdtype != CMDSPLBLTIN)
- || cmdentry.u.bltin == dotcmd
- || cmdentry.u.bltin == evalcmd))) {
- INTOFF;
- jp = makejob(cmd, 1);
- mode = cmd->ncmd.backgnd;
- if (flags & EV_BACKCMD) {
- mode = FORK_NOJOB;
- if (sh_pipe(pip) < 0)
- error("Pipe call failed");
- }
-#ifdef DO_SHAREDVFORK
- /* It is essential that if DO_SHAREDVFORK is defined that the
- * child's address space is actually shared with the parent as
- * we rely on this.
- */
- if (usefork == 0 && cmdentry.cmdtype == CMDNORMAL) {
- pid_t pid;
- int serrno;
-
- savelocalvars = localvars;
- localvars = NULL;
- vforked = 1;
- VFORK_BLOCK
- switch (pid = vfork()) {
- case -1:
- serrno = errno;
- VTRACE(DBG_EVAL, ("vfork() failed, errno=%d\n",
- serrno));
- INTON;
- error("Cannot vfork (%s)", strerror(serrno));
- break;
- case 0:
- /* Make sure that exceptions only unwind to
- * after the vfork(2)
- */
- SHELL_FORKED();
- if (setjmp(jmploc.loc)) {
- if (exception == EXSHELLPROC) {
- /*
- * We can't progress with the
- * vfork, so, set vforked = 2
- * so the parent knows,
- * and _exit();
- */
- vforked = 2;
- _exit(0);
- } else {
- _exit(exception == EXEXIT ?
- exitstatus : exerrno);
- }
- }
- savehandler = handler;
- handler = &jmploc;
- listmklocal(varlist.list,
- VDOEXPORT | VEXPORT | VNOFUNC);
- forkchild(jp, cmd, mode, vforked);
- break;
- default:
- VFORK_UNDO();
- /* restore from vfork(2) */
- handler = savehandler;
- poplocalvars();
- localvars = savelocalvars;
- if (vforked == 2) {
- vforked = 0;
-
- (void)waitpid(pid, NULL, 0);
- /*
- * We need to progress in a
- * normal fork fashion
- */
- goto normal_fork;
- }
- /*
- * Here the child has left home,
- * getting on with its life, so
- * so must we...
- */
- vforked = 0;
- forkparent(jp, cmd, mode, pid);
- goto parent;
- }
- VFORK_END
- } else {
- normal_fork:
-#endif
- if (forkshell(jp, cmd, mode) != 0)
- goto parent; /* at end of routine */
- flags |= EV_EXIT;
- FORCEINTON;
-#ifdef DO_SHAREDVFORK
- }
-#endif
- if (flags & EV_BACKCMD) {
- if (!vforked) {
- FORCEINTON;
- }
- close(pip[0]);
- movefd(pip[1], 1);
- }
- flags |= EV_EXIT;
- }
-
- /* This is the child process if a fork occurred. */
- /* Execute the command. */
- switch (cmdentry.cmdtype) {
- volatile int saved;
-
- case CMDFUNCTION:
- VXTRACE(DBG_EVAL, ("Shell function%s: ",vforked?" VF":""),
- trargs(argv));
- redirect(cmd->ncmd.redirect, saved =
- !(flags & EV_EXIT) || have_traps() ? REDIR_PUSH : 0);
- saveparam = shellparam;
- shellparam.malloc = 0;
- shellparam.reset = 1;
- shellparam.nparam = argc - 1;
- shellparam.p = argv + 1;
- shellparam.optnext = NULL;
- INTOFF;
- savelocalvars = localvars;
- localvars = NULL;
- reffunc(cmdentry.u.func);
- INTON;
- if (setjmp(jmploc.loc)) {
- if (exception == EXSHELLPROC) {
- freeparam((volatile struct shparam *)
- &saveparam);
- } else {
- freeparam(&shellparam);
- shellparam = saveparam;
- }
- if (saved)
- popredir();;
- unreffunc(cmdentry.u.func);
- poplocalvars();
- localvars = savelocalvars;
- funclinebase = savefuncline;
- funclineabs = savefuncabs;
- handler = savehandler;
- longjmp(handler->loc, 1);
- }
- savehandler = handler;
- handler = &jmploc;
- if (cmdentry.u.func) {
- if (cmdentry.lno_frel)
- funclinebase = cmdentry.lineno - 1;
- else
- funclinebase = 0;
- funclineabs = cmdentry.lineno;
-
- VTRACE(DBG_EVAL,
- ("function: node: %d '%s' # %d%s; funclinebase=%d\n",
- getfuncnode(cmdentry.u.func)->type,
- NODETYPENAME(getfuncnode(cmdentry.u.func)->type),
- cmdentry.lineno, cmdentry.lno_frel?" (=1)":"",
- funclinebase));
- }
- listmklocal(varlist.list, VDOEXPORT | VEXPORT);
- /* stop shell blowing its stack */
- if (++funcnest > 1000)
- error("too many nested function calls");
- evaltree(getfuncnode(cmdentry.u.func),
- flags & (EV_TESTED|EV_EXIT));
- funcnest--;
- INTOFF;
- unreffunc(cmdentry.u.func);
- poplocalvars();
- localvars = savelocalvars;
- funclinebase = savefuncline;
- funclineabs = savefuncabs;
- freeparam(&shellparam);
- shellparam = saveparam;
- handler = savehandler;
- if (saved)
- popredir();
- INTON;
- if (evalskip == SKIPFUNC) {
- evalskip = SKIPNONE;
- skipcount = 0;
- }
- if (flags & EV_EXIT)
- exitshell(exitstatus);
- break;
-
- case CMDSPLBLTIN:
- VTRACE(DBG_EVAL, ("special "));
- case CMDBUILTIN:
- VXTRACE(DBG_EVAL, ("builtin command [%d]%s: ", argc,
- vforked ? " VF" : ""), trargs(argv));
- mode = (cmdentry.u.bltin == execcmd) ? 0 : REDIR_PUSH;
- if (flags == EV_BACKCMD) {
- memout.nleft = 0;
- memout.nextc = memout.buf;
- memout.bufsize = 64;
- mode |= REDIR_BACKQ;
- }
- e = -1;
- savecmdname = commandname;
- savetopfile = getcurrentfile();
- savehandler = handler;
- temp_path = 0;
- if (!setjmp(jmploc.loc)) {
- handler = &jmploc;
-
- /*
- * We need to ensure the command hash table isn't
- * corrupted by temporary PATH assignments.
- * However we must ensure the 'local' command works!
- */
- if (path != pathval() && (cmdentry.u.bltin == hashcmd ||
- cmdentry.u.bltin == typecmd)) {
- savelocalvars = localvars;
- localvars = 0;
- temp_path = 1;
- mklocal(path - 5 /* PATH= */, 0);
- }
- redirect(cmd->ncmd.redirect, mode);
-
- /*
- * the empty command is regarded as a normal
- * builtin for the purposes of redirects, but
- * is a special builtin for var assigns.
- * (unless we are the "command" command.)
- */
- if (argc == 0 && !(cmd_flags & DO_NOFUNC))
- cmdentry.cmdtype = CMDSPLBLTIN;
-
- /* exec is a special builtin, but needs this list... */
- cmdenviron = varlist.list;
- /* we must check 'readonly' flag for all builtins */
- listsetvar(varlist.list,
- cmdentry.cmdtype == CMDSPLBLTIN ? 0 : VNOSET);
- commandname = argv[0];
- /* initialize nextopt */
- argptr = argv + 1;
- optptr = NULL;
- /* and getopt */
- optreset = 1;
- optind = 1;
- builtin_flags = flags;
- exitstatus = cmdentry.u.bltin(argc, argv);
- } else {
- e = exception;
- if (e == EXINT)
- exitstatus = SIGINT + 128;
- else if (e == EXEXEC)
- exitstatus = exerrno;
- else if (e != EXEXIT)
- exitstatus = 2;
- }
- handler = savehandler;
- flushall();
- out1 = &output;
- out2 = &errout;
- freestdout();
- if (temp_path) {
- poplocalvars();
- localvars = savelocalvars;
- }
- cmdenviron = NULL;
- if (e != EXSHELLPROC) {
- commandname = savecmdname;
- if (flags & EV_EXIT)
- exitshell(exitstatus);
- }
- if (e != -1) {
- if ((e != EXERROR && e != EXEXEC)
- || cmdentry.cmdtype == CMDSPLBLTIN)
- exraise(e);
- popfilesupto(savetopfile);
- FORCEINTON;
- }
- if (cmdentry.u.bltin != execcmd)
- popredir();
- if (flags == EV_BACKCMD) {
- backcmd->buf = memout.buf;
- backcmd->nleft = memout.nextc - memout.buf;
- memout.buf = NULL;
- }
- break;
-
- default:
- VXTRACE(DBG_EVAL, ("normal command%s: ", vforked?" VF":""),
- trargs(argv));
- redirect(cmd->ncmd.redirect,
- (vforked ? REDIR_VFORK : 0) | REDIR_KEEP);
- if (!vforked)
- for (sp = varlist.list ; sp ; sp = sp->next)
- setvareq(sp->text, VDOEXPORT|VEXPORT|VSTACK);
- envp = environment();
- shellexec(argv, envp, path, cmdentry.u.index, vforked);
- break;
- }
- goto out;
-
- parent: /* parent process gets here (if we forked) */
-
- exitstatus = 0; /* if not altered just below */
- if (mode == FORK_FG) { /* argument to fork */
- exitstatus = waitforjob(jp);
- } else if (mode == FORK_NOJOB) {
- backcmd->fd = pip[0];
- close(pip[1]);
- backcmd->jp = jp;
- }
- FORCEINTON;
-
- out:
- if (lastarg)
- /* implement $_ for whatever use that really is */
- (void) setvarsafe("_", lastarg, VNOERROR);
- popstackmark(&smark);
-}
-
-
-/*
- * Search for a command. This is called before we fork so that the
- * location of the command will be available in the parent as well as
- * the child. The check for "goodname" is an overly conservative
- * check that the name will not be subject to expansion.
- */
-
-STATIC void
-prehash(union node *n)
-{
- struct cmdentry entry;
-
- if (n && n->type == NCMD && n->ncmd.args)
- if (goodname(n->ncmd.args->narg.text))
- find_command(n->ncmd.args->narg.text, &entry, 0,
- pathval());
-}
-
-int
-in_function(void)
-{
- return funcnest;
-}
-
-enum skipstate
-current_skipstate(void)
-{
- return evalskip;
-}
-
-void
-save_skipstate(struct skipsave *p)
-{
- *p = s_k_i_p;
-}
-
-void
-restore_skipstate(const struct skipsave *p)
-{
- s_k_i_p = *p;
-}
-
-void
-stop_skipping(void)
-{
- evalskip = SKIPNONE;
- skipcount = 0;
-}
-
-/*
- * Builtin commands. Builtin commands whose functions are closely
- * tied to evaluation are implemented here.
- */
-
-/*
- * No command given.
- */
-
-int
-bltincmd(int argc, char **argv)
-{
- /*
- * Preserve exitstatus of a previous possible redirection
- * as POSIX mandates
- */
- return back_exitstatus;
-}
-
-
-/*
- * Handle break and continue commands. Break, continue, and return are
- * all handled by setting the evalskip flag. The evaluation routines
- * above all check this flag, and if it is set they start skipping
- * commands rather than executing them. The variable skipcount is
- * the number of loops to break/continue, or the number of function
- * levels to return. (The latter is always 1.) It should probably
- * be an error to break out of more loops than exist, but it isn't
- * in the standard shell so we don't make it one here.
- */
-
-int
-breakcmd(int argc, char **argv)
-{
- int n = argc > 1 ? number(argv[1]) : 1;
-
- if (n <= 0)
- error("invalid count: %d", n);
- if (n > loopnest)
- n = loopnest;
- if (n > 0) {
- evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
- skipcount = n;
- }
- return 0;
-}
-
-int
-dotcmd(int argc, char **argv)
-{
- exitstatus = 0;
-
- if (argc >= 2) { /* That's what SVR2 does */
- char *fullname;
- /*
- * dot_funcnest needs to be 0 when not in a dotcmd, so it
- * cannot be restored with (funcnest + 1).
- */
- int dot_funcnest_old;
- struct stackmark smark;
-
- setstackmark(&smark);
- fullname = find_dot_file(argv[1]);
- setinputfile(fullname, 1);
- commandname = fullname;
- dot_funcnest_old = dot_funcnest;
- dot_funcnest = funcnest + 1;
- cmdloop(0);
- dot_funcnest = dot_funcnest_old;
- popfile();
- popstackmark(&smark);
- }
- return exitstatus;
-}
-
-/*
- * Take commands from a file. To be compatible we should do a path
- * search for the file, which is necessary to find sub-commands.
- */
-
-STATIC char *
-find_dot_file(char *basename)
-{
- char *fullname;
- const char *path = pathval();
- struct stat statb;
-
- /* don't try this for absolute or relative paths */
- if (strchr(basename, '/')) {
- if (stat(basename, &statb) == 0) {
- if (S_ISDIR(statb.st_mode))
- error("%s: is a directory", basename);
- if (S_ISBLK(statb.st_mode))
- error("%s: is a block device", basename);
- return basename;
- }
- } else while ((fullname = padvance(&path, basename, 1)) != NULL) {
- if ((stat(fullname, &statb) == 0)) {
- /* weird format is to ease future code... */
- if (S_ISDIR(statb.st_mode) || S_ISBLK(statb.st_mode))
- ;
-#if notyet
- else if (unreadable()) {
- /*
- * testing this via st_mode is ugly to get
- * correct (and would ignore ACLs).
- * better way is just to open the file.
- * But doing that here would (currently)
- * mean opening the file twice, which
- * might not be safe. So, defer this
- * test until code is restructures so
- * we can return a fd. Then we also
- * get to fix the mem leak just below...
- */
- }
-#endif
- else {
- /*
- * Don't bother freeing here, since
- * it will be freed by the caller.
- * XXX no it won't - a bug for later.
- */
- return fullname;
- }
- }
- stunalloc(fullname);
- }
-
- /* not found in the PATH */
- error("%s: not found", basename);
- /* NOTREACHED */
-}
-
-
-
-/*
- * The return command.
- *
- * Quoth the POSIX standard:
- * The return utility shall cause the shell to stop executing the current
- * function or dot script. If the shell is not currently executing
- * a function or dot script, the results are unspecified.
- *
- * As for the unspecified part, there seems to be no de-facto standard: bash
- * ignores the return with a warning, zsh ignores the return in interactive
- * mode but seems to liken it to exit in a script. (checked May 2014)
- *
- * We choose to silently ignore the return. Older versions of this shell
- * set evalskip to SKIPFILE causing the shell to (indirectly) exit. This
- * had at least the problem of circumventing the check for stopped jobs,
- * which would occur for exit or ^D.
- */
-
-int
-returncmd(int argc, char **argv)
-{
- int ret = argc > 1 ? number(argv[1]) : exitstatus;
-
- if ((dot_funcnest == 0 && funcnest)
- || (dot_funcnest > 0 && funcnest - (dot_funcnest - 1) > 0)) {
- evalskip = SKIPFUNC;
- skipcount = 1;
- } else if (dot_funcnest > 0) {
- evalskip = SKIPFILE;
- skipcount = 1;
- } else {
- /* XXX: should a warning be issued? */
- ret = 0;
- }
-
- return ret;
-}
-
-
-int
-falsecmd(int argc, char **argv)
-{
- return 1;
-}
-
-
-int
-truecmd(int argc, char **argv)
-{
- return 0;
-}
-
-
-int
-execcmd(int argc, char **argv)
-{
- if (argc > 1) {
- struct strlist *sp;
-
- iflag = 0; /* exit on error */
- mflag = 0;
- optschanged();
- for (sp = cmdenviron; sp; sp = sp->next)
- setvareq(sp->text, VDOEXPORT|VEXPORT|VSTACK);
- shellexec(argv + 1, environment(), pathval(), 0, 0);
- }
- return 0;
-}
-
-static int
-conv_time(clock_t ticks, char *seconds, size_t l)
-{
- static clock_t tpm = 0;
- clock_t mins;
- int i;
-
- if (!tpm)
- tpm = sysconf(_SC_CLK_TCK) * 60;
-
- mins = ticks / tpm;
- snprintf(seconds, l, "%.4f", (ticks - mins * tpm) * 60.0 / tpm );
-
- if (seconds[0] == '6' && seconds[1] == '0') {
- /* 59.99995 got rounded up... */
- mins++;
- strlcpy(seconds, "0.0", l);
- return mins;
- }
-
- /* suppress trailing zeros */
- i = strlen(seconds) - 1;
- for (; seconds[i] == '0' && seconds[i - 1] != '.'; i--)
- seconds[i] = 0;
- return mins;
-}
-
-int
-timescmd(int argc, char **argv)
-{
- struct tms tms;
- int u, s, cu, cs;
- char us[8], ss[8], cus[8], css[8];
-
- nextopt("");
-
- times(&tms);
-
- u = conv_time(tms.tms_utime, us, sizeof(us));
- s = conv_time(tms.tms_stime, ss, sizeof(ss));
- cu = conv_time(tms.tms_cutime, cus, sizeof(cus));
- cs = conv_time(tms.tms_cstime, css, sizeof(css));
-
- outfmt(out1, "%dm%ss %dm%ss\n%dm%ss %dm%ss\n",
- u, us, s, ss, cu, cus, cs, css);
-
- return 0;
-}
diff --git a/bin/sh/eval.h b/bin/sh/eval.h
deleted file mode 100644
index b18dd42..0000000
--- a/bin/sh/eval.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/* $NetBSD: eval.h,v 1.22 2018/12/03 06:43:19 kre Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- *
- * @(#)eval.h 8.2 (Berkeley) 5/4/95
- */
-
-extern const char *commandname; /* currently executing command */
-extern int exitstatus; /* exit status of last command */
-extern int back_exitstatus; /* exit status of backquoted command */
-extern struct strlist *cmdenviron; /* environment for builtin command */
-
-
-struct backcmd { /* result of evalbackcmd */
- int fd; /* file descriptor to read from */
- char *buf; /* buffer */
- int nleft; /* number of chars in buffer */
- struct job *jp; /* job structure for command */
-};
-
-void evalstring(char *, int);
-union node; /* BLETCH for ansi C */
-void evaltree(union node *, int);
-void evalbackcmd(union node *, struct backcmd *);
-
-const char *syspath(void);
-
-/* in_function returns nonzero if we are currently evaluating a function */
-int in_function(void); /* return non-zero, if evaluating a function */
-
-/* reasons for skipping commands (see comment on breakcmd routine) */
-enum skipstate {
- SKIPNONE = 0, /* not skipping */
- SKIPBREAK, /* break */
- SKIPCONT, /* continue */
- SKIPFUNC, /* return in a function */
- SKIPFILE /* return in a dot command */
-};
-
-struct skipsave {
- enum skipstate state; /* skipping or not */
- int count; /* when break or continue, how many */
-};
-
-enum skipstate current_skipstate(void);
-void save_skipstate(struct skipsave *);
-void restore_skipstate(const struct skipsave *);
-void stop_skipping(void); /* reset internal skipping state to SKIPNONE */
-
-/*
- * Only for use by reset() in init.c!
- */
-void reset_eval(void);
-
-/* flags in argument to evaltree */
-#define EV_EXIT 0x01 /* exit after evaluating tree */
-#define EV_TESTED 0x02 /* exit status is checked; ignore -e flag */
-#define EV_BACKCMD 0x04 /* command executing within back quotes */
diff --git a/bin/sh/exec.c b/bin/sh/exec.c
deleted file mode 100644
index 674beb8..0000000
--- a/bin/sh/exec.c
+++ /dev/null
@@ -1,1183 +0,0 @@
-/* $NetBSD: exec.c,v 1.53 2018/07/25 14:42:50 kre Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- */
-
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)exec.c 8.4 (Berkeley) 6/8/95";
-#else
-__RCSID("$NetBSD: exec.c,v 1.53 2018/07/25 14:42:50 kre Exp $");
-#endif
-#endif /* not lint */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-/*
- * When commands are first encountered, they are entered in a hash table.
- * This ensures that a full path search will not have to be done for them
- * on each invocation.
- *
- * We should investigate converting to a linear search, even though that
- * would make the command name "hash" a misnomer.
- */
-
-#include "shell.h"
-#include "main.h"
-#include "nodes.h"
-#include "parser.h"
-#include "redir.h"
-#include "eval.h"
-#include "exec.h"
-#include "builtins.h"
-#include "var.h"
-#include "options.h"
-#include "input.h"
-#include "output.h"
-#include "syntax.h"
-#include "memalloc.h"
-#include "error.h"
-#include "init.h"
-#include "mystring.h"
-#include "show.h"
-#include "jobs.h"
-#include "alias.h"
-
-
-#define CMDTABLESIZE 31 /* should be prime */
-#define ARB 1 /* actual size determined at run time */
-
-
-
-struct tblentry {
- struct tblentry *next; /* next entry in hash chain */
- union param param; /* definition of builtin function */
- short cmdtype; /* index identifying command */
- char rehash; /* if set, cd done since entry created */
- char fn_ln1; /* for functions, LINENO from 1 */
- int lineno; /* for functions abs LINENO of definition */
- char cmdname[ARB]; /* name of command */
-};
-
-
-STATIC struct tblentry *cmdtable[CMDTABLESIZE];
-STATIC int builtinloc = -1; /* index in path of %builtin, or -1 */
-int exerrno = 0; /* Last exec error */
-
-
-STATIC void tryexec(char *, char **, char **, int);
-STATIC void printentry(struct tblentry *, int);
-STATIC void addcmdentry(char *, struct cmdentry *);
-STATIC void clearcmdentry(int);
-STATIC struct tblentry *cmdlookup(const char *, int);
-STATIC void delete_cmd_entry(void);
-
-#ifndef BSD
-STATIC void execinterp(char **, char **);
-#endif
-
-
-extern const char *const parsekwd[];
-
-/*
- * Exec a program. Never returns. If you change this routine, you may
- * have to change the find_command routine as well.
- */
-
-void
-shellexec(char **argv, char **envp, const char *path, int idx, int vforked)
-{
- char *cmdname;
- int e;
-
- if (strchr(argv[0], '/') != NULL) {
- tryexec(argv[0], argv, envp, vforked);
- e = errno;
- } else {
- e = ENOENT;
- while ((cmdname = padvance(&path, argv[0], 1)) != NULL) {
- if (--idx < 0 && pathopt == NULL) {
- tryexec(cmdname, argv, envp, vforked);
- if (errno != ENOENT && errno != ENOTDIR)
- e = errno;
- }
- stunalloc(cmdname);
- }
- }
-
- /* Map to POSIX errors */
- switch (e) {
- case EACCES: /* particularly this (unless no search perm) */
- /*
- * should perhaps check if this EACCES is an exec()
- * EACESS or a namei() EACESS - the latter should be 127
- * - but not today
- */
- case EINVAL: /* also explicitly these */
- case ENOEXEC:
- default: /* and anything else */
- exerrno = 126;
- break;
-
- case ENOENT: /* these are the "pathname lookup failed" errors */
- case ELOOP:
- case ENOTDIR:
- case ENAMETOOLONG:
- exerrno = 127;
- break;
- }
- CTRACE(DBG_ERRS|DBG_CMDS|DBG_EVAL,
- ("shellexec failed for %s, errno %d, vforked %d, suppressint %d\n",
- argv[0], e, vforked, suppressint));
- exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
- /* NOTREACHED */
-}
-
-
-STATIC void
-tryexec(char *cmd, char **argv, char **envp, int vforked)
-{
- int e;
-#ifndef BSD
- char *p;
-#endif
-
-#ifdef SYSV
- do {
- execve(cmd, argv, envp);
- } while (errno == EINTR);
-#else
- execve(cmd, argv, envp);
-#endif
- e = errno;
- if (e == ENOEXEC) {
- if (vforked) {
- /* We are currently vfork(2)ed, so raise an
- * exception, and evalcommand will try again
- * with a normal fork(2).
- */
- exraise(EXSHELLPROC);
- }
-#ifdef DEBUG
- VTRACE(DBG_CMDS, ("execve(cmd=%s) returned ENOEXEC\n", cmd));
-#endif
- initshellproc();
- setinputfile(cmd, 0);
- commandname = arg0 = savestr(argv[0]);
-#ifndef BSD
- pgetc(); pungetc(); /* fill up input buffer */
- p = parsenextc;
- if (parsenleft > 2 && p[0] == '#' && p[1] == '!') {
- argv[0] = cmd;
- execinterp(argv, envp);
- }
-#endif
- setparam(argv + 1);
- exraise(EXSHELLPROC);
- }
- errno = e;
-}
-
-
-#ifndef BSD
-/*
- * Execute an interpreter introduced by "#!", for systems where this
- * feature has not been built into the kernel. If the interpreter is
- * the shell, return (effectively ignoring the "#!"). If the execution
- * of the interpreter fails, exit.
- *
- * This code peeks inside the input buffer in order to avoid actually
- * reading any input. It would benefit from a rewrite.
- */
-
-#define NEWARGS 5
-
-STATIC void
-execinterp(char **argv, char **envp)
-{
- int n;
- char *inp;
- char *outp;
- char c;
- char *p;
- char **ap;
- char *newargs[NEWARGS];
- int i;
- char **ap2;
- char **new;
-
- n = parsenleft - 2;
- inp = parsenextc + 2;
- ap = newargs;
- for (;;) {
- while (--n >= 0 && (*inp == ' ' || *inp == '\t'))
- inp++;
- if (n < 0)
- goto bad;
- if ((c = *inp++) == '\n')
- break;
- if (ap == &newargs[NEWARGS])
-bad: error("Bad #! line");
- STARTSTACKSTR(outp);
- do {
- STPUTC(c, outp);
- } while (--n >= 0 && (c = *inp++) != ' ' && c != '\t' && c != '\n');
- STPUTC('\0', outp);
- n++, inp--;
- *ap++ = grabstackstr(outp);
- }
- if (ap == newargs + 1) { /* if no args, maybe no exec is needed */
- p = newargs[0];
- for (;;) {
- if (equal(p, "sh") || equal(p, "ash")) {
- return;
- }
- while (*p != '/') {
- if (*p == '\0')
- goto break2;
- p++;
- }
- p++;
- }
-break2:;
- }
- i = (char *)ap - (char *)newargs; /* size in bytes */
- if (i == 0)
- error("Bad #! line");
- for (ap2 = argv ; *ap2++ != NULL ; );
- new = ckmalloc(i + ((char *)ap2 - (char *)argv));
- ap = newargs, ap2 = new;
- while ((i -= sizeof (char **)) >= 0)
- *ap2++ = *ap++;
- ap = argv;
- while (*ap2++ = *ap++);
- shellexec(new, envp, pathval(), 0);
- /* NOTREACHED */
-}
-#endif
-
-
-
-/*
- * Do a path search. The variable path (passed by reference) should be
- * set to the start of the path before the first call; padvance will update
- * this value as it proceeds. Successive calls to padvance will return
- * the possible path expansions in sequence. If an option (indicated by
- * a percent sign) appears in the path entry then the global variable
- * pathopt will be set to point to it; otherwise pathopt will be set to
- * NULL.
- */
-
-const char *pathopt;
-
-char *
-padvance(const char **path, const char *name, int magic_percent)
-{
- const char *p;
- char *q;
- const char *start;
- int len;
-
- if (*path == NULL)
- return NULL;
- if (magic_percent)
- magic_percent = '%';
-
- start = *path;
- for (p = start ; *p && *p != ':' && *p != magic_percent ; p++)
- ;
- len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
- while (stackblocksize() < len)
- growstackblock();
- q = stackblock();
- if (p != start) {
- memcpy(q, start, p - start);
- q += p - start;
- if (q[-1] != '/')
- *q++ = '/';
- }
- strcpy(q, name);
- pathopt = NULL;
- if (*p == magic_percent) {
- pathopt = ++p;
- while (*p && *p != ':')
- p++;
- }
- if (*p == ':')
- *path = p + 1;
- else
- *path = NULL;
- return grabstackstr(q + strlen(name) + 1);
-}
-
-
-/*** Command hashing code ***/
-
-
-int
-hashcmd(int argc, char **argv)
-{
- struct tblentry **pp;
- struct tblentry *cmdp;
- int c;
- struct cmdentry entry;
- char *name;
- int allopt=0, bopt=0, fopt=0, ropt=0, sopt=0, uopt=0, verbose=0;
-
- while ((c = nextopt("bcfrsuv")) != '\0')
- switch (c) {
- case 'b': bopt = 1; break;
- case 'c': uopt = 1; break; /* c == u */
- case 'f': fopt = 1; break;
- case 'r': ropt = 1; break;
- case 's': sopt = 1; break;
- case 'u': uopt = 1; break;
- case 'v': verbose = 1; break;
- }
-
- if (ropt)
- clearcmdentry(0);
-
- if (bopt == 0 && fopt == 0 && sopt == 0 && uopt == 0)
- allopt = bopt = fopt = sopt = uopt = 1;
-
- if (*argptr == NULL) {
- for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
- for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
- switch (cmdp->cmdtype) {
- case CMDNORMAL:
- if (!uopt)
- continue;
- break;
- case CMDBUILTIN:
- if (!bopt)
- continue;
- break;
- case CMDSPLBLTIN:
- if (!sopt)
- continue;
- break;
- case CMDFUNCTION:
- if (!fopt)
- continue;
- break;
- default: /* never happens */
- continue;
- }
- if (!allopt || verbose ||
- cmdp->cmdtype == CMDNORMAL)
- printentry(cmdp, verbose);
- }
- }
- return 0;
- }
-
- while ((name = *argptr++) != NULL) {
- if ((cmdp = cmdlookup(name, 0)) != NULL) {
- switch (cmdp->cmdtype) {
- case CMDNORMAL:
- if (!uopt)
- continue;
- delete_cmd_entry();
- break;
- case CMDBUILTIN:
- if (!bopt)
- continue;
- if (builtinloc >= 0)
- delete_cmd_entry();
- break;
- case CMDSPLBLTIN:
- if (!sopt)
- continue;
- break;
- case CMDFUNCTION:
- if (!fopt)
- continue;
- break;
- }
- }
- find_command(name, &entry, DO_ERR, pathval());
- if (verbose) {
- if (entry.cmdtype != CMDUNKNOWN) { /* if no error msg */
- cmdp = cmdlookup(name, 0);
- if (cmdp != NULL)
- printentry(cmdp, verbose);
- }
- flushall();
- }
- }
- return 0;
-}
-
-STATIC void
-printentry(struct tblentry *cmdp, int verbose)
-{
- int idx;
- const char *path;
- char *name;
-
- switch (cmdp->cmdtype) {
- case CMDNORMAL:
- idx = cmdp->param.index;
- path = pathval();
- do {
- name = padvance(&path, cmdp->cmdname, 1);
- stunalloc(name);
- } while (--idx >= 0);
- if (verbose)
- out1fmt("Command from PATH[%d]: ",
- cmdp->param.index);
- out1str(name);
- break;
- case CMDSPLBLTIN:
- if (verbose)
- out1str("special ");
- /* FALLTHROUGH */
- case CMDBUILTIN:
- if (verbose)
- out1str("builtin ");
- out1fmt("%s", cmdp->cmdname);
- break;
- case CMDFUNCTION:
- if (verbose)
- out1str("function ");
- out1fmt("%s", cmdp->cmdname);
- if (verbose) {
- struct procstat ps;
-
- INTOFF;
- commandtext(&ps, getfuncnode(cmdp->param.func));
- INTON;
- out1str("() { ");
- out1str(ps.cmd);
- out1str("; }");
- }
- break;
- default:
- error("internal error: %s cmdtype %d",
- cmdp->cmdname, cmdp->cmdtype);
- }
- if (cmdp->rehash)
- out1c('*');
- out1c('\n');
-}
-
-
-
-/*
- * Resolve a command name. If you change this routine, you may have to
- * change the shellexec routine as well.
- */
-
-void
-find_command(char *name, struct cmdentry *entry, int act, const char *path)
-{
- struct tblentry *cmdp, loc_cmd;
- int idx;
- int prev;
- char *fullname;
- struct stat statb;
- int e;
- int (*bltin)(int,char **);
-
- /* If name contains a slash, don't use PATH or hash table */
- if (strchr(name, '/') != NULL) {
- if (act & DO_ABS) {
- while (stat(name, &statb) < 0) {
-#ifdef SYSV
- if (errno == EINTR)
- continue;
-#endif
- if (errno != ENOENT && errno != ENOTDIR)
- e = errno;
- entry->cmdtype = CMDUNKNOWN;
- entry->u.index = -1;
- return;
- }
- entry->cmdtype = CMDNORMAL;
- entry->u.index = -1;
- return;
- }
- entry->cmdtype = CMDNORMAL;
- entry->u.index = 0;
- return;
- }
-
- if (path != pathval())
- act |= DO_ALTPATH;
-
- if (act & DO_ALTPATH && strstr(path, "%builtin") != NULL)
- act |= DO_ALTBLTIN;
-
- /* If name is in the table, check answer will be ok */
- if ((cmdp = cmdlookup(name, 0)) != NULL) {
- do {
- switch (cmdp->cmdtype) {
- case CMDNORMAL:
- if (act & DO_ALTPATH) {
- cmdp = NULL;
- continue;
- }
- break;
- case CMDFUNCTION:
- if (act & DO_NOFUNC) {
- cmdp = NULL;
- continue;
- }
- break;
- case CMDBUILTIN:
- if ((act & DO_ALTBLTIN) || builtinloc >= 0) {
- cmdp = NULL;
- continue;
- }
- break;
- }
- /* if not invalidated by cd, we're done */
- if (cmdp->rehash == 0)
- goto success;
- } while (0);
- }
-
- /* If %builtin not in path, check for builtin next */
- if ((act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc < 0) &&
- (bltin = find_builtin(name)) != 0)
- goto builtin_success;
-
- /* We have to search path. */
- prev = -1; /* where to start */
- if (cmdp) { /* doing a rehash */
- if (cmdp->cmdtype == CMDBUILTIN)
- prev = builtinloc;
- else
- prev = cmdp->param.index;
- }
-
- e = ENOENT;
- idx = -1;
-loop:
- while ((fullname = padvance(&path, name, 1)) != NULL) {
- stunalloc(fullname);
- idx++;
- if (pathopt) {
- if (prefix("builtin", pathopt)) {
- if ((bltin = find_builtin(name)) == 0)
- goto loop;
- goto builtin_success;
- } else if (prefix("func", pathopt)) {
- /* handled below */
- } else {
- /* ignore unimplemented options */
- goto loop;
- }
- }
- /* if rehash, don't redo absolute path names */
- if (fullname[0] == '/' && idx <= prev) {
- if (idx < prev)
- goto loop;
- VTRACE(DBG_CMDS, ("searchexec \"%s\": no change\n",
- name));
- goto success;
- }
- while (stat(fullname, &statb) < 0) {
-#ifdef SYSV
- if (errno == EINTR)
- continue;
-#endif
- if (errno != ENOENT && errno != ENOTDIR)
- e = errno;
- goto loop;
- }
- e = EACCES; /* if we fail, this will be the error */
- if (!S_ISREG(statb.st_mode))
- goto loop;
- if (pathopt) { /* this is a %func directory */
- char *endname;
-
- if (act & DO_NOFUNC)
- goto loop;
- endname = fullname + strlen(fullname) + 1;
- grabstackstr(endname);
- readcmdfile(fullname);
- if ((cmdp = cmdlookup(name, 0)) == NULL ||
- cmdp->cmdtype != CMDFUNCTION)
- error("%s not defined in %s", name, fullname);
- ungrabstackstr(fullname, endname);
- goto success;
- }
-#ifdef notdef
- /* XXX this code stops root executing stuff, and is buggy
- if you need a group from the group list. */
- if (statb.st_uid == geteuid()) {
- if ((statb.st_mode & 0100) == 0)
- goto loop;
- } else if (statb.st_gid == getegid()) {
- if ((statb.st_mode & 010) == 0)
- goto loop;
- } else {
- if ((statb.st_mode & 01) == 0)
- goto loop;
- }
-#endif
- VTRACE(DBG_CMDS, ("searchexec \"%s\" returns \"%s\"\n", name,
- fullname));
- INTOFF;
- if (act & DO_ALTPATH) {
- /*
- * this should be a grabstackstr() but is not needed:
- * fullname is no longer needed for anything
- stalloc(strlen(fullname) + 1);
- */
- cmdp = &loc_cmd;
- } else
- cmdp = cmdlookup(name, 1);
- cmdp->cmdtype = CMDNORMAL;
- cmdp->param.index = idx;
- INTON;
- goto success;
- }
-
- /* We failed. If there was an entry for this command, delete it */
- if (cmdp)
- delete_cmd_entry();
- if (act & DO_ERR)
- outfmt(out2, "%s: %s\n", name, errmsg(e, E_EXEC));
- entry->cmdtype = CMDUNKNOWN;
- return;
-
-builtin_success:
- INTOFF;
- if (act & DO_ALTPATH)
- cmdp = &loc_cmd;
- else
- cmdp = cmdlookup(name, 1);
- if (cmdp->cmdtype == CMDFUNCTION)
- /* DO_NOFUNC must have been set */
- cmdp = &loc_cmd;
- cmdp->cmdtype = CMDBUILTIN;
- cmdp->param.bltin = bltin;
- INTON;
-success:
- if (cmdp) {
- cmdp->rehash = 0;
- entry->cmdtype = cmdp->cmdtype;
- entry->lineno = cmdp->lineno;
- entry->lno_frel = cmdp->fn_ln1;
- entry->u = cmdp->param;
- } else
- entry->cmdtype = CMDUNKNOWN;
-}
-
-
-
-/*
- * Search the table of builtin commands.
- */
-
-int
-(*find_builtin(char *name))(int, char **)
-{
- const struct builtincmd *bp;
-
- for (bp = builtincmd ; bp->name ; bp++) {
- if (*bp->name == *name
- && (*name == '%' || equal(bp->name, name)))
- return bp->builtin;
- }
- return 0;
-}
-
-int
-(*find_splbltin(char *name))(int, char **)
-{
- const struct builtincmd *bp;
-
- for (bp = splbltincmd ; bp->name ; bp++) {
- if (*bp->name == *name && equal(bp->name, name))
- return bp->builtin;
- }
- return 0;
-}
-
-/*
- * At shell startup put special builtins into hash table.
- * ensures they are executed first (see posix).
- * We stop functions being added with the same name
- * (as they are impossible to call)
- */
-
-void
-hash_special_builtins(void)
-{
- const struct builtincmd *bp;
- struct tblentry *cmdp;
-
- for (bp = splbltincmd ; bp->name ; bp++) {
- cmdp = cmdlookup(bp->name, 1);
- cmdp->cmdtype = CMDSPLBLTIN;
- cmdp->param.bltin = bp->builtin;
- }
-}
-
-
-
-/*
- * Called when a cd is done. Marks all commands so the next time they
- * are executed they will be rehashed.
- */
-
-void
-hashcd(void)
-{
- struct tblentry **pp;
- struct tblentry *cmdp;
-
- for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
- for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
- if (cmdp->cmdtype == CMDNORMAL
- || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
- cmdp->rehash = 1;
- }
- }
-}
-
-
-
-/*
- * Fix command hash table when PATH changed.
- * Called before PATH is changed. The argument is the new value of PATH;
- * pathval() still returns the old value at this point.
- * Called with interrupts off.
- */
-
-void
-changepath(const char *newval)
-{
- const char *old, *new;
- int idx;
- int firstchange;
- int bltin;
-
- old = pathval();
- new = newval;
- firstchange = 9999; /* assume no change */
- idx = 0;
- bltin = -1;
- for (;;) {
- if (*old != *new) {
- firstchange = idx;
- if ((*old == '\0' && *new == ':')
- || (*old == ':' && *new == '\0'))
- firstchange++;
- old = new; /* ignore subsequent differences */
- }
- if (*new == '\0')
- break;
- if (*new == '%' && bltin < 0 && prefix("builtin", new + 1))
- bltin = idx;
- if (*new == ':') {
- idx++;
- }
- new++, old++;
- }
- if (builtinloc < 0 && bltin >= 0)
- builtinloc = bltin; /* zap builtins */
- if (builtinloc >= 0 && bltin < 0)
- firstchange = 0;
- clearcmdentry(firstchange);
- builtinloc = bltin;
-}
-
-
-/*
- * Clear out command entries. The argument specifies the first entry in
- * PATH which has changed.
- */
-
-STATIC void
-clearcmdentry(int firstchange)
-{
- struct tblentry **tblp;
- struct tblentry **pp;
- struct tblentry *cmdp;
-
- INTOFF;
- for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
- pp = tblp;
- while ((cmdp = *pp) != NULL) {
- if ((cmdp->cmdtype == CMDNORMAL &&
- cmdp->param.index >= firstchange)
- || (cmdp->cmdtype == CMDBUILTIN &&
- builtinloc >= firstchange)) {
- *pp = cmdp->next;
- ckfree(cmdp);
- } else {
- pp = &cmdp->next;
- }
- }
- }
- INTON;
-}
-
-
-/*
- * Delete all functions.
- */
-
-#ifdef mkinit
-MKINIT void deletefuncs(void);
-MKINIT void hash_special_builtins(void);
-
-INIT {
- hash_special_builtins();
-}
-
-SHELLPROC {
- deletefuncs();
-}
-#endif
-
-void
-deletefuncs(void)
-{
- struct tblentry **tblp;
- struct tblentry **pp;
- struct tblentry *cmdp;
-
- INTOFF;
- for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
- pp = tblp;
- while ((cmdp = *pp) != NULL) {
- if (cmdp->cmdtype == CMDFUNCTION) {
- *pp = cmdp->next;
- freefunc(cmdp->param.func);
- ckfree(cmdp);
- } else {
- pp = &cmdp->next;
- }
- }
- }
- INTON;
-}
-
-
-
-/*
- * Locate a command in the command hash table. If "add" is nonzero,
- * add the command to the table if it is not already present. The
- * variable "lastcmdentry" is set to point to the address of the link
- * pointing to the entry, so that delete_cmd_entry can delete the
- * entry.
- */
-
-struct tblentry **lastcmdentry;
-
-
-STATIC struct tblentry *
-cmdlookup(const char *name, int add)
-{
- int hashval;
- const char *p;
- struct tblentry *cmdp;
- struct tblentry **pp;
-
- p = name;
- hashval = *p << 4;
- while (*p)
- hashval += *p++;
- hashval &= 0x7FFF;
- pp = &cmdtable[hashval % CMDTABLESIZE];
- for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
- if (equal(cmdp->cmdname, name))
- break;
- pp = &cmdp->next;
- }
- if (add && cmdp == NULL) {
- INTOFF;
- cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
- + strlen(name) + 1);
- cmdp->next = NULL;
- cmdp->cmdtype = CMDUNKNOWN;
- cmdp->rehash = 0;
- strcpy(cmdp->cmdname, name);
- INTON;
- }
- lastcmdentry = pp;
- return cmdp;
-}
-
-/*
- * Delete the command entry returned on the last lookup.
- */
-
-STATIC void
-delete_cmd_entry(void)
-{
- struct tblentry *cmdp;
-
- INTOFF;
- cmdp = *lastcmdentry;
- *lastcmdentry = cmdp->next;
- ckfree(cmdp);
- INTON;
-}
-
-
-
-#ifdef notdef
-void
-getcmdentry(char *name, struct cmdentry *entry)
-{
- struct tblentry *cmdp = cmdlookup(name, 0);
-
- if (cmdp) {
- entry->u = cmdp->param;
- entry->cmdtype = cmdp->cmdtype;
- } else {
- entry->cmdtype = CMDUNKNOWN;
- entry->u.index = 0;
- }
-}
-#endif
-
-
-/*
- * Add a new command entry, replacing any existing command entry for
- * the same name - except special builtins.
- */
-
-STATIC void
-addcmdentry(char *name, struct cmdentry *entry)
-{
- struct tblentry *cmdp;
-
- INTOFF;
- cmdp = cmdlookup(name, 1);
- if (cmdp->cmdtype != CMDSPLBLTIN) {
- if (cmdp->cmdtype == CMDFUNCTION)
- unreffunc(cmdp->param.func);
- cmdp->cmdtype = entry->cmdtype;
- cmdp->lineno = entry->lineno;
- cmdp->fn_ln1 = entry->lno_frel;
- cmdp->param = entry->u;
- }
- INTON;
-}
-
-
-/*
- * Define a shell function.
- */
-
-void
-defun(char *name, union node *func, int lineno)
-{
- struct cmdentry entry;
-
- INTOFF;
- entry.cmdtype = CMDFUNCTION;
- entry.lineno = lineno;
- entry.lno_frel = fnline1;
- entry.u.func = copyfunc(func);
- addcmdentry(name, &entry);
- INTON;
-}
-
-
-/*
- * Delete a function if it exists.
- */
-
-int
-unsetfunc(char *name)
-{
- struct tblentry *cmdp;
-
- if ((cmdp = cmdlookup(name, 0)) != NULL &&
- cmdp->cmdtype == CMDFUNCTION) {
- unreffunc(cmdp->param.func);
- delete_cmd_entry();
- }
- return 0;
-}
-
-/*
- * Locate and print what a word is...
- * also used for 'command -[v|V]'
- */
-
-int
-typecmd(int argc, char **argv)
-{
- struct cmdentry entry;
- struct tblentry *cmdp;
- const char * const *pp;
- struct alias *ap;
- int err = 0;
- char *arg;
- int c;
- int V_flag = 0;
- int v_flag = 0;
- int p_flag = 0;
-
- while ((c = nextopt("vVp")) != 0) {
- switch (c) {
- case 'v': v_flag = 1; break;
- case 'V': V_flag = 1; break;
- case 'p': p_flag = 1; break;
- }
- }
-
- if (argv[0][0] != 'c' && v_flag | V_flag | p_flag)
- error("usage: %s name...", argv[0]);
-
- if (v_flag && V_flag)
- error("-v and -V cannot both be specified");
-
- if (*argptr == NULL)
- error("usage: %s%s name ...", argv[0],
- argv[0][0] == 'c' ? " [-p] [-v|-V]" : "");
-
- while ((arg = *argptr++)) {
- if (!v_flag)
- out1str(arg);
- /* First look at the keywords */
- for (pp = parsekwd; *pp; pp++)
- if (**pp == *arg && equal(*pp, arg))
- break;
-
- if (*pp) {
- if (v_flag)
- out1fmt("%s\n", arg);
- else
- out1str(" is a shell keyword\n");
- continue;
- }
-
- /* Then look at the aliases */
- if ((ap = lookupalias(arg, 1)) != NULL) {
- int ml = 0;
-
- if (!v_flag) {
- out1str(" is an alias ");
- if (strchr(ap->val, '\n')) {
- out1str("(multiline)...\n");
- ml = 1;
- } else
- out1str("for: ");
- }
- out1fmt("%s\n", ap->val);
- if (ml && *argptr != NULL)
- out1c('\n');
- continue;
- }
-
- /* Then check if it is a tracked alias */
- if (!p_flag && (cmdp = cmdlookup(arg, 0)) != NULL) {
- entry.cmdtype = cmdp->cmdtype;
- entry.u = cmdp->param;
- } else {
- cmdp = NULL;
- /* Finally use brute force */
- find_command(arg, &entry, DO_ABS,
- p_flag ? syspath() + 5 : pathval());
- }
-
- switch (entry.cmdtype) {
- case CMDNORMAL: {
- if (strchr(arg, '/') == NULL) {
- const char *path;
- char *name;
- int j = entry.u.index;
-
- path = p_flag ? syspath() + 5 : pathval();
-
- do {
- name = padvance(&path, arg, 1);
- stunalloc(name);
- } while (--j >= 0);
- if (!v_flag)
- out1fmt(" is%s ",
- cmdp ? " a tracked alias for" : "");
- out1fmt("%s\n", name);
- } else {
- if (access(arg, X_OK) == 0) {
- if (!v_flag)
- out1fmt(" is ");
- out1fmt("%s\n", arg);
- } else {
- if (!v_flag)
- out1fmt(": %s\n",
- strerror(errno));
- else
- err = 126;
- }
- }
- break;
- }
- case CMDFUNCTION:
- if (!v_flag)
- out1str(" is a shell function\n");
- else
- out1fmt("%s\n", arg);
- break;
-
- case CMDBUILTIN:
- if (!v_flag)
- out1str(" is a shell builtin\n");
- else
- out1fmt("%s\n", arg);
- break;
-
- case CMDSPLBLTIN:
- if (!v_flag)
- out1str(" is a special shell builtin\n");
- else
- out1fmt("%s\n", arg);
- break;
-
- default:
- if (!v_flag)
- out1str(": not found\n");
- err = 127;
- break;
- }
- }
- return err;
-}
diff --git a/bin/sh/exec.h b/bin/sh/exec.h
deleted file mode 100644
index 90beba1..0000000
--- a/bin/sh/exec.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/* $NetBSD: exec.h,v 1.27 2018/06/22 11:04:55 kre Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- *
- * @(#)exec.h 8.3 (Berkeley) 6/8/95
- */
-
-/* values of cmdtype */
-#define CMDUNKNOWN -1 /* no entry in table for command */
-#define CMDNORMAL 0 /* command is an executable program */
-#define CMDFUNCTION 1 /* command is a shell function */
-#define CMDBUILTIN 2 /* command is a shell builtin */
-#define CMDSPLBLTIN 3 /* command is a special shell builtin */
-
-
-struct cmdentry {
- short cmdtype;
- short lno_frel; /* for functions: Line numbers count from 1 */
- int lineno; /* for functions: Abs line number of defn */
- union param {
- int index;
- int (*bltin)(int, char**);
- struct funcdef *func;
- } u;
-};
-
-
-/* action to find_command() */
-#define DO_ERR 0x01 /* prints errors */
-#define DO_ABS 0x02 /* checks absolute paths */
-#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
-#define DO_ALTPATH 0x08 /* using alternate path */
-#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
-
-extern const char *pathopt; /* set by padvance */
-
-void shellexec(char **, char **, const char *, int, int) __dead;
-char *padvance(const char **, const char *, int);
-void find_command(char *, struct cmdentry *, int, const char *);
-int (*find_builtin(char *))(int, char **);
-int (*find_splbltin(char *))(int, char **);
-void hashcd(void);
-void changepath(const char *);
-void deletefuncs(void);
-void getcmdentry(char *, struct cmdentry *);
-union node;
-void defun(char *, union node *, int);
-int unsetfunc(char *);
-void hash_special_builtins(void);
diff --git a/bin/sh/expand.c b/bin/sh/expand.c
deleted file mode 100644
index 955185b..0000000
--- a/bin/sh/expand.c
+++ /dev/null
@@ -1,2125 +0,0 @@
-/* $NetBSD: expand.c,v 1.129 2018/12/03 06:41:30 kre Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- */
-
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)expand.c 8.5 (Berkeley) 5/15/95";
-#else
-__RCSID("$NetBSD: expand.c,v 1.129 2018/12/03 06:41:30 kre Exp $");
-#endif
-#endif /* not lint */
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <dirent.h>
-#include <unistd.h>
-#include <pwd.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <wctype.h>
-#include <wchar.h>
-
-/*
- * Routines to expand arguments to commands. We have to deal with
- * backquotes, shell variables, and file metacharacters.
- */
-
-#include "shell.h"
-#include "main.h"
-#include "nodes.h"
-#include "eval.h"
-#include "expand.h"
-#include "syntax.h"
-#include "arithmetic.h"
-#include "parser.h"
-#include "jobs.h"
-#include "options.h"
-#include "builtins.h"
-#include "var.h"
-#include "input.h"
-#include "output.h"
-#include "memalloc.h"
-#include "error.h"
-#include "mystring.h"
-#include "show.h"
-
-/*
- * Structure specifying which parts of the string should be searched
- * for IFS characters.
- */
-
-struct ifsregion {
- struct ifsregion *next; /* next region in list */
- int begoff; /* offset of start of region */
- int endoff; /* offset of end of region */
- int inquotes; /* search for nul bytes only */
-};
-
-
-char *expdest; /* output of current string */
-struct nodelist *argbackq; /* list of back quote expressions */
-struct ifsregion ifsfirst; /* first struct in list of ifs regions */
-struct ifsregion *ifslastp; /* last struct in list */
-struct arglist exparg; /* holds expanded arg list */
-
-STATIC const char *argstr(const char *, int);
-STATIC const char *exptilde(const char *, int);
-STATIC void expbackq(union node *, int, int);
-STATIC const char *expari(const char *);
-STATIC int subevalvar(const char *, const char *, int, int, int);
-STATIC int subevalvar_trim(const char *, int, int, int, int, int);
-STATIC const char *evalvar(const char *, int);
-STATIC int varisset(const char *, int);
-STATIC void varvalue(const char *, int, int, int);
-STATIC void recordregion(int, int, int);
-STATIC void removerecordregions(int);
-STATIC void ifsbreakup(char *, struct arglist *);
-STATIC void ifsfree(void);
-STATIC void expandmeta(struct strlist *, int);
-STATIC void expmeta(char *, char *);
-STATIC void addfname(char *);
-STATIC struct strlist *expsort(struct strlist *);
-STATIC struct strlist *msort(struct strlist *, int);
-STATIC int patmatch(const char *, const char *, int);
-STATIC char *cvtnum(int, char *);
-static int collate_range_cmp(wchar_t, wchar_t);
-STATIC void add_args(struct strlist *);
-STATIC void rmescapes_nl(char *);
-
-#ifdef DEBUG
-#define NULLTERM_4_TRACE(p) STACKSTRNUL(p)
-#else
-#define NULLTERM_4_TRACE(p) do { /* nothing */ } while (/*CONSTCOND*/0)
-#endif
-
-#define IS_BORING(_ch) \
- ((_ch) == CTLQUOTEMARK || (_ch) == CTLQUOTEEND || (_ch) == CTLNONL)
-#define SKIP_BORING(p) \
- do { \
- char _ch; \
- \
- while ((_ch = *(p)), IS_BORING(_ch)) \
- (p)++; \
- } while (0)
-
-/*
- * Expand shell variables and backquotes inside a here document.
- */
-
-void
-expandhere(union node *arg, int fd)
-{
-
- herefd = fd;
- expandarg(arg, NULL, 0);
- xwrite(fd, stackblock(), expdest - stackblock());
-}
-
-
-static int
-collate_range_cmp(wchar_t c1, wchar_t c2)
-{
- wchar_t s1[2], s2[2];
-
- s1[0] = c1;
- s1[1] = L'\0';
- s2[0] = c2;
- s2[1] = L'\0';
- return (wcscoll(s1, s2));
-}
-
-/*
- * Perform variable substitution and command substitution on an argument,
- * placing the resulting list of arguments in arglist. If EXP_FULL is true,
- * perform splitting and file name expansion. When arglist is NULL, perform
- * here document expansion.
- */
-
-void
-expandarg(union node *arg, struct arglist *arglist, int flag)
-{
- struct strlist *sp;
- char *p;
-
- CTRACE(DBG_EXPAND, ("expandarg(fl=%#x)\n", flag));
- if (fflag) /* no filename expandsion */
- flag &= ~EXP_GLOB;
-
- argbackq = arg->narg.backquote;
- STARTSTACKSTR(expdest);
- ifsfirst.next = NULL;
- ifslastp = NULL;
- line_number = arg->narg.lineno;
- argstr(arg->narg.text, flag);
- if (arglist == NULL) {
- STACKSTRNUL(expdest);
- CTRACE(DBG_EXPAND, ("expandarg: no arglist, done (%d) \"%s\"\n",
- expdest - stackblock(), stackblock()));
- return; /* here document expanded */
- }
- STPUTC('\0', expdest);
- CTRACE(DBG_EXPAND, ("expandarg: arglist got (%d) \"%s\"\n",
- expdest - stackblock() - 1, stackblock()));
- p = grabstackstr(expdest);
- exparg.lastp = &exparg.list;
- /*
- * TODO - EXP_REDIR
- */
- if (flag & EXP_SPLIT) {
- ifsbreakup(p, &exparg);
- *exparg.lastp = NULL;
- exparg.lastp = &exparg.list;
- if (flag & EXP_GLOB)
- expandmeta(exparg.list, flag);
- else
- add_args(exparg.list);
- } else {
- if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
- rmescapes(p);
- sp = stalloc(sizeof(*sp));
- sp->text = p;
- *exparg.lastp = sp;
- exparg.lastp = &sp->next;
- }
- ifsfree();
- *exparg.lastp = NULL;
- if (exparg.list) {
- *arglist->lastp = exparg.list;
- arglist->lastp = exparg.lastp;
- }
-}
-
-
-
-/*
- * Perform variable and command substitution.
- * If EXP_GLOB is set, output CTLESC characters to allow for further processing.
- * If EXP_SPLIT is set, remember location of result for later,
- * Otherwise treat $@ like $* since no splitting will be performed.
- */
-
-STATIC const char *
-argstr(const char *p, int flag)
-{
- char c;
- const int quotes = flag & EXP_QNEEDED; /* do CTLESC */
- int firsteq = 1;
- const char *ifs = NULL;
- int ifs_split = EXP_IFS_SPLIT;
-
- if (flag & EXP_IFS_SPLIT)
- ifs = ifsval();
-
- CTRACE(DBG_EXPAND, ("argstr(\"%s\", %#x) quotes=%#x\n", p,flag,quotes));
-
- if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
- p = exptilde(p, flag);
- for (;;) {
- switch (c = *p++) {
- case '\0':
- NULLTERM_4_TRACE(expdest);
- VTRACE(DBG_EXPAND, ("argstr returning at \"\" "
- "added \"%s\" to expdest\n", stackblock()));
- return p - 1;
- case CTLENDVAR: /* end of expanding yyy in ${xxx-yyy} */
- case CTLENDARI: /* end of a $(( )) string */
- NULLTERM_4_TRACE(expdest);
- VTRACE(DBG_EXPAND, ("argstr returning at \"%.6s\"..."
- " after %2.2X; added \"%s\" to expdest\n",
- p, (c&0xff), stackblock()));
- return p;
- case CTLQUOTEMARK:
- /* "$@" syntax adherence hack */
- if (p[0] == CTLVAR && p[1] & VSQUOTE &&
- p[2] == '@' && p[3] == '=')
- break;
- if ((flag & EXP_SPLIT) != 0)
- STPUTC(c, expdest);
- ifs_split = 0;
- break;
- case CTLNONL:
- if (flag & EXP_NL)
- STPUTC(c, expdest);
- line_number++;
- break;
- case CTLCNL:
- STPUTC('\n', expdest); /* no line_number++ */
- break;
- case CTLQUOTEEND:
- if ((flag & EXP_SPLIT) != 0)
- STPUTC(c, expdest);
- ifs_split = EXP_IFS_SPLIT;
- break;
- case CTLESC:
- if (quotes)
- STPUTC(c, expdest);
- c = *p++;
- STPUTC(c, expdest);
- if (c == '\n') /* should not happen, but ... */
- line_number++;
- break;
- case CTLVAR: {
-#ifdef DEBUG
- unsigned int pos = expdest - stackblock();
- NULLTERM_4_TRACE(expdest);
-#endif
- p = evalvar(p, (flag & ~EXP_IFS_SPLIT) | (flag & ifs_split));
- NULLTERM_4_TRACE(expdest);
- VTRACE(DBG_EXPAND, ("argstr evalvar "
- "added %zd \"%s\" to expdest\n",
- (size_t)(expdest - (stackblock() + pos)),
- stackblock() + pos));
- break;
- }
- case CTLBACKQ:
- case CTLBACKQ|CTLQUOTE: {
-#ifdef DEBUG
- unsigned int pos = expdest - stackblock();
-#endif
- expbackq(argbackq->n, c & CTLQUOTE, flag);
- argbackq = argbackq->next;
- NULLTERM_4_TRACE(expdest);
- VTRACE(DBG_EXPAND, ("argstr expbackq added \"%s\" "
- "to expdest\n", stackblock() + pos));
- break;
- }
- case CTLARI: {
-#ifdef DEBUG
- unsigned int pos = expdest - stackblock();
-#endif
- p = expari(p);
- NULLTERM_4_TRACE(expdest);
- VTRACE(DBG_EXPAND, ("argstr expari "
- "+ \"%s\" to expdest p=\"%.5s...\"\n",
- stackblock() + pos, p));
- break;
- }
- case ':':
- case '=':
- /*
- * sort of a hack - expand tildes in variable
- * assignments (after the first '=' and after ':'s).
- */
- STPUTC(c, expdest);
- if (flag & EXP_VARTILDE && *p == '~') {
- if (c == '=') {
- if (firsteq)
- firsteq = 0;
- else
- break;
- }
- p = exptilde(p, flag);
- }
- break;
- default:
- if (c == '\n')
- line_number++;
- STPUTC(c, expdest);
- if (flag & ifs_split && strchr(ifs, c) != NULL) {
- /* We need to get the output split here... */
- recordregion(expdest - stackblock() - 1,
- expdest - stackblock(), 0);
- }
- break;
- }
- }
-}
-
-STATIC const char *
-exptilde(const char *p, int flag)
-{
- char c;
- const char *startp = p;
- struct passwd *pw;
- const char *home;
- const int quotes = flag & EXP_QNEEDED;
- char *user;
- struct stackmark smark;
-#ifdef DEBUG
- unsigned int offs = expdest - stackblock();
-#endif
-
- setstackmark(&smark);
- (void) grabstackstr(expdest);
- user = stackblock(); /* we will just borrow top of stack */
-
- while ((c = *++p) != '\0') {
- switch(c) {
- case CTLESC: /* any of these occurring */
- case CTLVAR: /* means ~ expansion */
- case CTLBACKQ: /* does not happen at all */
- case CTLBACKQ | CTLQUOTE:
- case CTLARI: /* just leave original unchanged */
- case CTLENDARI:
- case CTLQUOTEMARK:
- case '\n':
- popstackmark(&smark);
- return (startp);
- case CTLNONL:
- continue;
- case ':':
- if (!posix || flag & EXP_VARTILDE)
- goto done;
- break;
- case CTLENDVAR:
- case '/':
- goto done;
- }
- STPUTC(c, user);
- }
- done:
- STACKSTRNUL(user);
- user = stackblock(); /* to start of collected username */
-
- CTRACE(DBG_EXPAND, ("exptilde, found \"~%s\"", user));
- if (*user == '\0') {
- home = lookupvar("HOME");
- /*
- * if HOME is unset, results are unspecified...
- * we used to just leave the ~ unchanged, but
- * (some) other shells do ... and this seems more useful.
- */
- if (home == NULL && (pw = getpwuid(getuid())) != NULL)
- home = pw->pw_dir;
- } else if ((pw = getpwnam(user)) == NULL) {
- /*
- * If user does not exist, results are undefined.
- * so we can abort() here if we want, but let's not!
- */
- home = NULL;
- } else
- home = pw->pw_dir;
-
- VTRACE(DBG_EXPAND, (" ->\"%s\"", home ? home : "<<NULL>>"));
- popstackmark(&smark); /* now expdest is valid again */
-
- /*
- * Posix XCU 2.6.1: The value of $HOME (for ~) or the initial
- * working directory from getpwnam() for ~user
- * Nothing there about "except if a null string". So do what it wants.
- */
- if (home == NULL /* || *home == '\0' */) {
- CTRACE(DBG_EXPAND, (": returning unused \"%s\"\n", startp));
- return startp;
- } while ((c = *home++) != '\0') {
- if (quotes && NEEDESC(c))
- STPUTC(CTLESC, expdest);
- STPUTC(c, expdest);
- }
- CTRACE(DBG_EXPAND, (": added %d \"%.*s\" returning \"%s\"\n",
- expdest - stackblock() - offs, expdest - stackblock() - offs,
- stackblock() + offs, p));
-
- return (p);
-}
-
-
-STATIC void
-removerecordregions(int endoff)
-{
-
- VTRACE(DBG_EXPAND, ("removerecordregions(%d):", endoff));
- if (ifslastp == NULL) {
- VTRACE(DBG_EXPAND, (" none\n", endoff));
- return;
- }
-
- if (ifsfirst.endoff > endoff) {
- VTRACE(DBG_EXPAND, (" first(%d)", ifsfirst.endoff));
- while (ifsfirst.next != NULL) {
- struct ifsregion *ifsp;
- INTOFF;
- ifsp = ifsfirst.next->next;
- ckfree(ifsfirst.next);
- ifsfirst.next = ifsp;
- INTON;
- }
- if (ifsfirst.begoff > endoff)
- ifslastp = NULL;
- else {
- VTRACE(DBG_EXPAND,("->(%d,%d)",ifsfirst.begoff,endoff));
- ifslastp = &ifsfirst;
- ifsfirst.endoff = endoff;
- }
- VTRACE(DBG_EXPAND, ("\n"));
- return;
- }
-
- ifslastp = &ifsfirst;
- while (ifslastp->next && ifslastp->next->begoff < endoff)
- ifslastp=ifslastp->next;
- VTRACE(DBG_EXPAND, (" found(%d,%d)", ifslastp->begoff,ifslastp->endoff));
- while (ifslastp->next != NULL) {
- struct ifsregion *ifsp;
- INTOFF;
- ifsp = ifslastp->next->next;
- ckfree(ifslastp->next);
- ifslastp->next = ifsp;
- INTON;
- }
- if (ifslastp->endoff > endoff)
- ifslastp->endoff = endoff;
- VTRACE(DBG_EXPAND, ("->(%d,%d)", ifslastp->begoff,ifslastp->endoff));
-}
-
-
-/*
- * Expand arithmetic expression.
- *
- * In this incarnation, we start at the beginning (yes, "Let's start at the
- * very beginning. A very good place to start.") and collect the expression
- * until the end - which means expanding anything contained within.
- *
- * Fortunately, argstr() just happens to do that for us...
- */
-STATIC const char *
-expari(const char *p)
-{
- char *q, *start;
- intmax_t result;
- int adjustment;
- int begoff;
- int quoted;
- struct stackmark smark;
-
- /* ifsfree(); */
-
- /*
- * SPACE_NEEDED is enough for all possible digits (rounded up)
- * plus possible "-", and the terminating '\0', hence, plus 2
- *
- * The calculation produces the number of bytes needed to
- * represent the biggest possible value, in octal. We only
- * generate decimal, which takes (often) less digits (never more)
- * so this is safe, if occasionally slightly wasteful.
- */
-#define SPACE_NEEDED ((int)((sizeof(intmax_t) * CHAR_BIT + 2) / 3 + 2))
-
- quoted = *p++ == '"';
- begoff = expdest - stackblock();
- VTRACE(DBG_EXPAND, ("expari%s: \"%s\" begoff %d\n",
- quoted ? "(quoted)" : "", p, begoff));
-
- p = argstr(p, EXP_NL); /* expand $(( )) string */
- STPUTC('\0', expdest);
- start = stackblock() + begoff;
-
- removerecordregions(begoff); /* nothing there is kept */
- rmescapes_nl(start); /* convert CRTNONL back into \n's */
-
- setstackmark(&smark);
- q = grabstackstr(expdest); /* keep the expression while eval'ing */
- result = arith(start, line_number);
- popstackmark(&smark); /* return the stack to before grab */
-
- start = stackblock() + begoff; /* block may have moved */
- adjustment = expdest - start;
- STADJUST(-adjustment, expdest); /* remove the argstr() result */
-
- CHECKSTRSPACE(SPACE_NEEDED, expdest); /* nb: stack block might move */
- fmtstr(expdest, SPACE_NEEDED, "%"PRIdMAX, result);
-
- for (q = expdest; *q++ != '\0'; ) /* find end of what we added */
- ;
-
- if (quoted == 0) /* allow weird splitting */
- recordregion(begoff, begoff + q - 1 - expdest, 0);
- adjustment = q - expdest - 1;
- STADJUST(adjustment, expdest); /* move expdest to end */
- VTRACE(DBG_EXPAND, ("expari: adding %d \"%s\", returning \"%.5s...\"\n",
- adjustment, stackblock() + begoff, p));
-
- return p;
-}
-
-
-/*
- * Expand stuff in backwards quotes (these days, any command substitution).
- */
-
-STATIC void
-expbackq(union node *cmd, int quoted, int flag)
-{
- struct backcmd in;
- int i;
- char buf[128];
- char *p;
- char *dest = expdest; /* expdest may be reused by eval, use an alt */
- struct ifsregion saveifs, *savelastp;
- struct nodelist *saveargbackq;
- char lastc;
- int startloc = dest - stackblock();
- int saveherefd;
- const int quotes = flag & EXP_QNEEDED;
- int nnl;
- struct stackmark smark;
-
- VTRACE(DBG_EXPAND, ("expbackq( ..., q=%d flag=%#x) have %d\n",
- quoted, flag, startloc));
- INTOFF;
- saveifs = ifsfirst;
- savelastp = ifslastp;
- saveargbackq = argbackq;
- saveherefd = herefd;
- herefd = -1;
-
- setstackmark(&smark); /* preserve the stack */
- p = grabstackstr(dest); /* save what we have there currently */
- evalbackcmd(cmd, &in); /* evaluate the $( ) tree (using stack) */
- popstackmark(&smark); /* and return stack to when we entered */
-
- ifsfirst = saveifs;
- ifslastp = savelastp;
- argbackq = saveargbackq;
- herefd = saveherefd;
-
- p = in.buf; /* now extract the results */
- nnl = 0; /* dropping trailing \n's */
- for (;;) {
- if (--in.nleft < 0) {
- if (in.fd < 0)
- break;
- INTON;
- while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR)
- continue;
- INTOFF;
- VTRACE(DBG_EXPAND, ("expbackq: read returns %d\n", i));
- if (i <= 0)
- break;
- p = buf;
- in.nleft = i - 1;
- }
- lastc = *p++;
- if (lastc != '\0') {
- if (lastc == '\n') /* don't save \n yet */
- nnl++; /* it might be trailing */
- else {
- /*
- * We have something other than \n
- *
- * Before saving it, we need to insert
- * any \n's that we have just skipped.
- */
-
- /* XXX
- * this hack is just because our
- * CHECKSTRSPACE() is lazy, and only
- * ever grows the stack once, even
- * if that does not allocate the space
- * we requested. ie: safe for small
- * requests, but not large ones.
- * FIXME someday...
- */
- if (nnl < 20) {
- CHECKSTRSPACE(nnl + 2, dest);
- while (nnl > 0) {
- nnl--;
- USTPUTC('\n', dest);
- }
- } else {
- /* The slower, safer, way */
- while (nnl > 0) {
- nnl--;
- STPUTC('\n', dest);
- }
- CHECKSTRSPACE(2, dest);
- }
- if (quotes && quoted && NEEDESC(lastc))
- USTPUTC(CTLESC, dest);
- USTPUTC(lastc, dest);
- }
- }
- }
-
- if (in.fd >= 0)
- close(in.fd);
- if (in.buf)
- ckfree(in.buf);
- if (in.jp)
- back_exitstatus = waitforjob(in.jp);
- if (quoted == 0)
- recordregion(startloc, dest - stackblock(), 0);
- CTRACE(DBG_EXPAND, ("evalbackq: size=%d: \"%.*s\"\n",
- (int)((dest - stackblock()) - startloc),
- (int)((dest - stackblock()) - startloc),
- stackblock() + startloc));
-
- expdest = dest; /* all done, expdest is all ours again */
- INTON;
-}
-
-
-STATIC int
-subevalvar(const char *p, const char *str, int subtype, int startloc,
- int varflags)
-{
- char *startp;
- int saveherefd = herefd;
- struct nodelist *saveargbackq = argbackq;
- int amount;
-
- herefd = -1;
- VTRACE(DBG_EXPAND, ("subevalvar(%d) \"%.20s\" ${%.*s} sloc=%d vf=%x\n",
- subtype, p, p-str, str, startloc, varflags));
- argstr(p, subtype == VSASSIGN ? EXP_VARTILDE : EXP_TILDE);
- STACKSTRNUL(expdest);
- herefd = saveherefd;
- argbackq = saveargbackq;
- startp = stackblock() + startloc;
-
- switch (subtype) {
- case VSASSIGN:
- setvar(str, startp, 0);
- amount = startp - expdest; /* remove what argstr added */
- STADJUST(amount, expdest);
- varflags &= ~VSNUL; /*XXX Huh? What's that achieve? */
- return 1; /* go back and eval var again */
-
- case VSQUESTION:
- if (*p != CTLENDVAR) {
- outfmt(&errout, "%s\n", startp);
- error(NULL);
- }
- error("%.*s: parameter %snot set",
- (int)(p - str - 1),
- str, (varflags & VSNUL) ? "null or "
- : nullstr);
- /* NOTREACHED */
-
- default:
- abort();
- }
-}
-
-STATIC int
-subevalvar_trim(const char *p, int strloc, int subtype, int startloc,
- int varflags, int quotes)
-{
- char *startp;
- char *str;
- char *loc = NULL;
- char *q;
- int c = 0;
- int saveherefd = herefd;
- struct nodelist *saveargbackq = argbackq;
- int amount;
-
- herefd = -1;
- switch (subtype) {
- case VSTRIMLEFT:
- case VSTRIMLEFTMAX:
- case VSTRIMRIGHT:
- case VSTRIMRIGHTMAX:
- break;
- default:
- abort();
- break;
- }
-
- VTRACE(DBG_EXPAND,
- ("subevalvar_trim(\"%.9s\", STR@%d, SUBT=%d, start@%d, vf=%x, q=%x)\n",
- p, strloc, subtype, startloc, varflags, quotes));
-
- argstr(p, (varflags & (VSQUOTE|VSPATQ)) == VSQUOTE ? 0 : EXP_CASE);
- STACKSTRNUL(expdest);
- herefd = saveherefd;
- argbackq = saveargbackq;
- startp = stackblock() + startloc;
- str = stackblock() + strloc;
-
- switch (subtype) {
-
- case VSTRIMLEFT:
- for (loc = startp; loc < str; loc++) {
- c = *loc;
- *loc = '\0';
- if (patmatch(str, startp, quotes))
- goto recordleft;
- *loc = c;
- if (quotes && *loc == CTLESC)
- loc++;
- }
- return 0;
-
- case VSTRIMLEFTMAX:
- for (loc = str - 1; loc >= startp;) {
- c = *loc;
- *loc = '\0';
- if (patmatch(str, startp, quotes))
- goto recordleft;
- *loc = c;
- loc--;
- if (quotes && loc > startp &&
- *(loc - 1) == CTLESC) {
- for (q = startp; q < loc; q++)
- if (*q == CTLESC)
- q++;
- if (q > loc)
- loc--;
- }
- }
- return 0;
-
- case VSTRIMRIGHT:
- for (loc = str - 1; loc >= startp;) {
- if (patmatch(str, loc, quotes))
- goto recordright;
- loc--;
- if (quotes && loc > startp &&
- *(loc - 1) == CTLESC) {
- for (q = startp; q < loc; q++)
- if (*q == CTLESC)
- q++;
- if (q > loc)
- loc--;
- }
- }
- return 0;
-
- case VSTRIMRIGHTMAX:
- for (loc = startp; loc < str - 1; loc++) {
- if (patmatch(str, loc, quotes))
- goto recordright;
- if (quotes && *loc == CTLESC)
- loc++;
- }
- return 0;
-
- default:
- abort();
- }
-
- recordleft:
- *loc = c;
- amount = ((str - 1) - (loc - startp)) - expdest;
- STADJUST(amount, expdest);
- while (loc != str - 1)
- *startp++ = *loc++;
- return 1;
-
- recordright:
- amount = loc - expdest;
- STADJUST(amount, expdest);
- STPUTC('\0', expdest);
- STADJUST(-1, expdest);
- return 1;
-}
-
-
-/*
- * Expand a variable, and return a pointer to the next character in the
- * input string.
- */
-
-STATIC const char *
-evalvar(const char *p, int flag)
-{
- int subtype;
- int varflags;
- const char *var;
- char *val;
- int patloc;
- int c;
- int set;
- int special;
- int startloc;
- int varlen;
- int apply_ifs;
- const int quotes = flag & EXP_QNEEDED;
-
- varflags = (unsigned char)*p++;
- subtype = varflags & VSTYPE;
- var = p;
- special = !is_name(*p);
- p = strchr(p, '=') + 1;
-
- CTRACE(DBG_EXPAND,
- ("evalvar \"%.*s\", flag=%#X quotes=%#X vf=%#X subtype=%X\n",
- p - var - 1, var, flag, quotes, varflags, subtype));
-
- again: /* jump here after setting a variable with ${var=text} */
- if (varflags & VSLINENO) {
- if (line_num.flags & VUNSET) {
- set = 0;
- val = NULL;
- } else {
- set = 1;
- special = p - var;
- val = NULL;
- }
- } else if (special) {
- set = varisset(var, varflags & VSNUL);
- val = NULL;
- } else {
- val = lookupvar(var);
- if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
- val = NULL;
- set = 0;
- } else
- set = 1;
- }
-
- varlen = 0;
- startloc = expdest - stackblock();
-
- if (!set && uflag && *var != '@' && *var != '*') {
- switch (subtype) {
- case VSNORMAL:
- case VSTRIMLEFT:
- case VSTRIMLEFTMAX:
- case VSTRIMRIGHT:
- case VSTRIMRIGHTMAX:
- case VSLENGTH:
- error("%.*s: parameter not set",
- (int)(p - var - 1), var);
- /* NOTREACHED */
- }
- }
-
- if (!set && subtype != VSPLUS && special && *var == '@')
- if (startloc > 0 && expdest[-1] == CTLQUOTEMARK)
- expdest--, startloc--;
-
- if (set && subtype != VSPLUS) {
- /* insert the value of the variable */
- if (special) {
- if (varflags & VSLINENO) {
- /*
- * The LINENO hack (expansion part)
- */
- while (--special > 0) {
-/* not needed, it is a number...
- if (quotes && NEEDESC(*var))
- STPUTC(CTLESC, expdest);
-*/
- STPUTC(*var++, expdest);
- }
- } else
- varvalue(var, varflags&VSQUOTE, subtype, flag);
- if (subtype == VSLENGTH) {
- varlen = expdest - stackblock() - startloc;
- STADJUST(-varlen, expdest);
- }
- } else {
-
- if (subtype == VSLENGTH) {
- for (;*val; val++)
- varlen++;
- } else if (quotes && varflags & VSQUOTE) {
- for (; (c = *val) != '\0'; val++) {
- if (NEEDESC(c))
- STPUTC(CTLESC, expdest);
- STPUTC(c, expdest);
- }
- } else {
- while (*val)
- STPUTC(*val++, expdest);
- }
- }
- }
-
-
- if (varflags & VSQUOTE) {
- if (*var == '@' && shellparam.nparam != 1)
- apply_ifs = 1;
- else {
- /*
- * Mark so that we don't apply IFS if we recurse through
- * here expanding $bar from "${foo-$bar}".
- */
- flag |= EXP_IN_QUOTES;
- apply_ifs = 0;
- }
- } else if (flag & EXP_IN_QUOTES) {
- apply_ifs = 0;
- } else
- apply_ifs = 1;
-
- switch (subtype) {
- case VSLENGTH:
- expdest = cvtnum(varlen, expdest);
- break;
-
- case VSNORMAL:
- break;
-
- case VSPLUS:
- set = !set;
- /* FALLTHROUGH */
- case VSMINUS:
- if (!set) {
- argstr(p, flag | (apply_ifs ? EXP_IFS_SPLIT : 0));
- /*
- * ${x-a b c} doesn't get split, but removing the
- * 'apply_ifs = 0' apparently breaks ${1+"$@"}..
- * ${x-'a b' c} should generate 2 args.
- */
- if (*p != CTLENDVAR)
- /* We should have marked stuff already */
- apply_ifs = 0;
- }
- break;
-
- case VSTRIMLEFT:
- case VSTRIMLEFTMAX:
- case VSTRIMRIGHT:
- case VSTRIMRIGHTMAX:
- if (!set) {
- set = 1; /* allow argbackq to be advanced if needed */
- break;
- }
- /*
- * Terminate the string and start recording the pattern
- * right after it
- */
- STPUTC('\0', expdest);
- patloc = expdest - stackblock();
- if (subevalvar_trim(p, patloc, subtype, startloc, varflags,
- quotes) == 0) {
- int amount = (expdest - stackblock() - patloc) + 1;
- STADJUST(-amount, expdest);
- }
- /* Remove any recorded regions beyond start of variable */
- removerecordregions(startloc);
- apply_ifs = 1;
- break;
-
- case VSASSIGN:
- case VSQUESTION:
- if (set)
- break;
- if (subevalvar(p, var, subtype, startloc, varflags)) {
- /* if subevalvar() returns, it always returns 1 */
-
- varflags &= ~VSNUL;
- /*
- * Remove any recorded regions beyond
- * start of variable
- */
- removerecordregions(startloc);
- goto again;
- }
- apply_ifs = 0; /* never executed */
- break;
-
- default:
- abort();
- }
-
- if (apply_ifs)
- recordregion(startloc, expdest - stackblock(),
- varflags & VSQUOTE);
-
- if (subtype != VSNORMAL) { /* skip to end of alternative */
- int nesting = 1;
- for (;;) {
- if ((c = *p++) == CTLESC)
- p++;
- else if (c == CTLNONL)
- ;
- else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
- if (set)
- argbackq = argbackq->next;
- } else if (c == CTLVAR) {
- if ((*p++ & VSTYPE) != VSNORMAL)
- nesting++;
- } else if (c == CTLENDVAR) {
- if (--nesting == 0)
- break;
- }
- }
- }
- return p;
-}
-
-
-
-/*
- * Test whether a special parameter is set.
- */
-
-STATIC int
-varisset(const char *name, int nulok)
-{
- if (*name == '!')
- return backgndpid != -1;
- else if (*name == '@' || *name == '*') {
- if (*shellparam.p == NULL)
- return 0;
-
- if (nulok) {
- char **av;
-
- for (av = shellparam.p; *av; av++)
- if (**av != '\0')
- return 1;
- return 0;
- }
- } else if (is_digit(*name)) {
- char *ap;
- long num;
-
- /*
- * handle overflow sensibly (the *ap tests should never fail)
- */
- errno = 0;
- num = strtol(name, &ap, 10);
- if (errno != 0 || (*ap != '\0' && *ap != '='))
- return 0;
-
- if (num == 0)
- ap = arg0;
- else if (num > shellparam.nparam)
- return 0;
- else
- ap = shellparam.p[num - 1];
-
- if (nulok && (ap == NULL || *ap == '\0'))
- return 0;
- }
- return 1;
-}
-
-
-
-/*
- * Add the value of a specialized variable to the stack string.
- */
-
-STATIC void
-varvalue(const char *name, int quoted, int subtype, int flag)
-{
- int num;
- char *p;
- int i;
- int sep;
- char **ap;
-#ifdef DEBUG
- char *start = expdest;
-#endif
-
- VTRACE(DBG_EXPAND, ("varvalue(%c%s, sub=%d, fl=%#x)", *name,
- quoted ? ", quoted" : "", subtype, flag));
-
- if (subtype == VSLENGTH) /* no magic required ... */
- flag &= ~EXP_FULL;
-
-#define STRTODEST(p) \
- do {\
- if ((flag & EXP_QNEEDED) && quoted) { \
- while (*p) { \
- if (NEEDESC(*p)) \
- STPUTC(CTLESC, expdest); \
- STPUTC(*p++, expdest); \
- } \
- } else \
- while (*p) \
- STPUTC(*p++, expdest); \
- } while (0)
-
-
- switch (*name) {
- case '$':
- num = rootpid;
- break;
- case '?':
- num = exitstatus;
- break;
- case '#':
- num = shellparam.nparam;
- break;
- case '!':
- num = backgndpid;
- break;
- case '-':
- for (i = 0; i < option_flags; i++) {
- if (optlist[optorder[i]].val)
- STPUTC(optlist[optorder[i]].letter, expdest);
- }
- VTRACE(DBG_EXPAND, (": %.*s\n", expdest-start, start));
- return;
- case '@':
- if (flag & EXP_SPLIT && quoted) {
- VTRACE(DBG_EXPAND, (": $@ split (%d)\n",
- shellparam.nparam));
- /* GROSS HACK */
- if (shellparam.nparam == 0 &&
- expdest[-1] == CTLQUOTEMARK)
- expdest--;
- /* KCAH SSORG */
- for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
- STRTODEST(p);
- if (*ap)
- /* A NUL separates args inside "" */
- STPUTC('\0', expdest);
- }
- return;
- }
- /* fall through */
- case '*':
- sep = ifsval()[0];
- for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
- STRTODEST(p);
- if (!*ap)
- break;
- if (sep) {
- if (quoted && (flag & EXP_QNEEDED) &&
- NEEDESC(sep))
- STPUTC(CTLESC, expdest);
- STPUTC(sep, expdest);
- } else
- if ((flag & (EXP_SPLIT|EXP_IN_QUOTES)) == EXP_SPLIT
- && !quoted && **ap != '\0')
- STPUTC('\0', expdest);
- }
- VTRACE(DBG_EXPAND, (": %.*s\n", expdest-start, start));
- return;
- default:
- if (is_digit(*name)) {
- long lnum;
-
- errno = 0;
- lnum = strtol(name, &p, 10);
- if (errno != 0 || (*p != '\0' && *p != '='))
- return;
-
- if (lnum == 0)
- p = arg0;
- else if (lnum > 0 && lnum <= shellparam.nparam)
- p = shellparam.p[lnum - 1];
- else
- return;
- STRTODEST(p);
- }
- VTRACE(DBG_EXPAND, (": %.*s\n", expdest-start, start));
- return;
- }
- /*
- * only the specials with an int value arrive here
- */
- VTRACE(DBG_EXPAND, ("(%d)", num));
- expdest = cvtnum(num, expdest);
- VTRACE(DBG_EXPAND, (": %.*s\n", expdest-start, start));
-}
-
-
-
-/*
- * Record the fact that we have to scan this region of the
- * string for IFS characters.
- */
-
-STATIC void
-recordregion(int start, int end, int inquotes)
-{
- struct ifsregion *ifsp;
-
- VTRACE(DBG_EXPAND, ("recordregion(%d,%d,%d)\n", start, end, inquotes));
- if (ifslastp == NULL) {
- ifsp = &ifsfirst;
- } else {
- if (ifslastp->endoff == start
- && ifslastp->inquotes == inquotes) {
- /* extend previous area */
- ifslastp->endoff = end;
- return;
- }
- ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
- ifslastp->next = ifsp;
- }
- ifslastp = ifsp;
- ifslastp->next = NULL;
- ifslastp->begoff = start;
- ifslastp->endoff = end;
- ifslastp->inquotes = inquotes;
-}
-
-
-
-/*
- * Break the argument string into pieces based upon IFS and add the
- * strings to the argument list. The regions of the string to be
- * searched for IFS characters have been stored by recordregion.
- */
-STATIC void
-ifsbreakup(char *string, struct arglist *arglist)
-{
- struct ifsregion *ifsp;
- struct strlist *sp;
- char *start;
- char *p;
- char *q;
- const char *ifs;
- const char *ifsspc;
- int had_param_ch = 0;
-
- start = string;
-
- VTRACE(DBG_EXPAND, ("ifsbreakup(\"%s\")", string)); /* misses \0's */
- if (ifslastp == NULL) {
- /* Return entire argument, IFS doesn't apply to any of it */
- VTRACE(DBG_EXPAND, ("no regions\n", string));
- sp = stalloc(sizeof(*sp));
- sp->text = start;
- *arglist->lastp = sp;
- arglist->lastp = &sp->next;
- return;
- }
-
- ifs = ifsval();
-
- for (ifsp = &ifsfirst; ifsp != NULL; ifsp = ifsp->next) {
- p = string + ifsp->begoff;
- VTRACE(DBG_EXPAND, (" !%.*s!(%d)", ifsp->endoff-ifsp->begoff,
- p, ifsp->endoff-ifsp->begoff));
- while (p < string + ifsp->endoff) {
- had_param_ch = 1;
- q = p;
- if (IS_BORING(*p)) {
- p++;
- continue;
- }
- if (*p == CTLESC)
- p++;
- if (ifsp->inquotes) {
- /* Only NULs (should be from "$@") end args */
- if (*p != 0) {
- p++;
- continue;
- }
- ifsspc = NULL;
- VTRACE(DBG_EXPAND, (" \\0 nxt:\"%s\" ", p));
- } else {
- if (!strchr(ifs, *p)) {
- p++;
- continue;
- }
- had_param_ch = 0;
- ifsspc = strchr(" \t\n", *p);
-
- /* Ignore IFS whitespace at start */
- if (q == start && ifsspc != NULL) {
- p++;
- start = p;
- continue;
- }
- }
-
- /* Save this argument... */
- *q = '\0';
- VTRACE(DBG_EXPAND, ("<%s>", start));
- sp = stalloc(sizeof(*sp));
- sp->text = start;
- *arglist->lastp = sp;
- arglist->lastp = &sp->next;
- p++;
-
- if (ifsspc != NULL) {
- /* Ignore further trailing IFS whitespace */
- for (; p < string + ifsp->endoff; p++) {
- q = p;
- if (*p == CTLNONL)
- continue;
- if (*p == CTLESC)
- p++;
- if (strchr(ifs, *p) == NULL) {
- p = q;
- break;
- }
- if (strchr(" \t\n", *p) == NULL) {
- p++;
- break;
- }
- }
- }
- start = p;
- }
- }
-
- while (*start == CTLQUOTEEND)
- start++;
-
- /*
- * Save anything left as an argument.
- * Traditionally we have treated 'IFS=':'; set -- x$IFS' as
- * generating 2 arguments, the second of which is empty.
- * Some recent clarification of the Posix spec say that it
- * should only generate one....
- */
- if (had_param_ch || *start != 0) {
- VTRACE(DBG_EXPAND, (" T<%s>", start));
- sp = stalloc(sizeof(*sp));
- sp->text = start;
- *arglist->lastp = sp;
- arglist->lastp = &sp->next;
- }
- VTRACE(DBG_EXPAND, ("\n"));
-}
-
-STATIC void
-ifsfree(void)
-{
- while (ifsfirst.next != NULL) {
- struct ifsregion *ifsp;
- INTOFF;
- ifsp = ifsfirst.next->next;
- ckfree(ifsfirst.next);
- ifsfirst.next = ifsp;
- INTON;
- }
- ifslastp = NULL;
- ifsfirst.next = NULL;
-}
-
-
-
-/*
- * Expand shell metacharacters. At this point, the only control characters
- * should be escapes. The results are stored in the list exparg.
- */
-
-char *expdir;
-
-
-STATIC void
-expandmeta(struct strlist *str, int flag)
-{
- char *p;
- struct strlist **savelastp;
- struct strlist *sp;
- char c;
- /* TODO - EXP_REDIR */
-
- while (str) {
- p = str->text;
- for (;;) { /* fast check for meta chars */
- if ((c = *p++) == '\0')
- goto nometa;
- if (c == '*' || c == '?' || c == '[' /* || c == '!' */)
- break;
- }
- savelastp = exparg.lastp;
- INTOFF;
- if (expdir == NULL) {
- int i = strlen(str->text);
- expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
- }
-
- expmeta(expdir, str->text);
- ckfree(expdir);
- expdir = NULL;
- INTON;
- if (exparg.lastp == savelastp) {
- /*
- * no matches
- */
- nometa:
- *exparg.lastp = str;
- rmescapes(str->text);
- exparg.lastp = &str->next;
- } else {
- *exparg.lastp = NULL;
- *savelastp = sp = expsort(*savelastp);
- while (sp->next != NULL)
- sp = sp->next;
- exparg.lastp = &sp->next;
- }
- str = str->next;
- }
-}
-
-STATIC void
-add_args(struct strlist *str)
-{
- while (str) {
- *exparg.lastp = str;
- rmescapes(str->text);
- exparg.lastp = &str->next;
- str = str->next;
- }
-}
-
-
-/*
- * Do metacharacter (i.e. *, ?, [...]) expansion.
- */
-
-STATIC void
-expmeta(char *enddir, char *name)
-{
- char *p;
- const char *cp;
- char *q;
- char *start;
- char *endname;
- int metaflag;
- struct stat statb;
- DIR *dirp;
- struct dirent *dp;
- int atend;
- int matchdot;
-
- CTRACE(DBG_EXPAND|DBG_MATCH, ("expmeta(\"%s\")\n", name));
- metaflag = 0;
- start = name;
- for (p = name ; ; p++) {
- if (*p == '*' || *p == '?')
- metaflag = 1;
- else if (*p == '[') {
- q = p + 1;
- if (*q == '!' || *q == '^')
- q++;
- for (;;) {
- while (IS_BORING(*q))
- q++;
- if (*q == ']') {
- q++;
- metaflag = 1;
- break;
- }
- if (*q == '[' && q[1] == ':') {
- /*
- * character class, look for :] ending
- * also stop on ']' (end bracket expr)
- * or '\0' or '/' (end pattern)
- */
- while (*++q != '\0' && *q != ']' &&
- *q != '/') {
- if (*q == CTLESC) {
- if (*++q == '\0')
- break;
- if (*q == '/')
- break;
- } else if (*q == ':' &&
- q[1] == ']')
- break;
- }
- if (*q == ':') {
- /*
- * stopped at ':]'
- * still in [...]
- * skip ":]" and continue;
- */
- q += 2;
- continue;
- }
-
- /* done at end of pattern, not [...] */
- if (*q == '\0' || *q == '/')
- break;
-
- /* found the ']', we have a [...] */
- metaflag = 1;
- q++; /* skip ']' */
- break;
- }
- if (*q == CTLESC)
- q++;
- /* end of pattern cannot be escaped */
- if (*q == '/' || *q == '\0')
- break;
- q++;
- }
- } else if (*p == '\0')
- break;
- else if (IS_BORING(*p))
- continue;
- else if (*p == CTLESC)
- p++;
- if (*p == '/') {
- if (metaflag)
- break;
- start = p + 1;
- }
- }
- if (metaflag == 0) { /* we've reached the end of the file name */
- if (enddir != expdir)
- metaflag++;
- for (p = name ; ; p++) {
- if (IS_BORING(*p))
- continue;
- if (*p == CTLESC)
- p++;
- *enddir++ = *p;
- if (*p == '\0')
- break;
- }
- if (metaflag == 0 || lstat(expdir, &statb) >= 0)
- addfname(expdir);
- return;
- }
- endname = p;
- if (start != name) {
- p = name;
- while (p < start) {
- while (IS_BORING(*p))
- p++;
- if (*p == CTLESC)
- p++;
- *enddir++ = *p++;
- }
- }
- if (enddir == expdir) {
- cp = ".";
- } else if (enddir == expdir + 1 && *expdir == '/') {
- cp = "/";
- } else {
- cp = expdir;
- enddir[-1] = '\0';
- }
- if ((dirp = opendir(cp)) == NULL)
- return;
- if (enddir != expdir)
- enddir[-1] = '/';
- if (*endname == 0) {
- atend = 1;
- } else {
- atend = 0;
- *endname++ = '\0';
- }
- matchdot = 0;
- p = start;
- while (IS_BORING(*p))
- p++;
- if (*p == CTLESC)
- p++;
- if (*p == '.')
- matchdot++;
- while (! int_pending() && (dp = readdir(dirp)) != NULL) {
- if (dp->d_name[0] == '.' && ! matchdot)
- continue;
- if (patmatch(start, dp->d_name, 0)) {
- if (atend) {
- scopy(dp->d_name, enddir);
- addfname(expdir);
- } else {
- for (p = enddir, cp = dp->d_name;
- (*p++ = *cp++) != '\0';)
- continue;
- p[-1] = '/';
- expmeta(p, endname);
- }
- }
- }
- closedir(dirp);
- if (! atend)
- endname[-1] = '/';
-}
-
-
-/*
- * Add a file name to the list.
- */
-
-STATIC void
-addfname(char *name)
-{
- char *p;
- struct strlist *sp;
-
- p = stalloc(strlen(name) + 1);
- scopy(name, p);
- sp = stalloc(sizeof(*sp));
- sp->text = p;
- *exparg.lastp = sp;
- exparg.lastp = &sp->next;
-}
-
-
-/*
- * Sort the results of file name expansion. It calculates the number of
- * strings to sort and then calls msort (short for merge sort) to do the
- * work.
- */
-
-STATIC struct strlist *
-expsort(struct strlist *str)
-{
- int len;
- struct strlist *sp;
-
- len = 0;
- for (sp = str ; sp ; sp = sp->next)
- len++;
- return msort(str, len);
-}
-
-
-STATIC struct strlist *
-msort(struct strlist *list, int len)
-{
- struct strlist *p, *q = NULL;
- struct strlist **lpp;
- int half;
- int n;
-
- if (len <= 1)
- return list;
- half = len >> 1;
- p = list;
- for (n = half ; --n >= 0 ; ) {
- q = p;
- p = p->next;
- }
- q->next = NULL; /* terminate first half of list */
- q = msort(list, half); /* sort first half of list */
- p = msort(p, len - half); /* sort second half */
- lpp = &list;
- for (;;) {
- if (strcmp(p->text, q->text) < 0) {
- *lpp = p;
- lpp = &p->next;
- if ((p = *lpp) == NULL) {
- *lpp = q;
- break;
- }
- } else {
- *lpp = q;
- lpp = &q->next;
- if ((q = *lpp) == NULL) {
- *lpp = p;
- break;
- }
- }
- }
- return list;
-}
-
-
-/*
- * See if a character matches a character class, starting at the first colon
- * of "[:class:]".
- * If a valid character class is recognized, a pointer to the next character
- * after the final closing bracket is stored into *end, otherwise a null
- * pointer is stored into *end.
- */
-static int
-match_charclass(const char *p, wchar_t chr, const char **end)
-{
- char name[20];
- char *nameend;
- wctype_t cclass;
-
- *end = NULL;
- p++;
- nameend = strstr(p, ":]");
- if (nameend == NULL || nameend == p) /* not a valid class */
- return 0;
-
- if (!is_alpha(*p) || strspn(p, /* '_' is a local extension */
- "0123456789" "_"
- "abcdefghijklmnopqrstuvwxyz"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ") != (size_t)(nameend - p))
- return 0;
-
- *end = nameend + 2; /* committed to it being a char class */
- if ((size_t)(nameend - p) >= sizeof(name)) /* but too long */
- return 0; /* so no match */
- memcpy(name, p, nameend - p);
- name[nameend - p] = '\0';
- cclass = wctype(name);
- /* An unknown class matches nothing but is valid nevertheless. */
- if (cclass == 0)
- return 0;
- return iswctype(chr, cclass);
-}
-
-
-/*
- * Returns true if the pattern matches the string.
- */
-
-STATIC int
-patmatch(const char *pattern, const char *string, int squoted)
-{
- const char *p, *q, *end;
- const char *bt_p, *bt_q;
- char c;
- wchar_t wc, wc2;
-
- VTRACE(DBG_MATCH, ("patmatch(P=\"%s\", W=\"%s\"%s): ",
- pattern, string, squoted ? ", SQ" : ""));
- p = pattern;
- q = string;
- bt_p = NULL;
- bt_q = NULL;
- for (;;) {
- switch (c = *p++) {
- case '\0':
- if (squoted && *q == CTLESC) {
- if (q[1] == '\0')
- q++;
- }
- if (*q != '\0')
- goto backtrack;
- VTRACE(DBG_MATCH, ("match\n"));
- return 1;
- case CTLESC:
- if (squoted && *q == CTLESC)
- q++;
- if (*p == '\0' && *q == '\0') {
- VTRACE(DBG_MATCH, ("match-\\\n"));
- return 1;
- }
- if (*q++ != *p++)
- goto backtrack;
- break;
- case '\\':
- if (squoted && *q == CTLESC)
- q++;
- if (*q++ != *p++)
- goto backtrack;
- break;
- case CTLQUOTEMARK:
- case CTLQUOTEEND:
- case CTLNONL:
- continue;
- case '?':
- if (squoted && *q == CTLESC)
- q++;
- if (*q++ == '\0') {
- VTRACE(DBG_MATCH, ("?fail\n"));
- return 0;
- }
- break;
- case '*':
- c = *p;
- while (c == CTLQUOTEMARK || c == '*')
- c = *++p;
- if (c != CTLESC && !IS_BORING(c) &&
- c != '?' && c != '*' && c != '[') {
- while (*q != c) {
- if (squoted && *q == CTLESC &&
- q[1] == c)
- break;
- if (*q == '\0') {
- VTRACE(DBG_MATCH, ("*fail\n"));
- return 0;
- }
- if (squoted && *q == CTLESC)
- q++;
- q++;
- }
- }
- if (c == CTLESC && p[1] == '\0') {
- VTRACE(DBG_MATCH, ("match+\\\n"));
- return 1;
- }
- /*
- * First try the shortest match for the '*' that
- * could work. We can forget any earlier '*' since
- * there is no way having it match more characters
- * can help us, given that we are already here.
- */
- bt_p = p;
- bt_q = q;
- break;
- case '[': {
- const char *savep, *saveq, *endp;
- int invert, found;
- unsigned char chr;
-
- /*
- * First quick check to see if there is a
- * possible matching ']' - if not, then this
- * is not a char class, and the '[' is just
- * a literal '['.
- *
- * This check will not detect all non classes, but
- * that's OK - It just means that we execute the
- * harder code sometimes when it it cannot succeed.
- */
- endp = p;
- if (*endp == '!' || *endp == '^')
- endp++;
- for (;;) {
- while (IS_BORING(*endp))
- endp++;
- if (*endp == '\0')
- goto dft; /* no matching ] */
- if (*endp++ == ']')
- break;
- }
- /* end shortcut */
-
- invert = 0;
- savep = p, saveq = q;
- invert = 0;
- if (*p == '!' || *p == '^') {
- invert++;
- p++;
- }
- found = 0;
- if (*q == '\0') {
- VTRACE(DBG_MATCH, ("[]fail\n"));
- return 0;
- }
- if (squoted && *q == CTLESC)
- q++;
- chr = (unsigned char)*q++;
- c = *p++;
- do {
- if (IS_BORING(c))
- continue;
- if (c == '\0') {
- p = savep, q = saveq;
- c = '[';
- goto dft;
- }
- if (c == '[' && *p == ':') {
- found |= match_charclass(p, chr, &end);
- if (end != NULL) {
- p = end;
- continue;
- }
- }
- if (c == CTLESC || c == '\\')
- c = *p++;
- wc = (unsigned char)c;
- if (*p == '-' && p[1] != ']') {
- p++;
- if (*p == CTLESC || *p == '\\')
- p++;
- wc2 = (unsigned char)*p++;
- if ( collate_range_cmp(chr, wc) >= 0
- && collate_range_cmp(chr, wc2) <= 0
- )
- found = 1;
- } else {
- if (chr == wc)
- found = 1;
- }
- } while ((c = *p++) != ']');
- if (found == invert)
- goto backtrack;
- break;
- }
- dft: default:
- if (squoted && *q == CTLESC)
- q++;
- if (*q++ == c)
- break;
- backtrack:
- /*
- * If we have a mismatch (other than hitting the end
- * of the string), go back to the last '*' seen and
- * have it match one additional character.
- */
- if (bt_p == NULL) {
- VTRACE(DBG_MATCH, ("BTP fail\n"));
- return 0;
- }
- if (*bt_q == '\0') {
- VTRACE(DBG_MATCH, ("BTQ fail\n"));
- return 0;
- }
- bt_q++;
- p = bt_p;
- q = bt_q;
- break;
- }
- }
-}
-
-
-
-/*
- * Remove any CTLESC or CTLNONL characters from a string.
- */
-
-void
-rmescapes(char *str)
-{
- char *p, *q;
-
- p = str;
- while (*p != CTLESC && !IS_BORING(*p)) {
- if (*p++ == '\0')
- return;
- }
- q = p;
- while (*p) {
- if (IS_BORING(*p)) {
- p++;
- continue;
- }
- if (*p == CTLCNL) {
- p++;
- *q++ = '\n';
- continue;
- }
- if (*p == CTLESC)
- p++;
- *q++ = *p++;
- }
- *q = '\0';
-}
-
-/*
- * and a special version for dealing with expressions to be parsed
- * by the arithmetic evaluator. That needs to be able to count \n's
- * even ones that were \newline elided \n's, so we have to put the
- * latter back into the string - just being careful to put them only
- * at a place where white space can reasonably occur in the string
- * -- then the \n we insert will just be white space, and ignored
- * for all purposes except line counting.
- */
-
-void
-rmescapes_nl(char *str)
-{
- char *p, *q;
- int nls = 0, holdnl = 0, holdlast;
-
- p = str;
- while (*p != CTLESC && !IS_BORING(*p)) {
- if (*p++ == '\0')
- return;
- }
- if (p > str) /* must reprocess char before stopper (if any) */
- --p; /* so we do not place a \n badly */
- q = p;
- while (*p) {
- if (*p == CTLQUOTEMARK || *p == CTLQUOTEEND) {
- p++;
- continue;
- }
- if (*p == CTLNONL) {
- p++;
- nls++;
- continue;
- }
- if (*p == CTLCNL) {
- p++;
- *q++ = '\n';
- continue;
- }
- if (*p == CTLESC)
- p++;
-
- holdlast = holdnl;
- holdnl = is_in_name(*p); /* letters, digits, _ */
- if (q == str || is_space(q[-1]) || (*p != '=' && q[-1] != *p)) {
- if (nls > 0 && holdnl != holdlast) {
- while (nls > 0)
- *q++ = '\n', nls--;
- }
- }
- *q++ = *p++;
- }
- while (--nls >= 0)
- *q++ = '\n';
- *q = '\0';
-}
-
-
-
-/*
- * See if a pattern matches in a case statement.
- */
-
-int
-casematch(union node *pattern, char *val)
-{
- struct stackmark smark;
- int result;
- char *p;
-
- CTRACE(DBG_MATCH, ("casematch(P=\"%s\", W=\"%s\")\n",
- pattern->narg.text, val));
- setstackmark(&smark);
- argbackq = pattern->narg.backquote;
- STARTSTACKSTR(expdest);
- ifslastp = NULL;
- argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
- STPUTC('\0', expdest);
- p = grabstackstr(expdest);
- result = patmatch(p, val, 0);
- popstackmark(&smark);
- return result;
-}
-
-/*
- * Our own itoa(). Assumes result buffer is on the stack
- */
-
-STATIC char *
-cvtnum(int num, char *buf)
-{
- char temp[32];
- int neg = num < 0;
- char *p = temp + sizeof temp - 1;
-
- if (neg)
- num = -num;
-
- *p = '\0';
- do {
- *--p = num % 10 + '0';
- } while ((num /= 10) != 0 && p > temp + 1);
-
- if (neg)
- *--p = '-';
-
- while (*p)
- STPUTC(*p++, buf);
- return buf;
-}
-
-/*
- * Do most of the work for wordexp(3).
- */
-
-int
-wordexpcmd(int argc, char **argv)
-{
- size_t len;
- int i;
-
- out1fmt("%d", argc - 1);
- out1c('\0');
- for (i = 1, len = 0; i < argc; i++)
- len += strlen(argv[i]);
- out1fmt("%zu", len);
- out1c('\0');
- for (i = 1; i < argc; i++) {
- out1str(argv[i]);
- out1c('\0');
- }
- return (0);
-}
diff --git a/bin/sh/expand.h b/bin/sh/expand.h
deleted file mode 100644
index d435fd8..0000000
--- a/bin/sh/expand.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/* $NetBSD: expand.h,v 1.24 2018/11/18 17:23:37 kre Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- *
- * @(#)expand.h 8.2 (Berkeley) 5/4/95
- */
-
-#include <inttypes.h>
-
-struct strlist {
- struct strlist *next;
- char *text;
-};
-
-
-struct arglist {
- struct strlist *list;
- struct strlist **lastp;
-};
-
-/*
- * expandarg() flags
- */
-#define EXP_SPLIT 0x1 /* perform word splitting */
-#define EXP_TILDE 0x2 /* do normal tilde expansion */
-#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
-#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
-#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
-#define EXP_IFS_SPLIT 0x20 /* need to record arguments for ifs breakup */
-#define EXP_IN_QUOTES 0x40 /* don't set EXP_IFS_SPLIT again */
-#define EXP_GLOB 0x80 /* perform filename globbing */
-#define EXP_NL 0x100 /* keep CRTNONL in output */
-
-#define EXP_FULL (EXP_SPLIT | EXP_GLOB)
-#define EXP_QNEEDED (EXP_GLOB | EXP_CASE | EXP_REDIR)
-
-union node;
-
-void expandhere(union node *, int);
-void expandarg(union node *, struct arglist *, int);
-void rmescapes(char *);
-int casematch(union node *, char *);
diff --git a/bin/sh/funcs/cmv b/bin/sh/funcs/cmv
deleted file mode 100644
index 0e3eef6..0000000
--- a/bin/sh/funcs/cmv
+++ /dev/null
@@ -1,43 +0,0 @@
-# $NetBSD: cmv,v 1.8 2016/02/29 23:50:59 christos Exp $
-# Copyright (c) 1991, 1993
-# The Regents of the University of California. All rights reserved.
-#
-# This code is derived from software contributed to Berkeley by
-# Kenneth Almquist.
-#
-# 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.
-#
-# 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.
-#
-# @(#)cmv 8.2 (Berkeley) 5/4/95
-
-# Conditional move--don't replace an existing file.
-
-cmv() {
- if test $# != 2
- then echo "cmv: arg count"
- return 2
- fi
- if test -f "$2" -o -w "$2"
- then echo "$2 exists"
- return 2
- fi
- /bin/mv "$1" "$2"
-}
diff --git a/bin/sh/funcs/dirs b/bin/sh/funcs/dirs
deleted file mode 100644
index ef2ae0a..0000000
--- a/bin/sh/funcs/dirs
+++ /dev/null
@@ -1,67 +0,0 @@
-# $NetBSD: dirs,v 1.8 2016/02/29 23:50:59 christos Exp $
-# Copyright (c) 1991, 1993
-# The Regents of the University of California. All rights reserved.
-#
-# This code is derived from software contributed to Berkeley by
-# Kenneth Almquist.
-#
-# 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.
-#
-# 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.
-#
-# @(#)dirs 8.2 (Berkeley) 5/4/95
-
-# pushd, popd, and dirs --- written by Chris Bertin
-# Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris
-# as modified by Patrick Elam of GTRI and Kenneth Almquist at UW
-
-pushd () {
- SAVE=`pwd`
- if [ "$1" = "" ]
- then if [ "$DSTACK" = "" ]
- then echo "pushd: directory stack empty."
- return 1
- fi
- set $DSTACK
- cd $1 || return
- shift 1
- DSTACK="$*"
- else cd $1 > /dev/null || return
- fi
- DSTACK="$SAVE $DSTACK"
- dirs
-}
-
-popd () {
- if [ "$DSTACK" = "" ]
- then echo "popd: directory stack empty."
- return 1
- fi
- set $DSTACK
- cd $1
- shift
- DSTACK=$*
- dirs
-}
-
-dirs () {
- echo "`pwd` $DSTACK"
- return 0
-}
diff --git a/bin/sh/funcs/kill b/bin/sh/funcs/kill
deleted file mode 100644
index 70f2b27..0000000
--- a/bin/sh/funcs/kill
+++ /dev/null
@@ -1,43 +0,0 @@
-# $NetBSD: kill,v 1.8 2016/02/29 23:50:59 christos Exp $
-# Copyright (c) 1991, 1993
-# The Regents of the University of California. All rights reserved.
-#
-# This code is derived from software contributed to Berkeley by
-# Kenneth Almquist.
-#
-# 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.
-#
-# 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.
-#
-# @(#)kill 8.2 (Berkeley) 5/4/95
-
-# Convert job names to process ids and then run /bin/kill.
-
-kill() {
- local args x
- args=
- for x in "$@"
- do case $x in
- %*) x=`jobid "$x"` ;;
- esac
- args="$args $x"
- done
- /bin/kill $args
-}
diff --git a/bin/sh/funcs/login b/bin/sh/funcs/login
deleted file mode 100644
index a2fe60e..0000000
--- a/bin/sh/funcs/login
+++ /dev/null
@@ -1,32 +0,0 @@
-# $NetBSD: login,v 1.8 2016/02/29 23:50:59 christos Exp $
-# Copyright (c) 1991, 1993
-# The Regents of the University of California. All rights reserved.
-#
-# This code is derived from software contributed to Berkeley by
-# Kenneth Almquist.
-#
-# 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.
-#
-# 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.
-#
-# @(#)login 8.2 (Berkeley) 5/4/95
-
-# replaces the login builtin in the BSD shell
-login () exec login "$@"
diff --git a/bin/sh/funcs/newgrp b/bin/sh/funcs/newgrp
deleted file mode 100644
index 1ad46a3..0000000
--- a/bin/sh/funcs/newgrp
+++ /dev/null
@@ -1,31 +0,0 @@
-# $NetBSD: newgrp,v 1.8 2016/02/29 23:50:59 christos Exp $
-# Copyright (c) 1991, 1993
-# The Regents of the University of California. All rights reserved.
-#
-# This code is derived from software contributed to Berkeley by
-# Kenneth Almquist.
-#
-# 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.
-#
-# 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.
-#
-# @(#)newgrp 8.2 (Berkeley) 5/4/95
-
-newgrp() exec newgrp "$@"
diff --git a/bin/sh/funcs/popd b/bin/sh/funcs/popd
deleted file mode 100644
index 836741c..0000000
--- a/bin/sh/funcs/popd
+++ /dev/null
@@ -1,67 +0,0 @@
-# $NetBSD: popd,v 1.8 2016/02/29 23:50:59 christos Exp $
-# Copyright (c) 1991, 1993
-# The Regents of the University of California. All rights reserved.
-#
-# This code is derived from software contributed to Berkeley by
-# Kenneth Almquist.
-#
-# 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.
-#
-# 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.
-#
-# @(#)popd 8.2 (Berkeley) 5/4/95
-
-# pushd, popd, and dirs --- written by Chris Bertin
-# Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris
-# as modified by Patrick Elam of GTRI and Kenneth Almquist at UW
-
-pushd () {
- SAVE=`pwd`
- if [ "$1" = "" ]
- then if [ "$DSTACK" = "" ]
- then echo "pushd: directory stack empty."
- return 1
- fi
- set $DSTACK
- cd $1 || return
- shift 1
- DSTACK="$*"
- else cd $1 > /dev/null || return
- fi
- DSTACK="$SAVE $DSTACK"
- dirs
-}
-
-popd () {
- if [ "$DSTACK" = "" ]
- then echo "popd: directory stack empty."
- return 1
- fi
- set $DSTACK
- cd $1
- shift
- DSTACK=$*
- dirs
-}
-
-dirs () {
- echo "`pwd` $DSTACK"
- return 0
-}
diff --git a/bin/sh/funcs/pushd b/bin/sh/funcs/pushd
deleted file mode 100644
index c6ec1af..0000000
--- a/bin/sh/funcs/pushd
+++ /dev/null
@@ -1,67 +0,0 @@
-# $NetBSD: pushd,v 1.8 2016/02/29 23:50:59 christos Exp $
-# Copyright (c) 1991, 1993
-# The Regents of the University of California. All rights reserved.
-#
-# This code is derived from software contributed to Berkeley by
-# Kenneth Almquist.
-#
-# 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.
-#
-# 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.
-#
-# @(#)pushd 8.2 (Berkeley) 5/4/95
-
-# pushd, popd, and dirs --- written by Chris Bertin
-# Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris
-# as modified by Patrick Elam of GTRI and Kenneth Almquist at UW
-
-pushd () {
- SAVE=`pwd`
- if [ "$1" = "" ]
- then if [ "$DSTACK" = "" ]
- then echo "pushd: directory stack empty."
- return 1
- fi
- set $DSTACK
- cd $1 || return
- shift 1
- DSTACK="$*"
- else cd $1 > /dev/null || return
- fi
- DSTACK="$SAVE $DSTACK"
- dirs
-}
-
-popd () {
- if [ "$DSTACK" = "" ]
- then echo "popd: directory stack empty."
- return 1
- fi
- set $DSTACK
- cd $1
- shift
- DSTACK=$*
- dirs
-}
-
-dirs () {
- echo "`pwd` $DSTACK"
- return 0
-}
diff --git a/bin/sh/funcs/suspend b/bin/sh/funcs/suspend
deleted file mode 100644
index 7643f43..0000000
--- a/bin/sh/funcs/suspend
+++ /dev/null
@@ -1,35 +0,0 @@
-# $NetBSD: suspend,v 1.8 2016/02/29 23:50:59 christos Exp $
-# Copyright (c) 1991, 1993
-# The Regents of the University of California. All rights reserved.
-#
-# This code is derived from software contributed to Berkeley by
-# Kenneth Almquist.
-#
-# 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.
-#
-# 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.
-#
-# @(#)suspend 8.2 (Berkeley) 5/4/95
-
-suspend() {
- local -
- set +j
- kill -TSTP 0
-}
diff --git a/bin/sh/histedit.c b/bin/sh/histedit.c
deleted file mode 100644
index 5de3adc..0000000
--- a/bin/sh/histedit.c
+++ /dev/null
@@ -1,576 +0,0 @@
-/* $NetBSD: histedit.c,v 1.53 2018/07/13 22:43:44 kre Exp $ */
-
-/*-
- * Copyright (c) 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- */
-
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)histedit.c 8.2 (Berkeley) 5/4/95";
-#else
-__RCSID("$NetBSD: histedit.c,v 1.53 2018/07/13 22:43:44 kre Exp $");
-#endif
-#endif /* not lint */
-
-#include <sys/param.h>
-#include <paths.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-/*
- * Editline and history functions (and glue).
- */
-#include "shell.h"
-#include "parser.h"
-#include "var.h"
-#include "options.h"
-#include "builtins.h"
-#include "main.h"
-#include "output.h"
-#include "mystring.h"
-#include "myhistedit.h"
-#include "error.h"
-#include "alias.h"
-#ifndef SMALL
-#include "eval.h"
-#include "memalloc.h"
-
-#define MAXHISTLOOPS 4 /* max recursions through fc */
-#define DEFEDITOR "ed" /* default editor *should* be $EDITOR */
-
-History *hist; /* history cookie */
-EditLine *el; /* editline cookie */
-int displayhist;
-static FILE *el_in, *el_out;
-unsigned char _el_fn_complete(EditLine *, int);
-
-STATIC const char *fc_replace(const char *, char *, char *);
-
-#ifdef DEBUG
-extern FILE *tracefile;
-#endif
-
-/*
- * Set history and editing status. Called whenever the status may
- * have changed (figures out what to do).
- */
-void
-histedit(void)
-{
- FILE *el_err;
-
-#define editing (Eflag || Vflag)
-
- if (iflag == 1) {
- if (!hist) {
- /*
- * turn history on
- */
- INTOFF;
- hist = history_init();
- INTON;
-
- if (hist != NULL)
- sethistsize(histsizeval());
- else
- out2str("sh: can't initialize history\n");
- }
- if (editing && !el && isatty(0)) { /* && isatty(2) ??? */
- /*
- * turn editing on
- */
- char *term, *shname;
-
- INTOFF;
- if (el_in == NULL)
- el_in = fdopen(0, "r");
- if (el_out == NULL)
- el_out = fdopen(2, "w");
- if (el_in == NULL || el_out == NULL)
- goto bad;
- el_err = el_out;
-#if DEBUG
- if (tracefile)
- el_err = tracefile;
-#endif
- term = lookupvar("TERM");
- if (term)
- setenv("TERM", term, 1);
- else
- unsetenv("TERM");
- shname = arg0;
- if (shname[0] == '-')
- shname++;
- el = el_init(shname, el_in, el_out, el_err);
- if (el != NULL) {
- if (hist)
- el_set(el, EL_HIST, history, hist);
-
- set_prompt_lit(lookupvar("PSlit"));
- el_set(el, EL_SIGNAL, 1);
- el_set(el, EL_ALIAS_TEXT, alias_text, NULL);
- el_set(el, EL_ADDFN, "rl-complete",
- "ReadLine compatible completion function",
- _el_fn_complete);
- } else {
-bad:
- out2str("sh: can't initialize editing\n");
- }
- INTON;
- } else if (!editing && el) {
- INTOFF;
- el_end(el);
- el = NULL;
- INTON;
- }
- if (el) {
- if (Vflag)
- el_set(el, EL_EDITOR, "vi");
- else if (Eflag)
- el_set(el, EL_EDITOR, "emacs");
- el_set(el, EL_BIND, "^I",
- tabcomplete ? "rl-complete" : "ed-insert", NULL);
- el_source(el, lookupvar("EDITRC"));
- }
- } else {
- INTOFF;
- if (el) { /* no editing if not interactive */
- el_end(el);
- el = NULL;
- }
- if (hist) {
- history_end(hist);
- hist = NULL;
- }
- INTON;
- }
-}
-
-void
-set_prompt_lit(const char *lit_ch)
-{
- wchar_t wc;
-
- if (!(iflag && editing && el))
- return;
-
- if (lit_ch == NULL) {
- el_set(el, EL_PROMPT, getprompt);
- return;
- }
-
- mbtowc(&wc, NULL, 1); /* state init */
-
- if (mbtowc(&wc, lit_ch, strlen(lit_ch)) <= 0)
- el_set(el, EL_PROMPT, getprompt);
- else
- el_set(el, EL_PROMPT_ESC, getprompt, (int)wc);
-}
-
-void
-set_editrc(const char *fname)
-{
- if (iflag && editing && el)
- el_source(el, fname);
-}
-
-void
-sethistsize(const char *hs)
-{
- int histsize;
- HistEvent he;
-
- if (hist != NULL) {
- if (hs == NULL || *hs == '\0' || *hs == '-' ||
- (histsize = number(hs)) < 0)
- histsize = 100;
- history(hist, &he, H_SETSIZE, histsize);
- history(hist, &he, H_SETUNIQUE, 1);
- }
-}
-
-void
-setterm(const char *term)
-{
- if (el != NULL && term != NULL)
- if (el_set(el, EL_TERMINAL, term) != 0) {
- outfmt(out2, "sh: Can't set terminal type %s\n", term);
- outfmt(out2, "sh: Using dumb terminal settings.\n");
- }
-}
-
-int
-inputrc(int argc, char **argv)
-{
- if (argc != 2) {
- out2str("usage: inputrc file\n");
- return 1;
- }
- if (el != NULL) {
- if (el_source(el, argv[1])) {
- out2str("inputrc: failed\n");
- return 1;
- } else
- return 0;
- } else {
- out2str("sh: inputrc ignored, not editing\n");
- return 1;
- }
-}
-
-/*
- * This command is provided since POSIX decided to standardize
- * the Korn shell fc command. Oh well...
- */
-int
-histcmd(volatile int argc, char ** volatile argv)
-{
- int ch;
- const char * volatile editor = NULL;
- HistEvent he;
- volatile int lflg = 0, nflg = 0, rflg = 0, sflg = 0;
- int i, retval;
- const char *firststr, *laststr;
- int first, last, direction;
- char * volatile pat = NULL, * volatile repl; /* ksh "fc old=new" crap */
- static int active = 0;
- struct jmploc jmploc;
- struct jmploc *volatile savehandler;
- char editfile[MAXPATHLEN + 1];
- FILE * volatile efp;
-#ifdef __GNUC__
- repl = NULL; /* XXX gcc4 */
- efp = NULL; /* XXX gcc4 */
-#endif
-
- if (hist == NULL)
- error("history not active");
-
- if (argc == 1)
- error("missing history argument");
-
- optreset = 1; optind = 1; /* initialize getopt */
- while (not_fcnumber(argv[optind]) &&
- (ch = getopt(argc, argv, ":e:lnrs")) != -1)
- switch ((char)ch) {
- case 'e':
- editor = optionarg;
- break;
- case 'l':
- lflg = 1;
- break;
- case 'n':
- nflg = 1;
- break;
- case 'r':
- rflg = 1;
- break;
- case 's':
- sflg = 1;
- break;
- case ':':
- error("option -%c expects argument", optopt);
- /* NOTREACHED */
- case '?':
- default:
- error("unknown option: -%c", optopt);
- /* NOTREACHED */
- }
- argc -= optind, argv += optind;
-
- /*
- * If executing...
- */
- if (lflg == 0 || editor || sflg) {
- lflg = 0; /* ignore */
- editfile[0] = '\0';
- /*
- * Catch interrupts to reset active counter and
- * cleanup temp files.
- */
- savehandler = handler;
- if (setjmp(jmploc.loc)) {
- active = 0;
- if (*editfile)
- unlink(editfile);
- handler = savehandler;
- longjmp(handler->loc, 1);
- }
- handler = &jmploc;
- if (++active > MAXHISTLOOPS) {
- active = 0;
- displayhist = 0;
- error("called recursively too many times");
- }
- /*
- * Set editor.
- */
- if (sflg == 0) {
- if (editor == NULL &&
- (editor = bltinlookup("FCEDIT", 1)) == NULL &&
- (editor = bltinlookup("EDITOR", 1)) == NULL)
- editor = DEFEDITOR;
- if (editor[0] == '-' && editor[1] == '\0') {
- sflg = 1; /* no edit */
- editor = NULL;
- }
- }
- }
-
- /*
- * If executing, parse [old=new] now
- */
- if (lflg == 0 && argc > 0 &&
- ((repl = strchr(argv[0], '=')) != NULL)) {
- pat = argv[0];
- *repl++ = '\0';
- argc--, argv++;
- }
-
- /*
- * If -s is specified, accept only one operand
- */
- if (sflg && argc >= 2)
- error("too many args");
-
- /*
- * determine [first] and [last]
- */
- switch (argc) {
- case 0:
- firststr = lflg ? "-16" : "-1";
- laststr = "-1";
- break;
- case 1:
- firststr = argv[0];
- laststr = lflg ? "-1" : argv[0];
- break;
- case 2:
- firststr = argv[0];
- laststr = argv[1];
- break;
- default:
- error("too many args");
- /* NOTREACHED */
- }
- /*
- * Turn into event numbers.
- */
- first = str_to_event(firststr, 0);
- last = str_to_event(laststr, 1);
-
- if (rflg) {
- i = last;
- last = first;
- first = i;
- }
- /*
- * XXX - this should not depend on the event numbers
- * always increasing. Add sequence numbers or offset
- * to the history element in next (diskbased) release.
- */
- direction = first < last ? H_PREV : H_NEXT;
-
- /*
- * If editing, grab a temp file.
- */
- if (editor) {
- int fd;
- INTOFF; /* easier */
- snprintf(editfile, sizeof(editfile), "%s_shXXXXXX", _PATH_TMP);
- if ((fd = mkstemp(editfile)) < 0)
- error("can't create temporary file %s", editfile);
- if ((efp = fdopen(fd, "w")) == NULL) {
- close(fd);
- error("can't allocate stdio buffer for temp");
- }
- }
-
- /*
- * Loop through selected history events. If listing or executing,
- * do it now. Otherwise, put into temp file and call the editor
- * after.
- *
- * The history interface needs rethinking, as the following
- * convolutions will demonstrate.
- */
- history(hist, &he, H_FIRST);
- retval = history(hist, &he, H_NEXT_EVENT, first);
- for (;retval != -1; retval = history(hist, &he, direction)) {
- if (lflg) {
- if (!nflg)
- out1fmt("%5d ", he.num);
- out1str(he.str);
- } else {
- const char *s = pat ?
- fc_replace(he.str, pat, repl) : he.str;
-
- if (sflg) {
- if (displayhist) {
- out2str(s);
- }
-
- evalstring(strcpy(stalloc(strlen(s) + 1), s), 0);
- if (displayhist && hist) {
- /*
- * XXX what about recursive and
- * relative histnums.
- */
- history(hist, &he, H_ENTER, s);
- }
-
- break;
- } else
- fputs(s, efp);
- }
- /*
- * At end? (if we were to lose last, we'd sure be
- * messed up).
- */
- if (he.num == last)
- break;
- }
- if (editor) {
- char *editcmd;
- size_t cmdlen;
-
- fclose(efp);
- cmdlen = strlen(editor) + strlen(editfile) + 2;
- editcmd = stalloc(cmdlen);
- snprintf(editcmd, cmdlen, "%s %s", editor, editfile);
- evalstring(editcmd, 0); /* XXX - should use no JC command */
- INTON;
- readcmdfile(editfile); /* XXX - should read back - quick tst */
- unlink(editfile);
- }
-
- if (lflg == 0 && active > 0)
- --active;
- if (displayhist)
- displayhist = 0;
- return 0;
-}
-
-STATIC const char *
-fc_replace(const char *s, char *p, char *r)
-{
- char *dest;
- int plen = strlen(p);
-
- STARTSTACKSTR(dest);
- while (*s) {
- if (*s == *p && strncmp(s, p, plen) == 0) {
- while (*r)
- STPUTC(*r++, dest);
- s += plen;
- *p = '\0'; /* so no more matches */
- } else
- STPUTC(*s++, dest);
- }
- STACKSTRNUL(dest);
- dest = grabstackstr(dest);
-
- return (dest);
-}
-
-int
-not_fcnumber(char *s)
-{
- if (s == NULL)
- return 0;
- if (*s == '-')
- s++;
- return (!is_number(s));
-}
-
-int
-str_to_event(const char *str, int last)
-{
- HistEvent he;
- const char *s = str;
- int relative = 0;
- int i, retval;
-
- retval = history(hist, &he, H_FIRST);
- switch (*s) {
- case '-':
- relative = 1;
- /*FALLTHROUGH*/
- case '+':
- s++;
- }
- if (is_number(s)) {
- i = number(s);
- if (relative) {
- while (retval != -1 && i--) {
- retval = history(hist, &he, H_NEXT);
- }
- if (retval == -1)
- retval = history(hist, &he, H_LAST);
- } else {
- retval = history(hist, &he, H_NEXT_EVENT, i);
- if (retval == -1) {
- /*
- * the notion of first and last is
- * backwards to that of the history package
- */
- retval = history(hist, &he,
- last ? H_FIRST : H_LAST);
- }
- }
- if (retval == -1)
- error("history number %s not found (internal error)",
- str);
- } else {
- /*
- * pattern
- */
- retval = history(hist, &he, H_PREV_STR, str);
- if (retval == -1)
- error("history pattern not found: %s", str);
- }
- return (he.num);
-}
-#else
-int
-histcmd(int argc, char **argv)
-{
- error("not compiled with history support");
- /* NOTREACHED */
-}
-int
-inputrc(int argc, char **argv)
-{
- error("not compiled with history support");
- /* NOTREACHED */
-}
-#endif
diff --git a/bin/sh/init.h b/bin/sh/init.h
deleted file mode 100644
index 60d924e..0000000
--- a/bin/sh/init.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/* $NetBSD: init.h,v 1.10 2003/08/07 09:05:32 agc Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- *
- * @(#)init.h 8.2 (Berkeley) 5/4/95
- */
-
-void init(void);
-void reset(void);
-void initshellproc(void);
diff --git a/bin/sh/input.c b/bin/sh/input.c
deleted file mode 100644
index dc686f5..0000000
--- a/bin/sh/input.c
+++ /dev/null
@@ -1,695 +0,0 @@
-/* $NetBSD: input.c,v 1.69 2019/01/16 07:14:17 kre Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- */
-
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)input.c 8.3 (Berkeley) 6/9/95";
-#else
-__RCSID("$NetBSD: input.c,v 1.69 2019/01/16 07:14:17 kre Exp $");
-#endif
-#endif /* not lint */
-
-#include <stdio.h> /* defines BUFSIZ */
-#include <fcntl.h>
-#include <errno.h>
-#include <unistd.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-
-/*
- * This file implements the input routines used by the parser.
- */
-
-#include "shell.h"
-#include "redir.h"
-#include "syntax.h"
-#include "input.h"
-#include "output.h"
-#include "options.h"
-#include "memalloc.h"
-#include "error.h"
-#include "alias.h"
-#include "parser.h"
-#include "myhistedit.h"
-#include "show.h"
-
-#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
-
-MKINIT
-struct strpush {
- struct strpush *prev; /* preceding string on stack */
- const char *prevstring;
- int prevnleft;
- int prevlleft;
- struct alias *ap; /* if push was associated with an alias */
-};
-
-/*
- * The parsefile structure pointed to by the global variable parsefile
- * contains information about the current file being read.
- */
-
-MKINIT
-struct parsefile {
- struct parsefile *prev; /* preceding file on stack */
- int linno; /* current line */
- int fd; /* file descriptor (or -1 if string) */
- int nleft; /* number of chars left in this line */
- int lleft; /* number of chars left in this buffer */
- const char *nextc; /* next char in buffer */
- char *buf; /* input buffer */
- struct strpush *strpush; /* for pushing strings at this level */
- struct strpush basestrpush; /* so pushing one is fast */
-};
-
-
-int plinno = 1; /* input line number */
-int parsenleft; /* copy of parsefile->nleft */
-MKINIT int parselleft; /* copy of parsefile->lleft */
-const char *parsenextc; /* copy of parsefile->nextc */
-MKINIT struct parsefile basepf; /* top level input file */
-MKINIT char basebuf[BUFSIZ]; /* buffer for top level input file */
-struct parsefile *parsefile = &basepf; /* current input file */
-int init_editline = 0; /* editline library initialized? */
-int whichprompt; /* 1 == PS1, 2 == PS2 */
-
-STATIC void pushfile(void);
-static int preadfd(void);
-
-#ifdef mkinit
-INCLUDE <stdio.h>
-INCLUDE "input.h"
-INCLUDE "error.h"
-
-INIT {
- basepf.nextc = basepf.buf = basebuf;
-}
-
-RESET {
- if (exception != EXSHELLPROC)
- parselleft = parsenleft = 0; /* clear input buffer */
- popallfiles();
-}
-
-SHELLPROC {
- popallfiles();
-}
-#endif
-
-
-#if 0 /* this is unused */
-/*
- * Read a line from the script.
- */
-
-char *
-pfgets(char *line, int len)
-{
- char *p = line;
- int nleft = len;
- int c;
-
- while (--nleft > 0) {
- c = pgetc_macro();
- if (c == PFAKE) /* consecutive PFAKEs is impossible */
- c = pgetc_macro();
- if (c == PEOF) {
- if (p == line)
- return NULL;
- break;
- }
- *p++ = c;
- if (c == '\n') {
- plinno++;
- break;
- }
- }
- *p = '\0';
- return line;
-}
-#endif
-
-
-/*
- * Read a character from the script, returning PEOF on end of file.
- * Nul characters in the input are silently discarded.
- */
-
-int
-pgetc(void)
-{
- int c;
-
- c = pgetc_macro();
- if (c == PFAKE)
- c = pgetc_macro();
- return c;
-}
-
-
-static int
-preadfd(void)
-{
- int nr;
- char *buf = parsefile->buf;
- parsenextc = buf;
-
- retry:
-#ifndef SMALL
- if (parsefile->fd == 0 && el) {
- static const char *rl_cp;
- static int el_len;
-
- if (rl_cp == NULL)
- rl_cp = el_gets(el, &el_len);
- if (rl_cp == NULL)
- nr = el_len == 0 ? 0 : -1;
- else {
- nr = el_len;
- if (nr > BUFSIZ - 8)
- nr = BUFSIZ - 8;
- memcpy(buf, rl_cp, nr);
- if (nr != el_len) {
- el_len -= nr;
- rl_cp += nr;
- } else
- rl_cp = 0;
- }
-
- } else
-#endif
- nr = read(parsefile->fd, buf, BUFSIZ - 8);
-
-
- if (nr <= 0) {
- if (nr < 0) {
- if (errno == EINTR)
- goto retry;
- if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
- int flags = fcntl(0, F_GETFL, 0);
-
- if (flags >= 0 && flags & O_NONBLOCK) {
- flags &=~ O_NONBLOCK;
- if (fcntl(0, F_SETFL, flags) >= 0) {
- out2str("sh: turning off NDELAY mode\n");
- goto retry;
- }
- }
- }
- }
- nr = -1;
- }
- return nr;
-}
-
-/*
- * Refill the input buffer and return the next input character:
- *
- * 1) If a string was pushed back on the input, pop it;
- * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
- * from a string so we can't refill the buffer, return EOF.
- * 3) If there is more stuff in this buffer, use it else call read to fill it.
- * 4) Process input up to the next newline, deleting nul characters.
- */
-
-int
-preadbuffer(void)
-{
- char *p, *q;
- int more;
-#ifndef SMALL
- int something;
-#endif
- char savec;
-
- while (parsefile->strpush) {
- if (parsenleft == -1 && parsefile->strpush->ap != NULL)
- return PFAKE;
- popstring();
- if (--parsenleft >= 0)
- return (*parsenextc++);
- }
- if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
- return PEOF;
- flushout(&output);
- flushout(&errout);
-
- again:
- if (parselleft <= 0) {
- if ((parselleft = preadfd()) == -1) {
- parselleft = parsenleft = EOF_NLEFT;
- return PEOF;
- }
- }
-
- /* p = (not const char *)parsenextc; */
- p = parsefile->buf + (parsenextc - parsefile->buf);
- q = p;
-
- /* delete nul characters */
-#ifndef SMALL
- something = 0;
-#endif
- for (more = 1; more;) {
- switch (*p) {
- case '\0':
- p++; /* Skip nul */
- goto check;
-
- case '\t':
- case ' ':
- break;
-
- case '\n':
- parsenleft = q - parsenextc;
- more = 0; /* Stop processing here */
- break;
-
- default:
-#ifndef SMALL
- something = 1;
-#endif
- break;
- }
-
- *q++ = *p++;
- check:
- if (--parselleft <= 0) {
- parsenleft = q - parsenextc - 1;
- if (parsenleft < 0)
- goto again;
- *q = '\0';
- more = 0;
- }
- }
-
- savec = *q;
- *q = '\0';
-
-#ifndef SMALL
- if (parsefile->fd == 0 && hist && (something || whichprompt == 2)) {
- HistEvent he;
-
- INTOFF;
- history(hist, &he, whichprompt != 2 ? H_ENTER : H_APPEND,
- parsenextc);
- INTON;
- }
-#endif
-
- if (vflag) {
- out2str(parsenextc);
- flushout(out2);
- }
-
- *q = savec;
-
- return *parsenextc++;
-}
-
-/*
- * Test whether we have reached EOF on input stream.
- * Return true only if certain (without attempting a read).
- *
- * Note the similarity to the opening section of preadbuffer()
- */
-int
-at_eof(void)
-{
- struct strpush *sp = parsefile->strpush;
-
- if (parsenleft > 0) /* more chars are in the buffer */
- return 0;
-
- while (sp != NULL) {
- /*
- * If any pushed string has any remaining data,
- * then we are not at EOF (simulating popstring())
- */
- if (sp->prevnleft > 0)
- return 0;
- sp = sp->prev;
- }
-
- /*
- * If we reached real EOF and pushed it back,
- * or if we are just processing a string (not reading a file)
- * then there is no more. Note that if a file pushes a
- * string, the file's ->buf remains present.
- */
- if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
- return 1;
-
- /*
- * In other cases, there might be more
- */
- return 0;
-}
-
-/*
- * Undo the last call to pgetc. Only one character may be pushed back.
- * PEOF may be pushed back.
- */
-
-void
-pungetc(void)
-{
- parsenleft++;
- parsenextc--;
-}
-
-/*
- * Push a string back onto the input at this current parsefile level.
- * We handle aliases this way.
- */
-void
-pushstring(const char *s, int len, struct alias *ap)
-{
- struct strpush *sp;
-
- VTRACE(DBG_INPUT,
- ("pushstring(\"%.*s\", %d)%s%s%s had: nl=%d ll=%d \"%.*s\"\n",
- len, s, len, ap ? " for alias:'" : "",
- ap ? ap->name : "", ap ? "'" : "",
- parsenleft, parselleft, parsenleft, parsenextc));
-
- INTOFF;
- if (parsefile->strpush) {
- sp = ckmalloc(sizeof (struct strpush));
- sp->prev = parsefile->strpush;
- parsefile->strpush = sp;
- } else
- sp = parsefile->strpush = &(parsefile->basestrpush);
-
- sp->prevstring = parsenextc;
- sp->prevnleft = parsenleft;
- sp->prevlleft = parselleft;
- sp->ap = ap;
- if (ap)
- ap->flag |= ALIASINUSE;
- parsenextc = s;
- parsenleft = len;
- INTON;
-}
-
-void
-popstring(void)
-{
- struct strpush *sp = parsefile->strpush;
-
- INTOFF;
- if (sp->ap) {
- int alen;
-
- if ((alen = strlen(sp->ap->val)) > 0 &&
- (sp->ap->val[alen - 1] == ' ' ||
- sp->ap->val[alen - 1] == '\t'))
- checkkwd |= CHKALIAS;
- sp->ap->flag &= ~ALIASINUSE;
- }
- parsenextc = sp->prevstring;
- parsenleft = sp->prevnleft;
- parselleft = sp->prevlleft;
-
- VTRACE(DBG_INPUT, ("popstring()%s%s%s nl=%d ll=%d \"%.*s\"\n",
- sp->ap ? " from alias:'" : "", sp->ap ? sp->ap->name : "",
- sp->ap ? "'" : "", parsenleft, parselleft, parsenleft, parsenextc));
-
- parsefile->strpush = sp->prev;
- if (sp != &(parsefile->basestrpush))
- ckfree(sp);
- INTON;
-}
-
-/*
- * Set the input to take input from a file. If push is set, push the
- * old input onto the stack first.
- */
-
-void
-setinputfile(const char *fname, int push)
-{
- unsigned char magic[4];
- int fd;
- int fd2;
- struct stat sb;
-
- CTRACE(DBG_INPUT,("setinputfile(\"%s\", %spush)\n",fname,push?"":"no"));
-
- INTOFF;
- if ((fd = open(fname, O_RDONLY)) < 0)
- error("Can't open %s", fname);
-
- /* Since the message "Syntax error: "(" unexpected" is not very
- * helpful, we check if the file starts with the ELF magic to
- * avoid that message. The first lseek tries to make sure that
- * we can later rewind the file.
- */
- if (fstat(fd, &sb) == 0 && S_ISREG(sb.st_mode) &&
- lseek(fd, 0, SEEK_SET) == 0) {
- if (read(fd, magic, 4) == 4) {
- if (memcmp(magic, "\177ELF", 4) == 0) {
- (void)close(fd);
- error("Cannot execute ELF binary %s", fname);
- }
- }
- if (lseek(fd, 0, SEEK_SET) != 0) {
- (void)close(fd);
- error("Cannot rewind the file %s", fname);
- }
- }
-
- fd2 = to_upper_fd(fd); /* closes fd, returns higher equiv */
- if (fd2 == fd) {
- (void) close(fd);
- error("Out of file descriptors");
- }
-
- setinputfd(fd2, push);
- INTON;
-}
-
-/*
- * When a shell fd needs to be altered (when the user wants to use
- * the same fd - rare, but happens - we need to locate the ref to
- * the fd, and update it. This happens via a callback.
- * This is the callback func for fd's used for shell input
- */
-static void
-input_fd_swap(int from, int to)
-{
- struct parsefile *pf;
-
- pf = parsefile;
- while (pf != NULL) { /* don't need to stop at basepf */
- if (pf->fd == from)
- pf->fd = to;
- pf = pf->prev;
- }
-}
-
-/*
- * Like setinputfile, but takes an open file descriptor. Call this with
- * interrupts off.
- */
-
-void
-setinputfd(int fd, int push)
-{
- VTRACE(DBG_INPUT, ("setinputfd(%d, %spush)\n", fd, push?"":"no"));
-
- register_sh_fd(fd, input_fd_swap);
- (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
- if (push)
- pushfile();
- if (parsefile->fd > 0)
- sh_close(parsefile->fd);
- parsefile->fd = fd;
- if (parsefile->buf == NULL)
- parsefile->buf = ckmalloc(BUFSIZ);
- parselleft = parsenleft = 0;
- plinno = 1;
-
- CTRACE(DBG_INPUT, ("setinputfd(%d, %spush) done; plinno=1\n", fd,
- push ? "" : "no"));
-}
-
-
-/*
- * Like setinputfile, but takes input from a string.
- */
-
-void
-setinputstring(char *string, int push, int line1)
-{
-
- INTOFF;
- if (push) /* XXX: always, as it happens */
- pushfile();
- parsenextc = string;
- parselleft = parsenleft = strlen(string);
- plinno = line1;
-
- CTRACE(DBG_INPUT,
- ("setinputstring(\"%.20s%s\" (%d), %spush, @ %d)\n", string,
- (parsenleft > 20 ? "..." : ""), parsenleft, push?"":"no", line1));
- INTON;
-}
-
-
-
-/*
- * To handle the "." command, a stack of input files is used. Pushfile
- * adds a new entry to the stack and popfile restores the previous level.
- */
-
-STATIC void
-pushfile(void)
-{
- struct parsefile *pf;
-
- VTRACE(DBG_INPUT,
- ("pushfile(): fd=%d buf=%p nl=%d ll=%d \"%.*s\" plinno=%d\n",
- parsefile->fd, parsefile->buf, parsenleft, parselleft,
- parsenleft, parsenextc, plinno));
-
- parsefile->nleft = parsenleft;
- parsefile->lleft = parselleft;
- parsefile->nextc = parsenextc;
- parsefile->linno = plinno;
- pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
- pf->prev = parsefile;
- pf->fd = -1;
- pf->strpush = NULL;
- pf->basestrpush.prev = NULL;
- pf->buf = NULL;
- parsefile = pf;
-}
-
-
-void
-popfile(void)
-{
- struct parsefile *pf = parsefile;
-
- INTOFF;
- if (pf->fd >= 0)
- sh_close(pf->fd);
- if (pf->buf)
- ckfree(pf->buf);
- while (pf->strpush)
- popstring();
- parsefile = pf->prev;
- ckfree(pf);
- parsenleft = parsefile->nleft;
- parselleft = parsefile->lleft;
- parsenextc = parsefile->nextc;
-
- VTRACE(DBG_INPUT,
- ("popfile(): fd=%d buf=%p nl=%d ll=%d \"%.*s\" plinno:%d->%d\n",
- parsefile->fd, parsefile->buf, parsenleft, parselleft,
- parsenleft, parsenextc, plinno, parsefile->linno));
-
- plinno = parsefile->linno;
- INTON;
-}
-
-/*
- * Return current file (to go back to it later using popfilesupto()).
- */
-
-struct parsefile *
-getcurrentfile(void)
-{
- return parsefile;
-}
-
-
-/*
- * Pop files until the given file is on top again. Useful for regular
- * builtins that read shell commands from files or strings.
- * If the given file is not an active file, an error is raised.
- */
-
-void
-popfilesupto(struct parsefile *file)
-{
- while (parsefile != file && parsefile != &basepf)
- popfile();
- if (parsefile != file)
- error("popfilesupto() misused");
-}
-
-
-/*
- * Return to top level.
- */
-
-void
-popallfiles(void)
-{
- while (parsefile != &basepf)
- popfile();
-}
-
-
-
-/*
- * Close the file(s) that the shell is reading commands from. Called
- * after a fork is done.
- *
- * Takes one arg, vfork, which tells it to not modify its global vars
- * as it is still running in the parent.
- *
- * This code is (probably) unnecessary as the 'close on exec' flag is
- * set and should be enough. In the vfork case it is definitely wrong
- * to close the fds as another fork() may be done later to feed data
- * from a 'here' document into a pipe and we don't want to close the
- * pipe!
- */
-
-void
-closescript(int vforked)
-{
- if (vforked)
- return;
- popallfiles();
- if (parsefile->fd > 0) {
- sh_close(parsefile->fd);
- parsefile->fd = 0;
- }
-}
diff --git a/bin/sh/input.h b/bin/sh/input.h
deleted file mode 100644
index c40d4aa..0000000
--- a/bin/sh/input.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/* $NetBSD: input.h,v 1.21 2018/08/19 23:50:27 kre Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- *
- * @(#)input.h 8.2 (Berkeley) 5/4/95
- */
-
-/* PEOF (the end of file marker) is defined in syntax.h */
-
-/*
- * The input line number. Input.c just defines this variable, and saves
- * and restores it when files are pushed and popped. The user of this
- * package must set its value.
- */
-extern int plinno;
-extern int parsenleft; /* number of characters left in input buffer */
-extern const char *parsenextc; /* next character in input buffer */
-extern int init_editline; /* 0 == not setup, 1 == OK, -1 == failed */
-extern int whichprompt; /* 1 ==> PS1, 2 ==> PS2 */
-
-struct alias;
-struct parsefile;
-
-char *pfgets(char *, int);
-int pgetc(void);
-int preadbuffer(void);
-int at_eof(void);
-void pungetc(void);
-void pushstring(const char *, int, struct alias *);
-void popstring(void);
-void setinputfile(const char *, int);
-void setinputfd(int, int);
-void setinputstring(char *, int, int);
-void popfile(void);
-struct parsefile *getcurrentfile(void);
-void popfilesupto(struct parsefile *);
-void popallfiles(void);
-void closescript(int);
-
-#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
diff --git a/bin/sh/jobs.c b/bin/sh/jobs.c
deleted file mode 100644
index d066bb8..0000000
--- a/bin/sh/jobs.c
+++ /dev/null
@@ -1,1812 +0,0 @@
-/* $NetBSD: jobs.c,v 1.103 2018/12/03 02:38:30 kre Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- */
-
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)jobs.c 8.5 (Berkeley) 5/4/95";
-#else
-__RCSID("$NetBSD: jobs.c,v 1.103 2018/12/03 02:38:30 kre Exp $");
-#endif
-#endif /* not lint */
-
-#include <stdio.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <paths.h>
-#include <sys/types.h>
-#include <sys/param.h>
-#ifdef BSD
-#include <sys/wait.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#endif
-#include <sys/ioctl.h>
-
-#include "shell.h"
-#if JOBS
-#if OLD_TTY_DRIVER
-#include "sgtty.h"
-#else
-#include <termios.h>
-#endif
-#undef CEOF /* syntax.h redefines this */
-#endif
-#include "redir.h"
-#include "show.h"
-#include "main.h"
-#include "parser.h"
-#include "nodes.h"
-#include "jobs.h"
-#include "var.h"
-#include "options.h"
-#include "builtins.h"
-#include "trap.h"
-#include "syntax.h"
-#include "input.h"
-#include "output.h"
-#include "memalloc.h"
-#include "error.h"
-#include "mystring.h"
-
-
-#ifndef WCONTINUED
-#define WCONTINUED 0 /* So we can compile on old systems */
-#endif
-#ifndef WIFCONTINUED
-#define WIFCONTINUED(x) (0) /* ditto */
-#endif
-
-
-static struct job *jobtab; /* array of jobs */
-static int njobs; /* size of array */
-static int jobs_invalid; /* set in child */
-MKINIT pid_t backgndpid = -1; /* pid of last background process */
-#if JOBS
-int initialpgrp; /* pgrp of shell on invocation */
-static int curjob = -1; /* current job */
-#endif
-static int ttyfd = -1;
-
-STATIC void restartjob(struct job *);
-STATIC void freejob(struct job *);
-STATIC struct job *getjob(const char *, int);
-STATIC int dowait(int, struct job *, struct job **);
-#define WBLOCK 1
-#define WNOFREE 2
-#define WSILENT 4
-STATIC int jobstatus(const struct job *, int);
-STATIC int waitproc(int, struct job *, int *);
-STATIC void cmdtxt(union node *);
-STATIC void cmdlist(union node *, int);
-STATIC void cmdputs(const char *);
-inline static void cmdputi(int);
-
-#ifdef SYSV
-STATIC int onsigchild(void);
-#endif
-
-#ifdef OLD_TTY_DRIVER
-static pid_t tcgetpgrp(int fd);
-static int tcsetpgrp(int fd, pid_t pgrp);
-
-static pid_t
-tcgetpgrp(int fd)
-{
- pid_t pgrp;
- if (ioctl(fd, TIOCGPGRP, (char *)&pgrp) == -1)
- return -1;
- else
- return pgrp;
-}
-
-static int
-tcsetpgrp(int fd, pid_tpgrp)
-{
- return ioctl(fd, TIOCSPGRP, (char *)&pgrp);
-}
-#endif
-
-static void
-ttyfd_change(int from, int to)
-{
- if (ttyfd == from)
- ttyfd = to;
-}
-
-/*
- * Turn job control on and off.
- *
- * Note: This code assumes that the third arg to ioctl is a character
- * pointer, which is true on Berkeley systems but not System V. Since
- * System V doesn't have job control yet, this isn't a problem now.
- */
-
-MKINIT int jobctl;
-
-void
-setjobctl(int on)
-{
-#ifdef OLD_TTY_DRIVER
- int ldisc;
-#endif
-
- if (on == jobctl || rootshell == 0)
- return;
- if (on) {
-#if defined(FIOCLEX) || defined(FD_CLOEXEC)
- int i;
-
- if (ttyfd != -1)
- sh_close(ttyfd);
- if ((ttyfd = open("/dev/tty", O_RDWR)) == -1) {
- for (i = 0; i < 3; i++) {
- if (isatty(i) && (ttyfd = dup(i)) != -1)
- break;
- }
- if (i == 3)
- goto out;
- }
- ttyfd = to_upper_fd(ttyfd); /* Move to a high fd */
- register_sh_fd(ttyfd, ttyfd_change);
-#else
- out2str("sh: Need FIOCLEX or FD_CLOEXEC to support job control");
- goto out;
-#endif
- do { /* while we are in the background */
- if ((initialpgrp = tcgetpgrp(ttyfd)) < 0) {
- out:
- out2str("sh: can't access tty; job control turned off\n");
- mflag = 0;
- return;
- }
- if (initialpgrp == -1)
- initialpgrp = getpgrp();
- else if (initialpgrp != getpgrp()) {
- killpg(0, SIGTTIN);
- continue;
- }
- } while (0);
-
-#ifdef OLD_TTY_DRIVER
- if (ioctl(ttyfd, TIOCGETD, (char *)&ldisc) < 0
- || ldisc != NTTYDISC) {
- out2str("sh: need new tty driver to run job control; job control turned off\n");
- mflag = 0;
- return;
- }
-#endif
- setsignal(SIGTSTP, 0);
- setsignal(SIGTTOU, 0);
- setsignal(SIGTTIN, 0);
- if (getpgrp() != rootpid && setpgid(0, rootpid) == -1)
- error("Cannot set process group (%s) at %d",
- strerror(errno), __LINE__);
- if (tcsetpgrp(ttyfd, rootpid) == -1)
- error("Cannot set tty process group (%s) at %d",
- strerror(errno), __LINE__);
- } else { /* turning job control off */
- if (getpgrp() != initialpgrp && setpgid(0, initialpgrp) == -1)
- error("Cannot set process group (%s) at %d",
- strerror(errno), __LINE__);
- if (tcsetpgrp(ttyfd, initialpgrp) == -1)
- error("Cannot set tty process group (%s) at %d",
- strerror(errno), __LINE__);
- sh_close(ttyfd);
- ttyfd = -1;
- setsignal(SIGTSTP, 0);
- setsignal(SIGTTOU, 0);
- setsignal(SIGTTIN, 0);
- }
- jobctl = on;
-}
-
-
-#ifdef mkinit
-INCLUDE <stdlib.h>
-
-SHELLPROC {
- backgndpid = -1;
-#if JOBS
- jobctl = 0;
-#endif
-}
-
-#endif
-
-
-
-#if JOBS
-static int
-do_fgcmd(const char *arg_ptr)
-{
- struct job *jp;
- int i;
- int status;
-
- if (jobs_invalid)
- error("No current jobs");
- jp = getjob(arg_ptr, 0);
- if (jp->jobctl == 0)
- error("job not created under job control");
- out1fmt("%s", jp->ps[0].cmd);
- for (i = 1; i < jp->nprocs; i++)
- out1fmt(" | %s", jp->ps[i].cmd );
- out1c('\n');
- flushall();
-
- for (i = 0; i < jp->nprocs; i++)
- if (tcsetpgrp(ttyfd, jp->ps[i].pid) != -1)
- break;
-
- if (i >= jp->nprocs) {
- error("Cannot set tty process group (%s) at %d",
- strerror(errno), __LINE__);
- }
- restartjob(jp);
- INTOFF;
- status = waitforjob(jp);
- INTON;
- return status;
-}
-
-int
-fgcmd(int argc, char **argv)
-{
- nextopt("");
- return do_fgcmd(*argptr);
-}
-
-int
-fgcmd_percent(int argc, char **argv)
-{
- nextopt("");
- return do_fgcmd(*argv);
-}
-
-static void
-set_curjob(struct job *jp, int mode)
-{
- struct job *jp1, *jp2;
- int i, ji;
-
- ji = jp - jobtab;
-
- /* first remove from list */
- if (ji == curjob)
- curjob = jp->prev_job;
- else {
- for (i = 0; i < njobs; i++) {
- if (jobtab[i].prev_job != ji)
- continue;
- jobtab[i].prev_job = jp->prev_job;
- break;
- }
- }
-
- /* Then re-insert in correct position */
- switch (mode) {
- case 0: /* job being deleted */
- jp->prev_job = -1;
- break;
- case 1: /* newly created job or backgrounded job,
- put after all stopped jobs. */
- if (curjob != -1 && jobtab[curjob].state == JOBSTOPPED) {
- for (jp1 = jobtab + curjob; ; jp1 = jp2) {
- if (jp1->prev_job == -1)
- break;
- jp2 = jobtab + jp1->prev_job;
- if (jp2->state != JOBSTOPPED)
- break;
- }
- jp->prev_job = jp1->prev_job;
- jp1->prev_job = ji;
- break;
- }
- /* FALLTHROUGH */
- case 2: /* newly stopped job - becomes curjob */
- jp->prev_job = curjob;
- curjob = ji;
- break;
- }
-}
-
-int
-bgcmd(int argc, char **argv)
-{
- struct job *jp;
- int i;
-
- nextopt("");
- if (jobs_invalid)
- error("No current jobs");
- do {
- jp = getjob(*argptr, 0);
- if (jp->jobctl == 0)
- error("job not created under job control");
- set_curjob(jp, 1);
- out1fmt("[%ld] %s", (long)(jp - jobtab + 1), jp->ps[0].cmd);
- for (i = 1; i < jp->nprocs; i++)
- out1fmt(" | %s", jp->ps[i].cmd );
- out1c('\n');
- flushall();
- restartjob(jp);
- } while (*argptr && *++argptr);
- return 0;
-}
-
-
-STATIC void
-restartjob(struct job *jp)
-{
- struct procstat *ps;
- int i;
-
- if (jp->state == JOBDONE)
- return;
- INTOFF;
- for (i = 0; i < jp->nprocs; i++)
- if (killpg(jp->ps[i].pid, SIGCONT) != -1)
- break;
- if (i >= jp->nprocs)
- error("Cannot continue job (%s)", strerror(errno));
- for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
- if (WIFSTOPPED(ps->status)) {
- VTRACE(DBG_JOBS, (
- "restartjob: [%zu] pid %d status change"
- " from %#x (stopped) to -1 (running)\n",
- (size_t)(jp-jobtab+1), ps->pid, ps->status));
- ps->status = -1;
- jp->state = JOBRUNNING;
- }
- }
- INTON;
-}
-#endif
-
-inline static void
-cmdputi(int n)
-{
- char str[20];
-
- fmtstr(str, sizeof str, "%d", n);
- cmdputs(str);
-}
-
-static void
-showjob(struct output *out, struct job *jp, int mode)
-{
- int procno;
- int st;
- struct procstat *ps;
- int col;
- char s[64];
-
-#if JOBS
- if (mode & SHOW_PGID) {
- /* just output process (group) id of pipeline */
- outfmt(out, "%ld\n", (long)jp->ps->pid);
- return;
- }
-#endif
-
- procno = jp->nprocs;
- if (!procno)
- return;
-
- if (mode & SHOW_PID)
- mode |= SHOW_MULTILINE;
-
- if ((procno > 1 && !(mode & SHOW_MULTILINE))
- || (mode & SHOW_SIGNALLED)) {
- /* See if we have more than one status to report */
- ps = jp->ps;
- st = ps->status;
- do {
- int st1 = ps->status;
- if (st1 != st)
- /* yes - need multi-line output */
- mode |= SHOW_MULTILINE;
- if (st1 == -1 || !(mode & SHOW_SIGNALLED) || WIFEXITED(st1))
- continue;
- if (WIFSTOPPED(st1) || ((st1 = WTERMSIG(st1) & 0x7f)
- && st1 != SIGINT && st1 != SIGPIPE))
- mode |= SHOW_ISSIG;
-
- } while (ps++, --procno);
- procno = jp->nprocs;
- }
-
- if (mode & SHOW_SIGNALLED && !(mode & SHOW_ISSIG)) {
- if (jp->state == JOBDONE && !(mode & SHOW_NO_FREE)) {
- VTRACE(DBG_JOBS, ("showjob: freeing job %d\n",
- jp - jobtab + 1));
- freejob(jp);
- }
- return;
- }
-
- for (ps = jp->ps; --procno >= 0; ps++) { /* for each process */
- if (ps == jp->ps)
- fmtstr(s, 16, "[%ld] %c ",
- (long)(jp - jobtab + 1),
-#if JOBS
- jp - jobtab == curjob ?
- '+' :
- curjob != -1 &&
- jp - jobtab == jobtab[curjob].prev_job ?
- '-' :
-#endif
- ' ');
- else
- fmtstr(s, 16, " " );
- col = strlen(s);
- if (mode & SHOW_PID) {
- fmtstr(s + col, 16, "%ld ", (long)ps->pid);
- col += strlen(s + col);
- }
- if (ps->status == -1) {
- scopy("Running", s + col);
- } else if (WIFEXITED(ps->status)) {
- st = WEXITSTATUS(ps->status);
- if (st)
- fmtstr(s + col, 16, "Done(%d)", st);
- else
- fmtstr(s + col, 16, "Done");
- } else {
-#if JOBS
- if (WIFSTOPPED(ps->status))
- st = WSTOPSIG(ps->status);
- else /* WIFSIGNALED(ps->status) */
-#endif
- st = WTERMSIG(ps->status);
- scopyn(strsignal(st), s + col, 32);
- if (WCOREDUMP(ps->status)) {
- col += strlen(s + col);
- scopyn(" (core dumped)", s + col, 64 - col);
- }
- }
- col += strlen(s + col);
- outstr(s, out);
- do {
- outc(' ', out);
- col++;
- } while (col < 30);
- outstr(ps->cmd, out);
- if (mode & SHOW_MULTILINE) {
- if (procno > 0) {
- outc(' ', out);
- outc('|', out);
- }
- } else {
- while (--procno >= 0)
- outfmt(out, " | %s", (++ps)->cmd );
- }
- outc('\n', out);
- }
- flushout(out);
- jp->flags &= ~JOBCHANGED;
- if (jp->state == JOBDONE && !(mode & SHOW_NO_FREE))
- freejob(jp);
-}
-
-int
-jobscmd(int argc, char **argv)
-{
- int mode, m;
-
- mode = 0;
- while ((m = nextopt("lp")))
- if (m == 'l')
- mode = SHOW_PID;
- else
- mode = SHOW_PGID;
- if (!iflag)
- mode |= SHOW_NO_FREE;
- if (*argptr)
- do
- showjob(out1, getjob(*argptr,0), mode);
- while (*++argptr);
- else
- showjobs(out1, mode);
- return 0;
-}
-
-
-/*
- * Print a list of jobs. If "change" is nonzero, only print jobs whose
- * statuses have changed since the last call to showjobs.
- *
- * If the shell is interrupted in the process of creating a job, the
- * result may be a job structure containing zero processes. Such structures
- * will be freed here.
- */
-
-void
-showjobs(struct output *out, int mode)
-{
- int jobno;
- struct job *jp;
- int silent = 0, gotpid;
-
- CTRACE(DBG_JOBS, ("showjobs(%x) called\n", mode));
-
- /* If not even one one job changed, there is nothing to do */
- gotpid = dowait(WSILENT, NULL, NULL);
- while (dowait(WSILENT, NULL, NULL) > 0)
- continue;
-#ifdef JOBS
- /*
- * Check if we are not in our foreground group, and if not
- * put us in it.
- */
- if (mflag && gotpid != -1 && tcgetpgrp(ttyfd) != getpid()) {
- if (tcsetpgrp(ttyfd, getpid()) == -1)
- error("Cannot set tty process group (%s) at %d",
- strerror(errno), __LINE__);
- VTRACE(DBG_JOBS|DBG_INPUT, ("repaired tty process group\n"));
- silent = 1;
- }
-#endif
-
- for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
- if (!jp->used)
- continue;
- if (jp->nprocs == 0) {
- if (!jobs_invalid)
- freejob(jp);
- continue;
- }
- if ((mode & SHOW_CHANGED) && !(jp->flags & JOBCHANGED))
- continue;
- if (silent && (jp->flags & JOBCHANGED)) {
- jp->flags &= ~JOBCHANGED;
- continue;
- }
- showjob(out, jp, mode);
- }
-}
-
-/*
- * Mark a job structure as unused.
- */
-
-STATIC void
-freejob(struct job *jp)
-{
- INTOFF;
- if (jp->ps != &jp->ps0) {
- ckfree(jp->ps);
- jp->ps = &jp->ps0;
- }
- jp->nprocs = 0;
- jp->used = 0;
-#if JOBS
- set_curjob(jp, 0);
-#endif
- INTON;
-}
-
-/*
- * Extract the status of a completed job (for $?)
- */
-STATIC int
-jobstatus(const struct job *jp, int raw)
-{
- int status = 0;
- int retval;
-
- if ((jp->flags & JPIPEFAIL) && jp->nprocs) {
- int i;
-
- for (i = 0; i < jp->nprocs; i++)
- if (jp->ps[i].status != 0)
- status = jp->ps[i].status;
- } else
- status = jp->ps[jp->nprocs ? jp->nprocs - 1 : 0].status;
-
- if (raw)
- return status;
-
- if (WIFEXITED(status))
- retval = WEXITSTATUS(status);
-#if JOBS
- else if (WIFSTOPPED(status))
- retval = WSTOPSIG(status) + 128;
-#endif
- else {
- /* XXX: limits number of signals */
- retval = WTERMSIG(status) + 128;
- }
-
- return retval;
-}
-
-
-
-int
-waitcmd(int argc, char **argv)
-{
- struct job *job, *last;
- int retval;
- struct job *jp;
- int i;
- int any = 0;
- int found;
- char *pid = NULL, *fpid;
- char **arg;
- char idstring[20];
-
- while ((i = nextopt("np:")) != '\0') {
- switch (i) {
- case 'n':
- any = 1;
- break;
- case 'p':
- if (pid)
- error("more than one -p unsupported");
- pid = optionarg;
- break;
- }
- }
-
- if (pid != NULL) {
- if (!validname(pid, '\0', NULL))
- error("invalid name: -p '%s'", pid);
- if (unsetvar(pid, 0))
- error("%s readonly", pid);
- }
-
- /*
- * If we have forked, and not yet created any new jobs, then
- * we have no children, whatever jobtab claims,
- * so simply return in that case.
- *
- * The return code is 127 if we had any pid args (none are found)
- * or if we had -n (nothing exited), but 0 for plain old "wait".
- */
- if (jobs_invalid) {
- CTRACE(DBG_WAIT, ("builtin wait%s%s in child, invalid jobtab\n",
- any ? " -n" : "", *argptr ? " pid..." : ""));
- return (any || *argptr) ? 127 : 0;
- }
-
- /* clear stray flags left from previous waitcmd */
- for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
- jp->flags &= ~JOBWANTED;
- jp->ref = NULL;
- }
-
- CTRACE(DBG_WAIT,
- ("builtin wait%s%s\n", any ? " -n" : "", *argptr ? " pid..." : ""));
-
- /*
- * First, validate the jobnum args, count how many refer to
- * (different) running jobs, and if we had -n, and found that one has
- * already finished, we return that one. Otherwise remember
- * which ones we are looking for (JOBWANTED).
- */
- found = 0;
- last = NULL;
- for (arg = argptr; *arg; arg++) {
- last = jp = getjob(*arg, 1);
- if (!jp)
- continue;
- if (jp->ref == NULL)
- jp->ref = *arg;
- if (any && jp->state == JOBDONE) {
- /*
- * We just want any of them, and this one is
- * ready for consumption, bon apetit ...
- */
- retval = jobstatus(jp, 0);
- if (pid)
- setvar(pid, *arg, 0);
- if (!iflag)
- freejob(jp);
- CTRACE(DBG_WAIT, ("wait -n found %s already done: %d\n", *arg, retval));
- return retval;
- }
- if (!(jp->flags & JOBWANTED)) {
- /*
- * It is possible to list the same job several
- * times - the obvious "wait 1 1 1" or
- * "wait %% %2 102" where job 2 is current and pid 102
- * However many times it is requested, it is found once.
- */
- found++;
- jp->flags |= JOBWANTED;
- }
- job = jp;
- }
-
- VTRACE(DBG_WAIT, ("wait %s%s%sfound %d candidates (last %s)\n",
- any ? "-n " : "", *argptr ? *argptr : "",
- argptr[0] && argptr[1] ? "... " : " ", found,
- job ? (job->ref ? job->ref : "<no-arg>") : "none"));
-
- /*
- * If we were given a list of jobnums:
- * and none of those exist, then we're done.
- */
- if (*argptr && found == 0)
- return 127;
-
- /*
- * Otherwise we need to wait for something to complete
- * When it does, we check and see if it is one of the
- * jobs we're waiting on, and if so, we clean it up.
- * If we had -n, then we're done, otherwise we do it all again
- * until all we had listed are done, of if there were no
- * jobnum args, all are done.
- */
-
- retval = any || *argptr ? 127 : 0;
- fpid = NULL;
- for (;;) {
- VTRACE(DBG_WAIT, ("wait waiting (%d remain): ", found));
- for (jp = jobtab, i = njobs; --i >= 0; jp++) {
- if (jp->used && jp->flags & JOBWANTED &&
- jp->state == JOBDONE)
- break;
- if (jp->used && jp->state == JOBRUNNING)
- break;
- }
- if (i < 0) {
- CTRACE(DBG_WAIT, ("nothing running (ret: %d) fpid %s\n",
- retval, fpid ? fpid : "unset"));
- if (pid && fpid)
- setvar(pid, fpid, 0);
- return retval;
- }
- VTRACE(DBG_WAIT, ("found @%d/%d state: %d\n", njobs-i, njobs,
- jp->state));
-
- /*
- * There is at least 1 job running, so we can
- * safely wait() for something to exit.
- */
- if (jp->state == JOBRUNNING) {
- job = NULL;
- if ((i = dowait(WBLOCK|WNOFREE, NULL, &job)) == -1)
- return 128 + lastsig();
-
- /*
- * one of the job's processes exited,
- * but there are more
- */
- if (job->state == JOBRUNNING)
- continue;
- } else
- job = jp; /* we want this, and it is done */
-
- if (job->flags & JOBWANTED || (*argptr == 0 && any)) {
- int rv;
-
- job->flags &= ~JOBWANTED; /* got it */
- rv = jobstatus(job, 0);
- VTRACE(DBG_WAIT, (
- "wanted %d (%s) done: st=%d", i,
- job->ref ? job->ref : "", rv));
- if (any || job == last) {
- retval = rv;
- fpid = job->ref;
-
- VTRACE(DBG_WAIT, (" save"));
- if (pid) {
- /*
- * don't need fpid unless we are going
- * to return it.
- */
- if (fpid == NULL) {
- /*
- * this only happens with "wait -n"
- * (that is, no pid args)
- */
- snprintf(idstring, sizeof idstring,
- "%d", job->ps[ job->nprocs ?
- job->nprocs-1 :
- 0 ].pid);
- fpid = idstring;
- }
- VTRACE(DBG_WAIT, (" (for %s)", fpid));
- }
- }
-
- if (job->state == JOBDONE) {
- VTRACE(DBG_WAIT, (" free"));
- freejob(job);
- }
-
- if (any || (found > 0 && --found == 0)) {
- if (pid && fpid)
- setvar(pid, fpid, 0);
- VTRACE(DBG_WAIT, (" return %d\n", retval));
- return retval;
- }
- VTRACE(DBG_WAIT, ("\n"));
- continue;
- }
-
- /* this is to handle "wait" (no args) */
- if (found == 0 && job->state == JOBDONE) {
- VTRACE(DBG_JOBS|DBG_WAIT, ("Cleanup: %d\n", i));
- freejob(job);
- }
- }
-}
-
-
-int
-jobidcmd(int argc, char **argv)
-{
- struct job *jp;
- int i;
- int pg = 0, onep = 0, job = 0;
-
- while ((i = nextopt("gjp"))) {
- switch (i) {
- case 'g': pg = 1; break;
- case 'j': job = 1; break;
- case 'p': onep = 1; break;
- }
- }
- CTRACE(DBG_JOBS, ("jobidcmd%s%s%s%s %s\n", pg ? " -g" : "",
- onep ? " -p" : "", job ? " -j" : "", jobs_invalid ? " [inv]" : "",
- *argptr ? *argptr : "<implicit %%>"));
- if (pg + onep + job > 1)
- error("-g -j and -p options cannot be combined");
-
- if (argptr[0] && argptr[1])
- error("usage: jobid [-g|-p|-r] jobid");
-
- jp = getjob(*argptr, 0);
- if (job) {
- out1fmt("%%%zu\n", (size_t)(jp - jobtab + 1));
- return 0;
- }
- if (pg) {
- if (jp->pgrp != 0) {
- out1fmt("%ld\n", (long)jp->pgrp);
- return 0;
- }
- return 1;
- }
- if (onep) {
- i = jp->nprocs - 1;
- if (i < 0)
- return 1;
- out1fmt("%ld\n", (long)jp->ps[i].pid);
- return 0;
- }
- for (i = 0 ; i < jp->nprocs ; ) {
- out1fmt("%ld", (long)jp->ps[i].pid);
- out1c(++i < jp->nprocs ? ' ' : '\n');
- }
- return 0;
-}
-
-int
-getjobpgrp(const char *name)
-{
- struct job *jp;
-
- if (jobs_invalid)
- error("No such job: %s", name);
- jp = getjob(name, 1);
- if (jp == 0)
- return 0;
- return -jp->ps[0].pid;
-}
-
-/*
- * Convert a job name to a job structure.
- */
-
-STATIC struct job *
-getjob(const char *name, int noerror)
-{
- int jobno = -1;
- struct job *jp;
- int pid;
- int i;
- const char *err_msg = "No such job: %s";
-
- if (name == NULL) {
-#if JOBS
- jobno = curjob;
-#endif
- err_msg = "No current job";
- } else if (name[0] == '%') {
- if (is_number(name + 1)) {
- jobno = number(name + 1) - 1;
- } else if (!name[1] || !name[2]) {
- switch (name[1]) {
-#if JOBS
- case 0:
- case '+':
- case '%':
- jobno = curjob;
- err_msg = "No current job";
- break;
- case '-':
- jobno = curjob;
- if (jobno != -1)
- jobno = jobtab[jobno].prev_job;
- err_msg = "No previous job";
- break;
-#endif
- default:
- goto check_pattern;
- }
- } else {
- struct job *found;
- check_pattern:
- found = NULL;
- for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
- if (!jp->used || jp->nprocs <= 0)
- continue;
- if ((name[1] == '?'
- && strstr(jp->ps[0].cmd, name + 2))
- || prefix(name + 1, jp->ps[0].cmd)) {
- if (found) {
- err_msg = "%s: ambiguous";
- found = 0;
- break;
- }
- found = jp;
- }
- }
- if (found)
- return found;
- }
-
- } else if (is_number(name)) {
- pid = number(name);
- for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
- if (jp->used && jp->nprocs > 0
- && jp->ps[jp->nprocs - 1].pid == pid)
- return jp;
- }
- }
-
- if (jobno >= 0 && jobno < njobs) {
- jp = jobtab + jobno;
- if (jp->used)
- return jp;
- }
- if (!noerror)
- error(err_msg, name);
- return 0;
-}
-
-
-
-/*
- * Return a new job structure,
- */
-
-struct job *
-makejob(union node *node, int nprocs)
-{
- int i;
- struct job *jp;
-
- if (jobs_invalid) {
- for (i = njobs, jp = jobtab ; --i >= 0 ; jp++) {
- if (jp->used)
- freejob(jp);
- }
- jobs_invalid = 0;
- }
-
- for (i = njobs, jp = jobtab ; ; jp++) {
- if (--i < 0) {
- INTOFF;
- if (njobs == 0) {
- jobtab = ckmalloc(4 * sizeof jobtab[0]);
- } else {
- jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
- memcpy(jp, jobtab, njobs * sizeof jp[0]);
- /* Relocate `ps' pointers */
- for (i = 0; i < njobs; i++)
- if (jp[i].ps == &jobtab[i].ps0)
- jp[i].ps = &jp[i].ps0;
- ckfree(jobtab);
- jobtab = jp;
- }
- jp = jobtab + njobs;
- for (i = 4 ; --i >= 0 ; njobs++) {
- jobtab[njobs].used = 0;
- jobtab[njobs].prev_job = -1;
- }
- INTON;
- break;
- }
- if (jp->used == 0)
- break;
- }
- INTOFF;
- jp->state = JOBRUNNING;
- jp->used = 1;
- jp->flags = pipefail ? JPIPEFAIL : 0;
- jp->nprocs = 0;
- jp->pgrp = 0;
-#if JOBS
- jp->jobctl = jobctl;
- set_curjob(jp, 1);
-#endif
- if (nprocs > 1) {
- jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
- } else {
- jp->ps = &jp->ps0;
- }
- INTON;
- VTRACE(DBG_JOBS, ("makejob(%p, %d)%s returns %%%d\n", (void *)node,
- nprocs, (jp->flags&JPIPEFAIL)?" PF":"", jp - jobtab + 1));
- return jp;
-}
-
-
-/*
- * Fork off a subshell. If we are doing job control, give the subshell its
- * own process group. Jp is a job structure that the job is to be added to.
- * N is the command that will be evaluated by the child. Both jp and n may
- * be NULL. The mode parameter can be one of the following:
- * FORK_FG - Fork off a foreground process.
- * FORK_BG - Fork off a background process.
- * FORK_NOJOB - Like FORK_FG, but don't give the process its own
- * process group even if job control is on.
- *
- * When job control is turned off, background processes have their standard
- * input redirected to /dev/null (except for the second and later processes
- * in a pipeline).
- */
-
-int
-forkshell(struct job *jp, union node *n, int mode)
-{
- pid_t pid;
- int serrno;
-
- CTRACE(DBG_JOBS, ("forkshell(%%%d, %p, %d) called\n",
- jp - jobtab, n, mode));
-
- switch ((pid = fork())) {
- case -1:
- serrno = errno;
- VTRACE(DBG_JOBS, ("Fork failed, errno=%d\n", serrno));
- INTON;
- error("Cannot fork (%s)", strerror(serrno));
- break;
- case 0:
- SHELL_FORKED();
- forkchild(jp, n, mode, 0);
- return 0;
- default:
- return forkparent(jp, n, mode, pid);
- }
-}
-
-int
-forkparent(struct job *jp, union node *n, int mode, pid_t pid)
-{
- int pgrp;
-
- if (rootshell && mode != FORK_NOJOB && mflag) {
- if (jp == NULL || jp->nprocs == 0)
- pgrp = pid;
- else
- pgrp = jp->ps[0].pid;
- jp->pgrp = pgrp;
- /* This can fail because we are doing it in the child also */
- (void)setpgid(pid, pgrp);
- }
- if (mode == FORK_BG)
- backgndpid = pid; /* set $! */
- if (jp) {
- struct procstat *ps = &jp->ps[jp->nprocs++];
- ps->pid = pid;
- ps->status = -1;
- ps->cmd[0] = 0;
- if (/* iflag && rootshell && */ n)
- commandtext(ps, n);
- }
- CTRACE(DBG_JOBS, ("In parent shell: child = %d (mode %d)\n",pid,mode));
- return pid;
-}
-
-void
-forkchild(struct job *jp, union node *n, int mode, int vforked)
-{
- int wasroot;
- int pgrp;
- const char *devnull = _PATH_DEVNULL;
- const char *nullerr = "Can't open %s";
-
- wasroot = rootshell;
- CTRACE(DBG_JOBS, ("Child shell %d %sforked from %d (mode %d)\n",
- getpid(), vforked?"v":"", getppid(), mode));
-
- if (!vforked) {
- rootshell = 0;
- handler = &main_handler;
- }
-
- closescript(vforked);
- clear_traps(vforked);
-#if JOBS
- if (!vforked)
- jobctl = 0; /* do job control only in root shell */
- if (wasroot && mode != FORK_NOJOB && mflag) {
- if (jp == NULL || jp->nprocs == 0)
- pgrp = getpid();
- else
- pgrp = jp->ps[0].pid;
- /* This can fail because we are doing it in the parent also */
- (void)setpgid(0, pgrp);
- if (mode == FORK_FG) {
- if (tcsetpgrp(ttyfd, pgrp) == -1)
- error("Cannot set tty process group (%s) at %d",
- strerror(errno), __LINE__);
- }
- setsignal(SIGTSTP, vforked);
- setsignal(SIGTTOU, vforked);
- } else if (mode == FORK_BG) {
- ignoresig(SIGINT, vforked);
- ignoresig(SIGQUIT, vforked);
- if ((jp == NULL || jp->nprocs == 0) &&
- ! fd0_redirected_p ()) {
- close(0);
- if (open(devnull, O_RDONLY) != 0)
- error(nullerr, devnull);
- }
- }
-#else
- if (mode == FORK_BG) {
- ignoresig(SIGINT, vforked);
- ignoresig(SIGQUIT, vforked);
- if ((jp == NULL || jp->nprocs == 0) &&
- ! fd0_redirected_p ()) {
- close(0);
- if (open(devnull, O_RDONLY) != 0)
- error(nullerr, devnull);
- }
- }
-#endif
- if (wasroot && iflag) {
- setsignal(SIGINT, vforked);
- setsignal(SIGQUIT, vforked);
- setsignal(SIGTERM, vforked);
- }
-
- if (!vforked)
- jobs_invalid = 1;
-}
-
-/*
- * Wait for job to finish.
- *
- * Under job control we have the problem that while a child process is
- * running interrupts generated by the user are sent to the child but not
- * to the shell. This means that an infinite loop started by an inter-
- * active user may be hard to kill. With job control turned off, an
- * interactive user may place an interactive program inside a loop. If
- * the interactive program catches interrupts, the user doesn't want
- * these interrupts to also abort the loop. The approach we take here
- * is to have the shell ignore interrupt signals while waiting for a
- * forground process to terminate, and then send itself an interrupt
- * signal if the child process was terminated by an interrupt signal.
- * Unfortunately, some programs want to do a bit of cleanup and then
- * exit on interrupt; unless these processes terminate themselves by
- * sending a signal to themselves (instead of calling exit) they will
- * confuse this approach.
- */
-
-int
-waitforjob(struct job *jp)
-{
-#if JOBS
- int mypgrp = getpgrp();
-#endif
- int status;
- int st;
-
- INTOFF;
- VTRACE(DBG_JOBS, ("waitforjob(%%%d) called\n", jp - jobtab + 1));
- while (jp->state == JOBRUNNING) {
- dowait(WBLOCK, jp, NULL);
- }
-#if JOBS
- if (jp->jobctl) {
- if (tcsetpgrp(ttyfd, mypgrp) == -1)
- error("Cannot set tty process group (%s) at %d",
- strerror(errno), __LINE__);
- }
- if (jp->state == JOBSTOPPED && curjob != jp - jobtab)
- set_curjob(jp, 2);
-#endif
- status = jobstatus(jp, 1);
-
- /* convert to 8 bits */
- if (WIFEXITED(status))
- st = WEXITSTATUS(status);
-#if JOBS
- else if (WIFSTOPPED(status))
- st = WSTOPSIG(status) + 128;
-#endif
- else
- st = WTERMSIG(status) + 128;
-
- VTRACE(DBG_JOBS, ("waitforjob: job %d, nproc %d, status %d, st %x\n",
- jp - jobtab + 1, jp->nprocs, status, st));
-#if JOBS
- if (jp->jobctl) {
- /*
- * This is truly gross.
- * If we're doing job control, then we did a TIOCSPGRP which
- * caused us (the shell) to no longer be in the controlling
- * session -- so we wouldn't have seen any ^C/SIGINT. So, we
- * intuit from the subprocess exit status whether a SIGINT
- * occurred, and if so interrupt ourselves. Yuck. - mycroft
- */
- if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
- raise(SIGINT);
- }
-#endif
- if (! JOBS || jp->state == JOBDONE)
- freejob(jp);
- INTON;
- return st;
-}
-
-
-
-/*
- * Wait for a process to terminate.
- */
-
-STATIC int
-dowait(int flags, struct job *job, struct job **changed)
-{
- int pid;
- int status;
- struct procstat *sp;
- struct job *jp;
- struct job *thisjob;
- int done;
- int stopped;
-
- VTRACE(DBG_JOBS|DBG_PROCS, ("dowait(%x) called\n", flags));
-
- if (changed != NULL)
- *changed = NULL;
-
- do {
- pid = waitproc(flags & WBLOCK, job, &status);
- VTRACE(DBG_JOBS|DBG_PROCS, ("wait returns pid %d, status %#x\n",
- pid, status));
- } while (pid == -1 && errno == EINTR && pendingsigs == 0);
- if (pid <= 0)
- return pid;
- INTOFF;
- thisjob = NULL;
- for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
- if (jp->used) {
- done = 1;
- stopped = 1;
- for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
- if (sp->pid == -1)
- continue;
- if (sp->pid == pid &&
- (sp->status==-1 || WIFSTOPPED(sp->status))) {
- VTRACE(DBG_JOBS | DBG_PROCS,
- ("Job %d: changing status of proc %d from %#x to %#x\n",
- jp - jobtab + 1, pid,
- sp->status, status));
- if (WIFCONTINUED(status)) {
- if (sp->status != -1)
- jp->flags |= JOBCHANGED;
- sp->status = -1;
- jp->state = 0;
- } else
- sp->status = status;
- thisjob = jp;
- if (changed != NULL)
- *changed = jp;
- }
- if (sp->status == -1)
- stopped = 0;
- else if (WIFSTOPPED(sp->status))
- done = 0;
- }
- if (stopped) { /* stopped or done */
- int state = done ? JOBDONE : JOBSTOPPED;
-
- if (jp->state != state) {
- VTRACE(DBG_JOBS,
- ("Job %d: changing state from %d to %d\n",
- jp - jobtab + 1, jp->state, state));
- jp->state = state;
-#if JOBS
- if (done)
- set_curjob(jp, 0);
-#endif
- }
- }
- }
- }
-
- if (thisjob &&
- (thisjob->state != JOBRUNNING || thisjob->flags & JOBCHANGED)) {
- int mode = 0;
-
- if (!rootshell || !iflag)
- mode = SHOW_SIGNALLED;
- if ((job == thisjob && (flags & WNOFREE) == 0) ||
- job != thisjob)
- mode = SHOW_SIGNALLED | SHOW_NO_FREE;
- if (mode && (flags & WSILENT) == 0)
- showjob(out2, thisjob, mode);
- else {
- VTRACE(DBG_JOBS,
- ("Not printing status, rootshell=%d, job=%p\n",
- rootshell, job));
- thisjob->flags |= JOBCHANGED;
- }
- }
-
- INTON;
- return pid;
-}
-
-
-
-/*
- * Do a wait system call. If job control is compiled in, we accept
- * stopped processes. If block is zero, we return a value of zero
- * rather than blocking.
- *
- * System V doesn't have a non-blocking wait system call. It does
- * have a SIGCLD signal that is sent to a process when one of its
- * children dies. The obvious way to use SIGCLD would be to install
- * a handler for SIGCLD which simply bumped a counter when a SIGCLD
- * was received, and have waitproc bump another counter when it got
- * the status of a process. Waitproc would then know that a wait
- * system call would not block if the two counters were different.
- * This approach doesn't work because if a process has children that
- * have not been waited for, System V will send it a SIGCLD when it
- * installs a signal handler for SIGCLD. What this means is that when
- * a child exits, the shell will be sent SIGCLD signals continuously
- * until is runs out of stack space, unless it does a wait call before
- * restoring the signal handler. The code below takes advantage of
- * this (mis)feature by installing a signal handler for SIGCLD and
- * then checking to see whether it was called. If there are any
- * children to be waited for, it will be.
- *
- * If neither SYSV nor BSD is defined, we don't implement nonblocking
- * waits at all. In this case, the user will not be informed when
- * a background process until the next time she runs a real program
- * (as opposed to running a builtin command or just typing return),
- * and the jobs command may give out of date information.
- */
-
-#ifdef SYSV
-STATIC int gotsigchild;
-
-STATIC int onsigchild() {
- gotsigchild = 1;
-}
-#endif
-
-
-STATIC int
-waitproc(int block, struct job *jp, int *status)
-{
-#ifdef BSD
- int flags = 0;
-
-#if JOBS
- if (mflag || (jp != NULL && jp->jobctl))
- flags |= WUNTRACED | WCONTINUED;
-#endif
- if (block == 0)
- flags |= WNOHANG;
- VTRACE(DBG_WAIT, ("waitproc: doing waitpid(flags=%#x)\n", flags));
- return waitpid(-1, status, flags);
-#else
-#ifdef SYSV
- int (*save)();
-
- if (block == 0) {
- gotsigchild = 0;
- save = signal(SIGCLD, onsigchild);
- signal(SIGCLD, save);
- if (gotsigchild == 0)
- return 0;
- }
- return wait(status);
-#else
- if (block == 0)
- return 0;
- return wait(status);
-#endif
-#endif
-}
-
-/*
- * return 1 if there are stopped jobs, otherwise 0
- */
-int job_warning = 0;
-int
-stoppedjobs(void)
-{
- int jobno;
- struct job *jp;
-
- if (job_warning || jobs_invalid)
- return (0);
- for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
- if (jp->used == 0)
- continue;
- if (jp->state == JOBSTOPPED) {
- out2str("You have stopped jobs.\n");
- job_warning = 2;
- return (1);
- }
- }
-
- return (0);
-}
-
-/*
- * Return a string identifying a command (to be printed by the
- * jobs command).
- */
-
-STATIC char *cmdnextc;
-STATIC int cmdnleft;
-
-void
-commandtext(struct procstat *ps, union node *n)
-{
- int len;
-
- cmdnextc = ps->cmd;
- if (iflag || mflag || sizeof(ps->cmd) <= 60)
- len = sizeof(ps->cmd);
- else if (sizeof ps->cmd <= 400)
- len = 50;
- else if (sizeof ps->cmd <= 800)
- len = 80;
- else
- len = sizeof(ps->cmd) / 10;
- cmdnleft = len;
- cmdtxt(n);
- if (cmdnleft <= 0) {
- char *p = ps->cmd + len - 4;
- p[0] = '.';
- p[1] = '.';
- p[2] = '.';
- p[3] = 0;
- } else
- *cmdnextc = '\0';
-
- VTRACE(DBG_JOBS,
- ("commandtext: ps->cmd %p, end %p, left %d\n\t\"%s\"\n",
- ps->cmd, cmdnextc, cmdnleft, ps->cmd));
-}
-
-
-STATIC void
-cmdtxt(union node *n)
-{
- union node *np;
- struct nodelist *lp;
- const char *p;
- int i;
-
- if (n == NULL || cmdnleft <= 0)
- return;
- switch (n->type) {
- case NSEMI:
- cmdtxt(n->nbinary.ch1);
- cmdputs("; ");
- cmdtxt(n->nbinary.ch2);
- break;
- case NAND:
- cmdtxt(n->nbinary.ch1);
- cmdputs(" && ");
- cmdtxt(n->nbinary.ch2);
- break;
- case NOR:
- cmdtxt(n->nbinary.ch1);
- cmdputs(" || ");
- cmdtxt(n->nbinary.ch2);
- break;
- case NDNOT:
- cmdputs("! ");
- /* FALLTHROUGH */
- case NNOT:
- cmdputs("! ");
- cmdtxt(n->nnot.com);
- break;
- case NPIPE:
- for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
- cmdtxt(lp->n);
- if (lp->next)
- cmdputs(" | ");
- }
- if (n->npipe.backgnd)
- cmdputs(" &");
- break;
- case NSUBSHELL:
- cmdputs("(");
- cmdtxt(n->nredir.n);
- cmdputs(")");
- break;
- case NREDIR:
- case NBACKGND:
- cmdtxt(n->nredir.n);
- break;
- case NIF:
- cmdputs("if ");
- cmdtxt(n->nif.test);
- cmdputs("; then ");
- cmdtxt(n->nif.ifpart);
- if (n->nif.elsepart) {
- cmdputs("; else ");
- cmdtxt(n->nif.elsepart);
- }
- cmdputs("; fi");
- break;
- case NWHILE:
- cmdputs("while ");
- goto until;
- case NUNTIL:
- cmdputs("until ");
- until:
- cmdtxt(n->nbinary.ch1);
- cmdputs("; do ");
- cmdtxt(n->nbinary.ch2);
- cmdputs("; done");
- break;
- case NFOR:
- cmdputs("for ");
- cmdputs(n->nfor.var);
- cmdputs(" in ");
- cmdlist(n->nfor.args, 1);
- cmdputs("; do ");
- cmdtxt(n->nfor.body);
- cmdputs("; done");
- break;
- case NCASE:
- cmdputs("case ");
- cmdputs(n->ncase.expr->narg.text);
- cmdputs(" in ");
- for (np = n->ncase.cases; np; np = np->nclist.next) {
- cmdtxt(np->nclist.pattern);
- cmdputs(") ");
- cmdtxt(np->nclist.body);
- switch (n->type) { /* switch (not if) for later */
- case NCLISTCONT:
- cmdputs(";& ");
- break;
- default:
- cmdputs(";; ");
- break;
- }
- }
- cmdputs("esac");
- break;
- case NDEFUN:
- cmdputs(n->narg.text);
- cmdputs("() { ... }");
- break;
- case NCMD:
- cmdlist(n->ncmd.args, 1);
- cmdlist(n->ncmd.redirect, 0);
- if (n->ncmd.backgnd)
- cmdputs(" &");
- break;
- case NARG:
- cmdputs(n->narg.text);
- break;
- case NTO:
- p = ">"; i = 1; goto redir;
- case NCLOBBER:
- p = ">|"; i = 1; goto redir;
- case NAPPEND:
- p = ">>"; i = 1; goto redir;
- case NTOFD:
- p = ">&"; i = 1; goto redir;
- case NFROM:
- p = "<"; i = 0; goto redir;
- case NFROMFD:
- p = "<&"; i = 0; goto redir;
- case NFROMTO:
- p = "<>"; i = 0; goto redir;
- redir:
- if (n->nfile.fd != i)
- cmdputi(n->nfile.fd);
- cmdputs(p);
- if (n->type == NTOFD || n->type == NFROMFD) {
- if (n->ndup.dupfd < 0)
- cmdputs("-");
- else
- cmdputi(n->ndup.dupfd);
- } else {
- cmdtxt(n->nfile.fname);
- }
- break;
- case NHERE:
- case NXHERE:
- cmdputs("<<...");
- break;
- default:
- cmdputs("???");
- break;
- }
-}
-
-STATIC void
-cmdlist(union node *np, int sep)
-{
- for (; np; np = np->narg.next) {
- if (!sep)
- cmdputs(" ");
- cmdtxt(np);
- if (sep && np->narg.next)
- cmdputs(" ");
- }
-}
-
-
-STATIC void
-cmdputs(const char *s)
-{
- const char *p, *str = 0;
- char c, cc[2] = " ";
- char *nextc;
- int nleft;
- int subtype = 0;
- int quoted = 0;
- static char vstype[16][4] = { "", "}", "-", "+", "?", "=",
- "#", "##", "%", "%%", "}" };
-
- p = s;
- nextc = cmdnextc;
- nleft = cmdnleft;
- while (nleft > 0 && (c = *p++) != 0) {
- switch (c) {
- case CTLNONL:
- c = '\0';
- break;
- case CTLESC:
- c = *p++;
- break;
- case CTLVAR:
- subtype = *p++;
- if (subtype & VSLINENO) { /* undo LINENO hack */
- if ((subtype & VSTYPE) == VSLENGTH)
- str = "${#LINENO"; /*}*/
- else
- str = "${LINENO"; /*}*/
- while (is_digit(*p))
- p++;
- } else if ((subtype & VSTYPE) == VSLENGTH)
- str = "${#"; /*}*/
- else
- str = "${"; /*}*/
- if (!(subtype & VSQUOTE) != !(quoted & 1)) {
- quoted ^= 1;
- c = '"';
- } else {
- c = *str++;
- }
- break;
- case CTLENDVAR: /*{*/
- c = '}';
- if (quoted & 1)
- str = "\"";
- quoted >>= 1;
- subtype = 0;
- break;
- case CTLBACKQ:
- c = '$';
- str = "(...)";
- break;
- case CTLBACKQ+CTLQUOTE:
- c = '"';
- str = "$(...)\"";
- break;
- case CTLARI:
- c = '$';
- if (*p == ' ')
- p++;
- str = "(("; /*))*/
- break;
- case CTLENDARI: /*((*/
- c = ')';
- str = ")";
- break;
- case CTLQUOTEMARK:
- quoted ^= 1;
- c = '"';
- break;
- case CTLQUOTEEND:
- quoted >>= 1;
- c = '"';
- break;
- case '=':
- if (subtype == 0)
- break;
- str = vstype[subtype & VSTYPE];
- if (subtype & VSNUL)
- c = ':';
- else
- c = *str++; /*{*/
- if (c != '}')
- quoted <<= 1;
- else if (*p == CTLENDVAR)
- c = *str++;
- subtype = 0;
- break;
- case '\'':
- case '\\':
- case '"':
- case '$':
- /* These can only happen inside quotes */
- cc[0] = c;
- str = cc;
- c = '\\';
- break;
- default:
- break;
- }
- if (c != '\0') do { /* c == 0 implies nothing in str */
- *nextc++ = c;
- } while (--nleft > 0 && str && (c = *str++));
- str = 0;
- }
- if ((quoted & 1) && nleft) {
- *nextc++ = '"';
- nleft--;
- }
- cmdnleft = nleft;
- cmdnextc = nextc;
-}
diff --git a/bin/sh/jobs.h b/bin/sh/jobs.h
deleted file mode 100644
index a587e9e..0000000
--- a/bin/sh/jobs.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/* $NetBSD: jobs.h,v 1.23 2018/09/11 03:30:40 kre Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- *
- * @(#)jobs.h 8.2 (Berkeley) 5/4/95
- */
-
-#include "output.h"
-
-/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
-#define FORK_FG 0
-#define FORK_BG 1
-#define FORK_NOJOB 2
-
-/* mode flags for showjob(s) */
-#define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
-#define SHOW_MULTILINE 0x02 /* one line per process */
-#define SHOW_PID 0x04 /* include process pid */
-#define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
-#define SHOW_SIGNALLED 0x10 /* only if stopped/exited on signal */
-#define SHOW_ISSIG 0x20 /* job was signalled */
-#define SHOW_NO_FREE 0x40 /* do not free job */
-
-
-/*
- * A job structure contains information about a job. A job is either a
- * single process or a set of processes contained in a pipeline. In the
- * latter case, pidlist will be non-NULL, and will point to a -1 terminated
- * array of pids.
- */
-#define MAXCMDTEXT 200
-
-struct procstat {
- pid_t pid; /* process id */
- int status; /* last process status from wait() */
- char cmd[MAXCMDTEXT];/* text of command being run */
-};
-
-struct job {
- struct procstat ps0; /* status of process */
- struct procstat *ps; /* status or processes when more than one */
- void *ref; /* temporary reference, used variously */
- int nprocs; /* number of processes */
- pid_t pgrp; /* process group of this job */
- char state;
-#define JOBRUNNING 0 /* at least one proc running */
-#define JOBSTOPPED 1 /* all procs are stopped */
-#define JOBDONE 2 /* all procs are completed */
- char used; /* true if this entry is in used */
- char flags;
-#define JOBCHANGED 1 /* set if status has changed */
-#define JOBWANTED 2 /* set if this is a job being sought */
-#define JPIPEFAIL 4 /* set if -o pipefail when job created */
-#if JOBS
- char jobctl; /* job running under job control */
- int prev_job; /* previous job index */
-#endif
-};
-
-extern pid_t backgndpid; /* pid of last background process */
-extern int job_warning; /* user was warned about stopped jobs */
-
-void setjobctl(int);
-void showjobs(struct output *, int);
-struct job *makejob(union node *, int);
-int forkshell(struct job *, union node *, int);
-void forkchild(struct job *, union node *, int, int);
-int forkparent(struct job *, union node *, int, pid_t);
-int waitforjob(struct job *);
-int stoppedjobs(void);
-void commandtext(struct procstat *, union node *);
-int getjobpgrp(const char *);
-
-#if ! JOBS
-#define setjobctl(on) /* do nothing */
-#endif
diff --git a/bin/sh/machdep.h b/bin/sh/machdep.h
deleted file mode 100644
index 14e803b..0000000
--- a/bin/sh/machdep.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/* $NetBSD: machdep.h,v 1.11 2003/08/07 09:05:33 agc Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- *
- * @(#)machdep.h 8.2 (Berkeley) 5/4/95
- */
-
-/*
- * Most machines require the value returned from malloc to be aligned
- * in some way. The following macro will get this right on many machines.
- */
-
-#define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1)
-/*
- * It appears that grabstackstr() will barf with such alignments
- * because stalloc() will return a string allocated in a new stackblock.
- */
-#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
diff --git a/bin/sh/mail.c b/bin/sh/mail.c
deleted file mode 100644
index 484b50f..0000000
--- a/bin/sh/mail.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/* $NetBSD: mail.c,v 1.18 2017/06/04 20:28:13 kre Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- */
-
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)mail.c 8.2 (Berkeley) 5/4/95";
-#else
-__RCSID("$NetBSD: mail.c,v 1.18 2017/06/04 20:28:13 kre Exp $");
-#endif
-#endif /* not lint */
-
-/*
- * Routines to check for mail. (Perhaps make part of main.c?)
- */
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "shell.h"
-#include "exec.h" /* defines padvance() */
-#include "var.h"
-#include "output.h"
-#include "memalloc.h"
-#include "error.h"
-#include "mail.h"
-
-
-#define MAXMBOXES 10
-
-
-STATIC int nmboxes; /* number of mailboxes */
-STATIC off_t mailsize[MAXMBOXES]; /* sizes of mailboxes */
-
-
-
-/*
- * Print appropriate message(s) if mail has arrived. If the argument is
- * nozero, then the value of MAIL has changed, so we just update the
- * values.
- */
-
-void
-chkmail(int silent)
-{
- int i;
- const char *mpath;
- char *p;
- char *q;
- struct stackmark smark;
- struct stat statb;
-
- if (silent)
- nmboxes = 10;
- if (nmboxes == 0)
- return;
- setstackmark(&smark);
- mpath = mpathset() ? mpathval() : mailval();
- for (i = 0 ; i < nmboxes ; i++) {
- p = padvance(&mpath, nullstr, 1);
- if (p == NULL)
- break;
- stunalloc(p);
- if (*p == '\0')
- continue;
- for (q = p ; *q ; q++)
- ;
- if (q[-1] != '/')
- abort();
- q[-1] = '\0'; /* delete trailing '/' */
-#ifdef notdef /* this is what the System V shell claims to do (it lies) */
- if (stat(p, &statb) < 0)
- statb.st_mtime = 0;
- if (statb.st_mtime > mailtime[i] && ! silent) {
- out2str(pathopt ? pathopt : "you have mail");
- out2c('\n');
- }
- mailtime[i] = statb.st_mtime;
-#else /* this is what it should do */
- if (stat(p, &statb) < 0)
- statb.st_size = 0;
- if (statb.st_size > mailsize[i] && ! silent) {
- const char *pp;
-
- if ((pp = pathopt) != NULL) {
- int len = 0;
-
- while (*pp && *pp != ':')
- len++, pp++;
- if (len == 0) {
- CHECKSTRSPACE(16, p);
- strcat(p, ": file changed");
- } else {
- while (stackblocksize() <= len)
- growstackblock();
- p = stackblock();
- memcpy(p, pathopt, len);
- p[len] = '\0';
- }
- pp = p;
- } else
- pp = "you have mail";
-
- out2str(pp);
- out2c('\n');
- }
- mailsize[i] = statb.st_size;
-#endif
- }
- nmboxes = i;
- popstackmark(&smark);
-}
diff --git a/bin/sh/mail.h b/bin/sh/mail.h
deleted file mode 100644
index 9ea7c21..0000000
--- a/bin/sh/mail.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/* $NetBSD: mail.h,v 1.10 2003/08/07 09:05:34 agc Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- *
- * @(#)mail.h 8.2 (Berkeley) 5/4/95
- */
-
-void chkmail(int);
diff --git a/bin/sh/main.c b/bin/sh/main.c
deleted file mode 100644
index a023611..0000000
--- a/bin/sh/main.c
+++ /dev/null
@@ -1,393 +0,0 @@
-/* $NetBSD: main.c,v 1.80 2019/01/19 14:20:22 kre Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- */
-
-#include <sys/cdefs.h>
-#ifndef lint
-__COPYRIGHT("@(#) Copyright (c) 1991, 1993\
- The Regents of the University of California. All rights reserved.");
-#endif /* not lint */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)main.c 8.7 (Berkeley) 7/19/95";
-#else
-__RCSID("$NetBSD: main.c,v 1.80 2019/01/19 14:20:22 kre Exp $");
-#endif
-#endif /* not lint */
-
-#include <errno.h>
-#include <stdio.h>
-#include <signal.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <locale.h>
-#include <fcntl.h>
-
-
-#include "shell.h"
-#include "main.h"
-#include "mail.h"
-#include "options.h"
-#include "builtins.h"
-#include "output.h"
-#include "parser.h"
-#include "nodes.h"
-#include "expand.h"
-#include "eval.h"
-#include "jobs.h"
-#include "input.h"
-#include "trap.h"
-#include "var.h"
-#include "show.h"
-#include "memalloc.h"
-#include "error.h"
-#include "init.h"
-#include "mystring.h"
-#include "exec.h"
-#include "cd.h"
-#include "redir.h"
-
-#define PROFILE 0
-
-int rootpid;
-int rootshell;
-struct jmploc main_handler;
-int max_user_fd;
-#if PROFILE
-short profile_buf[16384];
-extern int etext();
-#endif
-
-STATIC void read_profile(const char *);
-
-/*
- * Main routine. We initialize things, parse the arguments, execute
- * profiles if we're a login shell, and then call cmdloop to execute
- * commands. The setjmp call sets up the location to jump to when an
- * exception occurs. When an exception occurs the variable "state"
- * is used to figure out how far we had gotten.
- */
-
-int
-main(int argc, char **argv)
-{
- struct stackmark smark;
- volatile int state;
- char *shinit;
- uid_t uid;
- gid_t gid;
-
- uid = getuid();
- gid = getgid();
-
- max_user_fd = fcntl(0, F_MAXFD);
- if (max_user_fd < 2)
- max_user_fd = 2;
-
- setlocale(LC_ALL, "");
-
- posix = getenv("POSIXLY_CORRECT") != NULL;
-#if PROFILE
- monitor(4, etext, profile_buf, sizeof profile_buf, 50);
-#endif
- state = 0;
- if (setjmp(main_handler.loc)) {
- /*
- * When a shell procedure is executed, we raise the
- * exception EXSHELLPROC to clean up before executing
- * the shell procedure.
- */
- switch (exception) {
- case EXSHELLPROC:
- rootpid = getpid();
- rootshell = 1;
- minusc = NULL;
- state = 3;
- break;
-
- case EXEXEC:
- exitstatus = exerrno;
- break;
-
- case EXERROR:
- exitstatus = 2;
- break;
-
- default:
- break;
- }
-
- if (exception != EXSHELLPROC) {
- if (state == 0 || iflag == 0 || ! rootshell ||
- exception == EXEXIT)
- exitshell(exitstatus);
- }
- reset();
- if (exception == EXINT) {
- out2c('\n');
- flushout(&errout);
- }
- popstackmark(&smark);
- FORCEINTON; /* enable interrupts */
- if (state == 1)
- goto state1;
- else if (state == 2)
- goto state2;
- else if (state == 3)
- goto state3;
- else
- goto state4;
- }
- handler = &main_handler;
-#ifdef DEBUG
-#if DEBUG >= 2
- debug = 1; /* this may be reset by procargs() later */
-#endif
- opentrace();
- trputs("Shell args: "); trargs(argv);
-#if DEBUG >= 3
- set_debug(((DEBUG)==3 ? "_@" : "++"), 1);
-#endif
-#endif
- rootpid = getpid();
- rootshell = 1;
- init();
- initpwd();
- setstackmark(&smark);
- procargs(argc, argv);
-
- /*
- * Limit bogus system(3) or popen(3) calls in setuid binaries,
- * by requiring the -p flag
- */
- if (!pflag && (uid != geteuid() || gid != getegid())) {
- setuid(uid);
- setgid(gid);
- /* PS1 might need to be changed accordingly. */
- choose_ps1();
- }
-
- if (argv[0] && argv[0][0] == '-') {
- state = 1;
- read_profile("/etc/profile");
- state1:
- state = 2;
- read_profile(".profile");
- }
- state2:
- state = 3;
- if ((iflag || !posix) &&
- getuid() == geteuid() && getgid() == getegid()) {
- struct stackmark env_smark;
-
- setstackmark(&env_smark);
- if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
- state = 3;
- read_profile(expandenv(shinit));
- }
- popstackmark(&env_smark);
- }
- state3:
- state = 4;
- line_number = 1; /* undo anything from profile files */
-
- if (sflag == 0 || minusc) {
- static int sigs[] = {
- SIGINT, SIGQUIT, SIGHUP,
-#ifdef SIGTSTP
- SIGTSTP,
-#endif
- SIGPIPE
- };
-#define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0]))
- size_t i;
-
- for (i = 0; i < SIGSSIZE; i++)
- setsignal(sigs[i], 0);
- }
-
- if (minusc)
- evalstring(minusc, sflag ? 0 : EV_EXIT);
-
- if (sflag || minusc == NULL) {
- state4: /* XXX ??? - why isn't this before the "if" statement */
- cmdloop(1);
- }
-#if PROFILE
- monitor(0);
-#endif
- line_number = plinno;
- exitshell(exitstatus);
- /* NOTREACHED */
-}
-
-
-/*
- * Read and execute commands. "Top" is nonzero for the top level command
- * loop; it turns on prompting if the shell is interactive.
- */
-
-void
-cmdloop(int top)
-{
- union node *n;
- struct stackmark smark;
- int inter;
- int numeof = 0;
- enum skipstate skip;
-
- CTRACE(DBG_ALWAYS, ("cmdloop(%d) called\n", top));
- setstackmark(&smark);
- for (;;) {
- if (pendingsigs)
- dotrap();
- inter = 0;
- if (iflag == 1 && top) {
- inter = 1;
- showjobs(out2, SHOW_CHANGED);
- chkmail(0);
- flushout(&errout);
- nflag = 0;
- }
- n = parsecmd(inter);
- VXTRACE(DBG_PARSE|DBG_EVAL|DBG_CMDS,("cmdloop: "),showtree(n));
- if (n == NEOF) {
- if (!top || numeof >= 50)
- break;
- if (nflag)
- break;
- if (!stoppedjobs()) {
- if (!iflag || !Iflag)
- break;
- out2str("\nUse \"exit\" to leave shell.\n");
- }
- numeof++;
- } else if (n != NULL && nflag == 0) {
- job_warning = (job_warning == 2) ? 1 : 0;
- numeof = 0;
- evaltree(n, 0);
- }
- rststackmark(&smark);
-
- /*
- * Any SKIP* can occur here! SKIP(FUNC|BREAK|CONT) occur when
- * a dotcmd is in a loop or a function body and appropriate
- * built-ins occurs in file scope in the sourced file. Values
- * other than SKIPFILE are reset by the appropriate eval*()
- * that contained the dotcmd() call.
- */
- skip = current_skipstate();
- if (skip != SKIPNONE) {
- if (skip == SKIPFILE)
- stop_skipping();
- break;
- }
- }
- popstackmark(&smark);
-}
-
-
-
-/*
- * Read /etc/profile or .profile. Return on error.
- */
-
-STATIC void
-read_profile(const char *name)
-{
- int fd;
- int xflag_set = 0;
- int vflag_set = 0;
-
- if (*name == '\0')
- return;
-
- INTOFF;
- if ((fd = open(name, O_RDONLY)) >= 0)
- setinputfd(fd, 1);
- INTON;
- if (fd < 0)
- return;
- /* -q turns off -x and -v just when executing init files */
- if (qflag) {
- if (xflag)
- xflag = 0, xflag_set = 1;
- if (vflag)
- vflag = 0, vflag_set = 1;
- }
- cmdloop(0);
- if (qflag) {
- if (xflag_set)
- xflag = 1;
- if (vflag_set)
- vflag = 1;
- }
- popfile();
-}
-
-
-
-/*
- * Read a file containing shell functions.
- */
-
-void
-readcmdfile(char *name)
-{
- int fd;
-
- INTOFF;
- if ((fd = open(name, O_RDONLY)) >= 0)
- setinputfd(fd, 1);
- else
- error("Can't open %s", name);
- INTON;
- cmdloop(0);
- popfile();
-}
-
-
-
-int
-exitcmd(int argc, char **argv)
-{
- if (stoppedjobs())
- return 0;
- if (argc > 1)
- exitshell(number(argv[1]));
- else
- exitshell_savedstatus();
- /* NOTREACHED */
-}
diff --git a/bin/sh/main.h b/bin/sh/main.h
deleted file mode 100644
index db1d576..0000000
--- a/bin/sh/main.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* $NetBSD: main.h,v 1.12 2018/12/03 02:38:30 kre Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- *
- * @(#)main.h 8.2 (Berkeley) 5/4/95
- */
-
-extern int rootpid; /* pid of main shell */
-extern int rootshell; /* true if we aren't a child of the main shell */
-extern struct jmploc main_handler; /* top level exception handler */
-
-void readcmdfile(char *);
-void cmdloop(int);
diff --git a/bin/sh/memalloc.c b/bin/sh/memalloc.c
deleted file mode 100644
index da8ff3c..0000000
--- a/bin/sh/memalloc.c
+++ /dev/null
@@ -1,334 +0,0 @@
-/* $NetBSD: memalloc.c,v 1.32 2018/08/22 20:08:54 kre Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- */
-
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)memalloc.c 8.3 (Berkeley) 5/4/95";
-#else
-__RCSID("$NetBSD: memalloc.c,v 1.32 2018/08/22 20:08:54 kre Exp $");
-#endif
-#endif /* not lint */
-
-#include <stdlib.h>
-#include <unistd.h>
-
-#include "shell.h"
-#include "output.h"
-#include "memalloc.h"
-#include "error.h"
-#include "machdep.h"
-#include "mystring.h"
-
-/*
- * Like malloc, but returns an error when out of space.
- */
-
-pointer
-ckmalloc(size_t nbytes)
-{
- pointer p;
-
- p = malloc(nbytes);
- if (p == NULL)
- error("Out of space");
- return p;
-}
-
-
-/*
- * Same for realloc.
- */
-
-pointer
-ckrealloc(pointer p, int nbytes)
-{
- p = realloc(p, nbytes);
- if (p == NULL)
- error("Out of space");
- return p;
-}
-
-
-/*
- * Make a copy of a string in safe storage.
- */
-
-char *
-savestr(const char *s)
-{
- char *p;
-
- p = ckmalloc(strlen(s) + 1);
- scopy(s, p);
- return p;
-}
-
-
-/*
- * Parse trees for commands are allocated in lifo order, so we use a stack
- * to make this more efficient, and also to avoid all sorts of exception
- * handling code to handle interrupts in the middle of a parse.
- *
- * The size 504 was chosen because the Ultrix malloc handles that size
- * well.
- */
-
-#define MINSIZE 504 /* minimum size of a block */
-
-struct stack_block {
- struct stack_block *prev;
- char space[MINSIZE];
-};
-
-struct stack_block stackbase;
-struct stack_block *stackp = &stackbase;
-struct stackmark *markp;
-char *stacknxt = stackbase.space;
-int stacknleft = MINSIZE;
-int sstrnleft;
-int herefd = -1;
-
-pointer
-stalloc(int nbytes)
-{
- char *p;
-
- nbytes = SHELL_ALIGN(nbytes);
- if (nbytes > stacknleft) {
- int blocksize;
- struct stack_block *sp;
-
- blocksize = nbytes;
- if (blocksize < MINSIZE)
- blocksize = MINSIZE;
- INTOFF;
- sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
- sp->prev = stackp;
- stacknxt = sp->space;
- stacknleft = blocksize;
- stackp = sp;
- INTON;
- }
- p = stacknxt;
- stacknxt += nbytes;
- stacknleft -= nbytes;
- return p;
-}
-
-
-void
-stunalloc(pointer p)
-{
- if (p == NULL) { /*DEBUG */
- write(2, "stunalloc\n", 10);
- abort();
- }
- stacknleft += stacknxt - (char *)p;
- stacknxt = p;
-}
-
-
-/* save the current status of the sh stack */
-void
-setstackmark(struct stackmark *mark)
-{
- mark->stackp = stackp;
- mark->stacknxt = stacknxt;
- mark->stacknleft = stacknleft;
- mark->sstrnleft = sstrnleft;
- mark->marknext = markp;
- markp = mark;
-}
-
-/* reset the stack mark, and remove it from the list of marks */
-void
-popstackmark(struct stackmark *mark)
-{
- markp = mark->marknext; /* delete mark from the list */
- rststackmark(mark); /* and reset stack */
-}
-
-/* reset the shell stack to its state recorded in the stack mark */
-void
-rststackmark(struct stackmark *mark)
-{
- struct stack_block *sp;
-
- INTOFF;
- while (stackp != mark->stackp) {
- /* delete any recently allocated mem blocks */
- sp = stackp;
- stackp = sp->prev;
- ckfree(sp);
- }
- stacknxt = mark->stacknxt;
- stacknleft = mark->stacknleft;
- sstrnleft = mark->sstrnleft;
- INTON;
-}
-
-
-/*
- * When the parser reads in a string, it wants to stick the string on the
- * stack and only adjust the stack pointer when it knows how big the
- * string is. Stackblock (defined in stack.h) returns a pointer to a block
- * of space on top of the stack and stackblocklen returns the length of
- * this block. Growstackblock will grow this space by at least one byte,
- * possibly moving it (like realloc). Grabstackblock actually allocates the
- * part of the block that has been used.
- */
-
-void
-growstackblock(void)
-{
- int newlen = SHELL_ALIGN(stacknleft * 2 + 100);
-
- INTOFF;
- if (stacknxt == stackp->space && stackp != &stackbase) {
- struct stack_block *oldstackp;
- struct stackmark *xmark;
- struct stack_block *sp;
-
- oldstackp = stackp;
- sp = stackp;
- stackp = sp->prev;
- sp = ckrealloc((pointer)sp,
- sizeof(struct stack_block) - MINSIZE + newlen);
- sp->prev = stackp;
- stackp = sp;
- stacknxt = sp->space;
- sstrnleft += newlen - stacknleft;
- stacknleft = newlen;
-
- /*
- * Stack marks pointing to the start of the old block
- * must be relocated to point to the new block
- */
- xmark = markp;
- while (xmark != NULL && xmark->stackp == oldstackp) {
- xmark->stackp = stackp;
- xmark->stacknxt = stacknxt;
- xmark->sstrnleft += stacknleft - xmark->stacknleft;
- xmark->stacknleft = stacknleft;
- xmark = xmark->marknext;
- }
- } else {
- char *oldspace = stacknxt;
- int oldlen = stacknleft;
- char *p = stalloc(newlen);
-
- (void)memcpy(p, oldspace, oldlen);
- stacknxt = p; /* free the space */
- stacknleft += newlen; /* we just allocated */
- }
- INTON;
-}
-
-void
-grabstackblock(int len)
-{
- len = SHELL_ALIGN(len);
- stacknxt += len;
- stacknleft -= len;
-}
-
-/*
- * The following routines are somewhat easier to use than the above.
- * The user declares a variable of type STACKSTR, which may be declared
- * to be a register. The macro STARTSTACKSTR initializes things. Then
- * the user uses the macro STPUTC to add characters to the string. In
- * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
- * grown as necessary. When the user is done, she can just leave the
- * string there and refer to it using stackblock(). Or she can allocate
- * the space for it using grabstackstr(). If it is necessary to allow
- * someone else to use the stack temporarily and then continue to grow
- * the string, the user should use grabstack to allocate the space, and
- * then call ungrabstr(p) to return to the previous mode of operation.
- *
- * USTPUTC is like STPUTC except that it doesn't check for overflow.
- * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
- * is space for at least one character.
- */
-
-char *
-growstackstr(void)
-{
- int len = stackblocksize();
- if (herefd >= 0 && len >= 1024) {
- xwrite(herefd, stackblock(), len);
- sstrnleft = len - 1;
- return stackblock();
- }
- growstackblock();
- sstrnleft = stackblocksize() - len - 1;
- return stackblock() + len;
-}
-
-/*
- * Called from CHECKSTRSPACE.
- */
-
-char *
-makestrspace(void)
-{
- int len = stackblocksize() - sstrnleft;
- growstackblock();
- sstrnleft = stackblocksize() - len;
- return stackblock() + len;
-}
-
-/*
- * Note that this only works to release stack space for reuse
- * if nothing else has allocated space on the stack since the grabstackstr()
- *
- * "s" is the start of the area to be released, and "p" represents the end
- * of the string we have stored beyond there and are now releasing.
- * (ie: "p" should be the same as in the call to grabstackstr()).
- *
- * stunalloc(s) and ungrabstackstr(s, p) are almost interchangable after
- * a grabstackstr(), however the latter also returns string space so we
- * can just continue with STPUTC() etc without needing a new STARTSTACKSTR(s)
- */
-void
-ungrabstackstr(char *s, char *p)
-{
-#ifdef DEBUG
- if (s < stacknxt || stacknxt + stacknleft < s)
- abort();
-#endif
- stacknleft += stacknxt - s;
- stacknxt = s;
- sstrnleft = stacknleft - (p - s);
-}
diff --git a/bin/sh/memalloc.h b/bin/sh/memalloc.h
deleted file mode 100644
index ed6669e..0000000
--- a/bin/sh/memalloc.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/* $NetBSD: memalloc.h,v 1.18 2018/08/22 20:08:54 kre Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- *
- * @(#)memalloc.h 8.2 (Berkeley) 5/4/95
- */
-
-struct stackmark {
- struct stack_block *stackp;
- char *stacknxt;
- int stacknleft;
- int sstrnleft;
- struct stackmark *marknext;
-};
-
-
-extern char *stacknxt;
-extern int stacknleft;
-extern int sstrnleft;
-extern int herefd;
-
-pointer ckmalloc(size_t);
-pointer ckrealloc(pointer, int);
-char *savestr(const char *);
-pointer stalloc(int);
-void stunalloc(pointer);
-void setstackmark(struct stackmark *);
-void popstackmark(struct stackmark *);
-void rststackmark(struct stackmark *);
-void growstackblock(void);
-void grabstackblock(int);
-char *growstackstr(void);
-char *makestrspace(void);
-void ungrabstackstr(char *, char *);
-
-
-
-#define stackblock() stacknxt
-#define stackblocksize() stacknleft
-#define STARTSTACKSTR(p) p = stackblock(), sstrnleft = stackblocksize()
-#define STPUTC(c, p) (--sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(), *p++ = (c)))
-#define CHECKSTRSPACE(n, p) { if (sstrnleft < n) p = makestrspace(); }
-#define USTPUTC(c, p) (--sstrnleft, *p++ = (c))
-#define STACKSTRNUL(p) (sstrnleft == 0? (p = growstackstr(), sstrnleft++, *p = '\0') : (*p = '\0'))
-#define STUNPUTC(p) (++sstrnleft, --p)
-#define STTOPC(p) p[-1]
-#define STADJUST(amount, p) (p += (amount), sstrnleft -= (amount))
-#define grabstackstr(p) stalloc((p) - stackblock())
-
-#define ckfree(p) free((pointer)(p))
diff --git a/bin/sh/miscbltin.c b/bin/sh/miscbltin.c
deleted file mode 100644
index 3988532..0000000
--- a/bin/sh/miscbltin.c
+++ /dev/null
@@ -1,458 +0,0 @@
-/* $NetBSD: miscbltin.c,v 1.44 2017/05/13 15:03:34 gson Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- */
-
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)miscbltin.c 8.4 (Berkeley) 5/4/95";
-#else
-__RCSID("$NetBSD: miscbltin.c,v 1.44 2017/05/13 15:03:34 gson Exp $");
-#endif
-#endif /* not lint */
-
-/*
- * Miscelaneous builtins.
- */
-
-#include <sys/types.h> /* quad_t */
-#include <sys/param.h> /* BSD4_4 */
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <errno.h>
-
-#include "shell.h"
-#include "options.h"
-#include "var.h"
-#include "output.h"
-#include "memalloc.h"
-#include "error.h"
-#include "builtins.h"
-#include "mystring.h"
-
-#undef rflag
-
-
-
-/*
- * The read builtin.
- * Backslahes escape the next char unless -r is specified.
- *
- * This uses unbuffered input, which may be avoidable in some cases.
- *
- * Note that if IFS=' :' then read x y should work so that:
- * 'a b' x='a', y='b'
- * ' a b ' x='a', y='b'
- * ':b' x='', y='b'
- * ':' x='', y=''
- * '::' x='', y=''
- * ': :' x='', y=''
- * ':::' x='', y='::'
- * ':b c:' x='', y='b c:'
- */
-
-int
-readcmd(int argc, char **argv)
-{
- char **ap;
- char c;
- int rflag;
- char *prompt;
- const char *ifs;
- char *p;
- int startword;
- int status;
- int i;
- int is_ifs;
- int saveall = 0;
-
- rflag = 0;
- prompt = NULL;
- while ((i = nextopt("p:r")) != '\0') {
- if (i == 'p')
- prompt = optionarg;
- else
- rflag = 1;
- }
-
- if (prompt && isatty(0)) {
- out2str(prompt);
- flushall();
- }
-
- if (*(ap = argptr) == NULL)
- error("arg count");
-
- if ((ifs = bltinlookup("IFS", 1)) == NULL)
- ifs = " \t\n";
-
- status = 0;
- startword = 2;
- STARTSTACKSTR(p);
- for (;;) {
- if (read(0, &c, 1) != 1) {
- status = 1;
- break;
- }
- if (c == '\0')
- continue;
- if (c == '\\' && !rflag) {
- if (read(0, &c, 1) != 1) {
- status = 1;
- break;
- }
- if (c != '\n')
- STPUTC(c, p);
- continue;
- }
- if (c == '\n')
- break;
- if (strchr(ifs, c))
- is_ifs = strchr(" \t\n", c) ? 1 : 2;
- else
- is_ifs = 0;
-
- if (startword != 0) {
- if (is_ifs == 1) {
- /* Ignore leading IFS whitespace */
- if (saveall)
- STPUTC(c, p);
- continue;
- }
- if (is_ifs == 2 && startword == 1) {
- /* Only one non-whitespace IFS per word */
- startword = 2;
- if (saveall)
- STPUTC(c, p);
- continue;
- }
- }
-
- if (is_ifs == 0) {
- /* append this character to the current variable */
- startword = 0;
- if (saveall)
- /* Not just a spare terminator */
- saveall++;
- STPUTC(c, p);
- continue;
- }
-
- /* end of variable... */
- startword = is_ifs;
-
- if (ap[1] == NULL) {
- /* Last variable needs all IFS chars */
- saveall++;
- STPUTC(c, p);
- continue;
- }
-
- STACKSTRNUL(p);
- setvar(*ap, stackblock(), 0);
- ap++;
- STARTSTACKSTR(p);
- }
- STACKSTRNUL(p);
-
- /* Remove trailing IFS chars */
- for (; stackblock() <= --p; *p = 0) {
- if (!strchr(ifs, *p))
- break;
- if (strchr(" \t\n", *p))
- /* Always remove whitespace */
- continue;
- if (saveall > 1)
- /* Don't remove non-whitespace unless it was naked */
- break;
- }
- setvar(*ap, stackblock(), 0);
-
- /* Set any remaining args to "" */
- while (*++ap != NULL)
- setvar(*ap, nullstr, 0);
- return status;
-}
-
-
-
-int
-umaskcmd(int argc, char **argv)
-{
- char *ap;
- int mask;
- int i;
- int symbolic_mode = 0;
-
- while ((i = nextopt("S")) != '\0') {
- symbolic_mode = 1;
- }
-
- INTOFF;
- mask = umask(0);
- umask(mask);
- INTON;
-
- if ((ap = *argptr) == NULL) {
- if (symbolic_mode) {
- char u[4], g[4], o[4];
-
- i = 0;
- if ((mask & S_IRUSR) == 0)
- u[i++] = 'r';
- if ((mask & S_IWUSR) == 0)
- u[i++] = 'w';
- if ((mask & S_IXUSR) == 0)
- u[i++] = 'x';
- u[i] = '\0';
-
- i = 0;
- if ((mask & S_IRGRP) == 0)
- g[i++] = 'r';
- if ((mask & S_IWGRP) == 0)
- g[i++] = 'w';
- if ((mask & S_IXGRP) == 0)
- g[i++] = 'x';
- g[i] = '\0';
-
- i = 0;
- if ((mask & S_IROTH) == 0)
- o[i++] = 'r';
- if ((mask & S_IWOTH) == 0)
- o[i++] = 'w';
- if ((mask & S_IXOTH) == 0)
- o[i++] = 'x';
- o[i] = '\0';
-
- out1fmt("u=%s,g=%s,o=%s\n", u, g, o);
- } else {
- out1fmt("%.4o\n", mask);
- }
- } else {
- if (isdigit((unsigned char)*ap)) {
- mask = 0;
- do {
- if (*ap >= '8' || *ap < '0')
- error("Illegal number: %s", argv[1]);
- mask = (mask << 3) + (*ap - '0');
- } while (*++ap != '\0');
- umask(mask);
- } else {
- void *set;
-
- INTOFF;
- if ((set = setmode(ap)) != 0) {
- mask = getmode(set, ~mask & 0777);
- ckfree(set);
- }
- INTON;
- if (!set)
- error("Cannot set mode `%s' (%s)", ap,
- strerror(errno));
-
- umask(~mask & 0777);
- }
- }
- return 0;
-}
-
-/*
- * ulimit builtin
- *
- * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
- * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
- * ash by J.T. Conklin.
- *
- * Public domain.
- */
-
-struct limits {
- const char *name;
- const char *unit;
- int cmd;
- int factor; /* multiply by to get rlim_{cur,max} values */
- char option;
-};
-
-static const struct limits limits[] = {
-#ifdef RLIMIT_CPU
- { "time", "seconds", RLIMIT_CPU, 1, 't' },
-#endif
-#ifdef RLIMIT_FSIZE
- { "file", "blocks", RLIMIT_FSIZE, 512, 'f' },
-#endif
-#ifdef RLIMIT_DATA
- { "data", "kbytes", RLIMIT_DATA, 1024, 'd' },
-#endif
-#ifdef RLIMIT_STACK
- { "stack", "kbytes", RLIMIT_STACK, 1024, 's' },
-#endif
-#ifdef RLIMIT_CORE
- { "coredump", "blocks", RLIMIT_CORE, 512, 'c' },
-#endif
-#ifdef RLIMIT_RSS
- { "memory", "kbytes", RLIMIT_RSS, 1024, 'm' },
-#endif
-#ifdef RLIMIT_MEMLOCK
- { "locked memory","kbytes", RLIMIT_MEMLOCK, 1024, 'l' },
-#endif
-#ifdef RLIMIT_NTHR
- { "thread", "threads", RLIMIT_NTHR, 1, 'r' },
-#endif
-#ifdef RLIMIT_NPROC
- { "process", "processes", RLIMIT_NPROC, 1, 'p' },
-#endif
-#ifdef RLIMIT_NOFILE
- { "nofiles", "descriptors", RLIMIT_NOFILE, 1, 'n' },
-#endif
-#ifdef RLIMIT_VMEM
- { "vmemory", "kbytes", RLIMIT_VMEM, 1024, 'v' },
-#endif
-#ifdef RLIMIT_SWAP
- { "swap", "kbytes", RLIMIT_SWAP, 1024, 'w' },
-#endif
-#ifdef RLIMIT_SBSIZE
- { "sbsize", "bytes", RLIMIT_SBSIZE, 1, 'b' },
-#endif
- { NULL, NULL, 0, 0, '\0' }
-};
-
-int
-ulimitcmd(int argc, char **argv)
-{
- int c;
- rlim_t val = 0;
- enum { SOFT = 0x1, HARD = 0x2 }
- how = SOFT | HARD;
- const struct limits *l;
- int set, all = 0;
- int optc, what;
- struct rlimit limit;
-
- what = 'f';
- while ((optc = nextopt("HSabtfdscmlrpnv")) != '\0')
- switch (optc) {
- case 'H':
- how = HARD;
- break;
- case 'S':
- how = SOFT;
- break;
- case 'a':
- all = 1;
- break;
- default:
- what = optc;
- }
-
- for (l = limits; l->name && l->option != what; l++)
- ;
- if (!l->name)
- error("internal error (%c)", what);
-
- set = *argptr ? 1 : 0;
- if (set) {
- char *p = *argptr;
-
- if (all || argptr[1])
- error("too many arguments");
- if (strcmp(p, "unlimited") == 0)
- val = RLIM_INFINITY;
- else {
- val = (rlim_t) 0;
-
- while ((c = *p++) >= '0' && c <= '9')
- val = (val * 10) + (long)(c - '0');
- if (c)
- error("bad number");
- val *= l->factor;
- }
- }
- if (all) {
- for (l = limits; l->name; l++) {
- getrlimit(l->cmd, &limit);
- if (how & SOFT)
- val = limit.rlim_cur;
- else if (how & HARD)
- val = limit.rlim_max;
-
- out1fmt("%-13s (-%c %-11s) ", l->name, l->option,
- l->unit);
- if (val == RLIM_INFINITY)
- out1fmt("unlimited\n");
- else
- {
- val /= l->factor;
-#ifdef BSD4_4
- out1fmt("%lld\n", (long long) val);
-#else
- out1fmt("%ld\n", (long) val);
-#endif
- }
- }
- return 0;
- }
-
- if (getrlimit(l->cmd, &limit) == -1)
- error("error getting limit (%s)", strerror(errno));
- if (set) {
- if (how & HARD)
- limit.rlim_max = val;
- if (how & SOFT)
- limit.rlim_cur = val;
- if (setrlimit(l->cmd, &limit) < 0)
- error("error setting limit (%s)", strerror(errno));
- } else {
- if (how & SOFT)
- val = limit.rlim_cur;
- else if (how & HARD)
- val = limit.rlim_max;
-
- if (val == RLIM_INFINITY)
- out1fmt("unlimited\n");
- else
- {
- val /= l->factor;
-#ifdef BSD4_4
- out1fmt("%lld\n", (long long) val);
-#else
- out1fmt("%ld\n", (long) val);
-#endif
- }
- }
- return 0;
-}
diff --git a/bin/sh/miscbltin.h b/bin/sh/miscbltin.h
deleted file mode 100644
index 4c12c82..0000000
--- a/bin/sh/miscbltin.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/* $NetBSD: miscbltin.h,v 1.3 2003/08/21 17:57:53 christos Exp $ */
-
-/*
- * Copyright (c) 1997 Christos Zoulas. All rights reserved.
- *
- * 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. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
- */
-
-int readcmd(int, char **);
-int umaskcmd(int, char **);
-int ulimitcmd(int, char **);
diff --git a/bin/sh/mkbuiltins b/bin/sh/mkbuiltins
deleted file mode 100644
index 2ebf7ac..0000000
--- a/bin/sh/mkbuiltins
+++ /dev/null
@@ -1,136 +0,0 @@
-#!/bin/sh -
-# $NetBSD: mkbuiltins,v 1.22 2009/10/06 19:56:58 apb Exp $
-#
-# Copyright (c) 1991, 1993
-# The Regents of the University of California. All rights reserved.
-#
-# This code is derived from software contributed to Berkeley by
-# Kenneth Almquist.
-#
-# 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.
-#
-# @(#)mkbuiltins 8.2 (Berkeley) 5/4/95
-
-havehist=1
-if [ x"$1" = x"-h" ]; then
- havehist=0
- shift
-fi
-
-shell=$1
-builtins=$2
-objdir=$3
-
-havejobs=0
-if grep '^#define JOBS[ ]*1' ${shell} > /dev/null
-then
- havejobs=1
-fi
-
-exec <$builtins 3> ${objdir}/builtins.c 4> ${objdir}/builtins.h
-
-echo '/*
- * This file was generated by the mkbuiltins program.
- */
-
-#include "shell.h"
-#include "builtins.h"
-
-const struct builtincmd builtincmd[] = {
-' >&3
-
-echo '/*
- * This file was generated by the mkbuiltins program.
- */
-
-#include <sys/cdefs.h>
-
-struct builtincmd {
- const char *name;
- int (*builtin)(int, char **);
-};
-
-extern const struct builtincmd builtincmd[];
-extern const struct builtincmd splbltincmd[];
-
-' >&4
-
-specials=
-
-while read line
-do
- set -- $line
- [ -z "$1" ] && continue
- case "$1" in
- \#if*|\#def*|\#end*)
- echo $line >&3
- echo $line >&4
- continue
- ;;
- \#*)
- continue
- ;;
- esac
-
- func=$1
- shift
- [ x"$1" = x'-j' ] && {
- [ $havejobs = 0 ] && continue
- shift
- }
- [ x"$1" = x'-h' ] && {
- [ $havehist = 0 ] && continue
- shift
- }
- echo 'int '"$func"'(int, char **);' >&4
- while
- [ $# != 0 ] && [ x"$1" != x'#' ]
- do
- [ x"$1" = x'-s' ] && {
- specials="$specials $2 $func"
- shift 2
- continue;
- }
- [ x"$1" = x'-u' ] && shift
- echo ' { "'$1'", '"$func"' },' >&3
- shift
- done
-done
-
-echo ' { 0, 0 },' >&3
-echo '};' >&3
-echo >&3
-echo 'const struct builtincmd splbltincmd[] = {' >&3
-
-set -- $specials
-while
- [ $# != 0 ]
-do
- echo ' { "'$1'", '"$2"' },' >&3
- shift 2
-done
-
-echo ' { 0, 0 },' >&3
-echo "};" >&3
diff --git a/bin/sh/mkinit.sh b/bin/sh/mkinit.sh
deleted file mode 100755
index da4f46f..0000000
--- a/bin/sh/mkinit.sh
+++ /dev/null
@@ -1,224 +0,0 @@
-#! /bin/sh
-# $NetBSD: mkinit.sh,v 1.10 2018/12/05 09:20:18 kre Exp $
-
-# Copyright (c) 2003 The NetBSD Foundation, Inc.
-# All rights reserved.
-#
-# This code is derived from software contributed to The NetBSD Foundation
-# by David Laight.
-#
-# 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.
-#
-# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
-
-srcs="$*"
-
-# use of echo in this script is broken
-
-# some echo versions will expand \n in the args, which breaks C
-# Note: this script is a HOST_PROG ... it must run in the
-# build host's environment, with its shell.
-
-# Fortunately, use of echo here is also trivially simplistic,
-# we can easily replace all uses with ...
-
-echo()
-{
- printf '%s\n' "$1"
-}
-
-# CAUTION: for anyone modifying this script.... use printf
-# rather than echo to output anything at all... then
-# you will avoid being bitten by the simplicity of this function.
-# This was done this way rather than wholesale replacement
-# to avoid unnecessary code churn.
-
-
-nl='
-'
-openparen='('
-
-# shells have bugs (including older NetBSD sh) in how \ is
-# used in pattern matching. So work out what the shell
-# running this script expects. We could also just use a
-# literal \ in the pattern, which would need to be quoted
-# of course, but then we'd run into a whole host of potential
-# other shell bugs (both with the quoting in the pattern, and
-# with the matching that follows if that works as inended).
-# Far easier, and more reliable, is to just work out what works,
-# and then use it, which more or less mandates using a variable...
-backslash='\\'
-var='abc\' # dummy test case.
-if [ "$var" = "${var%$backslash}" ]
-then
- # buggy sh, try the broken way
- backslash='\'
- if [ "$var" = "${var%$backslash}" ]
- then
- printf >&2 "$0: %s\n" 'No pattern match with \ (broken shell)'
- exit 1
- fi
-fi
-# We know we can detect the presence of a trailing \, which is all we need.
-# Now to confirm we will not generate false matches.
-var='abc'
-if [ "$var" != "${var%$backslash}" ]
-then
- printf >&2 "$0: %s\n" 'Bogus pattern match with \ (broken shell)'
- exit 1
-fi
-unset var
-
-includes=' "shell.h" "mystring.h" "init.h" '
-defines=
-decles=
-event_init=
-event_reset=
-event_shellproc=
-
-for src in $srcs; do
- exec <$src
- decnl="$nl"
- while IFS=; read -r line; do
- [ "$line" = x ]
- case "$line " in
- INIT["{ "]* ) event=init;;
- RESET["{ "]* ) event=reset;;
- SHELLPROC["{ "]* ) event=shellproc;;
- INCLUDE[\ \ ]* )
- IFS=' '
- set -- $line
- # ignore duplicates
- [ "${includes}" != "${includes% $2 *}" ] && continue
- includes="$includes$2 "
- continue
- ;;
- MKINIT\ )
- # struct declaration
- decles="$decles$nl"
- while
- read -r line
- decles="${decles}${line}${nl}"
- [ "$line" != "};" ]
- do
- :
- done
- decnl="$nl"
- continue
- ;;
- MKINIT["{ "]* )
- # strip initialiser
- def=${line#MKINIT}
- comment="${def#*;}"
- def="${def%;$comment}"
- def="${def%%=*}"
- def="${def% }"
- decles="${decles}${decnl}extern${def};${comment}${nl}"
- decnl=
- continue
- ;;
- \#define[\ \ ]* )
- IFS=' '
- set -- $line
- # Ignore those with arguments
- [ "$2" = "${2##*$openparen}" ] || continue
- # and multiline definitions
- [ "$line" = "${line%$backslash}" ] || continue
- defines="${defines}#undef $2${nl}${line}${nl}"
- continue
- ;;
- * ) continue;;
- esac
- # code for events
- ev="${nl} /* from $src: */${nl} {${nl}"
- # Indent the text by an extra <tab>
- while
- read -r line
- [ "$line" != "}" ]
- do
- case "$line" in
- ('') ;;
- ('#'*) ;;
- (*) line=" $line";;
- esac
- ev="${ev}${line}${nl}"
- done
- ev="${ev} }${nl}"
- eval event_$event=\"\$event_$event\$ev\"
- done
-done
-
-exec >init.c.tmp
-
-echo "/*"
-echo " * This file was generated by the mkinit program."
-echo " */"
-echo
-
-IFS=' '
-for f in $includes; do
- echo "#include $f"
-done
-
-echo
-echo
-echo
-echo "$defines"
-echo
-echo "$decles"
-echo
-echo
-echo "/*"
-echo " * Initialization code."
-echo " */"
-echo
-echo "void"
-echo "init(void)"
-echo "{"
-echo "${event_init}"
-echo "}"
-echo
-echo
-echo
-echo "/*"
-echo " * This routine is called when an error or an interrupt occurs in an"
-echo " * interactive shell and control is returned to the main command loop."
-echo " */"
-echo
-echo "void"
-echo "reset(void)"
-echo "{"
-echo "${event_reset}"
-echo "}"
-echo
-echo
-echo
-echo "/*"
-echo " * This routine is called to initialize the shell to run a shell procedure."
-echo " */"
-echo
-echo "void"
-echo "initshellproc(void)"
-echo "{"
-echo "${event_shellproc}"
-echo "}"
-
-exec >&-
-mv init.c.tmp init.c
diff --git a/bin/sh/mknodenames.sh b/bin/sh/mknodenames.sh
deleted file mode 100755
index 1d03200..0000000
--- a/bin/sh/mknodenames.sh
+++ /dev/null
@@ -1,69 +0,0 @@
-#! /bin/sh
-
-# $NetBSD: mknodenames.sh,v 1.6 2018/08/18 03:09:37 kre Exp $
-
-# Use this script however you like, but it would be amazing if
-# it has any purpose other than as part of building the shell...
-
-if [ -z "$1" ]; then
- echo "Usage: $0 nodes.h" 1>&2
- exit 1
-fi
-
-NODES=$1
-
-test -t 1 && test -z "$2" && exec > nodenames.h
-
-echo "\
-/*
- * Automatically generated by $0
- * DO NOT EDIT. Do Not 'cvs add'.
- */
-"
-echo "#ifndef NODENAMES_H_INCLUDED"
-echo "#define NODENAMES_H_INCLUDED"
-echo
-echo "#ifdef DEBUG"
-
-MAX=$(awk < "$NODES" '
- /#define/ {
- if ($3 > MAX) MAX = $3
- }
- END { print MAX }
-')
-
-echo
-echo '#ifdef DEFINE_NODENAMES'
-echo "STATIC const char * const NodeNames[${MAX} + 1] = {"
-
-grep '^#define' "$NODES" | sort -k3n | while read define name number opt_comment
-do
- : ${next:=0}
- while [ "$number" -gt "$next" ]
- do
- echo ' "???",'
- next=$(( next + 1))
- done
- echo ' "'"$name"'",'
- next=$(( number + 1 ))
-done
-
-echo "};"
-echo '#else'
-echo "extern const char * const NodeNames[${MAX} + 1];"
-echo '#endif'
-echo
-echo '#define NODETYPENAME(type) \'
-echo ' ((unsigned)(type) <= '"${MAX}"' ? NodeNames[(type)] : "??OOR??")'
-echo
-echo '#define NODETYPE(type) NODETYPENAME(type), (type)'
-echo '#define PRIdsNT "s(%d)"'
-echo
-echo '#else /* DEBUG */'
-echo
-echo '#define NODETYPE(type) (type)'
-echo '#define PRIdsNT "d"'
-echo
-echo '#endif /* DEBUG */'
-echo
-echo '#endif /* !NODENAMES_H_INCLUDED */'
diff --git a/bin/sh/mknodes.sh b/bin/sh/mknodes.sh
deleted file mode 100755
index 0b1ab80..0000000
--- a/bin/sh/mknodes.sh
+++ /dev/null
@@ -1,242 +0,0 @@
-#! /bin/sh
-# $NetBSD: mknodes.sh,v 1.4 2019/01/19 13:08:50 kre Exp $
-
-# Copyright (c) 2003 The NetBSD Foundation, Inc.
-# All rights reserved.
-#
-# This code is derived from software contributed to The NetBSD Foundation
-# by David Laight.
-#
-# 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.
-#
-# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
-
-nodetypes=$1
-nodes_pat=$2
-objdir="$3"
-
-exec <$nodetypes
-exec >$objdir/nodes.h.tmp
-
-echo "/*"
-echo " * This file was generated by mknodes.sh"
-echo " */"
-echo
-
-tagno=0
-while IFS=; read -r line; do
- line="${line%%#*}"
- IFS=' '
- set -- $line
- IFS=
- [ -z "$2" ] && continue
- case "$line" in
- [" "]* )
- IFS=' '
- [ $field = 0 ] && struct_list="$struct_list $struct"
- eval field_${struct}_$field=\"\$*\"
- eval numfld_$struct=\$field
- field=$(($field + 1))
- ;;
- * )
- define=$1
- struct=$2
- echo "#define $define $tagno"
- tagno=$(($tagno + 1))
- eval define_$struct=\"\$define_$struct \$define\"
- struct_define="$struct_define $struct"
- field=0
- ;;
- esac
-done
-
-echo
-
-IFS=' '
-for struct in $struct_list; do
- echo
- echo
- echo "struct $struct {"
- field=0
- while
- eval line=\"\$field_${struct}_$field\"
- field=$(($field + 1))
- [ -n "$line" ]
- do
- IFS=' '
- set -- $line
- name=$1
- case "$name" in
- type) if [ -n "$typetype" ] && [ "$typetype" != "$2" ]
- then
- echo >&2 "Conflicting type fields: node" \
- "$struct has $2, others $typetype"
- exit 1
- fi
- if [ $field -ne 1 ]
- then
- echo >&2 "Node $struct has type as field" \
- "$field (should only be first)"
- exit 1
- fi
- typetype=$2
- ;;
- *)
- if [ $field -eq 1 ]
- then
- echo >&2 "Node $struct does not have" \
- "type as first field"
- exit 1
- fi
- ;;
- esac
- case $2 in
- nodeptr ) type="union node *";;
- nodelist ) type="struct nodelist *";;
- string ) type="char *";;
- int*_t | uint*_t | int ) type="$2 ";;
- * ) name=; shift 2; type="$*";;
- esac
- echo " $type$name;"
- done
- echo "};"
-done
-
-echo
-echo
-echo "union node {"
-echo " $typetype type;"
-for struct in $struct_list; do
- echo " struct $struct $struct;"
-done
-echo "};"
-echo
-echo
-echo "struct nodelist {"
-echo " struct nodelist *next;"
-echo " union node *n;"
-echo "};"
-echo
-echo
-echo 'struct funcdef;'
-echo 'struct funcdef *copyfunc(union node *);'
-echo 'union node *getfuncnode(struct funcdef *);'
-echo 'void reffunc(struct funcdef *);'
-echo 'void unreffunc(struct funcdef *);'
-echo 'void freefunc(struct funcdef *);'
-
-mv $objdir/nodes.h.tmp $objdir/nodes.h || exit 1
-
-exec <$nodes_pat
-exec >$objdir/nodes.c.tmp
-
-echo "/*"
-echo " * This file was generated by mknodes.sh"
-echo " */"
-echo
-
-while IFS=; read -r line; do
- IFS=' '
- set -- $line
- IFS=
- case "$1" in
- '%SIZES' )
- echo "static const short nodesize[$tagno] = {"
- IFS=' '
- for struct in $struct_define; do
- echo " SHELL_ALIGN(sizeof (struct $struct)),"
- done
- echo "};"
- ;;
- '%CALCSIZE' )
- echo " if (n == NULL)"
- echo " return;"
- echo " res->bsize += nodesize[n->type];"
- echo " switch (n->type) {"
- IFS=' '
- for struct in $struct_list; do
- eval defines=\"\$define_$struct\"
- for define in $defines; do
- echo " case $define:"
- done
- eval field=\$numfld_$struct
- while
- [ $field != 0 ]
- do
- eval line=\"\$field_${struct}_$field\"
- field=$(($field - 1))
- IFS=' '
- set -- $line
- name=$1
- cl=", res)"
- case $2 in
- nodeptr ) fn=calcsize;;
- nodelist ) fn=sizenodelist;;
- string ) fn="res->ssize += strlen"
- cl=") + 1";;
- * ) continue;;
- esac
- echo " ${fn}(n->$struct.$name${cl};"
- done
- echo " break;"
- done
- echo " };"
- ;;
- '%COPY' )
- echo " if (n == NULL)"
- echo " return NULL;"
- echo " new = st->block;"
- echo " st->block = (char *) st->block + nodesize[n->type];"
- echo " switch (n->type) {"
- IFS=' '
- for struct in $struct_list; do
- eval defines=\"\$define_$struct\"
- for define in $defines; do
- echo " case $define:"
- done
- eval field=\$numfld_$struct
- while
- [ $field != 0 ]
- do
- eval line=\"\$field_${struct}_$field\"
- field=$(($field - 1))
- IFS=' '
- set -- $line
- name=$1
- case $2 in
- nodeptr ) fn="copynode(";;
- nodelist ) fn="copynodelist(";;
- string ) fn="nodesavestr(";;
- int*_t| uint*_t | int ) fn=;;
- * ) continue;;
- esac
- f="$struct.$name"
- echo " new->$f = ${fn}n->$f${fn:+, st)};"
- done
- echo " break;"
- done
- echo " };"
- echo " new->type = n->type;"
- ;;
- * ) echo "$line";;
- esac
-done
-
-mv $objdir/nodes.c.tmp $objdir/nodes.c || exit 1
diff --git a/bin/sh/mkoptions.sh b/bin/sh/mkoptions.sh
deleted file mode 100644
index aecb6df..0000000
--- a/bin/sh/mkoptions.sh
+++ /dev/null
@@ -1,198 +0,0 @@
-#! /bin/sh
-
-# $NetBSD: mkoptions.sh,v 1.5 2017/11/15 09:21:19 kre Exp $
-
-#
-# It would be more sensible to generate 2 .h files, one which
-# is for everyone to use, defines the "variables" and (perhaps) generates
-# the externs (though they could just be explicit in options.h)
-# and one just for options.c which generates the initialisation.
-#
-# But then I'd have to deal with making the Makefile handle that properly...
-# (this is simpler there, and it just means a bit more sh compile time.)
-
-set -f
-IFS=' ' # blank, tab (no newline)
-
-IF="$1"
-OF="${3+$3/}$2"
-
-E_FILE=$(${MKTEMP:-mktemp} -t MKO.E.$$)
-O_FILE=$(${MKTEMP:-mktemp} -t MKO.O.$$)
-trap 'rm -f "${E_FILE}" "${O_FILE}"' EXIT
-
-exec 5> "${E_FILE}"
-exec 6> "${O_FILE}"
-
-{
- printf '/*\n * File automatically generated by %s.\n' "$0"
- printf ' * Do not edit, do not add to cvs.\n'
- printf ' */\n\n'
-
- printf '#ifdef DEFINE_OPTIONS\n'
- printf 'struct optent optlist[] = {\n'
-} >"${OF}"
-
-FIRST=true
-
-${SED:-sed} <"${IF}" \
- -e '/^$/d' \
- -e '/^#/d' \
- -e '/^[ ]*\//d' \
- -e '/^[ ]*\*/d' \
- -e '/^[ ]*;/d' |
-sort -b -k2,2f -k2,2 < "${IF}" |
-while read line
-do
- # Look for comments in various styles, and ignore them
- # (these should generally be already removed by sed above)
-
- case "${line}" in
- '') continue;;
- /*) continue;;
- \**) continue;;
- \;*) continue;;
- \#*) continue;;
- esac
-
- case "${line}" in
- *'#if'*)
- COND="${line#*#}"
- COND="#${COND%%#*}"
- ;;
- *)
- COND=
- ;;
- esac
- set -- ${line%%[ ]#*}
-
- var="$1" name="$2"
-
- case "${var}" in
- ('' | [!A-Za-z_]* | *[!A-Za-z0-9_]*)
- printf >&2 "Bad var name: '%s'\\n" "${var}"
- # exit 1
- continue # just ignore it for now
- esac
-
- case "${name}" in
- ?) set -- ${var} '' $name $3 $4; name= ;;
- esac
-
- chr="$3" set="$4" dflt="$5"
-
- case "${chr}" in
- -) chr= set= dflt="$4";;
- ''|?) ;;
- *) printf >&2 'flag "%s": Not a character\n' "${chr}"; continue;;
- esac
-
- # options must have some kind of name, or they are useless...
- test -z "${name}${chr}" && continue
-
- case "${set}" in
- -) set= ;;
- [01] | [Oo][Nn] | [Oo][Ff][Ff]) dflt="${set}"; set= ;;
- ''|?) ;;
- *) printf >&2 'set "%s": Not a character\n' "${set}"; continue;;
- esac
-
- case "${dflt}" in
- '') ;;
- [Oo][Nn]) dflt=1;;
- [Oo][Ff][Ff]) dflt=0;;
- [01]) ;;
- *) printf >&2 'default "%s" invalid, use 0 off 1 on\n'; continue;;
- esac
-
- # validation complete, now to generate output
-
- if [ -n "${COND}" ]
- then
- printf '%s\n' "${COND}" >&4
- printf '%s\n' "${COND}" >&5
- printf '%s\n' "${COND}" >&6
- fi
-
- printf '\t_SH_OPT_%s,\n' "${var}" >&5
-
- if [ -n "${name}" ]
- then
- printf ' { "%s", ' "${name}" >&4
- else
- printf ' { 0, ' >&4
- fi
-
- if [ -n "${chr}" ]
- then
- printf "'%s', " "${chr}" >&4
- else
- chr=
- printf '0, ' >&4
- fi
-
- if [ -n "${set}" ]
- then
- printf "'%s', 0, " "${set}" >&4
- else
- printf '0, 0, ' >&4
- fi
-
- if [ -n "${dflt}" ]
- then
- printf '%s },\n' "${dflt}" >&4
- else
- printf '0 },\n' >&4
- fi
-
- printf '#define %s\toptlist[_SH_OPT_%s].val\n' "${var}" "${var}" >&6
-
- if [ -n "${COND}" ]
- then
- printf '#endif\n' >&4
- printf '#endif\n' >&5
- printf '#endif\n' >&6
- fi
-
- test -z "${chr}" && continue
-
- printf '%s _SH_OPT_%s %s\n' "${chr}" "${var}" "${COND}"
-
-done 4>>"${OF}" | sort -t' ' -k1,1f -k1,1 | while read chr index COND
-do
- if $FIRST
- then
- printf ' { 0, 0, 0, 0, 0 }\n};\n'
- printf '#endif\n\n'
-
- printf 'enum shell_opt_names {\n'
- cat "${E_FILE}"
- printf '};\n\n'
-
- printf '#ifdef DEFINE_OPTIONS\n'
- printf 'const unsigned char optorder[] = {\n'
- FIRST=false
- fi
- [ -n "${COND}" ] && printf '%s\n' "${COND}"
- printf '\t%s,\n' "${index}"
- [ -n "${COND}" ] && printf '#endif\n'
-
-done >>"${OF}"
-
-{
- printf '};\n\n'
- printf '#define NOPTS (sizeof optlist / sizeof optlist[0] - 1)\n'
- printf 'int sizeof_optlist = sizeof optlist;\n\n'
- printf \
- 'const int option_flags = (sizeof optorder / sizeof optorder[0]);\n'
- printf '\n#else\n\n'
- printf 'extern struct optent optlist[];\n'
- printf 'extern int sizeof_optlist;\n'
- printf 'extern const unsigned char optorder[];\n'
- printf 'extern const int option_flags;\n'
- printf '\n#endif\n\n'
-
- cat "${O_FILE}"
-} >> "${OF}"
-
-exit 0
diff --git a/bin/sh/mktokens b/bin/sh/mktokens
deleted file mode 100644
index a8f81c4..0000000
--- a/bin/sh/mktokens
+++ /dev/null
@@ -1,99 +0,0 @@
-#!/bin/sh -
-# $NetBSD: mktokens,v 1.14 2017/07/26 03:46:54 kre Exp $
-#
-# Copyright (c) 1991, 1993
-# The Regents of the University of California. All rights reserved.
-#
-# This code is derived from software contributed to Berkeley by
-# Kenneth Almquist.
-#
-# 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.
-#
-# @(#)mktokens 8.1 (Berkeley) 5/31/93
-
-: ${AWK:=awk}
-: ${SED:=sed}
-
-# The following is a list of tokens. The second column is nonzero if the
-# token marks the end of a list. The third column is the name to print in
-# error messages.
-
-# Note that all the keyword tokens come after TWORD, and all the others
-# come before it. We rely upon that relationship - keep it!
-
-cat > /tmp/ka$$ <<\!
-TEOF 1 end of file
-TNL 0 newline
-TSEMI 0 ";"
-TBACKGND 0 "&"
-TAND 0 "&&"
-TOR 0 "||"
-TPIPE 0 "|"
-TLP 0 "("
-TRP 1 ")"
-TENDCASE 1 ";;"
-TCASEFALL 1 ";&"
-TENDBQUOTE 1 "`"
-TREDIR 0 redirection
-TWORD 0 word
-TIF 0 "if"
-TTHEN 1 "then"
-TELSE 1 "else"
-TELIF 1 "elif"
-TFI 1 "fi"
-TWHILE 0 "while"
-TUNTIL 0 "until"
-TFOR 0 "for"
-TDO 1 "do"
-TDONE 1 "done"
-TBEGIN 0 "{"
-TEND 1 "}"
-TCASE 0 "case"
-TESAC 1 "esac"
-TNOT 0 "!"
-!
-nl=`wc -l /tmp/ka$$`
-exec > token.h
-${AWK} '{print "#define " $1 " " NR-1}' /tmp/ka$$
-echo '
-/* Array indicating which tokens mark the end of a list */
-const char tokendlist[] = {'
-${AWK} '{print "\t" $2 ","}' /tmp/ka$$
-echo '};
-
-const char *const tokname[] = {'
-${SED} -e 's/"/\\"/g' \
- -e 's/[^ ]*[ ][ ]*[^ ]*[ ][ ]*\(.*\)/ "\1",/' \
- /tmp/ka$$
-echo '};
-'
-${SED} 's/"//g' /tmp/ka$$ | ${AWK} '
-/TWORD/{print "#define KWDOFFSET " NR; print "";
- print "const char *const parsekwd[] = {"}
-/TIF/,/neverfound/{print " \"" $3 "\","}'
-echo ' 0
-};'
-
-rm /tmp/ka$$
diff --git a/bin/sh/myhistedit.h b/bin/sh/myhistedit.h
deleted file mode 100644
index 855c1bc..0000000
--- a/bin/sh/myhistedit.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* $NetBSD: myhistedit.h,v 1.13 2017/06/28 13:46:06 kre Exp $ */
-
-/*-
- * Copyright (c) 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 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.
- *
- * @(#)myhistedit.h 8.2 (Berkeley) 5/4/95
- */
-
-#include <histedit.h>
-
-extern History *hist;
-extern EditLine *el;
-extern int displayhist;
-
-void histedit(void);
-void sethistsize(const char *);
-void setterm(const char *);
-int inputrc(int, char **);
-void set_editrc(const char *);
-void set_prompt_lit(const char *);
-int not_fcnumber(char *);
-int str_to_event(const char *, int);
-
diff --git a/bin/sh/mystring.c b/bin/sh/mystring.c
deleted file mode 100644
index 9b6b40b..0000000
--- a/bin/sh/mystring.c
+++ /dev/null
@@ -1,140 +0,0 @@
-/* $NetBSD: mystring.c,v 1.18 2018/07/13 22:43:44 kre Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- */
-
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)mystring.c 8.2 (Berkeley) 5/4/95";
-#else
-__RCSID("$NetBSD: mystring.c,v 1.18 2018/07/13 22:43:44 kre Exp $");
-#endif
-#endif /* not lint */
-
-/*
- * String functions.
- *
- * equal(s1, s2) Return true if strings are equal.
- * scopy(from, to) Copy a string.
- * scopyn(from, to, n) Like scopy, but checks for overflow.
- * number(s) Convert a string of digits to an integer.
- * is_number(s) Return true if s is a string of digits.
- */
-
-#include <inttypes.h>
-#include <limits.h>
-#include <stdlib.h>
-#include "shell.h"
-#include "syntax.h"
-#include "error.h"
-#include "mystring.h"
-
-
-const char nullstr[1]; /* zero length string */
-
-/*
- * equal - #defined in mystring.h
- */
-
-/*
- * scopy - #defined in mystring.h
- */
-
-
-/*
- * scopyn - copy a string from "from" to "to", truncating the string
- * if necessary. "To" is always nul terminated, even if
- * truncation is performed. "Size" is the size of "to".
- */
-
-void
-scopyn(const char *from, char *to, int size)
-{
-
- while (--size > 0) {
- if ((*to++ = *from++) == '\0')
- return;
- }
- *to = '\0';
-}
-
-
-/*
- * prefix -- see if pfx is a prefix of string.
- */
-
-int
-prefix(const char *pfx, const char *string)
-{
- while (*pfx) {
- if (*pfx++ != *string++)
- return 0;
- }
- return 1;
-}
-
-
-/*
- * Convert a string of digits to an integer, printing an error message on
- * failure.
- */
-
-int
-number(const char *s)
-{
- char *ep = NULL;
- intmax_t n;
-
- if (!is_digit(*s) || ((n = strtoimax(s, &ep, 10)),
- (ep == NULL || ep == s || *ep != '\0')))
- error("Illegal number: '%s'", s);
- if (n < INT_MIN || n > INT_MAX)
- error("Number out of range: %s", s);
- return (int)n;
-}
-
-
-
-/*
- * Check for a valid number. This should be elsewhere.
- */
-
-int
-is_number(const char *p)
-{
- do {
- if (! is_digit(*p))
- return 0;
- } while (*++p != '\0');
- return 1;
-}
diff --git a/bin/sh/mystring.h b/bin/sh/mystring.h
deleted file mode 100644
index 08a73e9..0000000
--- a/bin/sh/mystring.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/* $NetBSD: mystring.h,v 1.11 2003/08/07 09:05:35 agc Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- *
- * @(#)mystring.h 8.2 (Berkeley) 5/4/95
- */
-
-#include <string.h>
-
-void scopyn(const char *, char *, int);
-int prefix(const char *, const char *);
-int number(const char *);
-int is_number(const char *);
-
-#define equal(s1, s2) (strcmp(s1, s2) == 0)
-#define scopy(s1, s2) ((void)strcpy(s2, s1))
diff --git a/bin/sh/nodes.c.pat b/bin/sh/nodes.c.pat
deleted file mode 100644
index 599597c..0000000
--- a/bin/sh/nodes.c.pat
+++ /dev/null
@@ -1,210 +0,0 @@
-/* $NetBSD: nodes.c.pat,v 1.14 2018/06/22 11:04:55 kre Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- *
- * @(#)nodes.c.pat 8.2 (Berkeley) 5/4/95
- */
-
-#include <stdlib.h>
-#include <stddef.h>
-
-/*
- * Routine for dealing with parsed shell commands.
- */
-
-#include "shell.h"
-#include "nodes.h"
-#include "memalloc.h"
-#include "machdep.h"
-#include "mystring.h"
-
-
-/* used to accumulate sizes of nodes */
-struct nodesize {
- int bsize; /* size of structures in function */
- int ssize; /* size of strings in node */
-};
-
-/* provides resources for node copies */
-struct nodecopystate {
- pointer block; /* block to allocate function from */
- char *string; /* block to allocate strings from */
-};
-
-
-%SIZES
-
-
-
-STATIC void calcsize(union node *, struct nodesize *);
-STATIC void sizenodelist(struct nodelist *, struct nodesize *);
-STATIC union node *copynode(union node *, struct nodecopystate *);
-STATIC struct nodelist *copynodelist(struct nodelist *, struct nodecopystate *);
-STATIC char *nodesavestr(char *, struct nodecopystate *);
-
-struct funcdef {
- unsigned int refcount;
- union node n; /* must be last */
-};
-
-
-/*
- * Make a copy of a parse tree.
- */
-
-struct funcdef *
-copyfunc(union node *n)
-{
- struct nodesize sz;
- struct nodecopystate st;
- struct funcdef *fn;
-
- if (n == NULL)
- return NULL;
- sz.bsize = offsetof(struct funcdef, n);
- sz.ssize = 0;
- calcsize(n, &sz);
- fn = ckmalloc(sz.bsize + sz.ssize);
- fn->refcount = 1;
- st.block = (char *)fn + offsetof(struct funcdef, n);
- st.string = (char *)fn + sz.bsize;
- copynode(n, &st);
- return fn;
-}
-
-union node *
-getfuncnode(struct funcdef *fn)
-{
- if (fn == NULL)
- return NULL;
- return &fn->n;
-}
-
-
-STATIC void
-calcsize(union node *n, struct nodesize *res)
-{
- %CALCSIZE
-}
-
-
-
-STATIC void
-sizenodelist(struct nodelist *lp, struct nodesize *res)
-{
- while (lp) {
- res->bsize += SHELL_ALIGN(sizeof(struct nodelist));
- calcsize(lp->n, res);
- lp = lp->next;
- }
-}
-
-
-
-STATIC union node *
-copynode(union node *n, struct nodecopystate *st)
-{
- union node *new;
-
- %COPY
- return new;
-}
-
-
-STATIC struct nodelist *
-copynodelist(struct nodelist *lp, struct nodecopystate *st)
-{
- struct nodelist *start;
- struct nodelist **lpp;
-
- lpp = &start;
- while (lp) {
- *lpp = st->block;
- st->block = (char *)st->block +
- SHELL_ALIGN(sizeof(struct nodelist));
- (*lpp)->n = copynode(lp->n, st);
- lp = lp->next;
- lpp = &(*lpp)->next;
- }
- *lpp = NULL;
- return start;
-}
-
-
-
-STATIC char *
-nodesavestr(char *s, struct nodecopystate *st)
-{
- register char *p = s;
- register char *q = st->string;
- char *rtn = st->string;
-
- while ((*q++ = *p++) != 0)
- continue;
- st->string = q;
- return rtn;
-}
-
-
-
-/*
- * Handle making a reference to a function, and releasing it.
- * Free the func code when there are no remaining references.
- */
-
-void
-reffunc(struct funcdef *fn)
-{
- if (fn != NULL)
- fn->refcount++;
-}
-
-void
-unreffunc(struct funcdef *fn)
-{
- if (fn != NULL) {
- if (--fn->refcount > 0)
- return;
- ckfree(fn);
- }
-}
-
-/*
- * this is used when we need to free the func, regardless of refcount
- * which only happens when re-initing the shell for a SHELLPROC
- */
-void
-freefunc(struct funcdef *fn)
-{
- if (fn != NULL)
- ckfree(fn);
-}
diff --git a/bin/sh/nodetypes b/bin/sh/nodetypes
deleted file mode 100644
index dc5ee4a..0000000
--- a/bin/sh/nodetypes
+++ /dev/null
@@ -1,149 +0,0 @@
-# $NetBSD: nodetypes,v 1.18 2017/06/08 13:12:17 kre Exp $
-# Copyright (c) 1991, 1993
-# The Regents of the University of California. All rights reserved.
-#
-# This code is derived from software contributed to Berkeley by
-# Kenneth Almquist.
-#
-# 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.
-#
-# @(#)nodetypes 8.2 (Berkeley) 5/4/95
-
-# This file describes the nodes used in parse trees. Unindented lines
-# contain a node type followed by a structure tag. Subsequent indented
-# lines specify the fields of the structure. Several node types can share
-# the same structure, in which case the fields of the structure should be
-# specified only once.
-#
-# A field of a structure is described by the name of the field followed
-# by a type. The currently implemented types are:
-# nodeptr - a pointer to a node
-# nodelist - a pointer to a list of nodes
-# string - a pointer to a nul terminated string
-# int - an integer
-# other - any type that can be copied by assignment
-# temp - a field that doesn't have to be copied when the node is copied
-# The last two types should be followed by the text of a C declaration for
-# the field.
-
-NSEMI nbinary # two commands separated by a semicolon
- type int
- ch1 nodeptr # the first child
- ch2 nodeptr # the second child
-
-NCMD ncmd # a simple command
- type int
- backgnd int # set to run command in background
- args nodeptr # the arguments
- redirect nodeptr # list of file redirections
- lineno int
-
-NPIPE npipe # a pipeline
- type int
- backgnd int # set to run pipeline in background
- cmdlist nodelist # the commands in the pipeline
-
-NREDIR nredir # redirection (of a complex command)
- type int
- n nodeptr # the command
- redirect nodeptr # list of file redirections
-
-NBACKGND nredir # run command in background
-NSUBSHELL nredir # run command in a subshell
-
-NAND nbinary # the && operator
-NOR nbinary # the || operator
-
-NIF nif # the if statement. Elif clauses are handled
- type int # using multiple if nodes.
- test nodeptr # if test
- ifpart nodeptr # then ifpart
- elsepart nodeptr # else elsepart
-
-NWHILE nbinary # the while statement. First child is the test
-NUNTIL nbinary # the until statement
-
-NFOR nfor # the for statement
- type int
- args nodeptr # for var in args
- body nodeptr # do body; done
- var string # the for variable
-
-NCASE ncase # a case statement
- type int
- expr nodeptr # the word to switch on
- cases nodeptr # the list of cases (NCLIST nodes)
- lineno int
-
-NCLISTCONT nclist # a case terminated by ';&' (fall through)
-NCLIST nclist # a case
- type int
- next nodeptr # the next case in list
- pattern nodeptr # list of patterns for this case
- body nodeptr # code to execute for this case
- lineno int
-
-
-NDEFUN narg # define a function. The "next" field contains
- # the body of the function.
-
-NARG narg # represents a word
- type int
- next nodeptr # next word in list
- text string # the text of the word
- backquote nodelist # list of commands in back quotes
- lineno int
-
-NTO nfile # fd> fname
-NCLOBBER nfile # fd>| fname
-NFROM nfile # fd< fname
-NFROMTO nfile # fd<> fname
-NAPPEND nfile # fd>> fname
- type int
- next nodeptr # next redirection in list
- fd int # file descriptor being redirected
- fname nodeptr # file name, in a NARG node
- expfname temp char *expfname # actual file name
-
-NTOFD ndup # fd<&dupfd
-NFROMFD ndup # fd>&dupfd
- type int
- next nodeptr # next redirection in list
- fd int # file descriptor being redirected
- dupfd int # file descriptor to duplicate
- vname nodeptr # file name if fd>&$var
-
-
-NHERE nhere # fd<<\!
-NXHERE nhere # fd<<!
- type int
- next nodeptr # next redirection in list
- fd int # file descriptor being redirected
- doc nodeptr # input to command (NARG node)
-
-NNOT nnot # ! command (actually pipeline)
-NDNOT nnot # ! ! pipeline (optimisation)
- type int
- com nodeptr
diff --git a/bin/sh/option.list b/bin/sh/option.list
deleted file mode 100644
index 3be683a..0000000
--- a/bin/sh/option.list
+++ /dev/null
@@ -1,79 +0,0 @@
-/* $NetBSD: option.list,v 1.9 2018/11/23 20:40:06 kre Exp $ */
-
-/*
- * define the shell's settable options
- *
- * new options can be defined by adding them here,
- * but they do nothing until code to implement them
- * is added (using the "var name" field)
- */
-
-/*
- * format is up to 5 columns... (followed by anything)
- * end of line comments can be introduced by ' #' (space/tab hash) to eol.
- *
- * The columns are:
- * 1. internal shell "var name" (required)
- * 2. option long name
- * if a single char, then no long name, and remaining
- * columns shift left (this becomes the short name)
- * 3. option short name (single character name)
- * if '-' or absent then no short name
- * if neither long nor short name, line is ignored
- * 4. option set short name (name of option equiv class)
- * if '-' or absent then no class
- * 5. default value of option
- * if absent, default is 0
- * only 0 or 1 possible (0==off 1==on) ("on" and "off" can be used)
- *
- * Data may be followed by any C preprocessor #if expression (incl the #if..)
- * (including #ifdef #ifndef) to conditionalise output for that option.
- * The #if expression continues until \n or next following '#'
- */
-
-// the POSIX defined options
-aflag allexport a # export all variables
-eflag errexit e # exit on command error ($? != 0)
-mflag monitor m # enable job control
-Cflag noclobber C # do not overwrite files when using >
-nflag noexec n # do not execue commands
-fflag noglob f # no pathname expansion
-uflag nounset u # expanding unset var is an error
-vflag verbose v # echo commands as read
-xflag xtrace x # trace command execution
-
-// the long name (ignoreeof) is standard, the I flag is not
-Iflag ignoreeof I # do not exit interactive shell on EOF
-
-// defined but not really implemented by the shell (yet) - they do nothing
-bflag notify b # [U] report bg job completion
-nolog nolog # [U] no func definitions in history
-// 'h' is standard, long name (trackall) is not
-hflag trackall h # [U] locate cmds in funcs during defn
-
-// 's' is standard for command line, not as 'set' option, nor 'stdin' name
-sflag stdin s # read from standard input
-// minusc c # command line option only.
-// -- o # handled differently...
-
-// non-standard options -- 'i' is just a state, not an option in standard.
-iflag interactive i # interactive shell
-cdprint cdprint # always print result of a cd
-usefork fork F # use fork(2) instead of vfork(2)
-pflag nopriv p # preserve privs if set[ug]id
-posix posix # be closer to POSIX compat
-qflag quietprofile q # disable -v/-x in startup files
-fnline1 local_lineno L on # number lines in funcs starting at 1
-promptcmds promptcmds # allow $( ) in PS1 (et al).
-pipefail pipefail # pipe exit status
-Xflag xlock X #ifndef SMALL # sticky stderr for -x (implies -x)
-
-// editline/history related options ("vi" is standard, 'V' and others are not)
-// only one of vi/emacs can be set, hence the "set" definition, value
-// of that can be any char (not used for a different set)
-Vflag vi V V # enable vi style editing
-Eflag emacs E V # enable emacs style editing
-tabcomplete tabcomplete # make <tab> cause filename expansion
-
-// internal debug option (not usually included in the shell)
-debug debug #ifdef DEBUG # enable internal shell debugging
diff --git a/bin/sh/options.c b/bin/sh/options.c
deleted file mode 100644
index d2c3e68..0000000
--- a/bin/sh/options.c
+++ /dev/null
@@ -1,631 +0,0 @@
-/* $NetBSD: options.c,v 1.53 2018/07/13 22:43:44 kre Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- */
-
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)options.c 8.2 (Berkeley) 5/4/95";
-#else
-__RCSID("$NetBSD: options.c,v 1.53 2018/07/13 22:43:44 kre Exp $");
-#endif
-#endif /* not lint */
-
-#include <signal.h>
-#include <unistd.h>
-#include <stdlib.h>
-
-#include "shell.h"
-#define DEFINE_OPTIONS
-#include "options.h"
-#undef DEFINE_OPTIONS
-#include "builtins.h"
-#include "nodes.h" /* for other header files */
-#include "eval.h"
-#include "jobs.h"
-#include "input.h"
-#include "output.h"
-#include "trap.h"
-#include "var.h"
-#include "memalloc.h"
-#include "error.h"
-#include "mystring.h"
-#include "syntax.h"
-#ifndef SMALL
-#include "myhistedit.h"
-#endif
-#include "show.h"
-
-char *arg0; /* value of $0 */
-struct shparam shellparam; /* current positional parameters */
-char **argptr; /* argument list for builtin commands */
-char *optionarg; /* set by nextopt (like getopt) */
-char *optptr; /* used by nextopt */
-
-char *minusc; /* argument to -c option */
-
-
-STATIC void options(int);
-STATIC void minus_o(char *, int);
-STATIC void setoption(int, int);
-STATIC int getopts(char *, char *, char **, char ***, char **);
-
-
-/*
- * Process the shell command line arguments.
- */
-
-void
-procargs(int argc, char **argv)
-{
- size_t i;
- int psx;
-
- argptr = argv;
- if (argc > 0)
- argptr++;
-
- psx = posix; /* save what we set it to earlier */
- /*
- * option values are mostly boolean 0:off 1:on
- * we use 2 (just in this routine) to mean "unknown yet"
- */
- for (i = 0; i < NOPTS; i++)
- optlist[i].val = 2;
- posix = psx; /* restore before processing -o ... */
-
- options(1);
-
- if (*argptr == NULL && minusc == NULL)
- sflag = 1;
- if (iflag == 2 && sflag == 1 && isatty(0) && isatty(2))
- iflag = 1;
- if (iflag == 1 && sflag == 2)
- iflag = 2;
- if (mflag == 2)
- mflag = iflag;
-#ifndef DO_SHAREDVFORK
- if (usefork == 2)
- usefork = 1;
-#endif
-#if DEBUG >= 2
- if (debug == 2)
- debug = 1;
-#endif
- /*
- * Any options not dealt with as special cases just above,
- * and which were not set on the command line, are set to
- * their expected default values (mostly "off")
- *
- * then as each option is initialised, save its setting now
- * as its "default" value for future use ("set -o default").
- */
- for (i = 0; i < NOPTS; i++) {
- if (optlist[i].val == 2)
- optlist[i].val = optlist[i].dflt;
- optlist[i].dflt = optlist[i].val;
- }
-
- arg0 = argv[0];
- if (sflag == 0 && minusc == NULL) {
- commandname = argv[0];
- arg0 = *argptr++;
- setinputfile(arg0, 0);
- commandname = arg0;
- }
- /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
- if (minusc != NULL) {
- if (argptr == NULL || *argptr == NULL)
- error("Bad -c option");
- minusc = *argptr++;
- if (*argptr != 0)
- arg0 = *argptr++;
- }
-
- shellparam.p = argptr;
- shellparam.reset = 1;
- /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
- while (*argptr) {
- shellparam.nparam++;
- argptr++;
- }
- optschanged();
-}
-
-
-void
-optschanged(void)
-{
- setinteractive(iflag);
-#ifndef SMALL
- histedit();
-#endif
- setjobctl(mflag);
-}
-
-/*
- * Process shell options. The global variable argptr contains a pointer
- * to the argument list; we advance it past the options.
- */
-
-STATIC void
-options(int cmdline)
-{
- static char empty[] = "";
- char *p;
- int val;
- int c;
-
- if (cmdline)
- minusc = NULL;
- while ((p = *argptr) != NULL) {
- argptr++;
- if ((c = *p++) == '-') {
- val = 1;
- if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
- if (!cmdline) {
- /* "-" means turn off -x and -v */
- if (p[0] == '\0')
- xflag = vflag = 0;
- /* "--" means reset params */
- else if (*argptr == NULL)
- setparam(argptr);
- }
- break; /* "-" or "--" terminates options */
- }
- } else if (c == '+') {
- val = 0;
- } else {
- argptr--;
- break;
- }
- while ((c = *p++) != '\0') {
- if (val == 1 && c == 'c' && cmdline) {
- /* command is after shell args*/
- minusc = empty;
- } else if (c == 'o') {
- if (*p != '\0')
- minus_o(p, val + (cmdline ? val : 0));
- else if (*argptr)
- minus_o(*argptr++,
- val + (cmdline ? val : 0));
- else if (!cmdline)
- minus_o(NULL, val);
- else
- error("arg for %co missing", "+-"[val]);
- break;
-#ifdef DEBUG
- } else if (c == 'D') {
- if (*p) {
- set_debug(p, val);
- break;
- } else if (*argptr)
- set_debug(*argptr++, val);
- else
- set_debug("*$", val);
-#endif
- } else {
- setoption(c, val);
- }
- }
- }
-}
-
-static void
-set_opt_val(size_t i, int val)
-{
- size_t j;
- int flag;
-
- if (val && (flag = optlist[i].opt_set)) {
- /* some options (eg vi/emacs) are mutually exclusive */
- for (j = 0; j < NOPTS; j++)
- if (optlist[j].opt_set == flag)
- optlist[j].val = 0;
- }
-#ifndef SMALL
- if (i == _SH_OPT_Xflag)
- xtracefdsetup(val);
-#endif
- optlist[i].val = val;
-#ifdef DEBUG
- if (&optlist[i].val == &debug)
- opentrace(); /* different "trace" than the -x one... */
-#endif
-}
-
-STATIC void
-minus_o(char *name, int val)
-{
- size_t i;
- const char *sep = ": ";
-
- if (name == NULL) {
- if (val) {
- out1str("Current option settings");
- for (i = 0; i < NOPTS; i++) {
- if (optlist[i].name == NULL) {
- out1fmt("%s%c%c", sep,
- "+-"[optlist[i].val],
- optlist[i].letter);
- sep = ", ";
- }
- }
- out1c('\n');
- for (i = 0; i < NOPTS; i++) {
- if (optlist[i].name)
- out1fmt("%-19s %s\n", optlist[i].name,
- optlist[i].val ? "on" : "off");
- }
- } else {
- out1str("set -o default");
- for (i = 0; i < NOPTS; i++) {
- if (optlist[i].val == optlist[i].dflt)
- continue;
- if (optlist[i].name)
- out1fmt(" %co %s",
- "+-"[optlist[i].val], optlist[i].name);
- else
- out1fmt(" %c%c", "+-"[optlist[i].val],
- optlist[i].letter);
- }
- out1c('\n');
- }
- } else {
- if (val == 1 && equal(name, "default")) { /* special case */
- for (i = 0; i < NOPTS; i++)
- set_opt_val(i, optlist[i].dflt);
- return;
- }
- if (val)
- val = 1;
- for (i = 0; i < NOPTS; i++)
- if (optlist[i].name && equal(name, optlist[i].name)) {
- set_opt_val(i, val);
-#ifndef SMALL
- if (i == _SH_OPT_Xflag)
- set_opt_val(_SH_OPT_xflag, val);
-#endif
- return;
- }
- error("Illegal option %co %s", "+-"[val], name);
- }
-}
-
-
-STATIC void
-setoption(int flag, int val)
-{
- size_t i;
-
- for (i = 0; i < NOPTS; i++)
- if (optlist[i].letter == flag) {
- set_opt_val(i, val);
-#ifndef SMALL
- if (i == _SH_OPT_Xflag)
- set_opt_val(_SH_OPT_xflag, val);
-#endif
- return;
- }
- error("Illegal option %c%c", "+-"[val], flag);
- /* NOTREACHED */
-}
-
-
-
-#ifdef mkinit
-INCLUDE "options.h"
-
-SHELLPROC {
- int i;
-
- for (i = 0; optlist[i].name; i++)
- optlist[i].val = 0;
- optschanged();
-
-}
-#endif
-
-
-/*
- * Set the shell parameters.
- */
-
-void
-setparam(char **argv)
-{
- char **newparam;
- char **ap;
- int nparam;
-
- for (nparam = 0 ; argv[nparam] ; nparam++)
- continue;
- ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
- while (*argv) {
- *ap++ = savestr(*argv++);
- }
- *ap = NULL;
- freeparam(&shellparam);
- shellparam.malloc = 1;
- shellparam.nparam = nparam;
- shellparam.p = newparam;
- shellparam.optnext = NULL;
-}
-
-
-/*
- * Free the list of positional parameters.
- */
-
-void
-freeparam(volatile struct shparam *param)
-{
- char **ap;
-
- if (param->malloc) {
- for (ap = param->p ; *ap ; ap++)
- ckfree(*ap);
- ckfree(param->p);
- }
-}
-
-
-
-/*
- * The shift builtin command.
- */
-
-int
-shiftcmd(int argc, char **argv)
-{
- int n;
- char **ap1, **ap2;
-
- if (argc > 2)
- error("Usage: shift [n]");
- n = 1;
- if (argc > 1)
- n = number(argv[1]);
- if (n > shellparam.nparam)
- error("can't shift that many");
- INTOFF;
- shellparam.nparam -= n;
- for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
- if (shellparam.malloc)
- ckfree(*ap1);
- }
- ap2 = shellparam.p;
- while ((*ap2++ = *ap1++) != NULL)
- continue;
- shellparam.optnext = NULL;
- INTON;
- return 0;
-}
-
-
-
-/*
- * The set command builtin.
- */
-
-int
-setcmd(int argc, char **argv)
-{
- if (argc == 1)
- return showvars(0, 0, 1, 0);
- INTOFF;
- options(0);
- optschanged();
- if (*argptr != NULL) {
- setparam(argptr);
- }
- INTON;
- return 0;
-}
-
-
-void
-getoptsreset(const char *value)
-{
- /*
- * This is just to detect the case where OPTIND=1
- * is executed. Any other string assigned to OPTIND
- * is OK, but is not a reset. No errors, so cannot use number()
- */
- if (is_digit(*value) && strtol(value, NULL, 10) == 1) {
- shellparam.optnext = NULL;
- shellparam.reset = 1;
- }
-}
-
-/*
- * The getopts builtin. Shellparam.optnext points to the next argument
- * to be processed. Shellparam.optptr points to the next character to
- * be processed in the current argument. If shellparam.optnext is NULL,
- * then it's the first time getopts has been called.
- */
-
-int
-getoptscmd(int argc, char **argv)
-{
- char **optbase;
-
- if (argc < 3)
- error("usage: getopts optstring var [arg]");
- else if (argc == 3)
- optbase = shellparam.p;
- else
- optbase = &argv[3];
-
- if (shellparam.reset == 1) {
- shellparam.optnext = optbase;
- shellparam.optptr = NULL;
- shellparam.reset = 0;
- }
-
- return getopts(argv[1], argv[2], optbase, &shellparam.optnext,
- &shellparam.optptr);
-}
-
-STATIC int
-getopts(char *optstr, char *optvar, char **optfirst, char ***optnext, char **optpptr)
-{
- char *p, *q;
- char c = '?';
- int done = 0;
- int ind = 0;
- int err = 0;
- char s[12];
-
- if ((p = *optpptr) == NULL || *p == '\0') {
- /* Current word is done, advance */
- if (*optnext == NULL)
- return 1;
- p = **optnext;
- if (p == NULL || *p != '-' || *++p == '\0') {
-atend:
- ind = *optnext - optfirst + 1;
- *optnext = NULL;
- p = NULL;
- done = 1;
- goto out;
- }
- (*optnext)++;
- if (p[0] == '-' && p[1] == '\0') /* check for "--" */
- goto atend;
- }
-
- c = *p++;
- for (q = optstr; *q != c; ) {
- if (*q == '\0') {
- if (optstr[0] == ':') {
- s[0] = c;
- s[1] = '\0';
- err |= setvarsafe("OPTARG", s, 0);
- } else {
- outfmt(&errout, "Illegal option -%c\n", c);
- (void) unsetvar("OPTARG", 0);
- }
- c = '?';
- goto bad;
- }
- if (*++q == ':')
- q++;
- }
-
- if (*++q == ':') {
- if (*p == '\0' && (p = **optnext) == NULL) {
- if (optstr[0] == ':') {
- s[0] = c;
- s[1] = '\0';
- err |= setvarsafe("OPTARG", s, 0);
- c = ':';
- } else {
- outfmt(&errout, "No arg for -%c option\n", c);
- (void) unsetvar("OPTARG", 0);
- c = '?';
- }
- goto bad;
- }
-
- if (p == **optnext)
- (*optnext)++;
- err |= setvarsafe("OPTARG", p, 0);
- p = NULL;
- } else
- err |= setvarsafe("OPTARG", "", 0);
- ind = *optnext - optfirst + 1;
- goto out;
-
-bad:
- ind = 1;
- *optnext = NULL;
- p = NULL;
-out:
- *optpptr = p;
- fmtstr(s, sizeof(s), "%d", ind);
- err |= setvarsafe("OPTIND", s, VNOFUNC);
- s[0] = c;
- s[1] = '\0';
- err |= setvarsafe(optvar, s, 0);
- if (err) {
- *optnext = NULL;
- *optpptr = NULL;
- flushall();
- exraise(EXERROR);
- }
- return done;
-}
-
-/*
- * XXX - should get rid of. have all builtins use getopt(3). the
- * library getopt must have the BSD extension static variable "optreset"
- * otherwise it can't be used within the shell safely.
- *
- * Standard option processing (a la getopt) for builtin routines. The
- * only argument that is passed to nextopt is the option string; the
- * other arguments are unnecessary. It return the character, or '\0' on
- * end of input.
- */
-
-int
-nextopt(const char *optstring)
-{
- char *p;
- const char *q;
- char c;
-
- if ((p = optptr) == NULL || *p == '\0') {
- p = *argptr;
- if (p == NULL || *p != '-' || *++p == '\0')
- return '\0';
- argptr++;
- if (p[0] == '-' && p[1] == '\0') /* check for "--" */
- return '\0';
- }
- c = *p++;
- for (q = optstring ; *q != c ; ) {
- if (*q == '\0')
- error("Illegal option -%c", c);
- if (*++q == ':')
- q++;
- }
- if (*++q == ':') {
- if (*p == '\0' && (p = *argptr++) == NULL)
- error("No arg for -%c option", c);
- optionarg = p;
- p = NULL;
- }
- optptr = p;
- return c;
-}
diff --git a/bin/sh/options.h b/bin/sh/options.h
deleted file mode 100644
index 4857d18..0000000
--- a/bin/sh/options.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/* $NetBSD: options.h,v 1.27 2017/05/28 00:38:01 kre Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- *
- * @(#)options.h 8.2 (Berkeley) 5/4/95
- */
-
-struct shparam {
- int nparam; /* # of positional parameters (without $0) */
- unsigned char malloc; /* if parameter list dynamically allocated */
- unsigned char reset; /* if getopts has been reset */
- char **p; /* parameter list */
- char **optnext; /* next parameter to be processed by getopts */
- char *optptr; /* used by getopts */
-};
-
-/*
- * Note that option default values can be changed at shell startup
- * depending upon the environment in which the shell is running.
- */
-struct optent {
- const char *name; /* for set -o <name> */
- const char letter; /* set [+/-]<letter> and $- */
- const char opt_set; /* mutually exclusive option set */
- unsigned char val; /* value of <letter>flag */
- unsigned char dflt; /* default value of flag */
-};
-
-#include "optinit.h"
-
-extern char *minusc; /* argument to -c option */
-extern char *arg0; /* $0 */
-extern struct shparam shellparam; /* $@ */
-extern char **argptr; /* argument list for builtin commands */
-extern char *optionarg; /* set by nextopt */
-extern char *optptr; /* used by nextopt */
-
-void procargs(int, char **);
-void optschanged(void);
-void setparam(char **);
-void freeparam(volatile struct shparam *);
-int nextopt(const char *);
-void getoptsreset(const char *);
diff --git a/bin/sh/output.c b/bin/sh/output.c
deleted file mode 100644
index 99bd913..0000000
--- a/bin/sh/output.c
+++ /dev/null
@@ -1,755 +0,0 @@
-/* $NetBSD: output.c,v 1.40 2017/11/21 03:42:39 kre Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- */
-
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)output.c 8.2 (Berkeley) 5/4/95";
-#else
-__RCSID("$NetBSD: output.c,v 1.40 2017/11/21 03:42:39 kre Exp $");
-#endif
-#endif /* not lint */
-
-/*
- * Shell output routines. We use our own output routines because:
- * When a builtin command is interrupted we have to discard
- * any pending output.
- * When a builtin command appears in back quotes, we want to
- * save the output of the command in a region obtained
- * via malloc, rather than doing a fork and reading the
- * output of the command via a pipe.
- * Our output routines may be smaller than the stdio routines.
- */
-
-#include <sys/types.h> /* quad_t */
-#include <sys/param.h> /* BSD4_4 */
-#include <sys/ioctl.h>
-
-#include <stdio.h> /* defines BUFSIZ */
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-
-#include "shell.h"
-#include "syntax.h"
-#include "output.h"
-#include "memalloc.h"
-#include "error.h"
-#include "redir.h"
-#include "options.h"
-#include "show.h"
-
-
-#define OUTBUFSIZ BUFSIZ
-#define BLOCK_OUT -2 /* output to a fixed block of memory */
-#define MEM_OUT -3 /* output to dynamically allocated memory */
-
-#ifdef SMALL
-#define CHAIN
-#else
-#define CHAIN ,NULL
-#endif
-
-
- /* nextc nleft bufsize buf fd flags chain */
-struct output output = {NULL, 0, OUTBUFSIZ, NULL, 1, 0 CHAIN };
-struct output errout = {NULL, 0, 100, NULL, 2, 0 CHAIN };
-struct output memout = {NULL, 0, 0, NULL, MEM_OUT, 0 CHAIN };
-struct output *out1 = &output;
-struct output *out2 = &errout;
-#ifndef SMALL
-struct output *outx = &errout;
-struct output *outxtop = NULL;
-#endif
-
-
-#ifdef mkinit
-
-INCLUDE "output.h"
-INCLUDE "memalloc.h"
-
-RESET {
- out1 = &output;
- out2 = &errout;
- if (memout.buf != NULL) {
- ckfree(memout.buf);
- memout.buf = NULL;
- }
-}
-
-#endif
-
-
-#ifdef notdef /* no longer used */
-/*
- * Set up an output file to write to memory rather than a file.
- */
-
-void
-open_mem(char *block, int length, struct output *file)
-{
- file->nextc = block;
- file->nleft = --length;
- file->fd = BLOCK_OUT;
- file->flags = 0;
-}
-#endif
-
-
-void
-out1str(const char *p)
-{
- outstr(p, out1);
-}
-
-
-void
-out2str(const char *p)
-{
- outstr(p, out2);
-}
-
-#ifndef SMALL
-void
-outxstr(const char *p)
-{
- outstr(p, outx);
-}
-#endif
-
-
-void
-outstr(const char *p, struct output *file)
-{
- char c = 0;
-
- while (*p)
- outc((c = *p++), file);
- if (file == out2 || (file == outx && c == '\n'))
- flushout(file);
-}
-
-
-void
-out2shstr(const char *p)
-{
- outshstr(p, out2);
-}
-
-#ifndef SMALL
-void
-outxshstr(const char *p)
-{
- outshstr(p, outx);
-}
-#endif
-
-/*
- * ' is in this list, not because it does not require quoting
- * (which applies to all the others) but because '' quoting cannot
- * be used to quote it.
- */
-static const char norm_chars [] = \
- "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/+-=_,.'";
-
-static int
-inquote(const char *p)
-{
- size_t l = strspn(p, norm_chars);
- char *s = strchr(p, '\'');
-
- return s == NULL ? p[l] != '\0' : s - p > (off_t)l;
-}
-
-void
-outshstr(const char *p, struct output *file)
-{
- int need_q;
- int inq;
- char c;
-
- if (strchr(p, '\'') != NULL && p[1] != '\0') {
- /*
- * string contains ' in it, and is not only the '
- * see if " quoting will work
- */
- size_t i = strcspn(p, "\\\"$`");
-
- if (p[i] == '\0') {
- /*
- * string contains no $ ` \ or " chars, perfect...
- *
- * We know it contains ' so needs quoting, so
- * this is easy...
- */
- outc('"', file);
- outstr(p, file);
- outc('"', file);
- return;
- }
- }
-
- need_q = p[0] == 0 || p[strspn(p, norm_chars)] != 0;
-
- /*
- * Don't emit ' unless something needs quoting before closing '
- */
- if (need_q && (p[0] == 0 || inquote(p) != 0)) {
- outc('\'', file);
- inq = 1;
- } else
- inq = 0;
-
- while ((c = *p++) != '\0') {
- if (c != '\'') {
- outc(c, file);
- continue;
- }
-
- if (inq)
- outc('\'', file); /* inq = 0, implicit */
- outc('\\', file);
- outc(c, file);
- if (need_q && *p != '\0') {
- if ((inq = inquote(p)) != 0)
- outc('\'', file);
- } else
- inq = 0;
- }
-
- if (inq)
- outc('\'', file);
-
- if (file == out2)
- flushout(file);
-}
-
-
-char out_junk[16];
-
-
-void
-emptyoutbuf(struct output *dest)
-{
- int offset;
-
- if (dest->fd == BLOCK_OUT) {
- dest->nextc = out_junk;
- dest->nleft = sizeof out_junk;
- dest->flags |= OUTPUT_ERR;
- } else if (dest->buf == NULL) {
- INTOFF;
- dest->buf = ckmalloc(dest->bufsize);
- dest->nextc = dest->buf;
- dest->nleft = dest->bufsize;
- INTON;
- VTRACE(DBG_OUTPUT, ("emptyoutbuf now %d @%p for fd %d\n",
- dest->nleft, dest->buf, dest->fd));
- } else if (dest->fd == MEM_OUT) {
- offset = dest->bufsize;
- INTOFF;
- dest->bufsize <<= 1;
- dest->buf = ckrealloc(dest->buf, dest->bufsize);
- dest->nleft = dest->bufsize - offset;
- dest->nextc = dest->buf + offset;
- INTON;
- } else {
- flushout(dest);
- }
- dest->nleft--;
-}
-
-
-void
-flushall(void)
-{
- flushout(&output);
- flushout(&errout);
-}
-
-
-void
-flushout(struct output *dest)
-{
-
- if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0)
- return;
- VTRACE(DBG_OUTPUT, ("flushout fd=%d %zd to write\n", dest->fd,
- (size_t)(dest->nextc - dest->buf)));
- if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0)
- dest->flags |= OUTPUT_ERR;
- dest->nextc = dest->buf;
- dest->nleft = dest->bufsize;
-}
-
-
-void
-freestdout(void)
-{
- INTOFF;
- if (output.buf) {
- ckfree(output.buf);
- output.buf = NULL;
- output.nleft = 0;
- }
- INTON;
-}
-
-
-void
-outfmt(struct output *file, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- doformat(file, fmt, ap);
- va_end(ap);
-}
-
-
-void
-out1fmt(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- doformat(out1, fmt, ap);
- va_end(ap);
-}
-
-#ifdef DEBUG
-void
-debugprintf(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- doformat(out2, fmt, ap);
- va_end(ap);
- flushout(out2);
-}
-#endif
-
-void
-fmtstr(char *outbuf, size_t length, const char *fmt, ...)
-{
- va_list ap;
- struct output strout;
-
- va_start(ap, fmt);
- strout.nextc = outbuf;
- strout.nleft = length;
- strout.fd = BLOCK_OUT;
- strout.flags = 0;
- doformat(&strout, fmt, ap);
- outc('\0', &strout);
- if (strout.flags & OUTPUT_ERR)
- outbuf[length - 1] = '\0';
- va_end(ap);
-}
-
-/*
- * Formatted output. This routine handles a subset of the printf formats:
- * - Formats supported: d, u, o, p, X, s, and c.
- * - The x format is also accepted but is treated like X.
- * - The l, ll and q modifiers are accepted.
- * - The - and # flags are accepted; # only works with the o format.
- * - Width and precision may be specified with any format except c.
- * - An * may be given for the width or precision.
- * - The obsolete practice of preceding the width with a zero to get
- * zero padding is not supported; use the precision field.
- * - A % may be printed by writing %% in the format string.
- */
-
-#define TEMPSIZE 24
-
-#ifdef BSD4_4
-#define HAVE_VASPRINTF 1
-#endif
-
-void
-doformat(struct output *dest, const char *f, va_list ap)
-{
-#if HAVE_VASPRINTF
- char *s;
-
- vasprintf(&s, f, ap);
- if (s == NULL)
- error("Could not allocate formatted output buffer");
- outstr(s, dest);
- free(s);
-#else /* !HAVE_VASPRINTF */
- static const char digit[] = "0123456789ABCDEF";
- char c;
- char temp[TEMPSIZE];
- int flushleft;
- int sharp;
- int width;
- int prec;
- int islong;
- int isquad;
- char *p;
- int sign;
-#ifdef BSD4_4
- quad_t l;
- u_quad_t num;
-#else
- long l;
- u_long num;
-#endif
- unsigned base;
- int len;
- int size;
- int pad;
-
- while ((c = *f++) != '\0') {
- if (c != '%') {
- outc(c, dest);
- continue;
- }
- flushleft = 0;
- sharp = 0;
- width = 0;
- prec = -1;
- islong = 0;
- isquad = 0;
- for (;;) {
- if (*f == '-')
- flushleft++;
- else if (*f == '#')
- sharp++;
- else
- break;
- f++;
- }
- if (*f == '*') {
- width = va_arg(ap, int);
- f++;
- } else {
- while (is_digit(*f)) {
- width = 10 * width + digit_val(*f++);
- }
- }
- if (*f == '.') {
- if (*++f == '*') {
- prec = va_arg(ap, int);
- f++;
- } else {
- prec = 0;
- while (is_digit(*f)) {
- prec = 10 * prec + digit_val(*f++);
- }
- }
- }
- if (*f == 'l') {
- f++;
- if (*f == 'l') {
- isquad++;
- f++;
- } else
- islong++;
- } else if (*f == 'q') {
- isquad++;
- f++;
- }
- switch (*f) {
- case 'd':
-#ifdef BSD4_4
- if (isquad)
- l = va_arg(ap, quad_t);
- else
-#endif
- if (islong)
- l = va_arg(ap, long);
- else
- l = va_arg(ap, int);
- sign = 0;
- num = l;
- if (l < 0) {
- num = -l;
- sign = 1;
- }
- base = 10;
- goto number;
- case 'u':
- base = 10;
- goto uns_number;
- case 'o':
- base = 8;
- goto uns_number;
- case 'p':
- outc('0', dest);
- outc('x', dest);
- /*FALLTHROUGH*/
- case 'x':
- /* we don't implement 'x'; treat like 'X' */
- case 'X':
- base = 16;
-uns_number: /* an unsigned number */
- sign = 0;
-#ifdef BSD4_4
- if (isquad)
- num = va_arg(ap, u_quad_t);
- else
-#endif
- if (islong)
- num = va_arg(ap, unsigned long);
- else
- num = va_arg(ap, unsigned int);
-number: /* process a number */
- p = temp + TEMPSIZE - 1;
- *p = '\0';
- while (num) {
- *--p = digit[num % base];
- num /= base;
- }
- len = (temp + TEMPSIZE - 1) - p;
- if (prec < 0)
- prec = 1;
- if (sharp && *f == 'o' && prec <= len)
- prec = len + 1;
- pad = 0;
- if (width) {
- size = len;
- if (size < prec)
- size = prec;
- size += sign;
- pad = width - size;
- if (flushleft == 0) {
- while (--pad >= 0)
- outc(' ', dest);
- }
- }
- if (sign)
- outc('-', dest);
- prec -= len;
- while (--prec >= 0)
- outc('0', dest);
- while (*p)
- outc(*p++, dest);
- while (--pad >= 0)
- outc(' ', dest);
- break;
- case 's':
- p = va_arg(ap, char *);
- pad = 0;
- if (width) {
- len = strlen(p);
- if (prec >= 0 && len > prec)
- len = prec;
- pad = width - len;
- if (flushleft == 0) {
- while (--pad >= 0)
- outc(' ', dest);
- }
- }
- prec++;
- while (--prec != 0 && *p)
- outc(*p++, dest);
- while (--pad >= 0)
- outc(' ', dest);
- break;
- case 'c':
- c = va_arg(ap, int);
- outc(c, dest);
- break;
- default:
- outc(*f, dest);
- break;
- }
- f++;
- }
-#endif /* !HAVE_VASPRINTF */
-}
-
-
-
-/*
- * Version of write which resumes after a signal is caught.
- */
-
-int
-xwrite(int fd, char *buf, int nbytes)
-{
- int ntry;
- int i;
- int n;
-
- n = nbytes;
- ntry = 0;
- while (n > 0) {
- i = write(fd, buf, n);
- if (i > 0) {
- if ((n -= i) <= 0)
- return nbytes;
- buf += i;
- ntry = 0;
- } else if (i == 0) {
- if (++ntry > 10)
- return nbytes - n;
- } else if (errno != EINTR) {
- return -1;
- }
- }
- return nbytes;
-}
-
-#ifndef SMALL
-static void
-xtrace_fd_swap(int from, int to)
-{
- struct output *o = outxtop;
-
- while (o != NULL) {
- if (o->fd == from)
- o->fd = to;
- o = o->chain;
- }
-}
-
-/*
- * the -X flag is to be set or reset (not necessarily changed)
- * Do what is needed to make tracing go to where it should
- *
- * Note: Xflag has not yet been altered, "on" indicates what it will become
- */
-
-void
-xtracefdsetup(int on)
-{
- if (!on) {
- flushout(outx);
-
- if (Xflag != 1) /* Was already +X */
- return; /* so nothing to do */
-
- outx = out2;
- CTRACE(DBG_OUTPUT, ("Tracing to stderr\n"));
- return;
- }
-
- if (Xflag == 1) { /* was already set */
- /*
- * This is a change of output file only
- * Just close the current one, and reuse the struct output
- */
- if (!(outx->flags & OUTPUT_CLONE))
- sh_close(outx->fd);
- } else if (outxtop == NULL) {
- /*
- * -X is just turning on, for the forst time,
- * need a new output struct to become outx
- */
- xtrace_clone(1);
- } else
- outx = outxtop;
-
- if (outx != out2) {
- outx->flags &= ~OUTPUT_CLONE;
- outx->fd = to_upper_fd(dup(out2->fd));
- register_sh_fd(outx->fd, xtrace_fd_swap);
- }
-
- CTRACE(DBG_OUTPUT, ("Tracing now to fd %d (from %d)\n",
- outx->fd, out2->fd));
-}
-
-void
-xtrace_clone(int new)
-{
- struct output *o;
-
- CTRACE(DBG_OUTPUT,
- ("xtrace_clone(%d): %sfd=%d buf=%p nleft=%d flags=%x ",
- new, (outx == out2 ? "out2: " : ""),
- outx->fd, outx->buf, outx->nleft, outx->flags));
-
- flushout(outx);
-
- if (!new && outxtop == NULL && Xflag == 0) {
- /* following stderr, nothing to save */
- CTRACE(DBG_OUTPUT, ("+X\n"));
- return;
- }
-
- o = ckmalloc(sizeof(*o));
- o->fd = outx->fd;
- o->flags = OUTPUT_CLONE;
- o->bufsize = outx->bufsize;
- o->nleft = 0;
- o->buf = NULL;
- o->nextc = NULL;
- o->chain = outxtop;
- outx = o;
- outxtop = o;
-
- CTRACE(DBG_OUTPUT, ("-> fd=%d flags=%x[CLONE]\n", outx->fd, o->flags));
-}
-
-void
-xtrace_pop(void)
-{
- struct output *o;
-
- CTRACE(DBG_OUTPUT, ("trace_pop: fd=%d buf=%p nleft=%d flags=%x ",
- outx->fd, outx->buf, outx->nleft, outx->flags));
-
- flushout(outx);
-
- if (outxtop == NULL) {
- /*
- * No -X has been used, so nothing much to do
- */
- CTRACE(DBG_OUTPUT, ("+X\n"));
- return;
- }
-
- o = outxtop;
- outx = o->chain;
- if (outx == NULL)
- outx = &errout;
- outxtop = o->chain;
- if (o != &errout) {
- if (o->fd >= 0 && !(o->flags & OUTPUT_CLONE))
- sh_close(o->fd);
- if (o->buf)
- ckfree(o->buf);
- ckfree(o);
- }
-
- CTRACE(DBG_OUTPUT, ("-> fd=%d buf=%p nleft=%d flags=%x\n",
- outx->fd, outx->buf, outx->nleft, outx->flags));
-}
-#endif /* SMALL */
diff --git a/bin/sh/output.h b/bin/sh/output.h
deleted file mode 100644
index a19df43..0000000
--- a/bin/sh/output.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/* $NetBSD: output.h,v 1.27 2017/11/21 03:42:39 kre Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- *
- * @(#)output.h 8.2 (Berkeley) 5/4/95
- */
-
-#ifndef OUTPUT_INCL
-
-#include <stdarg.h>
-
-struct output {
- char *nextc;
- int nleft;
- int bufsize;
- char *buf;
- short fd;
- short flags;
-#ifndef SMALL
- struct output *chain;
-#endif
-};
-
-/* flags for ->flags */
-#define OUTPUT_ERR 0x01 /* error occurred on output */
-#define OUTPUT_CLONE 0x02 /* this is a clone of another */
-
-extern struct output output;
-extern struct output errout;
-extern struct output memout;
-extern struct output *out1;
-extern struct output *out2;
-#ifdef SMALL
-#define outx out2
-#else
-extern struct output *outx;
-#endif
-
-void open_mem(char *, int, struct output *);
-void out1str(const char *);
-void out2str(const char *);
-void outstr(const char *, struct output *);
-void out2shstr(const char *);
-#ifdef SMALL
-#define outxstr out2str
-#define outxshstr out2shstr
-#else
-void outxstr(const char *);
-void outxshstr(const char *);
-#endif
-void outshstr(const char *, struct output *);
-void emptyoutbuf(struct output *);
-void flushall(void);
-void flushout(struct output *);
-void freestdout(void);
-void outfmt(struct output *, const char *, ...) __printflike(2, 3);
-void out1fmt(const char *, ...) __printflike(1, 2);
-#ifdef DEBUG
-void debugprintf(const char *, ...) __printflike(1, 2);
-#endif
-void fmtstr(char *, size_t, const char *, ...) __printflike(3, 4);
-void doformat(struct output *, const char *, va_list) __printflike(2, 0);
-int xwrite(int, char *, int);
-#ifdef SMALL
-#define xtracefdsetup(x) do { break; } while (0)
-#define xtrace_clone(x) do { break; } while (0)
-#define xtrace_pop() do { break; } while (0)
-#else
-void xtracefdsetup(int);
-void xtrace_clone(int);
-void xtrace_pop(void);
-#endif
-
-#define outc(c, file) (--(file)->nleft < 0? (emptyoutbuf(file), *(file)->nextc++ = (c)) : (*(file)->nextc++ = (c)))
-#define out1c(c) outc(c, out1)
-#define out2c(c) outc(c, out2)
-#define outxc(c) outc(c, outx)
-
-#define OUTPUT_INCL
-#endif
diff --git a/bin/sh/parser.c b/bin/sh/parser.c
deleted file mode 100644
index 6b153aa..0000000
--- a/bin/sh/parser.c
+++ /dev/null
@@ -1,2756 +0,0 @@
-/* $NetBSD: parser.c,v 1.164 2019/01/22 14:32:17 kre Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- */
-
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)parser.c 8.7 (Berkeley) 5/16/95";
-#else
-__RCSID("$NetBSD: parser.c,v 1.164 2019/01/22 14:32:17 kre Exp $");
-#endif
-#endif /* not lint */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <limits.h>
-
-#include "shell.h"
-#include "parser.h"
-#include "nodes.h"
-#include "expand.h" /* defines rmescapes() */
-#include "eval.h" /* defines commandname */
-#include "syntax.h"
-#include "options.h"
-#include "input.h"
-#include "output.h"
-#include "var.h"
-#include "error.h"
-#include "memalloc.h"
-#include "mystring.h"
-#include "alias.h"
-#include "show.h"
-#ifndef SMALL
-#include "myhistedit.h"
-#endif
-#ifdef DEBUG
-#include "nodenames.h"
-#endif
-
-/*
- * Shell command parser.
- */
-
-/* values returned by readtoken */
-#include "token.h"
-
-#define OPENBRACE '{'
-#define CLOSEBRACE '}'
-
-struct HereDoc {
- struct HereDoc *next; /* next here document in list */
- union node *here; /* redirection node */
- char *eofmark; /* string indicating end of input */
- int striptabs; /* if set, strip leading tabs */
- int startline; /* line number where << seen */
-};
-
-MKINIT struct parse_state parse_state;
-union parse_state_p psp = { .c_current_parser = &parse_state };
-
-static const struct parse_state init_parse_state = { /* all 0's ... */
- .ps_heredoclist = NULL,
- .ps_parsebackquote = 0,
- .ps_doprompt = 0,
- .ps_needprompt = 0,
- .ps_lasttoken = 0,
- .ps_tokpushback = 0,
- .ps_wordtext = NULL,
- .ps_checkkwd = 0,
- .ps_redirnode = NULL,
- .ps_heredoc = NULL,
- .ps_quoteflag = 0,
- .ps_startlinno = 0,
- .ps_funclinno = 0,
- .ps_elided_nl = 0,
-};
-
-STATIC union node *list(int);
-STATIC union node *andor(void);
-STATIC union node *pipeline(void);
-STATIC union node *command(void);
-STATIC union node *simplecmd(union node **, union node *);
-STATIC union node *makeword(int);
-STATIC void parsefname(void);
-STATIC int slurp_heredoc(char *const, const int, const int);
-STATIC void readheredocs(void);
-STATIC int peektoken(void);
-STATIC int readtoken(void);
-STATIC int xxreadtoken(void);
-STATIC int readtoken1(int, char const *, int);
-STATIC int noexpand(char *);
-STATIC void linebreak(void);
-STATIC void consumetoken(int);
-STATIC void synexpect(int, const char *) __dead;
-STATIC void synerror(const char *) __dead;
-STATIC void setprompt(int);
-STATIC int pgetc_linecont(void);
-
-static const char EOFhere[] = "EOF reading here (<<) document";
-
-#ifdef DEBUG
-int parsing = 0;
-#endif
-
-/*
- * Read and parse a command. Returns NEOF on end of file. (NULL is a
- * valid parse tree indicating a blank line.)
- */
-
-union node *
-parsecmd(int interact)
-{
- int t;
- union node *n;
-
-#ifdef DEBUG
- parsing++;
-#endif
- tokpushback = 0;
- checkkwd = 0;
- doprompt = interact;
- if (doprompt)
- setprompt(1);
- else
- setprompt(0);
- needprompt = 0;
- t = readtoken();
-#ifdef DEBUG
- parsing--;
-#endif
- if (t == TEOF)
- return NEOF;
- if (t == TNL)
- return NULL;
-
-#ifdef DEBUG
- parsing++;
-#endif
- tokpushback++;
- n = list(1);
-#ifdef DEBUG
- parsing--;
-#endif
- if (heredoclist)
- error("%d: Here document (<<%s) expected but not present",
- heredoclist->startline, heredoclist->eofmark);
- return n;
-}
-
-
-STATIC union node *
-list(int nlflag)
-{
- union node *ntop, *n1, *n2, *n3;
- int tok;
-
- CTRACE(DBG_PARSE, ("list(%d): entered @%d\n",nlflag,plinno));
-
- checkkwd = CHKNL | CHKKWD | CHKALIAS;
- if (nlflag == 0 && tokendlist[peektoken()])
- return NULL;
- ntop = n1 = NULL;
- for (;;) {
- n2 = andor();
- tok = readtoken();
- if (tok == TBACKGND) {
- if (n2->type == NCMD || n2->type == NPIPE)
- n2->ncmd.backgnd = 1;
- else if (n2->type == NREDIR)
- n2->type = NBACKGND;
- else {
- n3 = stalloc(sizeof(struct nredir));
- n3->type = NBACKGND;
- n3->nredir.n = n2;
- n3->nredir.redirect = NULL;
- n2 = n3;
- }
- }
-
- if (ntop == NULL)
- ntop = n2;
- else if (n1 == NULL) {
- n1 = stalloc(sizeof(struct nbinary));
- n1->type = NSEMI;
- n1->nbinary.ch1 = ntop;
- n1->nbinary.ch2 = n2;
- ntop = n1;
- } else {
- n3 = stalloc(sizeof(struct nbinary));
- n3->type = NSEMI;
- n3->nbinary.ch1 = n1->nbinary.ch2;
- n3->nbinary.ch2 = n2;
- n1->nbinary.ch2 = n3;
- n1 = n3;
- }
-
- switch (tok) {
- case TBACKGND:
- case TSEMI:
- tok = readtoken();
- /* FALLTHROUGH */
- case TNL:
- if (tok == TNL) {
- readheredocs();
- if (nlflag)
- return ntop;
- } else if (tok == TEOF && nlflag)
- return ntop;
- else
- tokpushback++;
-
- checkkwd = CHKNL | CHKKWD | CHKALIAS;
- if (!nlflag && tokendlist[peektoken()])
- return ntop;
- break;
- case TEOF:
- pungetc(); /* push back EOF on input */
- return ntop;
- default:
- if (nlflag)
- synexpect(-1, 0);
- tokpushback++;
- return ntop;
- }
- }
-}
-
-STATIC union node *
-andor(void)
-{
- union node *n1, *n2, *n3;
- int t;
-
- CTRACE(DBG_PARSE, ("andor: entered @%d\n", plinno));
-
- n1 = pipeline();
- for (;;) {
- if ((t = readtoken()) == TAND) {
- t = NAND;
- } else if (t == TOR) {
- t = NOR;
- } else {
- tokpushback++;
- return n1;
- }
- n2 = pipeline();
- n3 = stalloc(sizeof(struct nbinary));
- n3->type = t;
- n3->nbinary.ch1 = n1;
- n3->nbinary.ch2 = n2;
- n1 = n3;
- }
-}
-
-STATIC union node *
-pipeline(void)
-{
- union node *n1, *n2, *pipenode;
- struct nodelist *lp, *prev;
- int negate;
-
- CTRACE(DBG_PARSE, ("pipeline: entered @%d\n", plinno));
-
- negate = 0;
- checkkwd = CHKNL | CHKKWD | CHKALIAS;
- while (readtoken() == TNOT) {
- CTRACE(DBG_PARSE, ("pipeline: TNOT recognized\n"));
-#ifndef BOGUS_NOT_COMMAND
- if (posix && negate)
- synerror("2nd \"!\" unexpected");
-#endif
- negate++;
- }
- tokpushback++;
- n1 = command();
- if (readtoken() == TPIPE) {
- pipenode = stalloc(sizeof(struct npipe));
- pipenode->type = NPIPE;
- pipenode->npipe.backgnd = 0;
- lp = stalloc(sizeof(struct nodelist));
- pipenode->npipe.cmdlist = lp;
- lp->n = n1;
- do {
- prev = lp;
- lp = stalloc(sizeof(struct nodelist));
- lp->n = command();
- prev->next = lp;
- } while (readtoken() == TPIPE);
- lp->next = NULL;
- n1 = pipenode;
- }
- tokpushback++;
- if (negate) {
- CTRACE(DBG_PARSE, ("%snegate pipeline\n",
- (negate&1) ? "" : "double "));
- n2 = stalloc(sizeof(struct nnot));
- n2->type = (negate & 1) ? NNOT : NDNOT;
- n2->nnot.com = n1;
- return n2;
- } else
- return n1;
-}
-
-
-
-STATIC union node *
-command(void)
-{
- union node *n1, *n2;
- union node *ap, **app;
- union node *cp, **cpp;
- union node *redir, **rpp;
- int t;
-#ifdef BOGUS_NOT_COMMAND
- int negate = 0;
-#endif
-
- CTRACE(DBG_PARSE, ("command: entered @%d\n", plinno));
-
- checkkwd = CHKNL | CHKKWD | CHKALIAS;
- redir = NULL;
- n1 = NULL;
- rpp = &redir;
-
- /* Check for redirection which may precede command */
- while (readtoken() == TREDIR) {
- *rpp = n2 = redirnode;
- rpp = &n2->nfile.next;
- parsefname();
- }
- tokpushback++;
-
-#ifdef BOGUS_NOT_COMMAND /* only in pileline() */
- while (readtoken() == TNOT) {
- CTRACE(DBG_PARSE, ("command: TNOT (bogus) recognized\n"));
- negate++;
- }
- tokpushback++;
-#endif
-
- switch (readtoken()) {
- case TIF:
- n1 = stalloc(sizeof(struct nif));
- n1->type = NIF;
- n1->nif.test = list(0);
- consumetoken(TTHEN);
- n1->nif.ifpart = list(0);
- n2 = n1;
- while (readtoken() == TELIF) {
- n2->nif.elsepart = stalloc(sizeof(struct nif));
- n2 = n2->nif.elsepart;
- n2->type = NIF;
- n2->nif.test = list(0);
- consumetoken(TTHEN);
- n2->nif.ifpart = list(0);
- }
- if (lasttoken == TELSE)
- n2->nif.elsepart = list(0);
- else {
- n2->nif.elsepart = NULL;
- tokpushback++;
- }
- consumetoken(TFI);
- checkkwd = CHKKWD | CHKALIAS;
- break;
- case TWHILE:
- case TUNTIL:
- n1 = stalloc(sizeof(struct nbinary));
- n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
- n1->nbinary.ch1 = list(0);
- consumetoken(TDO);
- n1->nbinary.ch2 = list(0);
- consumetoken(TDONE);
- checkkwd = CHKKWD | CHKALIAS;
- break;
- case TFOR:
- if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
- synerror("Bad for loop variable");
- n1 = stalloc(sizeof(struct nfor));
- n1->type = NFOR;
- n1->nfor.var = wordtext;
- linebreak();
- if (lasttoken==TWORD && !quoteflag && equal(wordtext,"in")) {
- app = &ap;
- while (readtoken() == TWORD) {
- n2 = makeword(startlinno);
- *app = n2;
- app = &n2->narg.next;
- }
- *app = NULL;
- n1->nfor.args = ap;
- if (lasttoken != TNL && lasttoken != TSEMI)
- synexpect(TSEMI, 0);
- } else {
- static char argvars[5] = {
- CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'
- };
-
- n2 = stalloc(sizeof(struct narg));
- n2->type = NARG;
- n2->narg.text = argvars;
- n2->narg.backquote = NULL;
- n2->narg.next = NULL;
- n2->narg.lineno = startlinno;
- n1->nfor.args = n2;
- /*
- * Newline or semicolon here is optional (but note
- * that the original Bourne shell only allowed NL).
- */
- if (lasttoken != TNL && lasttoken != TSEMI)
- tokpushback++;
- }
- checkkwd = CHKNL | CHKKWD | CHKALIAS;
- if ((t = readtoken()) == TDO)
- t = TDONE;
- else if (t == TBEGIN)
- t = TEND;
- else
- synexpect(TDO, 0);
- n1->nfor.body = list(0);
- consumetoken(t);
- checkkwd = CHKKWD | CHKALIAS;
- break;
- case TCASE:
- n1 = stalloc(sizeof(struct ncase));
- n1->type = NCASE;
- n1->ncase.lineno = startlinno - elided_nl;
- consumetoken(TWORD);
- n1->ncase.expr = makeword(startlinno);
- linebreak();
- if (lasttoken != TWORD || !equal(wordtext, "in"))
- synexpect(-1, "in");
- cpp = &n1->ncase.cases;
- checkkwd = CHKNL | CHKKWD;
- readtoken();
- /*
- * Both ksh and bash accept 'case x in esac'
- * so configure scripts started taking advantage of this.
- * The page: http://pubs.opengroup.org/onlinepubs/\
- * 009695399/utilities/xcu_chap02.html contradicts itself,
- * as to if this is legal; the "Case Conditional Format"
- * paragraph shows one case is required, but the "Grammar"
- * section shows a grammar that explicitly allows the no
- * case option.
- *
- * The standard also says (section 2.10):
- * This formal syntax shall take precedence over the
- * preceding text syntax description.
- * ie: the "Grammar" section wins. The text is just
- * a rough guide (introduction to the common case.)
- */
- while (lasttoken != TESAC) {
- *cpp = cp = stalloc(sizeof(struct nclist));
- cp->type = NCLIST;
- app = &cp->nclist.pattern;
- if (lasttoken == TLP)
- readtoken();
- for (;;) {
- if (lasttoken < TWORD)
- synexpect(TWORD, 0);
- *app = ap = makeword(startlinno);
- checkkwd = CHKNL | CHKKWD;
- if (readtoken() != TPIPE)
- break;
- app = &ap->narg.next;
- readtoken();
- }
- if (lasttoken != TRP)
- synexpect(TRP, 0);
- cp->nclist.lineno = startlinno;
- cp->nclist.body = list(0);
-
- checkkwd = CHKNL | CHKKWD | CHKALIAS;
- if ((t = readtoken()) != TESAC) {
- if (t != TENDCASE && t != TCASEFALL) {
- synexpect(TENDCASE, 0);
- } else {
- if (t == TCASEFALL)
- cp->type = NCLISTCONT;
- checkkwd = CHKNL | CHKKWD;
- readtoken();
- }
- }
- cpp = &cp->nclist.next;
- }
- *cpp = NULL;
- checkkwd = CHKKWD | CHKALIAS;
- break;
- case TLP:
- n1 = stalloc(sizeof(struct nredir));
- n1->type = NSUBSHELL;
- n1->nredir.n = list(0);
- n1->nredir.redirect = NULL;
- if (n1->nredir.n == NULL)
- synexpect(-1, 0);
- consumetoken(TRP);
- checkkwd = CHKKWD | CHKALIAS;
- break;
- case TBEGIN:
- n1 = list(0);
- if (posix && n1 == NULL)
- synexpect(-1, 0);
- consumetoken(TEND);
- checkkwd = CHKKWD | CHKALIAS;
- break;
-
- case TBACKGND:
- case TSEMI:
- case TAND:
- case TOR:
- case TPIPE:
- case TNL:
- case TEOF:
- case TRP:
- case TENDCASE:
- case TCASEFALL:
- /*
- * simple commands must have something in them,
- * either a word (which at this point includes a=b)
- * or a redirection. If we reached the end of the
- * command (which one of these tokens indicates)
- * when we are just starting, and have not had a
- * redirect, then ...
- *
- * nb: it is still possible to end up with empty
- * simple commands, if the "command" is a var
- * expansion that produces nothing:
- * X= ; $X && $X
- * --> &&
- * That is OK and is handled after word expansions.
- */
- if (!redir)
- synexpect(-1, 0);
- /*
- * continue to build a node containing the redirect.
- * the tokpushback means that our ending token will be
- * read again in simplecmd, causing it to terminate,
- * so only the redirect(s) will be contained in the
- * returned n1
- */
- /* FALLTHROUGH */
- case TWORD:
- tokpushback++;
- n1 = simplecmd(rpp, redir);
- goto checkneg;
- default:
- synexpect(-1, 0);
- /* NOTREACHED */
- }
-
- /* Now check for redirection which may follow command */
- while (readtoken() == TREDIR) {
- *rpp = n2 = redirnode;
- rpp = &n2->nfile.next;
- parsefname();
- }
- tokpushback++;
- *rpp = NULL;
- if (redir) {
- if (n1 == NULL || n1->type != NSUBSHELL) {
- n2 = stalloc(sizeof(struct nredir));
- n2->type = NREDIR;
- n2->nredir.n = n1;
- n1 = n2;
- }
- n1->nredir.redirect = redir;
- }
-
- checkneg:
-#ifdef BOGUS_NOT_COMMAND
- if (negate) {
- VTRACE(DBG_PARSE, ("bogus %snegate command\n",
- (negate&1) ? "" : "double "));
- n2 = stalloc(sizeof(struct nnot));
- n2->type = (negate & 1) ? NNOT : NDNOT;
- n2->nnot.com = n1;
- return n2;
- }
- else
-#endif
- return n1;
-}
-
-
-STATIC union node *
-simplecmd(union node **rpp, union node *redir)
-{
- union node *args, **app;
- union node *n = NULL;
- int line = 0;
- int savecheckkwd;
-#ifdef BOGUS_NOT_COMMAND
- union node *n2;
- int negate = 0;
-#endif
-
- CTRACE(DBG_PARSE, ("simple command with%s redir already @%d\n",
- redir ? "" : "out", plinno));
-
- /* If we don't have any redirections already, then we must reset */
- /* rpp to be the address of the local redir variable. */
- if (redir == 0)
- rpp = &redir;
-
- args = NULL;
- app = &args;
-
-#ifdef BOGUS_NOT_COMMAND /* pipelines get negated, commands do not */
- while (readtoken() == TNOT) {
- VTRACE(DBG_PARSE, ("simplcmd: bogus TNOT recognized\n"));
- negate++;
- }
- tokpushback++;
-#endif
-
- savecheckkwd = CHKALIAS;
- for (;;) {
- checkkwd = savecheckkwd;
- if (readtoken() == TWORD) {
- if (line == 0)
- line = startlinno;
- n = makeword(startlinno);
- *app = n;
- app = &n->narg.next;
- if (savecheckkwd != 0 && !isassignment(wordtext))
- savecheckkwd = 0;
- } else if (lasttoken == TREDIR) {
- if (line == 0)
- line = startlinno;
- *rpp = n = redirnode;
- rpp = &n->nfile.next;
- parsefname(); /* read name of redirection file */
- } else if (lasttoken == TLP && app == &args->narg.next
- && redir == 0) {
- /* We have a function */
- consumetoken(TRP);
- funclinno = plinno;
- rmescapes(n->narg.text);
- if (strchr(n->narg.text, '/'))
- synerror("Bad function name");
- VTRACE(DBG_PARSE, ("Function '%s' seen @%d\n",
- n->narg.text, plinno));
- n->type = NDEFUN;
- n->narg.lineno = plinno - elided_nl;
- n->narg.next = command();
- funclinno = 0;
- goto checkneg;
- } else {
- tokpushback++;
- break;
- }
- }
-
- if (args == NULL && redir == NULL)
- synexpect(-1, 0);
- *app = NULL;
- *rpp = NULL;
- n = stalloc(sizeof(struct ncmd));
- n->type = NCMD;
- n->ncmd.lineno = line - elided_nl;
- n->ncmd.backgnd = 0;
- n->ncmd.args = args;
- n->ncmd.redirect = redir;
- n->ncmd.lineno = startlinno;
-
- checkneg:
-#ifdef BOGUS_NOT_COMMAND
- if (negate) {
- VTRACE(DBG_PARSE, ("bogus %snegate simplecmd\n",
- (negate&1) ? "" : "double "));
- n2 = stalloc(sizeof(struct nnot));
- n2->type = (negate & 1) ? NNOT : NDNOT;
- n2->nnot.com = n;
- return n2;
- }
- else
-#endif
- return n;
-}
-
-STATIC union node *
-makeword(int lno)
-{
- union node *n;
-
- n = stalloc(sizeof(struct narg));
- n->type = NARG;
- n->narg.next = NULL;
- n->narg.text = wordtext;
- n->narg.backquote = backquotelist;
- n->narg.lineno = lno;
- return n;
-}
-
-void
-fixredir(union node *n, const char *text, int err)
-{
-
- VTRACE(DBG_PARSE, ("Fix redir %s %d\n", text, err));
- if (!err)
- n->ndup.vname = NULL;
-
- if (is_number(text))
- n->ndup.dupfd = number(text);
- else if (text[0] == '-' && text[1] == '\0')
- n->ndup.dupfd = -1;
- else {
-
- if (err)
- synerror("Bad fd number");
- else
- n->ndup.vname = makeword(startlinno - elided_nl);
- }
-}
-
-
-STATIC void
-parsefname(void)
-{
- union node *n = redirnode;
-
- if (readtoken() != TWORD)
- synexpect(-1, 0);
- if (n->type == NHERE) {
- struct HereDoc *here = heredoc;
- struct HereDoc *p;
-
- if (quoteflag == 0)
- n->type = NXHERE;
- VTRACE(DBG_PARSE, ("Here document %d @%d\n", n->type, plinno));
- if (here->striptabs) {
- while (*wordtext == '\t')
- wordtext++;
- }
-
- /*
- * this test is not really necessary, we are not
- * required to expand wordtext, but there's no reason
- * it cannot be $$ or something like that - that would
- * not mean the pid, but literally two '$' characters.
- * There is no need for limits on what the word can be.
- * However, it needs to stay literal as entered, not
- * have $ converted to CTLVAR or something, which as
- * the parser is, at the minute, is impossible to prevent.
- * So, leave it like this until the rest of the parser is fixed.
- */
- if (!noexpand(wordtext))
- synerror("Illegal eof marker for << redirection");
-
- rmescapes(wordtext);
- here->eofmark = wordtext;
- here->next = NULL;
- if (heredoclist == NULL)
- heredoclist = here;
- else {
- for (p = heredoclist ; p->next ; p = p->next)
- continue;
- p->next = here;
- }
- } else if (n->type == NTOFD || n->type == NFROMFD) {
- fixredir(n, wordtext, 0);
- } else {
- n->nfile.fname = makeword(startlinno - elided_nl);
- }
-}
-
-/*
- * Check to see whether we are at the end of the here document. When this
- * is called, c is set to the first character of the next input line. If
- * we are at the end of the here document, this routine sets the c to PEOF.
- * The new value of c is returned.
- */
-
-static int
-checkend(int c, char * const eofmark, const int striptabs)
-{
-
- if (striptabs) {
- while (c == '\t')
- c = pgetc();
- }
- if (c == PEOF) {
- if (*eofmark == '\0')
- return (c);
- synerror(EOFhere);
- }
- if (c == *eofmark) {
- int c2;
- char *q;
-
- for (q = eofmark + 1; c2 = pgetc(), *q != '\0' && c2 == *q; q++)
- if (c2 == '\n') {
- plinno++;
- needprompt = doprompt;
- }
- if ((c2 == PEOF || c2 == '\n') && *q == '\0') {
- c = PEOF;
- if (c2 == '\n') {
- plinno++;
- needprompt = doprompt;
- }
- } else {
- pungetc();
- pushstring(eofmark + 1, q - (eofmark + 1), NULL);
- }
- } else if (c == '\n' && *eofmark == '\0') {
- c = PEOF;
- plinno++;
- needprompt = doprompt;
- }
- return (c);
-}
-
-
-/*
- * Input any here documents.
- */
-
-STATIC int
-slurp_heredoc(char *const eofmark, const int striptabs, const int sq)
-{
- int c;
- char *out;
- int lines = plinno;
-
- c = pgetc();
-
- /*
- * If we hit EOF on the input, and the eofmark is a null string ('')
- * we consider this empty line to be the eofmark, and exit without err.
- */
- if (c == PEOF && *eofmark != '\0')
- synerror(EOFhere);
-
- STARTSTACKSTR(out);
-
- while ((c = checkend(c, eofmark, striptabs)) != PEOF) {
- do {
- if (sq) {
- /*
- * in single quoted mode (eofmark quoted)
- * all we look for is \n so we can check
- * for the epfmark - everything saved literally.
- */
- STPUTC(c, out);
- if (c == '\n') {
- plinno++;
- break;
- }
- continue;
- }
- /*
- * In double quoted (non-quoted eofmark)
- * we must handle \ followed by \n here
- * otherwise we can mismatch the end mark.
- * All other uses of \ will be handled later
- * when the here doc is expanded.
- *
- * This also makes sure \\ followed by \n does
- * not suppress the newline (the \ quotes itself)
- */
- if (c == '\\') { /* A backslash */
- STPUTC(c, out);
- c = pgetc(); /* followed by */
- if (c == '\n') { /* a newline? */
- STPUTC(c, out);
- plinno++;
- continue; /* don't break */
- }
- }
- STPUTC(c, out); /* keep the char */
- if (c == '\n') { /* at end of line */
- plinno++;
- break; /* look for eofmark */
- }
- } while ((c = pgetc()) != PEOF);
-
- /*
- * If we have read a line, and reached EOF, without
- * finding the eofmark, whether the EOF comes before
- * or immediately after the \n, that is an error.
- */
- if (c == PEOF || (c = pgetc()) == PEOF)
- synerror(EOFhere);
- }
- STPUTC('\0', out);
-
- c = out - stackblock();
- out = stackblock();
- grabstackblock(c);
- wordtext = out;
-
- VTRACE(DBG_PARSE,
- ("Slurped a %d line %sheredoc (to '%s')%s: len %d, \"%.*s%s\" @%d\n",
- plinno - lines, sq ? "quoted " : "", eofmark,
- striptabs ? " tab stripped" : "", c, (c > 16 ? 16 : c),
- wordtext, (c > 16 ? "..." : ""), plinno));
-
- return (plinno - lines);
-}
-
-static char *
-insert_elided_nl(char *str)
-{
- while (elided_nl > 0) {
- STPUTC(CTLNONL, str);
- elided_nl--;
- }
- return str;
-}
-
-STATIC void
-readheredocs(void)
-{
- struct HereDoc *here;
- union node *n;
- int line, l;
-
- line = 0; /*XXX - gcc! obviously unneeded */
- if (heredoclist)
- line = heredoclist->startline + 1;
- l = 0;
- while (heredoclist) {
- line += l;
- here = heredoclist;
- heredoclist = here->next;
- if (needprompt) {
- setprompt(2);
- needprompt = 0;
- }
-
- l = slurp_heredoc(here->eofmark, here->striptabs,
- here->here->nhere.type == NHERE);
-
- here->here->nhere.doc = n = makeword(line);
-
- if (here->here->nhere.type == NHERE)
- continue;
-
- /*
- * Now "parse" here docs that have unquoted eofmarkers.
- */
- setinputstring(wordtext, 1, line);
- VTRACE(DBG_PARSE, ("Reprocessing %d line here doc from %d\n",
- l, line));
- readtoken1(pgetc(), DQSYNTAX, 1);
- n->narg.text = wordtext;
- n->narg.backquote = backquotelist;
- popfile();
- }
-}
-
-STATIC int
-peektoken(void)
-{
- int t;
-
- t = readtoken();
- tokpushback++;
- return (t);
-}
-
-STATIC int
-readtoken(void)
-{
- int t;
-#ifdef DEBUG
- int alreadyseen = tokpushback;
- int savecheckkwd = checkkwd;
-#endif
- struct alias *ap;
-
- top:
- t = xxreadtoken();
-
- if (checkkwd & CHKNL) {
- while (t == TNL) {
- readheredocs();
- t = xxreadtoken();
- }
- }
-
- /*
- * check for keywords and aliases
- */
- if (t == TWORD && !quoteflag) {
- const char *const *pp;
-
- if (checkkwd & CHKKWD)
- for (pp = parsekwd; *pp; pp++) {
- if (**pp == *wordtext && equal(*pp, wordtext)) {
- lasttoken = t = pp -
- parsekwd + KWDOFFSET;
- VTRACE(DBG_PARSE,
- ("keyword %s recognized @%d\n",
- tokname[t], plinno));
- goto out;
- }
- }
-
- if (checkkwd & CHKALIAS &&
- (ap = lookupalias(wordtext, 1)) != NULL) {
- VTRACE(DBG_PARSE,
- ("alias '%s' recognized -> <:%s:>\n",
- wordtext, ap->val));
- pushstring(ap->val, strlen(ap->val), ap);
- goto top;
- }
- }
- out:
- if (t != TNOT)
- checkkwd = 0;
-
- VTRACE(DBG_PARSE, ("%stoken %s %s @%d (chkkwd %x->%x)\n",
- alreadyseen ? "reread " : "", tokname[t],
- t == TWORD ? wordtext : "", plinno, savecheckkwd, checkkwd));
- return (t);
-}
-
-
-/*
- * Read the next input token.
- * If the token is a word, we set backquotelist to the list of cmds in
- * backquotes. We set quoteflag to true if any part of the word was
- * quoted.
- * If the token is TREDIR, then we set redirnode to a structure containing
- * the redirection.
- * In all cases, the variable startlinno is set to the number of the line
- * on which the token starts.
- *
- * [Change comment: here documents and internal procedures]
- * [Readtoken shouldn't have any arguments. Perhaps we should make the
- * word parsing code into a separate routine. In this case, readtoken
- * doesn't need to have any internal procedures, but parseword does.
- * We could also make parseoperator in essence the main routine, and
- * have parseword (readtoken1?) handle both words and redirection.]
- */
-
-#define RETURN(token) return lasttoken = (token)
-
-STATIC int
-xxreadtoken(void)
-{
- int c;
-
- if (tokpushback) {
- tokpushback = 0;
- CTRACE(DBG_LEXER,
- ("xxreadtoken() returns %s (%d) again\n",
- tokname[lasttoken], lasttoken));
- return lasttoken;
- }
- if (needprompt) {
- setprompt(2);
- needprompt = 0;
- }
- elided_nl = 0;
- startlinno = plinno;
- for (;;) { /* until token or start of word found */
- c = pgetc_macro();
- CTRACE(DBG_LEXER, ("xxreadtoken() sees '%c' (%#.2x) ",
- c&0xFF, c&0x1FF));
- switch (c) {
- case ' ': case '\t': case PFAKE:
- CTRACE(DBG_LEXER, (" ignored\n"));
- continue;
- case '#':
- while ((c = pgetc()) != '\n' && c != PEOF)
- continue;
- CTRACE(DBG_LEXER,
- ("skipped comment to (not incl) \\n\n"));
- pungetc();
- continue;
-
- case '\n':
- plinno++;
- CTRACE(DBG_LEXER, ("newline now @%d\n", plinno));
- needprompt = doprompt;
- RETURN(TNL);
- case PEOF:
- CTRACE(DBG_LEXER, ("EOF -> TEOF (return)\n"));
- RETURN(TEOF);
-
- case '&':
- if (pgetc_linecont() == '&') {
- CTRACE(DBG_LEXER,
- ("and another -> TAND (return)\n"));
- RETURN(TAND);
- }
- pungetc();
- CTRACE(DBG_LEXER, (" -> TBACKGND (return)\n"));
- RETURN(TBACKGND);
- case '|':
- if (pgetc_linecont() == '|') {
- CTRACE(DBG_LEXER,
- ("and another -> TOR (return)\n"));
- RETURN(TOR);
- }
- pungetc();
- CTRACE(DBG_LEXER, (" -> TPIPE (return)\n"));
- RETURN(TPIPE);
- case ';':
- switch (pgetc_linecont()) {
- case ';':
- CTRACE(DBG_LEXER,
- ("and another -> TENDCASE (return)\n"));
- RETURN(TENDCASE);
- case '&':
- CTRACE(DBG_LEXER,
- ("and '&' -> TCASEFALL (return)\n"));
- RETURN(TCASEFALL);
- default:
- pungetc();
- CTRACE(DBG_LEXER, (" -> TSEMI (return)\n"));
- RETURN(TSEMI);
- }
- case '(':
- CTRACE(DBG_LEXER, (" -> TLP (return)\n"));
- RETURN(TLP);
- case ')':
- CTRACE(DBG_LEXER, (" -> TRP (return)\n"));
- RETURN(TRP);
-
- case '\\':
- switch (pgetc()) {
- case '\n':
- startlinno = ++plinno;
- CTRACE(DBG_LEXER, ("\\\n ignored, now @%d\n",
- plinno));
- if (doprompt)
- setprompt(2);
- else
- setprompt(0);
- continue;
- case PEOF:
- CTRACE(DBG_LEXER,
- ("then EOF -> TEOF (return) '\\' dropped\n"));
- RETURN(TEOF);
- default:
- CTRACE(DBG_LEXER, ("not \\\n or EOF: "));
- pungetc();
- break;
- }
- /* FALLTHROUGH */
- default:
- CTRACE(DBG_LEXER, ("getting a word\n"));
- return readtoken1(c, BASESYNTAX, 0);
- }
- }
-#undef RETURN
-}
-
-
-
-/*
- * If eofmark is NULL, read a word or a redirection symbol. If eofmark
- * is not NULL, read a here document. In the latter case, eofmark is the
- * word which marks the end of the document and striptabs is true if
- * leading tabs should be stripped from the document. The argument firstc
- * is the first character of the input token or document.
- *
- * Because C does not have internal subroutines, I have simulated them
- * using goto's to implement the subroutine linkage. The following macros
- * will run code that appears at the end of readtoken1.
- */
-
-/*
- * We used to remember only the current syntax, variable nesting level,
- * double quote state for each var nesting level, and arith nesting
- * level (unrelated to var nesting) and one prev syntax when in arith
- * syntax. This worked for simple cases, but can't handle arith inside
- * var expansion inside arith inside var with some quoted and some not.
- *
- * Inspired by FreeBSD's implementation (though it was the obvious way)
- * though implemented differently, we now have a stack that keeps track
- * of what we are doing now, and what we were doing previously.
- * Every time something changes, which will eventually end and should
- * revert to the previous state, we push this stack, and then pop it
- * again later (that is every ${} with an operator (to parse the word
- * or pattern that follows) ${x} and $x are too simple to need it)
- * $(( )) $( ) and "...". Always. Really, always!
- *
- * The stack is implemented as one static (on the C stack) base block
- * containing LEVELS_PER_BLOCK (8) stack entries, which should be
- * enough for the vast majority of cases. For torture tests, we
- * malloc more blocks as needed. All accesses through the inline
- * functions below.
- */
-
-/*
- * varnest & arinest will typically be 0 or 1
- * (varnest can increment in usages like ${x=${y}} but probably
- * does not really need to)
- * parenlevel allows balancing parens inside a $(( )), it is reset
- * at each new nesting level ( $(( ( x + 3 ${unset-)} )) does not work.
- * quoted is special - we need to know 2 things ... are we inside "..."
- * (even if inherited from some previous nesting level) and was there
- * an opening '"' at this level (so the next will be closing).
- * "..." can span nesting levels, but cannot be opened in one and
- * closed in a different one.
- * To handle this, "quoted" has two fields, the bottom 4 (really 2)
- * bits are 0, 1, or 2, for un, single, and double quoted (single quoted
- * is really so special that this setting is not very important)
- * and 0x10 that indicates that an opening quote has been seen.
- * The bottom 4 bits are inherited, the 0x10 bit is not.
- */
-struct tokenstate {
- const char *ts_syntax;
- unsigned short ts_parenlevel; /* counters */
- unsigned short ts_varnest; /* 64000 levels should be enough! */
- unsigned short ts_arinest;
- unsigned short ts_quoted; /* 1 -> single, 2 -> double */
- unsigned short ts_magicq; /* heredoc or word expand */
-};
-
-#define NQ 0x00 /* Unquoted */
-#define SQ 0x01 /* Single Quotes */
-#define DQ 0x02 /* Double Quotes (or equivalent) */
-#define CQ 0x03 /* C style Single Quotes */
-#define QF 0x0F /* Mask to extract previous values */
-#define QS 0x10 /* Quoting started at this level in stack */
-
-#define LEVELS_PER_BLOCK 8
-#define VSS struct statestack
-
-struct statestack {
- VSS *prev; /* previous block in list */
- int cur; /* which of our tokenstates is current */
- struct tokenstate tokenstate[LEVELS_PER_BLOCK];
-};
-
-static inline struct tokenstate *
-currentstate(VSS *stack)
-{
- return &stack->tokenstate[stack->cur];
-}
-
-#ifdef notdef
-static inline struct tokenstate *
-prevstate(VSS *stack)
-{
- if (stack->cur != 0)
- return &stack->tokenstate[stack->cur - 1];
- if (stack->prev == NULL) /* cannot drop below base */
- return &stack->tokenstate[0];
- return &stack->prev->tokenstate[LEVELS_PER_BLOCK - 1];
-}
-#endif
-
-static inline VSS *
-bump_state_level(VSS *stack)
-{
- struct tokenstate *os, *ts;
-
- os = currentstate(stack);
-
- if (++stack->cur >= LEVELS_PER_BLOCK) {
- VSS *ss;
-
- ss = (VSS *)ckmalloc(sizeof (struct statestack));
- ss->cur = 0;
- ss->prev = stack;
- stack = ss;
- }
-
- ts = currentstate(stack);
-
- ts->ts_parenlevel = 0; /* parens inside never match outside */
-
- ts->ts_quoted = os->ts_quoted & QF; /* these are default settings */
- ts->ts_varnest = os->ts_varnest;
- ts->ts_arinest = os->ts_arinest; /* when appropriate */
- ts->ts_syntax = os->ts_syntax; /* they will be altered */
- ts->ts_magicq = os->ts_magicq;
-
- return stack;
-}
-
-static inline VSS *
-drop_state_level(VSS *stack)
-{
- if (stack->cur == 0) {
- VSS *ss;
-
- ss = stack;
- stack = ss->prev;
- if (stack == NULL)
- return ss;
- ckfree(ss);
- }
- --stack->cur;
- return stack;
-}
-
-static inline void
-cleanup_state_stack(VSS *stack)
-{
- while (stack->prev != NULL) {
- stack->cur = 0;
- stack = drop_state_level(stack);
- }
-}
-
-#define PARSESUB() {goto parsesub; parsesub_return:;}
-#define PARSEARITH() {goto parsearith; parsearith_return:;}
-
-/*
- * The following macros all assume the existance of a local var "stack"
- * which contains a pointer to the current struct stackstate
- */
-
-/*
- * These are macros rather than inline funcs to avoid code churn as much
- * as possible - they replace macros of the same name used previously.
- */
-#define ISDBLQUOTE() (currentstate(stack)->ts_quoted & QS)
-#define SETDBLQUOTE() (currentstate(stack)->ts_quoted = QS | DQ)
-#ifdef notdef
-#define CLRDBLQUOTE() (currentstate(stack)->ts_quoted = \
- stack->cur != 0 || stack->prev ? \
- prevstate(stack)->ts_quoted & QF : 0)
-#endif
-
-/*
- * This set are just to avoid excess typing and line lengths...
- * The ones that "look like" var names must be implemented to be lvalues
- */
-#define syntax (currentstate(stack)->ts_syntax)
-#define parenlevel (currentstate(stack)->ts_parenlevel)
-#define varnest (currentstate(stack)->ts_varnest)
-#define arinest (currentstate(stack)->ts_arinest)
-#define quoted (currentstate(stack)->ts_quoted)
-#define magicq (currentstate(stack)->ts_magicq)
-#define TS_PUSH() (stack = bump_state_level(stack))
-#define TS_POP() (stack = drop_state_level(stack))
-
-/*
- * Called to parse command substitutions. oldstyle is true if the command
- * is enclosed inside `` (otherwise it was enclosed in "$( )")
- *
- * Internally nlpp is a pointer to the head of the linked
- * list of commands (passed by reference), and savelen is the number of
- * characters on the top of the stack which must be preserved.
- */
-static char *
-parsebackq(VSS *const stack, char * const in,
- struct nodelist **const pbqlist, const int oldstyle)
-{
- struct nodelist **nlpp;
- const int savepbq = parsebackquote;
- union node *n;
- char *out;
- char *str = NULL;
- char *volatile sstr = str;
- struct jmploc jmploc;
- struct jmploc *const savehandler = handler;
- struct parsefile *const savetopfile = getcurrentfile();
- const int savelen = in - stackblock();
- int saveprompt;
- int lno;
-
- if (setjmp(jmploc.loc)) {
- popfilesupto(savetopfile);
- if (sstr)
- ckfree(__UNVOLATILE(sstr));
- cleanup_state_stack(stack);
- parsebackquote = 0;
- handler = savehandler;
- CTRACE(DBG_LEXER, ("parsebackq() err (%d), unwinding\n",
- exception));
- longjmp(handler->loc, 1);
- }
- INTOFF;
- sstr = str = NULL;
- if (savelen > 0) {
- sstr = str = ckmalloc(savelen);
- memcpy(str, stackblock(), savelen);
- }
- handler = &jmploc;
- INTON;
- if (oldstyle) {
- /*
- * We must read until the closing backquote, giving special
- * treatment to some slashes, and then push the string and
- * reread it as input, interpreting it normally.
- */
- int pc;
- int psavelen;
- char *pstr;
- int line1 = plinno;
-
- VTRACE(DBG_PARSE|DBG_LEXER,
- ("parsebackq: repackaging `` as $( )"));
- /*
- * Because the entire `...` is read here, we don't
- * need to bother the state stack. That will be used
- * (as appropriate) when the processed string is re-read.
- */
- STARTSTACKSTR(out);
-#ifdef DEBUG
- for (psavelen = 0;;psavelen++) { /* } */
-#else
- for (;;) {
-#endif
- if (needprompt) {
- setprompt(2);
- needprompt = 0;
- }
- pc = pgetc();
- VTRACE(DBG_LEXER,
- ("parsebackq() got '%c'(%#.2x) in `` %s", pc&0xFF,
- pc&0x1FF, pc == '`' ? "terminator\n" : ""));
- if (pc == '`')
- break;
- switch (pc) {
- case '\\':
- pc = pgetc();
- VTRACE(DBG_LEXER, ("then '%c'(%#.2x) ",
- pc&0xFF, pc&0x1FF));
-#ifdef DEBUG
- psavelen++;
-#endif
- if (pc == '\n') { /* keep \ \n for later */
- plinno++;
- VTRACE(DBG_LEXER, ("@%d ", plinno));
- needprompt = doprompt;
- }
- if (pc != '\\' && pc != '`' && pc != '$'
- && (!ISDBLQUOTE() || pc != '"')) {
- VTRACE(DBG_LEXER, ("keep '\\' "));
- STPUTC('\\', out);
- }
- break;
-
- case '\n':
- plinno++;
- VTRACE(DBG_LEXER, ("@%d ", plinno));
- needprompt = doprompt;
- break;
-
- case PEOF:
- startlinno = line1;
- VTRACE(DBG_LEXER, ("EOF\n", plinno));
- synerror("EOF in backquote substitution");
- break;
-
- default:
- break;
- }
- VTRACE(DBG_LEXER, (".\n", plinno));
- STPUTC(pc, out);
- }
- STPUTC('\0', out);
- VTRACE(DBG_LEXER, ("parsebackq() ``:"));
- VTRACE(DBG_PARSE|DBG_LEXER, (" read %d", psavelen));
- psavelen = out - stackblock();
- VTRACE(DBG_PARSE|DBG_LEXER, (" produced %d\n", psavelen));
- if (psavelen > 0) {
- pstr = grabstackstr(out);
- CTRACE(DBG_LEXER,
- ("parsebackq() reprocessing as $(%s)\n", pstr));
- setinputstring(pstr, 1, line1);
- }
- }
- nlpp = pbqlist;
- while (*nlpp)
- nlpp = &(*nlpp)->next;
- *nlpp = stalloc(sizeof(struct nodelist));
- (*nlpp)->next = NULL;
- parsebackquote = oldstyle;
-
- if (oldstyle) {
- saveprompt = doprompt;
- doprompt = 0;
- } else
- saveprompt = 0;
-
- lno = -plinno;
- CTRACE(DBG_LEXER, ("parsebackq() parsing embedded command list\n"));
- n = list(0);
- CTRACE(DBG_LEXER, ("parsebackq() parsed $() (%d -> %d)\n", -lno,
- lno + plinno));
- lno += plinno;
-
- if (oldstyle) {
- if (peektoken() != TEOF)
- synexpect(-1, 0);
- doprompt = saveprompt;
- } else
- consumetoken(TRP);
-
- (*nlpp)->n = n;
- if (oldstyle) {
- /*
- * Start reading from old file again, ignoring any pushed back
- * tokens left from the backquote parsing
- */
- CTRACE(DBG_LEXER, ("parsebackq() back to previous input\n"));
- popfile();
- tokpushback = 0;
- }
-
- while (stackblocksize() <= savelen)
- growstackblock();
- STARTSTACKSTR(out);
- if (str) {
- memcpy(out, str, savelen);
- STADJUST(savelen, out);
- INTOFF;
- ckfree(str);
- sstr = str = NULL;
- INTON;
- }
- parsebackquote = savepbq;
- handler = savehandler;
- if (arinest || ISDBLQUOTE()) {
- STPUTC(CTLBACKQ | CTLQUOTE, out);
- while (--lno >= 0)
- STPUTC(CTLNONL, out);
- } else
- STPUTC(CTLBACKQ, out);
-
- return out;
-}
-
-/*
- * Parse a redirection operator. The parameter "out" points to a string
- * specifying the fd to be redirected. It is guaranteed to be either ""
- * or a numeric string (for now anyway). The parameter "c" contains the
- * first character of the redirection operator.
- *
- * Note the string "out" is on the stack, which we are about to clobber,
- * so process it first...
- */
-
-static void
-parseredir(const char *out, int c)
-{
- union node *np;
- int fd;
-
- fd = (*out == '\0') ? -1 : number(out);
-
- np = stalloc(sizeof(struct nfile));
- VTRACE(DBG_LEXER, ("parseredir after '%s%c' ", out, c));
- if (c == '>') {
- if (fd < 0)
- fd = 1;
- c = pgetc_linecont();
- VTRACE(DBG_LEXER, ("is '%c'(%#.2x) ", c&0xFF, c&0x1FF));
- if (c == '>')
- np->type = NAPPEND;
- else if (c == '|')
- np->type = NCLOBBER;
- else if (c == '&')
- np->type = NTOFD;
- else {
- np->type = NTO;
- VTRACE(DBG_LEXER, ("unwanted ", c));
- pungetc();
- }
- } else { /* c == '<' */
- if (fd < 0)
- fd = 0;
- c = pgetc_linecont();
- VTRACE(DBG_LEXER, ("is '%c'(%#.2x) ", c&0xFF, c&0x1FF));
- switch (c) {
- case '<':
- /* if sizes differ, just discard the old one */
- if (sizeof (struct nfile) != sizeof (struct nhere))
- np = stalloc(sizeof(struct nhere));
- np->type = NHERE;
- np->nhere.fd = 0;
- heredoc = stalloc(sizeof(struct HereDoc));
- heredoc->here = np;
- heredoc->startline = plinno;
- if ((c = pgetc_linecont()) == '-') {
- CTRACE(DBG_LEXER, ("and '%c'(%#.2x) ",
- c & 0xFF, c & 0x1FF));
- heredoc->striptabs = 1;
- } else {
- heredoc->striptabs = 0;
- pungetc();
- }
- break;
-
- case '&':
- np->type = NFROMFD;
- break;
-
- case '>':
- np->type = NFROMTO;
- break;
-
- default:
- np->type = NFROM;
- VTRACE(DBG_LEXER, ("unwanted('%c'0#.2x)", c&0xFF,
- c&0x1FF));
- pungetc();
- break;
- }
- }
- np->nfile.fd = fd;
-
- VTRACE(DBG_LEXER, (" ->%"PRIdsNT" fd=%d\n", NODETYPENAME(np->type),fd));
-
- redirnode = np; /* this is the "value" of TRENODE */
-}
-
-/*
- * Called to parse a backslash escape sequence inside $'...'.
- * The backslash has already been read.
- */
-static char *
-readcstyleesc(char *out)
-{
- int c, vc, i, n;
- unsigned int v;
-
- c = pgetc();
- VTRACE(DBG_LEXER, ("CSTR(\\%c)(\\%#x)", c&0xFF, c&0x1FF));
- switch (c) {
- case '\0':
- case PEOF:
- synerror("Unterminated quoted string");
- case '\n':
- plinno++;
- VTRACE(DBG_LEXER, ("@%d ", plinno));
- if (doprompt)
- setprompt(2);
- else
- setprompt(0);
- return out;
-
- case '\\':
- case '\'':
- case '"':
- v = c;
- break;
-
- case 'a': v = '\a'; break;
- case 'b': v = '\b'; break;
- case 'e': v = '\033'; break;
- case 'f': v = '\f'; break;
- case 'n': v = '\n'; break;
- case 'r': v = '\r'; break;
- case 't': v = '\t'; break;
- case 'v': v = '\v'; break;
-
- case '0': case '1': case '2': case '3':
- case '4': case '5': case '6': case '7':
- v = c - '0';
- c = pgetc();
- if (c >= '0' && c <= '7') {
- v <<= 3;
- v += c - '0';
- c = pgetc();
- if (c >= '0' && c <= '7') {
- v <<= 3;
- v += c - '0';
- } else
- pungetc();
- } else
- pungetc();
- break;
-
- case 'c':
- c = pgetc();
- if (c < 0x3f || c > 0x7a || c == 0x60)
- synerror("Bad \\c escape sequence");
- if (c == '\\' && pgetc() != '\\')
- synerror("Bad \\c\\ escape sequence");
- if (c == '?')
- v = 127;
- else
- v = c & 0x1f;
- break;
-
- case 'x':
- n = 2;
- goto hexval;
- case 'u':
- n = 4;
- goto hexval;
- case 'U':
- n = 8;
- hexval:
- v = 0;
- for (i = 0; i < n; i++) {
- c = pgetc();
- if (c >= '0' && c <= '9')
- v = (v << 4) + c - '0';
- else if (c >= 'A' && c <= 'F')
- v = (v << 4) + c - 'A' + 10;
- else if (c >= 'a' && c <= 'f')
- v = (v << 4) + c - 'a' + 10;
- else {
- pungetc();
- break;
- }
- }
- if (n > 2 && v > 127) {
- if (v >= 0xd800 && v <= 0xdfff)
- synerror("Invalid \\u escape sequence");
-
- /* XXX should we use iconv here. What locale? */
- CHECKSTRSPACE(4, out);
-
- if (v <= 0x7ff) {
- USTPUTC(0xc0 | v >> 6, out);
- USTPUTC(0x80 | (v & 0x3f), out);
- return out;
- } else if (v <= 0xffff) {
- USTPUTC(0xe0 | v >> 12, out);
- USTPUTC(0x80 | ((v >> 6) & 0x3f), out);
- USTPUTC(0x80 | (v & 0x3f), out);
- return out;
- } else if (v <= 0x10ffff) {
- USTPUTC(0xf0 | v >> 18, out);
- USTPUTC(0x80 | ((v >> 12) & 0x3f), out);
- USTPUTC(0x80 | ((v >> 6) & 0x3f), out);
- USTPUTC(0x80 | (v & 0x3f), out);
- return out;
- }
- if (v > 127)
- v = '?';
- }
- break;
- default:
- synerror("Unknown $'' escape sequence");
- }
- vc = (char)v;
- VTRACE(DBG_LEXER, ("->%u(%#x)['%c']", v, v, vc&0xFF));
-
- /*
- * If we managed to create a \n from a \ sequence (no matter how)
- * then we replace it with the magic CRTCNL control char, which
- * will turn into a \n again later, but in the meantime, never
- * causes LINENO increments.
- */
- if (vc == '\n') {
- VTRACE(DBG_LEXER, ("CTLCNL."));
- USTPUTC(CTLCNL, out);
- return out;
- }
-
- /*
- * We can't handle NUL bytes.
- * POSIX says we should skip till the closing quote.
- */
- if (vc == '\0') {
- CTRACE(DBG_LEXER, ("\\0: skip to '", v, v, vc&0xFF));
- while ((c = pgetc()) != '\'') {
- if (c == '\\')
- c = pgetc();
- if (c == PEOF)
- synerror("Unterminated quoted string");
- if (c == '\n') {
- plinno++;
- if (doprompt)
- setprompt(2);
- else
- setprompt(0);
- }
- }
- pungetc();
- return out;
- }
- CVTRACE(DBG_LEXER, NEEDESC(vc), ("CTLESC-"));
- VTRACE(DBG_LEXER, ("'%c'(%#.2x)", vc&0xFF, vc&0x1FF));
- if (NEEDESC(vc))
- USTPUTC(CTLESC, out);
- USTPUTC(vc, out);
- return out;
-}
-
-/*
- * The lowest level basic tokenizer.
- *
- * The next input byte (character) is in firstc, syn says which
- * syntax tables we are to use (basic, single or double quoted, or arith)
- * and magicq (used with sqsyntax and dqsyntax only) indicates that the
- * quote character itself is not special (used parsing here docs and similar)
- *
- * The result is the type of the next token (its value, when there is one,
- * is saved in the relevant global var - must fix that someday!) which is
- * also saved for re-reading ("lasttoken").
- *
- * Overall, this routine does far more parsing than it is supposed to.
- * That will also need fixing, someday...
- */
-STATIC int
-readtoken1(int firstc, char const *syn, int oneword)
-{
- int c;
- char * out;
- int len;
- struct nodelist *bqlist;
- int quotef;
- VSS static_stack;
- VSS *stack = &static_stack;
-
- stack->prev = NULL;
- stack->cur = 0;
-
- syntax = syn;
-
-#ifdef DEBUG
-#define SYNTAX ( syntax == BASESYNTAX ? "BASE" : \
- syntax == DQSYNTAX ? "DQ" : \
- syntax == SQSYNTAX ? "SQ" : \
- syntax == ARISYNTAX ? "ARI" : \
- "???" )
-#endif
-
- startlinno = plinno;
- varnest = 0;
- quoted = 0;
- if (syntax == DQSYNTAX)
- SETDBLQUOTE();
- quotef = 0;
- bqlist = NULL;
- arinest = 0;
- parenlevel = 0;
- elided_nl = 0;
- magicq = oneword;
-
- CTRACE(DBG_LEXER, ("readtoken1(%c) syntax=%s %s%s(quoted=%x)\n",
- firstc&0xFF, SYNTAX, magicq ? "magic quotes" : "",
- ISDBLQUOTE()?" ISDBLQUOTE":"", quoted));
-
- STARTSTACKSTR(out);
-
- for (c = firstc ;; c = pgetc_macro()) { /* until of token */
- if (syntax == ARISYNTAX)
- out = insert_elided_nl(out);
- CHECKSTRSPACE(6, out); /* permit 6 calls to USTPUTC */
- switch (syntax[c]) {
- case CFAKE:
- VTRACE(DBG_LEXER, ("CFAKE"));
- if (syntax == BASESYNTAX && varnest == 0)
- break;
- VTRACE(DBG_LEXER, (","));
- continue;
- case CNL: /* '\n' */
- VTRACE(DBG_LEXER, ("CNL"));
- if (syntax == BASESYNTAX && varnest == 0)
- break; /* exit loop */
- USTPUTC(c, out);
- plinno++;
- VTRACE(DBG_LEXER, ("@%d,", plinno));
- if (doprompt)
- setprompt(2);
- else
- setprompt(0);
- continue;
-
- case CSBACK: /* single quoted backslash */
- if ((quoted & QF) == CQ) {
- out = readcstyleesc(out);
- continue;
- }
- VTRACE(DBG_LEXER, ("ESC:"));
- USTPUTC(CTLESC, out);
- /* FALLTHROUGH */
- case CWORD:
- VTRACE(DBG_LEXER, ("'%c'", c));
- USTPUTC(c, out);
- continue;
-
- case CCTL:
- CVTRACE(DBG_LEXER, !magicq || ISDBLQUOTE(),
- ("%s%sESC:",!magicq?"!m":"",ISDBLQUOTE()?"DQ":""));
- if (!magicq || ISDBLQUOTE())
- USTPUTC(CTLESC, out);
- VTRACE(DBG_LEXER, ("'%c'", c));
- USTPUTC(c, out);
- continue;
- case CBACK: /* backslash */
- c = pgetc();
- VTRACE(DBG_LEXER, ("\\'%c'(%#.2x)", c&0xFF, c&0x1FF));
- if (c == PEOF) {
- VTRACE(DBG_LEXER, ("EOF, keep \\ "));
- USTPUTC('\\', out);
- pungetc();
- continue;
- }
- if (c == '\n') {
- plinno++;
- elided_nl++;
- VTRACE(DBG_LEXER, ("eli \\n (%d) @%d ",
- elided_nl, plinno));
- if (doprompt)
- setprompt(2);
- else
- setprompt(0);
- continue;
- }
- CVTRACE(DBG_LEXER, quotef==0, (" QF=1 "));
- quotef = 1; /* current token is quoted */
- if (quoted && c != '\\' && c != '`' &&
- c != '$' && (c != '"' || magicq)) {
- /*
- * retain the \ (which we *know* needs CTLESC)
- * when in "..." and the following char is
- * not one of the magic few.)
- * Otherwise the \ has done its work, and
- * is dropped.
- */
- VTRACE(DBG_LEXER, ("ESC:'\\'"));
- USTPUTC(CTLESC, out);
- USTPUTC('\\', out);
- }
- CVTRACE(DBG_LEXER, NEEDESC(c) || !magicq,
- ("%sESC:", NEEDESC(c) ? "+" : "m"));
- VTRACE(DBG_LEXER, ("'%c'(%#.2x)", c&0xFF, c&0x1FF));
- if (NEEDESC(c))
- USTPUTC(CTLESC, out);
- else if (!magicq) {
- USTPUTC(CTLESC, out);
- USTPUTC(c, out);
- continue;
- }
- USTPUTC(c, out);
- continue;
- case CSQUOTE:
- if (syntax != SQSYNTAX) {
- CVTRACE(DBG_LEXER, !magicq, (" CQM "));
- if (!magicq)
- USTPUTC(CTLQUOTEMARK, out);
- CVTRACE(DBG_LEXER, quotef==0, (" QF=1 "));
- quotef = 1;
- TS_PUSH();
- syntax = SQSYNTAX;
- quoted = SQ;
- VTRACE(DBG_LEXER, (" TS_PUSH(SQ)"));
- continue;
- }
- if (magicq && arinest == 0 && varnest == 0) {
- /* Ignore inside quoted here document */
- VTRACE(DBG_LEXER, ("<<'>>"));
- USTPUTC(c, out);
- continue;
- }
- /* End of single quotes... */
- TS_POP();
- VTRACE(DBG_LEXER, ("SQ TS_POP->%s ", SYNTAX));
- CVTRACE(DBG_LEXER, syntax == BASESYNTAX, (" CQE "));
- if (syntax == BASESYNTAX)
- USTPUTC(CTLQUOTEEND, out);
- continue;
- case CDQUOTE:
- if (magicq && arinest == 0 /* && varnest == 0 */) {
- VTRACE(DBG_LEXER, ("<<\">>"));
- /* Ignore inside here document */
- USTPUTC(c, out);
- continue;
- }
- CVTRACE(DBG_LEXER, quotef==0, (" QF=1 "));
- quotef = 1;
- if (arinest) {
- if (ISDBLQUOTE()) {
- VTRACE(DBG_LEXER,
- (" CQE ari(%d", arinest));
- USTPUTC(CTLQUOTEEND, out);
- TS_POP();
- VTRACE(DBG_LEXER, ("%d)TS_POP->%s ",
- arinest, SYNTAX));
- } else {
- VTRACE(DBG_LEXER,
- (" ari(%d) %s TS_PUSH->DQ CQM ",
- arinest, SYNTAX));
- TS_PUSH();
- syntax = DQSYNTAX;
- SETDBLQUOTE();
- USTPUTC(CTLQUOTEMARK, out);
- }
- continue;
- }
- CVTRACE(DBG_LEXER, magicq, (" MQignDQ "));
- if (magicq)
- continue;
- if (ISDBLQUOTE()) {
- TS_POP();
- VTRACE(DBG_LEXER,
- (" DQ TS_POP->%s CQE ", SYNTAX));
- USTPUTC(CTLQUOTEEND, out);
- } else {
- VTRACE(DBG_LEXER,
- (" %s TS_POP->DQ CQM ", SYNTAX));
- TS_PUSH();
- syntax = DQSYNTAX;
- SETDBLQUOTE();
- USTPUTC(CTLQUOTEMARK, out);
- }
- continue;
- case CVAR: /* '$' */
- VTRACE(DBG_LEXER, ("'$'..."));
- out = insert_elided_nl(out);
- PARSESUB(); /* parse substitution */
- continue;
- case CENDVAR: /* CLOSEBRACE */
- if (varnest > 0 && !ISDBLQUOTE()) {
- VTRACE(DBG_LEXER, ("vn=%d !DQ", varnest));
- TS_POP();
- VTRACE(DBG_LEXER, (" TS_POP->%s CEV ", SYNTAX));
- USTPUTC(CTLENDVAR, out);
- } else {
- VTRACE(DBG_LEXER, ("'%c'", c));
- USTPUTC(c, out);
- }
- out = insert_elided_nl(out);
- continue;
- case CLP: /* '(' in arithmetic */
- parenlevel++;
- VTRACE(DBG_LEXER, ("'('(%d)", parenlevel));
- USTPUTC(c, out);
- continue;;
- case CRP: /* ')' in arithmetic */
- if (parenlevel > 0) {
- USTPUTC(c, out);
- --parenlevel;
- VTRACE(DBG_LEXER, ("')'(%d)", parenlevel));
- } else {
- VTRACE(DBG_LEXER, ("')'(%d)", parenlevel));
- if (pgetc_linecont() == /*(*/ ')') {
- out = insert_elided_nl(out);
- if (--arinest == 0) {
- TS_POP();
- USTPUTC(CTLENDARI, out);
- } else
- USTPUTC(/*(*/ ')', out);
- } else {
- break; /* to synerror() just below */
-#if 0 /* the old way, causes weird errors on bad input */
- /*
- * unbalanced parens
- * (don't 2nd guess - no error)
- */
- pungetc();
- USTPUTC(/*(*/ ')', out);
-#endif
- }
- }
- continue;
- case CBQUOTE: /* '`' */
- VTRACE(DBG_LEXER, ("'`' -> parsebackq()\n"));
- out = parsebackq(stack, out, &bqlist, 1);
- VTRACE(DBG_LEXER, ("parsebackq() -> readtoken1: "));
- continue;
- case CEOF: /* --> c == PEOF */
- VTRACE(DBG_LEXER, ("EOF "));
- break; /* will exit loop */
- default:
- VTRACE(DBG_LEXER, ("['%c'(%#.2x)]", c&0xFF, c&0x1FF));
- if (varnest == 0 && !ISDBLQUOTE())
- break; /* exit loop */
- USTPUTC(c, out);
- VTRACE(DBG_LEXER, (","));
- continue;
- }
- VTRACE(DBG_LEXER, (" END TOKEN\n", c&0xFF, c&0x1FF));
- break; /* break from switch -> break from for loop too */
- }
-
- if (syntax == ARISYNTAX) {
- cleanup_state_stack(stack);
- synerror(/*((*/ "Missing '))'");
- }
- if (syntax != BASESYNTAX && /* ! parsebackquote && */ !magicq) {
- cleanup_state_stack(stack);
- synerror("Unterminated quoted string");
- }
- if (varnest != 0) {
- cleanup_state_stack(stack);
- startlinno = plinno;
- /* { */
- synerror("Missing '}'");
- }
-
- STPUTC('\0', out);
- len = out - stackblock();
- out = stackblock();
-
- if (!magicq) {
- if ((c == '<' || c == '>')
- && quotef == 0 && (*out == '\0' || is_number(out))) {
- parseredir(out, c);
- cleanup_state_stack(stack);
- return lasttoken = TREDIR;
- } else {
- pungetc();
- }
- }
-
- VTRACE(DBG_PARSE|DBG_LEXER,
- ("readtoken1 %sword \"%s\", completed%s (%d) left %d enl\n",
- (quotef ? "quoted " : ""), out, (bqlist ? " with cmdsubs" : ""),
- len, elided_nl));
-
- quoteflag = quotef;
- backquotelist = bqlist;
- grabstackblock(len);
- wordtext = out;
- cleanup_state_stack(stack);
- return lasttoken = TWORD;
-/* end of readtoken routine */
-
-
-/*
- * Parse a substitution. At this point, we have read the dollar sign
- * and nothing else.
- */
-
-parsesub: {
- int subtype;
- int typeloc;
- int flags;
- char *p;
- static const char types[] = "}-+?=";
-
- c = pgetc_linecont();
- VTRACE(DBG_LEXER, ("\"$%c\"(%#.2x)", c&0xFF, c&0x1FF));
- if (c == '(' /*)*/) { /* $(command) or $((arith)) */
- if (pgetc_linecont() == '(' /*')'*/ ) {
- VTRACE(DBG_LEXER, ("\"$((\" ARITH "));
- out = insert_elided_nl(out);
- PARSEARITH();
- } else {
- VTRACE(DBG_LEXER, ("\"$(\" CSUB->parsebackq()\n"));
- out = insert_elided_nl(out);
- pungetc();
- out = parsebackq(stack, out, &bqlist, 0);
- VTRACE(DBG_LEXER, ("parseback()->readtoken1(): "));
- }
- } else if (c == OPENBRACE || is_name(c) || is_special(c)) {
- VTRACE(DBG_LEXER, (" $EXP:CTLVAR "));
- USTPUTC(CTLVAR, out);
- typeloc = out - stackblock();
- USTPUTC(VSNORMAL, out);
- subtype = VSNORMAL;
- flags = 0;
- if (c == OPENBRACE) {
- c = pgetc_linecont();
- if (c == '#') {
- if ((c = pgetc_linecont()) == CLOSEBRACE)
- c = '#';
- else if (is_name(c) || isdigit(c))
- subtype = VSLENGTH;
- else if (is_special(c)) {
- /*
- * ${#} is $# - the number of sh params
- * ${##} is the length of ${#}
- * ${###} is ${#} with as much nothing
- * as possible removed from start
- * ${##1} is ${#} with leading 1 gone
- * ${##\#} is ${#} with leading # gone
- *
- * this stuff is UGLY!
- */
- if (pgetc_linecont() == CLOSEBRACE) {
- pungetc();
- subtype = VSLENGTH;
- } else {
- static char cbuf[2];
-
- pungetc(); /* would like 2 */
- cbuf[0] = c; /* so ... */
- cbuf[1] = '\0';
- pushstring(cbuf, 1, NULL);
- c = '#'; /* ${#:...} */
- subtype = 0; /* .. or similar */
- }
- } else {
- pungetc();
- c = '#';
- subtype = 0;
- }
- }
- else
- subtype = 0;
- VTRACE(DBG_LEXER, ("${ st=%d ", subtype));
- }
- if (is_name(c)) {
- p = out;
- do {
- VTRACE(DBG_LEXER, ("%c", c));
- STPUTC(c, out);
- c = pgetc_linecont();
- } while (is_in_name(c));
-
-#if 0
- if (out - p == 6 && strncmp(p, "LINENO", 6) == 0) {
- int i;
- int linno;
- char buf[10];
-
- /*
- * The "LINENO hack"
- *
- * Replace the variable name with the
- * current line number.
- */
- linno = plinno;
- if (funclinno != 0)
- linno -= funclinno - 1;
- snprintf(buf, sizeof(buf), "%d", linno);
- STADJUST(-6, out);
- for (i = 0; buf[i] != '\0'; i++)
- STPUTC(buf[i], out);
- flags |= VSLINENO;
- }
-#endif
- } else if (is_digit(c)) {
- do {
- VTRACE(DBG_LEXER, ("%c", c));
- STPUTC(c, out);
- c = pgetc_linecont();
- } while (subtype != VSNORMAL && is_digit(c));
- }
- else if (is_special(c)) {
- VTRACE(DBG_LEXER, ("\"$%c", c));
- USTPUTC(c, out);
- c = pgetc_linecont();
- }
- else {
- VTRACE(DBG_LEXER, ("\"$%c(%#.2x)??\n", c&0xFF,c&0x1FF));
- badsub:
- cleanup_state_stack(stack);
- synerror("Bad substitution");
- }
-
- STPUTC('=', out);
- if (subtype == 0) {
- switch (c) {
- case ':':
- flags |= VSNUL;
- c = pgetc_linecont();
- /*FALLTHROUGH*/
- default:
- p = strchr(types, c);
- if (p == NULL)
- goto badsub;
- subtype = p - types + VSNORMAL;
- break;
- case '%':
- case '#':
- {
- int cc = c;
- subtype = c == '#' ? VSTRIMLEFT :
- VSTRIMRIGHT;
- c = pgetc_linecont();
- if (c == cc)
- subtype++;
- else
- pungetc();
- break;
- }
- }
- } else {
- if (subtype == VSLENGTH && c != /*{*/ '}')
- synerror("no modifiers allowed with ${#var}");
- pungetc();
- }
- if (quoted || arinest)
- flags |= VSQUOTE;
- if (subtype >= VSTRIMLEFT && subtype <= VSTRIMRIGHTMAX)
- flags |= VSPATQ;
- VTRACE(DBG_LEXER, (" st%d:%x", subtype, flags));
- *(stackblock() + typeloc) = subtype | flags;
- if (subtype != VSNORMAL) {
- TS_PUSH();
- varnest++;
- arinest = 0;
- if (subtype > VSASSIGN) { /* # ## % %% */
- syntax = BASESYNTAX;
- quoted = 0;
- magicq = 0;
- }
- VTRACE(DBG_LEXER, (" TS_PUSH->%s vn=%d%s ",
- SYNTAX, varnest, quoted ? " Q" : ""));
- }
- } else if (c == '\'' && syntax == BASESYNTAX) {
- USTPUTC(CTLQUOTEMARK, out);
- VTRACE(DBG_LEXER, (" CSTR \"$'\" CQM "));
- CVTRACE(DBG_LEXER, quotef==0, ("QF=1 "));
- quotef = 1;
- TS_PUSH();
- syntax = SQSYNTAX;
- quoted = CQ;
- VTRACE(DBG_LEXER, ("%s->TS_PUSH()->SQ ", SYNTAX));
- } else {
- VTRACE(DBG_LEXER, ("$unk -> '$' (pushback '%c'%#.2x)",
- c & 0xFF, c & 0x1FF));
- USTPUTC('$', out);
- pungetc();
- }
- goto parsesub_return;
-}
-
-
-/*
- * Parse an arithmetic expansion (indicate start of one and set state)
- */
-parsearith: {
-
-#if 0
- if (syntax == ARISYNTAX) {
- /*
- * we collapse embedded arithmetic expansion to
- * parentheses, which should be equivalent
- *
- * XXX It isn't, must fix, soonish...
- */
- USTPUTC('(' /*)*/, out);
- USTPUTC('(' /*)*/, out);
- /*
- * Need 2 of them because there will (should be)
- * two closing ))'s to follow later.
- */
- parenlevel += 2;
- } else
-#endif
- {
- VTRACE(DBG_LEXER, (" CTLARI%c ", ISDBLQUOTE()?'"':'_'));
- USTPUTC(CTLARI, out);
- if (ISDBLQUOTE())
- USTPUTC('"',out);
- else
- USTPUTC(' ',out);
-
- VTRACE(DBG_LEXER, ("%s->TS_PUSH->ARI(1)", SYNTAX));
- TS_PUSH();
- syntax = ARISYNTAX;
- arinest = 1;
- varnest = 0;
- magicq = 1;
- }
- goto parsearith_return;
-}
-
-} /* end of readtoken */
-
-
-
-
-#ifdef mkinit
-INCLUDE "parser.h"
-
-RESET {
- psp.v_current_parser = &parse_state;
-
- parse_state.ps_tokpushback = 0;
- parse_state.ps_checkkwd = 0;
- parse_state.ps_heredoclist = NULL;
-}
-#endif
-
-/*
- * Returns true if the text contains nothing to expand (no dollar signs
- * or backquotes).
- */
-
-STATIC int
-noexpand(char *text)
-{
- char *p;
- char c;
-
- p = text;
- while ((c = *p++) != '\0') {
- if (c == CTLQUOTEMARK || c == CTLQUOTEEND)
- continue;
- if (c == CTLESC)
- p++;
- else if (BASESYNTAX[(int)c] == CCTL)
- return 0;
- }
- return 1;
-}
-
-
-/*
- * Return true if the argument is a legal variable name (a letter or
- * underscore followed by zero or more letters, underscores, and digits).
- */
-
-int
-goodname(const char *name)
-{
- const char *p;
-
- p = name;
- if (! is_name(*p))
- return 0;
- while (*++p) {
- if (! is_in_name(*p))
- return 0;
- }
- return 1;
-}
-
-int
-isassignment(const char *p)
-{
- if (!is_name(*p))
- return 0;
- while (*++p != '=')
- if (*p == '\0' || !is_in_name(*p))
- return 0;
- return 1;
-}
-
-/*
- * skip past any \n's, and leave lasttoken set to whatever follows
- */
-STATIC void
-linebreak(void)
-{
- while (readtoken() == TNL)
- ;
-}
-
-/*
- * The next token must be "token" -- check, then move past it
- */
-STATIC void
-consumetoken(int token)
-{
- if (readtoken() != token) {
- VTRACE(DBG_PARSE, ("consumetoken(%d): expecting %s got %s",
- token, tokname[token], tokname[lasttoken]));
- CVTRACE(DBG_PARSE, (lasttoken==TWORD), (" \"%s\"", wordtext));
- VTRACE(DBG_PARSE, ("\n"));
- synexpect(token, NULL);
- }
-}
-
-/*
- * Called when an unexpected token is read during the parse. The argument
- * is the token that is expected, or -1 if more than one type of token can
- * occur at this point.
- */
-
-STATIC void
-synexpect(int token, const char *text)
-{
- char msg[64];
- char *p;
-
- if (lasttoken == TWORD) {
- size_t len = strlen(wordtext);
-
- if (len <= 13)
- fmtstr(msg, 34, "Word \"%.13s\" unexpected", wordtext);
- else
- fmtstr(msg, 34,
- "Word \"%.10s...\" unexpected", wordtext);
- } else
- fmtstr(msg, 34, "%s unexpected", tokname[lasttoken]);
-
- p = strchr(msg, '\0');
- if (text)
- fmtstr(p, 30, " (expecting \"%.10s\")", text);
- else if (token >= 0)
- fmtstr(p, 30, " (expecting %s)", tokname[token]);
-
- synerror(msg);
- /* NOTREACHED */
-}
-
-
-STATIC void
-synerror(const char *msg)
-{
- error("%d: Syntax error: %s", startlinno, msg);
- /* NOTREACHED */
-}
-
-STATIC void
-setprompt(int which)
-{
- whichprompt = which;
-
-#ifndef SMALL
- if (!el)
-#endif
- out2str(getprompt(NULL));
-}
-
-/*
- * handle getting the next character, while ignoring \ \n
- * (which is a little tricky as we only have one char of pushback
- * and we need that one elsewhere).
- */
-STATIC int
-pgetc_linecont(void)
-{
- int c;
-
- while ((c = pgetc()) == '\\') {
- c = pgetc();
- if (c == '\n') {
- plinno++;
- elided_nl++;
- VTRACE(DBG_LEXER, ("\"\\n\"drop(el=%d@%d)",
- elided_nl, plinno));
- if (doprompt)
- setprompt(2);
- else
- setprompt(0);
- } else {
- pungetc();
- /* Allow the backslash to be pushed back. */
- pushstring("\\", 1, NULL);
- return (pgetc());
- }
- }
- return (c);
-}
-
-/*
- * called by editline -- any expansions to the prompt
- * should be added here.
- */
-const char *
-getprompt(void *unused)
-{
- char *p;
- const char *cp;
- int wp;
-
- if (!doprompt)
- return "";
-
- VTRACE(DBG_PARSE|DBG_EXPAND, ("getprompt %d\n", whichprompt));
-
- switch (wp = whichprompt) {
- case 0:
- return "";
- case 1:
- p = ps1val();
- break;
- case 2:
- p = ps2val();
- break;
- default:
- return "<internal prompt error>";
- }
- if (p == NULL)
- return "";
-
- VTRACE(DBG_PARSE|DBG_EXPAND, ("prompt <<%s>>\n", p));
-
- cp = expandstr(p, plinno);
- whichprompt = wp; /* history depends on it not changing */
-
- VTRACE(DBG_PARSE|DBG_EXPAND, ("prompt -> <<%s>>\n", cp));
-
- return cp;
-}
-
-/*
- * Expand a string ... used for expanding prompts (PS1...)
- *
- * Never return NULL, always some string (return input string if invalid)
- *
- * The internal routine does the work, leaving the result on the
- * stack (or in a static string, or even the input string) and
- * handles parser recursion, and cleanup after an error while parsing.
- *
- * The visible interface copies the result off the stack (if it is there),
- * and handles stack management, leaving the stack in the exact same
- * state it was when expandstr() was called (so it can be used part way
- * through building a stack data structure - as in when PS2 is being
- * expanded half way through reading a "command line")
- *
- * on error, expandonstack() cleans up the parser state, but then
- * simply jumps out through expandstr() withut doing any stack cleanup,
- * which is OK, as the error handler must deal with that anyway.
- *
- * The split into two funcs is to avoid problems with setjmp/longjmp
- * and local variables which could otherwise be optimised into bizarre
- * behaviour.
- */
-static const char *
-expandonstack(char *ps, int cmdsub, int lineno)
-{
- union node n;
- struct jmploc jmploc;
- struct jmploc *const savehandler = handler;
- struct parsefile *const savetopfile = getcurrentfile();
- const int save_x = xflag;
- struct parse_state new_state = init_parse_state;
- struct parse_state *const saveparser = psp.v_current_parser;
- const char *result = NULL;
-
- if (!setjmp(jmploc.loc)) {
- handler = &jmploc;
-
- psp.v_current_parser = &new_state;
- setinputstring(ps, 1, lineno);
-
- readtoken1(pgetc(), DQSYNTAX, 1);
- if (backquotelist != NULL) {
- if (!cmdsub)
- result = ps;
- else if (!promptcmds)
- result = "-o promptcmds not set: ";
- }
- if (result == NULL) {
- n.narg.type = NARG;
- n.narg.next = NULL;
- n.narg.text = wordtext;
- n.narg.lineno = lineno;
- n.narg.backquote = backquotelist;
-
- xflag = 0; /* we might be expanding PS4 ... */
- expandarg(&n, NULL, 0);
- result = stackblock();
- }
- } else {
- psp.v_current_parser = saveparser;
- xflag = save_x;
- popfilesupto(savetopfile);
- handler = savehandler;
-
- if (exception == EXEXIT)
- longjmp(handler->loc, 1);
- if (exception == EXINT)
- exraise(SIGINT);
- return ps;
- }
- psp.v_current_parser = saveparser;
- xflag = save_x;
- popfilesupto(savetopfile);
- handler = savehandler;
-
-
- if (result == NULL)
- result = ps;
-
- return result;
-}
-
-const char *
-expandstr(char *ps, int lineno)
-{
- const char *result = NULL;
- struct stackmark smark;
- static char *buffer = NULL; /* storage for prompt, never freed */
- static size_t bufferlen = 0;
-
- setstackmark(&smark);
- /*
- * At this point we anticipate that there may be a string
- * growing on the stack, but we have no idea how big it is.
- * However we know that it cannot be bigger than the current
- * allocated stack block, so simply reserve the whole thing,
- * then we can use the stack without barfing all over what
- * is there already... (the stack mark undoes this later.)
- */
- (void) stalloc(stackblocksize());
-
- result = expandonstack(ps, 1, lineno);
-
- if (__predict_true(result == stackblock())) {
- size_t len = strlen(result) + 1;
-
- /*
- * the result (usual case) is on the stack, which we
- * are just about to discard (popstackmark()) so we
- * need to move it somewhere safe first.
- */
-
- if (__predict_false(len > bufferlen)) {
- char *new;
- size_t newlen = bufferlen;
-
- if (__predict_false(len > (SIZE_MAX >> 4))) {
- result = "huge prompt: ";
- goto getout;
- }
-
- if (newlen == 0)
- newlen = 32;
- while (newlen <= len)
- newlen <<= 1;
-
- new = (char *)realloc(buffer, newlen);
-
- if (__predict_false(new == NULL)) {
- /*
- * this should rarely (if ever) happen
- * but we must do something when it does...
- */
- result = "No mem for prompt: ";
- goto getout;
- } else {
- buffer = new;
- bufferlen = newlen;
- }
- }
- (void)memcpy(buffer, result, len);
- result = buffer;
- }
-
- getout:;
- popstackmark(&smark);
-
- return result;
-}
-
-/*
- * and a simpler version, which does no $( ) expansions, for
- * use during shell startup when we know we are not parsing,
- * and so the stack is not in use - we can do what we like,
- * and do not need to clean up (that's handled externally).
- *
- * Simply return the result, even if it is on the stack
- */
-const char *
-expandenv(char *arg)
-{
- return expandonstack(arg, 0, 0);
-}
diff --git a/bin/sh/parser.h b/bin/sh/parser.h
deleted file mode 100644
index 7545b4f..0000000
--- a/bin/sh/parser.h
+++ /dev/null
@@ -1,169 +0,0 @@
-/* $NetBSD: parser.h,v 1.27 2018/12/11 13:31:20 kre Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- *
- * @(#)parser.h 8.3 (Berkeley) 5/4/95
- */
-
-/* control characters in argument strings */
-#define CTL_FIRST '\201' /* first 'special' character */
-#define CTLESC '\201' /* escape next character */
-#define CTLVAR '\202' /* variable defn */
-#define CTLENDVAR '\203'
-#define CTLBACKQ '\204'
-#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
-/* CTLBACKQ | CTLQUOTE == '\205' */
-#define CTLARI '\206' /* arithmetic expression */
-#define CTLENDARI '\207'
-#define CTLQUOTEMARK '\210'
-#define CTLQUOTEEND '\211' /* only inside ${...} */
-#define CTLNONL '\212' /* The \n in a deleted \ \n sequence */
- /* pure concidence that (CTLNONL & 0x7f) == '\n' */
-#define CTLCNL '\213' /* A $'\n' - newline not counted */
-#define CTL_LAST '\213' /* last 'special' character */
-
-/* variable substitution byte (follows CTLVAR) */
-#define VSTYPE 0x0f /* type of variable substitution */
-#define VSNUL 0x10 /* colon--treat the empty string as unset */
-#define VSLINENO 0x20 /* expansion of $LINENO, the line number
- follows immediately */
-#define VSPATQ 0x40 /* ensure correct pattern quoting in ${x#pat} */
-#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
-
-/* values of VSTYPE field */
-#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
-#define VSMINUS 0x2 /* ${var-text} */
-#define VSPLUS 0x3 /* ${var+text} */
-#define VSQUESTION 0x4 /* ${var?message} */
-#define VSASSIGN 0x5 /* ${var=text} */
-#define VSTRIMLEFT 0x6 /* ${var#pattern} */
-#define VSTRIMLEFTMAX 0x7 /* ${var##pattern} */
-#define VSTRIMRIGHT 0x8 /* ${var%pattern} */
-#define VSTRIMRIGHTMAX 0x9 /* ${var%%pattern} */
-#define VSLENGTH 0xa /* ${#var} */
-
-union node *parsecmd(int);
-void fixredir(union node *, const char *, int);
-int goodname(const char *);
-int isassignment(const char *);
-const char *getprompt(void *);
-const char *expandstr(char *, int);
-const char *expandenv(char *);
-
-struct HereDoc;
-union node;
-struct nodelist;
-
-struct parse_state {
- struct HereDoc *ps_heredoclist; /* list of here documents to read */
- int ps_parsebackquote; /* nonzero inside backquotes */
- int ps_doprompt; /* if set, prompt the user */
- int ps_needprompt; /* true if interactive at line start */
- int ps_lasttoken; /* last token read */
- int ps_tokpushback; /* last token pushed back */
- char *ps_wordtext; /* text of last word returned by readtoken */
- int ps_checkkwd; /* word expansion flags, see below */
- struct nodelist *ps_backquotelist; /* list of cmdsubs to process */
- union node *ps_redirnode; /* node for current redirect */
- struct HereDoc *ps_heredoc; /* current heredoc << beign parsed */
- int ps_quoteflag; /* set if (part) of token was quoted */
- int ps_startlinno; /* line # where last token started */
- int ps_funclinno; /* line # of the current function */
- int ps_elided_nl; /* count of \ \n pairs we have seen */
-};
-
-/*
- * The parser references the elements of struct parse_state quite
- * frequently - they used to be simple globals, so one memory ref
- * per access, adding an indirect through global ptr would not be
- * nice. The following gross hack allows most of that cost to be
- * avoided, by allowing the compiler to understand that the global
- * pointer is in fact constant in any function, and so its value can
- * be cached, rather than needing to be fetched every time in case
- * some other called function has changed it.
- *
- * The rule to make this work is that any function that wants
- * to alter the global must restore it before it returns (and thus
- * must have an error trap handler). That means that the struct
- * used for the new parser state can be a local in that function's
- * stack frame, it never needs to be malloc'd.
- */
-
-union parse_state_p {
- struct parse_state *const c_current_parser;
- struct parse_state * v_current_parser;
-};
-
-extern union parse_state_p psp;
-
-#define current_parser (psp.c_current_parser)
-
-/*
- * Perhaps one day emulate "static" by moving most of these definitions into
- * parser.c ... (only checkkwd & tokpushback are used outside parser.c,
- * and only in init.c as a RESET activity)
- */
-#define tokpushback (current_parser->ps_tokpushback)
-#define checkkwd (current_parser->ps_checkkwd)
-
-#define noalias (current_parser->ps_noalias)
-#define heredoclist (current_parser->ps_heredoclist)
-#define parsebackquote (current_parser->ps_parsebackquote)
-#define doprompt (current_parser->ps_doprompt)
-#define needprompt (current_parser->ps_needprompt)
-#define lasttoken (current_parser->ps_lasttoken)
-#define wordtext (current_parser->ps_wordtext)
-#define backquotelist (current_parser->ps_backquotelist)
-#define redirnode (current_parser->ps_redirnode)
-#define heredoc (current_parser->ps_heredoc)
-#define quoteflag (current_parser->ps_quoteflag)
-#define startlinno (current_parser->ps_startlinno)
-#define funclinno (current_parser->ps_funclinno)
-#define elided_nl (current_parser->ps_elided_nl)
-
-/*
- * Values that can be set in checkkwd
- */
-#define CHKKWD 0x01 /* turn word into keyword (if it is) */
-#define CHKNL 0x02 /* ignore leading \n's */
-#define CHKALIAS 0x04 /* lookup words as aliases and ... */
-
-/*
- * NEOF is returned by parsecmd when it encounters an end of file. It
- * must be distinct from NULL, so we use the address of a variable that
- * happens to be handy.
- */
-#define NEOF ((union node *)&psp)
-
-#ifdef DEBUG
-extern int parsing;
-#endif
diff --git a/bin/sh/redir.c b/bin/sh/redir.c
deleted file mode 100644
index 751cce7..0000000
--- a/bin/sh/redir.c
+++ /dev/null
@@ -1,982 +0,0 @@
-/* $NetBSD: redir.c,v 1.62 2018/11/26 20:03:39 kamil Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- */
-
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)redir.c 8.2 (Berkeley) 5/4/95";
-#else
-__RCSID("$NetBSD: redir.c,v 1.62 2018/11/26 20:03:39 kamil Exp $");
-#endif
-#endif /* not lint */
-
-#include <sys/types.h>
-#include <sys/param.h> /* PIPE_BUF */
-#include <sys/stat.h>
-#include <signal.h>
-#include <string.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-
-/*
- * Code for dealing with input/output redirection.
- */
-
-#include "main.h"
-#include "builtins.h"
-#include "shell.h"
-#include "nodes.h"
-#include "jobs.h"
-#include "options.h"
-#include "expand.h"
-#include "redir.h"
-#include "output.h"
-#include "memalloc.h"
-#include "mystring.h"
-#include "error.h"
-#include "show.h"
-
-
-#define EMPTY -2 /* marks an unused slot in redirtab */
-#define CLOSED -1 /* fd was not open before redir */
-#ifndef PIPE_BUF
-# define PIPESIZE 4096 /* amount of buffering in a pipe */
-#else
-# define PIPESIZE PIPE_BUF
-#endif
-
-
-MKINIT
-struct renamelist {
- struct renamelist *next;
- int orig;
- int into;
-};
-
-MKINIT
-struct redirtab {
- struct redirtab *next;
- struct renamelist *renamed;
-};
-
-
-MKINIT struct redirtab *redirlist;
-
-/*
- * We keep track of whether or not fd0 has been redirected. This is for
- * background commands, where we want to redirect fd0 to /dev/null only
- * if it hasn't already been redirected.
- */
-STATIC int fd0_redirected = 0;
-
-/*
- * And also where to put internal use fds that should be out of the
- * way of user defined fds (normally)
- */
-STATIC int big_sh_fd = 0;
-
-STATIC const struct renamelist *is_renamed(const struct renamelist *, int);
-STATIC void fd_rename(struct redirtab *, int, int);
-STATIC void free_rl(struct redirtab *, int);
-STATIC void openredirect(union node *, char[10], int);
-STATIC int openhere(const union node *);
-STATIC int copyfd(int, int, int);
-STATIC void find_big_fd(void);
-
-
-struct shell_fds { /* keep track of internal shell fds */
- struct shell_fds *nxt;
- void (*cb)(int, int);
- int fd;
-};
-
-STATIC struct shell_fds *sh_fd_list;
-
-STATIC void renumber_sh_fd(struct shell_fds *);
-STATIC struct shell_fds *sh_fd(int);
-
-STATIC const struct renamelist *
-is_renamed(const struct renamelist *rl, int fd)
-{
- while (rl != NULL) {
- if (rl->orig == fd)
- return rl;
- rl = rl->next;
- }
- return NULL;
-}
-
-STATIC void
-free_rl(struct redirtab *rt, int reset)
-{
- struct renamelist *rl, *rn = rt->renamed;
-
- while ((rl = rn) != NULL) {
- rn = rl->next;
- if (rl->orig == 0)
- fd0_redirected--;
- VTRACE(DBG_REDIR, ("popredir %d%s: %s",
- rl->orig, rl->orig==0 ? " (STDIN)" : "",
- reset ? "" : "no reset\n"));
- if (reset) {
- if (rl->into < 0) {
- VTRACE(DBG_REDIR, ("closed\n"));
- close(rl->orig);
- } else {
- VTRACE(DBG_REDIR, ("from %d\n", rl->into));
- movefd(rl->into, rl->orig);
- }
- }
- ckfree(rl);
- }
- rt->renamed = NULL;
-}
-
-STATIC void
-fd_rename(struct redirtab *rt, int from, int to)
-{
- /* XXX someday keep a short list (8..10) of freed renamelists XXX */
- struct renamelist *rl = ckmalloc(sizeof(struct renamelist));
-
- rl->next = rt->renamed;
- rt->renamed = rl;
-
- rl->orig = from;
- rl->into = to;
-}
-
-/*
- * Process a list of redirection commands. If the REDIR_PUSH flag is set,
- * old file descriptors are stashed away so that the redirection can be
- * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
- * standard output, and the standard error if it becomes a duplicate of
- * stdout, is saved in memory.
- */
-
-void
-redirect(union node *redir, int flags)
-{
- union node *n;
- struct redirtab *sv = NULL;
- int i;
- int fd;
- char memory[10]; /* file descriptors to write to memory */
-
- CTRACE(DBG_REDIR, ("redirect(F=0x%x):%s\n", flags, redir?"":" NONE"));
- for (i = 10 ; --i >= 0 ; )
- memory[i] = 0;
- memory[1] = flags & REDIR_BACKQ;
- if (flags & REDIR_PUSH) {
- /*
- * We don't have to worry about REDIR_VFORK here, as
- * flags & REDIR_PUSH is never true if REDIR_VFORK is set.
- */
- sv = ckmalloc(sizeof (struct redirtab));
- sv->renamed = NULL;
- sv->next = redirlist;
- redirlist = sv;
- }
- for (n = redir ; n ; n = n->nfile.next) {
- fd = n->nfile.fd;
- VTRACE(DBG_REDIR, ("redir %d (max=%d) ", fd, max_user_fd));
- if (fd > max_user_fd)
- max_user_fd = fd;
- renumber_sh_fd(sh_fd(fd));
- if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
- n->ndup.dupfd == fd) {
- /* redirect from/to same file descriptor */
- /* make sure it stays open */
- if (fcntl(fd, F_SETFD, 0) < 0)
- error("fd %d: %s", fd, strerror(errno));
- VTRACE(DBG_REDIR, ("!cloexec\n"));
- continue;
- }
-
- if ((flags & REDIR_PUSH) && !is_renamed(sv->renamed, fd)) {
- INTOFF;
- if (big_sh_fd < 10)
- find_big_fd();
- if ((i = fcntl(fd, F_DUPFD, big_sh_fd)) == -1) {
- switch (errno) {
- case EBADF:
- i = CLOSED;
- break;
- case EMFILE:
- case EINVAL:
- find_big_fd();
- i = fcntl(fd, F_DUPFD, big_sh_fd);
- if (i >= 0)
- break;
- /* FALLTHRU */
- default:
- i = errno;
- INTON; /* XXX not needed here ? */
- error("%d: %s", fd, strerror(i));
- /* NOTREACHED */
- }
- }
- if (i >= 0)
- (void)fcntl(i, F_SETFD, FD_CLOEXEC);
- fd_rename(sv, fd, i);
- VTRACE(DBG_REDIR, ("saved as %d ", i));
- INTON;
- }
- VTRACE(DBG_REDIR, ("%s\n", fd == 0 ? "STDIN" : ""));
- if (fd == 0)
- fd0_redirected++;
- openredirect(n, memory, flags);
- }
- if (memory[1])
- out1 = &memout;
- if (memory[2])
- out2 = &memout;
-}
-
-
-STATIC void
-openredirect(union node *redir, char memory[10], int flags)
-{
- struct stat sb;
- int fd = redir->nfile.fd;
- char *fname;
- int f;
- int eflags, cloexec;
-
- /*
- * We suppress interrupts so that we won't leave open file
- * descriptors around. This may not be such a good idea because
- * an open of a device or a fifo can block indefinitely.
- */
- INTOFF;
- if (fd < 10)
- memory[fd] = 0;
- switch (redir->nfile.type) {
- case NFROM:
- fname = redir->nfile.expfname;
- if (flags & REDIR_VFORK)
- eflags = O_NONBLOCK;
- else
- eflags = 0;
- if ((f = open(fname, O_RDONLY|eflags)) < 0)
- goto eopen;
- VTRACE(DBG_REDIR, ("openredirect(< '%s') -> %d [%#x]",
- fname, f, eflags));
- if (eflags)
- (void)fcntl(f, F_SETFL, fcntl(f, F_GETFL, 0) & ~eflags);
- break;
- case NFROMTO:
- fname = redir->nfile.expfname;
- if ((f = open(fname, O_RDWR|O_CREAT, 0666)) < 0)
- goto ecreate;
- VTRACE(DBG_REDIR, ("openredirect(<> '%s') -> %d", fname, f));
- break;
- case NTO:
- if (Cflag) {
- fname = redir->nfile.expfname;
- if ((f = open(fname, O_WRONLY)) == -1) {
- if ((f = open(fname, O_WRONLY|O_CREAT|O_EXCL,
- 0666)) < 0)
- goto ecreate;
- } else if (fstat(f, &sb) == -1) {
- int serrno = errno;
- close(f);
- errno = serrno;
- goto ecreate;
- } else if (S_ISREG(sb.st_mode)) {
- close(f);
- errno = EEXIST;
- goto ecreate;
- }
- VTRACE(DBG_REDIR, ("openredirect(>| '%s') -> %d",
- fname, f));
- break;
- }
- /* FALLTHROUGH */
- case NCLOBBER:
- fname = redir->nfile.expfname;
- if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
- goto ecreate;
- VTRACE(DBG_REDIR, ("openredirect(> '%s') -> %d", fname, f));
- break;
- case NAPPEND:
- fname = redir->nfile.expfname;
- if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
- goto ecreate;
- VTRACE(DBG_REDIR, ("openredirect(>> '%s') -> %d", fname, f));
- break;
- case NTOFD:
- case NFROMFD:
- if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
- if (fd < 10 && redir->ndup.dupfd < 10 &&
- memory[redir->ndup.dupfd])
- memory[fd] = 1;
- else if (copyfd(redir->ndup.dupfd, fd,
- (flags & REDIR_KEEP) == 0) < 0)
- error("Redirect (from %d to %d) failed: %s",
- redir->ndup.dupfd, fd, strerror(errno));
- VTRACE(DBG_REDIR, ("openredirect: %d%c&%d\n", fd,
- "<>"[redir->nfile.type==NTOFD], redir->ndup.dupfd));
- } else {
- (void) close(fd);
- VTRACE(DBG_REDIR, ("openredirect: %d%c&-\n", fd,
- "<>"[redir->nfile.type==NTOFD]));
- }
- INTON;
- return;
- case NHERE:
- case NXHERE:
- VTRACE(DBG_REDIR, ("openredirect: %d<<...", fd));
- f = openhere(redir);
- break;
- default:
- abort();
- }
-
- cloexec = fd > 2 && (flags & REDIR_KEEP) == 0 && !posix;
- if (f != fd) {
- VTRACE(DBG_REDIR, (" -> %d", fd));
- if (copyfd(f, fd, cloexec) < 0) {
- int e = errno;
-
- close(f);
- error("redirect reassignment (fd %d) failed: %s", fd,
- strerror(e));
- }
- close(f);
- } else if (cloexec)
- (void)fcntl(f, F_SETFD, FD_CLOEXEC);
- VTRACE(DBG_REDIR, ("%s\n", cloexec ? " cloexec" : ""));
-
- INTON;
- return;
- ecreate:
- exerrno = 1;
- error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
- eopen:
- exerrno = 1;
- error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
-}
-
-
-/*
- * Handle here documents. Normally we fork off a process to write the
- * data to a pipe. If the document is short, we can stuff the data in
- * the pipe without forking.
- */
-
-STATIC int
-openhere(const union node *redir)
-{
- int pip[2];
- int len = 0;
-
- if (pipe(pip) < 0)
- error("Pipe call failed");
- if (redir->type == NHERE) {
- len = strlen(redir->nhere.doc->narg.text);
- if (len <= PIPESIZE) {
- xwrite(pip[1], redir->nhere.doc->narg.text, len);
- goto out;
- }
- }
- VTRACE(DBG_REDIR, (" forking [%d,%d]\n", pip[0], pip[1]));
- if (forkshell(NULL, NULL, FORK_NOJOB) == 0) {
- close(pip[0]);
- signal(SIGINT, SIG_IGN);
- signal(SIGQUIT, SIG_IGN);
- signal(SIGHUP, SIG_IGN);
-#ifdef SIGTSTP
- signal(SIGTSTP, SIG_IGN);
-#endif
- signal(SIGPIPE, SIG_DFL);
- if (redir->type == NHERE)
- xwrite(pip[1], redir->nhere.doc->narg.text, len);
- else
- expandhere(redir->nhere.doc, pip[1]);
- _exit(0);
- }
- VTRACE(DBG_REDIR, ("openhere (closing %d)", pip[1]));
- out:
- close(pip[1]);
- VTRACE(DBG_REDIR, (" (pipe fd=%d)", pip[0]));
- return pip[0];
-}
-
-
-
-/*
- * Undo the effects of the last redirection.
- */
-
-void
-popredir(void)
-{
- struct redirtab *rp = redirlist;
-
- INTOFF;
- free_rl(rp, 1);
- redirlist = rp->next;
- ckfree(rp);
- INTON;
-}
-
-/*
- * Undo all redirections. Called on error or interrupt.
- */
-
-#ifdef mkinit
-
-INCLUDE "redir.h"
-
-RESET {
- while (redirlist)
- popredir();
-}
-
-SHELLPROC {
- clearredir(0);
-}
-
-#endif
-
-/* Return true if fd 0 has already been redirected at least once. */
-int
-fd0_redirected_p(void)
-{
- return fd0_redirected != 0;
-}
-
-/*
- * Discard all saved file descriptors.
- */
-
-void
-clearredir(int vforked)
-{
- struct redirtab *rp;
- struct renamelist *rl;
-
- for (rp = redirlist ; rp ; rp = rp->next) {
- if (!vforked)
- free_rl(rp, 0);
- else for (rl = rp->renamed; rl; rl = rl->next)
- if (rl->into >= 0)
- close(rl->into);
- }
-}
-
-
-
-/*
- * Copy a file descriptor to be == to.
- * cloexec indicates if we want close-on-exec or not.
- * Returns -1 if any error occurs.
- */
-
-STATIC int
-copyfd(int from, int to, int cloexec)
-{
- int newfd;
-
- if (cloexec && to > 2)
- newfd = dup3(from, to, O_CLOEXEC);
- else
- newfd = dup2(from, to);
-
- return newfd;
-}
-
-/*
- * rename fd from to be fd to (closing from).
- * close-on-exec is never set on 'to' (unless
- * from==to and it was set on from) - ie: a no-op
- * returns to (or errors() if an error occurs).
- *
- * This is mostly used for rearranging the
- * results from pipe().
- */
-int
-movefd(int from, int to)
-{
- if (from == to)
- return to;
-
- (void) close(to);
- if (copyfd(from, to, 0) != to) {
- int e = errno;
-
- (void) close(from);
- error("Unable to make fd %d: %s", to, strerror(e));
- }
- (void) close(from);
-
- return to;
-}
-
-STATIC void
-find_big_fd(void)
-{
- int i, fd;
- static int last_start = 3; /* aim to keep sh fd's under 20 */
-
- if (last_start < 10)
- last_start++;
-
- for (i = (1 << last_start); i >= 10; i >>= 1) {
- if ((fd = fcntl(0, F_DUPFD, i - 1)) >= 0) {
- close(fd);
- break;
- }
- }
-
- fd = (i / 5) * 4;
- if (fd < 10)
- fd = 10;
-
- big_sh_fd = fd;
-}
-
-/*
- * If possible, move file descriptor fd out of the way
- * of expected user fd values. Returns the new fd
- * (which may be the input fd if things do not go well.)
- * Always set close-on-exec on the result, and close
- * the input fd unless it is to be our result.
- */
-int
-to_upper_fd(int fd)
-{
- int i;
-
- VTRACE(DBG_REDIR|DBG_OUTPUT, ("to_upper_fd(%d)", fd));
- if (big_sh_fd < 10)
- find_big_fd();
- do {
- i = fcntl(fd, F_DUPFD_CLOEXEC, big_sh_fd);
- if (i >= 0) {
- if (fd != i)
- close(fd);
- VTRACE(DBG_REDIR|DBG_OUTPUT, ("-> %d\n", i));
- return i;
- }
- if (errno != EMFILE && errno != EINVAL)
- break;
- find_big_fd();
- } while (big_sh_fd > 10);
-
- /*
- * If we wanted to move this fd to some random high number
- * we certainly do not intend to pass it through exec, even
- * if the reassignment failed.
- */
- (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
- VTRACE(DBG_REDIR|DBG_OUTPUT, (" fails ->%d\n", fd));
- return fd;
-}
-
-void
-register_sh_fd(int fd, void (*cb)(int, int))
-{
- struct shell_fds *fp;
-
- fp = ckmalloc(sizeof (struct shell_fds));
- if (fp != NULL) {
- fp->nxt = sh_fd_list;
- sh_fd_list = fp;
-
- fp->fd = fd;
- fp->cb = cb;
- }
-}
-
-void
-sh_close(int fd)
-{
- struct shell_fds **fpp, *fp;
-
- fpp = &sh_fd_list;
- while ((fp = *fpp) != NULL) {
- if (fp->fd == fd) {
- *fpp = fp->nxt;
- ckfree(fp);
- break;
- }
- fpp = &fp->nxt;
- }
- (void)close(fd);
-}
-
-STATIC struct shell_fds *
-sh_fd(int fd)
-{
- struct shell_fds *fp;
-
- for (fp = sh_fd_list; fp != NULL; fp = fp->nxt)
- if (fp->fd == fd)
- return fp;
- return NULL;
-}
-
-STATIC void
-renumber_sh_fd(struct shell_fds *fp)
-{
- int to;
-
- if (fp == NULL)
- return;
-
-#ifndef F_DUPFD_CLOEXEC
-#define F_DUPFD_CLOEXEC F_DUPFD
-#define CLOEXEC(fd) (fcntl((fd), F_SETFD, fcntl((fd),F_GETFD) | FD_CLOEXEC))
-#else
-#define CLOEXEC(fd)
-#endif
-
- /*
- * if we have had a collision, and the sh fd was a "big" one
- * try moving the sh fd base to a higher number (if possible)
- * so future sh fds are less likely to be in the user's sights
- * (incl this one when moved)
- */
- if (fp->fd >= big_sh_fd)
- find_big_fd();
-
- to = fcntl(fp->fd, F_DUPFD_CLOEXEC, big_sh_fd);
- if (to == -1)
- to = fcntl(fp->fd, F_DUPFD_CLOEXEC, big_sh_fd/2);
- if (to == -1)
- to = fcntl(fp->fd, F_DUPFD_CLOEXEC, fp->fd + 1);
- if (to == -1)
- to = fcntl(fp->fd, F_DUPFD_CLOEXEC, 10);
- if (to == -1)
- to = fcntl(fp->fd, F_DUPFD_CLOEXEC, 3);
- if (to == -1)
- error("insufficient file descriptors available");
- CLOEXEC(to);
-
- if (fp->fd == to) /* impossible? */
- return;
-
- (*fp->cb)(fp->fd, to);
- (void)close(fp->fd);
- fp->fd = to;
-}
-
-static const struct flgnames {
- const char *name;
- uint16_t minch;
- uint32_t value;
-} nv[] = {
-#ifdef O_APPEND
- { "append", 2, O_APPEND },
-#endif
-#ifdef O_ASYNC
- { "async", 2, O_ASYNC },
-#endif
-#ifdef O_SYNC
- { "sync", 2, O_SYNC },
-#endif
-#ifdef O_NONBLOCK
- { "nonblock", 3, O_NONBLOCK },
-#endif
-#ifdef O_FSYNC
- { "fsync", 2, O_FSYNC },
-#endif
-#ifdef O_DSYNC
- { "dsync", 2, O_DSYNC },
-#endif
-#ifdef O_RSYNC
- { "rsync", 2, O_RSYNC },
-#endif
-#ifdef O_ALT_IO
- { "altio", 2, O_ALT_IO },
-#endif
-#ifdef O_DIRECT
- { "direct", 2, O_DIRECT },
-#endif
-#ifdef O_NOSIGPIPE
- { "nosigpipe", 3, O_NOSIGPIPE },
-#endif
-#ifdef O_CLOEXEC
- { "cloexec", 2, O_CLOEXEC },
-#endif
- { 0, 0, 0 }
-};
-#define ALLFLAGS (O_APPEND|O_ASYNC|O_SYNC|O_NONBLOCK|O_DSYNC|O_RSYNC|\
- O_ALT_IO|O_DIRECT|O_NOSIGPIPE|O_CLOEXEC)
-
-static int
-getflags(int fd, int p)
-{
- int c, f;
-
- if (sh_fd(fd) != NULL) {
- if (!p)
- return -1;
- error("Can't get status for fd=%d (%s)", fd,
- "Bad file descriptor"); /*XXX*/
- }
-
- if ((c = fcntl(fd, F_GETFD)) == -1) {
- if (!p)
- return -1;
- error("Can't get status for fd=%d (%s)", fd, strerror(errno));
- }
- if ((f = fcntl(fd, F_GETFL)) == -1) {
- if (!p)
- return -1;
- error("Can't get flags for fd=%d (%s)", fd, strerror(errno));
- }
- if (c & FD_CLOEXEC)
- f |= O_CLOEXEC;
- return f & ALLFLAGS;
-}
-
-static void
-printone(int fd, int p, int verbose, int pfd)
-{
- int f = getflags(fd, p);
- const struct flgnames *fn;
-
- if (f == -1)
- return;
-
- if (pfd)
- outfmt(out1, "%d: ", fd);
- for (fn = nv; fn->name; fn++) {
- if (f & fn->value) {
- outfmt(out1, "%s%s", verbose ? "+" : "", fn->name);
- f &= ~fn->value;
- } else if (verbose)
- outfmt(out1, "-%s", fn->name);
- else
- continue;
- if (f || (verbose && fn[1].name))
- outfmt(out1, ",");
- }
- if (verbose && f) /* f should be normally be 0 */
- outfmt(out1, " +%#x", f);
- outfmt(out1, "\n");
-}
-
-static void
-parseflags(char *s, int *p, int *n)
-{
- int *v, *w;
- const struct flgnames *fn;
- size_t len;
-
- *p = 0;
- *n = 0;
- for (s = strtok(s, ","); s; s = strtok(NULL, ",")) {
- switch (*s++) {
- case '+':
- v = p;
- w = n;
- break;
- case '-':
- v = n;
- w = p;
- break;
- default:
- error("Missing +/- indicator before flag %s", s-1);
- }
-
- len = strlen(s);
- for (fn = nv; fn->name; fn++)
- if (len >= fn->minch && strncmp(s,fn->name,len) == 0) {
- *v |= fn->value;
- *w &=~ fn->value;
- break;
- }
- if (fn->name == 0)
- error("Bad flag `%s'", s);
- }
-}
-
-static void
-setone(int fd, int pos, int neg, int verbose)
-{
- int f = getflags(fd, 1);
- int n, cloexec;
-
- if (f == -1)
- return;
-
- cloexec = -1;
- if ((pos & O_CLOEXEC) && !(f & O_CLOEXEC))
- cloexec = FD_CLOEXEC;
- if ((neg & O_CLOEXEC) && (f & O_CLOEXEC))
- cloexec = 0;
-
- if (cloexec != -1 && fcntl(fd, F_SETFD, cloexec) == -1)
- error("Can't set status for fd=%d (%s)", fd, strerror(errno));
-
- pos &= ~O_CLOEXEC;
- neg &= ~O_CLOEXEC;
- f &= ~O_CLOEXEC;
- n = f;
- n |= pos;
- n &= ~neg;
- if (n != f && fcntl(fd, F_SETFL, n) == -1)
- error("Can't set flags for fd=%d (%s)", fd, strerror(errno));
- if (verbose)
- printone(fd, 1, verbose, 1);
-}
-
-int
-fdflagscmd(int argc, char *argv[])
-{
- char *num;
- int verbose = 0, ch, pos = 0, neg = 0;
- char *setflags = NULL;
-
- optreset = 1; optind = 1; /* initialize getopt */
- while ((ch = getopt(argc, argv, ":vs:")) != -1)
- switch ((char)ch) {
- case 'v':
- verbose = 1;
- break;
- case 's':
- if (setflags)
- goto msg;
- setflags = optarg;
- break;
- case '?':
- default:
- msg:
- error("Usage: fdflags [-v] [-s <flags> fd] [fd...]");
- /* NOTREACHED */
- }
-
- argc -= optind, argv += optind;
-
- if (setflags)
- parseflags(setflags, &pos, &neg);
-
- if (argc == 0) {
- int i;
-
- if (setflags)
- goto msg;
-
- for (i = 0; i <= max_user_fd; i++)
- printone(i, 0, verbose, 1);
- return 0;
- }
-
- while ((num = *argv++) != NULL) {
- int fd = number(num);
-
- while (num[0] == '0' && num[1] != '\0') /* skip 0's */
- num++;
- if (strlen(num) > 5)
- error("%s too big to be a file descriptor", num);
-
- if (setflags)
- setone(fd, pos, neg, verbose);
- else
- printone(fd, 1, verbose, argc > 1);
- }
- return 0;
-}
-
-#undef MAX /* in case we inherited them from somewhere */
-#undef MIN
-
-#define MIN(a,b) (/*CONSTCOND*/((a)<=(b)) ? (a) : (b))
-#define MAX(a,b) (/*CONSTCOND*/((a)>=(b)) ? (a) : (b))
-
- /* now make the compiler work for us... */
-#define MIN_REDIR MIN(MIN(MIN(MIN(NTO,NFROM), MIN(NTOFD,NFROMFD)), \
- MIN(MIN(NCLOBBER,NAPPEND), MIN(NHERE,NXHERE))), NFROMTO)
-#define MAX_REDIR MAX(MAX(MAX(MAX(NTO,NFROM), MAX(NTOFD,NFROMFD)), \
- MAX(MAX(NCLOBBER,NAPPEND), MAX(NHERE,NXHERE))), NFROMTO)
-
-static const char *redir_sym[MAX_REDIR - MIN_REDIR + 1] = {
- [NTO - MIN_REDIR]= ">",
- [NFROM - MIN_REDIR]= "<",
- [NTOFD - MIN_REDIR]= ">&",
- [NFROMFD - MIN_REDIR]= "<&",
- [NCLOBBER - MIN_REDIR]= ">|",
- [NAPPEND - MIN_REDIR]= ">>",
- [NHERE - MIN_REDIR]= "<<",
- [NXHERE - MIN_REDIR]= "<<",
- [NFROMTO - MIN_REDIR]= "<>",
-};
-
-int
-outredir(struct output *out, union node *n, int sep)
-{
- if (n == NULL)
- return 0;
- if (n->type < MIN_REDIR || n->type > MAX_REDIR ||
- redir_sym[n->type - MIN_REDIR] == NULL)
- return 0;
-
- if (sep)
- outc(sep, out);
-
- /*
- * ugly, but all redir node types have "fd" in same slot...
- * (and code other places assumes it as well)
- */
- if ((redir_sym[n->type - MIN_REDIR][0] == '<' && n->nfile.fd != 0) ||
- (redir_sym[n->type - MIN_REDIR][0] == '>' && n->nfile.fd != 1))
- outfmt(out, "%d", n->nfile.fd);
-
- outstr(redir_sym[n->type - MIN_REDIR], out);
-
- switch (n->type) {
- case NHERE:
- outstr("'...'", out);
- break;
- case NXHERE:
- outstr("...", out);
- break;
- case NTOFD:
- case NFROMFD:
- if (n->ndup.dupfd < 0)
- outc('-', out);
- else
- outfmt(out, "%d", n->ndup.dupfd);
- break;
- default:
- outstr(n->nfile.expfname, out);
- break;
- }
- return 1;
-}
diff --git a/bin/sh/redir.h b/bin/sh/redir.h
deleted file mode 100644
index b186bb4..0000000
--- a/bin/sh/redir.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/* $NetBSD: redir.h,v 1.24 2017/06/30 23:01:21 kre Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- *
- * @(#)redir.h 8.2 (Berkeley) 5/4/95
- */
-
-/* flags passed to redirect */
-#define REDIR_PUSH 0x01 /* save previous values of file descriptors */
-#define REDIR_BACKQ 0x02 /* save the command output in memory */
-#define REDIR_VFORK 0x04 /* running under vfork(2), be careful */
-#define REDIR_KEEP 0x08 /* don't close-on-exec */
-
-union node;
-void redirect(union node *, int);
-void popredir(void);
-int fd0_redirected_p(void);
-void clearredir(int);
-int movefd(int, int);
-int to_upper_fd(int);
-void register_sh_fd(int, void (*)(int, int));
-void sh_close(int);
-struct output;
-int outredir(struct output *, union node *, int);
-
-int max_user_fd; /* highest fd used by user */
diff --git a/bin/sh/sh.1 b/bin/sh/sh.1
deleted file mode 100644
index 4630689..0000000
--- a/bin/sh/sh.1
+++ /dev/null
@@ -1,4549 +0,0 @@
-.\" $NetBSD: sh.1,v 1.217 2019/01/21 14:09:24 kre Exp $
-.\" Copyright (c) 1991, 1993
-.\" The Regents of the University of California. All rights reserved.
-.\"
-.\" This code is derived from software contributed to Berkeley by
-.\" Kenneth Almquist.
-.\"
-.\" 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.
-.\"
-.\" @(#)sh.1 8.6 (Berkeley) 5/4/95
-.\"
-.Dd December 12, 2018
-.Dt SH 1
-.\" everything except c o and s (keep them ordered)
-.ds flags abCEeFfhIiLmnpquVvXx
-.Os
-.Sh NAME
-.Nm sh
-.Nd command interpreter (shell)
-.Sh SYNOPSIS
-.Nm
-.Bk -words
-.Op Fl \*[flags]
-.Op Cm +\*[flags]
-.Ek
-.Bk -words
-.Op Fl o Ar option_name
-.Op Cm +o Ar option_name
-.Ek
-.Bk -words
-.Op Ar command_file Op Ar argument ...
-.Ek
-.Nm
-.Fl c
-.Bk -words
-.Op Fl s
-.Op Fl \*[flags]
-.Op Cm +\*[flags]
-.Ek
-.Bk -words
-.Op Fl o Ar option_name
-.Op Cm +o Ar option_name
-.Ek
-.Bk -words
-.Ar command_string
-.Op Ar command_name Op Ar argument ...
-.Ek
-.Nm
-.Fl s
-.Bk -words
-.Op Fl \*[flags]
-.Op Cm +\*[flags]
-.Ek
-.Bk -words
-.Op Fl o Ar option_name
-.Op Cm +o Ar option_name
-.Ek
-.Bk -words
-.Op Ar argument ...
-.Ek
-.Sh DESCRIPTION
-.Nm
-is the standard command interpreter for the system.
-The current version of
-.Nm
-is in the process of being changed to conform more closely to the
-POSIX 1003.2 and 1003.2a specifications for the shell.
-This version has many
-features which make it appear similar in some respects to the Korn shell,
-but it is not a Korn shell clone (see
-.Xr ksh 1 ) .
-This man page is not intended
-to be a tutorial or a complete specification of the shell.
-.Ss Overview
-The shell is a command that reads lines from either a file or the
-terminal, interprets them, and generally executes other commands.
-A shell is the program that is running when a user logs into the system.
-(Users can select which shell is executed for them at login with the
-.Xr chsh 1
-command).
-The shell implements a language that has flow control
-constructs, a macro facility that provides a variety of features in
-addition to data storage, along with built in history and line editing
-capabilities.
-It incorporates many features to aid interactive use and
-has the advantage that the interpretative language is common to both
-interactive and non-interactive use (shell scripts).
-That is, commands
-can be typed directly to the running shell or can be put into a file and
-the file can be executed directly by the shell.
-.Ss Invocation
-If no arguments are present and if the standard input,
-and standard error output, of the shell
-are connected to a terminal (or terminals, or if the
-.Fl i
-flag is set),
-and the
-.Fl c
-option is not present, the shell is considered an interactive shell.
-An interactive shell generally prompts before each command and handles
-programming and command errors differently (as described below).
-When first starting,
-the shell inspects argument 0, and if it begins with a dash
-.Sq - ,
-the shell is also considered
-a login shell.
-This is normally done automatically by the system
-when the user first logs in.
-A login shell first reads commands
-from the files
-.Pa /etc/profile
-and
-.Pa .profile
-in the user's home directory
-.Pq \&$HOME ,
-if they exist.
-If the environment variable
-.Ev ENV
-is set on entry to a shell,
-or is set in the
-.Pa .profile
-of a login shell,
-and either the shell is interactive, or the
-.Cm posix
-option is not set,
-the shell then performs parameter and arithmetic
-expansion on the value of
-.Ev ENV ,
-(these are described later)
-and then reads commands from the file name that results.
-If
-.Ev ENV
-contains a command substitution, or one of the
-other expansions fails, or if there are no expansions
-to expand, the value of
-.Ev ENV
-is used as the file name.
-.Pp
-Therefore, a user should place commands that are to be executed only at
-login time in the
-.Pa .profile
-file, and commands that are executed for every shell inside the
-.Ev ENV
-file.
-To set the
-.Ev ENV
-variable to some file, place the following line in your
-.Pa .profile
-of your home directory
-.Pp
-.Dl ENV=$HOME/.shinit; export ENV
-.Pp
-substituting for
-.Dq .shinit
-any filename you wish.
-Since the
-.Ev ENV
-file can be read for every invocation of the shell, including shell scripts
-and non-interactive shells, the following paradigm is useful for
-restricting commands in the
-.Ev ENV
-file to interactive invocations.
-Place commands within the
-.Dq Ic case
-and
-.Dq Ic esac
-below (these commands are described later):
-.Bd -literal -offset indent
-case $- in *i*)
- # commands for interactive use only
- ...
-esac
-.Ed
-.Pp
-If command line arguments besides the options have been specified, and
-neither
-.Fl c
-nor
-.Fl s
-was given, then the shell treats the first argument
-as the name of a file from which to read commands (a shell script).
-This also becomes
-.Li $0
-and the remaining arguments are set as the
-positional parameters of the shell
-.Li ( $1 , $2 ,
-etc).
-Otherwise, if
-.Fl c
-was given, then the first argument, which must exist,
-is taken to be a string of
-.Nm
-commands to execute.
-Then if any additional arguments follow the command string,
-those arguments become
-.Li $0 , $1 ,
-\&...
-Otherwise, if additional arguments were given
-(which implies that
-.Fl s
-was set)
-those arguments become
-.Li $1 , $2 ,
-\&...
-If
-.Li $0
-has not been set by the preceding processing, it
-will be set to
-.Va argv\^ Ns [ 0 ]
-as passed to the shell, which will
-usually be the name of the shell itself.
-If
-.Fl s
-was given, or if neither
-.Fl c
-nor any additional (non-option) arguments were present,
-the shell reads commands from its standard input.
-.\"
-.\"
-.Ss Argument List Processing
-.\"
-Currently, all of the single letter options that can meaningfully
-be set using the
-.Ic set
-built-in, have a corresponding name
-that can be used as an argument to the
-.Fl o
-option.
-The
-.Ic set Fl o
-name is provided next to the single letter option in
-the description below.
-Some options have only a long name, they are described after
-the flag options, they are used with
-.Fl o
-or
-.Cm +o
-only, either on the command line, or with the
-.Ic set
-built-in command.
-Other options described are for the command line only.
-Specifying a dash
-.Dq Cm \-
-turns the option on, while using a plus
-.Dq Cm +
-disables the option.
-The following options can be set from the command line and,
-unless otherwise stated, with the
-.Ic set
-built-in (described later).
-.\"
-.\" strlen("quietprofile") == strlen("local_lineno"): pick the latter
-.\" to give the indent as the _ in local_lineno, and the fi ligature in
-.\" quietprofile combine to make "local_lineno' slightly wider when printed
-.\" (in italics) in a variable width font.
-.Bl -tag -width ".Fl L Em local_lineno" -offset indent
-.\"
-.It Fl a Em allexport
-Automatically export any variable to which a value is assigned
-while this flag is set, unless the variable has been marked as
-not for export.
-.It Fl b Em notify
-Enable asynchronous notification of background job completion.
-(Not implemented.)
-.It Fl C Em noclobber
-Don't overwrite existing files with
-.Dq > .
-.It Fl c
-Read commands from the
-.Ar command_string
-operand instead of, or in addition to, from the standard input.
-Special parameter
-.Dv 0 \" $0 (comments like this for searching sources only)
-will be set from the
-.Ar command_name
-operand if given, and the positional parameters
-.Dv ( 1 , 2 ,
-etc.)
-set from the remaining argument operands, if any.
-.Fl c
-is only available at invocation, it cannot be
-.Ic set ,
-and there is no form using
-.Dq Cm \&+ .
-.It Fl E Em emacs
-Enable the built-in emacs style
-command line editor (disables
-.Fl V
-if it has been set).
-(See the
-.Sx Command Line Editing
-section below.)
-.It Fl e Em errexit
-If not interactive, exit immediately if any untested command fails.
-If interactive, and an untested command fails,
-cease all processing of the current command and return to
-prompt for a new command.
-The exit status of a command is considered to be
-explicitly tested if the command is used to control an
-.Ic if ,
-.Ic elif ,
-.Ic while ,
-or
-.Ic until ,
-or if the command is the left hand operand of an
-.Dq &&
-or
-.Dq ||
-operator,
-or if it is a pipeline (or simple command) preceded by the
-.Dq \&!
-operator.
-With pipelines, only the status of the entire pipeline
-(indicated by the last command it contains)
-is tested when
-.Fl e
-is set to determine if the shell should exit.
-.It Fl F Em fork
-Cause the shell to always use
-.Xr fork 2
-instead of attempting
-.Xr vfork 2
-when it needs to create a new process.
-This should normally have no visible effect,
-but can slow execution.
-The
-.Nm
-can be compiled to always use
-.Xr fork 2
-in which case altering the
-.Fl F
-flag has no effect.
-.It Fl f Em noglob
-Disable pathname expansion.
-.It Fl h Em trackall
-Functions defined while this option is set will have paths bound to
-commands to be executed by the function at the time of the definition.
-When off when a function is defined,
-the file system is searched for commands each time the function is invoked.
-(Not implemented.)
-.It Fl I Em ignoreeof
-Ignore EOFs from input when interactive.
-(After a large number of consecutive EOFs the shell will exit anyway.)
-.It Fl i Em interactive
-Force the shell to behave interactively.
-.It Fl L Em local_lineno
-When set, before a function is defined,
-causes the variable
-.Dv LINENO
-when used within the function,
-to refer to the line number defined such that
-first line of the function is line 1.
-When reset,
-.Dv LINENO
-in a function refers to the line number within the file
-within which the definition of the function occurs.
-This option defaults to
-.Dq on
-in this shell.
-For more details see the section
-.Sx LINENO
-below.
-.It Fl m Em monitor
-Turn on job control (set automatically when interactive).
-.It Fl n Em noexec
-Read and parse commands, but do not execute them.
-This is useful for checking the syntax of shell scripts.
-If
-.Fl n
-becomes set in an interactive shell, it will automatically be
-cleared just before the next time the command line prompt
-.Pq Ev PS1
-is written.
-.It Fl p Em nopriv
-Do not attempt to reset effective UID if it does not match UID.
-This is not set by default to help avoid incorrect usage by setuid
-root programs via
-.Xr system 3
-or
-.Xr popen 3 .
-.It Fl q Em quietprofile
-If the
-.Fl v
-or
-.Fl x
-options have been set, do not apply them when reading
-initialization files, these being
-.Pa /etc/profile ,
-.Pa .profile ,
-and the file specified by the
-.Ev ENV
-environment variable.
-.It Fl s Em stdin
-Read commands from standard input (set automatically if
-neither
-.Fl c
-nor file arguments are present).
-If after processing a command_string with the
-.Fl c
-option, the shell has not exited, and the
-.Fl s
-option is set, it will continue reading more commands from standard input.
-This option has no effect when set or reset after the shell has
-already started reading from the command_file, or from standard input.
-Note that the
-.Fl s
-flag being set does not cause the shell to be interactive.
-.It Fl u Em nounset
-Write a message to standard error when attempting to obtain a
-value from a variable that is not set,
-and if the shell is not interactive, exit immediately.
-For interactive shells, instead return immediately to the command prompt
-and read the next command.
-Note that expansions (described later, see
-.Sx Word Expansions
-below) using the
-.Sq \&+ ,
-.Sq \&\- ,
-.Sq \&= ,
-or
-.Sq \&?
-operators test if the variable is set, before attempting to
-obtain its value, and hence are unaffected by
-.Fl u .
-.It Fl V Em vi
-Enable the built-in
-.Xr vi 1
-command line editor (disables
-.Fl E
-if it has been set).
-(See the
-.Sx Command Line Editing
-section below.)
-.It Fl v Em verbose
-The shell writes its input to standard error as it is read.
-Useful for debugging.
-.It Fl X Em xlock
-Cause output from the
-.Ic xtrace
-.Pq Fl x
-option to be sent to standard error as it exists when the
-.Fl X
-option is enabled (regardless of its previous state.)
-For example:
-.Bd -literal -compact
- set -X 2>/tmp/trace-file
-.Ed
-will arrange for tracing output to be sent to the file named,
-instead of wherever it was previously being sent,
-until the X option is set again, or cleared.
-.Pp
-Each change (set or clear) to
-.Fl X
-is also performed upon
-.Fl x ,
-but not the converse.
-.It Fl x Em xtrace
-Write each command to standard error (preceded by the expanded value of
-.Li $PS4 )
-before it is executed.
-Unless
-.Fl X
-is set,
-.Dq "standard error"
-means that which existed immediately before any redirections to
-be applied to the command are performed.
-Useful for debugging.
-.It "\ \ " Em cdprint
-Make an interactive shell always print the new directory name when
-changed by the
-.Ic cd
-command.
-In a non-interactive shell this option has no effect.
-.It "\ \ " Em nolog
-Prevent the entry of function definitions into the command history (see
-.Ic fc
-in the
-.Sx Built-ins
-section.)
-(Not implemented.)
-.It "\ \ " Em pipefail
-If set when a pipeline is created,
-the way the exit status of the pipeline is determined
-is altered.
-See
-.Sx Pipelines
-below for the details.
-.It "\ \ " Em posix
-Enables closer adherence to the POSIX shell standard.
-This option will default set at shell startup if the
-environment variable
-.Ev POSIXLY_CORRECT
-is present.
-That can be overridden (set or reset) by the
-.Fl o
-option on the command line.
-Currently this option controls whether (!posix) or not (posix)
-the file given by the
-.Ev ENV
-variable is read at startup by a non-interactive shell.
-It also controls whether file descriptors greater than 2
-opened using the
-.Ic exec
-built-in command are passed on to utilities executed
-.Dq ( yes
-in posix mode),
-whether a colon (:) terminates the user name in tilde (~) expansions
-other than in assignment statements
-.Dq ( no
-in posix mode),
-the format of the output of the
-.Ic kill Fl l
-command, where posix mode causes the names of the signals
-be separated by either a single space or newline, and where otherwise
-sufficient spaces are inserted to generate nice looking columns,
-and whether the shell treats
-an empty brace-list compound statement as a syntax error
-(expected by POSIX) or permits it.
-Such statements
-.Dq "{\ }"
-can be useful when defining dummy functions.
-Lastly, in posix mode, only one
-.Dq \&!
-is permitted before a pipeline.
-.It "\ \ " Em promptcmds
-Allows command substitutions (as well as parameter
-and arithmetic expansions, which are always performed)
-upon the prompt strings
-.Ev PS1 ,
-.Ev PS2 ,
-and
-.Ev PS4
-each time, before they are output.
-This option should not be set until after the prompts
-have been set (or verified) to avoid accidentally importing
-unwanted command substitutions from the environment.
-.It "\ \ " Em tabcomplete
-Enables filename completion in the command line editor.
-Typing a tab character will extend the current input word to match a
-filename.
-If more than one filename matches it is only extended to be the common prefix.
-Typing a second tab character will list all the matching names.
-One of the editing modes, either
-.Fl E
-or
-.Fl V ,
-must be enabled for this to work.
-.El
-.Ss Lexical Structure
-The shell reads input in terms of lines from a file and breaks it up into
-words at whitespace (blanks and tabs), and at certain sequences of
-characters that are special to the shell called
-.Dq operators .
-There are two types of operators: control operators and redirection
-operators (their meaning is discussed later).
-The following is a list of operators:
-.Bl -ohang -offset indent
-.It "Control operators:"
-.Dl & && \&( \&) \&; ;; ;& \&| || <newline>
-.It "Redirection operators:"
-.Dl < > >| << >> <& >& <<- <>
-.El
-.Ss Quoting
-Quoting is used to remove the special meaning of certain characters or
-words to the shell, such as operators, whitespace, or keywords.
-There are four types of quoting:
-matched single quotes,
-matched double quotes,
-backslash,
-and
-dollar preceding matched single quotes (enhanced C style strings.)
-.Ss Backslash
-An unquoted backslash preserves the literal meaning of the following
-character, with the exception of
-.Aq newline .
-An unquoted backslash preceding a
-.Aq newline
-is treated as a line continuation, the two characters are simply removed.
-.Ss Single Quotes
-Enclosing characters in single quotes preserves the literal meaning of all
-the characters (except single quotes, making it impossible to put
-single quotes in a single-quoted string).
-.Ss Double Quotes
-Enclosing characters within double quotes preserves the literal
-meaning of all characters except dollar sign
-.Pq Li \&$ ,
-backquote
-.Pq Li \&` ,
-and backslash
-.Pq Li \e .
-The backslash inside double quotes is historically weird, and serves to
-quote only the following characters (and these not in all contexts):
-.Dl $ ` \*q \e <newline> ,
-where a backslash newline is a line continuation as above.
-Otherwise it remains literal.
-.\"
-.\"
-.Ss Dollar Single Quotes ( Li \&$'...' )
-.\"
-.Bd -filled -offset indent
-.Bf Em
-Note: this form of quoting is still somewhat experimental,
-and yet to be included in the POSIX standard.
-This implementation is based upon the current proposals for
-standardization, and is subject to change should the eventual
-adopted text differ.
-.Ef
-.Ed
-.Pp
-Enclosing characters in a matched pair of single quotes, with the
-first immediately preceded by an unquoted dollar sign
-.Pq Li \&$
-provides a quoting mechanism similar to single quotes, except
-that within the sequence of characters, any backslash
-.Pq Li \e ,
-is an escape character, which causes the following character to
-be treated specially.
-Only a subset of the characters that can occur in the string
-are defined after a backslash, others are reserved for future
-definition, and currently generate a syntax error if used.
-The escape sequences are modeled after the similar sequences
-in strings in the C programming language, with some extensions.
-.Pp
-The following characters are treated literally when following
-the escape character (backslash):
-.Dl \e \&' \(dq
-The sequence
-.Dq Li \e\e
-allows the escape character (backslash) to appear in the string literally.
-.Dq Li \e'
-allows a single quote character into the string, such an
-escaped single quote does not terminate the quoted string.
-.Dq Li \e\(dq
-is for compatibility with C strings, the double quote has
-no special meaning in a shell C-style string,
-and does not need to be escaped, but may be.
-.Pp
-A newline following the escape character is treated as a line continuation,
-like the same sequence in a double quoted string,
-or when not quoted \(en
-the two characters, the backslash escape and the newline,
-are removed from the input string.
-.Pp
-The following characters, when escaped, are converted in a
-manner similar to the way they would be in a string in the C language:
-.Dl a b e f n r t v
-An escaped
-.Sq a
-generates an alert (or
-.Sq BEL )
-character, that is, control-G, or 0x07.
-In a similar way,
-.Sq b
-is backspace (0x08),
-.Sq e
-(an extension to C) is escape (0x1B),
-.Sq f
-is form feed (0x0C),
-.Sq n
-is newline (or line feed, 0x0A),
-.Sq r
-is return (0x0D),
-.Sq t
-is horizontal tab (0x09),
-and
-.Sq v
-is vertical tab (0x13).
-.Pp
-In addition to those there are 5 forms that need additional
-data, which is obtained from the subsequent characters.
-An escape
-.Pq Li \e
-followed by one, two or three, octal digits
-.Po So 0 Sc Ns \&.. Ns So 7 Sc Ns Pc
-is processed to form an 8 bit character value.
-If only one or two digits are present, the following
-character must be something other than an octal digit.
-It is safest to always use all 3 digits, with leading
-zeros if needed.
-If all three digits are present, the first must be one of
-.So 0 Sc Ns \&.. Ns So 3 Sc .
-.Pp
-An escape followed by
-.Sq x
-(lower case only) can be followed by one or two
-hexadecimal digits
-.Po So 0 Sc Ns \&.. Ns So 9 Sc , So A Sc Ns \&.. Ns So F Sc , or So a Sc Ns \&.. Ns So f Sc . Pc
-As with octal, if only one hex digit is present, the following
-character must be something other than a hex digit,
-so always giving 2 hex digits is best.
-However, unlike octal, it is unspecified in the standard
-how many hex digits can be consumed.
-This
-.Nm
-takes at most two, but other shells will continue consuming
-characters as long as they remain valid hex digits.
-Consequently, users should ensure that the character
-following the hex escape sequence is something other than
-a hex digit.
-One way to achieve this is to end the
-.Li $'...'
-string immediately
-after the final hex digit, and then, immediately start
-another, so
-.Dl \&$'\ex33'$'4...'
-always gives the character with value 0x33
-.Pq Sq 3 ,
-followed by the character
-.Sq 4 ,
-whereas
-.Dl \&$'\ex334'
-in some other shells would be the hex value 0x334 (10, or more, bits).
-.Pp
-There are two escape sequences beginning with
-.Sq Li \eu
-or
-.Sq Li \eU .
-The former is followed by from 1 to 4 hex digits, the latter by
-from 1 to 8 hex digits.
-Leading zeros can be used to pad the sequences to the maximum
-permitted length, to avoid any possible ambiguity problem with
-the following character, and because there are some shells that
-insist on exactly 4 (or 8) hex digits.
-These sequences are evaluated to form the value of a Unicode code
-point, which is then encoded into UTF-8 form, and entered into the
-string.
-(The code point should be converted to the appropriate
-code point value for the corresponding character in the character
-set given by the current locale, or perhaps the locale in use
-when the shell was started, but is not... currently.)
-Not all values that are possible to write are valid, values that
-specify (known) invalid Unicode code points will be rejected, or
-simply produce
-.Sq \&? .
-.Pp
-Lastly, as another addition to what is available in C, the escape
-character (backslash), followed by
-.Sq c
-(lower case only) followed by one additional character, which must
-be an alphabetic character (a letter), or one of the following:
-.Dl \&@ \&[ \&\e \&] \&^ \&_ \&?
-Other than
-.Sq Li \ec?
-the value obtained is the least significant 5 bits of the
-ASCII value of the character following the
-.Sq Li \ec
-escape sequence.
-That is what is commonly known as the
-.Dq control
-character obtained from the given character.
-The escape sequence
-.Sq Li \ec?
-yields the ASCII DEL character (0x7F).
-Note that to obtain the ASCII FS character (0x1C) this way,
-.Pq "that is control-\e"
-the trailing
-.Sq Li \e
-must be escaped itself, and so for this one case, the full
-escape sequence is
-.Dq Li \ec\e\e .
-The sequence
-.Dq Li \ec\e Ns Ar X\^
-where
-.Sq Ar X\^
-is some character other than
-.Sq Li \e
-is reserved for future use, its meaning is unspecified.
-In this
-.Nm
-an error is generated.
-.Pp
-If any of the preceding escape sequences generate the value
-.Sq \e0
-(a NUL character) that character, and all that follow in the same
-.Li $'...'
-string, are omitted from the resulting word.
-.Pp
-After the
-.Li $'...'
-string has had any included escape sequences
-converted, it is treated as if it had been a single quoted string.
-.\"
-.\"
-.Ss Reserved Words
-.\"
-Reserved words are words that have special meaning to the
-shell and are recognized at the beginning of a line and
-after a control operator.
-The following are reserved words:
-.Bl -column while while while while -offset indent
-.It Ic \&! Ta Ic \&{ Ta Ic \&} Ta Ic case
-.It Ic do Ta Ic done Ta Ic elif Ta Ic else
-.It Ic esac Ta Ic fi Ta Ic for Ta Ic if
-.It Ic in Ta Ic then Ta Ic until Ta Ic while
-.El
-.Pp
-Their meanings are discussed later.
-.\"
-.\"
-.Ss Aliases
-.\"
-An alias is a name and corresponding value set using the
-.Ic alias
-built-in command.
-Whenever a reserved word (see above) may occur,
-and after checking for reserved words, the shell
-checks the word to see if it matches an alias.
-If it does, it replaces it in the input stream with its value.
-For example, if there is an alias called
-.Dq lf
-with the value
-.Dq "ls -F" ,
-then the input:
-.Pp
-.Dl lf foobar Aq return
-.Pp
-would become
-.Pp
-.Dl ls -F foobar Aq return
-.Pp
-Aliases provide a convenient way for naive users to create shorthands for
-commands without having to learn how to create functions with arguments.
-They can also be used to create lexically obscure code.
-This use is strongly discouraged.
-.\"
-.Ss Commands
-.\"
-The shell interprets the words it reads according to a language, the
-specification of which is outside the scope of this man page (refer to the
-BNF in the POSIX 1003.2 document).
-Essentially though, a line is read and if the first
-word of the line (or after a control operator) is not a reserved word,
-then the shell has recognized a simple command.
-Otherwise, a complex
-command or some other special construct may have been recognized.
-.\"
-.\"
-.Ss Simple Commands
-.\"
-If a simple command has been recognized, the shell performs
-the following actions:
-.Bl -enum -offset indent
-.It
-Leading words of the form
-.Dq Ar name Ns Li = Ns Ar value
-are stripped off, the value is expanded, as described below,
-and the results are assigned to the environment of the simple command.
-Redirection operators and their arguments (as described below) are
-stripped off and saved for processing in step 3 below.
-.It
-The remaining words are expanded as described in the
-.Sx Word Expansions
-section below.
-The first remaining word is considered the command name and the
-command is located.
-Any remaining words are considered the arguments of the command.
-If no command name resulted, then the
-.Dq Ar name Ns Li = Ns Ar value
-variable assignments recognized in item 1 affect the current shell.
-.It
-Redirections are performed, from first to last, in the order given,
-as described in the next section.
-.El
-.\"
-.\"
-.Ss Redirections
-.\"
-Redirections are used to change where a command reads its input or sends
-its output.
-In general, redirections open, close, or duplicate an
-existing reference to a file.
-The overall format used for redirection is:
-.Pp
-.Dl Oo Ar n Oc Ns Va redir-op Ar file
-.Pp
-where
-.Va redir-op
-is one of the redirection operators mentioned previously.
-The following is a list of the possible redirections.
-The
-.Op Ar n
-is an optional number, as in
-.Sq Li 3
-(not
-.Li [3] ) ,
-that refers to a file descriptor.
-If present it must occur immediately before the redirection
-operator, with no intervening white space, and becomes a
-part of that operator.
-.Bl -tag -width aaabsfiles -offset indent
-.It Oo Ar n Oc Ns Ic > Ar file
-Redirect standard output (or
-.Ar n )
-to
-.Ar file .
-.It Oo Ar n Oc Ns Ic >| Ar file
-The same, but override the
-.Fl C
-option.
-.It Oo Ar n Oc Ns Ic >> Ar file
-Append standard output (or
-.Ar n )
-to
-.Ar file .
-.It Oo Ar n Oc Ns Ic < Ar file
-Redirect standard input (or
-.Ar n )
-from
-.Ar file .
-.It Oo Ar n1 Oc Ns Ic <& Ns Ar n2
-Duplicate standard input (or
-.Ar n1 )
-from file descriptor
-.Ar n2 .
-.Ar n2
-is expanded if not a digit string, the result must be a number.
-.It Oo Ar n Oc Ns Ic <&-
-Close standard input (or
-.Ar n ) .
-.It Oo Ar n1 Oc Ns Ic >& Ns Ar n2
-Duplicate standard output (or
-.Ar n1 )
-to
-.Ar n2 .
-.It Oo Ar n Oc Ns Ic >&-
-Close standard output (or
-.Ar n ) .
-.It Oo Ar n Oc Ns Ic <> Ar file
-Open
-.Ar file
-for reading and writing on standard input (or
-.Ar n ) .
-.El
-.Pp
-The following redirection is often called a
-.Dq here-document .
-.Bd -unfilled -offset indent
-.Oo Ar n Oc Ns Ic << Ar delimiter
-.Li \&... here-doc-text ...
-.Ar delimiter
-.Ed
-.Pp
-The
-.Dq here-doc-text
-starts immediately after the next unquoted newline character following
-the here-document redirection operator.
-If there is more than one here-document redirection on the same
-line, then the text for the first (from left to right) is read
-first, and subsequent here-doc-text for later here-document redirections
-follows immediately after, until all such redirections have been
-processed.
-.Pp
-All the text on successive lines up to the delimiter,
-which must appear on a line by itself, with nothing other
-than an immediately following newline, is
-saved away and made available to the command on standard input, or file
-descriptor n if it is specified.
-If the delimiter as specified on the initial line is
-quoted, then the here-doc-text is treated literally; otherwise, the text is
-treated much like a double quoted string, except that
-.Sq Li \(dq
-characters have no special meaning, and are not escaped by
-.Sq Li \&\e ,
-and is subjected to parameter expansion, command substitution, and arithmetic
-expansion as described in the
-.Sx Word Expansions
-section below.
-If the operator is
-.Ic <<-
-instead of
-.Ic << ,
-then leading tabs in all lines in the here-doc-text, including before the
-end delimiter, are stripped.
-If the delimiter is not quoted, lines in here-doc-text that end with
-an unquoted
-.Li \e
-are joined to the following line, the
-.Li \e
-and following
-newline are simply removed while reading the here-document,
-which thus guarantees
-that neither of those lines can be the end delimiter.
-.Pp
-It is a syntax error for the end of the input file (or string) to be
-reached before the delimiter is encountered.
-.\"
-.\"
-.Ss Search and Execution
-.\"
-There are three types of commands: shell functions, built-in commands, and
-normal programs \(em and the command is searched for (by name) in that order.
-A command that contains a slash
-.Sq \&/
-in its name is always a normal program.
-They each are executed in a different way.
-.Pp
-When a shell function is executed, all of the shell positional parameters
-(note: excluding
-.Li 0 , \" $0
-which is a special, not positional, parameter, and remains unchanged)
-are set to the arguments of the shell function.
-The variables which are explicitly placed in the environment of
-the command (by placing assignments to them before the function name) are
-made local to the function and are set to the values given,
-and exported for the benefit of programs executed with the function.
-Then the command given in the function definition is executed.
-The positional parameters, and local variables, are restored to
-their original values when the command completes.
-This all occurs within the current shell, and the function
-can alter variables, or other settings, of the shell, but
-not the positional parameters nor their related special parameters.
-.Pp
-Shell built-ins are executed internally to the shell, without spawning a
-new process.
-.Pp
-Otherwise, if the command name doesn't match a function or built-in, the
-command is searched for as a normal program in the file system (as
-described in the next section).
-When a normal program is executed, the shell runs the program,
-passing the arguments and the environment to the program.
-If the program is not a normal executable file, and if it does
-not begin with the
-.Dq magic number
-whose ASCII representation is
-.Dq Li "#!" ,
-so
-.Xr execve 2
-returns
-.Er ENOEXEC
-then) the shell will interpret the program in a sub-shell.
-The child shell will reinitialize itself in this case,
-so that the effect will be as if a
-new shell had been invoked to handle the ad-hoc shell script, except that
-the location of hashed commands located in the parent shell will be
-remembered by the child.
-.Pp
-Note that previous versions of this document and the source code itself
-misleadingly and sporadically refer to a shell script without a magic
-number as a
-.Dq shell procedure .
-.\"
-.\"
-.Ss Path Search
-.\"
-When locating a command, the shell first looks to see if it has a shell
-function by that name.
-Then it looks for a built-in command by that name.
-If a built-in command is not found, one of two things happen:
-.Bl -enum
-.It
-Command names containing a slash are simply executed without performing
-any searches.
-.It
-Otherwise, the shell searches each entry in
-.Ev PATH
-in turn for the command.
-The value of the
-.Ev PATH
-variable should be a series of entries separated by colons.
-Each entry consists of a directory name.
-The current directory may be indicated
-implicitly by an empty directory name, or explicitly by a single period.
-If a directory searched contains an executable file with the same
-name as the command given,
-the search terminates, and that program is executed.
-.El
-.Ss Command Exit Status
-Each command has an exit status that can influence the behavior
-of other shell commands.
-The paradigm is that a command exits
-with zero in normal cases, or to indicate success,
-and non-zero for failure,
-error, or a false indication.
-The man page for each command
-should indicate the various exit codes and what they mean.
-Additionally, the built-in commands return exit codes, as does
-an executed shell function.
-.Pp
-If a command consists entirely of variable assignments then the
-exit status of the command is that of the last command substitution
-if any, otherwise 0.
-.Pp
-If redirections are present, and any fail to be correctly performed,
-any command present is not executed, and an exit status of 2
-is returned.
-.Ss Complex Commands
-Complex commands are combinations of simple commands with control
-operators or reserved words, together creating a larger complex command.
-Overall, a shell program is a:
-.Bl -tag -width XpipelineX
-.It list
-Which is a sequence of one or more AND-OR lists.
-.It "AND-OR list"
-is a sequence of one or more pipelines.
-.It pipeline
-is a sequence of one or more commands.
-.It command
-is one of a simple command, a compound command, or a function definition.
-.It "simple command"
-has been explained above, and is the basic building block.
-.It "compound command"
-provides mechanisms to group lists to achieve different effects.
-.It "function definition"
-allows new simple commands to be created as groupings of existing commands.
-.El
-.Pp
-Unless otherwise stated, the exit status of a list
-is that of the last simple command executed by the list.
-.\"
-.\"
-.Ss Pipelines
-.\"
-A pipeline is a sequence of one or more commands separated
-by the control operator
-.Sq Ic \(ba ,
-and optionally preceded by the
-.Dq Ic \&!
-reserved word.
-Note that
-.Sq Ic \(ba
-is an operator, and so is recognized anywhere it appears unquoted,
-it does not require surrounding white space or other syntax elements.
-On the other hand
-.Dq Ic \&!
-being a reserved word, must be separated from adjacent words by
-white space (or other operators, perhaps redirects) and is only
-recognized as the reserved word when it appears in a command word
-position (such as at the beginning of a pipeline.)
-.Pp
-The standard output of all but
-the last command in the sequence is connected to the standard input
-of the next command.
-The standard output of the last
-command is inherited from the shell, as usual,
-as is the standard input of the first command.
-.Pp
-The format for a pipeline is:
-.Pp
-.Dl [!] command1 Op Li \&| command2 No ...
-.Pp
-The standard output of command1 is connected to the standard input of
-command2.
-The standard input, standard output, or both of each command is
-considered to be assigned by the pipeline before any redirection specified
-by redirection operators that are part of the command are performed.
-.Pp
-If the pipeline is not in the background (discussed later), the shell
-waits for all commands to complete.
-.Pp
-The commands in a pipeline can either be simple commands,
-or one of the compound commands described below.
-The simplest case of a pipeline is a single simple command.
-.Pp
-If the
-.Ic pipefail
-option was set when a pipeline was started,
-the pipeline status is the status of
-the last (lexically last, i.e.: rightmost) command in the
-pipeline to exit with non-zero exit status, or zero, if,
-and only if, all commands in the pipeline exited with a status of zero.
-If the
-.Ic pipefail
-option was not set, which is the default state,
-the pipeline status is the exit
-status of the last (rightmost) command in the pipeline,
-and the exit status of any other commands in the pipeline is ignored.
-.Pp
-If the reserved word
-.Dq Ic \&!
-precedes the pipeline, the exit status
-becomes the logical NOT of the pipeline status as determined above.
-That is, if the pipeline status is zero, the exit status is 1;
-if the pipeline status is other than zero, the exit status is zero.
-If there is no
-.Dq Ic \&!
-reserved word, the pipeline status becomes the exit status.
-.Pp
-Because pipeline assignment of standard input or standard output or both
-takes place before redirection, it can be modified by redirection.
-For example:
-.Pp
-.Dl $ command1 2>&1 \&| command2
-.Pp
-sends both the standard output and standard error of command1
-to the standard input of command2.
-.Pp
-Note that unlike some other shells, each process in the pipeline is a
-child of the invoking shell (unless it is a shell built-in, in which case
-it executes in the current shell \(em but any effect it has on the
-environment is wiped).
-.Pp
-A pipeline is a simple case of an AND-OR-list (described below.)
-A
-.Li \&;
-or
-.Aq newline
-terminator causes the preceding pipeline, or more generally,
-the preceding AND-OR-list to be executed sequentially;
-that is, the shell executes the commands, and waits for them
-to finish before proceeding to following commands.
-An
-.Li \&&
-terminator causes asynchronous (background) execution
-of the preceding AND-OR-list (see the next paragraph below).
-The exit status of an asynchronous AND-OR-list is zero.
-The actual status of the commands,
-after they have completed,
-can be obtained using the
-.Ic wait
-built-in command described later.
-.\"
-.\"
-.Ss Background Commands \(em Ic \&&
-.\"
-If a command, pipeline, or AND-OR-list
-is terminated by the control operator ampersand
-.Pq Li \&& ,
-the
-shell executes the command asynchronously \(em that is, the shell does not
-wait for the command to finish before executing the next command.
-.Pp
-The format for running a command in background is:
-.Pp
-.Dl command1 & Op Li command2 & No ...
-.Pp
-If the shell is not interactive, the standard input of an asynchronous
-command is set to
-.Pa /dev/null .
-The process identifier of the most recent command started in the
-background can be obtained from the value of the special parameter
-.Dq Dv \&! \" $!
-(see
-.Sx Special Parameters )
-provided it is accessed before the next asynchronous command is started.
-.\"
-.\"
-.Ss Lists \(em Generally Speaking
-.\"
-A list is a sequence of one or more commands separated by newlines,
-semicolons, or ampersands, and optionally terminated by one of these three
-characters.
-A shell program, which includes the commands given to an
-interactive shell, is a list.
-Each command in such a list is executed when it is fully parsed.
-Another use of a list is as a complete-command,
-which is parsed in its entirety, and then later the commands in
-the list are executed only if there were no parsing errors.
-.Pp
-The commands in a list are executed in the order they are written.
-If command is followed by an ampersand, the shell starts the
-command and immediately proceeds to the next command; otherwise it waits
-for the command to terminate before proceeding to the next one.
-A newline is equivalent to a
-.Sq Li \&;
-when no other operator is present, and the command being input
-could syntactically correctly be terminated at the point where
-the newline is encountered, otherwise it is just whitespace.
-.\"
-.\"
-.Ss AND-OR Lists (Short-Circuit List Operators)
-.\"
-.Dq Li \&&&
-and
-.Dq Li \&||
-are AND-OR list operators.
-After executing the commands that precede the
-.Dq Li \&&&
-the subsequent command is executed
-if and only if the exit status of the preceding command(s) is zero.
-.Dq Li \&||
-is similar, but executes the subsequent command if and only if the exit status
-of the preceding command is nonzero.
-If a command is not executed, the exit status remains unchanged
-and the following AND-OR list operator (if any) uses that status.
-.Dq Li \&&&
-and
-.Dq Li \&||
-both have the same priority.
-Note that these operators are left-associative, so
-.Dl true || echo bar && echo baz
-writes
-.Dq baz
-and nothing else.
-This is not the way it works in C.
-.\"
-.\"
-.Ss Flow-Control Constructs \(em Ic if , while , until , for , case
-.\"
-These commands are instances of compound commands.
-The syntax of the
-.Ic if
-command is
-.Bd -literal -offset indent
-.Ic if Ar list
-.Ic then Ar list
-.Ic [ elif Ar list
-.Ic then Ar list ] No ...
-.Ic [ else Ar list ]
-.Ic fi
-.Ed
-.Pp
-The first list is executed, and if the exit status of that list is zero,
-the list following the
-.Ic then
-is executed.
-Otherwise the list after an
-.Ic elif
-(if any) is executed and the process repeats.
-When no more
-.Ic elif
-reserved words, and accompanying lists, appear,
-the list after the
-.Ic else
-reserved word, if any, is executed.
-.Pp
-The syntax of the
-.Ic while
-command is
-.Bd -literal -offset indent
-.Ic while Ar list
-.Ic do Ar list
-.Ic done
-.Ed
-.Pp
-The two lists are executed repeatedly while the exit status of the
-first list is zero.
-The
-.Ic until
-command is similar, but has the word
-.Ic until
-in place of
-.Ic while ,
-which causes it to repeat until the exit status of the first list is zero.
-.Pp
-The syntax of the
-.Ic for
-command is
-.Bd -literal -offset indent
-.Ic for Ar variable Op Ic in Ar word No ...
-.Ic do Ar list
-.Ic done
-.Ed
-.Pp
-The words are expanded, or
-.Li \*q$@\*q
-if
-.Ic in
-(and the following words) is not present,
-and then the list is executed repeatedly with the
-variable set to each word in turn.
-If
-.Ic in
-appears after the variable, but no words are
-present, the list is not executed, and the exit status is zero.
-.Ic do
-and
-.Ic done
-may be replaced with
-.Sq Ic \&{
-and
-.Sq Ic \&} ,
-but doing so is non-standard and not recommended.
-.Pp
-The syntax of the
-.Ic break
-and
-.Ic continue
-commands is
-.Bd -literal -offset indent
-.Ic break Op Ar num
-.Ic continue Op Ar num
-.Ed
-.Pp
-.Ic break
-terminates the
-.Ar num
-innermost
-.Ic for , while ,
-or
-.Ic until
-loops.
-.Ic continue
-breaks execution of the
-.Ar num\^ Ns -1
-innermost
-.Ic for , while ,
-or
-.Ic until
-loops, and then continues with the next iteration of the enclosing loop.
-These are implemented as special built-in commands.
-The parameter
-.Ar num ,
-if given, must be an unsigned positive integer (greater than zero).
-If not given, 1 is used.
-.Pp
-The syntax of the
-.Ic case
-command is
-.Bd -literal -offset indent
-.Ic case Ar word Ic in
-.Oo Ic \&( Oc Ar pattern Ns Ic \&) Oo Ar list Oc Ic \&;&
-.Oo Ic \&( Oc Ar pattern Ns Ic \&) Oo Ar list Oc Ic \&;;
-.No \&...
-.Ic esac
-.Ed
-.Pp
-The pattern can actually be one or more patterns (see
-.Sx Shell Patterns
-described later), separated by
-.Dq \(or
-characters.
-.Pp
-.Ar word
-is expanded and matched against each
-.Ar pattern
-in turn,
-from first to last,
-with each pattern being expanded just before the match is attempted.
-When a match is found, pattern comparisons cease, and the associated
-.Ar list ,
-if given,
-is evaluated.
-If the list is terminated with
-.Dq Ic \&;&
-execution then falls through to the following list, if any,
-without evaluating its pattern, or attempting a match.
-When a list terminated with
-.Dq Ic \&;;
-has been executed, or when
-.Ic esac
-is reached, execution of the
-.Ic case
-statement is complete.
-The exit status is that of the last command executed
-from the last list evaluated, if any, or zero otherwise.
-.\"
-.\"
-.Ss Grouping Commands Together
-.\"
-Commands may be grouped by writing either
-.Dl Ic \&( Ns Ar list Ns Ic \&)
-or
-.Dl Ic \&{ Ar list Ns Ic \&; \&}
-These also form compound commands.
-.Pp
-Note that while parentheses are operators, and do not require
-any extra syntax, braces are reserved words, so the opening brace
-must be followed by white space (or some other operator), and the
-closing brace must occur in a position where a new command word might
-otherwise appear.
-.Pp
-The first of these executes the commands in a sub-shell.
-Built-in commands grouped into a
-.Li \&( Ns Ar list Ns \&)
-will not affect the current shell.
-The second form does not fork another shell so is slightly more efficient,
-and allows for commands which do affect the current shell.
-Grouping commands together this way allows you to redirect
-their output as though they were one program:
-.Bd -literal -offset indent
-{ echo -n \*qhello \*q ; echo \*qworld\*q ; } > greeting
-.Ed
-.Pp
-Note that
-.Dq Ic }
-must follow a control operator (here,
-.Dq Ic \&; )
-so that it is recognized as a reserved word and not as another command argument.
-.\"
-.\"
-.Ss Functions
-.\"
-The syntax of a function definition is
-.Pp
-.Dl Ar name Ns Ic \&() Ar command Op Ar redirect No ...
-.Pp
-A function definition is an executable statement; when executed it
-installs a function named name and returns an exit status of zero.
-The command is normally a list enclosed between
-.Dq {
-and
-.Dq } .
-The standard syntax also allows the command to be any of the other
-compound commands, including a sub-shell, all of which are supported.
-As an extension, this shell also allows a simple command
-(or even another function definition) to be
-used, though users should be aware this is non-standard syntax.
-This means that
-.Dl l() ls \*q$@\*q
-works to make
-.Dq l
-an alternative name for the
-.Ic ls
-command.
-.Pp
-If the optional redirect, (see
-.Sx Redirections ) ,
-which may be of any of the normal forms,
-is given, it is applied each time the
-function is called.
-This means that a simple
-.Dq Hello World
-function might be written (in the extended syntax) as:
-.Bd -literal -offset indent
-hello() cat <<EOF
-Hello World!
-EOF
-.Ed
-.Pp
-To be correctly standards conforming this should be re-written as:
-.Bd -literal -offset indent
-hello() { cat; } <<EOF
-Hello World!
-EOF
-.Ed
-.Pp
-Note the distinction between those forms, and
-.Bd -literal -offset indent
-hello() { cat <<EOF
-Hello World!
-EOF
-\&}
-.Ed
-.Pp
-which reads and processes the here-document
-each time the shell executes the function, and which applies
-that input only to the cat command, not to any other commands
-that might appear in the function.
-.Pp
-Variables may be declared to be local to a function by using the
-.Ic local
-command.
-This should usually appear as the first statement of a function,
-though
-.Ic local
-is an executable command which can be used anywhere in a function.
-See
-.Sx Built-ins
-below for its definition.
-.Pp
-The function completes after having executed
-.Ar command
-with exit status set to the status returned by
-.Ar command .
-If
-.Ar command
-is a compound-command
-it can use the
-.Ic return
-command (see
-.Sx Built-ins
-below)
-to finish before completing all of
-.Ar command .
-.Ss Variables and Parameters
-The shell maintains a set of parameters.
-A parameter denoted by a name is called a variable.
-When starting up, the shell turns all the environment
-variables into shell variables, and exports them.
-New variables can be set using the form
-.Pp
-.Dl Ar name Ns Li = Ns Ar value
-.Pp
-Variables set by the user must have a name consisting solely of
-alphabetics, numerics, and underscores \(em the first of which must not be
-numeric.
-A parameter can also be denoted by a number or a special
-character as explained below.
-.Ss Positional Parameters
-A positional parameter is a parameter denoted by a number (n > 0).
-The shell sets these initially to the values of its command line arguments
-that follow the name of the shell script.
-The
-.Ic set
-built-in can also be used to set or reset them, and
-.Ic shift
-can be used to manipulate the list.
-.Pp
-To refer to the 10th (and later) positional parameters,
-the form
-.Li \&${ Ns Ar n Ns Li \&}
-must be used.
-Without the braces, a digit following
-.Dq $
-can only refer to one of the first 9 positional parameters,
-or the special parameter
-.Dv 0 . \" $0
-The word
-.Dq Li $10
-is treated identically to
-.Dq Li ${1}0 .
-.\"
-.\"
-.Ss Special Parameters
-.\"
-A special parameter is a parameter denoted by one of the following special
-characters.
-The value of the parameter is listed next to its character.
-.Bl -tag -width thinhyphena
-.It Dv *
-Expands to the positional parameters, starting from one.
-When the
-expansion occurs within a double-quoted string it expands to a single
-field with the value of each parameter separated by the first character of
-the
-.Ev IFS
-variable, or by a
-.Aq space
-if
-.Ev IFS
-is unset.
-.It Dv @ \" $@
-Expands to the positional parameters, starting from one.
-When the expansion occurs within double quotes, each positional
-parameter expands as a separate argument.
-If there are no positional parameters, the
-expansion of @ generates zero arguments, even when
-.Dv $@
-is double-quoted.
-What this basically means, for example, is
-if
-.Li $1
-is
-.Dq abc
-and
-.Li $2
-is
-.Dq def\ ghi ,
-then
-.Li \*q$@\*q
-expands to
-the two arguments:
-.Pp
-.Sm off
-.Dl \*q abc \*q \ \*q def\ ghi \*q
-.Sm on
-.It Dv #
-Expands to the number of positional parameters.
-.It Dv \&?
-Expands to the exit status of the most recent pipeline.
-.It Dv \- No (hyphen, or minus)
-Expands to the current option flags (the single-letter
-option names concatenated into a string) as specified on
-invocation, by the set built-in command, or implicitly
-by the shell.
-.It Dv $
-Expands to the process ID of the invoked shell.
-A sub-shell retains the same value of
-.Dv $
-as its parent.
-.It Dv \&!
-Expands to the process ID of the most recent background
-command executed from the current shell.
-For a pipeline, the process ID is that of the last command in the pipeline.
-If no background commands have yet been started by the shell, then
-.Dq Dv \&!
-will be unset.
-Once set, the value of
-.Dq Dv \&!
-will be retained until another background command is started.
-.It Dv 0 No (zero) \" $0
-Expands to the name of the shell or shell script.
-.El
-.\"
-.\"
-.Ss Word Expansions
-.\"
-This section describes the various expansions that are performed on words.
-Not all expansions are performed on every word, as explained later.
-.Pp
-Tilde expansions, parameter expansions, command substitutions, arithmetic
-expansions, and quote removals that occur within a single word expand to a
-single field.
-It is only field splitting or pathname expansion that can
-create multiple fields from a single word.
-The single exception to this
-rule is the expansion of the special parameter
-.Dv @ \" $@
-within double quotes, as was described above.
-.Pp
-The order of word expansion is:
-.Bl -enum
-.It
-Tilde Expansion, Parameter Expansion, Command Substitution,
-Arithmetic Expansion (these all occur at the same time).
-.It
-Field Splitting is performed on fields
-generated by step (1) unless the
-.Ev IFS
-variable is null.
-.It
-Pathname Expansion (unless set
-.Fl f
-is in effect).
-.It
-Quote Removal.
-.El
-.Pp
-The $ character is used to introduce parameter expansion, command
-substitution, or arithmetic evaluation.
-.Ss Tilde Expansion (substituting a user's home directory)
-A word beginning with an unquoted tilde character (~) is
-subjected to tilde expansion.
-Provided all of the subsequent characters in the word are unquoted
-up to an unquoted slash (/)
-or when in an assignment or not in posix mode, an unquoted colon (:),
-or if neither of those appear, the end of the word,
-they are treated as a user name
-and are replaced with the pathname of the named user's home directory.
-If the user name is missing (as in
-.Pa ~/foobar ) ,
-the tilde is replaced with the value of the
-.Dv HOME
-variable (the current user's home directory).
-.Pp
-In variable assignments,
-an unquoted tilde immediately after the assignment operator (=), and
-each unquoted tilde immediately after an unquoted colon in the value
-to be assigned is also subject to tilde expansion as just stated.
-.\"
-.\"
-.Ss Parameter Expansion
-.\"
-The format for parameter expansion is as follows:
-.Pp
-.Dl ${ Ns Ar expression Ns Li }
-.Pp
-where
-.Ar expression
-consists of all characters until the matching
-.Sq Li } .
-Any
-.Sq Li }
-escaped by a backslash or within a quoted string, and characters in
-embedded arithmetic expansions, command substitutions, and variable
-expansions, are not examined in determining the matching
-.Sq Li } .
-.Pp
-The simplest form for parameter expansion is:
-.Pp
-.Dl ${ Ns Ar parameter Ns Li }
-.Pp
-The value, if any, of
-.Ar parameter
-is substituted.
-.Pp
-The parameter name or symbol can be enclosed in braces,
-which are optional in this simple case,
-except for positional parameters with more than one digit or
-when parameter is followed by a character that could be interpreted as
-part of the name.
-If a parameter expansion occurs inside double quotes:
-.Bl -enum
-.It
-pathname expansion is not performed on the results of the expansion;
-.It
-field splitting is not performed on the results of the
-expansion, with the exception of the special rules for
-.Dv @ . \" $@
-.El
-.Pp
-In addition, a parameter expansion where braces are used,
-can be modified by using one of the following formats.
-If the
-.Sq Ic \&:
-is omitted in the following modifiers, then the test in the expansion
-applies only to unset parameters, not null ones.
-.Bl -tag -width aaparameterwordaaaaa
-.It Li ${ Ns Ar parameter Ns Ic :- Ns Ar word Ns Li }
-.Sy Use Default Values.
-If
-.Ar parameter
-is unset or null, the expansion of
-.Ar word
-is substituted; otherwise, the value of
-.Ar parameter
-is substituted.
-.It Li ${ Ns Ar parameter Ns Ic := Ns Ar word Ns Li }
-.Sy Assign Default Values.
-If
-.Ar parameter
-is unset or null, the expansion of
-.Ar word
-is assigned to
-.Ar parameter .
-In all cases, the final value of
-.Ar parameter
-is substituted.
-Only variables, not positional parameters or special
-parameters, can be assigned in this way.
-.It Li ${ Ns Ar parameter Ns Ic :? Ns Oo Ar word\^ Oc Ns Li }
-.Sy Indicate Error if Null or Unset.
-If
-.Ar parameter
-is unset or null, the expansion of
-.Ar word
-(or a message indicating it is unset if
-.Ar word
-is omitted)
-is written to standard error and a non-interactive shell exits with
-a nonzero exit status.
-An interactive shell will not exit, but any associated command(s) will
-not be executed.
-If the
-.Ar parameter
-is set, its value is substituted.
-.It Li ${ Ns Ar parameter Ns Ic :+ Ns Ar word Ns Li }
-.Sy Use Alternative Value.
-If
-.Ar parameter
-is unset or null, null is substituted;
-otherwise, the expansion of
-.Ar word
-is substituted.
-The value of
-.Ar parameter
-.Em is not used
-in this expansion.
-.It Li ${ Ns Ic # Ns Ar parameter Ns Li }
-.Sy String Length.
-The length in characters of the value of
-.Ar parameter .
-.El
-.Pp
-The following four varieties of parameter expansion provide for substring
-processing.
-In each case, pattern matching notation (see
-.Sx Shell Patterns ) ,
-rather than regular expression notation, is used to evaluate the patterns.
-If parameter is
-.Dv *
-or
-.Dv @ , \" $@
-the result of the expansion is unspecified.
-Enclosing the full parameter expansion string in double quotes does not
-cause the following four varieties of pattern characters to be quoted,
-whereas quoting characters within the braces has this effect.
-.Bl -tag -width aaparameterwordaaaaa
-.It Li ${ Ns Ar parameter Ns Ic % Ns Ar word Ns Li }
-.Sy Remove Smallest Suffix Pattern.
-The
-.Ar word
-is expanded to produce a pattern.
-The parameter expansion then results in
-.Ar parameter ,
-with the
-smallest portion of the suffix matched by the pattern deleted.
-If the
-.Ar word
-is to start with a
-.Sq Li \&%
-character, it must be quoted.
-.It Li ${ Ns Ar parameter Ns Ic %% Ns Ar word Ns Li }
-.Sy Remove Largest Suffix Pattern.
-The
-.Ar word
-is expanded to produce a pattern.
-The parameter expansion then results in
-.Ar parameter ,
-with the largest
-portion of the suffix matched by the pattern deleted.
-The
-.Dq Ic %%
-pattern operator only produces different results from the
-.Dq Ic \&%
-operator when the pattern contains at least one unquoted
-.Sq Li \&* .
-.It Li ${ Ns Ar parameter Ns Ic \&# Ns Ar word Ns Li }
-.Sy Remove Smallest Prefix Pattern.
-The
-.Ar word
-is expanded to produce a pattern.
-The parameter expansion then results in
-.Ar parameter ,
-with the
-smallest portion of the prefix matched by the pattern deleted.
-If the
-.Ar word
-is to start with a
-.Sq Li \&#
-character, it must be quoted.
-.It Li ${ Ns Ar parameter Ns Ic \&## Ns Ar word Ns Li }
-.Sy Remove Largest Prefix Pattern.
-The
-.Ar word
-is expanded to produce a pattern.
-The parameter expansion then results in
-.Ar parameter ,
-with the largest
-portion of the prefix matched by the pattern deleted.
-This has the same relationship with the
-.Dq Ic \&#
-pattern operator as
-.Dq Ic %%
-has with
-.Dq Ic \&% .
-.El
-.\"
-.\"
-.Ss Command Substitution
-.\"
-Command substitution allows the output of a command to be substituted in
-place of the command (and surrounding syntax).
-Command substitution occurs when a word contains
-a command list enclosed as follows:
-.Pp
-.Dl Ic $( Ns Ar list Ns Ic \&)
-.Pp
-or the older
-.Pq Dq backquoted
-version, which is best avoided:
-.Pp
-.Dl Ic \&` Ns Ar list Ns Ns Ic \&`
-.Pp
-See the section
-.Sx Complex Commands
-above for the definition of
-.Ic list .
-.Pp
-The shell expands the command substitution by executing the
-.Ar list
-in a sub-shell environment and replacing the command substitution with the
-standard output of the
-.Ar list
-after removing any sequence of one or more
-.Ao newline Ac Ns s
-from the end of the substitution.
-(Embedded
-.Ao newline Ac Ns s
-before
-the end of the output are not removed; however, during field splitting,
-they may be used to separate fields
-.Pq "as spaces usually are"
-depending on the value of
-.Ev IFS
-and any quoting that is in effect.)
-.Pp
-Note that if a command substitution includes commands
-to be run in the background,
-the sub-shell running those commands
-will only wait for them to complete if an appropriate
-.Ic wait
-command is included in the command list.
-However, the shell in which the result of the command substitution
-will be used will wait for both the sub-shell to exit and for the
-file descriptor that was initially standard output for the command
-substitution sub-shell to be closed.
-In some circumstances this might not happen until all processes
-started by the command substitution have finished.
-.\" While the exit of the sub-shell closes its standard output,
-.\" any background process left running may still
-.\" have that file descriptor open.
-.\" This includes yet another sub-shell which might have been
-.\" (almost invisibly) created to wait for some other command to complete,
-.\" and even where the background command has had its
-.\" standard output redirected or closed,
-.\" the waiting sub-shell may still have it open.
-.\" Thus there is no guarantee that the result of a command substitution
-.\" will be available in the shell which is to use it before all of
-.\" the commands started by the command substitution have completed,
-.\" though careful coding can often avoid delays beyond the termination
-.\" of the command substitution sub-shell.
-.\" .Pp
-.\" For example, assuming a script were to contain the following
-.\" code (which could be done better other ways, attempting
-.\" this kind of trickery is not recommended):
-.\" .Bd -literal -offset indent
-.\" if [ "$( printf "Ready? " >&2; read ans; printf "${ans}";
-.\" { sleep 120 >/dev/null && kill $$ >/dev/null 2>&1; }& )" = go ]
-.\" then
-.\" printf Working...
-.\" # more code
-.\" fi
-.\" .Ed
-.\" .Pp
-.\" the
-.\" .Dq Working...
-.\" output will not be printed, and code that follows will never be executed.
-.\" Nor will anything later in the script
-.\" .Po
-.\" unless
-.\" .Dv SIGTERM
-.\" is trapped or ignored
-.\" .Pc .
-.\" .Pp
-.\" The intent is to prompt the user, wait for the user to
-.\" answer, then if the answer was
-.\" .Dq go
-.\" do the appropriate work, but set a 2 minute time limit
-.\" on completing that work.
-.\" If the work is not done by then, kill the shell doing it.
-.\" .Pp
-.\" It will usually not work as written, as while the 2 minute
-.\" .Sq sleep
-.\" has its standard output redirected, as does the
-.\" .Sq kill
-.\" that follows (which also redirects standard error,
-.\" so the user would not see an error if the work were
-.\" completed and there was no parent process left to kill);
-.\" the sub-shell waiting for the
-.\" .Sq sleep
-.\" to finish successfully, so it can start the
-.\" .Sq kill ,
-.\" does not.
-.\" It waits, with standard output still open,
-.\" for the 2 minutes until the sleep is done,
-.\" even though the kill is not going to need that file descriptor,
-.\" and there is nothing else which could.
-.\" The command substitution does not complete until after
-.\" the kill has executed and the background sub-shell
-.\" finishes \(en at which time the shell running it is
-.\" presumably dead.
-.\" .Pp
-.\" Rewriting the background sub-shell part of that as
-.\" .Dl "{ sleep 120 && kill $$ 2>&1; } >/dev/null &"
-.\" would allow this
-.\" .Nm
-.\" to perform as expected, but that is not guaranteed,
-.\" not all shells would behave as planned.
-.\" It is advised to avoid starting background processes
-.\" from within a command substitution.
-.\"
-.\"
-.Ss Arithmetic Expansion
-.\"
-Arithmetic expansion provides a mechanism for evaluating an arithmetic
-expression and substituting its value.
-The format for arithmetic expansion is as follows:
-.Pp
-.Dl Ic $(( Ns Ar expression Ns Ic \&))
-.Pp
-The expression in an arithmetic expansion is treated as if it were in
-double quotes, except that a double quote character inside the expression
-is just a normal character (it quotes nothing.)
-The shell expands all tokens in the expression for parameter expansion,
-command substitution, and quote removal (the only quoting character is
-the backslash
-.Sq \&\e ,
-and only when followed by another
-.Sq \&\e ,
-a dollar sign
-.Sq \&$ ,
-a backquote
-.Sq \&`
-or a newline.)
-.Pp
-Next, the shell evaluates the expanded result as an arithmetic expression
-and substitutes the calculated value of that expression.
-.Pp
-Arithmetic expressions use a syntax similar to that
-of the C language, and are evaluated using the
-.Ql intmax_t
-data type (this is an extension to POSIX, which requires only
-.Ql long
-arithmetic.)
-Shell variables may be referenced by name inside an arithmetic
-expression, without needing a
-.Dq \&$
-sign.
-Variables that are not set, or which have an empty (null string) value,
-used this way evaluate as zero (that is,
-.Dq x
-in arithmetic, as an R-Value, is evaluated as
-.Dq ${x:-0} )
-unless the
-.Nm
-.Fl u
-flag is set, in which case a reference to an unset variable is an error.
-Note that unset variables used in the ${var} form expand to a null
-string, which might result in syntax errors.
-Referencing the value of a variable which is not numeric is an error.
-.Pp
-All of the C expression operators applicable to integers are supported,
-and operate as they would in a C expression.
-Use white space, or parentheses, to disambiguate confusing syntax,
-otherwise, as in C, the longest sequence of consecutive characters
-which make a valid token (operator, variable name, or number) is taken
-to be that token, even if the token designated cannot be used
-and a different interpretation could produce a successful parse.
-This means, as an example, that
-.Dq a+++++b
-is parsed as the gibberish sequence
-.Dq "a ++ ++ + b" ,
-rather than as the valid alternative
-.Dq "a ++ + ++ b" .
-Similarly, separate the
-.Sq \&,
-operator from numbers with white space to avoid the possibility
-of confusion with the decimal indicator in some locales (though
-fractional, or floating-point, numbers are not supported in this
-implementation.)
-.Pp
-It should not be necessary to state that the C operators which
-operate on, or produce, pointer types, are not supported.
-Those include unary
-.Dq \&*
-and
-.Dq \&&
-and the struct and array referencing binary operators:
-.Dq \&. ,
-.Dq \&->
-and
-.Dq \&[ .
-.\"
-.\"
-.Ss White Space Splitting (Field Splitting)
-.\"
-After parameter expansion, command substitution, and
-arithmetic expansion the shell scans the results of
-expansions and substitutions that did not occur in double quotes,
-and
-.Dq Li $@
-even if it did,
-for field splitting and multiple fields can result.
-.Pp
-The shell treats each character of the
-.Ev IFS
-as a delimiter and uses the delimiters to split the results of parameter
-expansion and command substitution into fields.
-.Pp
-Non-whitespace characters in
-.Ev IFS
-are treated strictly as parameter separators.
-So adjacent non-whitespace
-.Ev IFS
-characters will produce empty parameters.
-On the other hand, any sequence of whitespace
-characters that occur in
-.Ev IFS
-(known as
-.Ev IFS
-whitespace)
-can occur, leading and trailing
-.Ev IFS
-whitespace, and any
-.Ev IFS
-whitespace surrounding a non whitespace
-.Ev IFS
-delimiter, is removed.
-Any sequence of
-.Ev IFS
-whitespace characters without a non-whitespace
-.Ev IFS
-delimiter acts as a single field separator.
-.Pp
-If
-.Ev IFS
-is unset it is assumed to contain space, tab, and newline,
-all of which are
-.Ev IFS
-whitespace characters.
-If
-.Ev IFS
-is set to a null string, there are no delimiters,
-and no field splitting occurs.
-.Ss Pathname Expansion (File Name Generation)
-Unless the
-.Fl f
-flag is set, file name generation is performed after word splitting is
-complete.
-Each word is viewed as a series of patterns, separated by slashes.
-The process of expansion replaces the word with the names of all
-existing files whose names can be formed by replacing each pattern with a
-string that matches the specified pattern.
-There are two restrictions on
-this: first, a pattern cannot match a string containing a slash, and
-second, a pattern cannot match a string starting with a period unless the
-first character of the pattern is a period.
-The next section describes the
-patterns used for both Pathname Expansion and the
-.Ic case
-command.
-.Ss Shell Patterns
-A pattern consists of normal characters, which match themselves,
-and meta-characters.
-The meta-characters are
-.Dq \&! ,
-.Dq * ,
-.Dq \&? ,
-and
-.Dq \&[ .
-These characters lose their special meanings if they are quoted.
-When command or variable substitution is performed
-and the dollar sign or backquotes are not double-quoted,
-the value of the variable or the output of
-the command is scanned for these characters and they are turned into
-meta-characters.
-.Pp
-An asterisk
-.Pq Dq *
-matches any string of characters.
-A question mark
-.Pq Dq \&?
-matches any single character.
-A left bracket
-.Pq Dq \&[
-introduces a character class.
-The end of the character class is indicated by a right bracket
-.Pq Dq \&] ;
-if this
-.Dq \&]
-is missing then the
-.Dq \&[
-matches a
-.Dq \&[
-rather than introducing a character class.
-A character class matches any of the characters between the square brackets.
-A named class of characters (see
-.Xr wctype 3 )
-may be specified by surrounding the name with
-.Pq Dq [:
-and
-.Pq Dq :] .
-For example,
-.Pq Dq [[:alpha:]]
-is a shell pattern that matches a single letter.
-A range of characters may be specified using a minus sign
-.Pq Dq \(mi .
-The character class may be complemented
-by making an exclamation mark
-.Pq Dq \&!
-the first character of the character class.
-.Pp
-To include a
-.Dq \&]
-in a character class, make it the first character listed (after the
-.Dq \&! ,
-if any).
-To include a
-.Dq \(mi ,
-make it the first (after !) or last character listed.
-If both
-.Dq \&]
-and
-.Dq \(mi
-are to be included, the
-.Dq \&]
-must be first (after !)
-and the
-.Dq \(mi
-last, in the character class.
-.\"
-.\"
-.Ss Built-ins
-.\"
-This section lists the built-in commands which are built-in because they
-need to perform some operation that can't be performed by a separate
-process.
-Or just because they traditionally are.
-In addition to these, there are several other commands that may
-be built in for efficiency (e.g.
-.Xr printf 1 ,
-.Xr echo 1 ,
-.Xr test 1 ,
-etc).
-.Bl -tag -width 5n
-.It Ic \&: Op Ar arg ...
-A null command that returns a 0 (true) exit value.
-Any arguments or redirects are evaluated, then ignored.
-.\"
-.It Ic \&. Ar file
-The dot command reads and executes the commands from the specified
-.Ar file
-in the current shell environment.
-The file does not need to be executable and is looked up from the directories
-listed in the
-.Ev PATH
-variable if its name does not contain a directory separator
-.Pq Sq / .
-The
-.Ic return
-command (see below)
-can be used for a premature return from the sourced file.
-.Pp
-The POSIX standard has been unclear on how loop control keywords (break
-and continue) behave across a dot command boundary.
-This implementation allows them to control loops surrounding the dot command,
-but obviously such behavior should not be relied on.
-It is now permitted by the standard, but not required.
-.\"
-.It Ic alias Op Ar name Ns Op Li = Ns Ar string ...
-If
-.Ar name Ns Li = Ns Ar string
-is specified, the shell defines the alias
-.Ar name
-with value
-.Ar string .
-If just
-.Ar name
-is specified, the value of the alias
-.Ar name
-is printed.
-With no arguments, the
-.Ic alias
-built-in prints the
-names and values of all defined aliases (see
-.Ic unalias ) .
-.\"
-.It Ic bg Op Ar job ...
-Continue the specified jobs (or the current job if no
-jobs are given) in the background.
-.\"
-.It Ic command Oo Fl pVv Oc Ar command Op Ar arg ...
-Execute the specified command but ignore shell functions when searching
-for it.
-(This is useful when you
-have a shell function with the same name as a command.)
-.Bl -tag -width 5n
-.It Fl p
-search for command using a
-.Ev PATH
-that guarantees to find all the standard utilities.
-.It Fl V
-Do not execute the command but
-search for the command and print the resolution of the
-command search.
-This is the same as the
-.Ic type
-built-in.
-.It Fl v
-Do not execute the command but
-search for the command and print the absolute pathname
-of utilities, the name for built-ins or the expansion of aliases.
-.El
-.\"
-.It Ic cd Oo Fl P Oc Op Ar directory Op Ar replace
-Switch to the specified directory (default
-.Ev $HOME ) .
-If
-.Ar replace
-is specified, then the new directory name is generated by replacing
-the first occurrence of the string
-.Ar directory
-in the current directory name with
-.Ar replace .
-Otherwise if
-.Ar directory
-is
-.Sq Li - ,
-then the current working directory is changed to the previous current
-working directory as set in
-.Ev OLDPWD .
-Otherwise if an entry for
-.Ev CDPATH
-appears in the environment of the
-.Ic cd
-command or the shell variable
-.Ev CDPATH
-is set and the directory name does not begin with a slash,
-and its first (or only) component isn't dot or dot dot,
-then the directories listed in
-.Ev CDPATH
-will be searched for the specified directory.
-The format of
-.Ev CDPATH
-is the same as that of
-.Ev PATH .
-.Pp
-The
-.Fl P
-option instructs the shell to update
-.Ev PWD
-with the specified physical directory path and change to that directory.
-This is the default.
-.Pp
-When the directory changes, the variable
-.Ev OLDPWD
-is set to the working directory before the change.
-.Pp
-Some shells also support a
-.Fl L
-option, which instructs the shell to update
-.Ev PWD
-with the logical path and to change the current directory
-accordingly.
-This is not supported.
-.Pp
-In an interactive shell, the
-.Ic cd
-command will print out the name of the
-directory that it actually switched to if this is different from the name
-that the user gave,
-or always if the
-.Cm cdprint
-option is set.
-The destination may be different either because the
-.Ev CDPATH
-mechanism was used
-.\" or because a symbolic link was crossed.
-or if the
-.Ar replace
-argument was used.
-.\"
-.It Ic eval Ar string ...
-Concatenate all the arguments with spaces.
-Then re-parse and execute the command.
-.\"
-.It Ic exec Op Ar command Op Ar arg ...
-Unless
-.Ar command
-is omitted, the shell process is replaced with the
-specified program (which must be a real program, not a shell built-in or
-function).
-Any redirections on the
-.Ic exec
-command are marked as permanent, so that they are not undone when the
-.Ic exec
-command finishes.
-When the
-.Cm posix
-option is not set,
-file descriptors created via such redirections are marked close-on-exec
-(see
-.Xr open 2
-.Dv O_CLOEXEC
-or
-.Xr fcntl 2
-.Dv F_SETFD /
-.Dv FD_CLOEXEC ) ,
-unless the descriptors refer to the standard input,
-output, or error (file descriptors 0, 1, 2).
-Traditionally Bourne-like shells
-(except
-.Xr ksh 1 ) ,
-made those file descriptors available to exec'ed processes.
-To be assured the close-on-exec setting is off,
-redirect the descriptor to (or from) itself,
-either when invoking a command for which the descriptor is wanted open,
-or by using
-.Ic exec
-(perhaps the same
-.Ic exec
-as opened it, after the open)
-to leave the descriptor open in the shell
-and pass it to all commands invoked subsequently.
-Alternatively, see the
-.Ic fdflags
-command below, which can set, or clear, this, and other,
-file descriptor flags.
-.\"
-.It Ic exit Op Ar exitstatus
-Terminate the shell process.
-If
-.Ar exitstatus
-is given it is used as the exit status of the shell; otherwise the
-exit status of the preceding command (the current value of $?) is used.
-.\"
-.It Ic export Oo Fl nx Oc Ar name Ns Oo =value Oc ...
-.It Ic export Oo Fl x Oc Oo Fl p Oo Ar name ... Oc Oc
-.It Ic export Fl q Oo Fl x Oc Ar name ...
-With no options,
-but one or more names,
-the specified names are exported so that they will appear in the
-environment of subsequent commands.
-With
-.Fl n
-the specified names are un-exported.
-Variables can also be un-exported using the
-.Ic unset
-built in command.
-With
-.Fl x
-(exclude) the specified names are marked not to be exported,
-and any that had been exported, will be un-exported.
-Later attempts to export the variable will be refused.
-Note this does not prevent explicitly exporting a variable
-to a single command, script or function by preceding that
-command invocation by a variable assignment to that variable,
-provided the variable is not also read-only.
-That is
-.Bd -literal -offset indent
-export -x FOO # FOO will now not be exported by default
-export FOO # this command will fail (non-fatally)
-FOO=some_value my_command
-.Ed
-.Pp
-still passes the value
-.Pq Li FOO=some_value
-to
-.Li my_command
-through the environment.
-.Pp
-The shell allows the value of a variable to be set at the
-same time it is exported (or unexported, etc) by writing
-.Pp
-.Dl export [-nx] name=value
-.Pp
-With no arguments the export command lists the names of all
-set exported variables,
-or if
-.Fl x
-was given, all set variables marked not for export.
-With the
-.Fl p
-option specified, the output will be formatted suitably for
-non-interactive use, and unset variables are included.
-When
-.Fl p
-is given, variable names, but not values, may also be
-given, in which case output is limited to the variables named.
-.Pp
-With
-.Fl q
-and a list of variable names, the
-.Ic export
-command will exit with status 0 if all the named
-variables have been marked for export, or 1 if
-any are not so marked.
-If
-.Fl x
-is also given,
-the test is instead for variables marked not to be exported.
-.Pp
-Other than with
-.Fl q ,
-the
-.Ic export
-built-in exits with status 0,
-unless an attempt is made to export a variable which has
-been marked as unavailable for export,
-in which cases it exits with status 1.
-In all cases if
-an invalid option, or option combination, is given,
-or an invalid variable name is present,
-.Ic export
-will write a message to the standard error output,
-and exit with a non-zero status.
-A non-interactive shell will terminate.
-.Pp
-Note that there is no restriction upon exporting,
-or un-exporting, read-only variables.
-The no-export flag can be reset by unsetting the variable
-and creating it again \(en provided the variable is not also read-only.
-.\"
-.It Ic fc Oo Fl e Ar editor Oc Op Ar first Op Ar last
-.It Ic fc Fl l Oo Fl nr Oc Op Ar first Op Ar last
-.It Ic fc Fl s Oo Ar old=new Oc Op Ar first
-The
-.Ic fc
-built-in lists, or edits and re-executes, commands previously entered
-to an interactive shell.
-.Bl -tag -width 5n
-.It Fl e Ar editor
-Use the editor named by
-.Ar editor
-to edit the commands.
-The
-.Ar editor
-string is a command name, subject to search via the
-.Ev PATH
-variable.
-The value in the
-.Ev FCEDIT
-variable is used as a default when
-.Fl e
-is not specified.
-If
-.Ev FCEDIT
-is null or unset, the value of the
-.Ev EDITOR
-variable is used.
-If
-.Ev EDITOR
-is null or unset,
-.Xr ed 1
-is used as the editor.
-.It Fl l No (ell)
-List the commands rather than invoking an editor on them.
-The commands are written in the sequence indicated by
-the first and last operands, as affected by
-.Fl r ,
-with each command preceded by the command number.
-.It Fl n
-Suppress command numbers when listing with
-.Fl l .
-.It Fl r
-Reverse the order of the commands listed (with
-.Fl l )
-or edited (with neither
-.Fl l
-nor
-.Fl s ) .
-.It Fl s
-Re-execute the command without invoking an editor.
-.It Ar first
-.It Ar last
-Select the commands to list or edit.
-The number of previous commands that
-can be accessed are determined by the value of the
-.Ev HISTSIZE
-variable.
-The value of
-.Ar first
-or
-.Ar last
-or both are one of the following:
-.Bl -tag -width 5n
-.It Oo Cm + Oc Ns Ar number
-A positive number representing a command number; command numbers can be
-displayed with the
-.Fl l
-option.
-.It Cm \- Ns Ar number
-A negative decimal number representing the command that was executed
-number of commands previously.
-For example, \-1 is the immediately previous command.
-.El
-.It Ar string
-A string indicating the most recently entered command that begins with
-that string.
-If the
-.Ar old Ns Li = Ns Ar new
-operand is not also specified with
-.Fl s ,
-the string form of the first operand cannot contain an embedded equal sign.
-.El
-.Pp
-The following environment variables affect the execution of
-.Ic fc :
-.Bl -tag -width HISTSIZE
-.It Ev FCEDIT
-Name of the editor to use.
-.It Ev HISTSIZE
-The number of previous commands that are accessible.
-.El
-.\"
-.It Ic fg Op Ar job
-Move the specified job or the current job to the foreground.
-A foreground job can interact with the user via standard input,
-and receive signals from the terminal.
-.\"
-.It Ic fdflags Oo Fl v Oc Op Ar fd ...
-.It Ic fdflags Oo Fl v Oc Fl s Ar flags fd Op ...
-Get or set file descriptor flags.
-The
-.Fl v
-argument enables verbose printing, printing flags that are also off, and
-the flags of the file descriptor being set after setting.
-The
-.Fl s
-flag interprets the
-.Ar flags
-argument as a comma separated list of file descriptor flags, each preceded
-with a
-.Dq \(pl
-or a
-.Dq \(mi
-indicating to set or clear the respective flag.
-Valid flags are:
-.Cm append ,
-.Cm async ,
-.Cm sync ,
-.Cm nonblock ,
-.Cm fsync ,
-.Cm dsync ,
-.Cm rsync ,
-.Cm direct ,
-.Cm nosigpipe ,
-and
-.Cm cloexec .
-Unique abbreviations of these names, of at least 2 characters,
-may be used on input.
-See
-.Xr fcntl 2
-and
-.Xr open 2
-for more information.
-.\"
-.It Ic getopts Ar optstring var
-The POSIX
-.Ic getopts
-command, not to be confused with the
-Bell Labs\[en]derived
-.Xr getopt 1 .
-.Pp
-The first argument should be a series of letters, each of which may be
-optionally followed by a colon to indicate that the option requires an
-argument.
-The variable specified is set to the parsed option.
-.Pp
-The
-.Ic getopts
-command deprecates the older
-.Xr getopt 1
-utility due to its handling of arguments containing whitespace.
-.Pp
-The
-.Ic getopts
-built-in may be used to obtain options and their arguments
-from a list of parameters.
-When invoked,
-.Ic getopts
-places the value of the next option from the option string in the list in
-the shell variable specified by
-.Ar var
-and its index in the shell variable
-.Ev OPTIND .
-When the shell is invoked,
-.Ev OPTIND
-is initialized to 1.
-For each option that requires an argument, the
-.Ic getopts
-built-in will place it in the shell variable
-.Ev OPTARG .
-If an option is not allowed for in the
-.Ar optstring ,
-then
-.Ev OPTARG
-will be unset.
-.Pp
-.Ar optstring
-is a string of recognized option letters (see
-.Xr getopt 3 ) .
-If a letter is followed by a colon, the option is expected to have an
-argument which may or may not be separated from it by whitespace.
-If an option character is not found where expected,
-.Ic getopts
-will set the variable
-.Ar var
-to a
-.Sq Li \&? ;
-.Ic getopts
-will then unset
-.Ev OPTARG
-and write output to standard error.
-By specifying a colon as the first character of
-.Ar optstring
-all errors will be ignored.
-.Pp
-A nonzero value is returned when the last option is reached.
-If there are no remaining arguments,
-.Ic getopts
-will set
-.Ar var
-to the special option,
-.Dq Li \-\- ,
-otherwise, it will set
-.Ar var
-to
-.Sq Li \&? .
-.Pp
-The following code fragment shows how one might process the arguments
-for a command that can take the options
-.Fl a
-and
-.Fl b ,
-and the option
-.Fl c ,
-which requires an argument.
-.Bd -literal -offset indent
-while getopts abc: f
-do
- case $f in
- a | b) flag=$f;;
- c) carg=$OPTARG;;
- \e?) echo $USAGE; exit 1;;
- esac
-done
-shift $((OPTIND - 1))
-.Ed
-.Pp
-This code will accept any of the following as equivalent:
-.Bd -literal -offset indent
-cmd \-acarg file file
-cmd \-a \-c arg file file
-cmd \-carg -a file file
-cmd \-a \-carg \-\- file file
-.Ed
-.\"
-.It Ic hash Oo Fl rv Oc Op Ar command ...
-The shell maintains a hash table which remembers the
-locations of commands.
-With no arguments whatsoever,
-the
-.Ic hash
-command prints out the contents of this table.
-Entries which have not been looked at since the last
-.Ic cd
-command are marked with an asterisk; it is possible for these entries
-to be invalid.
-.Pp
-With arguments, the
-.Ic hash
-command removes the specified commands from the hash table (unless
-they are functions) and then locates them.
-With the
-.Fl v
-option, hash prints the locations of the commands as it finds them.
-The
-.Fl r
-option causes the hash command to delete all the entries in the hash table
-except for functions.
-.\"
-.It Ic inputrc Ar file
-Read the
-.Ar file
-to set key bindings as defined by
-.Xr editrc 5 .
-.\"
-.It Ic jobid Oo Fl g Ns \&| Ns Fl j Ns \&| Ns Fl p Oc Op Ar job
-With no flags, print the process identifiers of the processes in the job.
-If the
-.Ar job
-argument is omitted, the current job is used.
-Any of the ways to select a job may be used for
-.Ar job ,
-including the
-.Sq Li \&%
-forms, or the process id of the job leader
-.Po
-.Dq Li \&$!
-if the job was created in the background.
-.Pc
-.Pp
-If one of the flags is given, then instead of the list of
-process identifiers, the
-.Ic jobid
-command prints:
-.Bl -tag -width ".Fl g"
-.It Fl g
-the process group, if one was created for this job,
-or nothing otherwise (the job is in the same process
-group as the shell.)
-.It Fl j
-the job identifier (using
-.Dq Li \&% Ns Ar n
-notation, where
-.Ar n
-is a number) is printed.
-.It Fl p
-only the process id of the process group leader is printed.
-.El
-.Pp
-These flags are mutually exclusive.
-.Pp
-.Ic jobid
-exits with status 2 if there is an argument error,
-status 1, if with
-.Fl g
-the job had no separate process group,
-or with
-.Fl p
-there is no process group leader (should not happen),
-and otherwise exits with status 0.
-.\"
-.It Ic jobs Oo Fl l Ns \&| Ns Fl p Oc Op Ar job ...
-Without
-.Ar job
-arguments,
-this command lists out all the background processes
-which are children of the current shell process.
-With
-.Ar job
-arguments, the listed jobs are shown instead.
-Without flags, the output contains the job
-identifier (see
-.Sx Job Control
-below), an indicator character if the job is the current or previous job,
-the current status of the job (running, suspended, or terminated successfully,
-unsuccessfully, or by a signal)
-and a (usually abbreviated) command string.
-.Pp
-With the
-.Fl l
-flag the output is in a longer form, with the process identifiers
-of each process (run from the top level, as in a pipeline), and the
-status of each process, rather than the job status.
-.Pp
-With the
-.Fl p
-flag, the output contains only the process identifier of the lead
-process.
-.Pp
-In an interactive shell, each job shown as completed in the output
-from the jobs command is implicitly waited for, and is removed from
-the jobs table, never to be seen again.
-In an interactive shell, when a background job terminates, the
-.Ic jobs
-command (with that job as an argument) is implicitly run just
-before outputting the next PS1 command prompt, after the job
-terminated.
-This indicates that the job finished, shows its status,
-and cleans up the job table entry for that job.
-Non-interactive shells need to execute
-.Ic wait
-commands to clean up terminated background jobs.
-.\"
-.It Ic local Oo Fl INx Oc Oo Ar variable | \- Oc ...
-Define local variables for a function.
-Local variables have their attributes, and values,
-as they were before the
-.Ic local
-declaration, restored when the function terminates.
-.Pp
-With the
-.Fl N
-flag, variables made local, are unset initially inside
-the function.
-Unless the
-.Fl x
-flag is also given, such variables are also unexported.
-The
-.Fl I
-flag, which is the default in this shell, causes
-the initial value and exported attribute
-of local variables
-to be inherited from the variable
-with the same name in the surrounding
-scope, if there is one.
-If there is not, the variable is initially unset,
-and not exported.
-The
-.Fl N
-and
-.Fl I
-flags are mutually exclusive, if both are given, the last specified applies.
-The read-only and unexportable attributes are always
-inherited, if a variable with the same name already exists.
-.Pp
-The
-.Fl x
-flag (lower case) causes the local variable to be exported,
-while the function runs, unless it has the unexportable attribute.
-This can also be accomplished by using the
-.Ic export
-command, giving the same
-.Ar variable
-names, after the
-.Ic local
-command.
-.Pp
-Making an existing read-only variable local is possible,
-but pointless.
-If an attempt is made to assign an initial value to such
-a variable, the
-.Ic local
-command fails, as does any later attempted assignment.
-If the
-.Ic readonly
-command is applied to a variable that has been declared local,
-the variable cannot be (further) modified within the function,
-or any other functions it calls, however when the function returns,
-the previous status (and value) of the variable is returned.
-.Pp
-Values may be given to local variables on the
-.Ic local
-command line in a similar fashion as used for
-.Ic export
-and
-.Ic readonly .
-These values are assigned immediately after the initialization
-described above.
-Note that any variable references on the command line will have
-been expanded before
-.Ic local
-is executed, so expressions like
-.Pp
-.Dl "local -N X=${X}"
-.Pp
-are well defined, first $X is expanded, and then the command run is
-.Pp
-.Dl "local -N X=old-value-of-X"
-.Pp
-After arranging to preserve the old value and attributes, of
-.Dv X
-.Dq ( old-value-of X )
-.Ic local
-unsets
-.Dv X ,
-unexports it, and then assigns the
-.Dq old-value-of-X
-to
-.Ev X .
-.Pp
-The shell uses dynamic scoping, so that if you make the variable
-.Dv x
-local to
-function
-.Dv f ,
-which then calls function
-.Dv g ,
-references to the variable
-.Dv x
-made inside
-.Dv g
-will refer to the variable
-.Dv x
-declared inside
-.Dv f ,
-not to the global variable named
-.Dv x .
-.Pp
-Another way to view this, is as if the shell just has one flat, global,
-namespace, in which all variables exist.
-The
-.Ic local
-command conceptually copies the variable(s) named to unnamed temporary
-variables, and when the function ends, copies them back again.
-All references to the variables reference the same global variables,
-but while the function is active, after the
-.Ic local
-command has run, the values and attributes of the variables might
-be altered, and later, when the function completes, be restored.
-.Pp
-Note that the positional parameters
-.Dv 1 , \" $1
-.Dv 2 , \" $2
-\&... (see
-.Sx Positional Parameters ) ,
-and the special parameters
-.Dv \&# , \" $#
-.Dv \&* \" $*
-and
-.Dv \&@ \" $@
-(see
-.Sx Special Parameters ) ,
-are always made local in all functions, and are reset inside the
-function to represent the options and arguments passed to the function.
-Note that
-.Li $0
-however retains the value it had outside the function,
-as do all the other special parameters.
-.Pp
-The only special parameter that can optionally be made local is
-.Dq Li \- .
-Making
-.Dq Li \-
-local causes any shell options that are changed via the set command inside the
-function to be restored to their original values when the function
-returns.
-If
-.Fl X
-option is altered after
-.Dq Li \-
-has been made local, then when the function returns, the previous
-destination for
-.Cm xtrace
-output (as of the time of the
-.Ic local
-command) will also be restored.
-If any of the shell's magic variables
-(those which return a value which may vary without
-the variable being explicitly altered,
-e.g.:
-.Dv SECONDS
-or
-.Dv HOSTNAME )
-are made local in a function,
-they will lose their special properties when set
-within the function, including by the
-.Ic local
-command itself
-(if not to be set in the function, there is little point
-in making a variable local)
-but those properties will be restored when the function returns.
-.Pp
-It is an error to use
-.Ic local
-outside the scope of a function definition.
-When used inside a function, it exits with status 0,
-unless an undefined option is used, or an attempt is made to
-assign a value to a read-only variable.
-.Pp
-Note that either
-.Fl I
-or
-.Fl N
-should always be used, or variables made local should always
-be given a value, or explicitly unset, as the default behavior
-(inheriting the earlier value, or starting unset after
-.Ic local )
-differs amongst shell implementations.
-Using
-.Dq Li local \&\-
-is an extension not implemented by most shells.
-.Pp
-See the section
-.Sx LINENO
-below for details of the effects of making the variable
-.Dv LINENO
-local.
-.\"
-.It Ic pwd Op Fl \&LP
-Print the current directory.
-If
-.Fl L
-is specified the cached value (initially set from
-.Ev PWD )
-is checked to see if it refers to the current directory; if it does
-the value is printed.
-Otherwise the current directory name is found using
-.Xr getcwd 3 .
-The environment variable
-.Ev PWD
-is set to the printed value.
-.Pp
-The default is
-.Ic pwd
-.Fl L ,
-but note that the built-in
-.Ic cd
-command doesn't support the
-.Fl L
-option and will cache (almost) the absolute path.
-If
-.Ic cd
-is changed (as unlikely as that is),
-.Ic pwd
-may be changed to default to
-.Ic pwd
-.Fl P .
-.Pp
-If the current directory is renamed and replaced by a symlink to the
-same directory, or the initial
-.Ev PWD
-value followed a symbolic link, then the cached value may not
-be the absolute path.
-.Pp
-The built-in command may differ from the program of the same name because
-the program will use
-.Ev PWD
-and the built-in uses a separately cached value.
-.\"
-.It Ic read Oo Fl p Ar prompt Oc Oo Fl r Oc Ar variable Op Ar ...
-The
-.Ar prompt
-is printed if the
-.Fl p
-option is specified and the standard input is a terminal.
-Then a line is read from the standard input.
-The trailing newline is deleted from the
-line and the line is split as described in the field splitting section of the
-.Sx Word Expansions
-section above, and the pieces are assigned to the variables in order.
-If there are more pieces than variables, the remaining pieces
-(along with the characters in
-.Ev IFS
-that separated them) are assigned to the last variable.
-If there are more variables than pieces,
-the remaining variables are assigned the null string.
-The
-.Ic read
-built-in will indicate success unless EOF is encountered on input, in
-which case failure is returned.
-.Pp
-By default, unless the
-.Fl r
-option is specified, the backslash
-.Dq \e
-acts as an escape character, causing the following character to be treated
-literally.
-If a backslash is followed by a newline, the backslash and the
-newline will be deleted.
-.\"
-.It Ic readonly Ar name Ns Oo =value Oc ...
-.It Ic readonly Oo Fl p Oo Ar name ... Oc Oc
-.It Ic readonly Fl q Ar name ...
-With no options,
-the specified names are marked as read only, so that they cannot be
-subsequently modified or unset.
-The shell allows the value of a variable
-to be set at the same time it is marked read only by writing
-.Pp
-.Dl readonly name=value
-.Pp
-With no arguments the
-.Ic readonly
-command lists the names of all set read only variables.
-With the
-.Fl p
-option specified,
-the output will be formatted suitably for non-interactive use,
-and unset variables are included.
-When the
-.Fl p
-option is given,
-a list of variable names (without values) may also be specified,
-in which case output is limited to the named variables.
-.Pp
-With the
-.Fl q
-option, the
-.Ic readonly
-command tests the read-only status of the variables listed
-and exits with status 0 if all named variables are read-only,
-or with status 1 if any are not read-only.
-.Pp
-Other than as specified for
-.Fl q
-the
-.Ic readonly
-command normally exits with status 0.
-In all cases, if an unknown option, or an invalid option combination,
-or an invalid variable name, is given;
-or a variable which was already read-only is attempted to be set;
-the exit status will not be zero, a diagnostic
-message will be written to the standard error output,
-and a non-interactive shell will terminate.
-.\"
-.It Ic return Op Ar n
-Stop executing the current function or a dot command with return value of
-.Ar n
-or the value of the last executed command, if not specified.
-For portability,
-.Ar n
-should be in the range from 0 to 255.
-.Pp
-The POSIX standard says that the results of
-.Ic return
-outside a function or a dot command are unspecified.
-This implementation treats such a return as a no-op with a return value of 0
-(success, true).
-Use the
-.Ic exit
-command instead, if you want to return from a script or exit
-your shell.
-.\"
-.It Ic set Oo { Fl options | Cm +options | Cm \-- } Oc Ar arg ...
-The
-.Ic set
-command performs four different functions.
-.Pp
-With no arguments, it lists the values of all shell variables.
-.Pp
-With a single option of either
-.Dq Fl o
-or
-.Dq Cm +o
-.Ic set
-outputs the current values of the options.
-In the
-.Fl o
-form, all options are listed, with their current values.
-In the
-.Cm +o
-form, the shell outputs a string that can later be used
-as a command to reset all options to their current values.
-.Pp
-If options are given, it sets the specified option
-flags, or clears them as described in the
-.Sx Argument List Processing
-section.
-In addition to the options listed there,
-when the
-.Dq "option name"
-given to
-.Ic set Fl o
-is
-.Cm default
-all of the options are reset to the values they had immediately
-after
-.Nm
-initialization, before any startup scripts, or other input, had been processed.
-While this may be of use to users or scripts, its primary purpose
-is for use in the output of
-.Dq Ic set Cm +o ,
-to avoid that command needing to list every available option.
-There is no
-.Cm +o default .
-.Pp
-The fourth use of the
-.Ic set
-command is to set the values of the shell's
-positional parameters to the specified arguments.
-To change the positional
-parameters without changing any options, use
-.Dq -\|-
-as the first argument to
-.Ic set .
-If no following arguments are present, the
-.Ic set
-command
-will clear all the positional parameters (equivalent to executing
-.Dq Li shift $# . )
-Otherwise the following arguments become
-.Li \&$1 ,
-.Li \&$2 ,
-\&...,
-and
-.Li \&$#
-is set to the number of arguments present.
-.\"
-.It Ic setvar Ar variable Ar value
-Assigns
-.Ar value
-to
-.Ar variable .
-(In general it is better to write
-.Li variable=value
-rather than using
-.Ic setvar .
-.Ic setvar
-is intended to be used in
-functions that assign values to variables whose names are passed as
-parameters.)
-.\"
-.It Ic shift Op Ar n
-Shift the positional parameters
-.Ar n
-times.
-If
-.Ar n
-is omitted, 1 is assumed.
-Each
-.Ic shift
-sets the value of
-.Li $1
-to the previous value of
-.Li $2 ,
-the value of
-.Li $2
-to the previous value of
-.Li $3 ,
-and so on, decreasing
-the value of
-.Li $#
-by one.
-The shift count must be less than or equal to the number of
-positional parameters (
-.Dq Li $# )
-before the shift.
-.\"
-.It Ic times
-Prints two lines to standard output.
-Each line contains two accumulated time values, expressed
-in minutes and seconds (including fractions of a second.)
-The first value gives the user time consumed, the second the system time.
-.Pp
-The first output line gives the CPU and system times consumed by the
-shell itself.
-The second line gives the accumulated times for children of this
-shell (and their descendants) which have exited, and then been
-successfully waited for by the relevant parent.
-See
-.Xr times 3
-for more information.
-.Pp
-.Ic times
-has no parameters, and exits with an exit status of 0 unless
-an attempt is made to give it an option.
-.\"
-.It Ic trap Ar action signal ...
-.It Ic trap \-
-.It Ic trap Op Fl l
-.It Ic trap Oo Fl p Oc Ar signal ...
-.It Ic trap Ar N signal ...
-.Pp
-Cause the shell to parse and execute action when any of the specified
-signals are received.
-The signals are specified by signal number or as the name of the signal.
-If
-.Ar signal
-is
-.Li 0 \" $0
-or its equivalent,
-.Li EXIT ,
-the action is executed when the shell exits.
-The
-.Ar action
-may be a null (empty) string,
-which causes the specified signals to be ignored.
-With
-.Ar action
-set to
-.Sq Li -
-the specified signals are set to their default actions.
-If the first
-.Ar signal
-is specified in its numeric form, then
-.Ar action
-can be omitted to achieve the same effect.
-This archaic,
-but still standard,
-form should not be relied upon, use the explicit
-.Sq Li -
-action.
-If no signals are specified with an action of
-.Sq Li - ,
-all signals are reset.
-.Pp
-When the shell forks off a sub-shell, it resets trapped (but not ignored)
-signals to the default action.
-On non-interactive shells, the
-.Ic trap
-command has no effect on signals that were
-ignored on entry to the shell.
-On interactive shells, the
-.Ic trap
-command will catch or reset signals ignored on entry.
-.Pp
-Issuing
-.Ic trap
-with option
-.Fl l
-will print a list of valid signal names.
-.Ic trap
-without any arguments causes it to write a list of signals and their
-associated non-default actions to the standard output in a format
-that is suitable as an input to the shell that achieves the same
-trapping results.
-With the
-.Fl p
-flag, trap prints the same information for the signals specified,
-or if none are given, for all signals, including those where the
-action is the default.
-These variants of the trap command may be executed in a sub-shell
-.Pq "such as in a command substitution" ,
-provided they appear as the sole, or first, command in that sub-shell,
-in which case the state of traps from the parent of that
-sub-shell is reported.
-.Pp
-Examples:
-.Pp
-.Dl trap
-.Pp
-List trapped signals and their corresponding actions.
-.Pp
-.Dl trap -l
-.Pp
-Print a list of valid signals.
-.Pp
-.Dl trap '' INT QUIT tstp 30
-.Pp
-Ignore signals INT QUIT TSTP USR1.
-.Pp
-.Dl trap date INT
-.Pp
-Run the
-.Dq date
-command (print the date) upon receiving signal INT.
-.Pp
-.Dl trap HUP INT
-.Pp
-Run the
-.Dq HUP
-command, or function, upon receiving signal INT.
-.Pp
-.Dl trap 1 2
-.Pp
-Reset the actions for signals 1 (HUP) and 2 (INT) to their defaults.
-.Bd -literal -offset indent
-traps=$(trap -p)
- # more commands ...
-trap 'action' SIG
- # more commands ...
-eval "$traps"
-.Ed
-.Pp
-Save the trap status, execute commands, changing some traps,
-and then reset all traps to their values at the start of the sequence.
-The
-.Fl p
-option is required in the first command here,
-or any signals that were previously
-untrapped (in their default states)
-and which were altered during the intermediate code,
-would not be reset by the final
-.Ic eval .
-.\"
-.It Ic type Op Ar name ...
-Interpret each
-.Ar name
-as a command and print the resolution of the command search.
-Possible resolutions are:
-shell keyword, alias, shell built-in,
-command, tracked alias and not found.
-For aliases the alias expansion is
-printed; for commands and tracked aliases the complete pathname of the
-command is printed.
-.\"
-.It Ic ulimit Oo Fl H Ns \*(Ba Ns Fl S Oc Op Fl a \*(Ba Fl btfdscmlrpnv Op Ar value
-Inquire about or set the hard or soft limits on processes or set new
-limits.
-The choice between hard limit (which no process is allowed to
-violate, and which may not be raised once it has been lowered) and soft
-limit (which causes processes to be signaled but not necessarily killed,
-and which may be raised) is made with these flags:
-.Bl -tag -width Fl
-.It Fl H
-set or inquire about hard limits
-.It Fl S
-set or inquire about soft limits.
-.El
-.Pp
-If neither
-.Fl H
-nor
-.Fl S
-is specified, the soft limit is displayed or both limits are set.
-If both are specified, the last one wins.
-.Pp
-The limit to be interrogated or set, then, is chosen by specifying
-any one of these flags:
-.Bl -tag -width Fl
-.It Fl a
-show all the current limits
-.It Fl b
-the socket buffer size of a process (bytes)
-.It Fl c
-the largest core dump size that can be produced
-(512-byte blocks)
-.It Fl d
-the data segment size of a process (kilobytes)
-.It Fl f
-the largest file that can be created
-(512-byte blocks)
-.It Fl l
-how much memory a process can lock with
-.Xr mlock 2
-(kilobytes)
-.It Fl m
-the total physical memory that can be
-in use by a process (kilobytes)
-.It Fl n
-the number of files a process can have open at once
-.It Fl p
-the number of processes this user can
-have at one time
-.It Fl r
-the number of threads this user can
-have at one time
-.It Fl s
-the stack size of a process (kilobytes)
-.It Fl t
-CPU time (seconds)
-.It Fl v
-how large a process address space can be
-.El
-.Pp
-If none of these is specified, it is the limit on file size that is shown
-or set.
-If value is specified, the limit is set to that number; otherwise
-the current limit is displayed.
-.Pp
-Limits of an arbitrary process can be displayed or set using the
-.Xr sysctl 8
-utility.
-.It Ic umask Oo Fl S Oc Op Ar mask
-Set the value of umask (see
-.Xr umask 2 )
-to the specified octal value.
-If the argument is omitted, the umask value is printed.
-With
-.Fl S
-a symbolic form is used instead of an octal number.
-.It Ic unalias Oo Fl a Oc Op Ar name
-If
-.Ar name
-is specified, the shell removes that alias.
-If
-.Fl a
-is specified, all aliases are removed.
-.It Ic unset Oo Fl efvx Oc Ar name ...
-If
-.Fl v
-is specified, the specified variables are unset and unexported.
-Readonly variables cannot be unset.
-If
-.Fl f
-is specified, the specified functions are undefined.
-If
-.Fl e
-is given, the specified variables are unexported, but otherwise unchanged,
-alternatively, if
-.Fl x
-is given, the exported status of the variable will be retained,
-even after it is unset.
-.Pp
-If no flags are provided
-.Fl v
-is assumed.
-If
-.Fl f
-is given with one of the other flags,
-then the named variables will be unset, or unexported, and functions
-of the same names will be undefined.
-The
-.Fl e
-and
-.Fl x
-flags both imply
-.Fl v .
-If
-.Fl e
-is given, the
-.Fl x
-flag is ignored.
-.Pp
-The exit status is 0, unless an attempt was made to unset
-a readonly variable, in which case the exit status is 1.
-It is not an error to unset (or undefine) a variable (or function)
-that is not currently set (or defined.)
-.\"
-.It Ic wait Oo Fl n Oc Oo Fl p Ar var Oc Op Ar job ...
-Wait for the specified jobs to complete
-and return the exit status of the last job in the parameter list,
-or 127 if that job is not a current child of the shell.
-.Pp
-If no
-.Ar job
-arguments are given, wait for all jobs to
-complete and then return an exit status of zero
-(including when there were no jobs, and so nothing exited.)
-.Pp
-With the
-.Fl n
-option, wait instead for any one of the given
-.Ar job Ns s,
-or if none are given, any job, to complete, and
-return the exit status of that job.
-If none of the given
-.Ar job
-arguments is a current child of the shell,
-or if no
-.Ar job
-arguments are given and the shell has no unwaited for children,
-then the exit status will be 127.
-.Pp
-The
-.Fl p Ar var
-option allows the process (or job) identifier of the
-job for which the exit status is returned to be obtained.
-The variable named (which must not be readonly) will be
-unset initially, then if a job has exited and its status is
-being returned, set to the identifier from the
-arg list (if given) of that job,
-or the lead process identifier of the job to exit when used with
-.Fl n
-and no job arguments.
-Note that
-.Fl p
-with neither
-.Fl n
-nor
-.Ar job
-arguments is useless, as in that case no job status is
-returned, the variable named is simply unset.
-.Pp
-If the wait is interrupted by a signal,
-its exit status will be greater than 128,
-and
-.Ar var ,
-if given, will remain unset.
-.Pp
-Once waited upon, by specific process number or job-id,
-or by a
-.Ic wait
-with no arguments,
-knowledge of the child is removed from the system,
-and it cannot be waited upon again.
-.Pp
-Note than when a list of jobs are given, more that
-one argument might refer to the same job.
-In that case, if the final argument represents a job
-that is also given earlier in the list, it is not
-defined whether the status returned will be the
-exit status of the job, or 127 indicating that
-the child no longer existed when the wait command
-reached the later argument in the list.
-In this
-.Nm
-the exit status will be that from the job.
-.Nm
-waits for each job exactly once, regardless of
-how many times (or how many different ways) it
-is listed in the arguments to
-.Ic wait .
-That is
-.Bd -literal -offset indent -compact
-wait 100 100 100
-.Ed
-is identical to
-.Bd -literal -offset indent -compact
-wait 100
-.Ed
-.El
-.\"
-.\"
-.Ss Job Control
-.\"
-Each process (or set of processes) started by
-.Nm
-is created as a
-.Dq job
-and added to the jobs table.
-When enabled by the
-.Fl m
-option
-.Pq aka Fl o Cm monitor
-when the job is created,
-.Nm
-places each job (if run from the top level shell)
-into a process group of its own, which allows control
-of the process(es), and its/their descendants, as a unit.
-When the
-.Fl m
-option is off, or when started from a sub-shell environment,
-jobs share the same process group as the parent shell.
-The
-.Fl m
-option is enabled by default in interactive shells with
-a terminal as standard input and standard error.
-.Pp
-Jobs with separate process groups may be stopped, and then later
-resumed in the foreground (with access to the terminal)
-or in the background (where attempting to read from the
-terminal will result in the job stopping.)
-A list of current jobs can be obtained using the
-.Ic jobs
-built-in command.
-Jobs are identified using either the process identifier
-of the lead process of the job (the value available in
-the special parameter
-.Dq Dv \&!
-if the job is started in the background), or using percent
-notation.
-Each job is given a
-.Dq job number
-which is a small integer, starting from 1, and can be
-referenced as
-.Dq Li \&% Ns Ar n
-where
-.Ar n
-is that number.
-Note that this applies to jobs both with and without their own process groups.
-Job numbers are shown in the output from the
-.Ic jobs
-command enclosed in brackets
-.Po
-.Sq Li \&[
-and
-.Sq Li \&]
-.Pc .
-Whenever the job table becomes empty, the numbers begin at one again.
-In addition, there is the concept of a current, and a previous job,
-identified by
-.Dq Li \&%+
-.Po
-or
-.Dq Li \&%%
-or even just
-.Dq Li \&%
-.Pc ,
-and a previous job, identified by
-.Dq Li \&%\- .
-Whenever a background job is started,
-or a job is resumed in the background,
-it becomes the current job.
-The job that was the current job
-(prepare for a big surprise here, drum roll..., wait for it...\&)
-becomes the previous job.
-When the current job terminates, the previous job is
-promoted to be the current job.
-In addition the form
-.Dq Li \&% Ns Ar string\^
-finds the job for which the command starts with
-.Ar string
-and the form
-.Dq Li \&%? Ns Ar string\^
-finds the job which contains the
-.Ar string
-in its command somewhere.
-Both forms require the result to be unambiguous.
-For this purpose the
-.Dq command
-is that shown in the output from the
-.Ic jobs
-command, not the original command line.
-.Pp
-The
-.Ic bg ,
-.Ic fg ,
-.Ic jobid ,
-.Ic jobs ,
-.Ic kill ,
-and
-.Ic wait
-commands all accept job identifiers as arguments, in addition to
-process identifiers (larger integers).
-See the
-.Sx Built-ins
-section above, and
-.Xr kill 1 ,
-for more details of those commands.
-In addition, a job identifier
-(using one of the
-.Dq \&% forms )
-issued as a command, without arguments, is interpreted as
-if it had been given as the argument to the
-.Ic fg
-command.
-.Pp
-To cause a foreground process to stop, enter the terminal's
-.Ic stop
-character (usually control-Z).
-To cause a background process to stop, send it a
-.Dv STOP
-signal, using the kill command.
-A useful function to define is
-.Bd -literal -offset indent
-stop() { kill -s STOP "${@:-%%}"; }
-.Ed
-.Pp
-The
-.Ic fg
-command resumes a stopped job, placing it in the foreground,
-and
-.Ic bg
-resumes a stopped job in the background.
-The
-.Ic jobid
-command provides information about process identifiers, job identifiers,
-and the process group identifier, for a job.
-.Pp
-Whenever a sub-shell is created, the jobs table becomes invalid
-(the sub-shell has no children.)
-However, to enable uses like
-.Bd -literal -offset indent
-PID=$(jobid -p %1)
-.Ed
-.Pp
-the table is only actually cleared in a sub-shell when needed to
-create the first job there (built-in commands run in the foreground
-do not create jobs.)
-Note that in this environment, there is no useful current job
-.Dq ( Li \&%%
-actually refers to the sub-shell itself, but is not accessible)
-but the job which is the current job in the parent can be accessed as
-.Dq Li \&%\- .
-.\"
-.\"
-.Ss Command Line Editing
-.\"
-When
-.Nm
-is being used interactively from a terminal, the current command
-and the command history (see
-.Ic fc
-in the
-.Sx Built-ins
-section)
-can be edited using emacs-mode or vi-mode command-line editing.
-The command
-.Ql set -o emacs
-(or
-.Fl E
-option)
-enables emacs-mode editing.
-The command
-.Ql set -o vi
-(or
-.Fl V
-option)
-enables vi-mode editing and places the current shell process into
-vi insert mode.
-(See the
-.Sx Argument List Processing
-section above.)
-.Pp
-The vi-mode uses commands similar to a subset of those described in the
-.Xr vi 1
-man page.
-With vi-mode
-enabled,
-.Nm sh
-can be switched between insert mode and command mode.
-It's similar to
-.Ic vi :
-pressing the
-.Aq ESC
-key will throw you into vi command mode.
-Pressing the
-.Aq return
-key while in command mode will pass the line to the shell.
-.Pp
-The emacs-mode uses commands similar to a subset available in the
-.Ic emacs
-editor.
-With emacs-mode enabled, special keys can be used to modify the text
-in the buffer using the control key.
-.Pp
-.Nm
-uses the
-.Xr editline 3
-library.
-See
-.Xr editline 7
-for a list of the possible command bindings,
-and the default settings in emacs and vi modes.
-Also see
-.Xr editrc 5
-for the commands that can be given to configure
-.Xr editline 7
-in the file named by the
-.Ev EDITRC
-parameter,
-or a file used with the
-.Ic inputrc
-built-in command,
-or using
-.Xr editline 7 Ap s
-configuration command line.
-.Pp
-When command line editing is enabled, the
-.Xr editline 7
-functions control printing of the
-.Ev PS1
-and
-.Ev PS2
-prompts when required.
-As, in this mode, the command line editor needs to
-keep track of what characters are in what position on
-the command line, care needs to be taken when setting
-the prompts.
-Normal printing characters are handled automatically,
-however mode setting sequences, which do not actually display
-on the terminal, need to be identified to
-.Xr editline 7 .
-This is done, when needed, by choosing a character that
-is not needed anywhere in the prompt, including in the mode
-setting sequences, any single character is acceptable,
-and assigning it to the shell parameter
-.Dv PSlit .
-Then that character should be used, in pairs, in the
-prompt string.
-Between each pair of
-.Dv PSlit
-characters are mode setting sequences, which affect the printing
-attributes of the following (normal) characters of the prompt,
-but do not themselves appear visibly, nor change the terminal's
-cursor position.
-.Pp
-Each such sequence, that is
-.Dv PSlit
-character, mode setting character sequence, and another
-.Dv PSlit
-character, must currently be followed by at least one following
-normal prompt character, or it will be ignored.
-That is, a
-.Dv PSlit
-character cannot be the final character of
-.Ev PS1
-or
-.Ev PS2 ,
-nor may two
-.Dv PSlit
-delimited sequences appear adjacent to each other.
-Each sequence can contain as many mode altering sequences as are
-required however.
-Only the first character from
-.Dv PSlit
-will be used.
-When set
-.Dv PSlit
-should usually be set to a string containing just one
-character, then it can simply be embedded in
-.Ev PS1
-(or
-.Ev PS2 )
-as in
-.Pp
-.D1 Li PS1=\*q${PSlit} Ns Ar mset\^ Ns Li ${PSlit}XYZ${PSlit} Ns Ar mclr\^ Ns Li ${PSlit}ABC\*q
-.Pp
-The prompt visible will be
-.Dq XYZABC
-with the
-.Dq XYZ
-part shown according as defined by the mode setting characters
-.Ar mset ,
-and then cleared again by
-.Ar mclr .
-See
-.Xr tput 1
-for one method to generate appropriate mode sequences.
-Note that both parts, XYZ and ABC, must each contain at least one
-character.
-.Pp
-If
-.Dv PSlit
-is unset, which is its initial state, or set to a null string,
-no literal character will be defined,
-and all characters of the prompt strings will be assumed
-to be visible characters (which includes spaces etc.)
-To allow smooth use of prompts, without needing redefinition, when
-.Xr editline 7
-is disabled, the character chosen should be one which will be
-ignored by the terminal if received, as when
-.Xr editline 7
-is not in use, the prompt strings are simply written to the terminal.
-For example, setting:
-.\" XXX: PS1 line is too long for -offset indent
-.Bd -literal -offset left
- PSlit="$(printf\ '\e1')"
- PS1="${PSlit}$(tput\ bold\ blink)${PSlit}\e$${PSlit}$(tput\ sgr0)${PSlit}\ "
-.Ed
-.Pp
-will arrange for the primary prompt to be a bold blinking dollar sign,
-if supported by the current terminal, followed by an (ordinary) space,
-and, as the SOH (control-A) character
-.Pq Sq \e1
-will not normally affect
-a terminal, this same prompt will usually work with
-.Xr editline 7
-enabled or disabled.
-.Sh ENVIRONMENT
-.Bl -tag -width MAILCHECK
-.It Ev CDPATH
-The search path used with the
-.Ic cd
-built-in.
-.It Ev EDITRC
-Gives the name of the file containing commands for
-.Xr editline 7 .
-See
-.Xr editrc 5
-for possible content and format.
-The file is processed, when in interactive mode with
-command line editing enabled, whenever
-.Ev EDITRC
-is set (even with no actual value change,)
-and if command line editing changes from disabled to enabled,
-or the editor style used is changed.
-(See the
-.Fl E
-and
-.Fl V
-options of the
-.Ic set
-built-in command, described in
-.Sx Built-ins
-above, which are documented further above in
-.Sx Argument List Processing . )
-If unset
-.Dq $HOME/.editrc
-is used.
-.It Ev ENV
-Names the file sourced at startup by the shell.
-Unused by this shell after initialization,
-but is usually passed through the environment to
-descendant shells.
-.It Ev EUSER
-Set to the login name of the effective user id running the shell,
-as returned by
-.Bd -compact -literal -offset indent
-getpwuid(geteuid())->pw_name
-.Ed
-.Po
-See
-.Xr getpwuid 3
-and
-.Xr geteuid 2
-for more details.
-.Pc
-This is obtained each time
-.Ev EUSER
-is expanded, so changes to the shell's execution identity
-cause updates without further action.
-If unset, it returns nothing.
-If set it loses its special properties, and is simply a variable.
-.It Ev HISTSIZE
-The number of lines in the history buffer for the shell.
-.It Ev HOME
-Set automatically by
-.Xr login 1
-from the user's login directory in the password file
-.Pq Xr passwd 5 .
-This environment variable also functions as the default argument for the
-.Ic cd
-built-in.
-.It Ev HOSTNAME
-Set to the current hostname of the system, as returned by
-.Xr gethostname 3 .
-This is obtained each time
-.Ev HOSTNAME
-is expanded, so changes to the system's name are reflected
-without further action.
-If unset, it returns nothing.
-If set it loses its special properties, and is simply a variable.
-.It Ev IFS
-Input Field Separators.
-This is normally set to
-.Aq space ,
-.Aq tab ,
-and
-.Aq newline .
-See the
-.Sx White Space Splitting
-section for more details.
-.It Ev LANG
-The string used to specify localization information that allows users
-to work with different culture-specific and language conventions.
-See
-.Xr nls 7 .
-.It Dv LINENO
-The current line number in the script or function.
-See the section
-.Sx LINENO
-below for more details.
-.It Ev MAIL
-The name of a mail file, that will be checked for the arrival of new mail.
-Overridden by
-.Ev MAILPATH .
-The check occurs just before
-.Ev PS1
-is written, immediately after reporting jobs which have changed status,
-in interactive shells only.
-New mail is considered to have arrived if the monitored file
-has increased in size since the last check.
-.\" .It Ev MAILCHECK
-.\" The frequency in seconds that the shell checks for the arrival of mail
-.\" in the files specified by the
-.\" .Ev MAILPATH
-.\" or the
-.\" .Ev MAIL
-.\" file.
-.\" If set to 0, the check will occur at each prompt.
-.It Ev MAILPATH
-A colon
-.Dq \&:
-separated list of file names, for the shell to check for incoming mail.
-This environment setting overrides the
-.Ev MAIL
-setting.
-There is a maximum of 10 mailboxes that can be monitored at once.
-.It Ev PATH
-The default search path for executables.
-See the
-.Sx Path Search
-section above.
-.It Ev POSIXLY_CORRECT
-If set in the environment upon initialization of the shell,
-then the shell option
-.Ic posix
-will be set.
-.Po
-See the description of the
-.Ic set
-command in the
-.Sx Built-ins
-section.
-.Pc
-After initialization it is unused by the shell,
-but is usually passed through the environment to
-descendant processes, including other instances of the shell,
-which may interpret it in a similar way.
-.It Ev PPID
-The process identified of the parent process of the
-current shell.
-This value is set at shell startup, ignoring
-any value in the environment, and then made readonly.
-.It Ev PS1
-The primary prompt string, which defaults to
-.Dq Li "$ " ,
-unless you are the superuser, in which case it defaults to
-.Dq Li "# " .
-This string is subject to parameter, arithmetic, and if
-enabled by setting the
-.Ic promptcmds
-option, command substitution before being output.
-During execution of commands used by command substitution,
-execution tracing, the
-.Ic xtrace
-.Ic ( set Fl x )
-option is temporarily disabled.
-If
-.Ic promptcmds
-is not set and the prompt string uses command substitution,
-the prompt used will be an appropriate error string.
-For other expansion errors, a message will be output,
-and the unexpanded string will then be used as the prompt.
-.It Ev PS2
-The secondary prompt string, which defaults to
-.Dq Li "> " .
-After expansion (as for
-.Ev PS1 )
-it is written whenever more input is required to complete the
-current command.
-.It Ev PS4
-Output, after expansion like
-.Ev PS1 ,
-before each line when execution trace
-.Ic ( set Fl x )
-is enabled.
-.Ev PS4
-defaults to
-.Dq Li "+ " .
-.It Ev PSc
-Initialized by the shell, ignoring any value from the environment,
-to a single character string, either
-.Sq \&#
-or
-.Sq \&$ ,
-depending upon whether the current user is the superuser or not.
-This is intended for use when building a custom
-.Ev PS1 .
-.It Ev PSlit
-Defines the character which may be embedded in pairs, in
-.Ev PS1
-or
-.Ev PS2
-to indicate to
-.Xr editline 7
-that the characters between each pair of occurrences of the
-.Dv PSlit
-character will not appear in the visible prompt, and will not
-cause the terminal's cursor to change position, but rather set terminal
-attributes for the following prompt character(s) at least one of
-which must be present.
-See
-.Sx Command Line Editing
-above for more information.
-.It Ev RANDOM
-Returns a different pseudo-random integer,
-in the range [0,32767] each time it is accessed.
-.Ev RANDOM
-can be assigned an integer value to seed the PRNG.
-If the value assigned is a constant, then the
-sequence of values produces on subsequent references of
-.Ev RANDOM
-will repeat after the next time the same constant is assigned.
-Note, this is not guaranteed to remain constant from one version
-of the shell to another \(en the PRNG algorithm, or seeding
-method is subject to change.
-If
-.Ev RANDOM
-is assigned an empty value (null string) then the next time
-.Ev RANDOM
-is accessed, it will be seeded from a more genuinely random source.
-The sequence of pseudo-random numbers generated will not be able to
-be generated again (except by luck, whether good or bad, depends!)
-This is also how the initial seed is generated, if none has been
-assigned before
-.Ev RANDOM
-is first accessed after shell initialization.
-Should the error message
-.Dq "RANDOM initialisation failed"
-appear on standard error, it indicates that the source
-of good random numbers was not available, and
-.Ev RANDOM
-has instead been seeded with a more predictable value.
-The following sequence of random numbers will
-not be as unpredictable as they otherwise would be.
-.It Ev SECONDS
-Returns the number of seconds since the current shell was started.
-If unset, it remains unset, and returns nothing, unless set again.
-If set, it loses its special properties, and becomes a normal variable.
-.It Ev START_TIME
-Initialized by the shell to the number of seconds since the Epoch
-(see
-.Xr localtime 3 )
-when the shell was started.
-The value of
-.Dl $(( Ns Ev START_TIME + Ev SECONDS Ns ))
-represents the current time, if
-.Ev START_TIME
-has not been modified, and
-.Ev SECONDS
-has not been set or unset.
-.It Ev TERM
-The default terminal setting for the shell.
-This is inherited by
-children of the shell, and is used in the history editing modes.
-.\" This is explicitly last, not in sort order - please leave!
-.It Ev ToD
-When referenced, uses the value of
-.Ev ToD_FORMAT
-(or
-.Dq \&%T
-if
-.Ev ToD_FORMAT
-is unset) as the format argument to
-.Xr strftime 3
-to encode the current time of day, in the time zone
-defined by
-.Ev TZ
-if set, or current local time if not, and returns the result.
-If unset
-.Ev ToD
-returns nothing.
-If set, it loses its special properties, and becomes a normal variable.
-.It Ev ToD_FORMAT
-Can be set to the
-.Xr strftime 3
-format string to be used when expanding
-.Ev ToD .
-Initially unset.
-.It Ev TZ
-If set, gives the time zone
-(see
-.Xr localtime 3 ,
-.Xr environ 7 )
-to use when formatting
-.Ev ToD
-and if exported, other utilities that deal with times.
-If unset, the system's local wall clock time zone is used.
-.It Ev NETBSD_SHELL
-Unlike the variables previously mentioned,
-this variable is somewhat strange,
-in that it cannot be set,
-inherited from the environment,
-modified, or exported from the shell.
-If set, by the shell, it indicates that the shell is the
-.Ic sh
-defined by this manual page, and gives its version information.
-It can also give information in additional space separated words,
-after the version string.
-If the shell was built as part of a reproducible build,
-the relevant date that was used for that build will be included.
-Finally, any non-standard compilation options,
-which may affect features available,
-that were used when building the shell will be listed.
-.Ev NETBSD_SHELL
-behaves like any other variable that has the read-only
-and un-exportable attributes set.
-.El
-.Ss Dv LINENO
-.Dv LINENO
-is in many respects a normal shell variable, containing an
-integer value. and can be expanded using any of the forms
-mentioned above which can be used for any other variable.
-.Pp
-.Dv LINENO
-can be exported, made readonly, or unset, as with any other
-variable, with similar effects.
-Note that while being readonly prevents later attempts to
-set, or unset,
-.Dv LINENO ,
-it does not prevent its value changing.
-References to
-.Dv LINENO
-.Pq "when not unset"
-always obtain the current line number.
-However,
-.Dv LINENO
-should normally not ever be set or unset.
-In this shell setting
-.Dv LINENO
-reverses the effect of an earlier
-.Ic unset ,
-but does not otherwise affect the value obtained.
-If unset,
-.Dv LINENO
-should not normally be set again, doing so is not portable.
-If
-.Dv LINENO
-is set or unset, different shells act differently.
-The value of
-.Dv LINENO
-is never imported from the environment when the shell is
-started, though if present there, as with any other variable,
-.Dv LINENO
-will be exported by this shell.
-.Pp
-.Dv LINENO
-is set automatically by the shell to be the number of the source
-line on which it occurs.
-When exported,
-.Dv LINENO
-is exported with its value set to the line number it would have
-had had it been referenced on the command line of the command to
-which it is exported.
-Line numbers are counted from 1, which is the first line the shell
-reads from any particular file.
-For this shell, standard input, including in an interactive shell,
-the user's terminal, is just another file and lines are counted
-there as well.
-However note that not all shells count interactive
-lines this way, it is not wise to rely upon
-.Dv LINENO
-having a useful value, except in a script, or a function.
-.Pp
-The role of
-.Dv LINENO
-in functions is less clear.
-In some shells,
-.Dv LINENO
-continues to refer to the line number in the script which defines
-the function,
-in others lines count from one within the function, always (and
-resume counting normally once the function definition is complete)
-and others count in functions from one if the function is defined
-interactively, but otherwise just reference the line number in the
-script in which the function is defined.
-This shell gives the user the option to choose.
-If the
-.Fl L
-flag (the
-.Ic local_lineno
-option, see
-.Sx Argument List Processing )
-is set, when the function is defined, then the function
-defaults to counting lines with one being the first line of the
-function.
-When the
-.Fl L
-flag is not set, the shell counts lines in a function definition
-in the same continuous sequence as the lines that surround the
-function definition.
-Further, if
-.Dv LINENO
-is made local
-(see
-.Sx Built-ins
-above)
-inside the function, the function can decide which
-behavior it prefers.
-If
-.Dv LINENO
-is made local and inherited, and not given a value, as in
-.Dl local Fl I Dv LINENO
-then from that point in the function,
-.Dv LINENO
-will give the line number as if lines are counted in sequence
-with the lines that surround the function definition (and
-any other function definitions in which this is nested.)
-If
-.Dv LINENO
-is made local, and in that same command, given a value, as
-.Dl local Oo Fl I Ns | Ns Fl N Oc Dv LINENO Ns = Ns Ar value
-then
-.Dv LINENO
-will give the line number as if lines are counted from one
-from the beginning of the function.
-The value nominally assigned in this case is irrelevant, and ignored.
-For completeness, if lineno is made local and unset, as in
-.Dl local Fl N Dv LINENO
-then
-.Dv LINENO
-is simply unset inside the function, and gives no value at all.
-.Pp
-Now for some technical details.
-The line on which
-.Dv LINENO
-occurs in a parameter expansion, is the line that contains the
-.Sq \&$
-that begins the expansion of
-.Dv LINENO .
-In the case of nested expansions, that
-.Sq \&$
-is the one that actually has
-.Dv LINENO
-as its parameter.
-In an arithmetic expansion, where no
-.Sq \&$
-is used to evaluate
-.Dv LINENO
-but
-.Dv LINENO
-is simply referenced as a variable, then the value is the
-line number of the line that contains the
-.Sq L
-of
-.Dv LINENO .
-For functions line one of the function definition (when relevant)
-is the line that contains the first character of the
-function name in the definition.
-When exported, the line number of the command is the line number
-where the first character of the word which becomes the command name occurs.
-.Pp
-When the shell opens a new file, for any reason,
-it counts lines from one in that file,
-and then resumes its original counting once it resumes reading the
-previous input stream.
-When handling a string passed to
-.Ic eval
-the line number starts at the line on which the string starts,
-and then if the string contains internal newline characters,
-those characters increase the line number.
-This means that references to
-.Dv LINENO
-in such a case can produce values larger than would be
-produced by a reference on the line after the
-.Ic eval .
-.Sh FILES
-.Bl -item
-.It
-.Pa $HOME/.profile
-.It
-.Pa /etc/profile
-.El
-.Sh EXIT STATUS
-Errors that are detected by the shell, such as a syntax error, will cause the
-shell to exit with a non-zero exit status.
-If the shell is not an
-interactive shell, the execution of the shell file will be aborted.
-Otherwise
-the shell will return the exit status of the last command executed, or
-if the exit built-in is used with a numeric argument, it will return the
-argument.
-.Sh SEE ALSO
-.Xr csh 1 ,
-.Xr echo 1 ,
-.Xr getopt 1 ,
-.Xr ksh 1 ,
-.Xr login 1 ,
-.Xr printf 1 ,
-.Xr test 1 ,
-.Xr editline 3 ,
-.Xr getopt 3 ,
-.\" .Xr profile 4 ,
-.Xr editrc 5 ,
-.Xr passwd 5 ,
-.Xr editline 7 ,
-.Xr environ 7 ,
-.Xr nls 7 ,
-.Xr sysctl 8
-.Sh HISTORY
-A
-.Nm
-command appeared in
-.At v1 .
-It was replaced in
-.At v7
-with a version that introduced the basis of the current syntax.
-That was, however, unmaintainable so we wrote this one.
-.Sh BUGS
-Setuid shell scripts should be avoided at all costs, as they are a
-significant security risk.
-.Pp
-The characters generated by filename completion should probably be quoted
-to ensure that the filename is still valid after the input line has been
-processed.
-.Pp
-Job control of compound statements (loops, etc) is a complete mess.
-.Pp
-Many, many, more.
-(But less than there were...)
diff --git a/bin/sh/shell.h b/bin/sh/shell.h
deleted file mode 100644
index 318d56e..0000000
--- a/bin/sh/shell.h
+++ /dev/null
@@ -1,224 +0,0 @@
-/* $NetBSD: shell.h,v 1.29 2019/01/22 13:48:28 kre Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- *
- * @(#)shell.h 8.2 (Berkeley) 5/4/95
- */
-
-/*
- * The follow should be set to reflect the type of system you have:
- * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
- * define BSD if you are running 4.2 BSD or later.
- * define SYSV if you are running under System V.
- * define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
- * define DEBUG=2 to compile in and enable debugging.
- * define DEBUG=3 for DEBUG==2 + enable most standard debug output
- * define DEBUG=4 for DEBUG==2 + enable absolutely everything
- * define DO_SHAREDVFORK to indicate that vfork(2) shares its address
- * with its parent.
- * define BOGUS_NOT_COMMAND to allow ! reserved words in weird places
- * (traditional ash behaviour.)
- *
- * When debugging is on, debugging info will be written to ./trace and
- * a quit signal will generate a core dump.
- */
-
-#ifndef SHELL_H
-#define SHELL_H
-#include <sys/param.h>
-
-#define JOBS 1
-#ifndef BSD
-#define BSD 1
-#endif
-
-#ifndef DO_SHAREDVFORK
-#if defined(__NetBSD_Version__) && __NetBSD_Version__ >= 104000000
-#define DO_SHAREDVFORK
-#endif
-#endif
-
-typedef void *pointer;
-#ifndef NULL
-#define NULL (void *)0
-#endif
-#ifndef STATIC
-#define STATIC /* empty */
-#endif
-#define MKINIT /* empty */
-
-#include <sys/cdefs.h>
-
-extern const char nullstr[1]; /* null string */
-
-#ifdef SMALL
-#undef DEBUG
-#endif
-
-#ifdef DEBUG
-
-extern uint64_t DFlags;
-extern int ShNest;
-
-/*
- * This is selected as there are 26 letters in ascii - not that that
- * matters for anything, just makes it easier to assign a different
- * command letter to each debug option. We currently use only 18
- * so this could be reduced, but that is of no real benefit. It can also
- * be increased, but that both limits the maximum value tha can be
- * used with DBG_EXTRAS(), and causes problems with verbose option naming.
- */
-#define DBG_VBOSE_SHIFT 27
-#define DBG_EXTRAS(n) ((DBG_VBOSE_SHIFT * 2) + (n))
-
-/*
- * Macros to enable tracing, so the mainainer can control
- * just how much debug output is dumped to the trace file
- *
- * In the X forms, "xtra" can be any legal C statement(s) without (bare) commas
- * executed if the relevant debug flag is enabled, after any tracing output.
- */
-#define CTRACE(when, param) do { \
- if ((DFlags & (when)) != 0) \
- trace param; \
- } while (/*CONSTCOND*/ 0)
-
-#define CCTRACE(when,cond,param) do { \
- if ((cond) && (DFlags & (when)) != 0) \
- trace param; \
- } while (/*CONSTCOND*/ 0)
-
-#define CTRACEV(when, param) do { \
- if ((DFlags & (when)) != 0) \
- tracev param; \
- } while (/*CONSTCOND*/ 0)
-
-#define XTRACE(when, param, xtra) do { \
- if ((DFlags & (when)) != 0) { \
- trace param; \
- xtra; \
- } \
- } while (/*CONSTCOND*/ 0)
-
-#define VTRACE(when, param) do { \
- if ((DFlags & \
- (when)<<DBG_VBOSE_SHIFT) != 0) \
- trace param; \
- } while (/*CONSTCOND*/ 0)
-
-#define CVTRACE(when,cond,param) do { \
- if ((cond) && (DFlags & \
- (when)<<DBG_VBOSE_SHIFT) != 0) \
- trace param; \
- } while (/*CONSTCOND*/ 0)
-
-#define VTRACEV(when, param) do { \
- if ((DFlags & \
- (when)<<DBG_VBOSE_SHIFT) != 0) \
- tracev param; \
- } while (/*CONSTCOND*/ 0)
-
-#define VXTRACE(when, param, xtra) do { \
- if ((DFlags & \
- (when)<<DBG_VBOSE_SHIFT) != 0) {\
- trace param; \
- xtra; \
- } \
- } while (/*CONSTCOND*/ 0)
-
-#define SHELL_FORKED() ShNest++
-#define VFORK_BLOCK { const int _ShNest = ShNest;
-#define VFORK_END }
-#define VFORK_UNDO() ShNest = _ShNest
-
-#define DBG_ALWAYS (1LL << 0)
-#define DBG_PARSE (1LL << 1) /* r (read commands) */
-#define DBG_EVAL (1LL << 2) /* e */
-#define DBG_EXPAND (1LL << 3) /* x */
-#define DBG_JOBS (1LL << 4) /* j */
-#define DBG_PROCS (1LL << 5) /* p */
-#define DBG_REDIR (1LL << 6) /* f (fds) */
-#define DBG_CMDS (1LL << 7) /* c */
-#define DBG_ERRS (1LL << 8) /* z (?) */
-#define DBG_WAIT (1LL << 9) /* w */
-#define DBG_TRAP (1LL << 10) /* t */
-#define DBG_VARS (1LL << 11) /* v */
-#define DBG_INPUT (1LL << 12) /* i */
-#define DBG_OUTPUT (1LL << 13) /* o */
-#define DBG_MEM (1LL << 14) /* m */
-#define DBG_ARITH (1LL << 15) /* a */
-#define DBG_HISTORY (1LL << 16) /* h */
-#define DBG_SIG (1LL << 17) /* s */
-#define DBG_MATCH (1LL << 18) /* g (glob) */
-#define DBG_LEXER (1LL << 19) /* l */
-
-/*
- * reserved extras: b=builtins y=alias
- * still free: d k n q u
- */
-
- /* use VTRACE(DBG_ALWAYS, (...)) to test this one */
-#define DBG_VERBOSE (1LL << DBG_VBOSE_SHIFT)
-
- /* DBG_EXTRAS 0 .. 9 (max) only - non-alpha options (no VTRACE !!) */
-#define DBG_U0 (1LL << DBG_EXTRAS(0)) /* 0 - ad-hoc extra flags */
-#define DBG_U1 (1LL << DBG_EXTRAS(1)) /* 1 - for short term */
-#define DBG_U2 (1LL << DBG_EXTRAS(2)) /* 2 - extra tracing */
-#define DBG_U3 (1LL << DBG_EXTRAS(3)) /* 3 - when needed */
- /* 4, 5, & 6 currently free */
-#define DBG_LINE (1LL << DBG_EXTRAS(7)) /* @ ($LINENO) */
-#define DBG_PID (1LL << DBG_EXTRAS(8)) /* $ ($$) */
-#define DBG_NEST (1LL << DBG_EXTRAS(9)) /* ^ */
-
-/* 26 lower case, 26 upper case, always, verbose, and 10 extras: 64 bits */
-
-extern void set_debug(const char *, int);
-
-#else /* DEBUG */
-
-#define CTRACE(when, param) /* conditional normal trace */
-#define CCTRACE(when, cond, param) /* more conditional normal trace */
-#define CTRACEV(when, param) /* conditional varargs trace */
-#define XTRACE(when, param, extra) /* conditional trace, plus more */
-#define VTRACE(when, param) /* conditional verbose trace */
-#define CVTRACE(when, cond, param) /* more conditional verbose trace */
-#define VTRACEV(when, param) /* conditional verbose varargs trace */
-#define VXTRACE(when, param, extra) /* cond verbose trace, plus more */
-
-#define SHELL_FORKED()
-#define VFORK_BLOCK
-#define VFORK_END
-#define VFORK_UNDO()
-
-#endif /* DEBUG */
-
-#endif /* SHELL_H */
diff --git a/bin/sh/show.c b/bin/sh/show.c
deleted file mode 100644
index fa9f5aa..0000000
--- a/bin/sh/show.c
+++ /dev/null
@@ -1,1175 +0,0 @@
-/* $NetBSD: show.c,v 1.52 2019/01/22 13:48:28 kre Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Copyright (c) 2017 The NetBSD Foundation, Inc. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- */
-
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)show.c 8.3 (Berkeley) 5/4/95";
-#else
-__RCSID("$NetBSD: show.c,v 1.52 2019/01/22 13:48:28 kre Exp $");
-#endif
-#endif /* not lint */
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <limits.h>
-
-#include <sys/types.h>
-#include <sys/uio.h>
-
-#include "shell.h"
-#include "parser.h"
-#include "nodes.h"
-#include "mystring.h"
-#include "show.h"
-#include "options.h"
-#include "redir.h"
-#include "error.h"
-#include "syntax.h"
-#include "input.h"
-#include "output.h"
-#include "var.h"
-#include "builtins.h"
-
-#define DEFINE_NODENAMES
-#include "nodenames.h" /* does almost nothing if !defined(DEBUG) */
-
-#define TR_STD_WIDTH 60 /* tend to fold lines wider than this */
-#define TR_IOVECS 10 /* number of lines or trace (max) / write */
-
-typedef struct traceinfo {
- int tfd; /* file descriptor for open trace file */
- int nxtiov; /* the buffer we should be writing to */
- char lastc; /* the last non-white character output */
- uint8_t supr; /* char classes to suppress after \n */
- pid_t pid; /* process id of process that opened that file */
- size_t llen; /* number of chars in current output line */
- size_t blen; /* chars used in current buffer being filled */
- char * tracefile; /* name of the tracefile */
- struct iovec lines[TR_IOVECS]; /* filled, flling, pending buffers */
-} TFILE;
-
-/* These are auto turned off when non white space is printed */
-#define SUP_NL 0x01 /* don't print \n */
-#define SUP_SP 0x03 /* suppress spaces */
-#define SUP_WSP 0x04 /* suppress all white space */
-
-#ifdef DEBUG /* from here to end of file ... */
-
-TFILE tracedata, *tracetfile;
-FILE *tracefile; /* just for histedit */
-
-uint64_t DFlags; /* currently enabled debug flags */
-int ShNest; /* depth of shell (internal) nesting */
-
-static void shtree(union node *, int, int, int, TFILE *);
-static void shcmd(union node *, TFILE *);
-static void shsubsh(union node *, TFILE *);
-static void shredir(union node *, TFILE *, int);
-static void sharg(union node *, TFILE *);
-static void indent(int, TFILE *);
-static void trstring(const char *);
-static void trace_putc(char, TFILE *);
-static void trace_puts(const char *, TFILE *);
-static void trace_flush(TFILE *, int);
-static char *trace_id(TFILE *);
-static void trace_fd_swap(int, int);
-
-inline static int trlinelen(TFILE *);
-
-
-/*
- * These functions are the externally visible interface
- * (but only for a DEBUG shell.)
- */
-
-void
-opentrace(void)
-{
- char *s;
- int fd;
- int i;
- pid_t pid;
-
- if (debug != 1) {
- /* leave fd open because libedit might be using it */
- if (tracefile)
- fflush(tracefile);
- if (tracetfile)
- trace_flush(tracetfile, 1);
- return;
- }
-#if DBG_PID == 1 /* using old shell.h, old tracing method */
- DFlags = DBG_PID; /* just force DBG_PID on, and leave it ... */
-#endif
- pid = getpid();
- if (asprintf(&s, "trace.%jd", (intmax_t)pid) <= 0) {
- debug = 0;
- error("Cannot asprintf tracefilename");
- };
-
- fd = open(s, O_WRONLY|O_APPEND|O_CREAT, 0666);
- if (fd == -1) {
- debug = 0;
- error("Can't open tracefile: %s (%s)\n", s, strerror(errno));
- }
- fd = to_upper_fd(fd);
- if (fd <= 2) {
- (void) close(fd);
- debug = 0;
- error("Attempt to use fd %d as tracefile thwarted\n", fd);
- }
- register_sh_fd(fd, trace_fd_swap);
-
- /*
- * This stuff is just so histedit has a FILE * to use
- */
- if (tracefile)
- (void) fclose(tracefile); /* also closes tfd */
- tracefile = fdopen(fd, "a"); /* don't care if it is NULL */
- if (tracefile) /* except here... */
- setlinebuf(tracefile);
-
- /*
- * Now the real tracing setup
- */
- if (tracedata.tfd > 0 && tracedata.tfd != fd)
- (void) close(tracedata.tfd); /* usually done by fclose() */
-
- tracedata.tfd = fd;
- tracedata.pid = pid;
- tracedata.nxtiov = 0;
- tracedata.blen = 0;
- tracedata.llen = 0;
- tracedata.lastc = '\0';
- tracedata.supr = SUP_NL | SUP_WSP;
-
-#define replace(f, v) do { \
- if (tracedata.f != NULL) \
- free(tracedata.f); \
- tracedata.f = v; \
- } while (/*CONSTCOND*/ 0)
-
- replace(tracefile, s);
-
- for (i = 0; i < TR_IOVECS; i++) {
- replace(lines[i].iov_base, NULL);
- tracedata.lines[i].iov_len = 0;
- }
-
-#undef replace
-
- tracetfile = &tracedata;
-
- trace_puts("\nTracing started.\n", tracetfile);
-}
-
-void
-trace(const char *fmt, ...)
-{
- va_list va;
- char *s;
-
- if (debug != 1 || !tracetfile)
- return;
- va_start(va, fmt);
- (void) vasprintf(&s, fmt, va);
- va_end(va);
-
- trace_puts(s, tracetfile);
- free(s);
- if (tracetfile->llen == 0)
- trace_flush(tracetfile, 0);
-}
-
-void
-tracev(const char *fmt, va_list va)
-{
- va_list ap;
- char *s;
-
- if (debug != 1 || !tracetfile)
- return;
- va_copy(ap, va);
- (void) vasprintf(&s, fmt, ap);
- va_end(ap);
-
- trace_puts(s, tracetfile);
- free(s);
- if (tracetfile->llen == 0)
- trace_flush(tracetfile, 0);
-}
-
-
-void
-trputs(const char *s)
-{
- if (debug != 1 || !tracetfile)
- return;
- trace_puts(s, tracetfile);
-}
-
-void
-trputc(int c)
-{
- if (debug != 1 || !tracetfile)
- return;
- trace_putc(c, tracetfile);
-}
-
-void
-showtree(union node *n)
-{
- TFILE *fp;
-
- if ((fp = tracetfile) == NULL)
- return;
-
- trace_puts("showtree(", fp);
- if (n == NULL)
- trace_puts("NULL", fp);
- else if (n == NEOF)
- trace_puts("NEOF", fp);
- else
- trace("%p", n);
- trace_puts(") called\n", fp);
- if (n != NULL && n != NEOF)
- shtree(n, 1, 1, 1, fp);
-}
-
-void
-trargs(char **ap)
-{
- if (debug != 1 || !tracetfile)
- return;
- while (*ap) {
- trstring(*ap++);
- if (*ap)
- trace_putc(' ', tracetfile);
- }
- trace_putc('\n', tracetfile);
-}
-
-void
-trargstr(union node *n)
-{
- sharg(n, tracetfile);
-}
-
-
-/*
- * Beyond here we just have the implementation of all of that
- */
-
-
-inline static int
-trlinelen(TFILE * fp)
-{
- return fp->llen;
-}
-
-static void
-shtree(union node *n, int ind, int ilvl, int nl, TFILE *fp)
-{
- struct nodelist *lp;
- const char *s;
-
- if (n == NULL) {
- if (nl)
- trace_putc('\n', fp);
- return;
- }
-
- indent(ind, fp);
- switch (n->type) {
- case NSEMI:
- s = NULL;
- goto binop;
- case NAND:
- s = " && ";
- goto binop;
- case NOR:
- s = " || ";
-binop:
- shtree(n->nbinary.ch1, 0, ilvl, 0, fp);
- if (s != NULL)
- trace_puts(s, fp);
- if (trlinelen(fp) >= TR_STD_WIDTH) {
- trace_putc('\n', fp);
- indent(ind < 0 ? 2 : ind + 1, fp);
- } else if (s == NULL) {
- if (fp->lastc != '&')
- trace_puts("; ", fp);
- else
- trace_putc(' ', fp);
- }
- shtree(n->nbinary.ch2, 0, ilvl, nl, fp);
- break;
- case NCMD:
- shcmd(n, fp);
- if (n->ncmd.backgnd)
- trace_puts(" &", fp);
- if (nl && trlinelen(fp) > 0)
- trace_putc('\n', fp);
- break;
- case NPIPE:
- for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
- shtree(lp->n, 0, ilvl, 0, fp);
- if (lp->next) {
- trace_puts(" |", fp);
- if (trlinelen(fp) >= TR_STD_WIDTH) {
- trace_putc('\n', fp);
- indent((ind < 0 ? ilvl : ind) + 1, fp);
- } else
- trace_putc(' ', fp);
- }
- }
- if (n->npipe.backgnd)
- trace_puts(" &", fp);
- if (nl || trlinelen(fp) >= TR_STD_WIDTH)
- trace_putc('\n', fp);
- break;
- case NBACKGND:
- case NSUBSHELL:
- shsubsh(n, fp);
- if (n->type == NBACKGND)
- trace_puts(" &", fp);
- if (nl && trlinelen(fp) > 0)
- trace_putc('\n', fp);
- break;
- case NDEFUN:
- trace_puts(n->narg.text, fp);
- trace_puts("() {\n", fp);
- indent(ind, fp);
- shtree(n->narg.next, (ind < 0 ? ilvl : ind) + 1, ilvl+1, 1, fp);
- indent(ind, fp);
- trace_puts("}\n", fp);
- break;
- case NDNOT:
- trace_puts("! ", fp);
- /* FALLTHROUGH */
- case NNOT:
- trace_puts("! ", fp);
- shtree(n->nnot.com, -1, ilvl, nl, fp);
- break;
- case NREDIR:
- shtree(n->nredir.n, -1, ilvl, 0, fp);
- shredir(n->nredir.redirect, fp, n->nredir.n == NULL);
- if (nl)
- trace_putc('\n', fp);
- break;
-
- case NIF:
- itsif:
- trace_puts("if ", fp);
- shtree(n->nif.test, -1, ilvl, 0, fp);
- if (trlinelen(fp) > 0 && trlinelen(fp) < TR_STD_WIDTH) {
- if (fp->lastc != '&')
- trace_puts(" ;", fp);
- } else
- indent(ilvl, fp);
- trace_puts(" then ", fp);
- if (nl || trlinelen(fp) > TR_STD_WIDTH - 24)
- indent(ilvl+1, fp);
- shtree(n->nif.ifpart, -1, ilvl + 1, 0, fp);
- if (trlinelen(fp) > 0 && trlinelen(fp) < TR_STD_WIDTH) {
- if (fp->lastc != '&')
- trace_puts(" ;", fp);
- } else
- indent(ilvl, fp);
- if (n->nif.elsepart && n->nif.elsepart->type == NIF) {
- if (nl || trlinelen(fp) > TR_STD_WIDTH - 24)
- indent(ilvl, fp);
- n = n->nif.elsepart;
- trace_puts(" el", fp);
- goto itsif;
- }
- if (n->nif.elsepart) {
- if (nl || trlinelen(fp) > TR_STD_WIDTH - 24)
- indent(ilvl+1, fp);
- trace_puts(" else ", fp);
- shtree(n->nif.elsepart, -1, ilvl + 1, 0, fp);
- if (fp->lastc != '&')
- trace_puts(" ;", fp);
- }
- trace_puts(" fi", fp);
- if (nl)
- trace_putc('\n', fp);
- break;
-
- case NWHILE:
- trace_puts("while ", fp);
- goto aloop;
- case NUNTIL:
- trace_puts("until ", fp);
- aloop:
- shtree(n->nbinary.ch1, -1, ilvl, 0, fp);
- if (trlinelen(fp) > 0 && trlinelen(fp) < TR_STD_WIDTH) {
- if (fp->lastc != '&')
- trace_puts(" ;", fp);
- } else
- trace_putc('\n', fp);
- trace_puts(" do ", fp);
- shtree(n->nbinary.ch1, -1, ilvl + 1, 1, fp);
- trace_puts(" done ", fp);
- if (nl)
- trace_putc('\n', fp);
- break;
-
- case NFOR:
- trace_puts("for ", fp);
- trace_puts(n->nfor.var, fp);
- if (n->nfor.args) {
- union node *argp;
-
- trace_puts(" in ", fp);
- for (argp = n->nfor.args; argp; argp=argp->narg.next) {
- sharg(argp, fp);
- trace_putc(' ', fp);
- }
- if (trlinelen(fp) > 0 && trlinelen(fp) < TR_STD_WIDTH) {
- if (fp->lastc != '&')
- trace_putc(';', fp);
- } else
- trace_putc('\n', fp);
- }
- trace_puts(" do ", fp);
- shtree(n->nfor.body, -1, ilvl + 1, 0, fp);
- if (fp->lastc != '&')
- trace_putc(';', fp);
- trace_puts(" done", fp);
- if (nl)
- trace_putc('\n', fp);
- break;
-
- case NCASE:
- trace_puts("case ", fp);
- sharg(n->ncase.expr, fp);
- trace_puts(" in", fp);
- if (nl)
- trace_putc('\n', fp);
- {
- union node *cp;
-
- for (cp = n->ncase.cases ; cp ; cp = cp->nclist.next) {
- union node *patp;
-
- if (nl || trlinelen(fp) > TR_STD_WIDTH - 16)
- indent(ilvl, fp);
- else
- trace_putc(' ', fp);
- trace_putc('(', fp);
- patp = cp->nclist.pattern;
- while (patp != NULL) {
- trace_putc(' ', fp);
- sharg(patp, fp);
- trace_putc(' ', fp);
- if ((patp = patp->narg.next) != NULL)
- trace_putc('|', fp);
- }
- trace_putc(')', fp);
- if (nl)
- indent(ilvl + 1, fp);
- else
- trace_putc(' ', fp);
- shtree(cp->nclist.body, -1, ilvl+2, 0, fp);
- if (cp->type == NCLISTCONT)
- trace_puts(" ;&", fp);
- else
- trace_puts(" ;;", fp);
- if (nl)
- trace_putc('\n', fp);
- }
- }
- if (nl) {
- trace_putc('\n', fp);
- indent(ind, fp);
- } else
- trace_putc(' ', fp);
- trace_puts("esac", fp);
- if (nl)
- trace_putc('\n', fp);
- break;
-
- default: {
- char *str;
-
- asprintf(&str, "<node type %d [%s]>", n->type,
- NODETYPENAME(n->type));
- trace_puts(str, fp);
- free(str);
- if (nl)
- trace_putc('\n', fp);
- }
- break;
- }
-}
-
-
-static void
-shcmd(union node *cmd, TFILE *fp)
-{
- union node *np;
- int first;
-
- first = 1;
- for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
- if (! first)
- trace_putc(' ', fp);
- sharg(np, fp);
- first = 0;
- }
- shredir(cmd->ncmd.redirect, fp, first);
-}
-
-static void
-shsubsh(union node *cmd, TFILE *fp)
-{
- trace_puts(" ( ", fp);
- shtree(cmd->nredir.n, -1, 3, 0, fp);
- trace_puts(" ) ", fp);
- shredir(cmd->ncmd.redirect, fp, 1);
-}
-
-static void
-shredir(union node *np, TFILE *fp, int first)
-{
- const char *s;
- int dftfd;
- char buf[106];
-
- for ( ; np ; np = np->nfile.next) {
- if (! first)
- trace_putc(' ', fp);
- switch (np->nfile.type) {
- case NTO: s = ">"; dftfd = 1; break;
- case NCLOBBER: s = ">|"; dftfd = 1; break;
- case NAPPEND: s = ">>"; dftfd = 1; break;
- case NTOFD: s = ">&"; dftfd = 1; break;
- case NFROM: s = "<"; dftfd = 0; break;
- case NFROMFD: s = "<&"; dftfd = 0; break;
- case NFROMTO: s = "<>"; dftfd = 0; break;
- case NXHERE: /* FALLTHROUGH */
- case NHERE: s = "<<"; dftfd = 0; break;
- default: s = "*error*"; dftfd = 0; break;
- }
- if (np->nfile.fd != dftfd) {
- sprintf(buf, "%d", np->nfile.fd);
- trace_puts(buf, fp);
- }
- trace_puts(s, fp);
- if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
- if (np->ndup.vname)
- sharg(np->ndup.vname, fp);
- else {
- if (np->ndup.dupfd < 0)
- trace_puts("-", fp);
- else {
- sprintf(buf, "%d", np->ndup.dupfd);
- trace_puts(buf, fp);
- }
- }
- } else
- if (np->nfile.type == NHERE || np->nfile.type == NXHERE) {
- if (np->nfile.type == NHERE)
- trace_putc('\\', fp);
- trace_puts("!!!\n", fp);
- s = np->nhere.doc->narg.text;
- if (strlen(s) > 100) {
- memmove(buf, s, 100);
- buf[100] = '\0';
- strcat(buf, " ...\n");
- s = buf;
- }
- trace_puts(s, fp);
- trace_puts("!!! ", fp);
- } else {
- sharg(np->nfile.fname, fp);
- }
- first = 0;
- }
-}
-
-static void
-sharg(union node *arg, TFILE *fp)
-{
- char *p, *s;
- struct nodelist *bqlist;
- int subtype = 0;
- int quoted = 0;
-
- if (arg->type != NARG) {
- asprintf(&s, "<node type %d> ! NARG\n", arg->type);
- trace_puts(s, fp);
- abort(); /* no need to free s, better not to */
- }
-
- bqlist = arg->narg.backquote;
- for (p = arg->narg.text ; *p ; p++) {
- switch (*p) {
- case CTLESC:
- trace_putc('\\', fp);
- trace_putc(*++p, fp);
- break;
-
- case CTLNONL:
- trace_putc('\\', fp);
- trace_putc('\n', fp);
- break;
-
- case CTLVAR:
- subtype = *++p;
- if (!quoted != !(subtype & VSQUOTE))
- trace_putc('"', fp);
- trace_putc('$', fp);
- trace_putc('{', fp); /*}*/
- if ((subtype & VSTYPE) == VSLENGTH)
- trace_putc('#', fp);
- if (subtype & VSLINENO)
- trace_puts("LINENO=", fp);
-
- while (*++p != '=')
- trace_putc(*p, fp);
-
- if (subtype & VSNUL)
- trace_putc(':', fp);
-
- switch (subtype & VSTYPE) {
- case VSNORMAL:
- /* { */
- trace_putc('}', fp);
- if (!quoted != !(subtype & VSQUOTE))
- trace_putc('"', fp);
- break;
- case VSMINUS:
- trace_putc('-', fp);
- break;
- case VSPLUS:
- trace_putc('+', fp);
- break;
- case VSQUESTION:
- trace_putc('?', fp);
- break;
- case VSASSIGN:
- trace_putc('=', fp);
- break;
- case VSTRIMLEFTMAX:
- trace_putc('#', fp);
- /* FALLTHROUGH */
- case VSTRIMLEFT:
- trace_putc('#', fp);
- break;
- case VSTRIMRIGHTMAX:
- trace_putc('%', fp);
- /* FALLTHROUGH */
- case VSTRIMRIGHT:
- trace_putc('%', fp);
- break;
- case VSLENGTH:
- break;
- default: {
- char str[32];
-
- snprintf(str, sizeof str,
- "<subtype %d>", subtype);
- trace_puts(str, fp);
- }
- break;
- }
- break;
- case CTLENDVAR:
- /* { */
- trace_putc('}', fp);
- if (!quoted != !(subtype & VSQUOTE))
- trace_putc('"', fp);
- subtype = 0;
- break;
-
- case CTLBACKQ|CTLQUOTE:
- if (!quoted)
- trace_putc('"', fp);
- /* FALLTHRU */
- case CTLBACKQ:
- trace_putc('$', fp);
- trace_putc('(', fp);
- if (bqlist) {
- shtree(bqlist->n, -1, 3, 0, fp);
- bqlist = bqlist->next;
- } else
- trace_puts("???", fp);
- trace_putc(')', fp);
- if (!quoted && *p == (CTLBACKQ|CTLQUOTE))
- trace_putc('"', fp);
- break;
-
- case CTLQUOTEMARK:
- if (subtype != 0 || !quoted) {
- trace_putc('"', fp);
- quoted++;
- }
- break;
- case CTLQUOTEEND:
- trace_putc('"', fp);
- quoted--;
- break;
- case CTLARI:
- if (*p == ' ')
- p++;
- trace_puts("$(( ", fp);
- break;
- case CTLENDARI:
- trace_puts(" ))", fp);
- break;
-
- default:
- if (*p == '$')
- trace_putc('\\', fp);
- trace_putc(*p, fp);
- break;
- }
- }
- if (quoted)
- trace_putc('"', fp);
-}
-
-
-static void
-indent(int amount, TFILE *fp)
-{
- int i;
-
- if (amount <= 0)
- return;
-
- amount <<= 2; /* indent slots -> chars */
-
- i = trlinelen(fp);
- fp->supr = SUP_NL;
- if (i > amount) {
- trace_putc('\n', fp);
- i = 0;
- }
- fp->supr = 0;
- for (; i < amount - 7 ; i++) {
- trace_putc('\t', fp);
- i |= 7;
- }
- while (i < amount) {
- trace_putc(' ', fp);
- i++;
- }
- fp->supr = SUP_WSP;
-}
-
-static void
-trace_putc(char c, TFILE *fp)
-{
- char *p;
-
- if (c == '\0')
- return;
- if (debug == 0 || fp == NULL)
- return;
-
- if (fp->llen == 0) {
- if (fp->blen != 0)
- abort();
-
- if ((fp->supr & SUP_NL) && c == '\n')
- return;
- if ((fp->supr & (SUP_WSP|SUP_SP)) && c == ' ')
- return;
- if ((fp->supr & SUP_WSP) && c == '\t')
- return;
-
- if (fp->nxtiov >= TR_IOVECS - 1) /* should be rare */
- trace_flush(fp, 0);
-
- p = trace_id(fp);
- if (p != NULL) {
- fp->lines[fp->nxtiov].iov_base = p;
- fp->lines[fp->nxtiov].iov_len = strlen(p);
- fp->nxtiov++;
- }
- } else if (fp->blen && fp->blen >= fp->lines[fp->nxtiov].iov_len) {
- fp->blen = 0;
- if (++fp->nxtiov >= TR_IOVECS)
- trace_flush(fp, 0);
- }
-
- if (fp->lines[fp->nxtiov].iov_len == 0) {
- p = (char *)malloc(2 * TR_STD_WIDTH);
- if (p == NULL) {
- trace_flush(fp, 1);
- debug = 0;
- return;
- }
- *p = '\0';
- fp->lines[fp->nxtiov].iov_base = p;
- fp->lines[fp->nxtiov].iov_len = 2 * TR_STD_WIDTH;
- fp->blen = 0;
- }
-
- p = (char *)fp->lines[fp->nxtiov].iov_base + fp->blen++;
- *p++ = c;
- *p = 0;
-
- if (c != ' ' && c != '\t' && c != '\n') {
- fp->lastc = c;
- fp->supr = 0;
- }
-
- if (c == '\n') {
- fp->lines[fp->nxtiov++].iov_len = fp->blen;
- fp->blen = 0;
- fp->llen = 0;
- fp->supr |= SUP_NL;
- return;
- }
-
- if (c == '\t')
- fp->llen |= 7;
- fp->llen++;
-}
-
-void
-trace_flush(TFILE *fp, int all)
-{
- int niov, i;
- ssize_t written;
-
- niov = fp->nxtiov;
- if (all && fp->blen > 0) {
- fp->lines[niov].iov_len = fp->blen;
- fp->blen = 0;
- fp->llen = 0;
- niov++;
- }
- if (niov == 0)
- return;
- if (fp->blen > 0 && --niov == 0)
- return;
- written = writev(fp->tfd, fp->lines, niov);
- for (i = 0; i < niov; i++) {
- free(fp->lines[i].iov_base);
- fp->lines[i].iov_base = NULL;
- fp->lines[i].iov_len = 0;
- }
- if (written == -1) {
- if (fp->blen > 0) {
- free(fp->lines[niov].iov_base);
- fp->lines[niov].iov_base = NULL;
- fp->lines[niov].iov_len = 0;
- }
- debug = 0;
- fp->blen = 0;
- fp->llen = 0;
- return;
- }
- if (fp->blen > 0) {
- fp->lines[0].iov_base = fp->lines[niov].iov_base;
- fp->lines[0].iov_len = fp->lines[niov].iov_len;
- fp->lines[niov].iov_base = NULL;
- fp->lines[niov].iov_len = 0;
- }
- fp->nxtiov = 0;
-}
-
-void
-trace_puts(const char *s, TFILE *fp)
-{
- char c;
-
- while ((c = *s++) != '\0')
- trace_putc(c, fp);
-}
-
-inline static char *
-trace_id(TFILE *tf)
-{
- int i;
- char indent[16];
- char *p;
- int lno;
- char c;
-
- if (DFlags & DBG_NEST) {
- if ((unsigned)ShNest >= sizeof indent - 1) {
- (void) snprintf(indent, sizeof indent,
- "### %*d ###", (int)(sizeof indent) - 9, ShNest);
- p = strchr(indent, '\0');
- } else {
- p = indent;
- for (i = 0; i < 6; i++)
- *p++ = (i < ShNest) ? '#' : ' ';
- while (i++ < ShNest && p < &indent[sizeof indent - 1])
- *p++ = '#';
- *p = '\0';
- }
- } else
- indent[0] = '\0';
-
- /*
- * If we are in the parser, then plinno is the current line
- * number being processed (parser line no).
- * If we are elsewhere, then line_number gives the source
- * line of whatever we are currently doing (close enough.)
- */
- if (parsing)
- lno = plinno;
- else
- lno = line_number;
-
- c = ((i = getpid()) == tf->pid) ? ':' : '=';
-
- if (DFlags & DBG_PID) {
- if (DFlags & DBG_LINE)
- (void) asprintf(&p, "%5d%c%s\t%4d%c@\t", i, c,
- indent, lno, parsing?'-':'+');
- else
- (void) asprintf(&p, "%5d%c%s\t", i, c, indent);
- return p;
- } else if (DFlags & DBG_NEST) {
- if (DFlags & DBG_LINE)
- (void) asprintf(&p, "%c%s\t%4d%c@\t", c, indent, lno,
- parsing?'-':'+');
- else
- (void) asprintf(&p, "%c%s\t", c, indent);
- return p;
- } else if (DFlags & DBG_LINE) {
- (void) asprintf(&p, "%c%4d%c@\t", c, lno, parsing?'-':'+');
- return p;
- }
- return NULL;
-}
-
-/*
- * Used only from trargs(), which itself is used only to print
- * arg lists (argv[]) either that passed into this shell, or
- * the arg list about to be given to some other command (incl
- * builtin, and function) as their argv[]. If any of the CTL*
- * chars seem to appear, they really should be just treated as data,
- * not special... But this is just debug, so, who cares!
- */
-static void
-trstring(const char *s)
-{
- const char *p;
- char c;
- TFILE *fp;
-
- if (debug != 1 || !tracetfile)
- return;
- fp = tracetfile;
- trace_putc('"', fp);
- for (p = s ; *p ; p++) {
- switch (*p) {
- case '\n': c = 'n'; goto backslash;
- case '\t': c = 't'; goto backslash;
- case '\r': c = 'r'; goto backslash;
- case '"': c = '"'; goto backslash;
- case '\\': c = '\\'; goto backslash;
- case CTLESC: c = 'e'; goto backslash;
- case CTLVAR: c = 'v'; goto backslash;
- case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
- case CTLBACKQ: c = 'q'; goto backslash;
- case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
-backslash: trace_putc('\\', fp);
- trace_putc(c, fp);
- break;
- default:
- if (*p >= ' ' && *p <= '~')
- trace_putc(*p, fp);
- else {
- trace_putc('\\', fp);
- trace_putc(*p >> 6 & 03, fp);
- trace_putc(*p >> 3 & 07, fp);
- trace_putc(*p & 07, fp);
- }
- break;
- }
- }
- trace_putc('"', fp);
-}
-
-/*
- * deal with the user "accidentally" picking our fd to use.
- */
-static void
-trace_fd_swap(int from, int to)
-{
- if (tracetfile == NULL || from == to)
- return;
-
- tracetfile->tfd = to;
-
- /*
- * This is just so histedit has a stdio FILE* to use.
- */
- if (tracefile)
- fclose(tracefile);
- tracefile = fdopen(to, "a");
- if (tracefile)
- setlinebuf(tracefile);
-}
-
-
-static struct debug_flag {
- char label;
- uint64_t flag;
-} debug_flags[] = {
- { 'a', DBG_ARITH }, /* arithmetic ( $(( )) ) */
- { 'c', DBG_CMDS }, /* command searching, ... */
- { 'e', DBG_EVAL }, /* evaluation of the parse tree */
- { 'f', DBG_REDIR }, /* file descriptors & redirections */
- { 'g', DBG_MATCH }, /* pattern matching (glob) */
- { 'h', DBG_HISTORY }, /* history & cmd line editing */
- { 'i', DBG_INPUT }, /* shell input routines */
- { 'j', DBG_JOBS }, /* job control, structures */
- { 'l', DBG_LEXER }, /* lexical analysis */
- { 'm', DBG_MEM }, /* memory management */
- { 'o', DBG_OUTPUT }, /* output routines */
- { 'p', DBG_PROCS }, /* process management, fork, ... */
- { 'r', DBG_PARSE }, /* parser, lexer, ... tree building */
- { 's', DBG_SIG }, /* signals and everything related */
- { 't', DBG_TRAP }, /* traps & signals */
- { 'v', DBG_VARS }, /* variables and parameters */
- { 'w', DBG_WAIT }, /* waits for processes to finish */
- { 'x', DBG_EXPAND }, /* word expansion ${} $() $(( )) */
- { 'z', DBG_ERRS }, /* error control, jumps, cleanup */
-
- { '0', DBG_U0 }, /* ad-hoc temp debug flag #0 */
- { '1', DBG_U1 }, /* ad-hoc temp debug flag #1 */
- { '2', DBG_U2 }, /* ad-hoc temp debug flag #2 */
- { '3', DBG_U3 }, /* ad-hoc temp debug flag #3 */
-
- { '@', DBG_LINE }, /* prefix trace lines with line# */
- { '$', DBG_PID }, /* prefix trace lines with sh pid */
- { '^', DBG_NEST }, /* show shell nesting level */
-
- /* alpha options only - but not DBG_LEXER */
- { '_', DBG_PARSE | DBG_EVAL | DBG_EXPAND | DBG_JOBS | DBG_SIG |
- DBG_PROCS | DBG_REDIR | DBG_CMDS | DBG_ERRS |
- DBG_WAIT | DBG_TRAP | DBG_VARS | DBG_MEM | DBG_MATCH |
- DBG_INPUT | DBG_OUTPUT | DBG_ARITH | DBG_HISTORY },
-
- /* { '*', DBG_ALLVERBOSE }, is handled in the code */
-
- { '#', DBG_U0 | DBG_U1 | DBG_U2 | DBG_U3 },
-
- { 0, 0 }
-};
-
-void
-set_debug(const char * flags, int on)
-{
- char f;
- struct debug_flag *df;
- int verbose;
-
- while ((f = *flags++) != '\0') {
- verbose = 0;
- if (is_upper(f)) {
- verbose = 1;
- f += 'a' - 'A';
- }
- if (f == '*')
- f = '_', verbose = 1;
- if (f == '+') {
- if (*flags == '+')
- flags++, verbose=1;
- }
-
- /*
- * Note: turning on any debug option also enables DBG_ALWAYS
- * turning on any verbose option also enables DBG_VERBOSE
- * Once enabled, those flags cannot be disabled.
- * (tracing can still be turned off with "set +o debug")
- */
- for (df = debug_flags; df->label != '\0'; df++) {
- if (f == '+' || df->label == f) {
- if (on) {
- DFlags |= DBG_ALWAYS | df->flag;
- if (verbose)
- DFlags |= DBG_VERBOSE |
- (df->flag << DBG_VBOSE_SHIFT);
- } else {
- DFlags &= ~(df->flag<<DBG_VBOSE_SHIFT);
- if (!verbose)
- DFlags &= ~df->flag;
- }
- }
- }
- }
-}
-
-
-int
-debugcmd(int argc, char **argv)
-{
- if (argc == 1) {
- struct debug_flag *df;
-
- out1fmt("Debug: %sabled. Flags: ", debug ? "en" : "dis");
- for (df = debug_flags; df->label != '\0'; df++) {
- if (df->flag & (df->flag - 1))
- continue;
- if (is_alpha(df->label) &&
- (df->flag << DBG_VBOSE_SHIFT) & DFlags)
- out1c(df->label - ('a' - 'A'));
- else if (df->flag & DFlags)
- out1c(df->label);
- }
- out1c('\n');
- return 0;
- }
-
- while (*++argv) {
- if (**argv == '-')
- set_debug(*argv + 1, 1);
- else if (**argv == '+')
- set_debug(*argv + 1, 0);
- else
- return 1;
- }
- return 0;
-}
-
-#endif /* DEBUG */
diff --git a/bin/sh/show.h b/bin/sh/show.h
deleted file mode 100644
index 2c48873..0000000
--- a/bin/sh/show.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/* $NetBSD: show.h,v 1.11 2017/06/30 23:00:40 kre Exp $ */
-
-/*-
- * Copyright (c) 1995
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 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.
- *
- * @(#)show.h 1.1 (Berkeley) 5/4/95
- */
-
-#include <stdarg.h>
-
-#ifdef DEBUG
-union node;
-void showtree(union node *);
-void trace(const char *, ...);
-void tracev(const char *, va_list);
-void trargs(char **);
-void trargstr(union node *);
-void trputc(int);
-void trputs(const char *);
-void opentrace(void);
-#endif
diff --git a/bin/sh/syntax.c b/bin/sh/syntax.c
deleted file mode 100644
index 7b460d4..0000000
--- a/bin/sh/syntax.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/* $NetBSD: syntax.c,v 1.7 2018/12/03 06:40:26 kre Exp $ */
-
-#include <sys/cdefs.h>
-__RCSID("$NetBSD: syntax.c,v 1.7 2018/12/03 06:40:26 kre Exp $");
-
-#include <limits.h>
-#include "shell.h"
-#include "syntax.h"
-#include "parser.h"
-
-#if CWORD != 0
-#error initialisation assumes 'CWORD' is zero
-#endif
-
-#define ndx(ch) (ch + 2 - CHAR_MIN)
-#define set(ch, val) [ndx(ch)] = val,
-#define set_range(s, e, val) [ndx(s) ... ndx(e)] = val,
-
-/* syntax table used when not in quotes */
-const char basesyntax[258] = { CFAKE, CEOF,
- set_range(CTL_FIRST, CTL_LAST, CCTL)
- set('\n', CNL)
- set('\\', CBACK)
- set('\'', CSQUOTE)
- set('"', CDQUOTE)
- set('`', CBQUOTE)
- set('$', CVAR)
- set('}', CENDVAR)
- set('<', CSPCL)
- set('>', CSPCL)
- set('(', CSPCL)
- set(')', CSPCL)
- set(';', CSPCL)
- set('&', CSPCL)
- set('|', CSPCL)
- set(' ', CSPCL)
- set('\t', CSPCL)
-};
-
-/* syntax table used when in double quotes */
-const char dqsyntax[258] = { CFAKE, CEOF,
- set_range(CTL_FIRST, CTL_LAST, CCTL)
- set('\n', CNL)
- set('\\', CBACK)
- set('"', CDQUOTE)
- set('`', CBQUOTE)
- set('$', CVAR)
- set('}', CENDVAR)
- /* ':/' for tilde expansion, '-]' for [a\-x] pattern ranges */
- set('!', CCTL)
- set('*', CCTL)
- set('?', CCTL)
- set('[', CCTL)
- set('=', CCTL)
- set('~', CCTL)
- set(':', CCTL)
- set('/', CCTL)
- set('-', CCTL)
- set(']', CCTL)
-};
-
-/* syntax table used when in single quotes */
-const char sqsyntax[258] = { CFAKE, CEOF,
- set_range(CTL_FIRST, CTL_LAST, CCTL)
- set('\n', CNL)
- set('\'', CSQUOTE)
- set('\\', CSBACK)
- /* ':/' for tilde expansion, '-]' for [a\-x] pattern ranges */
- set('!', CCTL)
- set('*', CCTL)
- set('?', CCTL)
- set('[', CCTL)
- set('=', CCTL)
- set('~', CCTL)
- set(':', CCTL)
- set('/', CCTL)
- set('-', CCTL)
- set(']', CCTL)
-};
-
-/* syntax table used when in arithmetic */
-const char arisyntax[258] = { CFAKE, CEOF,
- set_range(CTL_FIRST, CTL_LAST, CCTL)
- set('\n', CNL)
- set('\\', CBACK)
- set('`', CBQUOTE)
- set('\'', CSQUOTE)
- set('"', CDQUOTE)
- set('$', CVAR)
- set('}', CENDVAR)
- set('(', CLP)
- set(')', CRP)
-};
-
-/* character classification table */
-const char is_type[258] = { 0, 0,
- set_range('0', '9', ISDIGIT)
- set_range('a', 'z', ISLOWER)
- set_range('A', 'Z', ISUPPER)
- set('_', ISUNDER)
- set('#', ISSPECL)
- set('?', ISSPECL)
- set('$', ISSPECL)
- set('!', ISSPECL)
- set('-', ISSPECL)
- set('*', ISSPECL)
- set('@', ISSPECL)
- set(' ', ISSPACE)
- set('\t', ISSPACE)
- set('\n', ISSPACE)
-};
diff --git a/bin/sh/syntax.h b/bin/sh/syntax.h
deleted file mode 100644
index ad064b8..0000000
--- a/bin/sh/syntax.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/* $NetBSD: syntax.h,v 1.11 2018/12/03 06:40:26 kre Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- */
-
-#include <sys/cdefs.h>
-#include <ctype.h>
-
-/* Syntax classes */
-#define CWORD 0 /* character is nothing special */
-#define CNL 1 /* newline character */
-#define CBACK 2 /* a backslash character */
-#define CSQUOTE 3 /* single quote */
-#define CDQUOTE 4 /* double quote */
-#define CBQUOTE 5 /* backwards single quote */
-#define CVAR 6 /* a dollar sign */
-#define CENDVAR 7 /* a '}' character */
-#define CLP 8 /* a left paren in arithmetic */
-#define CRP 9 /* a right paren in arithmetic */
-#define CEOF 10 /* end of file */
-#define CSPCL 11 /* these terminate a word */
-#define CCTL 12 /* like CWORD, except it must be escaped */
-#define CSBACK 13 /* a backslash in a single quote syntax */
-#define CFAKE 14 /* a delimiter that does not exist */
- /*
- * note CSBACK == (CCTL|1)
- * the code does not rely upon that, but keeping it allows a
- * smart enough compiler to optimise some tests
- */
-
-/* Syntax classes for is_ functions */
-#define ISDIGIT 01 /* a digit */
-#define ISUPPER 02 /* an upper case letter */
-#define ISLOWER 04 /* a lower case letter */
-#define ISUNDER 010 /* an underscore */
-#define ISSPECL 020 /* the name of a special parameter */
-#define ISSPACE 040 /* a white space character */
-
-#define PEOF (CHAR_MIN - 1)
-#define PFAKE (CHAR_MIN - 2)
-#define SYNBASE (-PFAKE)
-
-
-#define BASESYNTAX (basesyntax + SYNBASE)
-#define DQSYNTAX (dqsyntax + SYNBASE)
-#define SQSYNTAX (sqsyntax + SYNBASE)
-#define ARISYNTAX (arisyntax + SYNBASE)
-
-/* These defines assume that the digits are contiguous (which is guaranteed) */
-#define is_digit(c) ((unsigned)((c) - '0') <= 9)
-#define sh_ctype(c) (is_type+SYNBASE)[(int)(c)]
-#define is_upper(c) (sh_ctype(c) & ISUPPER)
-#define is_lower(c) (sh_ctype(c) & ISLOWER)
-#define is_alpha(c) (sh_ctype(c) & (ISUPPER|ISLOWER))
-#define is_name(c) (sh_ctype(c) & (ISUPPER|ISLOWER|ISUNDER))
-#define is_in_name(c) (sh_ctype(c) & (ISUPPER|ISLOWER|ISUNDER|ISDIGIT))
-#define is_special(c) (sh_ctype(c) & (ISSPECL|ISDIGIT))
-#define is_space(c) (sh_ctype(c) & ISSPACE)
-#define digit_val(c) ((c) - '0')
-
-/* true if the arg char needs CTLESC to protect it */
-#define NEEDESC(c) (SQSYNTAX[(int)(c)] == CCTL || \
- SQSYNTAX[(int)(c)] == CSBACK)
-
-extern const char basesyntax[];
-extern const char dqsyntax[];
-extern const char sqsyntax[];
-extern const char arisyntax[];
-extern const char is_type[];
diff --git a/bin/sh/trap.c b/bin/sh/trap.c
deleted file mode 100644
index cb641fd..0000000
--- a/bin/sh/trap.c
+++ /dev/null
@@ -1,837 +0,0 @@
-/* $NetBSD: trap.c,v 1.51 2019/01/18 06:28:09 kre Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- */
-
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)trap.c 8.5 (Berkeley) 6/5/95";
-#else
-__RCSID("$NetBSD: trap.c,v 1.51 2019/01/18 06:28:09 kre Exp $");
-#endif
-#endif /* not lint */
-
-#include <signal.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-#include <termios.h>
-
-#undef CEOF /* from <termios.h> but concflicts with sh use */
-
-#include <sys/ioctl.h>
-#include <sys/resource.h>
-
-#include "shell.h"
-#include "main.h"
-#include "nodes.h" /* for other headers */
-#include "eval.h"
-#include "jobs.h"
-#include "show.h"
-#include "options.h"
-#include "builtins.h"
-#include "syntax.h"
-#include "output.h"
-#include "memalloc.h"
-#include "error.h"
-#include "trap.h"
-#include "mystring.h"
-#include "var.h"
-
-
-/*
- * Sigmode records the current value of the signal handlers for the various
- * modes. A value of zero means that the current handler is not known.
- * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
- */
-
-#define S_DFL 1 /* default signal handling (SIG_DFL) */
-#define S_CATCH 2 /* signal is caught */
-#define S_IGN 3 /* signal is ignored (SIG_IGN) */
-#define S_HARD_IGN 4 /* signal is ignored permenantly */
-#define S_RESET 5 /* temporary - to reset a hard ignored sig */
-
-
-MKINIT char sigmode[NSIG]; /* current value of signal */
-static volatile sig_atomic_t gotsig[NSIG];/* indicates specified signal received */
-volatile sig_atomic_t pendingsigs; /* indicates some signal received */
-
-int traps_invalid; /* in a subshell, but trap[] not yet cleared */
-static char * volatile trap[NSIG]; /* trap handler commands */
-static int in_dotrap;
-static int last_trapsig;
-
-static int exiting; /* exitshell() has been done */
-static int exiting_status; /* the status to use for exit() */
-
-static int getsigaction(int, sig_t *);
-STATIC const char *trap_signame(int);
-void printsignals(struct output *, int);
-
-/*
- * return the signal number described by `p' (as a number or a name)
- * or -1 if it isn't one
- */
-
-static int
-signame_to_signum(const char *p)
-{
- int i;
-
- if (is_number(p))
- return number(p);
-
- if (strcasecmp(p, "exit") == 0 )
- return 0;
-
- i = signalnumber(p);
- if (i == 0)
- i = -1;
- return i;
-}
-
-/*
- * return the name of a signal used by the "trap" command
- */
-STATIC const char *
-trap_signame(int signo)
-{
- static char nbuf[12];
- const char *p;
-
- if (signo == 0)
- return "EXIT";
- p = signalname(signo);
- if (p != NULL)
- return p;
- (void)snprintf(nbuf, sizeof nbuf, "%d", signo);
- return nbuf;
-}
-
-#ifdef SMALL
-/*
- * Print a list of valid signal names
- */
-void
-printsignals(struct output *out, int len)
-{
- int n;
-
- if (len != 0)
- outc(' ', out);
- for (n = 1; n < NSIG; n++) {
- outfmt(out, "%s", trap_signame(n));
- if ((n == NSIG/2) || n == (NSIG - 1))
- outstr("\n", out);
- else
- outc(' ', out);
- }
-}
-#else /* !SMALL */
-/*
- * Print the names of all the signals (neatly) to fp
- * "len" gives the number of chars already printed to
- * the current output line (in kill.c, always 0)
- */
-void
-printsignals(struct output *out, int len)
-{
- int sig;
- int nl, pad;
- const char *name;
- int termwidth = 80;
-
- if ((name = bltinlookup("COLUMNS", 1)) != NULL)
- termwidth = (int)strtol(name, NULL, 10);
- else if (isatty(1)) {
- struct winsize win;
-
- if (ioctl(1, TIOCGWINSZ, &win) == 0 && win.ws_col > 0)
- termwidth = win.ws_col;
- }
-
- if (posix)
- pad = 1;
- else
- pad = (len | 7) + 1 - len;
-
- for (sig = 0; (sig = signalnext(sig)) != 0; ) {
- name = signalname(sig);
- if (name == NULL)
- continue;
-
- nl = strlen(name);
-
- if (len > 0 && nl + len + pad >= termwidth) {
- outc('\n', out);
- len = 0;
- pad = 0;
- } else if (pad > 0 && len != 0)
- outfmt(out, "%*s", pad, "");
- else
- pad = 0;
-
- len += nl + pad;
- if (!posix)
- pad = (nl | 7) + 1 - nl;
- else
- pad = 1;
-
- outstr(name, out);
- }
- if (len != 0)
- outc('\n', out);
-}
-#endif /* SMALL */
-
-/*
- * The trap builtin.
- */
-
-int
-trapcmd(int argc, char **argv)
-{
- char *action;
- char **ap;
- int signo;
- int errs = 0;
- int printonly = 0;
-
- ap = argv + 1;
-
- CTRACE(DBG_TRAP, ("trapcmd: "));
- if (argc == 2 && strcmp(*ap, "-l") == 0) {
- CTRACE(DBG_TRAP, ("-l\n"));
- out1str("EXIT");
- printsignals(out1, 4);
- return 0;
- }
- if (argc == 2 && strcmp(*ap, "-") == 0) {
- CTRACE(DBG_TRAP, ("-\n"));
- for (signo = 0; signo < NSIG; signo++) {
- if (trap[signo] == NULL)
- continue;
- INTOFF;
- ckfree(trap[signo]);
- trap[signo] = NULL;
- if (signo != 0)
- setsignal(signo, 0);
- INTON;
- }
- traps_invalid = 0;
- return 0;
- }
- if (argc >= 2 && strcmp(*ap, "-p") == 0) {
- CTRACE(DBG_TRAP, ("-p "));
- printonly = 1;
- ap++;
- argc--;
- }
-
- if (argc > 1 && strcmp(*ap, "--") == 0) {
- argc--;
- ap++;
- }
-
- if (argc <= 1) {
- int count;
-
- CTRACE(DBG_TRAP, ("*all*\n"));
- if (printonly) {
- for (count = 0, signo = 0 ; signo < NSIG ; signo++)
- if (trap[signo] == NULL) {
- if (count == 0)
- out1str("trap -- -");
- out1fmt(" %s", trap_signame(signo));
- /* oh! unlucky 13 */
- if (++count >= 13) {
- out1str("\n");
- count = 0;
- }
- }
- if (count)
- out1str("\n");
- }
-
- for (count = 0, signo = 0 ; signo < NSIG ; signo++)
- if (trap[signo] != NULL && trap[signo][0] == '\0') {
- if (count == 0)
- out1str("trap -- ''");
- out1fmt(" %s", trap_signame(signo));
- /*
- * the prefix is 10 bytes, with 4 byte
- * signal names (common) we have room in
- * the 70 bytes left on a normal line for
- * 70/(4+1) signals, that's 14, but to
- * allow for the occasional longer sig name
- * we output one less...
- */
- if (++count >= 13) {
- out1str("\n");
- count = 0;
- }
- }
- if (count)
- out1str("\n");
-
- for (signo = 0 ; signo < NSIG ; signo++)
- if (trap[signo] != NULL && trap[signo][0] != '\0') {
- out1str("trap -- ");
- print_quoted(trap[signo]);
- out1fmt(" %s\n", trap_signame(signo));
- }
-
- return 0;
- }
- CTRACE(DBG_TRAP, ("\n"));
-
- action = NULL;
-
- if (!printonly && traps_invalid)
- free_traps();
-
- if (!printonly && !is_number(*ap)) {
- if ((*ap)[0] == '-' && (*ap)[1] == '\0')
- ap++; /* reset to default */
- else
- action = *ap++; /* can be '' for "ignore" */
- argc--;
- }
-
- if (argc < 2) { /* there must be at least 1 condition */
- out2str("Usage: trap [-l]\n"
- " trap -p [condition ...]\n"
- " trap action condition ...\n"
- " trap N condition ...\n");
- return 2;
- }
-
-
- while (*ap) {
- signo = signame_to_signum(*ap);
-
- if (signo < 0 || signo >= NSIG) {
- /* This is not a fatal error, so sayeth posix */
- outfmt(out2, "trap: '%s' bad condition\n", *ap);
- errs = 1;
- ap++;
- continue;
- }
- ap++;
-
- if (printonly) {
- out1str("trap -- ");
- if (trap[signo] == NULL)
- out1str("-");
- else
- print_quoted(trap[signo]);
- out1fmt(" %s\n", trap_signame(signo));
- continue;
- }
-
- INTOFF;
- if (action)
- action = savestr(action);
-
- VTRACE(DBG_TRAP, ("trap for %d from %s%s%s to %s%s%s\n", signo,
- trap[signo] ? "'" : "", trap[signo] ? trap[signo] : "-",
- trap[signo] ? "'" : "", action ? "'" : "",
- action ? action : "-", action ? "'" : ""));
-
- if (trap[signo])
- ckfree(trap[signo]);
-
- trap[signo] = action;
-
- if (signo != 0)
- setsignal(signo, 0);
- INTON;
- }
- return errs;
-}
-
-
-
-/*
- * Clear traps on a fork or vfork.
- * Takes one arg vfork, to tell it to not be destructive of
- * the parents variables.
- */
-void
-clear_traps(int vforked)
-{
- char * volatile *tp;
-
- VTRACE(DBG_TRAP, ("clear_traps(%d)\n", vforked));
- if (!vforked)
- traps_invalid = 1;
-
- for (tp = &trap[1] ; tp < &trap[NSIG] ; tp++) {
- if (*tp && **tp) { /* trap not NULL or SIG_IGN */
- INTOFF;
- setsignal(tp - trap, vforked == 1);
- INTON;
- }
- }
- if (vforked == 2)
- free_traps();
-}
-
-void
-free_traps(void)
-{
- char * volatile *tp;
-
- VTRACE(DBG_TRAP, ("free_traps%s\n", traps_invalid ? "(invalid)" : ""));
- INTOFF;
- for (tp = trap ; tp < &trap[NSIG] ; tp++)
- if (*tp && **tp) {
- ckfree(*tp);
- *tp = NULL;
- }
- traps_invalid = 0;
- INTON;
-}
-
-/*
- * See if there are any defined traps
- */
-int
-have_traps(void)
-{
- char * volatile *tp;
-
- if (traps_invalid)
- return 0;
-
- for (tp = trap ; tp < &trap[NSIG] ; tp++)
- if (*tp && **tp) /* trap not NULL or SIG_IGN */
- return 1;
- return 0;
-}
-
-/*
- * Set the signal handler for the specified signal. The routine figures
- * out what it should be set to.
- */
-void
-setsignal(int signo, int vforked)
-{
- int action;
- sig_t sigact = SIG_DFL, sig;
- char *t, tsig;
-
- if (traps_invalid || (t = trap[signo]) == NULL)
- action = S_DFL;
- else if (*t != '\0')
- action = S_CATCH;
- else
- action = S_IGN;
-
- VTRACE(DBG_TRAP, ("setsignal(%d%s) -> %d", signo,
- vforked ? ", VF" : "", action));
- if (rootshell && !vforked && action == S_DFL) {
- switch (signo) {
- case SIGINT:
- if (iflag || minusc || sflag == 0)
- action = S_CATCH;
- break;
- case SIGQUIT:
-#ifdef DEBUG
- if (debug)
- break;
-#endif
- /* FALLTHROUGH */
- case SIGTERM:
- if (rootshell && iflag)
- action = S_IGN;
- break;
-#if JOBS
- case SIGTSTP:
- case SIGTTOU:
- if (rootshell && mflag)
- action = S_IGN;
- break;
-#endif
- }
- }
-
- /*
- * Never let users futz with SIGCHLD
- * instead we will give them pseudo SIGCHLD's
- * when background jobs complete.
- */
- if (signo == SIGCHLD)
- action = S_DFL;
-
- VTRACE(DBG_TRAP, (" -> %d", action));
-
- t = &sigmode[signo];
- tsig = *t;
- if (tsig == 0) {
- /*
- * current setting unknown
- */
- if (!getsigaction(signo, &sigact)) {
- /*
- * Pretend it worked; maybe we should give a warning
- * here, but other shells don't. We don't alter
- * sigmode, so that we retry every time.
- */
- VTRACE(DBG_TRAP, (" getsigaction (%d)\n", errno));
- return;
- }
- VTRACE(DBG_TRAP, (" [%s]%s%s", sigact==SIG_IGN ? "IGN" :
- sigact==SIG_DFL ? "DFL" : "caught",
- iflag ? "i" : "", mflag ? "m" : ""));
-
- if (sigact == SIG_IGN) {
- /*
- * POSIX 3.14.13 states that non-interactive shells
- * should ignore trap commands for signals that were
- * ignored upon entry, and leaves the behavior
- * unspecified for interactive shells. On interactive
- * shells, or if job control is on, and we have a job
- * control related signal, we allow the trap to work.
- *
- * This change allows us to be POSIX compliant, and
- * at the same time override the default behavior if
- * we need to by setting the interactive flag.
- */
- if ((mflag && (signo == SIGTSTP ||
- signo == SIGTTIN || signo == SIGTTOU)) || iflag) {
- tsig = S_IGN;
- } else
- tsig = S_HARD_IGN;
- } else {
- tsig = S_RESET; /* force to be set */
- }
- }
- VTRACE(DBG_TRAP, (" tsig=%d\n", tsig));
-
- if (tsig == S_HARD_IGN || tsig == action)
- return;
-
- switch (action) {
- case S_DFL: sigact = SIG_DFL; break;
- case S_CATCH: sigact = onsig; break;
- case S_IGN: sigact = SIG_IGN; break;
- }
-
- sig = signal(signo, sigact);
-
- if (sig != SIG_ERR) {
- sigset_t ss;
-
- if (!vforked)
- *t = action;
-
- if (action == S_CATCH)
- (void)siginterrupt(signo, 1);
- /*
- * If our parent accidentally blocked signals for
- * us make sure we unblock them
- */
- (void)sigemptyset(&ss);
- (void)sigaddset(&ss, signo);
- (void)sigprocmask(SIG_UNBLOCK, &ss, NULL);
- }
- return;
-}
-
-/*
- * Return the current setting for sig w/o changing it.
- */
-static int
-getsigaction(int signo, sig_t *sigact)
-{
- struct sigaction sa;
-
- if (sigaction(signo, (struct sigaction *)0, &sa) == -1)
- return 0;
- *sigact = (sig_t) sa.sa_handler;
- return 1;
-}
-
-/*
- * Ignore a signal.
- */
-
-void
-ignoresig(int signo, int vforked)
-{
- if (sigmode[signo] == 0)
- setsignal(signo, vforked);
-
- VTRACE(DBG_TRAP, ("ignoresig(%d%s)\n", signo, vforked ? ", VF" : ""));
- if (sigmode[signo] != S_IGN && sigmode[signo] != S_HARD_IGN) {
- signal(signo, SIG_IGN);
- if (!vforked)
- sigmode[signo] = S_IGN;
- }
-}
-
-char *
-child_trap(void)
-{
- char * p;
-
- p = trap[SIGCHLD];
-
- if (traps_invalid || (p != NULL && *p == '\0'))
- p = NULL;
-
- return p;
-}
-
-
-#ifdef mkinit
-INCLUDE <signal.h>
-INCLUDE "trap.h"
-INCLUDE "shell.h"
-INCLUDE "show.h"
-
-SHELLPROC {
- char *sm;
-
- INTOFF;
- clear_traps(2);
- for (sm = sigmode ; sm < sigmode + NSIG ; sm++) {
- if (*sm == S_IGN) {
- *sm = S_HARD_IGN;
- VTRACE(DBG_TRAP, ("SHELLPROC: %d -> hard_ign\n",
- (sm - sigmode)));
- }
- }
- INTON;
-}
-#endif
-
-
-
-/*
- * Signal handler.
- */
-
-void
-onsig(int signo)
-{
- CTRACE(DBG_SIG, ("Signal %d, had: pending %d, gotsig[%d]=%d\n",
- signo, pendingsigs, signo, gotsig[signo]));
-
- /* This should not be needed.
- signal(signo, onsig);
- */
-
- if (signo == SIGINT && (traps_invalid || trap[SIGINT] == NULL)) {
- onint();
- return;
- }
-
- /*
- * if the signal will do nothing, no point reporting it
- */
- if (!traps_invalid && trap[signo] != NULL && trap[signo][0] != '\0' &&
- signo != SIGCHLD) {
- gotsig[signo] = 1;
- pendingsigs++;
- }
-}
-
-
-
-/*
- * Called to execute a trap. Perhaps we should avoid entering new trap
- * handlers while we are executing a trap handler.
- */
-
-void
-dotrap(void)
-{
- int i;
- char *tr;
- int savestatus;
- struct skipsave saveskip;
-
- in_dotrap++;
-
- CTRACE(DBG_TRAP, ("dotrap[%d]: %d pending, traps %sinvalid\n",
- in_dotrap, pendingsigs, traps_invalid ? "" : "not "));
- for (;;) {
- pendingsigs = 0;
- for (i = 1 ; ; i++) {
- if (i >= NSIG)
- return;
- if (gotsig[i])
- break;
- }
- gotsig[i] = 0;
-
- if (traps_invalid)
- continue;
-
- tr = trap[i];
-
- CTRACE(DBG_TRAP|DBG_SIG, ("dotrap %d: %s%s%s\n", i,
- tr ? "\"" : "", tr ? tr : "NULL", tr ? "\"" : ""));
-
- if (tr != NULL) {
- last_trapsig = i;
- save_skipstate(&saveskip);
- savestatus = exitstatus;
-
- tr = savestr(tr); /* trap code may free trap[i] */
- evalstring(tr, 0);
- ckfree(tr);
-
- if (current_skipstate() == SKIPNONE ||
- saveskip.state != SKIPNONE) {
- restore_skipstate(&saveskip);
- exitstatus = savestatus;
- }
- }
- }
-
- in_dotrap--;
-}
-
-int
-lastsig(void)
-{
- int i;
-
- for (i = NSIG; --i > 0; )
- if (gotsig[i])
- return i;
- return SIGINT; /* XXX */
-}
-
-/*
- * Controls whether the shell is interactive or not.
- */
-
-
-void
-setinteractive(int on)
-{
- static int is_interactive;
-
- if (on == is_interactive)
- return;
- setsignal(SIGINT, 0);
- setsignal(SIGQUIT, 0);
- setsignal(SIGTERM, 0);
- is_interactive = on;
-}
-
-
-
-/*
- * Called to exit the shell.
- */
-void
-exitshell(int status)
-{
- CTRACE(DBG_ERRS|DBG_PROCS|DBG_CMDS|DBG_TRAP,
- ("pid %d: exitshell(%d)\n", getpid(), status));
-
- exiting = 1;
- exiting_status = status;
- exitshell_savedstatus();
-}
-
-void
-exitshell_savedstatus(void)
-{
- struct jmploc loc;
- char *p;
- volatile int sig = 0;
- int s;
- sigset_t sigs;
-
- CTRACE(DBG_ERRS|DBG_PROCS|DBG_CMDS|DBG_TRAP,
- ("pid %d: exitshell_savedstatus()%s $?=%d xs=%d dt=%d ts=%d\n",
- getpid(), exiting ? " exiting" : "", exitstatus,
- exiting_status, in_dotrap, last_trapsig));
-
- if (!exiting) {
- if (in_dotrap && last_trapsig) {
- sig = last_trapsig;
- exiting_status = sig + 128;
- } else
- exiting_status = exitstatus;
- }
- exitstatus = exiting_status;
-
- if (!setjmp(loc.loc)) {
- handler = &loc;
-
- if (!traps_invalid && (p = trap[0]) != NULL && *p != '\0') {
- reset_eval();
- trap[0] = NULL;
- VTRACE(DBG_TRAP, ("exit trap: \"%s\"\n", p));
- evalstring(p, 0);
- }
- }
-
- INTOFF; /* we're done, no more interrupts. */
-
- if (!setjmp(loc.loc)) {
- handler = &loc; /* probably unnecessary */
- flushall();
-#if JOBS
- setjobctl(0);
-#endif
- }
-
- if ((s = sig) != 0 && s != SIGSTOP && s != SIGTSTP && s != SIGTTIN &&
- s != SIGTTOU) {
- struct rlimit nocore;
-
- /*
- * if the signal is of the core dump variety, don't...
- */
- nocore.rlim_cur = nocore.rlim_max = 0;
- (void) setrlimit(RLIMIT_CORE, &nocore);
-
- signal(s, SIG_DFL);
- sigemptyset(&sigs);
- sigaddset(&sigs, s);
- sigprocmask(SIG_UNBLOCK, &sigs, NULL);
-
- kill(getpid(), s);
- }
- _exit(exiting_status);
- /* NOTREACHED */
-}
diff --git a/bin/sh/trap.h b/bin/sh/trap.h
deleted file mode 100644
index 7ea3ef1..0000000
--- a/bin/sh/trap.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* $NetBSD: trap.h,v 1.25 2018/12/03 10:53:29 martin Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- *
- * @(#)trap.h 8.3 (Berkeley) 6/5/95
- */
-
-extern volatile sig_atomic_t pendingsigs;
-
-extern int traps_invalid;
-
-void clear_traps(int);
-void free_traps(void);
-int have_traps(void);
-void setsignal(int, int);
-void ignoresig(int, int);
-void onsig(int);
-void dotrap(void);
-char *child_trap(void);
-void setinteractive(int);
-void exitshell(int) __dead;
-void exitshell_savedstatus(void) __dead;
-int lastsig(void);
diff --git a/bin/sh/var.c b/bin/sh/var.c
deleted file mode 100644
index 378598c..0000000
--- a/bin/sh/var.c
+++ /dev/null
@@ -1,1587 +0,0 @@
-/* $NetBSD: var.c,v 1.75 2019/01/21 13:27:29 kre Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- */
-
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 5/4/95";
-#else
-__RCSID("$NetBSD: var.c,v 1.75 2019/01/21 13:27:29 kre Exp $");
-#endif
-#endif /* not lint */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <paths.h>
-#include <limits.h>
-#include <time.h>
-#include <pwd.h>
-#include <fcntl.h>
-#include <inttypes.h>
-
-/*
- * Shell variables.
- */
-
-#include "shell.h"
-#include "output.h"
-#include "expand.h"
-#include "nodes.h" /* for other headers */
-#include "eval.h" /* defines cmdenviron */
-#include "exec.h"
-#include "syntax.h"
-#include "options.h"
-#include "builtins.h"
-#include "mail.h"
-#include "var.h"
-#include "memalloc.h"
-#include "error.h"
-#include "mystring.h"
-#include "parser.h"
-#include "show.h"
-#include "machdep.h"
-#ifndef SMALL
-#include "myhistedit.h"
-#endif
-
-#ifdef SMALL
-#define VTABSIZE 39
-#else
-#define VTABSIZE 517
-#endif
-
-
-struct varinit {
- struct var *var;
- int flags;
- const char *text;
- union var_func_union v_u;
-};
-#define func v_u.set_func
-#define rfunc v_u.ref_func
-
-char *get_lineno(struct var *);
-
-#ifndef SMALL
-char *get_tod(struct var *);
-char *get_hostname(struct var *);
-char *get_seconds(struct var *);
-char *get_euser(struct var *);
-char *get_random(struct var *);
-#endif
-
-struct localvar *localvars;
-
-#ifndef SMALL
-struct var vhistsize;
-struct var vterm;
-struct var editrc;
-struct var ps_lit;
-#endif
-struct var vifs;
-struct var vmail;
-struct var vmpath;
-struct var vpath;
-struct var vps1;
-struct var vps2;
-struct var vps4;
-struct var vvers;
-struct var voptind;
-struct var line_num;
-#ifndef SMALL
-struct var tod;
-struct var host_name;
-struct var seconds;
-struct var euname;
-struct var random_num;
-
-intmax_t sh_start_time;
-#endif
-
-struct var line_num;
-int line_number;
-int funclinebase = 0;
-int funclineabs = 0;
-
-char ifs_default[] = " \t\n";
-
-const struct varinit varinit[] = {
-#ifndef SMALL
- { &vhistsize, VSTRFIXED|VTEXTFIXED|VUNSET, "HISTSIZE=",
- { .set_func= sethistsize } },
-#endif
- { &vifs, VSTRFIXED|VTEXTFIXED, "IFS= \t\n",
- { NULL } },
- { &vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=",
- { NULL } },
- { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=",
- { NULL } },
- { &vvers, VSTRFIXED|VTEXTFIXED|VNOEXPORT, "NETBSD_SHELL=",
- { NULL } },
- { &vpath, VSTRFIXED|VTEXTFIXED, "PATH=" _PATH_DEFPATH,
- { .set_func= changepath } },
- /*
- * vps1 depends on uid
- */
- { &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ",
- { NULL } },
- { &vps4, VSTRFIXED|VTEXTFIXED, "PS4=+ ",
- { NULL } },
-#ifndef SMALL
- { &vterm, VSTRFIXED|VTEXTFIXED|VUNSET, "TERM=",
- { .set_func= setterm } },
- { &editrc, VSTRFIXED|VTEXTFIXED|VUNSET, "EDITRC=",
- { .set_func= set_editrc } },
- { &ps_lit, VSTRFIXED|VTEXTFIXED|VUNSET, "PSlit=",
- { .set_func= set_prompt_lit } },
-#endif
- { &voptind, VSTRFIXED|VTEXTFIXED|VNOFUNC, "OPTIND=1",
- { .set_func= getoptsreset } },
- { &line_num, VSTRFIXED|VTEXTFIXED|VFUNCREF|VSPECIAL, "LINENO=1",
- { .ref_func= get_lineno } },
-#ifndef SMALL
- { &tod, VSTRFIXED|VTEXTFIXED|VFUNCREF, "ToD=",
- { .ref_func= get_tod } },
- { &host_name, VSTRFIXED|VTEXTFIXED|VFUNCREF, "HOSTNAME=",
- { .ref_func= get_hostname } },
- { &seconds, VSTRFIXED|VTEXTFIXED|VFUNCREF, "SECONDS=",
- { .ref_func= get_seconds } },
- { &euname, VSTRFIXED|VTEXTFIXED|VFUNCREF, "EUSER=",
- { .ref_func= get_euser } },
- { &random_num, VSTRFIXED|VTEXTFIXED|VFUNCREF|VSPECIAL, "RANDOM=",
- { .ref_func= get_random } },
-#endif
- { NULL, 0, NULL,
- { NULL } }
-};
-
-struct var *vartab[VTABSIZE];
-
-STATIC int strequal(const char *, const char *);
-STATIC struct var *find_var(const char *, struct var ***, int *);
-STATIC void showvar(struct var *, const char *, const char *, int);
-static void export_usage(const char *) __dead;
-
-/*
- * Initialize the varable symbol tables and import the environment
- */
-
-#ifdef mkinit
-INCLUDE <stdio.h>
-INCLUDE <unistd.h>
-INCLUDE <time.h>
-INCLUDE "var.h"
-INCLUDE "version.h"
-MKINIT char **environ;
-INIT {
- char **envp;
- char buf[64];
-
-#ifndef SMALL
- sh_start_time = (intmax_t)time((time_t *)0);
-#endif
- /*
- * Set up our default variables and their values.
- */
- initvar();
-
- /*
- * Import variables from the environment, which will
- * override anything initialised just previously.
- */
- for (envp = environ ; *envp ; envp++) {
- if (strchr(*envp, '=')) {
- setvareq(*envp, VEXPORT|VTEXTFIXED);
- }
- }
-
- /*
- * Set variables which override anything read from environment.
- *
- * PPID is readonly
- * Always default IFS
- * POSIX: "Whenever the shell is invoked, OPTIND shall
- * be initialized to 1."
- * PSc indicates the root/non-root status of this shell.
- * START_TIME belongs only to this shell.
- * NETBSD_SHELL is a constant (readonly), and is never exported
- * LINENO is simply magic...
- */
- snprintf(buf, sizeof(buf), "%d", (int)getppid());
- setvar("PPID", buf, VREADONLY);
- setvar("IFS", ifs_default, VTEXTFIXED);
- setvar("OPTIND", "1", VTEXTFIXED);
- setvar("PSc", (geteuid() == 0 ? "#" : "$"), VTEXTFIXED);
-
-#ifndef SMALL
- snprintf(buf, sizeof(buf), "%jd", sh_start_time);
- setvar("START_TIME", buf, VTEXTFIXED);
-#endif
-
- setvar("NETBSD_SHELL", NETBSD_SHELL
-#ifdef BUILD_DATE
- " BUILD:" BUILD_DATE
-#endif
-#ifdef DEBUG
- " DEBUG"
-#endif
-#if !defined(JOBS) || JOBS == 0
- " -JOBS"
-#endif
-#ifndef DO_SHAREDVFORK
- " -VFORK"
-#endif
-#ifdef SMALL
- " SMALL"
-#endif
-#ifdef TINY
- " TINY"
-#endif
-#ifdef OLD_TTY_DRIVER
- " OLD_TTY"
-#endif
-#ifdef SYSV
- " SYSV"
-#endif
-#ifndef BSD
- " -BSD"
-#endif
-#ifdef BOGUS_NOT_COMMAND
- " BOGUS_NOT"
-#endif
- , VTEXTFIXED|VREADONLY|VNOEXPORT);
-
- setvar("LINENO", "1", VTEXTFIXED);
-}
-#endif
-
-
-/*
- * This routine initializes the builtin variables. It is called when the
- * shell is initialized and again when a shell procedure is spawned.
- */
-
-void
-initvar(void)
-{
- const struct varinit *ip;
- struct var *vp;
- struct var **vpp;
-
- for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
- if (find_var(ip->text, &vpp, &vp->name_len) != NULL)
- continue;
- vp->next = *vpp;
- *vpp = vp;
- vp->text = strdup(ip->text);
- vp->flags = (ip->flags & ~VTEXTFIXED) | VSTRFIXED;
- vp->v_u = ip->v_u;
- }
- /*
- * PS1 depends on uid
- */
- if (find_var("PS1", &vpp, &vps1.name_len) == NULL) {
- vps1.next = *vpp;
- *vpp = &vps1;
- vps1.flags = VSTRFIXED;
- vps1.text = NULL;
- choose_ps1();
- }
-}
-
-void
-choose_ps1(void)
-{
- uid_t u = geteuid();
-
- if ((vps1.flags & (VTEXTFIXED|VSTACK)) == 0)
- free(vps1.text);
- vps1.text = strdup(u != 0 ? "PS1=$ " : "PS1=# ");
- vps1.flags &= ~(VTEXTFIXED|VSTACK);
-
- /*
- * Update PSc whenever we feel the need to update PS1
- */
- setvarsafe("PSc", (u == 0 ? "#" : "$"), 0);
-}
-
-/*
- * Validate a string as a valid variable name
- * nb: not parameter - special params and such are "invalid" here.
- * Name terminated by either \0 or the term param (usually '=' or '\0').
- *
- * If not NULL, the length of the (intended) name is returned via len
- */
-
-int
-validname(const char *name, int term, int *len)
-{
- const char *p = name;
- int ok = 1;
-
- if (p == NULL || *p == '\0' || *p == term) {
- if (len != NULL)
- *len = 0;
- return 0;
- }
-
- if (!is_name(*p))
- ok = 0;
- p++;
- for (;;) {
- if (*p == '\0' || *p == term)
- break;
- if (!is_in_name(*p))
- ok = 0;
- p++;
- }
- if (len != NULL)
- *len = p - name;
-
- return ok;
-}
-
-/*
- * Safe version of setvar, returns 1 on success 0 on failure.
- */
-
-int
-setvarsafe(const char *name, const char *val, int flags)
-{
- struct jmploc jmploc;
- struct jmploc * const savehandler = handler;
- int volatile err = 0;
-
- if (setjmp(jmploc.loc))
- err = 1;
- else {
- handler = &jmploc;
- setvar(name, val, flags);
- }
- handler = savehandler;
- return err;
-}
-
-/*
- * Set the value of a variable. The flags argument is ored with the
- * flags of the variable. If val is NULL, the variable is unset.
- *
- * This always copies name and val when setting a variable, so
- * the source strings can be from anywhere, and are no longer needed
- * after this function returns. The VTEXTFIXED and VSTACK flags should
- * not be used (but just in case they were, clear them.)
- */
-
-void
-setvar(const char *name, const char *val, int flags)
-{
- const char *p;
- const char *q;
- char *d;
- int len;
- int namelen;
- char *nameeq;
-
- p = name;
-
- if (!validname(p, '=', &namelen))
- error("%.*s: bad variable name", namelen, name);
- len = namelen + 2; /* 2 is space for '=' and '\0' */
- if (val == NULL) {
- flags |= VUNSET;
- } else {
- len += strlen(val);
- }
- d = nameeq = ckmalloc(len);
- q = name;
- while (--namelen >= 0)
- *d++ = *q++;
- *d++ = '=';
- *d = '\0';
- if (val)
- scopy(val, d);
- setvareq(nameeq, flags & ~(VTEXTFIXED | VSTACK));
-}
-
-
-
-/*
- * Same as setvar except that the variable and value are passed in
- * the first argument as name=value. Since the first argument will
- * be actually stored in the table, it should not be a string that
- * will go away. The flags (VTEXTFIXED or VSTACK) can be used to
- * indicate the source of the string (if neither is set, the string will
- * eventually be free()d when a replacement value is assigned.)
- */
-
-void
-setvareq(char *s, int flags)
-{
- struct var *vp, **vpp;
- int nlen;
-
- VTRACE(DBG_VARS, ("setvareq([%s],%#x) aflag=%d ", s, flags, aflag));
- if (aflag && !(flags & VNOEXPORT))
- flags |= VEXPORT;
- vp = find_var(s, &vpp, &nlen);
- if (vp != NULL) {
- VTRACE(DBG_VARS, ("was [%s] fl:%#x\n", vp->text,
- vp->flags));
- if (vp->flags & VREADONLY) {
- if ((flags & (VTEXTFIXED|VSTACK)) == 0)
- ckfree(s);
- if (flags & VNOERROR)
- return;
- error("%.*s: is read only", vp->name_len, vp->text);
- }
- if (flags & VNOSET) {
- if ((flags & (VTEXTFIXED|VSTACK)) == 0)
- ckfree(s);
- return;
- }
-
- INTOFF;
-
- if (vp->func && !(vp->flags & VFUNCREF) && !(flags & VNOFUNC))
- (*vp->func)(s + vp->name_len + 1);
-
- if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
- ckfree(vp->text);
-
- /*
- * if we set a magic var, the magic dissipates,
- * unless it is very special indeed.
- */
- if (vp->rfunc && (vp->flags & (VFUNCREF|VSPECIAL)) == VFUNCREF)
- vp->rfunc = NULL;
-
- vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
- if (flags & VNOEXPORT)
- vp->flags &= ~VEXPORT;
- if (flags & VDOEXPORT)
- vp->flags &= ~VNOEXPORT;
- if (vp->flags & VNOEXPORT)
- flags &= ~VEXPORT;
- vp->flags |= flags & ~(VNOFUNC | VDOEXPORT);
- vp->text = s;
-
- /*
- * We could roll this to a function, to handle it as
- * a regular variable function callback, but why bother?
- */
- if (vp == &vmpath || (vp == &vmail && ! mpathset()))
- chkmail(1);
-
- INTON;
- return;
- }
- /* not found */
- if (flags & VNOSET) {
- VTRACE(DBG_VARS, ("new noset\n"));
- if ((flags & (VTEXTFIXED|VSTACK)) == 0)
- ckfree(s);
- return;
- }
- vp = ckmalloc(sizeof (*vp));
- vp->flags = flags & ~(VNOFUNC|VFUNCREF|VDOEXPORT);
- vp->text = s;
- vp->name_len = nlen;
- vp->func = NULL;
- vp->next = *vpp;
- *vpp = vp;
-
- VTRACE(DBG_VARS, ("new [%s] (%d) %#x\n", s, nlen, vp->flags));
-}
-
-
-
-/*
- * Process a linked list of variable assignments.
- */
-
-void
-listsetvar(struct strlist *list, int flags)
-{
- struct strlist *lp;
-
- INTOFF;
- for (lp = list ; lp ; lp = lp->next) {
- setvareq(savestr(lp->text), flags);
- }
- INTON;
-}
-
-void
-listmklocal(struct strlist *list, int flags)
-{
- struct strlist *lp;
-
- for (lp = list ; lp ; lp = lp->next)
- mklocal(lp->text, flags);
-}
-
-
-/*
- * Find the value of a variable. Returns NULL if not set.
- */
-
-char *
-lookupvar(const char *name)
-{
- struct var *v;
-
- v = find_var(name, NULL, NULL);
- if (v == NULL || v->flags & VUNSET)
- return NULL;
- if (v->rfunc && (v->flags & VFUNCREF) != 0)
- return (*v->rfunc)(v) + v->name_len + 1;
- return v->text + v->name_len + 1;
-}
-
-
-
-/*
- * Search the environment of a builtin command. If the second argument
- * is nonzero, return the value of a variable even if it hasn't been
- * exported.
- */
-
-char *
-bltinlookup(const char *name, int doall)
-{
- struct strlist *sp;
- struct var *v;
-
- for (sp = cmdenviron ; sp ; sp = sp->next) {
- if (strequal(sp->text, name))
- return strchr(sp->text, '=') + 1;
- }
-
- v = find_var(name, NULL, NULL);
-
- if (v == NULL || v->flags & VUNSET || (!doall && !(v->flags & VEXPORT)))
- return NULL;
- if (v->rfunc && (v->flags & VFUNCREF) != 0)
- return (*v->rfunc)(v) + v->name_len + 1;
- return v->text + v->name_len + 1;
-}
-
-
-
-/*
- * Generate a list of exported variables. This routine is used to construct
- * the third argument to execve when executing a program.
- */
-
-char **
-environment(void)
-{
- int nenv;
- struct var **vpp;
- struct var *vp;
- char **env;
- char **ep;
-
- nenv = 0;
- for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
- for (vp = *vpp ; vp ; vp = vp->next)
- if ((vp->flags & (VEXPORT|VUNSET)) == VEXPORT)
- nenv++;
- }
- CTRACE(DBG_VARS, ("environment: %d vars to export\n", nenv));
- ep = env = stalloc((nenv + 1) * sizeof *env);
- for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
- for (vp = *vpp ; vp ; vp = vp->next)
- if ((vp->flags & (VEXPORT|VUNSET)) == VEXPORT) {
- if (vp->rfunc && (vp->flags & VFUNCREF))
- *ep++ = (*vp->rfunc)(vp);
- else
- *ep++ = vp->text;
- VTRACE(DBG_VARS, ("environment: %s\n", ep[-1]));
- }
- }
- *ep = NULL;
- return env;
-}
-
-
-/*
- * Called when a shell procedure is invoked to clear out nonexported
- * variables. It is also necessary to reallocate variables of with
- * VSTACK set since these are currently allocated on the stack.
- */
-
-#ifdef mkinit
-void shprocvar(void);
-
-SHELLPROC {
- shprocvar();
-}
-#endif
-
-void
-shprocvar(void)
-{
- struct var **vpp;
- struct var *vp, **prev;
-
- for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
- for (prev = vpp ; (vp = *prev) != NULL ; ) {
- if ((vp->flags & VEXPORT) == 0) {
- *prev = vp->next;
- if ((vp->flags & VTEXTFIXED) == 0)
- ckfree(vp->text);
- if ((vp->flags & VSTRFIXED) == 0)
- ckfree(vp);
- } else {
- if (vp->flags & VSTACK) {
- vp->text = savestr(vp->text);
- vp->flags &=~ VSTACK;
- }
- prev = &vp->next;
- }
- }
- }
- initvar();
-}
-
-
-
-/*
- * Command to list all variables which are set. Currently this command
- * is invoked from the set command when the set command is called without
- * any variables.
- */
-
-void
-print_quoted(const char *p)
-{
- const char *q;
-
- if (p[0] == '\0') {
- out1fmt("''");
- return;
- }
- if (strcspn(p, "|&;<>()$`\\\"' \t\n*?[]#~=%") == strlen(p)) {
- out1fmt("%s", p);
- return;
- }
- while (*p) {
- if (*p == '\'') {
- out1fmt("\\'");
- p++;
- continue;
- }
- q = strchr(p, '\'');
- if (!q) {
- out1fmt("'%s'", p );
- return;
- }
- out1fmt("'%.*s'", (int)(q - p), p );
- p = q;
- }
-}
-
-static int
-sort_var(const void *v_v1, const void *v_v2)
-{
- const struct var * const *v1 = v_v1;
- const struct var * const *v2 = v_v2;
- char *t1 = (*v1)->text, *t2 = (*v2)->text;
-
- if (*t1 == *t2) {
- char *p, *s;
-
- STARTSTACKSTR(p);
-
- /*
- * note: if lengths are equal, strings must be different
- * so we don't care which string we pick for the \0 in
- * that case.
- */
- if ((strchr(t1, '=') - t1) <= (strchr(t2, '=') - t2)) {
- s = t1;
- t1 = p;
- } else {
- s = t2;
- t2 = p;
- }
-
- while (*s && *s != '=') {
- STPUTC(*s, p);
- s++;
- }
- STPUTC('\0', p);
- }
-
- return strcoll(t1, t2);
-}
-
-/*
- * POSIX requires that 'set' (but not export or readonly) output the
- * variables in lexicographic order - by the locale's collating order (sigh).
- * Maybe we could keep them in an ordered balanced binary tree
- * instead of hashed lists.
- * For now just roll 'em through qsort for printing...
- */
-
-STATIC void
-showvar(struct var *vp, const char *cmd, const char *xtra, int show_value)
-{
- const char *p;
-
- if (cmd)
- out1fmt("%s ", cmd);
- if (xtra)
- out1fmt("%s ", xtra);
- p = vp->text;
- if (vp->rfunc && (vp->flags & VFUNCREF) != 0) {
- p = (*vp->rfunc)(vp);
- if (p == NULL)
- p = vp->text;
- }
- for ( ; *p != '=' ; p++)
- out1c(*p);
- if (!(vp->flags & VUNSET) && show_value) {
- out1fmt("=");
- print_quoted(++p);
- }
- out1c('\n');
-}
-
-int
-showvars(const char *cmd, int flag, int show_value, const char *xtra)
-{
- struct var **vpp;
- struct var *vp;
-
- static struct var **list; /* static in case we are interrupted */
- static int list_len;
- int count = 0;
-
- if (!list) {
- list_len = 32;
- list = ckmalloc(list_len * sizeof *list);
- }
-
- for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
- for (vp = *vpp ; vp ; vp = vp->next) {
- if (flag && !(vp->flags & flag))
- continue;
- if (vp->flags & VUNSET && !(show_value & 2))
- continue;
- if (count >= list_len) {
- list = ckrealloc(list,
- (list_len << 1) * sizeof *list);
- list_len <<= 1;
- }
- list[count++] = vp;
- }
- }
-
- qsort(list, count, sizeof *list, sort_var);
-
- for (vpp = list; count--; vpp++)
- showvar(*vpp, cmd, xtra, show_value);
-
- /* no free(list), will be used again next time ... */
-
- return 0;
-}
-
-
-
-/*
- * The export and readonly commands.
- */
-
-static void __dead
-export_usage(const char *cmd)
-{
-#ifdef SMALL
- if (*cmd == 'r')
- error("Usage: %s [ -p | var[=val]... ]", cmd);
- else
- error("Usage: %s [ -p | [-n] var[=val]... ]", cmd);
-#else
- if (*cmd == 'r')
- error("Usage: %s [-p [var...] | -q var... | var[=val]... ]", cmd);
- else
- error(
- "Usage: %s [ -px [var...] | -q[x] var... | [-n|x] var[=val]... ]",
- cmd);
-#endif
-}
-
-int
-exportcmd(int argc, char **argv)
-{
- struct var *vp;
- char *name;
- const char *p = argv[0];
- int flag = p[0] == 'r'? VREADONLY : VEXPORT;
- int pflg = 0;
- int nflg = 0;
-#ifndef SMALL
- int xflg = 0;
- int qflg = 0;
-#endif
- int res;
- int c;
- int f;
-
-#ifdef SMALL
-#define EXPORT_OPTS "np"
-#else
-#define EXPORT_OPTS "npqx"
-#endif
-
- while ((c = nextopt(EXPORT_OPTS)) != '\0') {
-
-#undef EXPORT_OPTS
-
- switch (c) {
- case 'n':
- if (pflg || flag == VREADONLY
-#ifndef SMALL
- || qflg || xflg
-#endif
- )
- export_usage(p);
- nflg = 1;
- break;
- case 'p':
- if (nflg
-#ifndef SMALL
- || qflg
-#endif
- )
- export_usage(p);
- pflg = 3;
- break;
-#ifndef SMALL
- case 'q':
- if (nflg || pflg)
- export_usage(p);
- qflg = 1;
- break;
- case 'x':
- if (nflg || flag == VREADONLY)
- export_usage(p);
- flag = VNOEXPORT;
- xflg = 1;
- break;
-#endif
- }
- }
-
- if ((nflg
-#ifndef SMALL
- || qflg
-#endif
- ) && *argptr == NULL)
- export_usage(p);
-
-#ifndef SMALL
- if (pflg && *argptr != NULL) {
- while ((name = *argptr++) != NULL) {
- int len;
-
- vp = find_var(name, NULL, &len);
- if (name[len] == '=')
- export_usage(p);
- if (!goodname(name))
- error("%s: bad variable name", name);
-
- if (vp && vp->flags & flag)
- showvar(vp, p, xflg ? "-x" : NULL, 1);
- }
- return 0;
- }
-#endif
-
- if (pflg || *argptr == NULL)
- return showvars( pflg ? p : 0, flag, pflg,
-#ifndef SMALL
- pflg && xflg ? "-x" :
-#endif
- NULL );
-
- res = 0;
-#ifndef SMALL
- if (qflg) {
- while ((name = *argptr++) != NULL) {
- int len;
-
- vp = find_var(name, NULL, &len);
- if (name[len] == '=')
- export_usage(p);
- if (!goodname(name))
- error("%s: bad variable name", name);
-
- if (vp == NULL || !(vp->flags & flag))
- res = 1;
- }
- return res;
- }
-#endif
-
- while ((name = *argptr++) != NULL) {
- int len;
-
- f = flag;
-
- vp = find_var(name, NULL, &len);
- p = name + len;
- if (*p++ != '=')
- p = NULL;
-
- if (vp != NULL) {
- if (nflg)
- vp->flags &= ~flag;
- else if (flag&VEXPORT && vp->flags&VNOEXPORT) {
- /* note we go ahead and do any assignment */
- sh_warnx("%.*s: not available for export",
- len, name);
- res = 1;
- } else {
- if (flag == VNOEXPORT)
- vp->flags &= ~VEXPORT;
-
- /* if not NULL will be done in setvar below */
- if (p == NULL)
- vp->flags |= flag;
- }
- if (p == NULL)
- continue;
- } else if (nflg && p == NULL && !goodname(name))
- error("%s: bad variable name", name);
-
- if (!nflg || p != NULL)
- setvar(name, p, f);
- }
- return res;
-}
-
-
-/*
- * The "local" command.
- */
-
-int
-localcmd(int argc, char **argv)
-{
- char *name;
- int c;
- int flags = 0; /*XXX perhaps VUNSET from a -o option value */
-
- if (! in_function())
- error("Not in a function");
-
- /* upper case options, as bash stole all the good ones ... */
- while ((c = nextopt("INx")) != '\0')
- switch (c) {
- case 'I': flags &= ~VUNSET; break;
- case 'N': flags |= VUNSET; break;
- case 'x': flags |= VEXPORT; break;
- }
-
- while ((name = *argptr++) != NULL) {
- mklocal(name, flags);
- }
- return 0;
-}
-
-
-/*
- * Make a variable a local variable. When a variable is made local, its
- * value and flags are saved in a localvar structure. The saved values
- * will be restored when the shell function returns. We handle the name
- * "-" as a special case.
- */
-
-void
-mklocal(const char *name, int flags)
-{
- struct localvar *lvp;
- struct var **vpp;
- struct var *vp;
-
- INTOFF;
- lvp = ckmalloc(sizeof (struct localvar));
- if (name[0] == '-' && name[1] == '\0') {
- char *p;
- p = ckmalloc(sizeof_optlist);
- lvp->text = memcpy(p, optlist, sizeof_optlist);
- lvp->rfunc = NULL;
- vp = NULL;
- xtrace_clone(0);
- } else {
- vp = find_var(name, &vpp, NULL);
- if (vp == NULL) {
- flags &= ~VNOEXPORT;
- if (strchr(name, '='))
- setvareq(savestr(name),
- VSTRFIXED | (flags & ~VUNSET));
- else
- setvar(name, NULL, VSTRFIXED|flags);
- vp = *vpp; /* the new variable */
- lvp->text = NULL;
- lvp->flags = VUNSET;
- lvp->rfunc = NULL;
- } else {
- lvp->text = vp->text;
- lvp->flags = vp->flags;
- lvp->v_u = vp->v_u;
- vp->flags |= VSTRFIXED|VTEXTFIXED;
- if (flags & (VDOEXPORT | VUNSET))
- vp->flags &= ~VNOEXPORT;
- if (vp->flags & VNOEXPORT &&
- (flags & (VEXPORT|VDOEXPORT|VUNSET)) == VEXPORT)
- flags &= ~VEXPORT;
- if (flags & (VNOEXPORT | VUNSET))
- vp->flags &= ~VEXPORT;
- flags &= ~VNOEXPORT;
- if (name[vp->name_len] == '=')
- setvareq(savestr(name), flags & ~VUNSET);
- else if (flags & VUNSET)
- unsetvar(name, 0);
- else
- vp->flags |= flags & (VUNSET|VEXPORT);
-
- if (vp == &line_num) {
- if (name[vp->name_len] == '=')
- funclinebase = funclineabs -1;
- else
- funclinebase = 0;
- }
- }
- }
- lvp->vp = vp;
- lvp->next = localvars;
- localvars = lvp;
- INTON;
-}
-
-
-/*
- * Called after a function returns.
- */
-
-void
-poplocalvars(void)
-{
- struct localvar *lvp;
- struct var *vp;
-
- while ((lvp = localvars) != NULL) {
- localvars = lvp->next;
- vp = lvp->vp;
- VTRACE(DBG_VARS, ("poplocalvar %s\n", vp ? vp->text : "-"));
- if (vp == NULL) { /* $- saved */
- memcpy(optlist, lvp->text, sizeof_optlist);
- ckfree(lvp->text);
- xtrace_pop();
- optschanged();
- } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
- (void)unsetvar(vp->text, 0);
- } else {
- if (lvp->func && (lvp->flags & (VNOFUNC|VFUNCREF)) == 0)
- (*lvp->func)(lvp->text + vp->name_len + 1);
- if ((vp->flags & VTEXTFIXED) == 0)
- ckfree(vp->text);
- vp->flags = lvp->flags;
- vp->text = lvp->text;
- vp->v_u = lvp->v_u;
- }
- ckfree(lvp);
- }
-}
-
-
-int
-setvarcmd(int argc, char **argv)
-{
- if (argc <= 2)
- return unsetcmd(argc, argv);
- else if (argc == 3)
- setvar(argv[1], argv[2], 0);
- else
- error("List assignment not implemented");
- return 0;
-}
-
-
-/*
- * The unset builtin command. We unset the function before we unset the
- * variable to allow a function to be unset when there is a readonly variable
- * with the same name.
- */
-
-int
-unsetcmd(int argc, char **argv)
-{
- char **ap;
- int i;
- int flg_func = 0;
- int flg_var = 0;
- int flg_x = 0;
- int ret = 0;
-
- while ((i = nextopt("efvx")) != '\0') {
- switch (i) {
- case 'f':
- flg_func = 1;
- break;
- case 'e':
- case 'x':
- flg_x = (2 >> (i == 'e'));
- /* FALLTHROUGH */
- case 'v':
- flg_var = 1;
- break;
- }
- }
-
- if (flg_func == 0 && flg_var == 0)
- flg_var = 1;
-
- for (ap = argptr; *ap ; ap++) {
- if (flg_func)
- ret |= unsetfunc(*ap);
- if (flg_var)
- ret |= unsetvar(*ap, flg_x);
- }
- return ret;
-}
-
-
-/*
- * Unset the specified variable.
- */
-
-int
-unsetvar(const char *s, int unexport)
-{
- struct var **vpp;
- struct var *vp;
-
- vp = find_var(s, &vpp, NULL);
- if (vp == NULL)
- return 0;
-
- if (vp->flags & VREADONLY && !(unexport & 1))
- return 1;
-
- INTOFF;
- if (unexport & 1) {
- vp->flags &= ~VEXPORT;
- } else {
- if (vp->text[vp->name_len + 1] != '\0')
- setvar(s, nullstr, 0);
- if (!(unexport & 2))
- vp->flags &= ~VEXPORT;
- vp->flags |= VUNSET;
- if ((vp->flags&(VEXPORT|VSTRFIXED|VREADONLY|VNOEXPORT)) == 0) {
- if ((vp->flags & VTEXTFIXED) == 0)
- ckfree(vp->text);
- *vpp = vp->next;
- ckfree(vp);
- }
- }
- INTON;
- return 0;
-}
-
-
-/*
- * Returns true if the two strings specify the same varable. The first
- * variable name is terminated by '='; the second may be terminated by
- * either '=' or '\0'.
- */
-
-STATIC int
-strequal(const char *p, const char *q)
-{
- while (*p == *q++) {
- if (*p++ == '=')
- return 1;
- }
- if (*p == '=' && *(q - 1) == '\0')
- return 1;
- return 0;
-}
-
-/*
- * Search for a variable.
- * 'name' may be terminated by '=' or a NUL.
- * vppp is set to the pointer to vp, or the list head if vp isn't found
- * lenp is set to the number of characters in 'name'
- */
-
-STATIC struct var *
-find_var(const char *name, struct var ***vppp, int *lenp)
-{
- unsigned int hashval;
- int len;
- struct var *vp, **vpp;
- const char *p = name;
-
- hashval = 0;
- while (*p && *p != '=')
- hashval = 2 * hashval + (unsigned char)*p++;
-
- len = p - name;
- if (lenp)
- *lenp = len;
-
- vpp = &vartab[hashval % VTABSIZE];
- if (vppp)
- *vppp = vpp;
-
- for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) {
- if (vp->name_len != len)
- continue;
- if (memcmp(vp->text, name, len) != 0)
- continue;
- if (vppp)
- *vppp = vpp;
- return vp;
- }
- return NULL;
-}
-
-/*
- * The following are the functions that create the values for
- * shell variables that are dynamically produced when needed.
- *
- * The output strings cannot be malloc'd as there is nothing to
- * free them - callers assume these are ordinary variables where
- * the value returned is vp->text
- *
- * Each function needs its own storage space, as the results are
- * used to create processes' environment, and (if exported) all
- * the values will (might) be needed simultaneously.
- *
- * It is not a problem if a var is updated while nominally in use
- * somewhere, all these are intended to be dynamic, the value they
- * return is not guaranteed, an updated vaue is just as good.
- *
- * So, malloc a single buffer for the result of each function,
- * grow, and even shrink, it as needed, but once we have one that
- * is a suitable size for the actual usage, simply hold it forever.
- *
- * For a SMALL shell we implement only LINENO, none of the others,
- * and give it just a fixed length static buffer for its result.
- */
-
-#ifndef SMALL
-
-struct space_reserved { /* record of space allocated for results */
- char *b;
- int len;
-};
-
-/* rough (over-)estimate of the number of bytes needed to hold a number */
-static int
-digits_in(intmax_t number)
-{
- int res = 0;
-
- if (number & ~((1LL << 62) - 1))
- res = 64; /* enough for 2^200 and a bit more */
- else if (number & ~((1LL << 32) - 1))
- res = 20; /* enough for 2^64 */
- else if (number & ~((1 << 23) - 1))
- res = 10; /* enough for 2^32 */
- else
- res = 8; /* enough for 2^23 or smaller */
-
- return res;
-}
-
-static int
-make_space(struct space_reserved *m, int bytes)
-{
- void *p;
-
- if (m->len >= bytes && m->len <= (bytes<<2))
- return 1;
-
- bytes = SHELL_ALIGN(bytes);
- /* not ckrealloc() - we want failure, not error() here */
- p = realloc(m->b, bytes);
- if (p == NULL) /* what we had should still be there */
- return 0;
-
- m->b = p;
- m->len = bytes;
- m->b[bytes - 1] = '\0';
-
- return 1;
-}
-#endif
-
-char *
-get_lineno(struct var *vp)
-{
-#ifdef SMALL
-#define length (8 + 10) /* 10 digits is enough for a 32 bit line num */
- static char result[length];
-#else
- static struct space_reserved buf;
-#define result buf.b
-#define length buf.len
-#endif
- int ln = line_number;
-
- if (vp->flags & VUNSET)
- return NULL;
-
- ln -= funclinebase;
-
-#ifndef SMALL
- if (!make_space(&buf, vp->name_len + 2 + digits_in(ln)))
- return vp->text;
-#endif
-
- snprintf(result, length, "%.*s=%d", vp->name_len, vp->text, ln);
- return result;
-}
-#undef result
-#undef length
-
-#ifndef SMALL
-
-char *
-get_hostname(struct var *vp)
-{
- static struct space_reserved buf;
-
- if (vp->flags & VUNSET)
- return NULL;
-
- if (!make_space(&buf, vp->name_len + 2 + 256))
- return vp->text;
-
- memcpy(buf.b, vp->text, vp->name_len + 1); /* include '=' */
- (void)gethostname(buf.b + vp->name_len + 1,
- buf.len - vp->name_len - 3);
- return buf.b;
-}
-
-char *
-get_tod(struct var *vp)
-{
- static struct space_reserved buf; /* space for answers */
- static struct space_reserved tzs; /* remember TZ last used */
- static timezone_t last_zone; /* timezone data for tzs zone */
- const char *fmt;
- char *tz;
- time_t now;
- struct tm tm_now, *tmp;
- timezone_t zone = NULL;
- static char t_err[] = "time error";
- int len;
-
- if (vp->flags & VUNSET)
- return NULL;
-
- fmt = lookupvar("ToD_FORMAT");
- if (fmt == NULL)
- fmt="%T";
- tz = lookupvar("TZ");
- (void)time(&now);
-
- if (tz != NULL) {
- if (tzs.b == NULL || strcmp(tzs.b, tz) != 0) {
- if (make_space(&tzs, strlen(tz) + 1)) {
- INTOFF;
- strcpy(tzs.b, tz);
- if (last_zone)
- tzfree(last_zone);
- last_zone = zone = tzalloc(tz);
- INTON;
- } else
- zone = tzalloc(tz);
- } else
- zone = last_zone;
-
- tmp = localtime_rz(zone, &now, &tm_now);
- } else
- tmp = localtime_r(&now, &tm_now);
-
- len = (strlen(fmt) * 4) + vp->name_len + 2;
- while (make_space(&buf, len)) {
- memcpy(buf.b, vp->text, vp->name_len+1);
- if (tmp == NULL) {
- if (buf.len >= vp->name_len+2+(int)(sizeof t_err - 1)) {
- strcpy(buf.b + vp->name_len + 1, t_err);
- if (zone && zone != last_zone)
- tzfree(zone);
- return buf.b;
- }
- len = vp->name_len + 4 + sizeof t_err - 1;
- continue;
- }
- if (strftime_z(zone, buf.b + vp->name_len + 1,
- buf.len - vp->name_len - 2, fmt, tmp)) {
- if (zone && zone != last_zone)
- tzfree(zone);
- return buf.b;
- }
- if (len >= 4096) /* Let's be reasonable */
- break;
- len <<= 1;
- }
- if (zone && zone != last_zone)
- tzfree(zone);
- return vp->text;
-}
-
-char *
-get_seconds(struct var *vp)
-{
- static struct space_reserved buf;
- intmax_t secs;
-
- if (vp->flags & VUNSET)
- return NULL;
-
- secs = (intmax_t)time((time_t *)0) - sh_start_time;
- if (!make_space(&buf, vp->name_len + 2 + digits_in(secs)))
- return vp->text;
-
- snprintf(buf.b, buf.len, "%.*s=%jd", vp->name_len, vp->text, secs);
- return buf.b;
-}
-
-char *
-get_euser(struct var *vp)
-{
- static struct space_reserved buf;
- static uid_t lastuid = 0;
- uid_t euid;
- struct passwd *pw;
-
- if (vp->flags & VUNSET)
- return NULL;
-
- euid = geteuid();
- if (buf.b != NULL && lastuid == euid)
- return buf.b;
-
- pw = getpwuid(euid);
- if (pw == NULL)
- return vp->text;
-
- if (make_space(&buf, vp->name_len + 2 + strlen(pw->pw_name))) {
- lastuid = euid;
- snprintf(buf.b, buf.len, "%.*s=%s", vp->name_len, vp->text,
- pw->pw_name);
- return buf.b;
- }
-
- return vp->text;
-}
-
-char *
-get_random(struct var *vp)
-{
- static struct space_reserved buf;
- static intmax_t random_val = 0;
-
-#ifdef USE_LRAND48
-#define random lrand48
-#define srandom srand48
-#endif
-
- if (vp->flags & VUNSET)
- return NULL;
-
- if (vp->text != buf.b) {
- /*
- * Either initialisation, or a new seed has been set
- */
- if (vp->text[vp->name_len + 1] == '\0') {
- int fd;
-
- /*
- * initialisation (without pre-seeding),
- * or explictly requesting a truly random seed.
- */
- fd = open("/dev/urandom", 0);
- if (fd == -1) {
- out2str("RANDOM initialisation failed\n");
- random_val = (getpid()<<3) ^ time((time_t *)0);
- } else {
- int n;
-
- do {
- n = read(fd,&random_val,sizeof random_val);
- } while (n != sizeof random_val);
- close(fd);
- }
- } else
- /* good enough for today */
- random_val = strtoimax(vp->text+vp->name_len+1,NULL,0);
-
- srandom((long)random_val);
- }
-
-#if 0
- random_val = (random_val + 1) & 0x7FFF; /* 15 bit "random" numbers */
-#else
- random_val = (random() >> 5) & 0x7FFF;
-#endif
-
- if (!make_space(&buf, vp->name_len + 2 + digits_in(random_val)))
- return vp->text;
-
- snprintf(buf.b, buf.len, "%.*s=%jd", vp->name_len, vp->text,
- random_val);
-
- if (buf.b != vp->text && (vp->flags & (VTEXTFIXED|VSTACK)) == 0)
- free(vp->text);
- vp->flags |= VTEXTFIXED;
- vp->text = buf.b;
-
- return vp->text;
-#undef random
-#undef srandom
-}
-
-#endif /* SMALL */
diff --git a/bin/sh/var.h b/bin/sh/var.h
deleted file mode 100644
index 43bef4b..0000000
--- a/bin/sh/var.h
+++ /dev/null
@@ -1,151 +0,0 @@
-/* $NetBSD: var.h,v 1.38 2018/12/04 14:03:30 kre Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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.
- *
- * @(#)var.h 8.2 (Berkeley) 5/4/95
- */
-
-#ifndef VUNSET /* double include protection */
-/*
- * Shell variables.
- */
-
-/* flags */
-#define VUNSET 0x0001 /* the variable is not set */
-#define VEXPORT 0x0002 /* variable is exported */
-#define VREADONLY 0x0004 /* variable cannot be modified */
-#define VNOEXPORT 0x0008 /* variable may not be exported */
-
-#define VSTRFIXED 0x0010 /* variable struct is statically allocated */
-#define VTEXTFIXED 0x0020 /* text is statically allocated */
-#define VSTACK 0x0040 /* text is allocated on the stack */
-#define VNOFUNC 0x0100 /* don't call the callback function */
-#define VFUNCREF 0x0200 /* the function is called on ref, not set */
-
-#define VSPECIAL 0x1000 /* magic properties not lost when set */
-#define VDOEXPORT 0x2000 /* obey VEXPORT even if VNOEXPORT */
-#define VNOSET 0x4000 /* do not set variable - just readonly test */
-#define VNOERROR 0x8000 /* be quiet if set fails (no error msg) */
-
-struct var;
-
-union var_func_union { /* function to be called when: */
- void (*set_func)(const char *); /* variable gets set/unset */
- char*(*ref_func)(struct var *); /* variable is referenced */
-};
-
-struct var {
- struct var *next; /* next entry in hash list */
- int flags; /* flags are defined above */
- char *text; /* name=value */
- int name_len; /* length of name */
- union var_func_union v_u; /* function to apply (sometimes) */
-};
-
-
-struct localvar {
- struct localvar *next; /* next local variable in list */
- struct var *vp; /* the variable that was made local */
- int flags; /* saved flags */
- char *text; /* saved text */
- union var_func_union v_u; /* saved function */
-};
-
-
-extern struct localvar *localvars;
-
-extern struct var vifs;
-extern char ifs_default[];
-extern struct var vmail;
-extern struct var vmpath;
-extern struct var vpath;
-extern struct var vps1;
-extern struct var vps2;
-extern struct var vps4;
-extern struct var line_num;
-#ifndef SMALL
-extern struct var editrc;
-extern struct var vterm;
-extern struct var vtermcap;
-extern struct var vhistsize;
-extern struct var ps_lit;
-extern struct var euname;
-extern struct var random_num;
-extern intmax_t sh_start_time;
-#endif
-
-extern int line_number;
-extern int funclinebase;
-extern int funclineabs;
-
-/*
- * The following macros access the values of the above variables.
- * They have to skip over the name. They return the null string
- * for unset variables.
- */
-
-#define ifsset() ((vifs.flags & VUNSET) == 0)
-#define ifsval() (ifsset() ? (vifs.text + 4) : ifs_default)
-#define mailval() (vmail.text + 5)
-#define mpathval() (vmpath.text + 9)
-#define pathval() (vpath.text + 5)
-#define ps1val() (vps1.text + 4)
-#define ps2val() (vps2.text + 4)
-#define ps4val() (vps4.text + 4)
-#define optindval() (voptind.text + 7)
-#ifndef SMALL
-#define histsizeval() (vhistsize.text + 9)
-#define termval() (vterm.text + 5)
-#endif
-
-#define mpathset() ((vmpath.flags & VUNSET) == 0)
-
-void initvar(void);
-void setvar(const char *, const char *, int);
-void setvareq(char *, int);
-struct strlist;
-void listsetvar(struct strlist *, int);
-char *lookupvar(const char *);
-char *bltinlookup(const char *, int);
-char **environment(void);
-void shprocvar(void);
-int showvars(const char *, int, int, const char *);
-void mklocal(const char *, int);
-void listmklocal(struct strlist *, int);
-void poplocalvars(void);
-int unsetvar(const char *, int);
-void choose_ps1(void);
-int setvarsafe(const char *, const char *, int);
-void print_quoted(const char *);
-int validname(const char *, int, int *);
-
-#endif
diff --git a/bin/sh/version.h b/bin/sh/version.h
deleted file mode 100644
index 59069e4..0000000
--- a/bin/sh/version.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* $NetBSD: version.h,v 1.3 2018/12/12 12:16:42 kre Exp $ */
-
-/*-
- * Copyright (c) 2014 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
- */
-
-/*
- * This value should be modified rarely - only when significant changes
- * to the shell (which does not mean a bug fixed, or some new feature added)
- * have been made. The most likely reason to change this value would be
- * when a new (shell only) release is to be exported. This should not be
- * updated just because a new NetBSD release is to include this code.
- */
-#define NETBSD_SHELL "20181212"
diff --git a/usr.bin/make/Makefile.boot b/usr.bin/make/Makefile.boot
deleted file mode 100644
index f5be09c..0000000
--- a/usr.bin/make/Makefile.boot
+++ /dev/null
@@ -1,45 +0,0 @@
-# $NetBSD: Makefile.boot,v 1.21 2014/02/24 07:23:44 skrll Exp $
-#
-# a very simple makefile...
-#
-# You only want to use this if you aren't running NetBSD.
-#
-# modify MACHINE and MACHINE_ARCH as appropriate for your target architecture
-#
-CC=gcc -O -g
-
-.c.o:
- ${CC} ${CFLAGS} -c $< -o $@
-
-MACHINE=i386
-MACHINE_ARCH=i386
-# tested on HP-UX 10.20
-#MAKE_MACHINE=hppa
-#MAKE_MACHINE_ARCH=hppa
-CFLAGS= -DTARGET_MACHINE=\"${MACHINE}\" \
- -DTARGET_MACHINE_ARCH=\"${MACHINE_ARCH}\" \
- -DMAKE_MACHINE=\"${MACHINE}\"
-LIBS=
-
-OBJ=arch.o buf.o compat.o cond.o dir.o for.o hash.o job.o main.o make.o \
- make_malloc.o parse.o str.o strlist.o suff.o targ.o trace.o var.o util.o
-
-LIBOBJ= lst.lib/lstAppend.o lst.lib/lstAtEnd.o lst.lib/lstAtFront.o \
- lst.lib/lstClose.o lst.lib/lstConcat.o lst.lib/lstDatum.o \
- lst.lib/lstDeQueue.o lst.lib/lstDestroy.o lst.lib/lstDupl.o \
- lst.lib/lstEnQueue.o lst.lib/lstFind.o lst.lib/lstFindFrom.o \
- lst.lib/lstFirst.o lst.lib/lstForEach.o lst.lib/lstForEachFrom.o \
- lst.lib/lstInit.o lst.lib/lstInsert.o lst.lib/lstIsAtEnd.o \
- lst.lib/lstIsEmpty.o lst.lib/lstLast.o lst.lib/lstMember.o \
- lst.lib/lstNext.o lst.lib/lstOpen.o lst.lib/lstRemove.o \
- lst.lib/lstReplace.o lst.lib/lstSucc.o lst.lib/lstPrev.o
-
-bmake: ${OBJ} ${LIBOBJ}
-# @echo 'make of make and make.0 started.'
- ${CC} ${CFLAGS} ${OBJ} ${LIBOBJ} -o bmake ${LIBS}
- @ls -l $@
-# nroff -h -man make.1 > make.0
-# @echo 'make of make and make.0 completed.'
-
-clean:
- rm -f ${OBJ} ${LIBOBJ} ${PORTOBJ} bmake
diff --git a/usr.bin/make/PSD.doc/Makefile b/usr.bin/make/PSD.doc/Makefile
deleted file mode 100644
index 67702b8..0000000
--- a/usr.bin/make/PSD.doc/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-# $NetBSD: Makefile,v 1.4 2014/07/05 19:22:43 dholland Exp $
-# @(#)Makefile 8.1 (Berkeley) 8/14/93
-
-SECTION=reference/ref1
-ARTICLE=make
-SRCS= tutorial.ms
-MACROS= -ms
-EXTRAHTMLFILES=make1.png make2.png
-
-.include <bsd.doc.mk>
diff --git a/usr.bin/make/PSD.doc/tutorial.ms b/usr.bin/make/PSD.doc/tutorial.ms
deleted file mode 100644
index 814a09a..0000000
--- a/usr.bin/make/PSD.doc/tutorial.ms
+++ /dev/null
@@ -1,3794 +0,0 @@
-.\" $NetBSD: tutorial.ms,v 1.13 2017/03/01 13:05:11 kre Exp $
-.\" Copyright (c) 1988, 1989, 1993
-.\" The Regents of the University of California. All rights reserved.
-.\"
-.\" This code is derived from software contributed to Berkeley by
-.\" Adam de Boor.
-.\"
-.\" 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.
-.\"
-.\" Copyright (c) 1988, 1989 by Adam de Boor
-.\" Copyright (c) 1989 by Berkeley Softworks
-.\"
-.\" This code is derived from software contributed to Berkeley by
-.\" Adam de Boor.
-.\"
-.\" 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. All advertising materials mentioning features or use of this software
-.\" must display the following acknowledgement:
-.\" This product includes software developed by the University of
-.\" California, Berkeley and its contributors.
-.\" 4. 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.
-.\"
-.\" @(#)tutorial.ms 8.1 (Berkeley) 8/18/93
-.\"
-.EH 'PSD:12-%''PMake \*- A Tutorial'
-.OH 'PMake \*- A Tutorial''PSD:12-%'
-.\" Ix is an indexing macro similar to .IX but I've disabled it for now
-.\" Since that would require 2 passes and I am not in the mood for that.
-.de Ix
-..
-.\" Rd is section (region) define and Rm is region mention? Again disable for
-.\" now.
-.de Rd
-..
-.de Rm
-..
-.\" xH is a macro to provide numbered headers that are automatically stuffed
-.\" into a table-of-contents, properly indented, etc. If the first argument
-.\" is numeric, it is taken as the depth for numbering (as for .NH), else
-.\" the default (1) is assumed.
-.\"
-.\" @P The initial paragraph distance.
-.\" @Q The piece of section number to increment (or 0 if none given)
-.\" @R Section header.
-.\" @S Indent for toc entry
-.\" @T Argument to NH (can't use @Q b/c giving 0 to NH resets the counter)
-.de xH
-.NH \\$1
-\\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
-.nr PD .1v
-.XS \\n%
-.ta 0.6i
-\\*(SN \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
-.XE
-.nr PD .3v
-..
-.\" CW is used to place a string in fixed-width or switch to a
-.\" fixed-width font.
-.\" C is a typewriter font for a laserwriter. Use something else if
-.\" you don't have one...
-.de CW
-.ie !\\n(.$ .ft C
-.el \&\\$3\fC\\$1\fP\\$2
-..
-.\" Anything I put in a display I want to be in fixed-width
-.am DS
-.CW
-..
-.\" The stuff in .No produces a little stop sign in the left margin
-.\" that says NOTE in it. Unfortunately, it does cause a break, but
-.\" hey. Can't have everything. In case you're wondering how I came
-.\" up with such weird commands, they came from running grn on a
-.\" gremlin file...
-.de No
-.br
-.ne 0.5i
-.ie n \{\
-.nr g3 \w'NOTE '
-.po -\\n(g3u
-.br
-NOTE
-.br
-.po +\\n(g3u
-.\}
-.el \{\
-.po -0.5i
-.br
-.mk
-.nr g3 \\n(.f
-.nr g4 \\n(.s
-.sp -1
-.\" .st cf
-\D't 5u'
-.sp -1
-\h'50u'
-.sp -1
-\D't 3u'
-.sp -1
-.sp 7u
-\h'53u'
-\d\D'p -0.19i 0.0i 0.0i -0.13i 0.30i 0.0i 0.0i 0.13i'
-.sp -1
-.ft R
-.ps 6
-.nr g8 \\n(.d
-.ds g9 "NOTE
-.sp 74u
-\h'85u'\v'0.85n'\h-\w\\*(g9u/2u\&\\*(g9
-.sp |\\n(g8u
-.sp 166u
-\D't 3u'
-.br
-.po
-.rt
-.ft \\n(g3
-.ps \\n(g4
-.\}
-..
-.de Bp
-.ie !\\n(.$ .IP \(bu 2
-.el .IP "\&" 2
-..
-.ie n .po +\w'NOTE 'u
-.el .po +.3i
-.TL
-PMake \*- A Tutorial
-.AU
-Adam de Boor
-.AI
-Berkeley Softworks
-2150 Shattuck Ave, Penthouse
-Berkeley, CA 94704
-adam@bsw.uu.net
-\&...!uunet!bsw!adam
-.FS
-Permission to use, copy, modify, and distribute this software and its
-documentation for any purpose and without fee is hereby granted,
-provided that the above copyright notice appears in all copies.
-The University of California, Berkeley Softworks, and Adam de Boor make no
-representations about the suitability of this software for any
-purpose. It is provided "as is" without express or implied warranty.
-.FE
-.PP
-.xH 1 Introduction
-.LP
-PMake is a program for creating other programs, or anything else you
-can think of for it to do. The basic idea behind PMake is that, for
-any given system, be it a program or a document or whatever, there
-will be some files that depend on the state of other files (on when
-they were last modified). PMake takes these dependencies, which you
-must specify, and uses them to build whatever it is you want it to
-build.
-.LP
-PMake is almost fully-compatible with Make, with which you may already
-be familiar. PMake's most important feature is its ability to run
-several different jobs at once, making the creation of systems
-considerably faster. It also has a great deal more functionality than
-Make. Throughout the text, whenever something is mentioned that is an
-important difference between PMake and Make (i.e. something that will
-cause a makefile to fail if you don't do something about it), or is
-simply important, it will be flagged with a little sign in the left
-margin, like this:
-.No
-.LP
-This tutorial is divided into three main sections corresponding to basic,
-intermediate and advanced PMake usage. If you already know Make well,
-you will only need to skim chapter 2 (there are some aspects of
-PMake that I consider basic to its use that didn't exist in Make).
-Things in chapter 3 make life much easier, while those in chapter 4
-are strictly for those who know what they are doing. Chapter 5 has
-definitions for the jargon I use and chapter 6 contains possible
-solutions to the problems presented throughout the tutorial.
-.xH 1 The Basics of PMake
-.LP
-PMake takes as input a file that tells a) which files depend on which
-other files to be complete and b) what to do about files that are
-``out-of-date.'' This file is known as a ``makefile'' and is usually
-.Ix 0 def makefile
-kept in the top-most directory of the system to be built. While you
-can call the makefile anything you want, PMake will look for
-.CW Makefile
-and
-.CW makefile
-(in that order) in the current directory if you don't tell it
-otherwise.
-.Ix 0 def makefile default
-To specify a different makefile, use the
-.B \-f
-flag (e.g.
-.CW "pmake -f program.mk" ''). ``
-.Ix 0 ref flags -f
-.Ix 0 ref makefile other
-.LP
-A makefile has four different types of lines in it:
-.RS
-.IP \(bu 2
-File dependency specifications
-.IP \(bu 2
-Creation commands
-.IP \(bu 2
-Variable assignments
-.IP \(bu 2
-Comments, include statements and conditional directives
-.RE
-.LP
-Any line may be continued over multiple lines by ending it with a
-backslash.
-.Ix 0 def "continuation line"
-The backslash, following newline and any initial whitespace
-on the following line are compressed into a single space before the
-input line is examined by PMake.
-.xH 2 Dependency Lines
-.LP
-As mentioned in the introduction, in any system, there are
-dependencies between the files that make up the system. For instance,
-in a program made up of several C source files and one header file,
-the C files will need to be re-compiled should the header file be
-changed. For a document of several chapters and one macro file, the
-chapters will need to be reprocessed if any of the macros changes.
-.Ix 0 def "dependency"
-These are dependencies and are specified by means of dependency lines in
-the makefile.
-.LP
-.Ix 0 def "dependency line"
-On a dependency line, there are targets and sources, separated by a
-one- or two-character operator.
-The targets ``depend'' on the sources and are usually created from
-them.
-.Ix 0 def target
-.Ix 0 def source
-.Ix 0 ref operator
-Any number of targets and sources may be specified on a dependency line.
-All the targets in the line are made to depend on all the sources.
-Targets and sources need not be actual files, but every source must be
-either an actual file or another target in the makefile.
-If you run out of room, use a backslash at the end of the line to continue onto
-the next one.
-.LP
-Any file may be a target and any file may be a source, but the
-relationship between the two (or however many) is determined by the
-``operator'' that separates them.
-.Ix 0 def operator
-Three types of operators exist: one specifies that the datedness of a
-target is determined by the state of its sources, while another
-specifies other files (the sources) that need to be dealt with before
-the target can be re-created. The third operator is very similar to
-the first, with the additional condition that the target is
-out-of-date if it has no sources. These operations are represented by
-the colon, the exclamation point and the double-colon, respectively, and are
-mutually exclusive. Their exact semantics are as follows:
-.IP ":"
-.Ix 0 def operator colon
-.Ix 0 def :
-If a colon is used, a target on the line is considered to be
-``out-of-date'' (and in need of creation) if
-.RS
-.IP \(bu 2
-any of the sources has been modified more recently than the target, or
-.IP \(bu 2
-the target doesn't exist.
-.RE
-.Ix 0 def out-of-date
-.IP "\&"
-Under this operation, steps will be taken to re-create the target only
-if it is found to be out-of-date by using these two rules.
-.IP "!"
-.Ix 0 def operator force
-.Ix 0 def !
-If an exclamation point is used, the target will always be re-created,
-but this will not happen until all of its sources have been examined
-and re-created, if necessary.
-.IP "::"
-.Ix 0 def operator double-colon
-.Ix 0 def ::
-If a double-colon is used, a target is out-of-date if:
-.RS
-.IP \(bu 2
-any of the sources has been modified more recently than the target, or
-.IP \(bu 2
-the target doesn't exist, or
-.IP \(bu 2
-the target has no sources.
-.RE
-.IP "\&"
-If the target is out-of-date according to these rules, it will be re-created.
-This operator also does something else to the targets, but I'll go
-into that in the next section (``Shell Commands'').
-.LP
-Enough words, now for an example. Take that C program I mentioned
-earlier. Say there are three C files
-.CW a.c , (
-.CW b.c
-and
-.CW c.c )
-each of which
-includes the file
-.CW defs.h .
-The dependencies between the files could then be expressed as follows:
-.DS
-program : a.o b.o c.o
-a.o b.o c.o : defs.h
-a.o : a.c
-b.o : b.c
-c.o : c.c
-.DE
-.LP
-You may be wondering at this point, where
-.CW a.o ,
-.CW b.o
-and
-.CW c.o
-came in and why
-.I they
-depend on
-.CW defs.h
-and the C files don't. The reason is quite simple:
-.CW program
-cannot be made by linking together .c files \*- it must be
-made from .o files. Likewise, if you change
-.CW defs.h ,
-it isn't the .c files that need to be re-created, it's the .o files.
-If you think of dependencies in these terms \*- which files (targets)
-need to be created from which files (sources) \*- you should have no problems.
-.LP
-An important thing to notice about the above example, is that all the
-\&.o files appear as targets on more than one line. This is perfectly
-all right: the target is made to depend on all the sources mentioned
-on all the dependency lines. E.g.
-.CW a.o
-depends on both
-.CW defs.h
-and
-.CW a.c .
-.Ix 0 ref dependency
-.No
-.LP
-The order of the dependency lines in the makefile is
-important: the first target on the first dependency line in the
-makefile will be the one that gets made if you don't say otherwise.
-That's why
-.CW program
-comes first in the example makefile, above.
-.LP
-Both targets and sources may contain the standard C-Shell wildcard
-characters
-.CW { , (
-.CW } ,
-.CW * ,
-.CW ? ,
-.CW [ ,
-and
-.CW ] ),
-but the non-curly-brace ones may only appear in the final component
-(the file portion) of the target or source. The characters mean the
-following things:
-.IP \fB{}\fP
-These enclose a comma-separated list of options and cause the pattern
-to be expanded once for each element of the list. Each expansion
-contains a different element. For example,
-.CW src/{whiffle,beep,fish}.c
-expands to the three words
-.CW src/whiffle.c ,
-.CW src/beep.c ,
-and
-.CW src/fish.c .
-These braces may be nested and, unlike the other wildcard characters,
-the resulting words need not be actual files. All other wildcard
-characters are expanded using the files that exist when PMake is
-started.
-.IP \fB*\fP
-This matches zero or more characters of any sort.
-.CW src/*.c
-will expand to the same three words as above as long as
-.CW src
-contains those three files (and no other files that end in
-.CW .c ).
-.IP \fB?\fP
-Matches any single character.
-.IP \fB[]\fP
-This is known as a character class and contains either a list of
-single characters, or a series of character ranges
-.CW a-z , (
-for example means all characters between a and z), or both. It matches
-any single character contained in the list. E.g.
-.CW [A-Za-z]
-will match all letters, while
-.CW [0123456789]
-will match all numbers.
-.xH 2 Shell Commands
-.LP
-``Isn't that nice,'' you say to yourself, ``but how are files
-actually `re-created,' as he likes to spell it?''
-The re-creation is accomplished by commands you place in the makefile.
-These commands are passed to the Bourne shell (better known as
-``/bin/sh'') to be executed and are
-.Ix 0 ref shell
-.Ix 0 ref re-creation
-.Ix 0 ref update
-expected to do what's necessary to update the target file (PMake
-doesn't actually check to see if the target was created. It just
-assumes it's there).
-.Ix 0 ref target
-.LP
-Shell commands in a makefile look a lot like shell commands you would
-type at a terminal, with one important exception: each command in a
-makefile
-.I must
-be preceded by at least one tab.
-.LP
-Each target has associated with it a shell script made up of
-one or more of these shell commands. The creation script for a target
-should immediately follow the dependency line for that target. While
-any given target may appear on more than one dependency line, only one
-of these dependency lines may be followed by a creation script, unless
-the `::' operator was used on the dependency line.
-.Ix 0 ref operator double-colon
-.Ix 0 ref ::
-.No
-.LP
-If the double-colon was used, each dependency line for the target
-may be followed by a shell script. That script will only be executed
-if the target on the associated dependency line is out-of-date with
-respect to the sources on that line, according to the rules I gave
-earlier.
-I'll give you a good example of this later on.
-.LP
-To expand on the earlier makefile, you might add commands as follows:
-.DS
-program : a.o b.o c.o
- cc a.o b.o c.o \-o program
-a.o b.o c.o : defs.h
-a.o : a.c
- cc \-c a.c
-b.o : b.c
- cc \-c b.c
-c.o : c.c
- cc \-c c.c
-.DE
-.LP
-Something you should remember when writing a makefile is, the
-commands will be executed if the
-.I target
-on the dependency line is out-of-date, not the sources.
-.Ix 0 ref target
-.Ix 0 ref source
-.Ix 0 ref out-of-date
-In this example, the command
-.CW "cc \-c a.c" '' ``
-will be executed if
-.CW a.o
-is out-of-date. Because of the `:' operator,
-.Ix 0 ref :
-.Ix 0 ref operator colon
-this means that should
-.CW a.c
-.I or
-.CW defs.h
-have been modified more recently than
-.CW a.o ,
-the command will be executed
-.CW a.o "\&" (
-will be considered out-of-date).
-.Ix 0 ref out-of-date
-.LP
-Remember how I said the only difference between a makefile shell
-command and a regular shell command was the leading tab? I lied. There
-is another way in which makefile commands differ from regular ones.
-The first two characters after the initial whitespace are treated
-specially.
-If they are any combination of `@' and `\-', they cause PMake to do
-different things.
-.LP
-In most cases, shell commands are printed before they're
-actually executed. This is to keep you informed of what's going on. If
-an `@' appears, however, this echoing is suppressed. In the case of an
-.CW echo
-command, say
-.CW "echo Linking index" ,'' ``
-it would be
-rather silly to see
-.DS
-echo Linking index
-Linking index
-.DE
-.LP
-so PMake allows you to place an `@' before the command
-.CW "@echo Linking index" '') (``
-to prevent the command from being printed.
-.LP
-The other special character is the `\-'. In case you didn't know,
-shell commands finish with a certain ``exit status.'' This status is
-made available by the operating system to whatever program invoked the
-command. Normally this status will be 0 if everything went ok and
-non-zero if something went wrong. For this reason, PMake will consider
-an error to have occurred if one of the shells it invokes returns a non-zero
-status. When it detects an error, PMake's usual action is to abort
-whatever it's doing and exit with a non-zero status itself (any other
-targets that were being created will continue being made, but nothing
-new will be started. PMake will exit after the last job finishes).
-This behavior can be altered, however, by placing a `\-' at the front
-of a command
-.CW "\-mv index index.old" ''), (``
-certain command-line arguments,
-or doing other things, to be detailed later. In such
-a case, the non-zero status is simply ignored and PMake keeps chugging
-along.
-.No
-.LP
-Because all the commands are given to a single shell to execute, such
-things as setting shell variables, changing directories, etc., last
-beyond the command in which they are found. This also allows shell
-compound commands (like
-.CW for
-loops) to be entered in a natural manner.
-Since this could cause problems for some makefiles that depend on
-each command being executed by a single shell, PMake has a
-.B \-B
-.Ix 0 ref compatibility
-.Ix 0 ref flags -B
-flag (it stands for backwards-compatible) that forces each command to
-be given to a separate shell. It also does several other things, all
-of which I discourage since they are now old-fashioned.\|.\|.\|.
-.No
-.LP
-A target's shell script is fed to the shell on its (the shell's) input stream.
-This means that any commands, such as
-.CW ci
-that need to get input from the terminal won't work right \*- they'll
-get the shell's input, something they probably won't find to their
-liking. A simple way around this is to give a command like this:
-.DS
-ci $(SRCS) < /dev/tty
-.DE
-This would force the program's input to come from the terminal. If you
-can't do this for some reason, your only other alternative is to use
-PMake in its fullest compatibility mode. See
-.B Compatibility
-in chapter 4.
-.Ix 0 ref compatibility
-.LP
-.xH 2 Variables
-.LP
-PMake, like Make before it, has the ability to save text in variables
-to be recalled later at your convenience. Variables in PMake are used
-much like variables in the shell and, by tradition, consist of
-all upper-case letters (you don't
-.I have
-to use all upper-case letters.
-In fact there's nothing to stop you from calling a variable
-.CW @^&$%$ .
-Just tradition). Variables are assigned-to using lines of the form
-.Ix 0 def variable assignment
-.DS
-VARIABLE = value
-.DE
-.Ix 0 def variable assignment
-appended-to by
-.DS
-VARIABLE += value
-.DE
-.Ix 0 def variable appending
-.Ix 0 def variable assignment appended
-.Ix 0 def +=
-conditionally assigned-to (if the variable isn't already defined) by
-.DS
-VARIABLE ?= value
-.DE
-.Ix 0 def variable assignment conditional
-.Ix 0 def ?=
-and assigned-to with expansion (i.e. the value is expanded (see below)
-before being assigned to the variable\*-useful for placing a value at
-the beginning of a variable, or other things) by
-.DS
-VARIABLE := value
-.DE
-.Ix 0 def variable assignment expanded
-.Ix 0 def :=
-.LP
-Any whitespace before
-.I value
-is stripped off. When appending, a space is placed between the old
-value and the stuff being appended.
-.LP
-The final way a variable may be assigned to is using
-.DS
-VARIABLE != shell-command
-.DE
-.Ix 0 def variable assignment shell-output
-.Ix 0 def !=
-In this case,
-.I shell-command
-has all its variables expanded (see below) and is passed off to a
-shell to execute. The output of the shell is then placed in the
-variable. Any newlines (other than the final one) are replaced by
-spaces before the assignment is made. This is typically used to find
-the current directory via a line like:
-.DS
-CWD != pwd
-.DE
-.LP
-.B Note:
-this is intended to be used to execute commands that produce small amounts
-of output (e.g. ``pwd''). The implementation is less than intelligent and will
-likely freeze if you execute something that produces thousands of
-bytes of output (8 Kb is the limit on many UNIX systems).
-.LP
-The value of a variable may be retrieved by enclosing the variable
-name in parentheses or curly braces and preceding the whole thing
-with a dollar sign.
-.LP
-For example, to set the variable CFLAGS to the string
-.CW "\-I/sprite/src/lib/libc \-O" ,'' ``
-you would place a line
-.DS
-CFLAGS = \-I/sprite/src/lib/libc \-O
-.DE
-in the makefile and use the word
-.CW "$(CFLAGS)"
-wherever you would like the string
-.CW "\-I/sprite/src/lib/libc \-O"
-to appear. This is called variable expansion.
-.Ix 0 def variable expansion
-.No
-.LP
-Unlike Make, PMake will not expand a variable unless it knows
-the variable exists. E.g. if you have a
-.CW "${i}"
-in a shell command and you have not assigned a value to the variable
-.CW i
-(the empty string is considered a value, by the way), where Make would have
-substituted the empty string, PMake will leave the
-.CW "${i}"
-alone.
-To keep PMake from substituting for a variable it knows, precede the
-dollar sign with another dollar sign.
-(e.g. to pass
-.CW "${HOME}"
-to the shell, use
-.CW "$${HOME}" ).
-This causes PMake, in effect, to expand the
-.CW $
-macro, which expands to a single
-.CW $ .
-For compatibility, Make's style of variable expansion will be used
-if you invoke PMake with any of the compatibility flags (\c
-.B \-V ,
-.B \-B
-or
-.B \-M .
-The
-.B \-V
-flag alters just the variable expansion).
-.Ix 0 ref flags -V
-.Ix 0 ref flags -B
-.Ix 0 ref flags -M
-.Ix 0 ref compatibility
-.LP
-.Ix 0 ref variable expansion
-There are two different times at which variable expansion occurs:
-When parsing a dependency line, the expansion occurs immediately
-upon reading the line. If any variable used on a dependency line is
-undefined, PMake will print a message and exit.
-Variables in shell commands are expanded when the command is
-executed.
-Variables used inside another variable are expanded whenever the outer
-variable is expanded (the expansion of an inner variable has no effect
-on the outer variable. I.e. if the outer variable is used on a dependency
-line and in a shell command, and the inner variable changes value
-between when the dependency line is read and the shell command is
-executed, two different values will be substituted for the outer
-variable).
-.Ix 0 def variable types
-.LP
-Variables come in four flavors, though they are all expanded the same
-and all look about the same. They are (in order of expanding scope):
-.RS
-.IP \(bu 2
-Local variables.
-.Ix 0 ref variable local
-.IP \(bu 2
-Command-line variables.
-.Ix 0 ref variable command-line
-.IP \(bu 2
-Global variables.
-.Ix 0 ref variable global
-.IP \(bu 2
-Environment variables.
-.Ix 0 ref variable environment
-.RE
-.LP
-The classification of variables doesn't matter much, except that the
-classes are searched from the top (local) to the bottom (environment)
-when looking up a variable. The first one found wins.
-.xH 3 Local Variables
-.LP
-.Ix 0 def variable local
-Each target can have as many as seven local variables. These are
-variables that are only ``visible'' within that target's shell script
-and contain such things as the target's name, all of its sources (from
-all its dependency lines), those sources that were out-of-date, etc.
-Four local variables are defined for all targets. They are:
-.RS
-.IP ".TARGET"
-.Ix 0 def variable local .TARGET
-.Ix 0 def .TARGET
-The name of the target.
-.IP ".OODATE"
-.Ix 0 def variable local .OODATE
-.Ix 0 def .OODATE
-The list of the sources for the target that were considered out-of-date.
-The order in the list is not guaranteed to be the same as the order in
-which the dependencies were given.
-.IP ".ALLSRC"
-.Ix 0 def variable local .ALLSRC
-.Ix 0 def .ALLSRC
-The list of all sources for this target in the order in which they
-were given.
-.IP ".PREFIX"
-.Ix 0 def variable local .PREFIX
-.Ix 0 def .PREFIX
-The target without its suffix and without any leading path. E.g. for
-the target
-.CW ../../lib/compat/fsRead.c ,
-this variable would contain
-.CW fsRead .
-.RE
-.LP
-Three other local variables are set only for certain targets under
-special circumstances. These are the ``.IMPSRC,''
-.Ix 0 ref variable local .IMPSRC
-.Ix 0 ref .IMPSRC
-``.ARCHIVE,''
-.Ix 0 ref variable local .ARCHIVE
-.Ix 0 ref .ARCHIVE
-and ``.MEMBER''
-.Ix 0 ref variable local .MEMBER
-.Ix 0 ref .MEMBER
-variables. When they are set and how they are used is described later.
-.LP
-Four of these variables may be used in sources as well as in shell
-scripts.
-.Ix 0 def "dynamic source"
-.Ix 0 def source dynamic
-These are ``.TARGET'', ``.PREFIX'', ``.ARCHIVE'' and ``.MEMBER''. The
-variables in the sources are expanded once for each target on the
-dependency line, providing what is known as a ``dynamic source,''
-.Rd 0
-allowing you to specify several dependency lines at once. For example,
-.DS
-$(OBJS) : $(.PREFIX).c
-.DE
-will create a dependency between each object file and its
-corresponding C source file.
-.xH 3 Command-line Variables
-.LP
-.Ix 0 def variable command-line
-Command-line variables are set when PMake is first invoked by giving a
-variable assignment as one of the arguments. For example,
-.DS
-pmake "CFLAGS = -I/sprite/src/lib/libc -O"
-.DE
-would make
-.CW CFLAGS
-be a command-line variable with the given value. Any assignments to
-.CW CFLAGS
-in the makefile will have no effect, because once it
-is set, there is (almost) nothing you can do to change a command-line
-variable (the search order, you see). Command-line variables may be
-set using any of the four assignment operators, though only
-.CW =
-and
-.CW ?=
-behave as you would expect them to, mostly because assignments to
-command-line variables are performed before the makefile is read, thus
-the values set in the makefile are unavailable at the time.
-.CW +=
-.Ix 0 ref +=
-.Ix 0 ref variable assignment appended
-is the same as
-.CW = ,
-because the old value of the variable is sought only in the scope in
-which the assignment is taking place (for reasons of efficiency that I
-won't get into here).
-.CW :=
-and
-.CW ?=
-.Ix 0 ref :=
-.Ix 0 ref ?=
-.Ix 0 ref variable assignment expanded
-.Ix 0 ref variable assignment conditional
-will work if the only variables used are in the environment.
-.CW !=
-is sort of pointless to use from the command line, since the same
-effect can no doubt be accomplished using the shell's own command
-substitution mechanisms (backquotes and all that).
-.xH 3 Global Variables
-.LP
-.Ix 0 def variable global
-Global variables are those set or appended-to in the makefile.
-There are two classes of global variables: those you set and those PMake sets.
-As I said before, the ones you set can have any name you want them to have,
-except they may not contain a colon or an exclamation point.
-The variables PMake sets (almost) always begin with a
-period and always contain upper-case letters, only. The variables are
-as follows:
-.RS
-.IP .PMAKE
-.Ix 0 def variable global .PMAKE
-.Ix 0 def .PMAKE
-.Ix 0 def variable global MAKE
-.Ix 0 def MAKE
-The name by which PMake was invoked is stored in this variable. For
-compatibility, the name is also stored in the MAKE variable.
-.IP .MAKEFLAGS
-.Ix 0 def variable global .MAKEFLAGS
-.Ix 0 def .MAKEFLAGS variable
-.Ix 0 def variable global MFLAGS
-.Ix 0 def MFLAGS
-All the relevant flags with which PMake was invoked. This does not
-include such things as
-.B \-f
-or variable assignments. Again for compatibility, this value is stored
-in the MFLAGS variable as well.
-.RE
-.LP
-Two other variables, ``.INCLUDES'' and ``.LIBS,'' are covered in the
-section on special targets in chapter 3.
-.Ix 0 ref variable global .INCLUDES
-.Ix 0 ref variable global .LIBS
-.LP
-Global variables may be deleted using lines of the form:
-.Ix 0 def #undef
-.Ix 0 def variable deletion
-.DS
-#undef \fIvariable\fP
-.DE
-The
-.CW # ' `
-must be the first character on the line. Note that this may only be
-done on global variables.
-.xH 3 Environment Variables
-.LP
-.Ix 0 def variable environment
-Environment variables are passed by the shell that invoked PMake and
-are given by PMake to each shell it invokes. They are expanded like
-any other variable, but they cannot be altered in any way.
-.LP
-One special environment variable,
-.CW PMAKE ,
-.Ix 0 def variable environment PMAKE
-is examined by PMake for command-line flags, variable assignments,
-etc., it should always use. This variable is examined before the
-actual arguments to PMake are. In addition, all flags given to PMake,
-either through the
-.CW PMAKE
-variable or on the command line, are placed in this environment
-variable and exported to each shell PMake executes. Thus recursive
-invocations of PMake automatically receive the same flags as the
-top-most one.
-.LP
-Using all these variables, you can compress the sample makefile even more:
-.DS
-OBJS = a.o b.o c.o
-program : $(OBJS)
- cc $(.ALLSRC) \-o $(.TARGET)
-$(OBJS) : defs.h
-a.o : a.c
- cc \-c a.c
-b.o : b.c
- cc \-c b.c
-c.o : c.c
- cc \-c c.c
-.DE
-.Ix 0 ref variable local .ALLSRC
-.Ix 0 ref .ALLSRC
-.Ix 0 ref variable local .TARGET
-.Ix 0 ref .TARGET
-.Rd 3
-.xH 2 Comments
-.LP
-.Ix 0 def comments
-Comments in a makefile start with a `#' character and extend to the
-end of the line. They may appear
-anywhere you want them, except in a shell command (though the shell
-will treat it as a comment, too). If, for some reason, you need to use the `#'
-in a variable or on a dependency line, put a backslash in front of it.
-PMake will compress the two into a single `#' (Note: this isn't true
-if PMake is operating in full-compatibility mode).
-.Ix 0 ref flags -M
-.Ix 0 ref compatibility
-.xH 2 Parallelism
-.No
-.LP
-PMake was specifically designed to re-create several targets at once,
-when possible. You do not have to do anything special to cause this to
-happen (unless PMake was configured to not act in parallel, in which
-case you will have to make use of the
-.B \-L
-and
-.B \-J
-flags (see below)),
-.Ix 0 ref flags -L
-.Ix 0 ref flags -J
-but you do have to be careful at times.
-.LP
-There are several problems you are likely to encounter. One is
-that some makefiles (and programs) are written in such a way that it is
-impossible for two targets to be made at once. The program
-.CW xstr ,
-for example,
-always modifies the files
-.CW strings
-and
-.CW x.c .
-There is no way to change it. Thus you cannot run two of them at once
-without something being trashed. Similarly, if you have commands
-in the makefile that always send output to the same file, you will not
-be able to make more than one target at once unless you change the
-file you use. You can, for instance, add a
-.CW $$$$
-to the end of the file name to tack on the process ID of the shell
-executing the command (each
-.CW $$
-expands to a single
-.CW $ ,
-thus giving you the shell variable
-.CW $$ ).
-Since only one shell is used for all the
-commands, you'll get the same file name for each command in the
-script.
-.LP
-The other problem comes from improperly-specified dependencies that
-worked in Make because of its sequential, depth-first way of examining
-them. While I don't want to go into depth on how PMake
-works (look in chapter 4 if you're interested), I will warn you that
-files in two different ``levels'' of the dependency tree may be
-examined in a different order in PMake than they were in Make. For
-example, given the makefile
-.DS
-a : b c
-b : d
-.DE
-PMake will examine the targets in the order
-.CW c ,
-.CW d ,
-.CW b ,
-.CW a .
-If the makefile's author expected PMake to abort before making
-.CW c
-if an error occurred while making
-.CW b ,
-or if
-.CW b
-needed to exist before
-.CW c
-was made,
-s/he will be sorely disappointed. The dependencies are
-incomplete, since in both these cases,
-.CW c
-would depend on
-.CW b .
-So watch out.
-.LP
-Another problem you may face is that, while PMake is set up to handle the
-output from multiple jobs in a graceful fashion, the same is not so for input.
-It has no way to regulate input to different jobs,
-so if you use the redirection from
-.CW /dev/tty
-I mentioned earlier, you must be careful not to run two of the jobs at once.
-.xH 2 Writing and Debugging a Makefile
-.LP
-Now you know most of what's in a makefile, what do you do next? There
-are two choices: (1) use one of the uncommonly-available makefile
-generators or (2) write your own makefile (I leave out the third choice of
-ignoring PMake and doing everything by hand as being beyond the bounds
-of common sense).
-.LP
-When faced with the writing of a makefile, it is usually best to start
-from first principles: just what
-.I are
-you trying to do? What do you want the makefile finally to produce?
-.LP
-To begin with a somewhat traditional example, let's say you need to
-write a makefile to create a program,
-.CW expr ,
-that takes standard infix expressions and converts them to prefix form (for
-no readily apparent reason). You've got three source files, in C, that
-make up the program:
-.CW main.c ,
-.CW parse.c ,
-and
-.CW output.c .
-Harking back to my pithy advice about dependency lines, you write the
-first line of the file:
-.DS
-expr : main.o parse.o output.o
-.DE
-because you remember
-.CW expr
-is made from
-.CW .o
-files, not
-.CW .c
-files. Similarly for the
-.CW .o
-files you produce the lines:
-.DS
-main.o : main.c
-parse.o : parse.c
-output.o : output.c
-main.o parse.o output.o : defs.h
-.DE
-.LP
-Great. You've now got the dependencies specified. What you need now is
-commands. These commands, remember, must produce the target on the
-dependency line, usually by using the sources you've listed.
-You remember about local variables? Good, so it should come
-to you as no surprise when you write
-.DS
-expr : main.o parse.o output.o
- cc -o $(.TARGET) $(.ALLSRC)
-.DE
-Why use the variables? If your program grows to produce postfix
-expressions too (which, of course, requires a name change or two), it
-is one fewer place you have to change the file. You cannot do this for
-the object files, however, because they depend on their corresponding
-source files
-.I and
-.CW defs.h ,
-thus if you said
-.DS
- cc -c $(.ALLSRC)
-.DE
-you'd get (for
-.CW main.o ):
-.DS
- cc -c main.c defs.h
-.DE
-which is wrong. So you round out the makefile with these lines:
-.DS
-main.o : main.c
- cc -c main.c
-parse.o : parse.c
- cc -c parse.c
-output.o : output.c
- cc -c output.c
-.DE
-.LP
-The makefile is now complete and will, in fact, create the program you
-want it to without unnecessary compilations or excessive typing on
-your part. There are two things wrong with it, however (aside from it
-being altogether too long, something I'll address in chapter 3):
-.IP 1)
-The string
-.CW "main.o parse.o output.o" '' ``
-is repeated twice, necessitating two changes when you add postfix
-(you were planning on that, weren't you?). This is in direct violation
-of de Boor's First Rule of writing makefiles:
-.QP
-.I
-Anything that needs to be written more than once
-should be placed in a variable.
-.IP "\&"
-I cannot emphasize this enough as being very important to the
-maintenance of a makefile and its program.
-.IP 2)
-There is no way to alter the way compilations are performed short of
-editing the makefile and making the change in all places. This is evil
-and violates de Boor's Second Rule, which follows directly from the
-first:
-.QP
-.I
-Any flags or programs used inside a makefile should be placed in a variable so
-they may be changed, temporarily or permanently, with the greatest ease.
-.LP
-The makefile should more properly read:
-.DS
-OBJS = main.o parse.o output.o
-expr : $(OBJS)
- $(CC) $(CFLAGS) -o $(.TARGET) $(.ALLSRC)
-main.o : main.c
- $(CC) $(CFLAGS) -c main.c
-parse.o : parse.c
- $(CC) $(CFLAGS) -c parse.c
-output.o : output.c
- $(CC) $(CFLAGS) -c output.c
-$(OBJS) : defs.h
-.DE
-Alternatively, if you like the idea of dynamic sources mentioned in
-section 2.3.1,
-.Rm 0 2.3.1
-.Rd 4
-.Ix 0 ref "dynamic source"
-.Ix 0 ref source dynamic
-you could write it like this:
-.DS
-OBJS = main.o parse.o output.o
-expr : $(OBJS)
- $(CC) $(CFLAGS) -o $(.TARGET) $(.ALLSRC)
-$(OBJS) : $(.PREFIX).c defs.h
- $(CC) $(CFLAGS) -c $(.PREFIX).c
-.DE
-These two rules and examples lead to de Boor's First Corollary:
-.QP
-.I
-Variables are your friends.
-.LP
-Once you've written the makefile comes the sometimes-difficult task of
-.Ix 0 ref debugging
-making sure the darn thing works. Your most helpful tool to make sure
-the makefile is at least syntactically correct is the
-.B \-n
-.Ix 0 ref flags -n
-flag, which allows you to see if PMake will choke on the makefile. The
-second thing the
-.B \-n
-flag lets you do is see what PMake would do without it actually doing
-it, thus you can make sure the right commands would be executed were
-you to give PMake its head.
-.LP
-When you find your makefile isn't behaving as you hoped, the first
-question that comes to mind (after ``What time is it, anyway?'') is
-``Why not?'' In answering this, two flags will serve you well:
-.CW "-d m" '' ``
-.Ix 0 ref flags -d
-and
-.CW "-p 2" .'' ``
-.Ix 0 ref flags -p
-The first causes PMake to tell you as it examines each target in the
-makefile and indicate why it is deciding whatever it is deciding. You
-can then use the information printed for other targets to see where
-you went wrong. The
-.CW "-p 2" '' ``
-flag makes PMake print out its internal state when it is done,
-allowing you to see that you forgot to make that one chapter depend on
-that file of macros you just got a new version of. The output from
-.CW "-p 2" '' ``
-is intended to resemble closely a real makefile, but with additional
-information provided and with variables expanded in those commands
-PMake actually printed or executed.
-.LP
-Something to be especially careful about is circular dependencies.
-.Ix 0 def dependency circular
-E.g.
-.DS
-a : b
-b : c d
-d : a
-.DE
-In this case, because of how PMake works,
-.CW c
-is the only thing PMake will examine, because
-.CW d
-and
-.CW a
-will effectively fall off the edge of the universe, making it
-impossible to examine
-.CW b
-(or them, for that matter).
-PMake will tell you (if run in its normal mode) all the targets
-involved in any cycle it looked at (i.e. if you have two cycles in the
-graph (naughty, naughty), but only try to make a target in one of
-them, PMake will only tell you about that one. You'll have to try to
-make the other to find the second cycle). When run as Make, it will
-only print the first target in the cycle.
-.xH 2 Invoking PMake
-.LP
-.Ix 0 ref flags
-.Ix 0 ref arguments
-.Ix 0 ref usage
-PMake comes with a wide variety of flags to choose from.
-They may appear in any order, interspersed with command-line variable
-assignments and targets to create.
-The flags are as follows:
-.IP "\fB\-d\fP \fIwhat\fP"
-.Ix 0 def flags -d
-.Ix 0 ref debugging
-This causes PMake to spew out debugging information that
-may prove useful to you. If you can't
-figure out why PMake is doing what it's doing, you might try using
-this flag. The
-.I what
-parameter is a string of single characters that tell PMake what
-aspects you are interested in. Most of what I describe will make
-little sense to you, unless you've dealt with Make before. Just
-remember where this table is and come back to it as you read on.
-The characters and the information they produce are as follows:
-.RS
-.IP a
-Archive searching and caching.
-.IP c
-Conditional evaluation.
-.IP d
-The searching and caching of directories.
-.IP j
-Various snippets of information related to the running of the multiple
-shells. Not particularly interesting.
-.IP m
-The making of each target: what target is being examined; when it was
-last modified; whether it is out-of-date; etc.
-.IP p
-Makefile parsing.
-.IP r
-Remote execution.
-.IP s
-The application of suffix-transformation rules. (See chapter 3)
-.IP t
-The maintenance of the list of targets.
-.IP v
-Variable assignment.
-.RE
-.IP "\&"
-Of these all, the
-.CW m
-and
-.CW s
-letters will be most useful to you.
-If the
-.B \-d
-is the final argument or the argument from which it would get these
-key letters (see below for a note about which argument would be used)
-begins with a
-.B \- ,
-all of these debugging flags will be set, resulting in massive amounts
-of output.
-.IP "\fB\-f\fP \fImakefile\fP"
-.Ix 0 def flags -f
-Specify a makefile to read different from the standard makefiles
-.CW Makefile "\&" (
-or
-.CW makefile ).
-.Ix 0 ref makefile default
-.Ix 0 ref makefile other
-If
-.I makefile
-is ``\-'', PMake uses the standard input. This is useful for making
-quick and dirty makefiles.\|.\|.
-.Ix 0 ref makefile "quick and dirty"
-.IP \fB\-h\fP
-.Ix 0 def flags -h
-Prints out a summary of the various flags PMake accepts. It can also
-be used to find out what level of concurrency was compiled into the
-version of PMake you are using (look at
-.B \-J
-and
-.B \-L )
-and various other information on how PMake was configured.
-.Ix 0 ref configuration
-.Ix 0 ref makefile system
-.IP \fB\-i\fP
-.Ix 0 def flags -i
-If you give this flag, PMake will ignore non-zero status returned
-by any of its shells. It's like placing a `\-' before all the commands
-in the makefile.
-.IP \fB\-k\fP
-.Ix 0 def flags -k
-This is similar to
-.B \-i
-in that it allows PMake to continue when it sees an error, but unlike
-.B \-i ,
-where PMake continues blithely as if nothing went wrong,
-.B \-k
-causes it to recognize the error and only continue work on those
-things that don't depend on the target, either directly or indirectly (through
-depending on something that depends on it), whose creation returned the error.
-The `k' is for ``keep going''.\|.\|.
-.Ix 0 ref target
-.IP \fB\-l\fP
-.Ix 0 def flags -l
-PMake has the ability to lock a directory against other
-people executing it in the same directory (by means of a file called
-``LOCK.make'' that it creates and checks for in the directory). This
-is a Good Thing because two people doing the same thing in the same place
-can be disastrous for the final product (too many cooks and all that).
-Whether this locking is the default is up to your system
-administrator. If locking is on,
-.B \-l
-will turn it off, and vice versa. Note that this locking will not
-prevent \fIyou\fP from invoking PMake twice in the same place \*- if
-you own the lock file, PMake will warn you about it but continue to execute.
-.IP "\fB\-m\fP \fIdirectory\fP"
-.Ix 0 def flags -m
-Tells PMake another place to search for included makefiles via the <...>
-style. Several
-.B \-m
-options can be given to form a search path. If this construct is used the
-default system makefile search path is completely overridden.
-To be explained in chapter 3, section 3.2.
-.Rm 2 3.2
-.IP \fB\-n\fP
-.Ix 0 def flags -n
-This flag tells PMake not to execute the commands needed to update the
-out-of-date targets in the makefile. Rather, PMake will simply print
-the commands it would have executed and exit. This is particularly
-useful for checking the correctness of a makefile. If PMake doesn't do
-what you expect it to, it's a good chance the makefile is wrong.
-.IP "\fB\-p\fP \fInumber\fP"
-.Ix 0 def flags -p
-.Ix 0 ref debugging
-This causes PMake to print its input in a reasonable form, though
-not necessarily one that would make immediate sense to anyone but me. The
-.I number
-is a bitwise-or of 1 and 2 where 1 means it should print the input
-before doing any processing and 2 says it should print it after
-everything has been re-created. Thus
-.CW "\-p 3"
-would print it twice\*-once before processing and once after (you
-might find the difference between the two interesting). This is mostly
-useful to me, but you may find it informative in some bizarre circumstances.
-.IP \fB\-q\fP
-.Ix 0 def flags -q
-If you give PMake this flag, it will not try to re-create anything. It
-will just see if anything is out-of-date and exit non-zero if so.
-.IP \fB\-r\fP
-.Ix 0 def flags -r
-When PMake starts up, it reads a default makefile that tells it what
-sort of system it's on and gives it some idea of what to do if you
-don't tell it anything. I'll tell you about it in chapter 3. If you
-give this flag, PMake won't read the default makefile.
-.IP \fB\-s\fP
-.Ix 0 def flags -s
-This causes PMake to not print commands before they're executed. It
-is the equivalent of putting an `@' before every command in the
-makefile.
-.IP \fB\-t\fP
-.Ix 0 def flags -t
-Rather than try to re-create a target, PMake will simply ``touch'' it
-so as to make it appear up-to-date. If the target didn't exist before,
-it will when PMake finishes, but if the target did exist, it will
-appear to have been updated.
-.IP \fB\-v\fP
-.Ix 0 def flags -v
-This is a mixed-compatibility flag intended to mimic the System V
-version of Make. It is the same as giving
-.B \-B ,
-and
-.B \-V
-as well as turning off directory locking. Targets can still be created
-in parallel, however. This is the mode PMake will enter if it is
-invoked either as
-.CW smake '' ``
-or
-.CW vmake ''. ``
-.IP \fB\-x\fP
-.Ix 0 def flags -x
-This tells PMake it's ok to export jobs to other machines, if they're
-available. It is used when running in Make mode, as exporting in this
-mode tends to make things run slower than if the commands were just
-executed locally.
-.IP \fB\-B\fP
-.Ix 0 ref compatibility
-.Ix 0 def flags -B
-Forces PMake to be as backwards-compatible with Make as possible while
-still being itself.
-This includes:
-.RS
-.IP \(bu 2
-Executing one shell per shell command
-.IP \(bu 2
-Expanding anything that looks even vaguely like a variable, with the
-empty string replacing any variable PMake doesn't know.
-.IP \(bu 2
-Refusing to allow you to escape a `#' with a backslash.
-.IP \(bu 2
-Permitting undefined variables on dependency lines and conditionals
-(see below). Normally this causes PMake to abort.
-.RE
-.IP \fB\-C\fP
-.Ix 0 def flags -C
-This nullifies any and all compatibility mode flags you may have given
-or implied up to the time the
-.B \-C
-is encountered. It is useful mostly in a makefile that you wrote for PMake
-to avoid bad things happening when someone runs PMake as
-.CW make '' ``
-or has things set in the environment that tell it to be compatible.
-.B \-C
-is
-.I not
-placed in the
-.CW PMAKE
-environment variable or the
-.CW .MAKEFLAGS
-or
-.CW MFLAGS
-global variables.
-.Ix 0 ref variable environment PMAKE
-.Ix 0 ref variable global .MAKEFLAGS
-.Ix 0 ref variable global MFLAGS
-.Ix 0 ref .MAKEFLAGS variable
-.Ix 0 ref MFLAGS
-.IP "\fB\-D\fP \fIvariable\fP"
-.Ix 0 def flags -D
-Allows you to define a variable to have
-.CW 1 '' ``
-as its value. The variable is a global variable, not a command-line
-variable. This is useful mostly for people who are used to the C
-compiler arguments and those using conditionals, which I'll get into
-in section 4.3
-.Rm 1 4.3
-.IP "\fB\-I\fP \fIdirectory\fP"
-.Ix 0 def flags -I
-Tells PMake another place to search for included makefiles. Yet
-another thing to be explained in chapter 3 (section 3.2, to be
-precise).
-.Rm 2 3.2
-.IP "\fB\-J\fP \fInumber\fP"
-.Ix 0 def flags -J
-Gives the absolute maximum number of targets to create at once on both
-local and remote machines.
-.IP "\fB\-L\fP \fInumber\fP"
-.Ix 0 def flags -L
-This specifies the maximum number of targets to create on the local
-machine at once. This may be 0, though you should be wary of doing
-this, as PMake may hang until a remote machine becomes available, if
-one is not available when it is started.
-.IP \fB\-M\fP
-.Ix 0 ref compatibility
-.Ix 0 def flags -M
-This is the flag that provides absolute, complete, full compatibility
-with Make. It still allows you to use all but a few of the features of
-PMake, but it is non-parallel. This is the mode PMake enters if you
-call it
-.CW make .'' ``
-.IP \fB\-P\fP
-.Ix 0 def flags -P
-.Ix 0 ref "output control"
-When creating targets in parallel, several shells are executing at
-once, each wanting to write its own two cent's-worth to the screen.
-This output must be captured by PMake in some way in order to prevent
-the screen from being filled with garbage even more indecipherable
-than you usually see. PMake has two ways of doing this, one of which
-provides for much cleaner output and a clear separation between the
-output of different jobs, the other of which provides a more immediate
-response so one can tell what is really happening. The former is done
-by notifying you when the creation of a target starts, capturing the
-output and transferring it to the screen all at once when the job
-finishes. The latter is done by catching the output of the shell (and
-its children) and buffering it until an entire line is received, then
-printing that line preceded by an indication of which job produced
-the output. Since I prefer this second method, it is the one used by
-default. The first method will be used if you give the
-.B \-P
-flag to PMake.
-.IP \fB\-V\fP
-.Ix 0 def flags -V
-As mentioned before, the
-.B \-V
-flag tells PMake to use Make's style of expanding variables,
-substituting the empty string for any variable it doesn't know.
-.IP \fB\-W\fP
-.Ix 0 def flags -W
-There are several times when PMake will print a message at you that is
-only a warning, i.e. it can continue to work in spite of your having
-done something silly (such as forgotten a leading tab for a shell
-command). Sometimes you are well aware of silly things you have done
-and would like PMake to stop bothering you. This flag tells it to shut
-up about anything non-fatal.
-.IP \fB\-X\fP
-.Ix 0 def flags -X
-This flag causes PMake to not attempt to export any jobs to another
-machine.
-.LP
-Several flags may follow a single `\-'. Those flags that require
-arguments take them from successive parameters. E.g.
-.DS
-pmake -fDnI server.mk DEBUG /chip2/X/server/include
-.DE
-will cause PMake to read
-.CW server.mk
-as the input makefile, define the variable
-.CW DEBUG
-as a global variable and look for included makefiles in the directory
-.CW /chip2/X/server/include .
-.xH 2 Summary
-.LP
-A makefile is made of four types of lines:
-.RS
-.IP \(bu 2
-Dependency lines
-.IP \(bu 2
-Creation commands
-.IP \(bu 2
-Variable assignments
-.IP \(bu 2
-Comments, include statements and conditional directives
-.RE
-.LP
-A dependency line is a list of one or more targets, an operator
-.CW : ', (`
-.CW :: ', `
-or
-.CW ! '), `
-and a list of zero or more sources. Sources may contain wildcards and
-certain local variables.
-.LP
-A creation command is a regular shell command preceded by a tab. In
-addition, if the first two characters after the tab (and other
-whitespace) are a combination of
-.CW @ ' `
-or
-.CW - ', `
-PMake will cause the command to not be printed (if the character is
-.CW @ ') `
-or errors from it to be ignored (if
-.CW - '). `
-A blank line, dependency line or variable assignment terminates a
-creation script. There may be only one creation script for each target
-with a
-.CW : ' `
-or
-.CW ! ' `
-operator.
-.LP
-Variables are places to store text. They may be unconditionally
-assigned-to using the
-.CW = ' `
-.Ix 0 ref =
-.Ix 0 ref variable assignment
-operator, appended-to using the
-.CW += ' `
-.Ix 0 ref +=
-.Ix 0 ref variable assignment appended
-operator, conditionally (if the variable is undefined) assigned-to
-with the
-.CW ?= ' `
-.Ix 0 ref ?=
-.Ix 0 ref variable assignment conditional
-operator, and assigned-to with variable expansion with the
-.CW := ' `
-.Ix 0 ref :=
-.Ix 0 ref variable assignment expanded
-operator. The output of a shell command may be assigned to a variable
-using the
-.CW != ' `
-.Ix 0 ref !=
-.Ix 0 ref variable assignment shell-output
-operator. Variables may be expanded (their value inserted) by enclosing
-their name in parentheses or curly braces, preceded by a dollar sign.
-A dollar sign may be escaped with another dollar sign. Variables are
-not expanded if PMake doesn't know about them. There are seven local
-variables:
-.CW .TARGET ,
-.CW .ALLSRC ,
-.CW .OODATE ,
-.CW .PREFIX ,
-.CW .IMPSRC ,
-.CW .ARCHIVE ,
-and
-.CW .MEMBER .
-Four of them
-.CW .TARGET , (
-.CW .PREFIX ,
-.CW .ARCHIVE ,
-and
-.CW .MEMBER )
-may be used to specify ``dynamic sources.''
-.Ix 0 ref "dynamic source"
-.Ix 0 ref source dynamic
-Variables are good. Know them. Love them. Live them.
-.LP
-Debugging of makefiles is best accomplished using the
-.B \-n ,
-.B "\-d m" ,
-and
-.B "\-p 2"
-flags.
-.xH 2 Exercises
-.ce
-\s+4\fBTBA\fP\s0
-.xH 1 Short-cuts and Other Nice Things
-.LP
-Based on what I've told you so far, you may have gotten the impression
-that PMake is just a way of storing away commands and making sure you
-don't forget to compile something. Good. That's just what it is.
-However, the ways I've described have been inelegant, at best, and
-painful, at worst.
-This chapter contains things that make the
-writing of makefiles easier and the makefiles themselves shorter and
-easier to modify (and, occasionally, simpler). In this chapter, I
-assume you are somewhat more
-familiar with Sprite (or UNIX, if that's what you're using) than I did
-in chapter 2, just so you're on your toes.
-So without further ado...
-.xH 2 Transformation Rules
-.LP
-As you know, a file's name consists of two parts: a base name, which
-gives some hint as to the contents of the file, and a suffix, which
-usually indicates the format of the file.
-Over the years, as
-.UX
-has developed,
-naming conventions, with regard to suffixes, have also developed that have
-become almost as incontrovertible as Law. E.g. a file ending in
-.CW .c
-is assumed to contain C source code; one with a
-.CW .o
-suffix is assumed to be a compiled, relocatable object file that may
-be linked into any program; a file with a
-.CW .ms
-suffix is usually a text file to be processed by Troff with the \-ms
-macro package, and so on.
-One of the best aspects of both Make and PMake comes from their
-understanding of how the suffix of a file pertains to its contents and
-their ability to do things with a file based solely on its suffix. This
-ability comes from something known as a transformation rule. A
-transformation rule specifies how to change a file with one suffix
-into a file with another suffix.
-.LP
-A transformation rule looks much like a dependency line, except the
-target is made of two known suffixes stuck together. Suffixes are made
-known to PMake by placing them as sources on a dependency line whose
-target is the special target
-.CW .SUFFIXES .
-E.g.
-.DS
-\&.SUFFIXES : .o .c
-\&.c.o :
- $(CC) $(CFLAGS) -c $(.IMPSRC)
-.DE
-The creation script attached to the target is used to transform a file with
-the first suffix (in this case,
-.CW .c )
-into a file with the second suffix (here,
-.CW .o ).
-In addition, the target inherits whatever attributes have been applied
-to the transformation rule.
-The simple rule given above says that to transform a C source file
-into an object file, you compile it using
-.CW cc
-with the
-.CW \-c
-flag.
-This rule is taken straight from the system makefile. Many
-transformation rules (and suffixes) are defined there, and I refer you
-to it for more examples (type
-.CW "pmake -h" '' ``
-to find out where it is).
-.LP
-There are several things to note about the transformation rule given
-above:
-.RS
-.IP 1)
-The
-.CW .IMPSRC
-variable.
-.Ix 0 def variable local .IMPSRC
-.Ix 0 def .IMPSRC
-This variable is set to the ``implied source'' (the file from which
-the target is being created; the one with the first suffix), which, in this
-case, is the .c file.
-.IP 2)
-The
-.CW CFLAGS
-variable. Almost all of the transformation rules in the system
-makefile are set up using variables that you can alter in your
-makefile to tailor the rule to your needs. In this case, if you want
-all your C files to be compiled with the
-.B \-g
-flag, to provide information for
-.CW dbx ,
-you would set the
-.CW CFLAGS
-variable to contain
-.CW -g
-.CW "CFLAGS = -g" '') (``
-and PMake would take care of the rest.
-.RE
-.LP
-To give you a quick example, the makefile in 2.3.4
-.Rm 3 2.3.4
-could be changed to this:
-.DS
-OBJS = a.o b.o c.o
-program : $(OBJS)
- $(CC) -o $(.TARGET) $(.ALLSRC)
-$(OBJS) : defs.h
-.DE
-The transformation rule I gave above takes the place of the 6 lines\**
-.FS
-This is also somewhat cleaner, I think, than the dynamic source
-solution presented in 2.6
-.FE
-.Rm 4 2.6
-.DS
-a.o : a.c
- cc -c a.c
-b.o : b.c
- cc -c b.c
-c.o : c.c
- cc -c c.c
-.DE
-.LP
-Now you may be wondering about the dependency between the
-.CW .o
-and
-.CW .c
-files \*- it's not mentioned anywhere in the new makefile. This is
-because it isn't needed: one of the effects of applying a
-transformation rule is the target comes to depend on the implied
-source. That's why it's called the implied
-.I source .
-.LP
-For a more detailed example. Say you have a makefile like this:
-.DS
-a.out : a.o b.o
- $(CC) $(.ALLSRC)
-.DE
-and a directory set up like this:
-.DS
-total 4
--rw-rw-r-- 1 deboor 34 Sep 7 00:43 Makefile
--rw-rw-r-- 1 deboor 119 Oct 3 19:39 a.c
--rw-rw-r-- 1 deboor 201 Sep 7 00:43 a.o
--rw-rw-r-- 1 deboor 69 Sep 7 00:43 b.c
-.DE
-While just typing
-.CW pmake '' ``
-will do the right thing, it's much more informative to type
-.CW "pmake -d s" ''. ``
-This will show you what PMake is up to as it processes the files. In
-this case, PMake prints the following:
-.DS
-Suff_FindDeps (a.out)
- using existing source a.o
- applying .o -> .out to "a.o"
-Suff_FindDeps (a.o)
- trying a.c...got it
- applying .c -> .o to "a.c"
-Suff_FindDeps (b.o)
- trying b.c...got it
- applying .c -> .o to "b.c"
-Suff_FindDeps (a.c)
- trying a.y...not there
- trying a.l...not there
- trying a.c,v...not there
- trying a.y,v...not there
- trying a.l,v...not there
-Suff_FindDeps (b.c)
- trying b.y...not there
- trying b.l...not there
- trying b.c,v...not there
- trying b.y,v...not there
- trying b.l,v...not there
---- a.o ---
-cc -c a.c
---- b.o ---
-cc -c b.c
---- a.out ---
-cc a.o b.o
-.DE
-.LP
-.CW Suff_FindDeps
-is the name of a function in PMake that is called to check for implied
-sources for a target using transformation rules.
-The transformations it tries are, naturally
-enough, limited to the ones that have been defined (a transformation
-may be defined multiple times, by the way, but only the most recent
-one will be used). You will notice, however, that there is a definite
-order to the suffixes that are tried. This order is set by the
-relative positions of the suffixes on the
-.CW .SUFFIXES
-line \*- the earlier a suffix appears, the earlier it is checked as
-the source of a transformation. Once a suffix has been defined, the
-only way to change its position in the pecking order is to remove all
-the suffixes (by having a
-.CW .SUFFIXES
-dependency line with no sources) and redefine them in the order you
-want. (Previously-defined transformation rules will be automatically
-redefined as the suffixes they involve are re-entered.)
-.LP
-Another way to affect the search order is to make the dependency
-explicit. In the above example,
-.CW a.out
-depends on
-.CW a.o
-and
-.CW b.o .
-Since a transformation exists from
-.CW .o
-to
-.CW .out ,
-PMake uses that, as indicated by the
-.CW "using existing source a.o" '' ``
-message.
-.LP
-The search for a transformation starts from the suffix of the target
-and continues through all the defined transformations, in the order
-dictated by the suffix ranking, until an existing file with the same
-base (the target name minus the suffix and any leading directories) is
-found. At that point, one or more transformation rules will have been
-found to change the one existing file into the target.
-.LP
-For example, ignoring what's in the system makefile for now, say you
-have a makefile like this:
-.DS
-\&.SUFFIXES : .out .o .c .y .l
-\&.l.c :
- lex $(.IMPSRC)
- mv lex.yy.c $(.TARGET)
-\&.y.c :
- yacc $(.IMPSRC)
- mv y.tab.c $(.TARGET)
-\&.c.o :
- cc -c $(.IMPSRC)
-\&.o.out :
- cc -o $(.TARGET) $(.IMPSRC)
-.DE
-and the single file
-.CW jive.l .
-If you were to type
-.CW "pmake -rd ms jive.out" ,'' ``
-you would get the following output for
-.CW jive.out :
-.DS
-Suff_FindDeps (jive.out)
- trying jive.o...not there
- trying jive.c...not there
- trying jive.y...not there
- trying jive.l...got it
- applying .l -> .c to "jive.l"
- applying .c -> .o to "jive.c"
- applying .o -> .out to "jive.o"
-.DE
-and this is why: PMake starts with the target
-.CW jive.out ,
-figures out its suffix
-.CW .out ) (
-and looks for things it can transform to a
-.CW .out
-file. In this case, it only finds
-.CW .o ,
-so it looks for the file
-.CW jive.o .
-It fails to find it, so it looks for transformations into a
-.CW .o
-file. Again it has only one choice:
-.CW .c .
-So it looks for
-.CW jive.c
-and, as you know, fails to find it. At this point it has two choices:
-it can create the
-.CW .c
-file from either a
-.CW .y
-file or a
-.CW .l
-file. Since
-.CW .y
-came first on the
-.CW .SUFFIXES
-line, it checks for
-.CW jive.y
-first, but can't find it, so it looks for
-.CW jive.l
-and, lo and behold, there it is.
-At this point, it has defined a transformation path as follows:
-.CW .l
-\(->
-.CW .c
-\(->
-.CW .o
-\(->
-.CW .out
-and applies the transformation rules accordingly. For completeness,
-and to give you a better idea of what PMake actually did with this
-three-step transformation, this is what PMake printed for the rest of
-the process:
-.DS
-Suff_FindDeps (jive.o)
- using existing source jive.c
- applying .c -> .o to "jive.c"
-Suff_FindDeps (jive.c)
- using existing source jive.l
- applying .l -> .c to "jive.l"
-Suff_FindDeps (jive.l)
-Examining jive.l...modified 17:16:01 Oct 4, 1987...up-to-date
-Examining jive.c...non-existent...out-of-date
---- jive.c ---
-lex jive.l
-\&.\|.\|. meaningless lex output deleted .\|.\|.
-mv lex.yy.c jive.c
-Examining jive.o...non-existent...out-of-date
---- jive.o ---
-cc -c jive.c
-Examining jive.out...non-existent...out-of-date
---- jive.out ---
-cc -o jive.out jive.o
-.DE
-.LP
-One final question remains: what does PMake do with targets that have
-no known suffix? PMake simply pretends it actually has a known suffix
-and searches for transformations accordingly.
-The suffix it chooses is the source for the
-.CW .NULL
-.Ix 0 ref .NULL
-target mentioned later. In the system makefile,
-.CW .out
-is chosen as the ``null suffix''
-.Ix 0 def suffix null
-.Ix 0 def "null suffix"
-because most people use PMake to create programs. You are, however,
-free and welcome to change it to a suffix of your own choosing.
-The null suffix is ignored, however, when PMake is in compatibility
-mode (see chapter 4).
-.xH 2 Including Other Makefiles
-.Ix 0 def makefile inclusion
-.Rd 2
-.LP
-Just as for programs, it is often useful to extract certain parts of a
-makefile into another file and just include it in other makefiles
-somehow. Many compilers allow you say something like
-.DS
-#include "defs.h"
-.DE
-to include the contents of
-.CW defs.h
-in the source file. PMake allows you to do the same thing for
-makefiles, with the added ability to use variables in the filenames.
-An include directive in a makefile looks either like this:
-.DS
-#include <file>
-.DE
-or this
-.DS
-#include "file"
-.DE
-The difference between the two is where PMake searches for the file:
-the first way, PMake will look for
-the file only in the system makefile directory (or directories)
-(to find out what that directory is, give PMake the
-.B \-h
-flag).
-.Ix 0 ref flags -h
-The system makefile directory search path can be overridden via the
-.B \-m
-option.
-.Ix 0 ref flags -m
-For files in double-quotes, the search is more complex:
-.RS
-.IP 1)
-The directory of the makefile that's including the file.
-.IP 2)
-The current directory (the one in which you invoked PMake).
-.IP 3)
-The directories given by you using
-.B \-I
-flags, in the order in which you gave them.
-.IP 4)
-Directories given by
-.CW .PATH
-dependency lines (see chapter 4).
-.IP 5)
-The system makefile directory.
-.RE
-.LP
-in that order.
-.LP
-You are free to use PMake variables in the filename\*-PMake will
-expand them before searching for the file. You must specify the
-searching method with either angle brackets or double-quotes
-.I outside
-of a variable expansion. I.e. the following
-.DS
-SYSTEM = <command.mk>
-
-#include $(SYSTEM)
-.DE
-won't work.
-.xH 2 Saving Commands
-.LP
-.Ix 0 def ...
-There may come a time when you will want to save certain commands to
-be executed when everything else is done. For instance: you're
-making several different libraries at one time and you want to create the
-members in parallel. Problem is,
-.CW ranlib
-is another one of those programs that can't be run more than once in
-the same directory at the same time (each one creates a file called
-.CW __.SYMDEF
-into which it stuffs information for the linker to use. Two of them
-running at once will overwrite each other's file and the result will
-be garbage for both parties). You might want a way to save the ranlib
-commands til the end so they can be run one after the other, thus
-keeping them from trashing each other's file. PMake allows you to do
-this by inserting an ellipsis (``.\|.\|.'') as a command between
-commands to be run at once and those to be run later.
-.LP
-So for the
-.CW ranlib
-case above, you might do this:
-.Rd 5
-.DS
-lib1.a : $(LIB1OBJS)
- rm -f $(.TARGET)
- ar cr $(.TARGET) $(.ALLSRC)
- ...
- ranlib $(.TARGET)
-
-lib2.a : $(LIB2OBJS)
- rm -f $(.TARGET)
- ar cr $(.TARGET) $(.ALLSRC)
- ...
- ranlib $(.TARGET)
-.DE
-.Ix 0 ref variable local .TARGET
-.Ix 0 ref variable local .ALLSRC
-This would save both
-.DS
-ranlib $(.TARGET)
-.DE
-commands until the end, when they would run one after the other
-(using the correct value for the
-.CW .TARGET
-variable, of course).
-.LP
-Commands saved in this manner are only executed if PMake manages to
-re-create everything without an error.
-.xH 2 Target Attributes
-.LP
-PMake allows you to give attributes to targets by means of special
-sources. Like everything else PMake uses, these sources begin with a
-period and are made up of all upper-case letters. There are various
-reasons for using them, and I will try to give examples for most of
-them. Others you'll have to find uses for yourself. Think of it as ``an
-exercise for the reader.'' By placing one (or more) of these as a source on a
-dependency line, you are ``marking the target(s) with that
-attribute.'' That's just the way I phrase it, so you know.
-.LP
-Any attributes given as sources for a transformation rule are applied
-to the target of the transformation rule when the rule is applied.
-.Ix 0 def attributes
-.Ix 0 ref source
-.Ix 0 ref target
-.nr pw 12
-.IP .DONTCARE \n(pw
-.Ix 0 def attributes .DONTCARE
-.Ix 0 def .DONTCARE
-If a target is marked with this attribute and PMake can't figure out
-how to create it, it will ignore this fact and assume the file isn't
-really needed or actually exists and PMake just can't find it. This may prove
-wrong, but the error will be noted later on, not when PMake tries to create
-the target so marked. This attribute also prevents PMake from
-attempting to touch the target if it is given the
-.B \-t
-flag.
-.Ix 0 ref flags -t
-.IP .EXEC \n(pw
-.Ix 0 def attributes .EXEC
-.Ix 0 def .EXEC
-This attribute causes its shell script to be executed while having no
-effect on targets that depend on it. This makes the target into a sort
-of subroutine. An example. Say you have some LISP files that need to
-be compiled and loaded into a LISP process. To do this, you echo LISP
-commands into a file and execute a LISP with this file as its input
-when everything's done. Say also that you have to load other files
-from another system before you can compile your files and further,
-that you don't want to go through the loading and dumping unless one
-of
-.I your
-files has changed. Your makefile might look a little bit
-like this (remember, this is an educational example, and don't worry
-about the
-.CW COMPILE
-rule, all will soon become clear, grasshopper):
-.DS
-system : init a.fasl b.fasl c.fasl
- for i in $(.ALLSRC);
- do
- echo -n '(load "' >> input
- echo -n ${i} >> input
- echo '")' >> input
- done
- echo '(dump "$(.TARGET)")' >> input
- lisp < input
-
-a.fasl : a.l init COMPILE
-b.fasl : b.l init COMPILE
-c.fasl : c.l init COMPILE
-COMPILE : .USE
- echo '(compile "$(.ALLSRC)")' >> input
-init : .EXEC
- echo '(load-system)' > input
-.DE
-.Ix 0 ref .USE
-.Ix 0 ref attributes .USE
-.Ix 0 ref variable local .ALLSRC
-.IP "\&"
-.CW .EXEC
-sources, don't appear in the local variables of targets that depend on
-them (nor are they touched if PMake is given the
-.B \-t
-flag).
-.Ix 0 ref flags -t
-Note that all the rules, not just that for
-.CW system ,
-include
-.CW init
-as a source. This is because none of the other targets can be made
-until
-.CW init
-has been made, thus they depend on it.
-.IP .EXPORT \n(pw
-.Ix 0 def attributes .EXPORT
-.Ix 0 def .EXPORT
-This is used to mark those targets whose creation should be sent to
-another machine if at all possible. This may be used by some
-exportation schemes if the exportation is expensive. You should ask
-your system administrator if it is necessary.
-.IP .EXPORTSAME \n(pw
-.Ix 0 def attributes .EXPORTSAME
-.Ix 0 def .EXPORTSAME
-Tells the export system that the job should be exported to a machine
-of the same architecture as the current one. Certain operations (e.g.
-running text through
-.CW nroff )
-can be performed the same on any architecture (CPU and
-operating system type), while others (e.g. compiling a program with
-.CW cc )
-must be performed on a machine with the same architecture. Not all
-export systems will support this attribute.
-.IP .IGNORE \n(pw
-.Ix 0 def attributes .IGNORE
-.Ix 0 def .IGNORE attribute
-Giving a target the
-.CW .IGNORE
-attribute causes PMake to ignore errors from any of the target's commands, as
-if they all had `\-' before them.
-.IP .INVISIBLE \n(pw
-.Ix 0 def attributes .INVISIBLE
-.Ix 0 def .INVISIBLE
-This allows you to specify one target as a source for another without
-the one affecting the other's local variables. Useful if, say, you
-have a makefile that creates two programs, one of which is used to
-create the other, so it must exist before the other is created. You
-could say
-.DS
-prog1 : $(PROG1OBJS) prog2 MAKEINSTALL
-prog2 : $(PROG2OBJS) .INVISIBLE MAKEINSTALL
-.DE
-where
-.CW MAKEINSTALL
-is some complex .USE rule (see below) that depends on the
-.Ix 0 ref .USE
-.CW .ALLSRC
-variable containing the right things. Without the
-.CW .INVISIBLE
-attribute for
-.CW prog2 ,
-the
-.CW MAKEINSTALL
-rule couldn't be applied. This is not as useful as it should be, and
-the semantics may change (or the whole thing go away) in the
-not-too-distant future.
-.IP .JOIN \n(pw
-.Ix 0 def attributes .JOIN
-.Ix 0 def .JOIN
-This is another way to avoid performing some operations in parallel
-while permitting everything else to be done so. Specifically it
-forces the target's shell script to be executed only if one or more of the
-sources was out-of-date. In addition, the target's name,
-in both its
-.CW .TARGET
-variable and all the local variables of any target that depends on it,
-is replaced by the value of its
-.CW .ALLSRC
-variable.
-As an example, suppose you have a program that has four libraries that
-compile in the same directory along with, and at the same time as, the
-program. You again have the problem with
-.CW ranlib
-that I mentioned earlier, only this time it's more severe: you
-can't just put the ranlib off to the end since the program
-will need those libraries before it can be re-created. You can do
-something like this:
-.DS
-program : $(OBJS) libraries
- cc -o $(.TARGET) $(.ALLSRC)
-
-libraries : lib1.a lib2.a lib3.a lib4.a .JOIN
- ranlib $(.OODATE)
-.DE
-.Ix 0 ref variable local .TARGET
-.Ix 0 ref variable local .ALLSRC
-.Ix 0 ref variable local .OODATE
-.Ix 0 ref .TARGET
-.Ix 0 ref .ALLSRC
-.Ix 0 ref .OODATE
-In this case, PMake will re-create the
-.CW $(OBJS)
-as necessary, along with
-.CW lib1.a ,
-.CW lib2.a ,
-.CW lib3.a
-and
-.CW lib4.a .
-It will then execute
-.CW ranlib
-on any library that was changed and set
-.CW program 's
-.CW .ALLSRC
-variable to contain what's in
-.CW $(OBJS)
-followed by
-.CW "lib1.a lib2.a lib3.a lib4.a" .'' ``
-In case you're wondering, it's called
-.CW .JOIN
-because it joins together different threads of the ``input graph'' at
-the target marked with the attribute.
-Another aspect of the .JOIN attribute is it keeps the target from
-being created if the
-.B \-t
-flag was given.
-.Ix 0 ref flags -t
-.IP .MAKE \n(pw
-.Ix 0 def attributes .MAKE
-.Ix 0 def .MAKE
-The
-.CW .MAKE
-attribute marks its target as being a recursive invocation of PMake.
-This forces PMake to execute the script associated with the target (if
-it's out-of-date) even if you gave the
-.B \-n
-or
-.B \-t
-flag. By doing this, you can start at the top of a system and type
-.DS
-pmake -n
-.DE
-and have it descend the directory tree (if your makefiles are set up
-correctly), printing what it would have executed if you hadn't
-included the
-.B \-n
-flag.
-.IP .NOEXPORT \n(pw
-.Ix 0 def attributes .NOEXPORT
-.Ix 0 def .NOEXPORT attribute
-If possible, PMake will attempt to export the creation of all targets to
-another machine (this depends on how PMake was configured). Sometimes,
-the creation is so simple, it is pointless to send it to another
-machine. If you give the target the
-.CW .NOEXPORT
-attribute, it will be run locally, even if you've given PMake the
-.B "\-L 0"
-flag.
-.IP .NOTMAIN \n(pw
-.Ix 0 def attributes .NOTMAIN
-.Ix 0 def .NOTMAIN
-Normally, if you do not specify a target to make in any other way,
-PMake will take the first target on the first dependency line of a
-makefile as the target to create. That target is known as the ``Main
-Target'' and is labeled as such if you print the dependencies out
-using the
-.B \-p
-flag.
-.Ix 0 ref flags -p
-Giving a target this attribute tells PMake that the target is
-definitely
-.I not
-the Main Target.
-This allows you to place targets in an included makefile and
-have PMake create something else by default.
-.IP .PRECIOUS \n(pw
-.Ix 0 def attributes .PRECIOUS
-.Ix 0 def .PRECIOUS attribute
-When PMake is interrupted (you type control-C at the keyboard), it
-will attempt to clean up after itself by removing any half-made
-targets. If a target has the
-.CW .PRECIOUS
-attribute, however, PMake will leave it alone. An additional side
-effect of the `::' operator is to mark the targets as
-.CW .PRECIOUS .
-.Ix 0 ref operator double-colon
-.Ix 0 ref ::
-.IP .SILENT \n(pw
-.Ix 0 def attributes .SILENT
-.Ix 0 def .SILENT attribute
-Marking a target with this attribute keeps its commands from being
-printed when they're executed, just as if they had an `@' in front of them.
-.IP .USE \n(pw
-.Ix 0 def attributes .USE
-.Ix 0 def .USE
-By giving a target this attribute, you turn it into PMake's equivalent
-of a macro. When the target is used as a source for another target,
-the other target acquires the commands, sources and attributes (except
-.CW .USE )
-of the source.
-If the target already has commands, the
-.CW .USE
-target's commands are added to the end. If more than one .USE-marked
-source is given to a target, the rules are applied sequentially.
-.IP "\&" \n(pw
-The typical .USE rule (as I call them) will use the sources of the
-target to which it is applied (as stored in the
-.CW .ALLSRC
-variable for the target) as its ``arguments,'' if you will.
-For example, you probably noticed that the commands for creating
-.CW lib1.a
-and
-.CW lib2.a
-in the example in section 3.3
-.Rm 5 3.3
-were exactly the same. You can use the
-.CW .USE
-attribute to eliminate the repetition, like so:
-.DS
-lib1.a : $(LIB1OBJS) MAKELIB
-lib2.a : $(LIB2OBJS) MAKELIB
-
-MAKELIB : .USE
- rm -f $(.TARGET)
- ar cr $(.TARGET) $(.ALLSRC)
- ...
- ranlib $(.TARGET)
-.DE
-.Ix 0 ref variable local .TARGET
-.Ix 0 ref variable local .ALLSRC
-.IP "\&" \n(pw
-Several system makefiles (not to be confused with The System Makefile)
-make use of these .USE rules to make your
-life easier (they're in the default, system makefile directory...take a look).
-Note that the .USE rule source itself
-.CW MAKELIB ) (
-does not appear in any of the targets's local variables.
-There is no limit to the number of times I could use the
-.CW MAKELIB
-rule. If there were more libraries, I could continue with
-.CW "lib3.a : $(LIB3OBJS) MAKELIB" '' ``
-and so on and so forth.
-.xH 2 Special Targets
-.LP
-As there were in Make, so there are certain targets that have special
-meaning to PMake. When you use one on a dependency line, it is the
-only target that may appear on the left-hand-side of the operator.
-.Ix 0 ref target
-.Ix 0 ref operator
-As for the attributes and variables, all the special targets
-begin with a period and consist of upper-case letters only.
-I won't describe them all in detail because some of them are rather
-complex and I'll describe them in more detail than you'll want in
-chapter 4.
-The targets are as follows:
-.nr pw 10
-.IP .BEGIN \n(pw
-.Ix 0 def .BEGIN
-Any commands attached to this target are executed before anything else
-is done. You can use it for any initialization that needs doing.
-.IP .DEFAULT \n(pw
-.Ix 0 def .DEFAULT
-This is sort of a .USE rule for any target (that was used only as a
-source) that PMake can't figure out any other way to create. It's only
-``sort of'' a .USE rule because only the shell script attached to the
-.CW .DEFAULT
-target is used. The
-.CW .IMPSRC
-variable of a target that inherits
-.CW .DEFAULT 's
-commands is set to the target's own name.
-.Ix 0 ref .IMPSRC
-.Ix 0 ref variable local .IMPSRC
-.IP .END \n(pw
-.Ix 0 def .END
-This serves a function similar to
-.CW .BEGIN ,
-in that commands attached to it are executed once everything has been
-re-created (so long as no errors occurred). It also serves the extra
-function of being a place on which PMake can hang commands you put off
-to the end. Thus the script for this target will be executed before
-any of the commands you save with the ``.\|.\|.''.
-.Ix 0 ref ...
-.IP .EXPORT \n(pw
-The sources for this target are passed to the exportation system compiled
-into PMake. Some systems will use these sources to configure
-themselves. You should ask your system administrator about this.
-.IP .IGNORE \n(pw
-.Ix 0 def .IGNORE target
-.Ix 0 ref .IGNORE attribute
-.Ix 0 ref attributes .IGNORE
-This target marks each of its sources with the
-.CW .IGNORE
-attribute. If you don't give it any sources, then it is like
-giving the
-.B \-i
-flag when you invoke PMake \*- errors are ignored for all commands.
-.Ix 0 ref flags -i
-.IP .INCLUDES \n(pw
-.Ix 0 def .INCLUDES target
-.Ix 0 def variable global .INCLUDES
-.Ix 0 def .INCLUDES variable
-The sources for this target are taken to be suffixes that indicate a
-file that can be included in a program source file.
-The suffix must have already been declared with
-.CW .SUFFIXES
-(see below).
-Any suffix so marked will have the directories on its search path
-(see
-.CW .PATH ,
-below) placed in the
-.CW .INCLUDES
-variable, each preceded by a
-.B \-I
-flag. This variable can then be used as an argument for the compiler
-in the normal fashion. The
-.CW .h
-suffix is already marked in this way in the system makefile.
-.Ix 0 ref makefile system
-E.g. if you have
-.DS
-\&.SUFFIXES : .bitmap
-\&.PATH.bitmap : /usr/local/X/lib/bitmaps
-\&.INCLUDES : .bitmap
-.DE
-PMake will place
-.CW "-I/usr/local/X/lib/bitmaps" '' ``
-in the
-.CW .INCLUDES
-variable and you can then say
-.DS
-cc $(.INCLUDES) -c xprogram.c
-.DE
-(Note: the
-.CW .INCLUDES
-variable is not actually filled in until the entire makefile has been read.)
-.IP .INTERRUPT \n(pw
-.Ix 0 def .INTERRUPT
-When PMake is interrupted,
-it will execute the commands in the script for this target, if it
-exists.
-.IP .LIBS \n(pw
-.Ix 0 def .LIBS target
-.Ix 0 def .LIBS variable
-.Ix 0 def variable global .LIBS
-This does for libraries what
-.CW .INCLUDES
-does for include files, except the flag used is
-.B \-L ,
-as required by those linkers that allow you to tell them where to find
-libraries. The variable used is
-.CW .LIBS .
-Be forewarned that PMake may not have been compiled to do this if the
-linker on your system doesn't accept the
-.B \-L
-flag, though the
-.CW .LIBS
-variable will always be defined once the makefile has been read.
-.IP .MAIN \n(pw
-.Ix 0 def .MAIN
-If you didn't give a target (or targets) to create when you invoked
-PMake, it will take the sources of this target as the targets to
-create.
-.IP .MAKEFLAGS \n(pw
-.Ix 0 def .MAKEFLAGS target
-This target provides a way for you to always specify flags for PMake
-when the makefile is used. The flags are just as they would be typed
-to the shell (except you can't use shell variables unless they're in
-the environment),
-though the
-.B \-f
-and
-.B \-r
-flags have no effect.
-.IP .NULL \n(pw
-.Ix 0 def .NULL
-.Ix 0 ref suffix null
-.Ix 0 ref "null suffix"
-This allows you to specify what suffix PMake should pretend a file has
-if, in fact, it has no known suffix. Only one suffix may be so
-designated. The last source on the dependency line is the suffix that
-is used (you should, however, only give one suffix.\|.\|.).
-.IP .PATH \n(pw
-.Ix 0 def .PATH
-If you give sources for this target, PMake will take them as
-directories in which to search for files it cannot find in the current
-directory. If you give no sources, it will clear out any directories
-added to the search path before. Since the effects of this all get
-very complex, I'll leave it til chapter four to give you a complete
-explanation.
-.IP .PATH\fIsuffix\fP \n(pw
-.Ix 0 ref .PATH
-This does a similar thing to
-.CW .PATH ,
-but it does it only for files with the given suffix. The suffix must
-have been defined already. Look at
-.B "Search Paths"
-(section 4.1)
-.Rm 6 4.1
-for more information.
-.IP .PRECIOUS \n(pw
-.Ix 0 def .PRECIOUS target
-.Ix 0 ref .PRECIOUS attribute
-.Ix 0 ref attributes .PRECIOUS
-Similar to
-.CW .IGNORE ,
-this gives the
-.CW .PRECIOUS
-attribute to each source on the dependency line, unless there are no
-sources, in which case the
-.CW .PRECIOUS
-attribute is given to every target in the file.
-.IP .RECURSIVE \n(pw
-.Ix 0 def .RECURSIVE
-.Ix 0 ref attributes .MAKE
-.Ix 0 ref .MAKE
-This target applies the
-.CW .MAKE
-attribute to all its sources. It does nothing if you don't give it any sources.
-.IP .SHELL \n(pw
-.Ix 0 def .SHELL
-PMake is not constrained to only using the Bourne shell to execute
-the commands you put in the makefile. You can tell it some other shell
-to use with this target. Check out
-.B "A Shell is a Shell is a Shell"
-(section 4.4)
-.Rm 7 4.4
-for more information.
-.IP .SILENT \n(pw
-.Ix 0 def .SILENT target
-.Ix 0 ref .SILENT attribute
-.Ix 0 ref attributes .SILENT
-When you use
-.CW .SILENT
-as a target, it applies the
-.CW .SILENT
-attribute to each of its sources. If there are no sources on the
-dependency line, then it is as if you gave PMake the
-.B \-s
-flag and no commands will be echoed.
-.IP .SUFFIXES \n(pw
-.Ix 0 def .SUFFIXES
-This is used to give new file suffixes for PMake to handle. Each
-source is a suffix PMake should recognize. If you give a
-.CW .SUFFIXES
-dependency line with no sources, PMake will forget about all the
-suffixes it knew (this also nukes the null suffix).
-For those targets that need to have suffixes defined, this is how you do it.
-.LP
-In addition to these targets, a line of the form
-.DS
-\fIattribute\fP : \fIsources\fP
-.DE
-applies the
-.I attribute
-to all the targets listed as
-.I sources .
-.xH 2 Modifying Variable Expansion
-.LP
-.Ix 0 def variable expansion modified
-.Ix 0 ref variable expansion
-.Ix 0 def variable modifiers
-Variables need not always be expanded verbatim. PMake defines several
-modifiers that may be applied to a variable's value before it is
-expanded. You apply a modifier by placing it after the variable name
-with a colon between the two, like so:
-.DS
-${\fIVARIABLE\fP:\fImodifier\fP}
-.DE
-Each modifier is a single character followed by something specific to
-the modifier itself.
-You may apply as many modifiers as you want \*- each one is applied to
-the result of the previous and is separated from the previous by
-another colon.
-.LP
-There are seven ways to modify a variable's expansion, most of which
-come from the C shell variable modification characters:
-.RS
-.IP "M\fIpattern\fP"
-.Ix 0 def :M
-.Ix 0 def modifier match
-This is used to select only those words (a word is a series of
-characters that are neither spaces nor tabs) that match the given
-.I pattern .
-The pattern is a wildcard pattern like that used by the shell, where
-.CW *
-means 0 or more characters of any sort;
-.CW ?
-is any single character;
-.CW [abcd]
-matches any single character that is either `a', `b', `c' or `d'
-(there may be any number of characters between the brackets);
-.CW [0-9]
-matches any single character that is between `0' and `9' (i.e. any
-digit. This form may be freely mixed with the other bracket form), and
-`\\' is used to escape any of the characters `*', `?', `[' or `:',
-leaving them as regular characters to match themselves in a word.
-For example, the system makefile
-.CW <makedepend.mk>
-uses
-.CW "$(CFLAGS:M-[ID]*)" '' ``
-to extract all the
-.CW \-I
-and
-.CW \-D
-flags that would be passed to the C compiler. This allows it to
-properly locate include files and generate the correct dependencies.
-.IP "N\fIpattern\fP"
-.Ix 0 def :N
-.Ix 0 def modifier nomatch
-This is identical to
-.CW :M
-except it substitutes all words that don't match the given pattern.
-.IP "S/\fIsearch-string\fP/\fIreplacement-string\fP/[g]"
-.Ix 0 def :S
-.Ix 0 def modifier substitute
-Causes the first occurrence of
-.I search-string
-in the variable to be replaced by
-.I replacement-string ,
-unless the
-.CW g
-flag is given at the end, in which case all occurrences of the string
-are replaced. The substitution is performed on each word in the
-variable in turn. If
-.I search-string
-begins with a
-.CW ^ ,
-the string must match starting at the beginning of the word. If
-.I search-string
-ends with a
-.CW $ ,
-the string must match to the end of the word (these two may be
-combined to force an exact match). If a backslash precedes these two
-characters, however, they lose their special meaning. Variable
-expansion also occurs in the normal fashion inside both the
-.I search-string
-and the
-.I replacement-string ,
-.B except
-that a backslash is used to prevent the expansion of a
-.CW $ ,
-not another dollar sign, as is usual.
-Note that
-.I search-string
-is just a string, not a pattern, so none of the usual
-regular-expression/wildcard characters have any special meaning save
-.CW ^
-and
-.CW $ .
-In the replacement string,
-the
-.CW &
-character is replaced by the
-.I search-string
-unless it is preceded by a backslash.
-You are allowed to use any character except
-colon or exclamation point to separate the two strings. This so-called
-delimiter character may be placed in either string by preceding it
-with a backslash.
-.IP T
-.Ix 0 def :T
-.Ix 0 def modifier tail
-Replaces each word in the variable expansion by its last
-component (its ``tail''). For example, given
-.DS
-OBJS = ../lib/a.o b /usr/lib/libm.a
-TAILS = $(OBJS:T)
-.DE
-the variable
-.CW TAILS
-would expand to
-.CW "a.o b libm.a" .'' ``
-.IP H
-.Ix 0 def :H
-.Ix 0 def modifier head
-This is similar to
-.CW :T ,
-except that every word is replaced by everything but the tail (the
-``head''). Using the same definition of
-.CW OBJS ,
-the string
-.CW "$(OBJS:H)" '' ``
-would expand to
-.CW "../lib /usr/lib" .'' ``
-Note that the final slash on the heads is removed and
-anything without a head is replaced by the empty string.
-.IP E
-.Ix 0 def :E
-.Ix 0 def modifier extension
-.Ix 0 def modifier suffix
-.Ix 0 ref suffix "variable modifier"
-.CW :E
-replaces each word by its suffix (``extension''). So
-.CW "$(OBJS:E)" '' ``
-would give you
-.CW ".o .a" .'' ``
-.IP R
-.Ix 0 def :R
-.Ix 0 def modifier root
-.Ix 0 def modifier base
-This replaces each word by everything but the suffix (the ``root'' of
-the word).
-.CW "$(OBJS:R)" '' ``
-expands to ``
-.CW "../lib/a b /usr/lib/libm" .''
-.RE
-.LP
-In addition, the System V style of substitution is also supported.
-This looks like:
-.DS
-$(\fIVARIABLE\fP:\fIsearch-string\fP=\fIreplacement\fP)
-.DE
-It must be the last modifier in the chain. The search is anchored at
-the end of each word, so only suffixes or whole words may be replaced.
-.xH 2 More on Debugging
-.xH 2 More Exercises
-.IP (3.1)
-You've got a set programs, each of which is created from its own
-assembly-language source file (suffix
-.CW .asm ).
-Each program can be assembled into two versions, one with error-checking
-code assembled in and one without. You could assemble them into files
-with different suffixes
-.CW .eobj \& (
-and
-.CW .obj ,
-for instance), but your linker only understands files that end in
-.CW .obj .
-To top it all off, the final executables
-.I must
-have the suffix
-.CW .exe .
-How can you still use transformation rules to make your life easier
-(Hint: assume the error-checking versions have
-.CW ec
-tacked onto their prefix)?
-.IP (3.2)
-Assume, for a moment or two, you want to perform a sort of
-``indirection'' by placing the name of a variable into another one,
-then you want to get the value of the first by expanding the second
-somehow. Unfortunately, PMake doesn't allow constructs like
-.DS I
-$($(FOO))
-.DE
-What do you do? Hint: no further variable expansion is performed after
-modifiers are applied, thus if you cause a $ to occur in the
-expansion, that's what will be in the result.
-.xH 1 PMake for Gods
-.LP
-This chapter is devoted to those facilities in PMake that allow you to
-do a great deal in a makefile with very little work, as well as do
-some things you couldn't do in Make without a great deal of work (and
-perhaps the use of other programs). The problem with these features,
-is they must be handled with care, or you will end up with a mess.
-.LP
-Once more, I assume a greater familiarity with
-.UX
-or Sprite than I did in the previous two chapters.
-.xH 2 Search Paths
-.Rd 6
-.LP
-PMake supports the dispersal of files into multiple directories by
-allowing you to specify places to look for sources with
-.CW .PATH
-targets in the makefile. The directories you give as sources for these
-targets make up a ``search path.'' Only those files used exclusively
-as sources are actually sought on a search path, the assumption being
-that anything listed as a target in the makefile can be created by the
-makefile and thus should be in the current directory.
-.LP
-There are two types of search paths
-in PMake: one is used for all types of files (including included
-makefiles) and is specified with a plain
-.CW .PATH
-target (e.g.
-.CW ".PATH : RCS" ''), ``
-while the other is specific to a certain type of file, as indicated by
-the file's suffix. A specific search path is indicated by immediately following
-the
-.CW .PATH
-with the suffix of the file. For instance
-.DS
-\&.PATH.h : /sprite/lib/include /sprite/att/lib/include
-.DE
-would tell PMake to look in the directories
-.CW /sprite/lib/include
-and
-.CW /sprite/att/lib/include
-for any files whose suffix is
-.CW .h .
-.LP
-The current directory is always consulted first to see if a file
-exists. Only if it cannot be found there are the directories in the
-specific search path, followed by those in the general search path,
-consulted.
-.LP
-A search path is also used when expanding wildcard characters. If the
-pattern has a recognizable suffix on it, the path for that suffix will
-be used for the expansion. Otherwise the default search path is employed.
-.LP
-When a file is found in some directory other than the current one, all
-local variables that would have contained the target's name
-.CW .ALLSRC , (
-and
-.CW .IMPSRC )
-will instead contain the path to the file, as found by PMake.
-Thus if you have a file
-.CW ../lib/mumble.c
-and a makefile
-.DS
-\&.PATH.c : ../lib
-mumble : mumble.c
- $(CC) -o $(.TARGET) $(.ALLSRC)
-.DE
-the command executed to create
-.CW mumble
-would be
-.CW "cc -o mumble ../lib/mumble.c" .'' ``
-(As an aside, the command in this case isn't strictly necessary, since
-it will be found using transformation rules if it isn't given. This is because
-.CW .out
-is the null suffix by default and a transformation exists from
-.CW .c
-to
-.CW .out .
-Just thought I'd throw that in.)
-.LP
-If a file exists in two directories on the same search path, the file
-in the first directory on the path will be the one PMake uses. So if
-you have a large system spread over many directories, it would behoove
-you to follow a naming convention that avoids such conflicts.
-.LP
-Something you should know about the way search paths are implemented
-is that each directory is read, and its contents cached, exactly once
-\&\*- when it is first encountered \*- so any changes to the
-directories while PMake is running will not be noted when searching
-for implicit sources, nor will they be found when PMake attempts to
-discover when the file was last modified, unless the file was created in the
-current directory. While people have suggested that PMake should read
-the directories each time, my experience suggests that the caching seldom
-causes problems. In addition, not caching the directories slows things
-down enormously because of PMake's attempts to apply transformation
-rules through non-existent files \*- the number of extra file-system
-searches is truly staggering, especially if many files without
-suffixes are used and the null suffix isn't changed from
-.CW .out .
-.xH 2 Archives and Libraries
-.LP
-.UX
-and Sprite allow you to merge files into an archive using the
-.CW ar
-command. Further, if the files are relocatable object files, you can
-run
-.CW ranlib
-on the archive and get yourself a library that you can link into any
-program you want. The main problem with archives is they double the
-space you need to store the archived files, since there's one copy in
-the archive and one copy out by itself. The problem with libraries is
-you usually think of them as
-.CW -lm
-rather than
-.CW /usr/lib/libm.a
-and the linker thinks they're out-of-date if you so much as look at
-them.
-.LP
-PMake solves the problem with archives by allowing you to tell it to
-examine the files in the archives (so you can remove the individual
-files without having to regenerate them later). To handle the problem
-with libraries, PMake adds an additional way of deciding if a library
-is out-of-date:
-.IP \(bu 2
-If the table of contents is older than the library, or is missing, the
-library is out-of-date.
-.LP
-A library is any target that looks like
-.CW \-l name'' ``
-or that ends in a suffix that was marked as a library using the
-.CW .LIBS
-target.
-.CW .a
-is so marked in the system makefile.
-.LP
-Members of an archive are specified as
-``\fIarchive\fP(\fImember\fP[ \fImember\fP...])''.
-Thus
-.CW libdix.a(window.o) '' ``'
-specifies the file
-.CW window.o
-in the archive
-.CW libdix.a .
-You may also use wildcards to specify the members of the archive. Just
-remember that most the wildcard characters will only find
-.I existing
-files.
-.LP
-A file that is a member of an archive is treated specially. If the
-file doesn't exist, but it is in the archive, the modification time
-recorded in the archive is used for the file when determining if the
-file is out-of-date. When figuring out how to make an archived member target
-(not the file itself, but the file in the archive \*- the
-\fIarchive\fP(\fImember\fP) target), special care is
-taken with the transformation rules, as follows:
-.IP \(bu 2
-\&\fIarchive\fP(\fImember\fP) is made to depend on \fImember\fP.
-.IP \(bu 2
-The transformation from the \fImember\fP's suffix to the
-\fIarchive\fP's suffix is applied to the \fIarchive\fP(\fImember\fP) target.
-.IP \(bu 2
-The \fIarchive\fP(\fImember\fP)'s
-.CW .TARGET
-variable is set to the name of the \fImember\fP if \fImember\fP is
-actually a target, or the path to the member file if \fImember\fP is
-only a source.
-.IP \(bu 2
-The
-.CW .ARCHIVE
-variable for the \fIarchive\fP(\fImember\fP) target is set to the name
-of the \fIarchive\fP.
-.Ix 0 def variable local .ARCHIVE
-.Ix 0 def .ARCHIVE
-.IP \(bu 2
-The
-.CW .MEMBER
-variable is set to the actual string inside the parentheses. In most
-cases, this will be the same as the
-.CW .TARGET
-variable.
-.Ix 0 def variable local .MEMBER
-.Ix 0 def .MEMBER
-.IP \(bu 2
-The \fIarchive\fP(\fImember\fP)'s place in the local variables of the
-targets that depend on it is taken by the value of its
-.CW .TARGET
-variable.
-.LP
-Thus, a program library could be created with the following makefile:
-.DS
-\&.o.a :
- ...
- rm -f $(.TARGET:T)
-OBJS = obj1.o obj2.o obj3.o
-libprog.a : libprog.a($(OBJS))
- ar cru $(.TARGET) $(.OODATE)
- ranlib $(.TARGET)
-.DE
-This will cause the three object files to be compiled (if the
-corresponding source files were modified after the object file or, if
-that doesn't exist, the archived object file), the out-of-date ones
-archived in
-.CW libprog.a ,
-a table of contents placed in the archive and the newly-archived
-object files to be removed.
-.LP
-All this is used in the
-.CW makelib.mk
-system makefile to create a single library with ease. This makefile
-looks like this:
-.DS
-.SM
-#
-# Rules for making libraries. The object files that make up the library
-# are removed once they are archived.
-#
-# To make several libraries in parallel, you should define the variable
-# "many_libraries". This will serialize the invocations of ranlib.
-#
-# To use, do something like this:
-#
-# OBJECTS = <files in the library>
-#
-# fish.a: fish.a($(OBJECTS)) MAKELIB
-#
-#
-
-#ifndef _MAKELIB_MK
-_MAKELIB_MK =
-
-#include <po.mk>
-
-\&.po.a .o.a :
- ...
- rm -f $(.MEMBER)
-
-ARFLAGS ?= crl
-
-#
-# Re-archive the out-of-date members and recreate the library's table of
-# contents using ranlib. If many_libraries is defined, put the ranlib
-# off til the end so many libraries can be made at once.
-#
-MAKELIB : .USE .PRECIOUS
- ar $(ARFLAGS) $(.TARGET) $(.OODATE)
-#ifndef no_ranlib
-# ifdef many_libraries
- ...
-# endif /* many_libraries */
- ranlib $(.TARGET)
-#endif /* no_ranlib */
-
-#endif /* _MAKELIB_MK */
-.DE
-.xH 2 On the Condition...
-.Rd 1
-.LP
-Like the C compiler before it, PMake allows you to configure the makefile,
-based on the current environment, using conditional statements. A
-conditional looks like this:
-.DS
-#if \fIboolean expression\fP
-\fIlines\fP
-#elif \fIanother boolean expression\fP
-\fImore lines\fP
-#else
-\fIstill more lines\fP
-#endif
-.DE
-They may be nested to a maximum depth of 30 and may occur anywhere
-(except in a comment, of course). The
-.CW # '' ``
-must the very first character on the line.
-.LP
-Each
-.I "boolean expression"
-is made up of terms that look like function calls, the standard C
-boolean operators
-.CW && ,
-.CW || ,
-and
-.CW ! ,
-and the standard relational operators
-.CW == ,
-.CW != ,
-.CW > ,
-.CW >= ,
-.CW < ,
-and
-.CW <= ,
-with
-.CW ==
-and
-.CW !=
-being overloaded to allow string comparisons as well.
-.CW &&
-represents logical AND;
-.CW ||
-is logical OR and
-.CW !
-is logical NOT. The arithmetic and string operators take precedence
-over all three of these operators, while NOT takes precedence over
-AND, which takes precedence over OR. This precedence may be
-overridden with parentheses, and an expression may be parenthesized to
-your heart's content. Each term looks like a call on one of four
-functions:
-.nr pw 9
-.Ix 0 def make
-.Ix 0 def conditional make
-.Ix 0 def if make
-.IP make \n(pw
-The syntax is
-.CW make( \fItarget\fP\c
-.CW )
-where
-.I target
-is a target in the makefile. This is true if the given target was
-specified on the command line, or as the source for a
-.CW .MAIN
-target (note that the sources for
-.CW .MAIN
-are only used if no targets were given on the command line).
-.IP defined \n(pw
-.Ix 0 def defined
-.Ix 0 def conditional defined
-.Ix 0 def if defined
-The syntax is
-.CW defined( \fIvariable\fP\c
-.CW )
-and is true if
-.I variable
-is defined. Certain variables are defined in the system makefile that
-identify the system on which PMake is being run.
-.IP exists \n(pw
-.Ix 0 def exists
-.Ix 0 def conditional exists
-.Ix 0 def if exists
-The syntax is
-.CW exists( \fIfile\fP\c
-.CW )
-and is true if the file can be found on the global search path
-(i.e. that defined by
-.CW .PATH
-targets, not by
-.CW .PATH \fIsuffix\fP
-targets).
-.IP empty \n(pw
-.Ix 0 def empty
-.Ix 0 def conditional empty
-.Ix 0 def if empty
-This syntax is much like the others, except the string inside the
-parentheses is of the same form as you would put between parentheses
-when expanding a variable, complete with modifiers and everything. The
-function returns true if the resulting string is empty (NOTE: an undefined
-variable in this context will cause at the very least a warning
-message about a malformed conditional, and at the worst will cause the
-process to stop once it has read the makefile. If you want to check
-for a variable being defined or empty, use the expression
-.CW !defined( \fIvar\fP\c ``
-.CW ") || empty(" \fIvar\fP\c
-.CW ) ''
-as the definition of
-.CW ||
-will prevent the
-.CW empty()
-from being evaluated and causing an error, if the variable is
-undefined). This can be used to see if a variable contains a given
-word, for example:
-.DS
-#if !empty(\fIvar\fP:M\fIword\fP)
-.DE
-.LP
-The arithmetic and string operators may only be used to test the value
-of a variable. The lefthand side must contain the variable expansion,
-while the righthand side contains either a string, enclosed in
-double-quotes, or a number. The standard C numeric conventions (except
-for specifying an octal number) apply to both sides. E.g.
-.DS
-#if $(OS) == 4.3
-
-#if $(MACHINE) == "sun3"
-
-#if $(LOAD_ADDR) < 0xc000
-.DE
-are all valid conditionals. In addition, the numeric value of a
-variable can be tested as a boolean as follows:
-.DS
-#if $(LOAD)
-.DE
-would see if
-.CW LOAD
-contains a non-zero value and
-.DS
-#if !$(LOAD)
-.DE
-would test if
-.CW LOAD
-contains a zero value.
-.LP
-In addition to the bare
-.CW #if ,'' ``
-there are other forms that apply one of the first two functions to each
-term. They are as follows:
-.DS
- ifdef \fRdefined\fP
- ifndef \fR!defined\fP
- ifmake \fRmake\fP
- ifnmake \fR!make\fP
-.DE
-There are also the ``else if'' forms:
-.CW elif ,
-.CW elifdef ,
-.CW elifndef ,
-.CW elifmake ,
-and
-.CW elifnmake .
-.LP
-For instance, if you wish to create two versions of a program, one of which
-is optimized (the production version) and the other of which is for debugging
-(has symbols for dbx), you have two choices: you can create two
-makefiles, one of which uses the
-.CW \-g
-flag for the compilation, while the other uses the
-.CW \-O
-flag, or you can use another target (call it
-.CW debug )
-to create the debug version. The construct below will take care of
-this for you. I have also made it so defining the variable
-.CW DEBUG
-(say with
-.CW "pmake -D DEBUG" )
-will also cause the debug version to be made.
-.DS
-#if defined(DEBUG) || make(debug)
-CFLAGS += -g
-#else
-CFLAGS += -O
-#endif
-.DE
-There are, of course, problems with this approach. The most glaring
-annoyance is that if you want to go from making a debug version to
-making a production version, you have to remove all the object files,
-or you will get some optimized and some debug versions in the same
-program. Another annoyance is you have to be careful not to make two
-targets that ``conflict'' because of some conditionals in the
-makefile. For instance
-.DS
-#if make(print)
-FORMATTER = ditroff -Plaser_printer
-#endif
-#if make(draft)
-FORMATTER = nroff -Pdot_matrix_printer
-#endif
-.DE
-would wreak havoc if you tried
-.CW "pmake draft print" '' ``
-since you would use the same formatter for each target. As I said,
-this all gets somewhat complicated.
-.xH 2 A Shell is a Shell is a Shell
-.Rd 7
-.LP
-In normal operation, the Bourne Shell (better known as
-.CW sh '') ``
-is used to execute the commands to re-create targets. PMake also allows you
-to specify a different shell for it to use when executing these
-commands. There are several things PMake must know about the shell you
-wish to use. These things are specified as the sources for the
-.CW .SHELL
-.Ix 0 ref .SHELL
-.Ix 0 ref target .SHELL
-target by keyword, as follows:
-.IP "\fBpath=\fP\fIpath\fP"
-PMake needs to know where the shell actually resides, so it can
-execute it. If you specify this and nothing else, PMake will use the
-last component of the path and look in its table of the shells it
-knows and use the specification it finds, if any. Use this if you just
-want to use a different version of the Bourne or C Shell (yes, PMake knows
-how to use the C Shell too).
-.IP "\fBname=\fP\fIname\fP"
-This is the name by which the shell is to be known. It is a single
-word and, if no other keywords are specified (other than
-.B path ),
-it is the name by which PMake attempts to find a specification for
-it (as mentioned above). You can use this if you would just rather use
-the C Shell than the Bourne Shell
-.CW ".SHELL: name=csh" '' (``
-will do it).
-.IP "\fBquiet=\fP\fIecho-off command\fP"
-As mentioned before, PMake actually controls whether commands are
-printed by introducing commands into the shell's input stream. This
-keyword, and the next two, control what those commands are. The
-.B quiet
-keyword is the command used to turn echoing off. Once it is turned
-off, echoing is expected to remain off until the echo-on command is given.
-.IP "\fBecho=\fP\fIecho-on command\fP"
-The command PMake should give to turn echoing back on again.
-.IP "\fBfilter=\fP\fIprinted echo-off command\fP"
-Many shells will echo the echo-off command when it is given. This
-keyword tells PMake in what format the shell actually prints the
-echo-off command. Wherever PMake sees this string in the shell's
-output, it will delete it and any following whitespace, up to and
-including the next newline. See the example at the end of this section
-for more details.
-.IP "\fBechoFlag=\fP\fIflag to turn echoing on\fP"
-Unless a target has been marked
-.CW .SILENT ,
-PMake wants to start the shell running with echoing on. To do this, it
-passes this flag to the shell as one of its arguments. If either this
-or the next flag begins with a `\-', the flags will be passed to the
-shell as separate arguments. Otherwise, the two will be concatenated
-(if they are used at the same time, of course).
-.IP "\fBerrFlag=\fP\fIflag to turn error checking on\fP"
-Likewise, unless a target is marked
-.CW .IGNORE ,
-PMake wishes error-checking to be on from the very start. To this end,
-it will pass this flag to the shell as an argument. The same rules for
-an initial `\-' apply as for the
-.B echoFlag .
-.IP "\fBcheck=\fP\fIcommand to turn error checking on\fP"
-Just as for echo-control, error-control is achieved by inserting
-commands into the shell's input stream. This is the command to make
-the shell check for errors. It also serves another purpose if the
-shell doesn't have error-control as commands, but I'll get into that
-in a minute. Again, once error checking has been turned on, it is
-expected to remain on until it is turned off again.
-.IP "\fBignore=\fP\fIcommand to turn error checking off\fP"
-This is the command PMake uses to turn error checking off. It has
-another use if the shell doesn't do error-control, but I'll tell you
-about that.\|.\|.\|now.
-.IP "\fBhasErrCtl=\fP\fIyes or no\fP"
-This takes a value that is either
-.B yes
-or
-.B no .
-Now you might think that the existence of the
-.B check
-and
-.B ignore
-keywords would be enough to tell PMake if the shell can do
-error-control, but you'd be wrong. If
-.B hasErrCtl
-is
-.B yes ,
-PMake uses the check and ignore commands in a straight-forward manner.
-If this is
-.B no ,
-however, their use is rather different. In this case, the check
-command is used as a template, in which the string
-.B %s
-is replaced by the command that's about to be executed, to produce a
-command for the shell that will echo the command to be executed. The
-ignore command is also used as a template, again with
-.B %s
-replaced by the command to be executed, to produce a command that will
-execute the command to be executed and ignore any error it returns.
-When these strings are used as templates, you must provide newline(s)
-.CW \en '') (``
-in the appropriate place(s).
-.LP
-The strings that follow these keywords may be enclosed in single or
-double quotes (the quotes will be stripped off) and may contain the
-usual C backslash-characters (\en is newline, \er is return, \eb is
-backspace, \e' escapes a single-quote inside single-quotes, \e"
-escapes a double-quote inside double-quotes). Now for an example.
-.LP
-This is actually the contents of the
-.CW <shx.mk>
-system makefile, and causes PMake to use the Bourne Shell in such a
-way that each command is printed as it is executed. That is, if more
-than one command is given on a line, each will be printed separately.
-Similarly, each time the body of a loop is executed, the commands
-within that loop will be printed, etc. The specification runs like
-this:
-.DS
-#
-# This is a shell specification to have the Bourne shell echo
-# the commands just before executing them, rather than when it reads
-# them. Useful if you want to see how variables are being expanded, etc.
-#
-\&.SHELL : path=/bin/sh \e
- quiet="set -" \e
- echo="set -x" \e
- filter="+ set - " \e
- echoFlag=x \e
- errFlag=e \e
- hasErrCtl=yes \e
- check="set -e" \e
- ignore="set +e"
-.DE
-.LP
-It tells PMake the following:
-.Bp
-The shell is located in the file
-.CW /bin/sh .
-It need not tell PMake that the name of the shell is
-.CW sh
-as PMake can figure that out for itself (it's the last component of
-the path).
-.Bp
-The command to stop echoing is
-.CW "set -" .
-.Bp
-The command to start echoing is
-.CW "set -x" .
-.Bp
-When the echo off command is executed, the shell will print
-.CW "+ set - "
-(The `+' comes from using the
-.CW \-x
-flag (rather than the
-.CW \-v
-flag PMake usually uses)). PMake will remove all occurrences of this
-string from the output, so you don't notice extra commands you didn't
-put there.
-.Bp
-The flag the Bourne Shell will take to start echoing in this way is
-the
-.CW \-x
-flag. The Bourne Shell will only take its flag arguments concatenated
-as its first argument, so neither this nor the
-.B errFlag
-specification begins with a \-.
-.Bp
-The flag to use to turn error-checking on from the start is
-.CW \-e .
-.Bp
-The shell can turn error-checking on and off, and the commands to do
-so are
-.CW "set +e"
-and
-.CW "set -e" ,
-respectively.
-.LP
-I should note that this specification is for Bourne Shells that are
-not part of Berkeley
-.UX ,
-as shells from Berkeley don't do error control. You can get a similar
-effect, however, by changing the last three lines to be:
-.DS
- hasErrCtl=no \e
- check="echo \e"+ %s\e"\en" \e
- ignore="sh -c '%s || exit 0\en"
-.DE
-.LP
-This will cause PMake to execute the two commands
-.DS
-echo "+ \fIcmd\fP"
-sh -c '\fIcmd\fP || true'
-.DE
-for each command for which errors are to be ignored. (In case you are
-wondering, the thing for
-.CW ignore
-tells the shell to execute another shell without error checking on and
-always exit 0, since the
-.B ||
-causes the
-.CW "exit 0"
-to be executed only if the first command exited non-zero, and if the
-first command exited zero, the shell will also exit zero, since that's
-the last command it executed).
-.xH 2 Compatibility
-.Ix 0 ref compatibility
-.LP
-There are three (well, 3 \(12) levels of backwards-compatibility built
-into PMake. Most makefiles will need none at all. Some may need a
-little bit of work to operate correctly when run in parallel. Each
-level encompasses the previous levels (e.g.
-.B \-B
-(one shell per command) implies
-.B \-V )
-The three levels are described in the following three sections.
-.xH 3 DEFCON 3 \*- Variable Expansion
-.Ix 0 ref compatibility
-.LP
-As noted before, PMake will not expand a variable unless it knows of a
-value for it. This can cause problems for makefiles that expect to
-leave variables undefined except in special circumstances (e.g. if
-more flags need to be passed to the C compiler or the output from a
-text processor should be sent to a different printer). If the
-variables are enclosed in curly braces
-.CW ${PRINTER} ''), (``
-the shell will let them pass. If they are enclosed in parentheses,
-however, the shell will declare a syntax error and the make will come
-to a grinding halt.
-.LP
-You have two choices: change the makefile to define the variables
-(their values can be overridden on the command line, since that's
-where they would have been set if you used Make, anyway) or always give the
-.B \-V
-flag (this can be done with the
-.CW .MAKEFLAGS
-target, if you want).
-.xH 3 DEFCON 2 \*- The Number of the Beast
-.Ix 0 ref compatibility
-.LP
-Then there are the makefiles that expect certain commands, such as
-changing to a different directory, to not affect other commands in a
-target's creation script. You can solve this is either by going
-back to executing one shell per command (which is what the
-.B \-B
-flag forces PMake to do), which slows the process down a good bit and
-requires you to use semicolons and escaped newlines for shell constructs, or
-by changing the makefile to execute the offending command(s) in a subshell
-(by placing the line inside parentheses), like so:
-.DS
-install :: .MAKE
- (cd src; $(.PMAKE) install)
- (cd lib; $(.PMAKE) install)
- (cd man; $(.PMAKE) install)
-.DE
-.Ix 0 ref operator double-colon
-.Ix 0 ref variable global .PMAKE
-.Ix 0 ref .PMAKE
-.Ix 0 ref .MAKE
-.Ix 0 ref attribute .MAKE
-This will always execute the three makes (even if the
-.B \-n
-flag was given) because of the combination of the ``::'' operator and
-the
-.CW .MAKE
-attribute. Each command will change to the proper directory to perform
-the install, leaving the main shell in the directory in which it started.
-.xH 3 "DEFCON 1 \*- Imitation is the Not the Highest Form of Flattery"
-.Ix 0 ref compatibility
-.LP
-The final category of makefile is the one where every command requires
-input, the dependencies are incompletely specified, or you simply
-cannot create more than one target at a time, as mentioned earlier. In
-addition, you may not have the time or desire to upgrade the makefile
-to run smoothly with PMake. If you are the conservative sort, this is
-the compatibility mode for you. It is entered either by giving PMake
-the
-.B \-M
-flag (for Make), or by executing PMake as
-.CW make .'' ``
-In either case, PMake performs things exactly like Make (while still
-supporting most of the nice new features PMake provides). This
-includes:
-.IP \(bu 2
-No parallel execution.
-.IP \(bu 2
-Targets are made in the exact order specified by the makefile. The
-sources for each target are made in strict left-to-right order, etc.
-.IP \(bu 2
-A single Bourne shell is used to execute each command, thus the
-shell's
-.CW $$
-variable is useless, changing directories doesn't work across command
-lines, etc.
-.IP \(bu 2
-If no special characters exist in a command line, PMake will break the
-command into words itself and execute the command directly, without
-executing a shell first. The characters that cause PMake to execute a
-shell are:
-.CW # ,
-.CW = ,
-.CW | ,
-.CW ^ ,
-.CW ( ,
-.CW ) ,
-.CW { ,
-.CW } ,
-.CW ; ,
-.CW & ,
-.CW < ,
-.CW > ,
-.CW * ,
-.CW ? ,
-.CW [ ,
-.CW ] ,
-.CW : ,
-.CW $ ,
-.CW ` ,
-and
-.CW \e .
-You should notice that these are all the characters that are given
-special meaning by the shell (except
-.CW '
-and
-.CW " ,
-which PMake deals with all by its lonesome).
-.IP \(bu 2
-The use of the null suffix is turned off.
-.Ix 0 ref "null suffix"
-.Ix 0 ref suffix null
-.xH 2 The Way Things Work
-.LP
-When PMake reads the makefile, it parses sources and targets into
-nodes in a graph. The graph is directed only in the sense that PMake
-knows which way is up. Each node contains not only links to all its
-parents and children (the nodes that depend on it and those on which
-it depends, respectively), but also a count of the number of its
-children that have already been processed.
-.LP
-The most important thing to know about how PMake uses this graph is
-that the traversal is breadth-first and occurs in two passes.
-.LP
-After PMake has parsed the makefile, it begins with the nodes the user
-has told it to make (either on the command line, or via a
-.CW .MAIN
-target, or by the target being the first in the file not labeled with
-the
-.CW .NOTMAIN
-attribute) placed in a queue. It continues to take the node off the
-front of the queue, mark it as something that needs to be made, pass
-the node to
-.CW Suff_FindDeps
-(mentioned earlier) to find any implicit sources for the node, and
-place all the node's children that have yet to be marked at the end of
-the queue. If any of the children is a
-.CW .USE
-rule, its attributes are applied to the parent, then its commands are
-appended to the parent's list of commands and its children are linked
-to its parent. The parent's unmade children counter is then decremented
-(since the
-.CW .USE
-node has been processed). You will note that this allows a
-.CW .USE
-node to have children that are
-.CW .USE
-nodes and the rules will be applied in sequence.
-If the node has no children, it is placed at the end of
-another queue to be examined in the second pass. This process
-continues until the first queue is empty.
-.LP
-At this point, all the leaves of the graph are in the examination
-queue. PMake removes the node at the head of the queue and sees if it
-is out-of-date. If it is, it is passed to a function that will execute
-the commands for the node asynchronously. When the commands have
-completed, all the node's parents have their unmade children counter
-decremented and, if the counter is then 0, they are placed on the
-examination queue. Likewise, if the node is up-to-date. Only those
-parents that were marked on the downward pass are processed in this
-way. Thus PMake traverses the graph back up to the nodes the user
-instructed it to create. When the examination queue is empty and no
-shells are running to create a target, PMake is finished.
-.LP
-Once all targets have been processed, PMake executes the commands
-attached to the
-.CW .END
-target, either explicitly or through the use of an ellipsis in a shell
-script. If there were no errors during the entire process but there
-are still some targets unmade (PMake keeps a running count of how many
-targets are left to be made), there is a cycle in the graph. PMake does
-a depth-first traversal of the graph to find all the targets that
-weren't made and prints them out one by one.
-.xH 1 Answers to Exercises
-.IP (3.1)
-This is something of a trick question, for which I apologize. The
-trick comes from the UNIX definition of a suffix, which PMake doesn't
-necessarily share. You will have noticed that all the suffixes used in
-this tutorial (and in UNIX in general) begin with a period
-.CW .ms , (
-.CW .c ,
-etc.). Now, PMake's idea of a suffix is more like English's: it's the
-characters at the end of a word. With this in mind, one possible
-.Ix 0 def suffix
-solution to this problem goes as follows:
-.DS I
-\&.SUFFIXES : ec.exe .exe ec.obj .obj .asm
-ec.objec.exe .obj.exe :
- link -o $(.TARGET) $(.IMPSRC)
-\&.asmec.obj :
- asm -o $(.TARGET) -DDO_ERROR_CHECKING $(.IMPSRC)
-\&.asm.obj :
- asm -o $(.TARGET) $(.IMPSRC)
-.DE
-.IP (3.2)
-The trick to this one lies in the ``:='' variable-assignment operator
-and the ``:S'' variable-expansion modifier.
-.Ix 0 ref variable assignment expanded
-.Ix 0 ref variable expansion modified
-.Ix 0 ref modifier substitute
-.Ix 0 ref :S
-.Ix 0 ref :=
-Basically what you want is to take the pointer variable, so to speak,
-and transform it into an invocation of the variable at which it
-points. You might try something like
-.DS I
-$(PTR:S/^/\e$(/:S/$/))
-.DE
-which places
-.CW $( '' ``
-at the front of the variable name and
-.CW ) '' ``
-at the end, thus transforming
-.CW VAR ,'' ``
-for example, into
-.CW $(VAR) ,'' ``
-which is just what we want. Unfortunately (as you know if you've tried
-it), since, as it says in the hint, PMake does no further substitution
-on the result of a modified expansion, that's \fIall\fP you get. The
-solution is to make use of ``:='' to place that string into yet
-another variable, then invoke the other variable directly:
-.DS I
-*PTR := $(PTR:S/^/\e$(/:S/$/)/)
-.DE
-You can then use
-.CW $(*PTR) '' ``
-to your heart's content.
-.de Gp
-.XP
-\&\fB\\$1:\fP
-..
-.xH 1 Glossary of Jargon
-.Gp "attribute"
-A property given to a target that causes PMake to treat it differently.
-.Gp "command script"
-The lines immediately following a dependency line that specify
-commands to execute to create each of the targets on the dependency
-line. Each line in the command script must begin with a tab.
-.Gp "command-line variable"
-A variable defined in an argument when PMake is first executed.
-Overrides all assignments to the same variable name in the makefile.
-.Gp "conditional"
-A construct much like that used in C that allows a makefile to be
-configured on the fly based on the local environment, or on what is being
-made by that invocation of PMake.
-.Gp "creation script"
-Commands used to create a target. See ``command script.''
-.Gp "dependency"
-The relationship between a source and a target. This comes in three
-flavors, as indicated by the operator between the target and the
-source. `:' gives a straight time-wise dependency (if the target is
-older than the source, the target is out-of-date), while `!' provides
-simply an ordering and always considers the target out-of-date. `::'
-is much like `:', save it creates multiple instances of a target each
-of which depends on its own list of sources.
-.Gp "dynamic source"
-This refers to a source that has a local variable invocation in it. It
-allows a single dependency line to specify a different source for each
-target on the line.
-.Gp "global variable"
-Any variable defined in a makefile. Takes precedence over variables
-defined in the environment, but not over command-line or local variables.
-.Gp "input graph"
-What PMake constructs from a makefile. Consists of nodes made of the
-targets in the makefile, and the links between them (the
-dependencies). The links are directed (from source to target) and
-there may not be any cycles (loops) in the graph.
-.Gp "local variable"
-A variable defined by PMake visible only in a target's shell script.
-There are seven local variables, not all of which are defined for
-every target:
-.CW .TARGET ,
-.CW .ALLSRC ,
-.CW .OODATE ,
-.CW .PREFIX ,
-.CW .IMPSRC ,
-.CW .ARCHIVE ,
-and
-.CW .MEMBER .
-.CW .TARGET ,
-.CW .PREFIX ,
-.CW .ARCHIVE ,
-and
-.CW .MEMBER
-may be used on dependency lines to create ``dynamic sources.''
-.Gp "makefile"
-A file that describes how a system is built. If you don't know what it
-is after reading this tutorial.\|.\|.\|.
-.Gp "modifier"
-A letter, following a colon, used to alter how a variable is expanded.
-It has no effect on the variable itself.
-.Gp "operator"
-What separates a source from a target (on a dependency line) and specifies
-the relationship between the two. There are three:
-.CW : ', `
-.CW :: ', `
-and
-.CW ! '. `
-.Gp "search path"
-A list of directories in which a file should be sought. PMake's view
-of the contents of directories in a search path does not change once
-the makefile has been read. A file is sought on a search path only if
-it is exclusively a source.
-.Gp "shell"
-A program to which commands are passed in order to create targets.
-.Gp "source"
-Anything to the right of an operator on a dependency line. Targets on
-the dependency line are usually created from the sources.
-.Gp "special target"
-A target that causes PMake to do special things when it's encountered.
-.Gp "suffix"
-The tail end of a file name. Usually begins with a period,
-.CW .c
-or
-.CW .ms ,
-e.g.
-.Gp "target"
-A word to the left of the operator on a dependency line. More
-generally, any file that PMake might create. A file may be (and often
-is) both a target and a source (what it is depends on how PMake is
-looking at it at the time \*- sort of like the wave/particle duality
-of light, you know).
-.Gp "transformation rule"
-A special construct in a makefile that specifies how to create a file
-of one type from a file of another, as indicated by their suffixes.
-.Gp "variable expansion"
-The process of substituting the value of a variable for a reference to
-it. Expansion may be altered by means of modifiers.
-.Gp "variable"
-A place in which to store text that may be retrieved later. Also used
-to define the local environment. Conditionals exist that test whether
-a variable is defined or not.
-.bp
-.\" Output table of contents last, with an entry for the index, making
-.\" sure to save and restore the last real page number for the index...
-.nr @n \n(PN+1
-.\" We are not generating an index
-.\" .XS \n(@n
-.\" Index
-.\" .XE
-.nr %% \n%
-.PX
-.nr % \n(%%
diff --git a/usr.bin/make/arch.c b/usr.bin/make/arch.c
deleted file mode 100644
index 8241434..0000000
--- a/usr.bin/make/arch.c
+++ /dev/null
@@ -1,1369 +0,0 @@
-/* $NetBSD: arch.c,v 1.70 2017/04/16 20:49:09 riastradh Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-/*
- * Copyright (c) 1989 by Berkeley Softworks
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: arch.c,v 1.70 2017/04/16 20:49:09 riastradh Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)arch.c 8.2 (Berkeley) 1/2/94";
-#else
-__RCSID("$NetBSD: arch.c,v 1.70 2017/04/16 20:49:09 riastradh Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * arch.c --
- * Functions to manipulate libraries, archives and their members.
- *
- * Once again, cacheing/hashing comes into play in the manipulation
- * of archives. The first time an archive is referenced, all of its members'
- * headers are read and hashed and the archive closed again. All hashed
- * archives are kept on a list which is searched each time an archive member
- * is referenced.
- *
- * The interface to this module is:
- * Arch_ParseArchive Given an archive specification, return a list
- * of GNode's, one for each member in the spec.
- * FAILURE is returned if the specification is
- * invalid for some reason.
- *
- * Arch_Touch Alter the modification time of the archive
- * member described by the given node to be
- * the current time.
- *
- * Arch_TouchLib Update the modification time of the library
- * described by the given node. This is special
- * because it also updates the modification time
- * of the library's table of contents.
- *
- * Arch_MTime Find the modification time of a member of
- * an archive *in the archive*. The time is also
- * placed in the member's GNode. Returns the
- * modification time.
- *
- * Arch_MemTime Find the modification time of a member of
- * an archive. Called when the member doesn't
- * already exist. Looks in the archive for the
- * modification time. Returns the modification
- * time.
- *
- * Arch_FindLib Search for a library along a path. The
- * library name in the GNode should be in
- * -l<name> format.
- *
- * Arch_LibOODate Special function to decide if a library node
- * is out-of-date.
- *
- * Arch_Init Initialize this module.
- *
- * Arch_End Cleanup this module.
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/param.h>
-
-#include <ar.h>
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <utime.h>
-
-#include "make.h"
-#include "hash.h"
-#include "dir.h"
-#include "config.h"
-
-#ifdef TARGET_MACHINE
-#undef MAKE_MACHINE
-#define MAKE_MACHINE TARGET_MACHINE
-#endif
-#ifdef TARGET_MACHINE_ARCH
-#undef MAKE_MACHINE_ARCH
-#define MAKE_MACHINE_ARCH TARGET_MACHINE_ARCH
-#endif
-
-static Lst archives; /* Lst of archives we've already examined */
-
-typedef struct Arch {
- char *name; /* Name of archive */
- Hash_Table members; /* All the members of the archive described
- * by <name, struct ar_hdr *> key/value pairs */
- char *fnametab; /* Extended name table strings */
- size_t fnamesize; /* Size of the string table */
-} Arch;
-
-static int ArchFindArchive(const void *, const void *);
-#ifdef CLEANUP
-static void ArchFree(void *);
-#endif
-static struct ar_hdr *ArchStatMember(char *, char *, Boolean);
-static FILE *ArchFindMember(char *, char *, struct ar_hdr *, const char *);
-#if defined(__svr4__) || defined(__SVR4) || defined(__ELF__)
-#define SVR4ARCHIVES
-static int ArchSVR4Entry(Arch *, char *, size_t, FILE *);
-#endif
-
-#ifdef CLEANUP
-/*-
- *-----------------------------------------------------------------------
- * ArchFree --
- * Free memory used by an archive
- *
- * Results:
- * None.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-static void
-ArchFree(void *ap)
-{
- Arch *a = (Arch *)ap;
- Hash_Search search;
- Hash_Entry *entry;
-
- /* Free memory from hash entries */
- for (entry = Hash_EnumFirst(&a->members, &search);
- entry != NULL;
- entry = Hash_EnumNext(&search))
- free(Hash_GetValue(entry));
-
- free(a->name);
- free(a->fnametab);
- Hash_DeleteTable(&a->members);
- free(a);
-}
-#endif
-
-
-
-/*-
- *-----------------------------------------------------------------------
- * Arch_ParseArchive --
- * Parse the archive specification in the given line and find/create
- * the nodes for the specified archive members, placing their nodes
- * on the given list.
- *
- * Input:
- * linePtr Pointer to start of specification
- * nodeLst Lst on which to place the nodes
- * ctxt Context in which to expand variables
- *
- * Results:
- * SUCCESS if it was a valid specification. The linePtr is updated
- * to point to the first non-space after the archive spec. The
- * nodes for the members are placed on the given list.
- *
- * Side Effects:
- * Some nodes may be created. The given list is extended.
- *
- *-----------------------------------------------------------------------
- */
-ReturnStatus
-Arch_ParseArchive(char **linePtr, Lst nodeLst, GNode *ctxt)
-{
- char *cp; /* Pointer into line */
- GNode *gn; /* New node */
- char *libName; /* Library-part of specification */
- char *memName; /* Member-part of specification */
- char *nameBuf; /* temporary place for node name */
- char saveChar; /* Ending delimiter of member-name */
- Boolean subLibName; /* TRUE if libName should have/had
- * variable substitution performed on it */
-
- libName = *linePtr;
-
- subLibName = FALSE;
-
- for (cp = libName; *cp != '(' && *cp != '\0'; cp++) {
- if (*cp == '$') {
- /*
- * Variable spec, so call the Var module to parse the puppy
- * so we can safely advance beyond it...
- */
- int length;
- void *freeIt;
- char *result;
-
- result = Var_Parse(cp, ctxt, VARF_UNDEFERR|VARF_WANTRES,
- &length, &freeIt);
- free(freeIt);
-
- if (result == var_Error) {
- return(FAILURE);
- } else {
- subLibName = TRUE;
- }
-
- cp += length-1;
- }
- }
-
- *cp++ = '\0';
- if (subLibName) {
- libName = Var_Subst(NULL, libName, ctxt, VARF_UNDEFERR|VARF_WANTRES);
- }
-
-
- for (;;) {
- /*
- * First skip to the start of the member's name, mark that
- * place and skip to the end of it (either white-space or
- * a close paren).
- */
- Boolean doSubst = FALSE; /* TRUE if need to substitute in memName */
-
- while (*cp != '\0' && *cp != ')' && isspace ((unsigned char)*cp)) {
- cp++;
- }
- memName = cp;
- while (*cp != '\0' && *cp != ')' && !isspace ((unsigned char)*cp)) {
- if (*cp == '$') {
- /*
- * Variable spec, so call the Var module to parse the puppy
- * so we can safely advance beyond it...
- */
- int length;
- void *freeIt;
- char *result;
-
- result = Var_Parse(cp, ctxt, VARF_UNDEFERR|VARF_WANTRES,
- &length, &freeIt);
- free(freeIt);
-
- if (result == var_Error) {
- return(FAILURE);
- } else {
- doSubst = TRUE;
- }
-
- cp += length;
- } else {
- cp++;
- }
- }
-
- /*
- * If the specification ends without a closing parenthesis,
- * chances are there's something wrong (like a missing backslash),
- * so it's better to return failure than allow such things to happen
- */
- if (*cp == '\0') {
- printf("No closing parenthesis in archive specification\n");
- return (FAILURE);
- }
-
- /*
- * If we didn't move anywhere, we must be done
- */
- if (cp == memName) {
- break;
- }
-
- saveChar = *cp;
- *cp = '\0';
-
- /*
- * XXX: This should be taken care of intelligently by
- * SuffExpandChildren, both for the archive and the member portions.
- */
- /*
- * If member contains variables, try and substitute for them.
- * This will slow down archive specs with dynamic sources, of course,
- * since we'll be (non-)substituting them three times, but them's
- * the breaks -- we need to do this since SuffExpandChildren calls
- * us, otherwise we could assume the thing would be taken care of
- * later.
- */
- if (doSubst) {
- char *buf;
- char *sacrifice;
- char *oldMemName = memName;
- size_t sz;
-
- memName = Var_Subst(NULL, memName, ctxt,
- VARF_UNDEFERR|VARF_WANTRES);
-
- /*
- * Now form an archive spec and recurse to deal with nested
- * variables and multi-word variable values.... The results
- * are just placed at the end of the nodeLst we're returning.
- */
- sz = strlen(memName)+strlen(libName)+3;
- buf = sacrifice = bmake_malloc(sz);
-
- snprintf(buf, sz, "%s(%s)", libName, memName);
-
- if (strchr(memName, '$') && strcmp(memName, oldMemName) == 0) {
- /*
- * Must contain dynamic sources, so we can't deal with it now.
- * Just create an ARCHV node for the thing and let
- * SuffExpandChildren handle it...
- */
- gn = Targ_FindNode(buf, TARG_CREATE);
-
- if (gn == NULL) {
- free(buf);
- return(FAILURE);
- } else {
- gn->type |= OP_ARCHV;
- (void)Lst_AtEnd(nodeLst, gn);
- }
- } else if (Arch_ParseArchive(&sacrifice, nodeLst, ctxt)!=SUCCESS) {
- /*
- * Error in nested call -- free buffer and return FAILURE
- * ourselves.
- */
- free(buf);
- return(FAILURE);
- }
- /*
- * Free buffer and continue with our work.
- */
- free(buf);
- } else if (Dir_HasWildcards(memName)) {
- Lst members = Lst_Init(FALSE);
- char *member;
- size_t sz = MAXPATHLEN, nsz;
- nameBuf = bmake_malloc(sz);
-
- Dir_Expand(memName, dirSearchPath, members);
- while (!Lst_IsEmpty(members)) {
- member = (char *)Lst_DeQueue(members);
- nsz = strlen(libName) + strlen(member) + 3;
- if (sz > nsz)
- nameBuf = bmake_realloc(nameBuf, sz = nsz * 2);
-
- snprintf(nameBuf, sz, "%s(%s)", libName, member);
- free(member);
- gn = Targ_FindNode(nameBuf, TARG_CREATE);
- if (gn == NULL) {
- free(nameBuf);
- return (FAILURE);
- } else {
- /*
- * We've found the node, but have to make sure the rest of
- * the world knows it's an archive member, without having
- * to constantly check for parentheses, so we type the
- * thing with the OP_ARCHV bit before we place it on the
- * end of the provided list.
- */
- gn->type |= OP_ARCHV;
- (void)Lst_AtEnd(nodeLst, gn);
- }
- }
- Lst_Destroy(members, NULL);
- free(nameBuf);
- } else {
- size_t sz = strlen(libName) + strlen(memName) + 3;
- nameBuf = bmake_malloc(sz);
- snprintf(nameBuf, sz, "%s(%s)", libName, memName);
- gn = Targ_FindNode(nameBuf, TARG_CREATE);
- free(nameBuf);
- if (gn == NULL) {
- return (FAILURE);
- } else {
- /*
- * We've found the node, but have to make sure the rest of the
- * world knows it's an archive member, without having to
- * constantly check for parentheses, so we type the thing with
- * the OP_ARCHV bit before we place it on the end of the
- * provided list.
- */
- gn->type |= OP_ARCHV;
- (void)Lst_AtEnd(nodeLst, gn);
- }
- }
- if (doSubst) {
- free(memName);
- }
-
- *cp = saveChar;
- }
-
- /*
- * If substituted libName, free it now, since we need it no longer.
- */
- if (subLibName) {
- free(libName);
- }
-
- /*
- * We promised the pointer would be set up at the next non-space, so
- * we must advance cp there before setting *linePtr... (note that on
- * entrance to the loop, cp is guaranteed to point at a ')')
- */
- do {
- cp++;
- } while (*cp != '\0' && isspace ((unsigned char)*cp));
-
- *linePtr = cp;
- return (SUCCESS);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * ArchFindArchive --
- * See if the given archive is the one we are looking for. Called
- * From ArchStatMember and ArchFindMember via Lst_Find.
- *
- * Input:
- * ar Current list element
- * archName Name we want
- *
- * Results:
- * 0 if it is, non-zero if it isn't.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-static int
-ArchFindArchive(const void *ar, const void *archName)
-{
- return (strcmp(archName, ((const Arch *)ar)->name));
-}
-
-/*-
- *-----------------------------------------------------------------------
- * ArchStatMember --
- * Locate a member of an archive, given the path of the archive and
- * the path of the desired member.
- *
- * Input:
- * archive Path to the archive
- * member Name of member. If it is a path, only the last
- * component is used.
- * hash TRUE if archive should be hashed if not already so.
- *
- * Results:
- * A pointer to the current struct ar_hdr structure for the member. Note
- * That no position is returned, so this is not useful for touching
- * archive members. This is mostly because we have no assurances that
- * The archive will remain constant after we read all the headers, so
- * there's not much point in remembering the position...
- *
- * Side Effects:
- *
- *-----------------------------------------------------------------------
- */
-static struct ar_hdr *
-ArchStatMember(char *archive, char *member, Boolean hash)
-{
-#define AR_MAX_NAME_LEN (sizeof(arh.ar_name)-1)
- FILE * arch; /* Stream to archive */
- int size; /* Size of archive member */
- char *cp; /* Useful character pointer */
- char magic[SARMAG];
- LstNode ln; /* Lst member containing archive descriptor */
- Arch *ar; /* Archive descriptor */
- Hash_Entry *he; /* Entry containing member's description */
- struct ar_hdr arh; /* archive-member header for reading archive */
- char memName[MAXPATHLEN+1];
- /* Current member name while hashing. */
-
- /*
- * Because of space constraints and similar things, files are archived
- * using their final path components, not the entire thing, so we need
- * to point 'member' to the final component, if there is one, to make
- * the comparisons easier...
- */
- cp = strrchr(member, '/');
- if (cp != NULL) {
- member = cp + 1;
- }
-
- ln = Lst_Find(archives, archive, ArchFindArchive);
- if (ln != NULL) {
- ar = (Arch *)Lst_Datum(ln);
-
- he = Hash_FindEntry(&ar->members, member);
-
- if (he != NULL) {
- return ((struct ar_hdr *)Hash_GetValue(he));
- } else {
- /* Try truncated name */
- char copy[AR_MAX_NAME_LEN+1];
- size_t len = strlen(member);
-
- if (len > AR_MAX_NAME_LEN) {
- len = AR_MAX_NAME_LEN;
- strncpy(copy, member, AR_MAX_NAME_LEN);
- copy[AR_MAX_NAME_LEN] = '\0';
- }
- if ((he = Hash_FindEntry(&ar->members, copy)) != NULL)
- return ((struct ar_hdr *)Hash_GetValue(he));
- return NULL;
- }
- }
-
- if (!hash) {
- /*
- * Caller doesn't want the thing hashed, just use ArchFindMember
- * to read the header for the member out and close down the stream
- * again. Since the archive is not to be hashed, we assume there's
- * no need to allocate extra room for the header we're returning,
- * so just declare it static.
- */
- static struct ar_hdr sarh;
-
- arch = ArchFindMember(archive, member, &sarh, "r");
-
- if (arch == NULL) {
- return NULL;
- } else {
- fclose(arch);
- return (&sarh);
- }
- }
-
- /*
- * We don't have this archive on the list yet, so we want to find out
- * everything that's in it and cache it so we can get at it quickly.
- */
- arch = fopen(archive, "r");
- if (arch == NULL) {
- return NULL;
- }
-
- /*
- * We use the ARMAG string to make sure this is an archive we
- * can handle...
- */
- if ((fread(magic, SARMAG, 1, arch) != 1) ||
- (strncmp(magic, ARMAG, SARMAG) != 0)) {
- fclose(arch);
- return NULL;
- }
-
- ar = bmake_malloc(sizeof(Arch));
- ar->name = bmake_strdup(archive);
- ar->fnametab = NULL;
- ar->fnamesize = 0;
- Hash_InitTable(&ar->members, -1);
- memName[AR_MAX_NAME_LEN] = '\0';
-
- while (fread((char *)&arh, sizeof(struct ar_hdr), 1, arch) == 1) {
- if (strncmp( arh.ar_fmag, ARFMAG, sizeof(arh.ar_fmag)) != 0) {
- /*
- * The header is bogus, so the archive is bad
- * and there's no way we can recover...
- */
- goto badarch;
- } else {
- /*
- * We need to advance the stream's pointer to the start of the
- * next header. Files are padded with newlines to an even-byte
- * boundary, so we need to extract the size of the file from the
- * 'size' field of the header and round it up during the seek.
- */
- arh.ar_size[sizeof(arh.ar_size)-1] = '\0';
- size = (int)strtol(arh.ar_size, NULL, 10);
-
- (void)strncpy(memName, arh.ar_name, sizeof(arh.ar_name));
- for (cp = &memName[AR_MAX_NAME_LEN]; *cp == ' '; cp--) {
- continue;
- }
- cp[1] = '\0';
-
-#ifdef SVR4ARCHIVES
- /*
- * svr4 names are slash terminated. Also svr4 extended AR format.
- */
- if (memName[0] == '/') {
- /*
- * svr4 magic mode; handle it
- */
- switch (ArchSVR4Entry(ar, memName, size, arch)) {
- case -1: /* Invalid data */
- goto badarch;
- case 0: /* List of files entry */
- continue;
- default: /* Got the entry */
- break;
- }
- }
- else {
- if (cp[0] == '/')
- cp[0] = '\0';
- }
-#endif
-
-#ifdef AR_EFMT1
- /*
- * BSD 4.4 extended AR format: #1/<namelen>, with name as the
- * first <namelen> bytes of the file
- */
- if (strncmp(memName, AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0 &&
- isdigit((unsigned char)memName[sizeof(AR_EFMT1) - 1])) {
-
- unsigned int elen = atoi(&memName[sizeof(AR_EFMT1)-1]);
-
- if (elen > MAXPATHLEN)
- goto badarch;
- if (fread(memName, elen, 1, arch) != 1)
- goto badarch;
- memName[elen] = '\0';
- if (fseek(arch, -elen, SEEK_CUR) != 0)
- goto badarch;
- if (DEBUG(ARCH) || DEBUG(MAKE)) {
- fprintf(debug_file, "ArchStat: Extended format entry for %s\n", memName);
- }
- }
-#endif
-
- he = Hash_CreateEntry(&ar->members, memName, NULL);
- Hash_SetValue(he, bmake_malloc(sizeof(struct ar_hdr)));
- memcpy(Hash_GetValue(he), &arh, sizeof(struct ar_hdr));
- }
- if (fseek(arch, (size + 1) & ~1, SEEK_CUR) != 0)
- goto badarch;
- }
-
- fclose(arch);
-
- (void)Lst_AtEnd(archives, ar);
-
- /*
- * Now that the archive has been read and cached, we can look into
- * the hash table to find the desired member's header.
- */
- he = Hash_FindEntry(&ar->members, member);
-
- if (he != NULL) {
- return ((struct ar_hdr *)Hash_GetValue(he));
- } else {
- return NULL;
- }
-
-badarch:
- fclose(arch);
- Hash_DeleteTable(&ar->members);
- free(ar->fnametab);
- free(ar);
- return NULL;
-}
-
-#ifdef SVR4ARCHIVES
-/*-
- *-----------------------------------------------------------------------
- * ArchSVR4Entry --
- * Parse an SVR4 style entry that begins with a slash.
- * If it is "//", then load the table of filenames
- * If it is "/<offset>", then try to substitute the long file name
- * from offset of a table previously read.
- *
- * Results:
- * -1: Bad data in archive
- * 0: A table was loaded from the file
- * 1: Name was successfully substituted from table
- * 2: Name was not successfully substituted from table
- *
- * Side Effects:
- * If a table is read, the file pointer is moved to the next archive
- * member
- *
- *-----------------------------------------------------------------------
- */
-static int
-ArchSVR4Entry(Arch *ar, char *name, size_t size, FILE *arch)
-{
-#define ARLONGNAMES1 "//"
-#define ARLONGNAMES2 "/ARFILENAMES"
- size_t entry;
- char *ptr, *eptr;
-
- if (strncmp(name, ARLONGNAMES1, sizeof(ARLONGNAMES1) - 1) == 0 ||
- strncmp(name, ARLONGNAMES2, sizeof(ARLONGNAMES2) - 1) == 0) {
-
- if (ar->fnametab != NULL) {
- if (DEBUG(ARCH)) {
- fprintf(debug_file, "Attempted to redefine an SVR4 name table\n");
- }
- return -1;
- }
-
- /*
- * This is a table of archive names, so we build one for
- * ourselves
- */
- ar->fnametab = bmake_malloc(size);
- ar->fnamesize = size;
-
- if (fread(ar->fnametab, size, 1, arch) != 1) {
- if (DEBUG(ARCH)) {
- fprintf(debug_file, "Reading an SVR4 name table failed\n");
- }
- return -1;
- }
- eptr = ar->fnametab + size;
- for (entry = 0, ptr = ar->fnametab; ptr < eptr; ptr++)
- switch (*ptr) {
- case '/':
- entry++;
- *ptr = '\0';
- break;
-
- case '\n':
- break;
-
- default:
- break;
- }
- if (DEBUG(ARCH)) {
- fprintf(debug_file, "Found svr4 archive name table with %lu entries\n",
- (unsigned long)entry);
- }
- return 0;
- }
-
- if (name[1] == ' ' || name[1] == '\0')
- return 2;
-
- entry = (size_t)strtol(&name[1], &eptr, 0);
- if ((*eptr != ' ' && *eptr != '\0') || eptr == &name[1]) {
- if (DEBUG(ARCH)) {
- fprintf(debug_file, "Could not parse SVR4 name %s\n", name);
- }
- return 2;
- }
- if (entry >= ar->fnamesize) {
- if (DEBUG(ARCH)) {
- fprintf(debug_file, "SVR4 entry offset %s is greater than %lu\n",
- name, (unsigned long)ar->fnamesize);
- }
- return 2;
- }
-
- if (DEBUG(ARCH)) {
- fprintf(debug_file, "Replaced %s with %s\n", name, &ar->fnametab[entry]);
- }
-
- (void)strncpy(name, &ar->fnametab[entry], MAXPATHLEN);
- name[MAXPATHLEN] = '\0';
- return 1;
-}
-#endif
-
-
-/*-
- *-----------------------------------------------------------------------
- * ArchFindMember --
- * Locate a member of an archive, given the path of the archive and
- * the path of the desired member. If the archive is to be modified,
- * the mode should be "r+", if not, it should be "r".
- *
- * Input:
- * archive Path to the archive
- * member Name of member. If it is a path, only the last
- * component is used.
- * arhPtr Pointer to header structure to be filled in
- * mode The mode for opening the stream
- *
- * Results:
- * An FILE *, opened for reading and writing, positioned at the
- * start of the member's struct ar_hdr, or NULL if the member was
- * nonexistent. The current struct ar_hdr for member.
- *
- * Side Effects:
- * The passed struct ar_hdr structure is filled in.
- *
- *-----------------------------------------------------------------------
- */
-static FILE *
-ArchFindMember(char *archive, char *member, struct ar_hdr *arhPtr,
- const char *mode)
-{
- FILE * arch; /* Stream to archive */
- int size; /* Size of archive member */
- char *cp; /* Useful character pointer */
- char magic[SARMAG];
- size_t len, tlen;
-
- arch = fopen(archive, mode);
- if (arch == NULL) {
- return NULL;
- }
-
- /*
- * We use the ARMAG string to make sure this is an archive we
- * can handle...
- */
- if ((fread(magic, SARMAG, 1, arch) != 1) ||
- (strncmp(magic, ARMAG, SARMAG) != 0)) {
- fclose(arch);
- return NULL;
- }
-
- /*
- * Because of space constraints and similar things, files are archived
- * using their final path components, not the entire thing, so we need
- * to point 'member' to the final component, if there is one, to make
- * the comparisons easier...
- */
- cp = strrchr(member, '/');
- if (cp != NULL) {
- member = cp + 1;
- }
- len = tlen = strlen(member);
- if (len > sizeof(arhPtr->ar_name)) {
- tlen = sizeof(arhPtr->ar_name);
- }
-
- while (fread((char *)arhPtr, sizeof(struct ar_hdr), 1, arch) == 1) {
- if (strncmp(arhPtr->ar_fmag, ARFMAG, sizeof(arhPtr->ar_fmag) ) != 0) {
- /*
- * The header is bogus, so the archive is bad
- * and there's no way we can recover...
- */
- fclose(arch);
- return NULL;
- } else if (strncmp(member, arhPtr->ar_name, tlen) == 0) {
- /*
- * If the member's name doesn't take up the entire 'name' field,
- * we have to be careful of matching prefixes. Names are space-
- * padded to the right, so if the character in 'name' at the end
- * of the matched string is anything but a space, this isn't the
- * member we sought.
- */
- if (tlen != sizeof(arhPtr->ar_name) && arhPtr->ar_name[tlen] != ' '){
- goto skip;
- } else {
- /*
- * To make life easier, we reposition the file at the start
- * of the header we just read before we return the stream.
- * In a more general situation, it might be better to leave
- * the file at the actual member, rather than its header, but
- * not here...
- */
- if (fseek(arch, -sizeof(struct ar_hdr), SEEK_CUR) != 0) {
- fclose(arch);
- return NULL;
- }
- return (arch);
- }
- } else
-#ifdef AR_EFMT1
- /*
- * BSD 4.4 extended AR format: #1/<namelen>, with name as the
- * first <namelen> bytes of the file
- */
- if (strncmp(arhPtr->ar_name, AR_EFMT1,
- sizeof(AR_EFMT1) - 1) == 0 &&
- isdigit((unsigned char)arhPtr->ar_name[sizeof(AR_EFMT1) - 1])) {
-
- unsigned int elen = atoi(&arhPtr->ar_name[sizeof(AR_EFMT1)-1]);
- char ename[MAXPATHLEN + 1];
-
- if (elen > MAXPATHLEN) {
- fclose(arch);
- return NULL;
- }
- if (fread(ename, elen, 1, arch) != 1) {
- fclose(arch);
- return NULL;
- }
- ename[elen] = '\0';
- if (DEBUG(ARCH) || DEBUG(MAKE)) {
- fprintf(debug_file, "ArchFind: Extended format entry for %s\n", ename);
- }
- if (strncmp(ename, member, len) == 0) {
- /* Found as extended name */
- if (fseek(arch, -sizeof(struct ar_hdr) - elen,
- SEEK_CUR) != 0) {
- fclose(arch);
- return NULL;
- }
- return (arch);
- }
- if (fseek(arch, -elen, SEEK_CUR) != 0) {
- fclose(arch);
- return NULL;
- }
- goto skip;
- } else
-#endif
- {
-skip:
- /*
- * This isn't the member we're after, so we need to advance the
- * stream's pointer to the start of the next header. Files are
- * padded with newlines to an even-byte boundary, so we need to
- * extract the size of the file from the 'size' field of the
- * header and round it up during the seek.
- */
- arhPtr->ar_size[sizeof(arhPtr->ar_size)-1] = '\0';
- size = (int)strtol(arhPtr->ar_size, NULL, 10);
- if (fseek(arch, (size + 1) & ~1, SEEK_CUR) != 0) {
- fclose(arch);
- return NULL;
- }
- }
- }
-
- /*
- * We've looked everywhere, but the member is not to be found. Close the
- * archive and return NULL -- an error.
- */
- fclose(arch);
- return NULL;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Arch_Touch --
- * Touch a member of an archive.
- *
- * Input:
- * gn Node of member to touch
- *
- * Results:
- * The 'time' field of the member's header is updated.
- *
- * Side Effects:
- * The modification time of the entire archive is also changed.
- * For a library, this could necessitate the re-ranlib'ing of the
- * whole thing.
- *
- *-----------------------------------------------------------------------
- */
-void
-Arch_Touch(GNode *gn)
-{
- FILE * arch; /* Stream open to archive, positioned properly */
- struct ar_hdr arh; /* Current header describing member */
- char *p1, *p2;
-
- arch = ArchFindMember(Var_Value(ARCHIVE, gn, &p1),
- Var_Value(MEMBER, gn, &p2),
- &arh, "r+");
-
- free(p1);
- free(p2);
-
- snprintf(arh.ar_date, sizeof(arh.ar_date), "%-12ld", (long) now);
-
- if (arch != NULL) {
- (void)fwrite((char *)&arh, sizeof(struct ar_hdr), 1, arch);
- fclose(arch);
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Arch_TouchLib --
- * Given a node which represents a library, touch the thing, making
- * sure that the table of contents also is touched.
- *
- * Input:
- * gn The node of the library to touch
- *
- * Results:
- * None.
- *
- * Side Effects:
- * Both the modification time of the library and of the RANLIBMAG
- * member are set to 'now'.
- *
- *-----------------------------------------------------------------------
- */
-void
-#if !defined(RANLIBMAG)
-Arch_TouchLib(GNode *gn MAKE_ATTR_UNUSED)
-#else
-Arch_TouchLib(GNode *gn)
-#endif
-{
-#ifdef RANLIBMAG
- FILE * arch; /* Stream open to archive */
- struct ar_hdr arh; /* Header describing table of contents */
- struct utimbuf times; /* Times for utime() call */
-
- arch = ArchFindMember(gn->path, UNCONST(RANLIBMAG), &arh, "r+");
- snprintf(arh.ar_date, sizeof(arh.ar_date), "%-12ld", (long) now);
-
- if (arch != NULL) {
- (void)fwrite((char *)&arh, sizeof(struct ar_hdr), 1, arch);
- fclose(arch);
-
- times.actime = times.modtime = now;
- utime(gn->path, &times);
- }
-#endif
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Arch_MTime --
- * Return the modification time of a member of an archive.
- *
- * Input:
- * gn Node describing archive member
- *
- * Results:
- * The modification time(seconds).
- *
- * Side Effects:
- * The mtime field of the given node is filled in with the value
- * returned by the function.
- *
- *-----------------------------------------------------------------------
- */
-time_t
-Arch_MTime(GNode *gn)
-{
- struct ar_hdr *arhPtr; /* Header of desired member */
- time_t modTime; /* Modification time as an integer */
- char *p1, *p2;
-
- arhPtr = ArchStatMember(Var_Value(ARCHIVE, gn, &p1),
- Var_Value(MEMBER, gn, &p2),
- TRUE);
-
- free(p1);
- free(p2);
-
- if (arhPtr != NULL) {
- modTime = (time_t)strtol(arhPtr->ar_date, NULL, 10);
- } else {
- modTime = 0;
- }
-
- gn->mtime = modTime;
- return (modTime);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Arch_MemMTime --
- * Given a non-existent archive member's node, get its modification
- * time from its archived form, if it exists.
- *
- * Results:
- * The modification time.
- *
- * Side Effects:
- * The mtime field is filled in.
- *
- *-----------------------------------------------------------------------
- */
-time_t
-Arch_MemMTime(GNode *gn)
-{
- LstNode ln;
- GNode *pgn;
- char *nameStart,
- *nameEnd;
-
- if (Lst_Open(gn->parents) != SUCCESS) {
- gn->mtime = 0;
- return (0);
- }
- while ((ln = Lst_Next(gn->parents)) != NULL) {
- pgn = (GNode *)Lst_Datum(ln);
-
- if (pgn->type & OP_ARCHV) {
- /*
- * If the parent is an archive specification and is being made
- * and its member's name matches the name of the node we were
- * given, record the modification time of the parent in the
- * child. We keep searching its parents in case some other
- * parent requires this child to exist...
- */
- nameStart = strchr(pgn->name, '(') + 1;
- nameEnd = strchr(nameStart, ')');
-
- if ((pgn->flags & REMAKE) &&
- strncmp(nameStart, gn->name, nameEnd - nameStart) == 0) {
- gn->mtime = Arch_MTime(pgn);
- }
- } else if (pgn->flags & REMAKE) {
- /*
- * Something which isn't a library depends on the existence of
- * this target, so it needs to exist.
- */
- gn->mtime = 0;
- break;
- }
- }
-
- Lst_Close(gn->parents);
-
- return (gn->mtime);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Arch_FindLib --
- * Search for a library along the given search path.
- *
- * Input:
- * gn Node of library to find
- * path Search path
- *
- * Results:
- * None.
- *
- * Side Effects:
- * The node's 'path' field is set to the found path (including the
- * actual file name, not -l...). If the system can handle the -L
- * flag when linking (or we cannot find the library), we assume that
- * the user has placed the .LIBRARIES variable in the final linking
- * command (or the linker will know where to find it) and set the
- * TARGET variable for this node to be the node's name. Otherwise,
- * we set the TARGET variable to be the full path of the library,
- * as returned by Dir_FindFile.
- *
- *-----------------------------------------------------------------------
- */
-void
-Arch_FindLib(GNode *gn, Lst path)
-{
- char *libName; /* file name for archive */
- size_t sz = strlen(gn->name) + 6 - 2;
-
- libName = bmake_malloc(sz);
- snprintf(libName, sz, "lib%s.a", &gn->name[2]);
-
- gn->path = Dir_FindFile(libName, path);
-
- free(libName);
-
-#ifdef LIBRARIES
- Var_Set(TARGET, gn->name, gn, 0);
-#else
- Var_Set(TARGET, gn->path == NULL ? gn->name : gn->path, gn, 0);
-#endif /* LIBRARIES */
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Arch_LibOODate --
- * Decide if a node with the OP_LIB attribute is out-of-date. Called
- * from Make_OODate to make its life easier.
- *
- * There are several ways for a library to be out-of-date that are
- * not available to ordinary files. In addition, there are ways
- * that are open to regular files that are not available to
- * libraries. A library that is only used as a source is never
- * considered out-of-date by itself. This does not preclude the
- * library's modification time from making its parent be out-of-date.
- * A library will be considered out-of-date for any of these reasons,
- * given that it is a target on a dependency line somewhere:
- * Its modification time is less than that of one of its
- * sources (gn->mtime < gn->cmgn->mtime).
- * Its modification time is greater than the time at which the
- * make began (i.e. it's been modified in the course
- * of the make, probably by archiving).
- * The modification time of one of its sources is greater than
- * the one of its RANLIBMAG member (i.e. its table of contents
- * is out-of-date). We don't compare of the archive time
- * vs. TOC time because they can be too close. In my
- * opinion we should not bother with the TOC at all since
- * this is used by 'ar' rules that affect the data contents
- * of the archive, not by ranlib rules, which affect the
- * TOC.
- *
- * Input:
- * gn The library's graph node
- *
- * Results:
- * TRUE if the library is out-of-date. FALSE otherwise.
- *
- * Side Effects:
- * The library will be hashed if it hasn't been already.
- *
- *-----------------------------------------------------------------------
- */
-Boolean
-Arch_LibOODate(GNode *gn)
-{
- Boolean oodate;
-
- if (gn->type & OP_PHONY) {
- oodate = TRUE;
- } else if (OP_NOP(gn->type) && Lst_IsEmpty(gn->children)) {
- oodate = FALSE;
- } else if ((!Lst_IsEmpty(gn->children) && gn->cmgn == NULL) ||
- (gn->mtime > now) ||
- (gn->cmgn != NULL && gn->mtime < gn->cmgn->mtime)) {
- oodate = TRUE;
- } else {
-#ifdef RANLIBMAG
- struct ar_hdr *arhPtr; /* Header for __.SYMDEF */
- int modTimeTOC; /* The table-of-contents's mod time */
-
- arhPtr = ArchStatMember(gn->path, UNCONST(RANLIBMAG), FALSE);
-
- if (arhPtr != NULL) {
- modTimeTOC = (int)strtol(arhPtr->ar_date, NULL, 10);
-
- if (DEBUG(ARCH) || DEBUG(MAKE)) {
- fprintf(debug_file, "%s modified %s...", RANLIBMAG, Targ_FmtTime(modTimeTOC));
- }
- oodate = (gn->cmgn == NULL || gn->cmgn->mtime > modTimeTOC);
- } else {
- /*
- * A library w/o a table of contents is out-of-date
- */
- if (DEBUG(ARCH) || DEBUG(MAKE)) {
- fprintf(debug_file, "No t.o.c....");
- }
- oodate = TRUE;
- }
-#else
- oodate = FALSE;
-#endif
- }
- return (oodate);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Arch_Init --
- * Initialize things for this module.
- *
- * Results:
- * None.
- *
- * Side Effects:
- * The 'archives' list is initialized.
- *
- *-----------------------------------------------------------------------
- */
-void
-Arch_Init(void)
-{
- archives = Lst_Init(FALSE);
-}
-
-
-
-/*-
- *-----------------------------------------------------------------------
- * Arch_End --
- * Cleanup things for this module.
- *
- * Results:
- * None.
- *
- * Side Effects:
- * The 'archives' list is freed
- *
- *-----------------------------------------------------------------------
- */
-void
-Arch_End(void)
-{
-#ifdef CLEANUP
- Lst_Destroy(archives, ArchFree);
-#endif
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Arch_IsLib --
- * Check if the node is a library
- *
- * Results:
- * True or False.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-int
-Arch_IsLib(GNode *gn)
-{
- static const char armag[] = "!<arch>\n";
- char buf[sizeof(armag)-1];
- int fd;
-
- if ((fd = open(gn->path, O_RDONLY)) == -1)
- return FALSE;
-
- if (read(fd, buf, sizeof(buf)) != sizeof(buf)) {
- (void)close(fd);
- return FALSE;
- }
-
- (void)close(fd);
-
- return memcmp(buf, armag, sizeof(buf)) == 0;
-}
diff --git a/usr.bin/make/buf.c b/usr.bin/make/buf.c
deleted file mode 100644
index ac95c16..0000000
--- a/usr.bin/make/buf.c
+++ /dev/null
@@ -1,291 +0,0 @@
-/* $NetBSD: buf.c,v 1.25 2012/04/24 20:26:58 sjg Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-/*
- * Copyright (c) 1988, 1989 by Adam de Boor
- * Copyright (c) 1989 by Berkeley Softworks
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: buf.c,v 1.25 2012/04/24 20:26:58 sjg Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)buf.c 8.1 (Berkeley) 6/6/93";
-#else
-__RCSID("$NetBSD: buf.c,v 1.25 2012/04/24 20:26:58 sjg Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * buf.c --
- * Functions for automatically-expanded buffers.
- */
-
-#include "make.h"
-#include "buf.h"
-
-#ifndef max
-#define max(a,b) ((a) > (b) ? (a) : (b))
-#endif
-
-#define BUF_DEF_SIZE 256 /* Default buffer size */
-
-/*-
- *-----------------------------------------------------------------------
- * Buf_Expand_1 --
- * Extend buffer for single byte add.
- *
- *-----------------------------------------------------------------------
- */
-void
-Buf_Expand_1(Buffer *bp)
-{
- bp->size += max(bp->size, 16);
- bp->buffer = bmake_realloc(bp->buffer, bp->size);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Buf_AddBytes --
- * Add a number of bytes to the buffer.
- *
- * Results:
- * None.
- *
- * Side Effects:
- * Guess what?
- *
- *-----------------------------------------------------------------------
- */
-void
-Buf_AddBytes(Buffer *bp, int numBytes, const Byte *bytesPtr)
-{
- int count = bp->count;
- Byte *ptr;
-
- if (__predict_false(count + numBytes >= bp->size)) {
- bp->size += max(bp->size, numBytes + 16);
- bp->buffer = bmake_realloc(bp->buffer, bp->size);
- }
-
- ptr = bp->buffer + count;
- bp->count = count + numBytes;
- ptr[numBytes] = 0;
- memcpy(ptr, bytesPtr, numBytes);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Buf_GetAll --
- * Get all the available data at once.
- *
- * Results:
- * A pointer to the data and the number of bytes available.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-Byte *
-Buf_GetAll(Buffer *bp, int *numBytesPtr)
-{
-
- if (numBytesPtr != NULL)
- *numBytesPtr = bp->count;
-
- return (bp->buffer);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Buf_Empty --
- * Throw away bytes in a buffer.
- *
- * Results:
- * None.
- *
- * Side Effects:
- * The bytes are discarded.
- *
- *-----------------------------------------------------------------------
- */
-void
-Buf_Empty(Buffer *bp)
-{
-
- bp->count = 0;
- *bp->buffer = 0;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Buf_Init --
- * Initialize a buffer. If no initial size is given, a reasonable
- * default is used.
- *
- * Input:
- * size Initial size for the buffer
- *
- * Results:
- * A buffer to be given to other functions in this library.
- *
- * Side Effects:
- * The buffer is created, the space allocated and pointers
- * initialized.
- *
- *-----------------------------------------------------------------------
- */
-void
-Buf_Init(Buffer *bp, int size)
-{
- if (size <= 0) {
- size = BUF_DEF_SIZE;
- }
- bp->size = size;
- bp->count = 0;
- bp->buffer = bmake_malloc(size);
- *bp->buffer = 0;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Buf_Destroy --
- * Nuke a buffer and all its resources.
- *
- * Input:
- * buf Buffer to destroy
- * freeData TRUE if the data should be destroyed
- *
- * Results:
- * Data buffer, NULL if freed
- *
- * Side Effects:
- * The buffer is freed.
- *
- *-----------------------------------------------------------------------
- */
-Byte *
-Buf_Destroy(Buffer *buf, Boolean freeData)
-{
- Byte *data;
-
- data = buf->buffer;
- if (freeData) {
- free(data);
- data = NULL;
- }
-
- buf->size = 0;
- buf->count = 0;
- buf->buffer = NULL;
-
- return data;
-}
-
-
-/*-
- *-----------------------------------------------------------------------
- * Buf_DestroyCompact --
- * Nuke a buffer and return its data.
- *
- * Input:
- * buf Buffer to destroy
- *
- * Results:
- * Data buffer
- *
- * Side Effects:
- * If the buffer size is much greater than its content,
- * a new buffer will be allocated and the old one freed.
- *
- *-----------------------------------------------------------------------
- */
-#ifndef BUF_COMPACT_LIMIT
-# define BUF_COMPACT_LIMIT 128 /* worthwhile saving */
-#endif
-
-Byte *
-Buf_DestroyCompact(Buffer *buf)
-{
-#if BUF_COMPACT_LIMIT > 0
- Byte *data;
-
- if (buf->size - buf->count >= BUF_COMPACT_LIMIT) {
- /* We trust realloc to be smart */
- data = bmake_realloc(buf->buffer, buf->count + 1);
- if (data) {
- data[buf->count] = 0;
- Buf_Destroy(buf, FALSE);
- return data;
- }
- }
-#endif
- return Buf_Destroy(buf, FALSE);
-}
diff --git a/usr.bin/make/buf.h b/usr.bin/make/buf.h
deleted file mode 100644
index 7bd2d2b..0000000
--- a/usr.bin/make/buf.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/* $NetBSD: buf.h,v 1.19 2017/05/31 22:02:06 maya Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- *
- * from: @(#)buf.h 8.1 (Berkeley) 6/6/93
- */
-
-/*
- * Copyright (c) 1988, 1989 by Adam de Boor
- * Copyright (c) 1989 by Berkeley Softworks
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. 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.
- *
- * from: @(#)buf.h 8.1 (Berkeley) 6/6/93
- */
-
-/*-
- * buf.h --
- * Header for users of the buf library.
- */
-
-#ifndef MAKE_BUF_H
-#define MAKE_BUF_H
-
-typedef char Byte;
-
-typedef struct Buffer {
- int size; /* Current size of the buffer */
- int count; /* Number of bytes in buffer */
- Byte *buffer; /* The buffer itself (zero terminated) */
-} Buffer;
-
-/* If we aren't on netbsd, __predict_false() might not be defined. */
-#ifndef __predict_false
-#define __predict_false(x) (x)
-#endif
-
-/* Buf_AddByte adds a single byte to a buffer. */
-#define Buf_AddByte(bp, byte) do { \
- int _count = ++(bp)->count; \
- char *_ptr; \
- if (__predict_false(_count >= (bp)->size)) \
- Buf_Expand_1(bp); \
- _ptr = (bp)->buffer + _count; \
- _ptr[-1] = (byte); \
- _ptr[0] = 0; \
- } while (0)
-
-#define BUF_ERROR 256
-
-#define Buf_Size(bp) ((bp)->count)
-
-void Buf_Expand_1(Buffer *);
-void Buf_AddBytes(Buffer *, int, const Byte *);
-Byte *Buf_GetAll(Buffer *, int *);
-void Buf_Empty(Buffer *);
-void Buf_Init(Buffer *, int);
-Byte *Buf_Destroy(Buffer *, Boolean);
-Byte *Buf_DestroyCompact(Buffer *);
-
-#endif /* MAKE_BUF_H */
diff --git a/usr.bin/make/compat.c b/usr.bin/make/compat.c
deleted file mode 100644
index 538c456..0000000
--- a/usr.bin/make/compat.c
+++ /dev/null
@@ -1,778 +0,0 @@
-/* $NetBSD: compat.c,v 1.107 2017/07/20 19:29:54 sjg Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-/*
- * Copyright (c) 1988, 1989 by Adam de Boor
- * Copyright (c) 1989 by Berkeley Softworks
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: compat.c,v 1.107 2017/07/20 19:29:54 sjg Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)compat.c 8.2 (Berkeley) 3/19/94";
-#else
-__RCSID("$NetBSD: compat.c,v 1.107 2017/07/20 19:29:54 sjg Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * compat.c --
- * The routines in this file implement the full-compatibility
- * mode of PMake. Most of the special functionality of PMake
- * is available in this mode. Things not supported:
- * - different shells.
- * - friendly variable substitution.
- *
- * Interface:
- * Compat_Run Initialize things for this module and recreate
- * thems as need creatin'
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-
-#include <ctype.h>
-#include <errno.h>
-#include <signal.h>
-#include <stdio.h>
-
-#include "make.h"
-#include "hash.h"
-#include "dir.h"
-#include "job.h"
-#include "metachar.h"
-#include "pathnames.h"
-
-
-static GNode *curTarg = NULL;
-static GNode *ENDNode;
-static void CompatInterrupt(int);
-static pid_t compatChild;
-static int compatSigno;
-
-/*
- * CompatDeleteTarget -- delete a failed, interrupted, or otherwise
- * duffed target if not inhibited by .PRECIOUS.
- */
-static void
-CompatDeleteTarget(GNode *gn)
-{
- if ((gn != NULL) && !Targ_Precious (gn)) {
- char *p1;
- char *file = Var_Value(TARGET, gn, &p1);
-
- if (!noExecute && eunlink(file) != -1) {
- Error("*** %s removed", file);
- }
-
- free(p1);
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * CompatInterrupt --
- * Interrupt the creation of the current target and remove it if
- * it ain't precious.
- *
- * Results:
- * None.
- *
- * Side Effects:
- * The target is removed and the process exits. If .INTERRUPT exists,
- * its commands are run first WITH INTERRUPTS IGNORED..
- *
- * XXX: is .PRECIOUS supposed to inhibit .INTERRUPT? I doubt it, but I've
- * left the logic alone for now. - dholland 20160826
- *
- *-----------------------------------------------------------------------
- */
-static void
-CompatInterrupt(int signo)
-{
- GNode *gn;
-
- CompatDeleteTarget(curTarg);
-
- if ((curTarg != NULL) && !Targ_Precious (curTarg)) {
- /*
- * Run .INTERRUPT only if hit with interrupt signal
- */
- if (signo == SIGINT) {
- gn = Targ_FindNode(".INTERRUPT", TARG_NOCREATE);
- if (gn != NULL) {
- Compat_Make(gn, gn);
- }
- }
- }
- if (signo == SIGQUIT)
- _exit(signo);
- /*
- * If there is a child running, pass the signal on
- * we will exist after it has exited.
- */
- compatSigno = signo;
- if (compatChild > 0) {
- KILLPG(compatChild, signo);
- } else {
- bmake_signal(signo, SIG_DFL);
- kill(myPid, signo);
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * CompatRunCommand --
- * Execute the next command for a target. If the command returns an
- * error, the node's made field is set to ERROR and creation stops.
- *
- * Input:
- * cmdp Command to execute
- * gnp Node from which the command came
- *
- * Results:
- * 0 if the command succeeded, 1 if an error occurred.
- *
- * Side Effects:
- * The node's 'made' field may be set to ERROR.
- *
- *-----------------------------------------------------------------------
- */
-int
-CompatRunCommand(void *cmdp, void *gnp)
-{
- char *cmdStart; /* Start of expanded command */
- char *cp, *bp;
- Boolean silent, /* Don't print command */
- doIt; /* Execute even if -n */
- volatile Boolean errCheck; /* Check errors */
- int reason; /* Reason for child's death */
- int status; /* Description of child's death */
- pid_t cpid; /* Child actually found */
- pid_t retstat; /* Result of wait */
- LstNode cmdNode; /* Node where current command is located */
- const char ** volatile av; /* Argument vector for thing to exec */
- char ** volatile mav;/* Copy of the argument vector for freeing */
- int argc; /* Number of arguments in av or 0 if not
- * dynamically allocated */
- Boolean local; /* TRUE if command should be executed
- * locally */
- Boolean useShell; /* TRUE if command should be executed
- * using a shell */
- char * volatile cmd = (char *)cmdp;
- GNode *gn = (GNode *)gnp;
-
- silent = gn->type & OP_SILENT;
- errCheck = !(gn->type & OP_IGNORE);
- doIt = FALSE;
-
- cmdNode = Lst_Member(gn->commands, cmd);
- cmdStart = Var_Subst(NULL, cmd, gn, VARF_WANTRES);
-
- /*
- * brk_string will return an argv with a NULL in av[0], thus causing
- * execvp to choke and die horribly. Besides, how can we execute a null
- * command? In any case, we warn the user that the command expanded to
- * nothing (is this the right thing to do?).
- */
-
- if (*cmdStart == '\0') {
- free(cmdStart);
- return(0);
- }
- cmd = cmdStart;
- Lst_Replace(cmdNode, cmdStart);
-
- if ((gn->type & OP_SAVE_CMDS) && (gn != ENDNode)) {
- (void)Lst_AtEnd(ENDNode->commands, cmdStart);
- return(0);
- }
- if (strcmp(cmdStart, "...") == 0) {
- gn->type |= OP_SAVE_CMDS;
- return(0);
- }
-
- while ((*cmd == '@') || (*cmd == '-') || (*cmd == '+')) {
- switch (*cmd) {
- case '@':
- silent = DEBUG(LOUD) ? FALSE : TRUE;
- break;
- case '-':
- errCheck = FALSE;
- break;
- case '+':
- doIt = TRUE;
- if (!shellName) /* we came here from jobs */
- Shell_Init();
- break;
- }
- cmd++;
- }
-
- while (isspace((unsigned char)*cmd))
- cmd++;
-
- /*
- * If we did not end up with a command, just skip it.
- */
- if (!*cmd)
- return (0);
-
-#if !defined(MAKE_NATIVE)
- /*
- * In a non-native build, the host environment might be weird enough
- * that it's necessary to go through a shell to get the correct
- * behaviour. Or perhaps the shell has been replaced with something
- * that does extra logging, and that should not be bypassed.
- */
- useShell = TRUE;
-#else
- /*
- * Search for meta characters in the command. If there are no meta
- * characters, there's no need to execute a shell to execute the
- * command.
- *
- * Additionally variable assignments and empty commands
- * go to the shell. Therefore treat '=' and ':' like shell
- * meta characters as documented in make(1).
- */
-
- useShell = needshell(cmd, FALSE);
-#endif
-
- /*
- * Print the command before echoing if we're not supposed to be quiet for
- * this one. We also print the command if -n given.
- */
- if (!silent || NoExecute(gn)) {
- printf("%s\n", cmd);
- fflush(stdout);
- }
-
- /*
- * If we're not supposed to execute any commands, this is as far as
- * we go...
- */
- if (!doIt && NoExecute(gn)) {
- return (0);
- }
- if (DEBUG(JOB))
- fprintf(debug_file, "Execute: '%s'\n", cmd);
-
-again:
- if (useShell) {
- /*
- * We need to pass the command off to the shell, typically
- * because the command contains a "meta" character.
- */
- static const char *shargv[5];
- int shargc;
-
- shargc = 0;
- shargv[shargc++] = shellPath;
- /*
- * The following work for any of the builtin shell specs.
- */
- if (errCheck && shellErrFlag) {
- shargv[shargc++] = shellErrFlag;
- }
- if (DEBUG(SHELL))
- shargv[shargc++] = "-xc";
- else
- shargv[shargc++] = "-c";
- shargv[shargc++] = cmd;
- shargv[shargc++] = NULL;
- av = shargv;
- argc = 0;
- bp = NULL;
- mav = NULL;
- } else {
- /*
- * No meta-characters, so no need to exec a shell. Break the command
- * into words to form an argument vector we can execute.
- */
- mav = brk_string(cmd, &argc, TRUE, &bp);
- if (mav == NULL) {
- useShell = 1;
- goto again;
- }
- av = (void *)mav;
- }
-
- local = TRUE;
-
-#ifdef USE_META
- if (useMeta) {
- meta_compat_start();
- }
-#endif
-
- /*
- * Fork and execute the single command. If the fork fails, we abort.
- */
- compatChild = cpid = vFork();
- if (cpid < 0) {
- Fatal("Could not fork");
- }
- if (cpid == 0) {
- Var_ExportVars();
-#ifdef USE_META
- if (useMeta) {
- meta_compat_child();
- }
-#endif
- if (local)
- (void)execvp(av[0], (char *const *)UNCONST(av));
- else
- (void)execv(av[0], (char *const *)UNCONST(av));
- execError("exec", av[0]);
- _exit(1);
- }
-
- free(mav);
- free(bp);
-
- Lst_Replace(cmdNode, NULL);
-
-#ifdef USE_META
- if (useMeta) {
- meta_compat_parent();
- }
-#endif
-
- /*
- * The child is off and running. Now all we can do is wait...
- */
- while (1) {
-
- while ((retstat = wait(&reason)) != cpid) {
- if (retstat > 0)
- JobReapChild(retstat, reason, FALSE); /* not ours? */
- if (retstat == -1 && errno != EINTR) {
- break;
- }
- }
-
- if (retstat > -1) {
- if (WIFSTOPPED(reason)) {
- status = WSTOPSIG(reason); /* stopped */
- } else if (WIFEXITED(reason)) {
- status = WEXITSTATUS(reason); /* exited */
-#if defined(USE_META) && defined(USE_FILEMON_ONCE)
- if (useMeta) {
- meta_cmd_finish(NULL);
- }
-#endif
- if (status != 0) {
- if (DEBUG(ERROR)) {
- fprintf(debug_file, "\n*** Failed target: %s\n*** Failed command: ",
- gn->name);
- for (cp = cmd; *cp; ) {
- if (isspace((unsigned char)*cp)) {
- fprintf(debug_file, " ");
- while (isspace((unsigned char)*cp))
- cp++;
- } else {
- fprintf(debug_file, "%c", *cp);
- cp++;
- }
- }
- fprintf(debug_file, "\n");
- }
- printf("*** Error code %d", status);
- }
- } else {
- status = WTERMSIG(reason); /* signaled */
- printf("*** Signal %d", status);
- }
-
-
- if (!WIFEXITED(reason) || (status != 0)) {
- if (errCheck) {
-#ifdef USE_META
- if (useMeta) {
- meta_job_error(NULL, gn, 0, status);
- }
-#endif
- gn->made = ERROR;
- if (keepgoing) {
- /*
- * Abort the current target, but let others
- * continue.
- */
- printf(" (continuing)\n");
- } else {
- printf("\n");
- }
- if (deleteOnError) {
- CompatDeleteTarget(gn);
- }
- } else {
- /*
- * Continue executing commands for this target.
- * If we return 0, this will happen...
- */
- printf(" (ignored)\n");
- status = 0;
- }
- }
- break;
- } else {
- Fatal("error in wait: %d: %s", retstat, strerror(errno));
- /*NOTREACHED*/
- }
- }
- free(cmdStart);
- compatChild = 0;
- if (compatSigno) {
- bmake_signal(compatSigno, SIG_DFL);
- kill(myPid, compatSigno);
- }
-
- return (status);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Compat_Make --
- * Make a target.
- *
- * Input:
- * gnp The node to make
- * pgnp Parent to abort if necessary
- *
- * Results:
- * 0
- *
- * Side Effects:
- * If an error is detected and not being ignored, the process exits.
- *
- *-----------------------------------------------------------------------
- */
-int
-Compat_Make(void *gnp, void *pgnp)
-{
- GNode *gn = (GNode *)gnp;
- GNode *pgn = (GNode *)pgnp;
-
- if (!shellName) /* we came here from jobs */
- Shell_Init();
- if (gn->made == UNMADE && (gn == pgn || (pgn->type & OP_MADE) == 0)) {
- /*
- * First mark ourselves to be made, then apply whatever transformations
- * the suffix module thinks are necessary. Once that's done, we can
- * descend and make all our children. If any of them has an error
- * but the -k flag was given, our 'make' field will be set FALSE again.
- * This is our signal to not attempt to do anything but abort our
- * parent as well.
- */
- gn->flags |= REMAKE;
- gn->made = BEINGMADE;
- if ((gn->type & OP_MADE) == 0)
- Suff_FindDeps(gn);
- Lst_ForEach(gn->children, Compat_Make, gn);
- if ((gn->flags & REMAKE) == 0) {
- gn->made = ABORTED;
- pgn->flags &= ~REMAKE;
- goto cohorts;
- }
-
- if (Lst_Member(gn->iParents, pgn) != NULL) {
- char *p1;
- Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), pgn, 0);
- free(p1);
- }
-
- /*
- * All the children were made ok. Now cmgn->mtime contains the
- * modification time of the newest child, we need to find out if we
- * exist and when we were modified last. The criteria for datedness
- * are defined by the Make_OODate function.
- */
- if (DEBUG(MAKE)) {
- fprintf(debug_file, "Examining %s...", gn->name);
- }
- if (! Make_OODate(gn)) {
- gn->made = UPTODATE;
- if (DEBUG(MAKE)) {
- fprintf(debug_file, "up-to-date.\n");
- }
- goto cohorts;
- } else if (DEBUG(MAKE)) {
- fprintf(debug_file, "out-of-date.\n");
- }
-
- /*
- * If the user is just seeing if something is out-of-date, exit now
- * to tell him/her "yes".
- */
- if (queryFlag) {
- exit(1);
- }
-
- /*
- * We need to be re-made. We also have to make sure we've got a $?
- * variable. To be nice, we also define the $> variable using
- * Make_DoAllVar().
- */
- Make_DoAllVar(gn);
-
- /*
- * Alter our type to tell if errors should be ignored or things
- * should not be printed so CompatRunCommand knows what to do.
- */
- if (Targ_Ignore(gn)) {
- gn->type |= OP_IGNORE;
- }
- if (Targ_Silent(gn)) {
- gn->type |= OP_SILENT;
- }
-
- if (Job_CheckCommands(gn, Fatal)) {
- /*
- * Our commands are ok, but we still have to worry about the -t
- * flag...
- */
- if (!touchFlag || (gn->type & OP_MAKE)) {
- curTarg = gn;
-#ifdef USE_META
- if (useMeta && !NoExecute(gn)) {
- meta_job_start(NULL, gn);
- }
-#endif
- Lst_ForEach(gn->commands, CompatRunCommand, gn);
- curTarg = NULL;
- } else {
- Job_Touch(gn, gn->type & OP_SILENT);
- }
- } else {
- gn->made = ERROR;
- }
-#ifdef USE_META
- if (useMeta && !NoExecute(gn)) {
- if (meta_job_finish(NULL) != 0)
- gn->made = ERROR;
- }
-#endif
-
- if (gn->made != ERROR) {
- /*
- * If the node was made successfully, mark it so, update
- * its modification time and timestamp all its parents. Note
- * that for .ZEROTIME targets, the timestamping isn't done.
- * This is to keep its state from affecting that of its parent.
- */
- gn->made = MADE;
- pgn->flags |= Make_Recheck(gn) == 0 ? FORCE : 0;
- if (!(gn->type & OP_EXEC)) {
- pgn->flags |= CHILDMADE;
- Make_TimeStamp(pgn, gn);
- }
- } else if (keepgoing) {
- pgn->flags &= ~REMAKE;
- } else {
- PrintOnError(gn, "\nStop.");
- exit(1);
- }
- } else if (gn->made == ERROR) {
- /*
- * Already had an error when making this beastie. Tell the parent
- * to abort.
- */
- pgn->flags &= ~REMAKE;
- } else {
- if (Lst_Member(gn->iParents, pgn) != NULL) {
- char *p1;
- Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), pgn, 0);
- free(p1);
- }
- switch(gn->made) {
- case BEINGMADE:
- Error("Graph cycles through %s", gn->name);
- gn->made = ERROR;
- pgn->flags &= ~REMAKE;
- break;
- case MADE:
- if ((gn->type & OP_EXEC) == 0) {
- pgn->flags |= CHILDMADE;
- Make_TimeStamp(pgn, gn);
- }
- break;
- case UPTODATE:
- if ((gn->type & OP_EXEC) == 0) {
- Make_TimeStamp(pgn, gn);
- }
- break;
- default:
- break;
- }
- }
-
-cohorts:
- Lst_ForEach(gn->cohorts, Compat_Make, pgnp);
- return (0);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Compat_Run --
- * Initialize this mode and start making.
- *
- * Input:
- * targs List of target nodes to re-create
- *
- * Results:
- * None.
- *
- * Side Effects:
- * Guess what?
- *
- *-----------------------------------------------------------------------
- */
-void
-Compat_Run(Lst targs)
-{
- GNode *gn = NULL;/* Current root target */
- int errors; /* Number of targets not remade due to errors */
-
- if (!shellName)
- Shell_Init();
-
- if (bmake_signal(SIGINT, SIG_IGN) != SIG_IGN) {
- bmake_signal(SIGINT, CompatInterrupt);
- }
- if (bmake_signal(SIGTERM, SIG_IGN) != SIG_IGN) {
- bmake_signal(SIGTERM, CompatInterrupt);
- }
- if (bmake_signal(SIGHUP, SIG_IGN) != SIG_IGN) {
- bmake_signal(SIGHUP, CompatInterrupt);
- }
- if (bmake_signal(SIGQUIT, SIG_IGN) != SIG_IGN) {
- bmake_signal(SIGQUIT, CompatInterrupt);
- }
-
- ENDNode = Targ_FindNode(".END", TARG_CREATE);
- ENDNode->type = OP_SPECIAL;
- /*
- * If the user has defined a .BEGIN target, execute the commands attached
- * to it.
- */
- if (!queryFlag) {
- gn = Targ_FindNode(".BEGIN", TARG_NOCREATE);
- if (gn != NULL) {
- Compat_Make(gn, gn);
- if (gn->made == ERROR) {
- PrintOnError(gn, "\nStop.");
- exit(1);
- }
- }
- }
-
- /*
- * Expand .USE nodes right now, because they can modify the structure
- * of the tree.
- */
- Make_ExpandUse(targs);
-
- /*
- * For each entry in the list of targets to create, call Compat_Make on
- * it to create the thing. Compat_Make will leave the 'made' field of gn
- * in one of several states:
- * UPTODATE gn was already up-to-date
- * MADE gn was recreated successfully
- * ERROR An error occurred while gn was being created
- * ABORTED gn was not remade because one of its inferiors
- * could not be made due to errors.
- */
- errors = 0;
- while (!Lst_IsEmpty (targs)) {
- gn = (GNode *)Lst_DeQueue(targs);
- Compat_Make(gn, gn);
-
- if (gn->made == UPTODATE) {
- printf("`%s' is up to date.\n", gn->name);
- } else if (gn->made == ABORTED) {
- printf("`%s' not remade because of errors.\n", gn->name);
- errors += 1;
- }
- }
-
- /*
- * If the user has defined a .END target, run its commands.
- */
- if (errors == 0) {
- Compat_Make(ENDNode, ENDNode);
- if (gn->made == ERROR) {
- PrintOnError(gn, "\nStop.");
- exit(1);
- }
- }
-}
diff --git a/usr.bin/make/cond.c b/usr.bin/make/cond.c
deleted file mode 100644
index 7c9c96a..0000000
--- a/usr.bin/make/cond.c
+++ /dev/null
@@ -1,1436 +0,0 @@
-/* $NetBSD: cond.c,v 1.75 2017/04/16 20:59:04 riastradh Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-/*
- * Copyright (c) 1988, 1989 by Adam de Boor
- * Copyright (c) 1989 by Berkeley Softworks
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: cond.c,v 1.75 2017/04/16 20:59:04 riastradh Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)cond.c 8.2 (Berkeley) 1/2/94";
-#else
-__RCSID("$NetBSD: cond.c,v 1.75 2017/04/16 20:59:04 riastradh Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * cond.c --
- * Functions to handle conditionals in a makefile.
- *
- * Interface:
- * Cond_Eval Evaluate the conditional in the passed line.
- *
- */
-
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h> /* For strtoul() error checking */
-
-#include "make.h"
-#include "hash.h"
-#include "dir.h"
-#include "buf.h"
-
-/*
- * The parsing of conditional expressions is based on this grammar:
- * E -> F || E
- * E -> F
- * F -> T && F
- * F -> T
- * T -> defined(variable)
- * T -> make(target)
- * T -> exists(file)
- * T -> empty(varspec)
- * T -> target(name)
- * T -> commands(name)
- * T -> symbol
- * T -> $(varspec) op value
- * T -> $(varspec) == "string"
- * T -> $(varspec) != "string"
- * T -> "string"
- * T -> ( E )
- * T -> ! T
- * op -> == | != | > | < | >= | <=
- *
- * 'symbol' is some other symbol to which the default function (condDefProc)
- * is applied.
- *
- * Tokens are scanned from the 'condExpr' string. The scanner (CondToken)
- * will return TOK_AND for '&' and '&&', TOK_OR for '|' and '||',
- * TOK_NOT for '!', TOK_LPAREN for '(', TOK_RPAREN for ')' and will evaluate
- * the other terminal symbols, using either the default function or the
- * function given in the terminal, and return the result as either TOK_TRUE
- * or TOK_FALSE.
- *
- * TOK_FALSE is 0 and TOK_TRUE 1 so we can directly assign C comparisons.
- *
- * All Non-Terminal functions (CondE, CondF and CondT) return TOK_ERROR on
- * error.
- */
-typedef enum {
- TOK_FALSE = 0, TOK_TRUE = 1, TOK_AND, TOK_OR, TOK_NOT,
- TOK_LPAREN, TOK_RPAREN, TOK_EOF, TOK_NONE, TOK_ERROR
-} Token;
-
-/*-
- * Structures to handle elegantly the different forms of #if's. The
- * last two fields are stored in condInvert and condDefProc, respectively.
- */
-static void CondPushBack(Token);
-static int CondGetArg(char **, char **, const char *);
-static Boolean CondDoDefined(int, const char *);
-static int CondStrMatch(const void *, const void *);
-static Boolean CondDoMake(int, const char *);
-static Boolean CondDoExists(int, const char *);
-static Boolean CondDoTarget(int, const char *);
-static Boolean CondDoCommands(int, const char *);
-static Boolean CondCvtArg(char *, double *);
-static Token CondToken(Boolean);
-static Token CondT(Boolean);
-static Token CondF(Boolean);
-static Token CondE(Boolean);
-static int do_Cond_EvalExpression(Boolean *);
-
-static const struct If {
- const char *form; /* Form of if */
- int formlen; /* Length of form */
- Boolean doNot; /* TRUE if default function should be negated */
- Boolean (*defProc)(int, const char *); /* Default function to apply */
-} ifs[] = {
- { "def", 3, FALSE, CondDoDefined },
- { "ndef", 4, TRUE, CondDoDefined },
- { "make", 4, FALSE, CondDoMake },
- { "nmake", 5, TRUE, CondDoMake },
- { "", 0, FALSE, CondDoDefined },
- { NULL, 0, FALSE, NULL }
-};
-
-static const struct If *if_info; /* Info for current statement */
-static char *condExpr; /* The expression to parse */
-static Token condPushBack=TOK_NONE; /* Single push-back token used in
- * parsing */
-
-static unsigned int cond_depth = 0; /* current .if nesting level */
-static unsigned int cond_min_depth = 0; /* depth at makefile open */
-
-/*
- * Indicate when we should be strict about lhs of comparisons.
- * TRUE when Cond_EvalExpression is called from Cond_Eval (.if etc)
- * FALSE when Cond_EvalExpression is called from var.c:ApplyModifiers
- * since lhs is already expanded and we cannot tell if
- * it was a variable reference or not.
- */
-static Boolean lhsStrict;
-
-static int
-istoken(const char *str, const char *tok, size_t len)
-{
- return strncmp(str, tok, len) == 0 && !isalpha((unsigned char)str[len]);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * CondPushBack --
- * Push back the most recent token read. We only need one level of
- * this, so the thing is just stored in 'condPushback'.
- *
- * Input:
- * t Token to push back into the "stream"
- *
- * Results:
- * None.
- *
- * Side Effects:
- * condPushback is overwritten.
- *
- *-----------------------------------------------------------------------
- */
-static void
-CondPushBack(Token t)
-{
- condPushBack = t;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * CondGetArg --
- * Find the argument of a built-in function.
- *
- * Input:
- * parens TRUE if arg should be bounded by parens
- *
- * Results:
- * The length of the argument and the address of the argument.
- *
- * Side Effects:
- * The pointer is set to point to the closing parenthesis of the
- * function call.
- *
- *-----------------------------------------------------------------------
- */
-static int
-CondGetArg(char **linePtr, char **argPtr, const char *func)
-{
- char *cp;
- int argLen;
- Buffer buf;
- int paren_depth;
- char ch;
-
- cp = *linePtr;
- if (func != NULL)
- /* Skip opening '(' - verfied by caller */
- cp++;
-
- if (*cp == '\0') {
- /*
- * No arguments whatsoever. Because 'make' and 'defined' aren't really
- * "reserved words", we don't print a message. I think this is better
- * than hitting the user with a warning message every time s/he uses
- * the word 'make' or 'defined' at the beginning of a symbol...
- */
- *argPtr = NULL;
- return (0);
- }
-
- while (*cp == ' ' || *cp == '\t') {
- cp++;
- }
-
- /*
- * Create a buffer for the argument and start it out at 16 characters
- * long. Why 16? Why not?
- */
- Buf_Init(&buf, 16);
-
- paren_depth = 0;
- for (;;) {
- ch = *cp;
- if (ch == 0 || ch == ' ' || ch == '\t')
- break;
- if ((ch == '&' || ch == '|') && paren_depth == 0)
- break;
- if (*cp == '$') {
- /*
- * Parse the variable spec and install it as part of the argument
- * if it's valid. We tell Var_Parse to complain on an undefined
- * variable, so we don't do it too. Nor do we return an error,
- * though perhaps we should...
- */
- char *cp2;
- int len;
- void *freeIt;
-
- cp2 = Var_Parse(cp, VAR_CMD, VARF_UNDEFERR|VARF_WANTRES,
- &len, &freeIt);
- Buf_AddBytes(&buf, strlen(cp2), cp2);
- free(freeIt);
- cp += len;
- continue;
- }
- if (ch == '(')
- paren_depth++;
- else
- if (ch == ')' && --paren_depth < 0)
- break;
- Buf_AddByte(&buf, *cp);
- cp++;
- }
-
- *argPtr = Buf_GetAll(&buf, &argLen);
- Buf_Destroy(&buf, FALSE);
-
- while (*cp == ' ' || *cp == '\t') {
- cp++;
- }
-
- if (func != NULL && *cp++ != ')') {
- Parse_Error(PARSE_WARNING, "Missing closing parenthesis for %s()",
- func);
- return (0);
- }
-
- *linePtr = cp;
- return (argLen);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * CondDoDefined --
- * Handle the 'defined' function for conditionals.
- *
- * Results:
- * TRUE if the given variable is defined.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-static Boolean
-CondDoDefined(int argLen MAKE_ATTR_UNUSED, const char *arg)
-{
- char *p1;
- Boolean result;
-
- if (Var_Value(arg, VAR_CMD, &p1) != NULL) {
- result = TRUE;
- } else {
- result = FALSE;
- }
-
- free(p1);
- return (result);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * CondStrMatch --
- * Front-end for Str_Match so it returns 0 on match and non-zero
- * on mismatch. Callback function for CondDoMake via Lst_Find
- *
- * Results:
- * 0 if string matches pattern
- *
- * Side Effects:
- * None
- *
- *-----------------------------------------------------------------------
- */
-static int
-CondStrMatch(const void *string, const void *pattern)
-{
- return(!Str_Match(string, pattern));
-}
-
-/*-
- *-----------------------------------------------------------------------
- * CondDoMake --
- * Handle the 'make' function for conditionals.
- *
- * Results:
- * TRUE if the given target is being made.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-static Boolean
-CondDoMake(int argLen MAKE_ATTR_UNUSED, const char *arg)
-{
- return Lst_Find(create, arg, CondStrMatch) != NULL;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * CondDoExists --
- * See if the given file exists.
- *
- * Results:
- * TRUE if the file exists and FALSE if it does not.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-static Boolean
-CondDoExists(int argLen MAKE_ATTR_UNUSED, const char *arg)
-{
- Boolean result;
- char *path;
-
- path = Dir_FindFile(arg, dirSearchPath);
- if (DEBUG(COND)) {
- fprintf(debug_file, "exists(%s) result is \"%s\"\n",
- arg, path ? path : "");
- }
- if (path != NULL) {
- result = TRUE;
- free(path);
- } else {
- result = FALSE;
- }
- return (result);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * CondDoTarget --
- * See if the given node exists and is an actual target.
- *
- * Results:
- * TRUE if the node exists as a target and FALSE if it does not.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-static Boolean
-CondDoTarget(int argLen MAKE_ATTR_UNUSED, const char *arg)
-{
- GNode *gn;
-
- gn = Targ_FindNode(arg, TARG_NOCREATE);
- return (gn != NULL) && !OP_NOP(gn->type);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * CondDoCommands --
- * See if the given node exists and is an actual target with commands
- * associated with it.
- *
- * Results:
- * TRUE if the node exists as a target and has commands associated with
- * it and FALSE if it does not.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-static Boolean
-CondDoCommands(int argLen MAKE_ATTR_UNUSED, const char *arg)
-{
- GNode *gn;
-
- gn = Targ_FindNode(arg, TARG_NOCREATE);
- return (gn != NULL) && !OP_NOP(gn->type) && !Lst_IsEmpty(gn->commands);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * CondCvtArg --
- * Convert the given number into a double.
- * We try a base 10 or 16 integer conversion first, if that fails
- * then we try a floating point conversion instead.
- *
- * Results:
- * Sets 'value' to double value of string.
- * Returns 'true' if the convertion suceeded
- *
- *-----------------------------------------------------------------------
- */
-static Boolean
-CondCvtArg(char *str, double *value)
-{
- char *eptr, ech;
- unsigned long l_val;
- double d_val;
-
- errno = 0;
- if (!*str) {
- *value = (double)0;
- return TRUE;
- }
- l_val = strtoul(str, &eptr, str[1] == 'x' ? 16 : 10);
- ech = *eptr;
- if (ech == 0 && errno != ERANGE) {
- d_val = str[0] == '-' ? -(double)-l_val : (double)l_val;
- } else {
- if (ech != 0 && ech != '.' && ech != 'e' && ech != 'E')
- return FALSE;
- d_val = strtod(str, &eptr);
- if (*eptr)
- return FALSE;
- }
-
- *value = d_val;
- return TRUE;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * CondGetString --
- * Get a string from a variable reference or an optionally quoted
- * string. This is called for the lhs and rhs of string compares.
- *
- * Results:
- * Sets freeIt if needed,
- * Sets quoted if string was quoted,
- * Returns NULL on error,
- * else returns string - absent any quotes.
- *
- * Side Effects:
- * Moves condExpr to end of this token.
- *
- *
- *-----------------------------------------------------------------------
- */
-/* coverity:[+alloc : arg-*2] */
-static char *
-CondGetString(Boolean doEval, Boolean *quoted, void **freeIt, Boolean strictLHS)
-{
- Buffer buf;
- char *cp;
- char *str;
- int len;
- int qt;
- char *start;
-
- Buf_Init(&buf, 0);
- str = NULL;
- *freeIt = NULL;
- *quoted = qt = *condExpr == '"' ? 1 : 0;
- if (qt)
- condExpr++;
- for (start = condExpr; *condExpr && str == NULL; condExpr++) {
- switch (*condExpr) {
- case '\\':
- if (condExpr[1] != '\0') {
- condExpr++;
- Buf_AddByte(&buf, *condExpr);
- }
- break;
- case '"':
- if (qt) {
- condExpr++; /* we don't want the quotes */
- goto got_str;
- } else
- Buf_AddByte(&buf, *condExpr); /* likely? */
- break;
- case ')':
- case '!':
- case '=':
- case '>':
- case '<':
- case ' ':
- case '\t':
- if (!qt)
- goto got_str;
- else
- Buf_AddByte(&buf, *condExpr);
- break;
- case '$':
- /* if we are in quotes, then an undefined variable is ok */
- str = Var_Parse(condExpr, VAR_CMD,
- ((!qt && doEval) ? VARF_UNDEFERR : 0) |
- VARF_WANTRES, &len, freeIt);
- if (str == var_Error) {
- if (*freeIt) {
- free(*freeIt);
- *freeIt = NULL;
- }
- /*
- * Even if !doEval, we still report syntax errors, which
- * is what getting var_Error back with !doEval means.
- */
- str = NULL;
- goto cleanup;
- }
- condExpr += len;
- /*
- * If the '$' was first char (no quotes), and we are
- * followed by space, the operator or end of expression,
- * we are done.
- */
- if ((condExpr == start + len) &&
- (*condExpr == '\0' ||
- isspace((unsigned char) *condExpr) ||
- strchr("!=><)", *condExpr))) {
- goto cleanup;
- }
- /*
- * Nope, we better copy str to buf
- */
- for (cp = str; *cp; cp++) {
- Buf_AddByte(&buf, *cp);
- }
- if (*freeIt) {
- free(*freeIt);
- *freeIt = NULL;
- }
- str = NULL; /* not finished yet */
- condExpr--; /* don't skip over next char */
- break;
- default:
- if (strictLHS && !qt && *start != '$' &&
- !isdigit((unsigned char) *start)) {
- /* lhs must be quoted, a variable reference or number */
- if (*freeIt) {
- free(*freeIt);
- *freeIt = NULL;
- }
- str = NULL;
- goto cleanup;
- }
- Buf_AddByte(&buf, *condExpr);
- break;
- }
- }
- got_str:
- str = Buf_GetAll(&buf, NULL);
- *freeIt = str;
- cleanup:
- Buf_Destroy(&buf, FALSE);
- return str;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * CondToken --
- * Return the next token from the input.
- *
- * Results:
- * A Token for the next lexical token in the stream.
- *
- * Side Effects:
- * condPushback will be set back to TOK_NONE if it is used.
- *
- *-----------------------------------------------------------------------
- */
-static Token
-compare_expression(Boolean doEval)
-{
- Token t;
- char *lhs;
- char *rhs;
- char *op;
- void *lhsFree;
- void *rhsFree;
- Boolean lhsQuoted;
- Boolean rhsQuoted;
- double left, right;
-
- t = TOK_ERROR;
- rhs = NULL;
- lhsFree = rhsFree = FALSE;
- lhsQuoted = rhsQuoted = FALSE;
-
- /*
- * Parse the variable spec and skip over it, saving its
- * value in lhs.
- */
- lhs = CondGetString(doEval, &lhsQuoted, &lhsFree, lhsStrict);
- if (!lhs)
- goto done;
-
- /*
- * Skip whitespace to get to the operator
- */
- while (isspace((unsigned char) *condExpr))
- condExpr++;
-
- /*
- * Make sure the operator is a valid one. If it isn't a
- * known relational operator, pretend we got a
- * != 0 comparison.
- */
- op = condExpr;
- switch (*condExpr) {
- case '!':
- case '=':
- case '<':
- case '>':
- if (condExpr[1] == '=') {
- condExpr += 2;
- } else {
- condExpr += 1;
- }
- break;
- default:
- if (!doEval) {
- t = TOK_FALSE;
- goto done;
- }
- /* For .ifxxx "..." check for non-empty string. */
- if (lhsQuoted) {
- t = lhs[0] != 0;
- goto done;
- }
- /* For .ifxxx <number> compare against zero */
- if (CondCvtArg(lhs, &left)) {
- t = left != 0.0;
- goto done;
- }
- /* For .if ${...} check for non-empty string (defProc is ifdef). */
- if (if_info->form[0] == 0) {
- t = lhs[0] != 0;
- goto done;
- }
- /* Otherwise action default test ... */
- t = if_info->defProc(strlen(lhs), lhs) != if_info->doNot;
- goto done;
- }
-
- while (isspace((unsigned char)*condExpr))
- condExpr++;
-
- if (*condExpr == '\0') {
- Parse_Error(PARSE_WARNING,
- "Missing right-hand-side of operator");
- goto done;
- }
-
- rhs = CondGetString(doEval, &rhsQuoted, &rhsFree, FALSE);
- if (!rhs)
- goto done;
-
- if (rhsQuoted || lhsQuoted) {
-do_string_compare:
- if (((*op != '!') && (*op != '=')) || (op[1] != '=')) {
- Parse_Error(PARSE_WARNING,
- "String comparison operator should be either == or !=");
- goto done;
- }
-
- if (DEBUG(COND)) {
- fprintf(debug_file, "lhs = \"%s\", rhs = \"%s\", op = %.2s\n",
- lhs, rhs, op);
- }
- /*
- * Null-terminate rhs and perform the comparison.
- * t is set to the result.
- */
- if (*op == '=') {
- t = strcmp(lhs, rhs) == 0;
- } else {
- t = strcmp(lhs, rhs) != 0;
- }
- } else {
- /*
- * rhs is either a float or an integer. Convert both the
- * lhs and the rhs to a double and compare the two.
- */
-
- if (!CondCvtArg(lhs, &left) || !CondCvtArg(rhs, &right))
- goto do_string_compare;
-
- if (DEBUG(COND)) {
- fprintf(debug_file, "left = %f, right = %f, op = %.2s\n", left,
- right, op);
- }
- switch(op[0]) {
- case '!':
- if (op[1] != '=') {
- Parse_Error(PARSE_WARNING,
- "Unknown operator");
- goto done;
- }
- t = (left != right);
- break;
- case '=':
- if (op[1] != '=') {
- Parse_Error(PARSE_WARNING,
- "Unknown operator");
- goto done;
- }
- t = (left == right);
- break;
- case '<':
- if (op[1] == '=') {
- t = (left <= right);
- } else {
- t = (left < right);
- }
- break;
- case '>':
- if (op[1] == '=') {
- t = (left >= right);
- } else {
- t = (left > right);
- }
- break;
- }
- }
-
-done:
- free(lhsFree);
- free(rhsFree);
- return t;
-}
-
-static int
-get_mpt_arg(char **linePtr, char **argPtr, const char *func MAKE_ATTR_UNUSED)
-{
- /*
- * Use Var_Parse to parse the spec in parens and return
- * TOK_TRUE if the resulting string is empty.
- */
- int length;
- void *freeIt;
- char *val;
- char *cp = *linePtr;
-
- /* We do all the work here and return the result as the length */
- *argPtr = NULL;
-
- val = Var_Parse(cp - 1, VAR_CMD, VARF_WANTRES, &length, &freeIt);
- /*
- * Advance *linePtr to beyond the closing ). Note that
- * we subtract one because 'length' is calculated from 'cp - 1'.
- */
- *linePtr = cp - 1 + length;
-
- if (val == var_Error) {
- free(freeIt);
- return -1;
- }
-
- /* A variable is empty when it just contains spaces... 4/15/92, christos */
- while (isspace(*(unsigned char *)val))
- val++;
-
- /*
- * For consistency with the other functions we can't generate the
- * true/false here.
- */
- length = *val ? 2 : 1;
- free(freeIt);
- return length;
-}
-
-static Boolean
-CondDoEmpty(int arglen, const char *arg MAKE_ATTR_UNUSED)
-{
- return arglen == 1;
-}
-
-static Token
-compare_function(Boolean doEval)
-{
- static const struct fn_def {
- const char *fn_name;
- int fn_name_len;
- int (*fn_getarg)(char **, char **, const char *);
- Boolean (*fn_proc)(int, const char *);
- } fn_defs[] = {
- { "defined", 7, CondGetArg, CondDoDefined },
- { "make", 4, CondGetArg, CondDoMake },
- { "exists", 6, CondGetArg, CondDoExists },
- { "empty", 5, get_mpt_arg, CondDoEmpty },
- { "target", 6, CondGetArg, CondDoTarget },
- { "commands", 8, CondGetArg, CondDoCommands },
- { NULL, 0, NULL, NULL },
- };
- const struct fn_def *fn_def;
- Token t;
- char *arg = NULL;
- int arglen;
- char *cp = condExpr;
- char *cp1;
-
- for (fn_def = fn_defs; fn_def->fn_name != NULL; fn_def++) {
- if (!istoken(cp, fn_def->fn_name, fn_def->fn_name_len))
- continue;
- cp += fn_def->fn_name_len;
- /* There can only be whitespace before the '(' */
- while (isspace(*(unsigned char *)cp))
- cp++;
- if (*cp != '(')
- break;
-
- arglen = fn_def->fn_getarg(&cp, &arg, fn_def->fn_name);
- if (arglen <= 0) {
- condExpr = cp;
- return arglen < 0 ? TOK_ERROR : TOK_FALSE;
- }
- /* Evaluate the argument using the required function. */
- t = !doEval || fn_def->fn_proc(arglen, arg);
- free(arg);
- condExpr = cp;
- return t;
- }
-
- /* Push anything numeric through the compare expression */
- cp = condExpr;
- if (isdigit((unsigned char)cp[0]) || strchr("+-", cp[0]))
- return compare_expression(doEval);
-
- /*
- * Most likely we have a naked token to apply the default function to.
- * However ".if a == b" gets here when the "a" is unquoted and doesn't
- * start with a '$'. This surprises people.
- * If what follows the function argument is a '=' or '!' then the syntax
- * would be invalid if we did "defined(a)" - so instead treat as an
- * expression.
- */
- arglen = CondGetArg(&cp, &arg, NULL);
- for (cp1 = cp; isspace(*(unsigned char *)cp1); cp1++)
- continue;
- if (*cp1 == '=' || *cp1 == '!')
- return compare_expression(doEval);
- condExpr = cp;
-
- /*
- * Evaluate the argument using the default function.
- * This path always treats .if as .ifdef. To get here the character
- * after .if must have been taken literally, so the argument cannot
- * be empty - even if it contained a variable expansion.
- */
- t = !doEval || if_info->defProc(arglen, arg) != if_info->doNot;
- free(arg);
- return t;
-}
-
-static Token
-CondToken(Boolean doEval)
-{
- Token t;
-
- t = condPushBack;
- if (t != TOK_NONE) {
- condPushBack = TOK_NONE;
- return t;
- }
-
- while (*condExpr == ' ' || *condExpr == '\t') {
- condExpr++;
- }
-
- switch (*condExpr) {
-
- case '(':
- condExpr++;
- return TOK_LPAREN;
-
- case ')':
- condExpr++;
- return TOK_RPAREN;
-
- case '|':
- if (condExpr[1] == '|') {
- condExpr++;
- }
- condExpr++;
- return TOK_OR;
-
- case '&':
- if (condExpr[1] == '&') {
- condExpr++;
- }
- condExpr++;
- return TOK_AND;
-
- case '!':
- condExpr++;
- return TOK_NOT;
-
- case '#':
- case '\n':
- case '\0':
- return TOK_EOF;
-
- case '"':
- case '$':
- return compare_expression(doEval);
-
- default:
- return compare_function(doEval);
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * CondT --
- * Parse a single term in the expression. This consists of a terminal
- * symbol or TOK_NOT and a terminal symbol (not including the binary
- * operators):
- * T -> defined(variable) | make(target) | exists(file) | symbol
- * T -> ! T | ( E )
- *
- * Results:
- * TOK_TRUE, TOK_FALSE or TOK_ERROR.
- *
- * Side Effects:
- * Tokens are consumed.
- *
- *-----------------------------------------------------------------------
- */
-static Token
-CondT(Boolean doEval)
-{
- Token t;
-
- t = CondToken(doEval);
-
- if (t == TOK_EOF) {
- /*
- * If we reached the end of the expression, the expression
- * is malformed...
- */
- t = TOK_ERROR;
- } else if (t == TOK_LPAREN) {
- /*
- * T -> ( E )
- */
- t = CondE(doEval);
- if (t != TOK_ERROR) {
- if (CondToken(doEval) != TOK_RPAREN) {
- t = TOK_ERROR;
- }
- }
- } else if (t == TOK_NOT) {
- t = CondT(doEval);
- if (t == TOK_TRUE) {
- t = TOK_FALSE;
- } else if (t == TOK_FALSE) {
- t = TOK_TRUE;
- }
- }
- return (t);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * CondF --
- * Parse a conjunctive factor (nice name, wot?)
- * F -> T && F | T
- *
- * Results:
- * TOK_TRUE, TOK_FALSE or TOK_ERROR
- *
- * Side Effects:
- * Tokens are consumed.
- *
- *-----------------------------------------------------------------------
- */
-static Token
-CondF(Boolean doEval)
-{
- Token l, o;
-
- l = CondT(doEval);
- if (l != TOK_ERROR) {
- o = CondToken(doEval);
-
- if (o == TOK_AND) {
- /*
- * F -> T && F
- *
- * If T is TOK_FALSE, the whole thing will be TOK_FALSE, but we have to
- * parse the r.h.s. anyway (to throw it away).
- * If T is TOK_TRUE, the result is the r.h.s., be it an TOK_ERROR or no.
- */
- if (l == TOK_TRUE) {
- l = CondF(doEval);
- } else {
- (void)CondF(FALSE);
- }
- } else {
- /*
- * F -> T
- */
- CondPushBack(o);
- }
- }
- return (l);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * CondE --
- * Main expression production.
- * E -> F || E | F
- *
- * Results:
- * TOK_TRUE, TOK_FALSE or TOK_ERROR.
- *
- * Side Effects:
- * Tokens are, of course, consumed.
- *
- *-----------------------------------------------------------------------
- */
-static Token
-CondE(Boolean doEval)
-{
- Token l, o;
-
- l = CondF(doEval);
- if (l != TOK_ERROR) {
- o = CondToken(doEval);
-
- if (o == TOK_OR) {
- /*
- * E -> F || E
- *
- * A similar thing occurs for ||, except that here we make sure
- * the l.h.s. is TOK_FALSE before we bother to evaluate the r.h.s.
- * Once again, if l is TOK_FALSE, the result is the r.h.s. and once
- * again if l is TOK_TRUE, we parse the r.h.s. to throw it away.
- */
- if (l == TOK_FALSE) {
- l = CondE(doEval);
- } else {
- (void)CondE(FALSE);
- }
- } else {
- /*
- * E -> F
- */
- CondPushBack(o);
- }
- }
- return (l);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Cond_EvalExpression --
- * Evaluate an expression in the passed line. The expression
- * consists of &&, ||, !, make(target), defined(variable)
- * and parenthetical groupings thereof.
- *
- * Results:
- * COND_PARSE if the condition was valid grammatically
- * COND_INVALID if not a valid conditional.
- *
- * (*value) is set to the boolean value of the condition
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-int
-Cond_EvalExpression(const struct If *info, char *line, Boolean *value, int eprint, Boolean strictLHS)
-{
- static const struct If *dflt_info;
- const struct If *sv_if_info = if_info;
- char *sv_condExpr = condExpr;
- Token sv_condPushBack = condPushBack;
- int rval;
-
- lhsStrict = strictLHS;
-
- while (*line == ' ' || *line == '\t')
- line++;
-
- if (info == NULL && (info = dflt_info) == NULL) {
- /* Scan for the entry for .if - it can't be first */
- for (info = ifs; ; info++)
- if (info->form[0] == 0)
- break;
- dflt_info = info;
- }
- assert(info != NULL);
-
- if_info = info;
- condExpr = line;
- condPushBack = TOK_NONE;
-
- rval = do_Cond_EvalExpression(value);
-
- if (rval == COND_INVALID && eprint)
- Parse_Error(PARSE_FATAL, "Malformed conditional (%s)", line);
-
- if_info = sv_if_info;
- condExpr = sv_condExpr;
- condPushBack = sv_condPushBack;
-
- return rval;
-}
-
-static int
-do_Cond_EvalExpression(Boolean *value)
-{
-
- switch (CondE(TRUE)) {
- case TOK_TRUE:
- if (CondToken(TRUE) == TOK_EOF) {
- *value = TRUE;
- return COND_PARSE;
- }
- break;
- case TOK_FALSE:
- if (CondToken(TRUE) == TOK_EOF) {
- *value = FALSE;
- return COND_PARSE;
- }
- break;
- default:
- case TOK_ERROR:
- break;
- }
-
- return COND_INVALID;
-}
-
-
-/*-
- *-----------------------------------------------------------------------
- * Cond_Eval --
- * Evaluate the conditional in the passed line. The line
- * looks like this:
- * .<cond-type> <expr>
- * where <cond-type> is any of if, ifmake, ifnmake, ifdef,
- * ifndef, elif, elifmake, elifnmake, elifdef, elifndef
- * and <expr> consists of &&, ||, !, make(target), defined(variable)
- * and parenthetical groupings thereof.
- *
- * Input:
- * line Line to parse
- *
- * Results:
- * COND_PARSE if should parse lines after the conditional
- * COND_SKIP if should skip lines after the conditional
- * COND_INVALID if not a valid conditional.
- *
- * Side Effects:
- * None.
- *
- * Note that the states IF_ACTIVE and ELSE_ACTIVE are only different in order
- * to detect splurious .else lines (as are SKIP_TO_ELSE and SKIP_TO_ENDIF)
- * otherwise .else could be treated as '.elif 1'.
- *
- *-----------------------------------------------------------------------
- */
-int
-Cond_Eval(char *line)
-{
-#define MAXIF 128 /* maximum depth of .if'ing */
-#define MAXIF_BUMP 32 /* how much to grow by */
- enum if_states {
- IF_ACTIVE, /* .if or .elif part active */
- ELSE_ACTIVE, /* .else part active */
- SEARCH_FOR_ELIF, /* searching for .elif/else to execute */
- SKIP_TO_ELSE, /* has been true, but not seen '.else' */
- SKIP_TO_ENDIF /* nothing else to execute */
- };
- static enum if_states *cond_state = NULL;
- static unsigned int max_if_depth = MAXIF;
-
- const struct If *ifp;
- Boolean isElif;
- Boolean value;
- int level; /* Level at which to report errors. */
- enum if_states state;
-
- level = PARSE_FATAL;
- if (!cond_state) {
- cond_state = bmake_malloc(max_if_depth * sizeof(*cond_state));
- cond_state[0] = IF_ACTIVE;
- }
- /* skip leading character (the '.') and any whitespace */
- for (line++; *line == ' ' || *line == '\t'; line++)
- continue;
-
- /* Find what type of if we're dealing with. */
- if (line[0] == 'e') {
- if (line[1] != 'l') {
- if (!istoken(line + 1, "ndif", 4))
- return COND_INVALID;
- /* End of conditional section */
- if (cond_depth == cond_min_depth) {
- Parse_Error(level, "if-less endif");
- return COND_PARSE;
- }
- /* Return state for previous conditional */
- cond_depth--;
- return cond_state[cond_depth] <= ELSE_ACTIVE ? COND_PARSE : COND_SKIP;
- }
-
- /* Quite likely this is 'else' or 'elif' */
- line += 2;
- if (istoken(line, "se", 2)) {
- /* It is else... */
- if (cond_depth == cond_min_depth) {
- Parse_Error(level, "if-less else");
- return COND_PARSE;
- }
-
- state = cond_state[cond_depth];
- switch (state) {
- case SEARCH_FOR_ELIF:
- state = ELSE_ACTIVE;
- break;
- case ELSE_ACTIVE:
- case SKIP_TO_ENDIF:
- Parse_Error(PARSE_WARNING, "extra else");
- /* FALLTHROUGH */
- default:
- case IF_ACTIVE:
- case SKIP_TO_ELSE:
- state = SKIP_TO_ENDIF;
- break;
- }
- cond_state[cond_depth] = state;
- return state <= ELSE_ACTIVE ? COND_PARSE : COND_SKIP;
- }
- /* Assume for now it is an elif */
- isElif = TRUE;
- } else
- isElif = FALSE;
-
- if (line[0] != 'i' || line[1] != 'f')
- /* Not an ifxxx or elifxxx line */
- return COND_INVALID;
-
- /*
- * Figure out what sort of conditional it is -- what its default
- * function is, etc. -- by looking in the table of valid "ifs"
- */
- line += 2;
- for (ifp = ifs; ; ifp++) {
- if (ifp->form == NULL)
- return COND_INVALID;
- if (istoken(ifp->form, line, ifp->formlen)) {
- line += ifp->formlen;
- break;
- }
- }
-
- /* Now we know what sort of 'if' it is... */
-
- if (isElif) {
- if (cond_depth == cond_min_depth) {
- Parse_Error(level, "if-less elif");
- return COND_PARSE;
- }
- state = cond_state[cond_depth];
- if (state == SKIP_TO_ENDIF || state == ELSE_ACTIVE) {
- Parse_Error(PARSE_WARNING, "extra elif");
- cond_state[cond_depth] = SKIP_TO_ENDIF;
- return COND_SKIP;
- }
- if (state != SEARCH_FOR_ELIF) {
- /* Either just finished the 'true' block, or already SKIP_TO_ELSE */
- cond_state[cond_depth] = SKIP_TO_ELSE;
- return COND_SKIP;
- }
- } else {
- /* Normal .if */
- if (cond_depth + 1 >= max_if_depth) {
- /*
- * This is rare, but not impossible.
- * In meta mode, dirdeps.mk (only runs at level 0)
- * can need more than the default.
- */
- max_if_depth += MAXIF_BUMP;
- cond_state = bmake_realloc(cond_state, max_if_depth *
- sizeof(*cond_state));
- }
- state = cond_state[cond_depth];
- cond_depth++;
- if (state > ELSE_ACTIVE) {
- /* If we aren't parsing the data, treat as always false */
- cond_state[cond_depth] = SKIP_TO_ELSE;
- return COND_SKIP;
- }
- }
-
- /* And evaluate the conditional expresssion */
- if (Cond_EvalExpression(ifp, line, &value, 1, TRUE) == COND_INVALID) {
- /* Syntax error in conditional, error message already output. */
- /* Skip everything to matching .endif */
- cond_state[cond_depth] = SKIP_TO_ELSE;
- return COND_SKIP;
- }
-
- if (!value) {
- cond_state[cond_depth] = SEARCH_FOR_ELIF;
- return COND_SKIP;
- }
- cond_state[cond_depth] = IF_ACTIVE;
- return COND_PARSE;
-}
-
-
-
-/*-
- *-----------------------------------------------------------------------
- * Cond_End --
- * Make sure everything's clean at the end of a makefile.
- *
- * Results:
- * None.
- *
- * Side Effects:
- * Parse_Error will be called if open conditionals are around.
- *
- *-----------------------------------------------------------------------
- */
-void
-Cond_restore_depth(unsigned int saved_depth)
-{
- int open_conds = cond_depth - cond_min_depth;
-
- if (open_conds != 0 || saved_depth > cond_depth) {
- Parse_Error(PARSE_FATAL, "%d open conditional%s", open_conds,
- open_conds == 1 ? "" : "s");
- cond_depth = cond_min_depth;
- }
-
- cond_min_depth = saved_depth;
-}
-
-unsigned int
-Cond_save_depth(void)
-{
- int depth = cond_min_depth;
-
- cond_min_depth = cond_depth;
- return depth;
-}
diff --git a/usr.bin/make/config.h b/usr.bin/make/config.h
deleted file mode 100644
index 06af09c..0000000
--- a/usr.bin/make/config.h
+++ /dev/null
@@ -1,160 +0,0 @@
-/* $NetBSD: config.h,v 1.21 2012/03/31 00:12:24 christos Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- *
- * from: @(#)config.h 8.1 (Berkeley) 6/6/93
- */
-
-/*
- * Copyright (c) 1988, 1989 by Adam de Boor
- * Copyright (c) 1989 by Berkeley Softworks
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. 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.
- *
- * from: @(#)config.h 8.1 (Berkeley) 6/6/93
- */
-
-/*
- * DEFMAXJOBS
- * DEFMAXLOCAL
- * These control the default concurrency. On no occasion will more
- * than DEFMAXJOBS targets be created at once (locally or remotely)
- * DEFMAXLOCAL is the highest number of targets which will be
- * created on the local machine at once. Note that if you set this
- * to 0, nothing will ever happen...
- */
-#define DEFMAXJOBS 4
-#define DEFMAXLOCAL 1
-
-/*
- * INCLUDES
- * LIBRARIES
- * These control the handling of the .INCLUDES and .LIBS variables.
- * If INCLUDES is defined, the .INCLUDES variable will be filled
- * from the search paths of those suffixes which are marked by
- * .INCLUDES dependency lines. Similarly for LIBRARIES and .LIBS
- * See suff.c for more details.
- */
-#define INCLUDES
-#define LIBRARIES
-
-/*
- * LIBSUFF
- * Is the suffix used to denote libraries and is used by the Suff module
- * to find the search path on which to seek any -l<xx> targets.
- *
- * RECHECK
- * If defined, Make_Update will check a target for its current
- * modification time after it has been re-made, setting it to the
- * starting time of the make only if the target still doesn't exist.
- * Unfortunately, under NFS the modification time often doesn't
- * get updated in time, so a target will appear to not have been
- * re-made, causing later targets to appear up-to-date. On systems
- * that don't have this problem, you should defined this. Under
- * NFS you probably should not, unless you aren't exporting jobs.
- */
-#define LIBSUFF ".a"
-#define RECHECK
-
-/*
- * POSIX
- * Adhere to the POSIX 1003.2 draft for the make(1) program.
- * - Use MAKEFLAGS instead of MAKE to pick arguments from the
- * environment.
- * - Allow empty command lines if starting with tab.
- */
-#define POSIX
-
-/*
- * SYSVINCLUDE
- * Recognize system V like include directives [include "filename"]
- * SYSVVARSUB
- * Recognize system V like ${VAR:x=y} variable substitutions
- */
-#define SYSVINCLUDE
-#define SYSVVARSUB
-
-/*
- * GMAKEEXPORT
- * Recognize gmake like variable export directives [export <VAR>=<VALUE>]
- */
-#define GMAKEEXPORT
-
-/*
- * SUNSHCMD
- * Recognize SunOS and Solaris:
- * VAR :sh= CMD # Assign VAR to the command substitution of CMD
- * ${VAR:sh} # Return the command substitution of the value
- * # of ${VAR}
- */
-#define SUNSHCMD
-
-/*
- * USE_IOVEC
- * We have writev(2)
- */
-#define USE_IOVEC
-
-#if defined(MAKE_NATIVE) && !defined(__ELF__)
-# ifndef RANLIBMAG
-# define RANLIBMAG "__.SYMDEF"
-# endif
-#endif
diff --git a/usr.bin/make/dir.c b/usr.bin/make/dir.c
deleted file mode 100644
index 0062ac0..0000000
--- a/usr.bin/make/dir.c
+++ /dev/null
@@ -1,1849 +0,0 @@
-/* $NetBSD: dir.c,v 1.73 2018/07/12 18:03:31 christos Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-/*
- * Copyright (c) 1988, 1989 by Adam de Boor
- * Copyright (c) 1989 by Berkeley Softworks
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: dir.c,v 1.73 2018/07/12 18:03:31 christos Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)dir.c 8.2 (Berkeley) 1/2/94";
-#else
-__RCSID("$NetBSD: dir.c,v 1.73 2018/07/12 18:03:31 christos Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * dir.c --
- * Directory searching using wildcards and/or normal names...
- * Used both for source wildcarding in the Makefile and for finding
- * implicit sources.
- *
- * The interface for this module is:
- * Dir_Init Initialize the module.
- *
- * Dir_InitCur Set the cur Path.
- *
- * Dir_InitDot Set the dot Path.
- *
- * Dir_End Cleanup the module.
- *
- * Dir_SetPATH Set ${.PATH} to reflect state of dirSearchPath.
- *
- * Dir_HasWildcards Returns TRUE if the name given it needs to
- * be wildcard-expanded.
- *
- * Dir_Expand Given a pattern and a path, return a Lst of names
- * which match the pattern on the search path.
- *
- * Dir_FindFile Searches for a file on a given search path.
- * If it exists, the entire path is returned.
- * Otherwise NULL is returned.
- *
- * Dir_FindHereOrAbove Search for a path in the current directory and
- * then all the directories above it in turn until
- * the path is found or we reach the root ("/").
- *
- * Dir_MTime Return the modification time of a node. The file
- * is searched for along the default search path.
- * The path and mtime fields of the node are filled
- * in.
- *
- * Dir_AddDir Add a directory to a search path.
- *
- * Dir_MakeFlags Given a search path and a command flag, create
- * a string with each of the directories in the path
- * preceded by the command flag and all of them
- * separated by a space.
- *
- * Dir_Destroy Destroy an element of a search path. Frees up all
- * things that can be freed for the element as long
- * as the element is no longer referenced by any other
- * search path.
- * Dir_ClearPath Resets a search path to the empty list.
- *
- * For debugging:
- * Dir_PrintDirectories Print stats about the directory cache.
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <dirent.h>
-#include <errno.h>
-#include <stdio.h>
-
-#include "make.h"
-#include "hash.h"
-#include "dir.h"
-#include "job.h"
-
-/*
- * A search path consists of a Lst of Path structures. A Path structure
- * has in it the name of the directory and a hash table of all the files
- * in the directory. This is used to cut down on the number of system
- * calls necessary to find implicit dependents and their like. Since
- * these searches are made before any actions are taken, we need not
- * worry about the directory changing due to creation commands. If this
- * hampers the style of some makefiles, they must be changed.
- *
- * A list of all previously-read directories is kept in the
- * openDirectories Lst. This list is checked first before a directory
- * is opened.
- *
- * The need for the caching of whole directories is brought about by
- * the multi-level transformation code in suff.c, which tends to search
- * for far more files than regular make does. In the initial
- * implementation, the amount of time spent performing "stat" calls was
- * truly astronomical. The problem with hashing at the start is,
- * of course, that pmake doesn't then detect changes to these directories
- * during the course of the make. Three possibilities suggest themselves:
- *
- * 1) just use stat to test for a file's existence. As mentioned
- * above, this is very inefficient due to the number of checks
- * engendered by the multi-level transformation code.
- * 2) use readdir() and company to search the directories, keeping
- * them open between checks. I have tried this and while it
- * didn't slow down the process too much, it could severely
- * affect the amount of parallelism available as each directory
- * open would take another file descriptor out of play for
- * handling I/O for another job. Given that it is only recently
- * that UNIX OS's have taken to allowing more than 20 or 32
- * file descriptors for a process, this doesn't seem acceptable
- * to me.
- * 3) record the mtime of the directory in the Path structure and
- * verify the directory hasn't changed since the contents were
- * hashed. This will catch the creation or deletion of files,
- * but not the updating of files. However, since it is the
- * creation and deletion that is the problem, this could be
- * a good thing to do. Unfortunately, if the directory (say ".")
- * were fairly large and changed fairly frequently, the constant
- * rehashing could seriously degrade performance. It might be
- * good in such cases to keep track of the number of rehashes
- * and if the number goes over a (small) limit, resort to using
- * stat in its place.
- *
- * An additional thing to consider is that pmake is used primarily
- * to create C programs and until recently pcc-based compilers refused
- * to allow you to specify where the resulting object file should be
- * placed. This forced all objects to be created in the current
- * directory. This isn't meant as a full excuse, just an explanation of
- * some of the reasons for the caching used here.
- *
- * One more note: the location of a target's file is only performed
- * on the downward traversal of the graph and then only for terminal
- * nodes in the graph. This could be construed as wrong in some cases,
- * but prevents inadvertent modification of files when the "installed"
- * directory for a file is provided in the search path.
- *
- * Another data structure maintained by this module is an mtime
- * cache used when the searching of cached directories fails to find
- * a file. In the past, Dir_FindFile would simply perform an access()
- * call in such a case to determine if the file could be found using
- * just the name given. When this hit, however, all that was gained
- * was the knowledge that the file existed. Given that an access() is
- * essentially a stat() without the copyout() call, and that the same
- * filesystem overhead would have to be incurred in Dir_MTime, it made
- * sense to replace the access() with a stat() and record the mtime
- * in a cache for when Dir_MTime was actually called.
- */
-
-Lst dirSearchPath; /* main search path */
-
-static Lst openDirectories; /* the list of all open directories */
-
-/*
- * Variables for gathering statistics on the efficiency of the hashing
- * mechanism.
- */
-static int hits, /* Found in directory cache */
- misses, /* Sad, but not evil misses */
- nearmisses, /* Found under search path */
- bigmisses; /* Sought by itself */
-
-static Path *dot; /* contents of current directory */
-static Path *cur; /* contents of current directory, if not dot */
-static Path *dotLast; /* a fake path entry indicating we need to
- * look for . last */
-static Hash_Table mtimes; /* Results of doing a last-resort stat in
- * Dir_FindFile -- if we have to go to the
- * system to find the file, we might as well
- * have its mtime on record. XXX: If this is done
- * way early, there's a chance other rules will
- * have already updated the file, in which case
- * we'll update it again. Generally, there won't
- * be two rules to update a single file, so this
- * should be ok, but... */
-
-static Hash_Table lmtimes; /* same as mtimes but for lstat */
-
-static int DirFindName(const void *, const void *);
-static int DirMatchFiles(const char *, Path *, Lst);
-static void DirExpandCurly(const char *, const char *, Lst, Lst);
-static void DirExpandInt(const char *, Lst, Lst);
-static int DirPrintWord(void *, void *);
-static int DirPrintDir(void *, void *);
-static char *DirLookup(Path *, const char *, const char *, Boolean);
-static char *DirLookupSubdir(Path *, const char *);
-static char *DirFindDot(Boolean, const char *, const char *);
-static char *DirLookupAbs(Path *, const char *, const char *);
-
-
-/*
- * We use stat(2) a lot, cache the results
- * mtime and mode are all we care about.
- */
-struct cache_st {
- time_t mtime;
- mode_t mode;
-};
-
-/* minimize changes below */
-#define CST_LSTAT 1
-#define CST_UPDATE 2
-
-static int
-cached_stats(Hash_Table *htp, const char *pathname, struct stat *st, int flags)
-{
- Hash_Entry *entry;
- struct cache_st *cst;
- int rc;
-
- if (!pathname || !pathname[0])
- return -1;
-
- entry = Hash_FindEntry(htp, pathname);
-
- if (entry && (flags & CST_UPDATE) == 0) {
- cst = entry->clientPtr;
-
- memset(st, 0, sizeof(*st));
- st->st_mtime = cst->mtime;
- st->st_mode = cst->mode;
- if (DEBUG(DIR)) {
- fprintf(debug_file, "Using cached time %s for %s\n",
- Targ_FmtTime(st->st_mtime), pathname);
- }
- return 0;
- }
-
- rc = (flags & CST_LSTAT) ? lstat(pathname, st) : stat(pathname, st);
- if (rc == -1)
- return -1;
-
- if (st->st_mtime == 0)
- st->st_mtime = 1; /* avoid confusion with missing file */
-
- if (!entry)
- entry = Hash_CreateEntry(htp, pathname, NULL);
- if (!entry->clientPtr)
- entry->clientPtr = bmake_malloc(sizeof(*cst));
- cst = entry->clientPtr;
- cst->mtime = st->st_mtime;
- cst->mode = st->st_mode;
- if (DEBUG(DIR)) {
- fprintf(debug_file, " Caching %s for %s\n",
- Targ_FmtTime(st->st_mtime), pathname);
- }
-
- return 0;
-}
-
-int
-cached_stat(const char *pathname, void *st)
-{
- return cached_stats(&mtimes, pathname, st, 0);
-}
-
-int
-cached_lstat(const char *pathname, void *st)
-{
- return cached_stats(&lmtimes, pathname, st, CST_LSTAT);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Dir_Init --
- * initialize things for this module
- *
- * Results:
- * none
- *
- * Side Effects:
- * some directories may be opened.
- *-----------------------------------------------------------------------
- */
-void
-Dir_Init(const char *cdname)
-{
- if (!cdname) {
- dirSearchPath = Lst_Init(FALSE);
- openDirectories = Lst_Init(FALSE);
- Hash_InitTable(&mtimes, 0);
- Hash_InitTable(&lmtimes, 0);
- return;
- }
- Dir_InitCur(cdname);
-
- dotLast = bmake_malloc(sizeof(Path));
- dotLast->refCount = 1;
- dotLast->hits = 0;
- dotLast->name = bmake_strdup(".DOTLAST");
- Hash_InitTable(&dotLast->files, -1);
-}
-
-/*
- * Called by Dir_Init() and whenever .CURDIR is assigned to.
- */
-void
-Dir_InitCur(const char *cdname)
-{
- Path *p;
-
- if (cdname != NULL) {
- /*
- * Our build directory is not the same as our source directory.
- * Keep this one around too.
- */
- if ((p = Dir_AddDir(NULL, cdname))) {
- p->refCount += 1;
- if (cur && cur != p) {
- /*
- * We've been here before, cleanup.
- */
- cur->refCount -= 1;
- Dir_Destroy(cur);
- }
- cur = p;
- }
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Dir_InitDot --
- * (re)initialize "dot" (current/object directory) path hash
- *
- * Results:
- * none
- *
- * Side Effects:
- * some directories may be opened.
- *-----------------------------------------------------------------------
- */
-void
-Dir_InitDot(void)
-{
- if (dot != NULL) {
- LstNode ln;
-
- /* Remove old entry from openDirectories, but do not destroy. */
- ln = Lst_Member(openDirectories, dot);
- (void)Lst_Remove(openDirectories, ln);
- }
-
- dot = Dir_AddDir(NULL, ".");
-
- if (dot == NULL) {
- Error("Cannot open `.' (%s)", strerror(errno));
- exit(1);
- }
-
- /*
- * We always need to have dot around, so we increment its reference count
- * to make sure it's not destroyed.
- */
- dot->refCount += 1;
- Dir_SetPATH(); /* initialize */
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Dir_End --
- * cleanup things for this module
- *
- * Results:
- * none
- *
- * Side Effects:
- * none
- *-----------------------------------------------------------------------
- */
-void
-Dir_End(void)
-{
-#ifdef CLEANUP
- if (cur) {
- cur->refCount -= 1;
- Dir_Destroy(cur);
- }
- dot->refCount -= 1;
- dotLast->refCount -= 1;
- Dir_Destroy(dotLast);
- Dir_Destroy(dot);
- Dir_ClearPath(dirSearchPath);
- Lst_Destroy(dirSearchPath, NULL);
- Dir_ClearPath(openDirectories);
- Lst_Destroy(openDirectories, NULL);
- Hash_DeleteTable(&mtimes);
-#endif
-}
-
-/*
- * We want ${.PATH} to indicate the order in which we will actually
- * search, so we rebuild it after any .PATH: target.
- * This is the simplest way to deal with the effect of .DOTLAST.
- */
-void
-Dir_SetPATH(void)
-{
- LstNode ln; /* a list element */
- Path *p;
- Boolean hasLastDot = FALSE; /* true we should search dot last */
-
- Var_Delete(".PATH", VAR_GLOBAL);
-
- if (Lst_Open(dirSearchPath) == SUCCESS) {
- if ((ln = Lst_First(dirSearchPath)) != NULL) {
- p = (Path *)Lst_Datum(ln);
- if (p == dotLast) {
- hasLastDot = TRUE;
- Var_Append(".PATH", dotLast->name, VAR_GLOBAL);
- }
- }
-
- if (!hasLastDot) {
- if (dot)
- Var_Append(".PATH", dot->name, VAR_GLOBAL);
- if (cur)
- Var_Append(".PATH", cur->name, VAR_GLOBAL);
- }
-
- while ((ln = Lst_Next(dirSearchPath)) != NULL) {
- p = (Path *)Lst_Datum(ln);
- if (p == dotLast)
- continue;
- if (p == dot && hasLastDot)
- continue;
- Var_Append(".PATH", p->name, VAR_GLOBAL);
- }
-
- if (hasLastDot) {
- if (dot)
- Var_Append(".PATH", dot->name, VAR_GLOBAL);
- if (cur)
- Var_Append(".PATH", cur->name, VAR_GLOBAL);
- }
- Lst_Close(dirSearchPath);
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * DirFindName --
- * See if the Path structure describes the same directory as the
- * given one by comparing their names. Called from Dir_AddDir via
- * Lst_Find when searching the list of open directories.
- *
- * Input:
- * p Current name
- * dname Desired name
- *
- * Results:
- * 0 if it is the same. Non-zero otherwise
- *
- * Side Effects:
- * None
- *-----------------------------------------------------------------------
- */
-static int
-DirFindName(const void *p, const void *dname)
-{
- return (strcmp(((const Path *)p)->name, dname));
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Dir_HasWildcards --
- * see if the given name has any wildcard characters in it
- * be careful not to expand unmatching brackets or braces.
- * XXX: This code is not 100% correct. ([^]] fails etc.)
- * I really don't think that make(1) should be expanding
- * patterns, because then you have to set a mechanism for
- * escaping the expansion!
- *
- * Input:
- * name name to check
- *
- * Results:
- * returns TRUE if the word should be expanded, FALSE otherwise
- *
- * Side Effects:
- * none
- *-----------------------------------------------------------------------
- */
-Boolean
-Dir_HasWildcards(char *name)
-{
- char *cp;
- int wild = 0, brace = 0, bracket = 0;
-
- for (cp = name; *cp; cp++) {
- switch(*cp) {
- case '{':
- brace++;
- wild = 1;
- break;
- case '}':
- brace--;
- break;
- case '[':
- bracket++;
- wild = 1;
- break;
- case ']':
- bracket--;
- break;
- case '?':
- case '*':
- wild = 1;
- break;
- default:
- break;
- }
- }
- return wild && bracket == 0 && brace == 0;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * DirMatchFiles --
- * Given a pattern and a Path structure, see if any files
- * match the pattern and add their names to the 'expansions' list if
- * any do. This is incomplete -- it doesn't take care of patterns like
- * src / *src / *.c properly (just *.c on any of the directories), but it
- * will do for now.
- *
- * Input:
- * pattern Pattern to look for
- * p Directory to search
- * expansion Place to store the results
- *
- * Results:
- * Always returns 0
- *
- * Side Effects:
- * File names are added to the expansions lst. The directory will be
- * fully hashed when this is done.
- *-----------------------------------------------------------------------
- */
-static int
-DirMatchFiles(const char *pattern, Path *p, Lst expansions)
-{
- Hash_Search search; /* Index into the directory's table */
- Hash_Entry *entry; /* Current entry in the table */
- Boolean isDot; /* TRUE if the directory being searched is . */
-
- isDot = (*p->name == '.' && p->name[1] == '\0');
-
- for (entry = Hash_EnumFirst(&p->files, &search);
- entry != NULL;
- entry = Hash_EnumNext(&search))
- {
- /*
- * See if the file matches the given pattern. Note we follow the UNIX
- * convention that dot files will only be found if the pattern
- * begins with a dot (note also that as a side effect of the hashing
- * scheme, .* won't match . or .. since they aren't hashed).
- */
- if (Str_Match(entry->name, pattern) &&
- ((entry->name[0] != '.') ||
- (pattern[0] == '.')))
- {
- (void)Lst_AtEnd(expansions,
- (isDot ? bmake_strdup(entry->name) :
- str_concat(p->name, entry->name,
- STR_ADDSLASH)));
- }
- }
- return (0);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * DirExpandCurly --
- * Expand curly braces like the C shell. Does this recursively.
- * Note the special case: if after the piece of the curly brace is
- * done there are no wildcard characters in the result, the result is
- * placed on the list WITHOUT CHECKING FOR ITS EXISTENCE.
- *
- * Input:
- * word Entire word to expand
- * brace First curly brace in it
- * path Search path to use
- * expansions Place to store the expansions
- *
- * Results:
- * None.
- *
- * Side Effects:
- * The given list is filled with the expansions...
- *
- *-----------------------------------------------------------------------
- */
-static void
-DirExpandCurly(const char *word, const char *brace, Lst path, Lst expansions)
-{
- const char *end; /* Character after the closing brace */
- const char *cp; /* Current position in brace clause */
- const char *start; /* Start of current piece of brace clause */
- int bracelevel; /* Number of braces we've seen. If we see a
- * right brace when this is 0, we've hit the
- * end of the clause. */
- char *file; /* Current expansion */
- int otherLen; /* The length of the other pieces of the
- * expansion (chars before and after the
- * clause in 'word') */
- char *cp2; /* Pointer for checking for wildcards in
- * expansion before calling Dir_Expand */
-
- start = brace+1;
-
- /*
- * Find the end of the brace clause first, being wary of nested brace
- * clauses.
- */
- for (end = start, bracelevel = 0; *end != '\0'; end++) {
- if (*end == '{') {
- bracelevel++;
- } else if ((*end == '}') && (bracelevel-- == 0)) {
- break;
- }
- }
- if (*end == '\0') {
- Error("Unterminated {} clause \"%s\"", start);
- return;
- } else {
- end++;
- }
- otherLen = brace - word + strlen(end);
-
- for (cp = start; cp < end; cp++) {
- /*
- * Find the end of this piece of the clause.
- */
- bracelevel = 0;
- while (*cp != ',') {
- if (*cp == '{') {
- bracelevel++;
- } else if ((*cp == '}') && (bracelevel-- <= 0)) {
- break;
- }
- cp++;
- }
- /*
- * Allocate room for the combination and install the three pieces.
- */
- file = bmake_malloc(otherLen + cp - start + 1);
- if (brace != word) {
- strncpy(file, word, brace-word);
- }
- if (cp != start) {
- strncpy(&file[brace-word], start, cp-start);
- }
- strcpy(&file[(brace-word)+(cp-start)], end);
-
- /*
- * See if the result has any wildcards in it. If we find one, call
- * Dir_Expand right away, telling it to place the result on our list
- * of expansions.
- */
- for (cp2 = file; *cp2 != '\0'; cp2++) {
- switch(*cp2) {
- case '*':
- case '?':
- case '{':
- case '[':
- Dir_Expand(file, path, expansions);
- goto next;
- }
- }
- if (*cp2 == '\0') {
- /*
- * Hit the end w/o finding any wildcards, so stick the expansion
- * on the end of the list.
- */
- (void)Lst_AtEnd(expansions, file);
- } else {
- next:
- free(file);
- }
- start = cp+1;
- }
-}
-
-
-/*-
- *-----------------------------------------------------------------------
- * DirExpandInt --
- * Internal expand routine. Passes through the directories in the
- * path one by one, calling DirMatchFiles for each. NOTE: This still
- * doesn't handle patterns in directories...
- *
- * Input:
- * word Word to expand
- * path Path on which to look
- * expansions Place to store the result
- *
- * Results:
- * None.
- *
- * Side Effects:
- * Things are added to the expansions list.
- *
- *-----------------------------------------------------------------------
- */
-static void
-DirExpandInt(const char *word, Lst path, Lst expansions)
-{
- LstNode ln; /* Current node */
- Path *p; /* Directory in the node */
-
- if (Lst_Open(path) == SUCCESS) {
- while ((ln = Lst_Next(path)) != NULL) {
- p = (Path *)Lst_Datum(ln);
- DirMatchFiles(word, p, expansions);
- }
- Lst_Close(path);
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * DirPrintWord --
- * Print a word in the list of expansions. Callback for Dir_Expand
- * when DEBUG(DIR), via Lst_ForEach.
- *
- * Results:
- * === 0
- *
- * Side Effects:
- * The passed word is printed, followed by a space.
- *
- *-----------------------------------------------------------------------
- */
-static int
-DirPrintWord(void *word, void *dummy MAKE_ATTR_UNUSED)
-{
- fprintf(debug_file, "%s ", (char *)word);
-
- return 0;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Dir_Expand --
- * Expand the given word into a list of words by globbing it looking
- * in the directories on the given search path.
- *
- * Input:
- * word the word to expand
- * path the list of directories in which to find the
- * resulting files
- * expansions the list on which to place the results
- *
- * Results:
- * A list of words consisting of the files which exist along the search
- * path matching the given pattern.
- *
- * Side Effects:
- * Directories may be opened. Who knows?
- *-----------------------------------------------------------------------
- */
-void
-Dir_Expand(const char *word, Lst path, Lst expansions)
-{
- const char *cp;
-
- if (DEBUG(DIR)) {
- fprintf(debug_file, "Expanding \"%s\"... ", word);
- }
-
- cp = strchr(word, '{');
- if (cp) {
- DirExpandCurly(word, cp, path, expansions);
- } else {
- cp = strchr(word, '/');
- if (cp) {
- /*
- * The thing has a directory component -- find the first wildcard
- * in the string.
- */
- for (cp = word; *cp; cp++) {
- if (*cp == '?' || *cp == '[' || *cp == '*' || *cp == '{') {
- break;
- }
- }
- if (*cp == '{') {
- /*
- * This one will be fun.
- */
- DirExpandCurly(word, cp, path, expansions);
- return;
- } else if (*cp != '\0') {
- /*
- * Back up to the start of the component
- */
- char *dirpath;
-
- while (cp > word && *cp != '/') {
- cp--;
- }
- if (cp != word) {
- char sc;
- /*
- * If the glob isn't in the first component, try and find
- * all the components up to the one with a wildcard.
- */
- sc = cp[1];
- ((char *)UNCONST(cp))[1] = '\0';
- dirpath = Dir_FindFile(word, path);
- ((char *)UNCONST(cp))[1] = sc;
- /*
- * dirpath is null if can't find the leading component
- * XXX: Dir_FindFile won't find internal components.
- * i.e. if the path contains ../Etc/Object and we're
- * looking for Etc, it won't be found. Ah well.
- * Probably not important.
- */
- if (dirpath != NULL) {
- char *dp = &dirpath[strlen(dirpath) - 1];
- if (*dp == '/')
- *dp = '\0';
- path = Lst_Init(FALSE);
- (void)Dir_AddDir(path, dirpath);
- DirExpandInt(cp+1, path, expansions);
- Lst_Destroy(path, NULL);
- }
- } else {
- /*
- * Start the search from the local directory
- */
- DirExpandInt(word, path, expansions);
- }
- } else {
- /*
- * Return the file -- this should never happen.
- */
- DirExpandInt(word, path, expansions);
- }
- } else {
- /*
- * First the files in dot
- */
- DirMatchFiles(word, dot, expansions);
-
- /*
- * Then the files in every other directory on the path.
- */
- DirExpandInt(word, path, expansions);
- }
- }
- if (DEBUG(DIR)) {
- Lst_ForEach(expansions, DirPrintWord, NULL);
- fprintf(debug_file, "\n");
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * DirLookup --
- * Find if the file with the given name exists in the given path.
- *
- * Results:
- * The path to the file or NULL. This path is guaranteed to be in a
- * different part of memory than name and so may be safely free'd.
- *
- * Side Effects:
- * None.
- *-----------------------------------------------------------------------
- */
-static char *
-DirLookup(Path *p, const char *name MAKE_ATTR_UNUSED, const char *cp,
- Boolean hasSlash MAKE_ATTR_UNUSED)
-{
- char *file; /* the current filename to check */
-
- if (DEBUG(DIR)) {
- fprintf(debug_file, " %s ...\n", p->name);
- }
-
- if (Hash_FindEntry(&p->files, cp) == NULL)
- return NULL;
-
- file = str_concat(p->name, cp, STR_ADDSLASH);
- if (DEBUG(DIR)) {
- fprintf(debug_file, " returning %s\n", file);
- }
- p->hits += 1;
- hits += 1;
- return file;
-}
-
-
-/*-
- *-----------------------------------------------------------------------
- * DirLookupSubdir --
- * Find if the file with the given name exists in the given path.
- *
- * Results:
- * The path to the file or NULL. This path is guaranteed to be in a
- * different part of memory than name and so may be safely free'd.
- *
- * Side Effects:
- * If the file is found, it is added in the modification times hash
- * table.
- *-----------------------------------------------------------------------
- */
-static char *
-DirLookupSubdir(Path *p, const char *name)
-{
- struct stat stb; /* Buffer for stat, if necessary */
- char *file; /* the current filename to check */
-
- if (p != dot) {
- file = str_concat(p->name, name, STR_ADDSLASH);
- } else {
- /*
- * Checking in dot -- DON'T put a leading ./ on the thing.
- */
- file = bmake_strdup(name);
- }
-
- if (DEBUG(DIR)) {
- fprintf(debug_file, "checking %s ...\n", file);
- }
-
- if (cached_stat(file, &stb) == 0) {
- nearmisses += 1;
- return (file);
- }
- free(file);
- return NULL;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * DirLookupAbs --
- * Find if the file with the given name exists in the given path.
- *
- * Results:
- * The path to the file, the empty string or NULL. If the file is
- * the empty string, the search should be terminated.
- * This path is guaranteed to be in a different part of memory
- * than name and so may be safely free'd.
- *
- * Side Effects:
- * None.
- *-----------------------------------------------------------------------
- */
-static char *
-DirLookupAbs(Path *p, const char *name, const char *cp)
-{
- char *p1; /* pointer into p->name */
- const char *p2; /* pointer into name */
-
- if (DEBUG(DIR)) {
- fprintf(debug_file, " %s ...\n", p->name);
- }
-
- /*
- * If the file has a leading path component and that component
- * exactly matches the entire name of the current search
- * directory, we can attempt another cache lookup. And if we don't
- * have a hit, we can safely assume the file does not exist at all.
- */
- for (p1 = p->name, p2 = name; *p1 && *p1 == *p2; p1++, p2++) {
- continue;
- }
- if (*p1 != '\0' || p2 != cp - 1) {
- return NULL;
- }
-
- if (Hash_FindEntry(&p->files, cp) == NULL) {
- if (DEBUG(DIR)) {
- fprintf(debug_file, " must be here but isn't -- returning\n");
- }
- /* Return empty string: terminates search */
- return bmake_strdup("");
- }
-
- p->hits += 1;
- hits += 1;
- if (DEBUG(DIR)) {
- fprintf(debug_file, " returning %s\n", name);
- }
- return (bmake_strdup(name));
-}
-
-/*-
- *-----------------------------------------------------------------------
- * DirFindDot --
- * Find the file given on "." or curdir
- *
- * Results:
- * The path to the file or NULL. This path is guaranteed to be in a
- * different part of memory than name and so may be safely free'd.
- *
- * Side Effects:
- * Hit counts change
- *-----------------------------------------------------------------------
- */
-static char *
-DirFindDot(Boolean hasSlash MAKE_ATTR_UNUSED, const char *name, const char *cp)
-{
-
- if (Hash_FindEntry(&dot->files, cp) != NULL) {
- if (DEBUG(DIR)) {
- fprintf(debug_file, " in '.'\n");
- }
- hits += 1;
- dot->hits += 1;
- return (bmake_strdup(name));
- }
- if (cur &&
- Hash_FindEntry(&cur->files, cp) != NULL) {
- if (DEBUG(DIR)) {
- fprintf(debug_file, " in ${.CURDIR} = %s\n", cur->name);
- }
- hits += 1;
- cur->hits += 1;
- return str_concat(cur->name, cp, STR_ADDSLASH);
- }
-
- return NULL;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Dir_FindFile --
- * Find the file with the given name along the given search path.
- *
- * Input:
- * name the file to find
- * path the Lst of directories to search
- *
- * Results:
- * The path to the file or NULL. This path is guaranteed to be in a
- * different part of memory than name and so may be safely free'd.
- *
- * Side Effects:
- * If the file is found in a directory which is not on the path
- * already (either 'name' is absolute or it is a relative path
- * [ dir1/.../dirn/file ] which exists below one of the directories
- * already on the search path), its directory is added to the end
- * of the path on the assumption that there will be more files in
- * that directory later on. Sometimes this is true. Sometimes not.
- *-----------------------------------------------------------------------
- */
-char *
-Dir_FindFile(const char *name, Lst path)
-{
- LstNode ln; /* a list element */
- char *file; /* the current filename to check */
- Path *p; /* current path member */
- const char *cp; /* Terminal name of file */
- Boolean hasLastDot = FALSE; /* true we should search dot last */
- Boolean hasSlash; /* true if 'name' contains a / */
- struct stat stb; /* Buffer for stat, if necessary */
- const char *trailing_dot = ".";
-
- /*
- * Find the final component of the name and note whether it has a
- * slash in it (the name, I mean)
- */
- cp = strrchr(name, '/');
- if (cp) {
- hasSlash = TRUE;
- cp += 1;
- } else {
- hasSlash = FALSE;
- cp = name;
- }
-
- if (DEBUG(DIR)) {
- fprintf(debug_file, "Searching for %s ...", name);
- }
-
- if (Lst_Open(path) == FAILURE) {
- if (DEBUG(DIR)) {
- fprintf(debug_file, "couldn't open path, file not found\n");
- }
- misses += 1;
- return NULL;
- }
-
- if ((ln = Lst_First(path)) != NULL) {
- p = (Path *)Lst_Datum(ln);
- if (p == dotLast) {
- hasLastDot = TRUE;
- if (DEBUG(DIR))
- fprintf(debug_file, "[dot last]...");
- }
- }
- if (DEBUG(DIR)) {
- fprintf(debug_file, "\n");
- }
-
- /*
- * If there's no leading directory components or if the leading
- * directory component is exactly `./', consult the cached contents
- * of each of the directories on the search path.
- */
- if (!hasSlash || (cp - name == 2 && *name == '.')) {
- /*
- * We look through all the directories on the path seeking one which
- * contains the final component of the given name. If such a beast
- * is found, we concatenate the directory name and the final
- * component and return the resulting string. If we don't find any
- * such thing, we go on to phase two...
- *
- * No matter what, we always look for the file in the current
- * directory before anywhere else (unless we found the magic
- * DOTLAST path, in which case we search it last) and we *do not*
- * add the ./ to it if it exists.
- * This is so there are no conflicts between what the user
- * specifies (fish.c) and what pmake finds (./fish.c).
- */
- if (!hasLastDot &&
- (file = DirFindDot(hasSlash, name, cp)) != NULL) {
- Lst_Close(path);
- return file;
- }
-
- while ((ln = Lst_Next(path)) != NULL) {
- p = (Path *)Lst_Datum(ln);
- if (p == dotLast)
- continue;
- if ((file = DirLookup(p, name, cp, hasSlash)) != NULL) {
- Lst_Close(path);
- return file;
- }
- }
-
- if (hasLastDot &&
- (file = DirFindDot(hasSlash, name, cp)) != NULL) {
- Lst_Close(path);
- return file;
- }
- }
- Lst_Close(path);
-
- /*
- * We didn't find the file on any directory in the search path.
- * If the name doesn't contain a slash, that means it doesn't exist.
- * If it *does* contain a slash, however, there is still hope: it
- * could be in a subdirectory of one of the members of the search
- * path. (eg. /usr/include and sys/types.h. The above search would
- * fail to turn up types.h in /usr/include, but it *is* in
- * /usr/include/sys/types.h).
- * [ This no longer applies: If we find such a beast, we assume there
- * will be more (what else can we assume?) and add all but the last
- * component of the resulting name onto the search path (at the
- * end).]
- * This phase is only performed if the file is *not* absolute.
- */
- if (!hasSlash) {
- if (DEBUG(DIR)) {
- fprintf(debug_file, " failed.\n");
- }
- misses += 1;
- return NULL;
- }
-
- if (*cp == '\0') {
- /* we were given a trailing "/" */
- cp = trailing_dot;
- }
-
- if (name[0] != '/') {
- Boolean checkedDot = FALSE;
-
- if (DEBUG(DIR)) {
- fprintf(debug_file, " Trying subdirectories...\n");
- }
-
- if (!hasLastDot) {
- if (dot) {
- checkedDot = TRUE;
- if ((file = DirLookupSubdir(dot, name)) != NULL)
- return file;
- }
- if (cur && (file = DirLookupSubdir(cur, name)) != NULL)
- return file;
- }
-
- (void)Lst_Open(path);
- while ((ln = Lst_Next(path)) != NULL) {
- p = (Path *)Lst_Datum(ln);
- if (p == dotLast)
- continue;
- if (p == dot) {
- if (checkedDot)
- continue;
- checkedDot = TRUE;
- }
- if ((file = DirLookupSubdir(p, name)) != NULL) {
- Lst_Close(path);
- return file;
- }
- }
- Lst_Close(path);
-
- if (hasLastDot) {
- if (dot && !checkedDot) {
- checkedDot = TRUE;
- if ((file = DirLookupSubdir(dot, name)) != NULL)
- return file;
- }
- if (cur && (file = DirLookupSubdir(cur, name)) != NULL)
- return file;
- }
-
- if (checkedDot) {
- /*
- * Already checked by the given name, since . was in the path,
- * so no point in proceeding...
- */
- if (DEBUG(DIR)) {
- fprintf(debug_file, " Checked . already, returning NULL\n");
- }
- return NULL;
- }
-
- } else { /* name[0] == '/' */
-
- /*
- * For absolute names, compare directory path prefix against the
- * the directory path of each member on the search path for an exact
- * match. If we have an exact match on any member of the search path,
- * use the cached contents of that member to lookup the final file
- * component. If that lookup fails we can safely assume that the
- * file does not exist at all. This is signified by DirLookupAbs()
- * returning an empty string.
- */
- if (DEBUG(DIR)) {
- fprintf(debug_file, " Trying exact path matches...\n");
- }
-
- if (!hasLastDot && cur && ((file = DirLookupAbs(cur, name, cp))
- != NULL)) {
- if (file[0] == '\0') {
- free(file);
- return NULL;
- }
- return file;
- }
-
- (void)Lst_Open(path);
- while ((ln = Lst_Next(path)) != NULL) {
- p = (Path *)Lst_Datum(ln);
- if (p == dotLast)
- continue;
- if ((file = DirLookupAbs(p, name, cp)) != NULL) {
- Lst_Close(path);
- if (file[0] == '\0') {
- free(file);
- return NULL;
- }
- return file;
- }
- }
- Lst_Close(path);
-
- if (hasLastDot && cur && ((file = DirLookupAbs(cur, name, cp))
- != NULL)) {
- if (file[0] == '\0') {
- free(file);
- return NULL;
- }
- return file;
- }
- }
-
- /*
- * Didn't find it that way, either. Sigh. Phase 3. Add its directory
- * onto the search path in any case, just in case, then look for the
- * thing in the hash table. If we find it, grand. We return a new
- * copy of the name. Otherwise we sadly return a NULL pointer. Sigh.
- * Note that if the directory holding the file doesn't exist, this will
- * do an extra search of the final directory on the path. Unless something
- * weird happens, this search won't succeed and life will be groovy.
- *
- * Sigh. We cannot add the directory onto the search path because
- * of this amusing case:
- * $(INSTALLDIR)/$(FILE): $(FILE)
- *
- * $(FILE) exists in $(INSTALLDIR) but not in the current one.
- * When searching for $(FILE), we will find it in $(INSTALLDIR)
- * b/c we added it here. This is not good...
- */
-#ifdef notdef
- if (cp == traling_dot) {
- cp = strrchr(name, '/');
- cp += 1;
- }
- cp[-1] = '\0';
- (void)Dir_AddDir(path, name);
- cp[-1] = '/';
-
- bigmisses += 1;
- ln = Lst_Last(path);
- if (ln == NULL) {
- return NULL;
- } else {
- p = (Path *)Lst_Datum(ln);
- }
-
- if (Hash_FindEntry(&p->files, cp) != NULL) {
- return (bmake_strdup(name));
- } else {
- return NULL;
- }
-#else /* !notdef */
- if (DEBUG(DIR)) {
- fprintf(debug_file, " Looking for \"%s\" ...\n", name);
- }
-
- bigmisses += 1;
- if (cached_stat(name, &stb) == 0) {
- return (bmake_strdup(name));
- }
-
- if (DEBUG(DIR)) {
- fprintf(debug_file, " failed. Returning NULL\n");
- }
- return NULL;
-#endif /* notdef */
-}
-
-
-/*-
- *-----------------------------------------------------------------------
- * Dir_FindHereOrAbove --
- * search for a path starting at a given directory and then working
- * our way up towards the root.
- *
- * Input:
- * here starting directory
- * search_path the path we are looking for
- * result the result of a successful search is placed here
- * rlen the length of the result buffer
- * (typically MAXPATHLEN + 1)
- *
- * Results:
- * 0 on failure, 1 on success [in which case the found path is put
- * in the result buffer].
- *
- * Side Effects:
- *-----------------------------------------------------------------------
- */
-int
-Dir_FindHereOrAbove(char *here, char *search_path, char *result, int rlen) {
-
- struct stat st;
- char dirbase[MAXPATHLEN + 1], *db_end;
- char try[MAXPATHLEN + 1], *try_end;
-
- /* copy out our starting point */
- snprintf(dirbase, sizeof(dirbase), "%s", here);
- db_end = dirbase + strlen(dirbase);
-
- /* loop until we determine a result */
- while (1) {
-
- /* try and stat(2) it ... */
- snprintf(try, sizeof(try), "%s/%s", dirbase, search_path);
- if (cached_stat(try, &st) != -1) {
- /*
- * success! if we found a file, chop off
- * the filename so we return a directory.
- */
- if ((st.st_mode & S_IFMT) != S_IFDIR) {
- try_end = try + strlen(try);
- while (try_end > try && *try_end != '/')
- try_end--;
- if (try_end > try)
- *try_end = 0; /* chop! */
- }
-
- /*
- * done!
- */
- snprintf(result, rlen, "%s", try);
- return(1);
- }
-
- /*
- * nope, we didn't find it. if we used up dirbase we've
- * reached the root and failed.
- */
- if (db_end == dirbase)
- break; /* failed! */
-
- /*
- * truncate dirbase from the end to move up a dir
- */
- while (db_end > dirbase && *db_end != '/')
- db_end--;
- *db_end = 0; /* chop! */
-
- } /* while (1) */
-
- /*
- * we failed...
- */
- return(0);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Dir_MTime --
- * Find the modification time of the file described by gn along the
- * search path dirSearchPath.
- *
- * Input:
- * gn the file whose modification time is desired
- *
- * Results:
- * The modification time or 0 if it doesn't exist
- *
- * Side Effects:
- * The modification time is placed in the node's mtime slot.
- * If the node didn't have a path entry before, and Dir_FindFile
- * found one for it, the full name is placed in the path slot.
- *-----------------------------------------------------------------------
- */
-int
-Dir_MTime(GNode *gn, Boolean recheck)
-{
- char *fullName; /* the full pathname of name */
- struct stat stb; /* buffer for finding the mod time */
-
- if (gn->type & OP_ARCHV) {
- return Arch_MTime(gn);
- } else if (gn->type & OP_PHONY) {
- gn->mtime = 0;
- return 0;
- } else if (gn->path == NULL) {
- if (gn->type & OP_NOPATH)
- fullName = NULL;
- else {
- fullName = Dir_FindFile(gn->name, Suff_FindPath(gn));
- if (fullName == NULL && gn->flags & FROM_DEPEND &&
- !Lst_IsEmpty(gn->iParents)) {
- char *cp;
-
- cp = strrchr(gn->name, '/');
- if (cp) {
- /*
- * This is an implied source, and it may have moved,
- * see if we can find it via the current .PATH
- */
- cp++;
-
- fullName = Dir_FindFile(cp, Suff_FindPath(gn));
- if (fullName) {
- /*
- * Put the found file in gn->path
- * so that we give that to the compiler.
- */
- gn->path = bmake_strdup(fullName);
- if (!Job_RunTarget(".STALE", gn->fname))
- fprintf(stdout,
- "%s: %s, %d: ignoring stale %s for %s, "
- "found %s\n", progname, gn->fname, gn->lineno,
- makeDependfile, gn->name, fullName);
- }
- }
- }
- if (DEBUG(DIR))
- fprintf(debug_file, "Found '%s' as '%s'\n",
- gn->name, fullName ? fullName : "(not found)" );
- }
- } else {
- fullName = gn->path;
- }
-
- if (fullName == NULL) {
- fullName = bmake_strdup(gn->name);
- }
-
- if (cached_stats(&mtimes, fullName, &stb, recheck ? CST_UPDATE : 0) < 0) {
- if (gn->type & OP_MEMBER) {
- if (fullName != gn->path)
- free(fullName);
- return Arch_MemMTime(gn);
- } else {
- stb.st_mtime = 0;
- }
- }
-
- if (fullName && gn->path == NULL) {
- gn->path = fullName;
- }
-
- gn->mtime = stb.st_mtime;
- return (gn->mtime);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Dir_AddDir --
- * Add the given name to the end of the given path. The order of
- * the arguments is backwards so ParseDoDependency can do a
- * Lst_ForEach of its list of paths...
- *
- * Input:
- * path the path to which the directory should be
- * added
- * name the name of the directory to add
- *
- * Results:
- * none
- *
- * Side Effects:
- * A structure is added to the list and the directory is
- * read and hashed.
- *-----------------------------------------------------------------------
- */
-Path *
-Dir_AddDir(Lst path, const char *name)
-{
- LstNode ln = NULL; /* node in case Path structure is found */
- Path *p = NULL; /* pointer to new Path structure */
- DIR *d; /* for reading directory */
- struct dirent *dp; /* entry in directory */
-
- if (strcmp(name, ".DOTLAST") == 0) {
- ln = Lst_Find(path, name, DirFindName);
- if (ln != NULL)
- return (Path *)Lst_Datum(ln);
- else {
- dotLast->refCount += 1;
- (void)Lst_AtFront(path, dotLast);
- }
- }
-
- if (path)
- ln = Lst_Find(openDirectories, name, DirFindName);
- if (ln != NULL) {
- p = (Path *)Lst_Datum(ln);
- if (path && Lst_Member(path, p) == NULL) {
- p->refCount += 1;
- (void)Lst_AtEnd(path, p);
- }
- } else {
- if (DEBUG(DIR)) {
- fprintf(debug_file, "Caching %s ...", name);
- }
-
- if ((d = opendir(name)) != NULL) {
- p = bmake_malloc(sizeof(Path));
- p->name = bmake_strdup(name);
- p->hits = 0;
- p->refCount = 1;
- Hash_InitTable(&p->files, -1);
-
- while ((dp = readdir(d)) != NULL) {
-#if defined(sun) && defined(d_ino) /* d_ino is a sunos4 #define for d_fileno */
- /*
- * The sun directory library doesn't check for a 0 inode
- * (0-inode slots just take up space), so we have to do
- * it ourselves.
- */
- if (dp->d_fileno == 0) {
- continue;
- }
-#endif /* sun && d_ino */
- (void)Hash_CreateEntry(&p->files, dp->d_name, NULL);
- }
- (void)closedir(d);
- (void)Lst_AtEnd(openDirectories, p);
- if (path != NULL)
- (void)Lst_AtEnd(path, p);
- }
- if (DEBUG(DIR)) {
- fprintf(debug_file, "done\n");
- }
- }
- return p;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Dir_CopyDir --
- * Callback function for duplicating a search path via Lst_Duplicate.
- * Ups the reference count for the directory.
- *
- * Results:
- * Returns the Path it was given.
- *
- * Side Effects:
- * The refCount of the path is incremented.
- *
- *-----------------------------------------------------------------------
- */
-void *
-Dir_CopyDir(void *p)
-{
- ((Path *)p)->refCount += 1;
-
- return (p);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Dir_MakeFlags --
- * Make a string by taking all the directories in the given search
- * path and preceding them by the given flag. Used by the suffix
- * module to create variables for compilers based on suffix search
- * paths.
- *
- * Input:
- * flag flag which should precede each directory
- * path list of directories
- *
- * Results:
- * The string mentioned above. Note that there is no space between
- * the given flag and each directory. The empty string is returned if
- * Things don't go well.
- *
- * Side Effects:
- * None
- *-----------------------------------------------------------------------
- */
-char *
-Dir_MakeFlags(const char *flag, Lst path)
-{
- char *str; /* the string which will be returned */
- char *s1, *s2;/* the current directory preceded by 'flag' */
- LstNode ln; /* the node of the current directory */
- Path *p; /* the structure describing the current directory */
-
- str = bmake_strdup("");
-
- if (Lst_Open(path) == SUCCESS) {
- while ((ln = Lst_Next(path)) != NULL) {
- p = (Path *)Lst_Datum(ln);
- s2 = str_concat(flag, p->name, 0);
- str = str_concat(s1 = str, s2, STR_ADDSPACE);
- free(s1);
- free(s2);
- }
- Lst_Close(path);
- }
-
- return (str);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Dir_Destroy --
- * Nuke a directory descriptor, if possible. Callback procedure
- * for the suffixes module when destroying a search path.
- *
- * Input:
- * pp The directory descriptor to nuke
- *
- * Results:
- * None.
- *
- * Side Effects:
- * If no other path references this directory (refCount == 0),
- * the Path and all its data are freed.
- *
- *-----------------------------------------------------------------------
- */
-void
-Dir_Destroy(void *pp)
-{
- Path *p = (Path *)pp;
- p->refCount -= 1;
-
- if (p->refCount == 0) {
- LstNode ln;
-
- ln = Lst_Member(openDirectories, p);
- (void)Lst_Remove(openDirectories, ln);
-
- Hash_DeleteTable(&p->files);
- free(p->name);
- free(p);
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Dir_ClearPath --
- * Clear out all elements of the given search path. This is different
- * from destroying the list, notice.
- *
- * Input:
- * path Path to clear
- *
- * Results:
- * None.
- *
- * Side Effects:
- * The path is set to the empty list.
- *
- *-----------------------------------------------------------------------
- */
-void
-Dir_ClearPath(Lst path)
-{
- Path *p;
- while (!Lst_IsEmpty(path)) {
- p = (Path *)Lst_DeQueue(path);
- Dir_Destroy(p);
- }
-}
-
-
-/*-
- *-----------------------------------------------------------------------
- * Dir_Concat --
- * Concatenate two paths, adding the second to the end of the first.
- * Makes sure to avoid duplicates.
- *
- * Input:
- * path1 Dest
- * path2 Source
- *
- * Results:
- * None
- *
- * Side Effects:
- * Reference counts for added dirs are upped.
- *
- *-----------------------------------------------------------------------
- */
-void
-Dir_Concat(Lst path1, Lst path2)
-{
- LstNode ln;
- Path *p;
-
- for (ln = Lst_First(path2); ln != NULL; ln = Lst_Succ(ln)) {
- p = (Path *)Lst_Datum(ln);
- if (Lst_Member(path1, p) == NULL) {
- p->refCount += 1;
- (void)Lst_AtEnd(path1, p);
- }
- }
-}
-
-/********** DEBUG INFO **********/
-void
-Dir_PrintDirectories(void)
-{
- LstNode ln;
- Path *p;
-
- fprintf(debug_file, "#*** Directory Cache:\n");
- fprintf(debug_file, "# Stats: %d hits %d misses %d near misses %d losers (%d%%)\n",
- hits, misses, nearmisses, bigmisses,
- (hits+bigmisses+nearmisses ?
- hits * 100 / (hits + bigmisses + nearmisses) : 0));
- fprintf(debug_file, "# %-20s referenced\thits\n", "directory");
- if (Lst_Open(openDirectories) == SUCCESS) {
- while ((ln = Lst_Next(openDirectories)) != NULL) {
- p = (Path *)Lst_Datum(ln);
- fprintf(debug_file, "# %-20s %10d\t%4d\n", p->name, p->refCount, p->hits);
- }
- Lst_Close(openDirectories);
- }
-}
-
-static int
-DirPrintDir(void *p, void *dummy MAKE_ATTR_UNUSED)
-{
- fprintf(debug_file, "%s ", ((Path *)p)->name);
- return 0;
-}
-
-void
-Dir_PrintPath(Lst path)
-{
- Lst_ForEach(path, DirPrintDir, NULL);
-}
diff --git a/usr.bin/make/dir.h b/usr.bin/make/dir.h
deleted file mode 100644
index 52ab35e..0000000
--- a/usr.bin/make/dir.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/* $NetBSD: dir.h,v 1.18 2017/05/31 22:02:06 maya Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- *
- * from: @(#)dir.h 8.1 (Berkeley) 6/6/93
- */
-
-/*
- * Copyright (c) 1988, 1989 by Adam de Boor
- * Copyright (c) 1989 by Berkeley Softworks
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. 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.
- *
- * from: @(#)dir.h 8.1 (Berkeley) 6/6/93
- */
-
-/* dir.h --
- */
-
-#ifndef MAKE_DIR_H
-#define MAKE_DIR_H
-
-typedef struct Path {
- char *name; /* Name of directory */
- int refCount; /* Number of paths with this directory */
- int hits; /* the number of times a file in this
- * directory has been found */
- Hash_Table files; /* Hash table of files in directory */
-} Path;
-
-void Dir_Init(const char *);
-void Dir_InitCur(const char *);
-void Dir_InitDot(void);
-void Dir_End(void);
-void Dir_SetPATH(void);
-Boolean Dir_HasWildcards(char *);
-void Dir_Expand(const char *, Lst, Lst);
-char *Dir_FindFile(const char *, Lst);
-int Dir_FindHereOrAbove(char *, char *, char *, int);
-int Dir_MTime(GNode *, Boolean);
-Path *Dir_AddDir(Lst, const char *);
-char *Dir_MakeFlags(const char *, Lst);
-void Dir_ClearPath(Lst);
-void Dir_Concat(Lst, Lst);
-void Dir_PrintDirectories(void);
-void Dir_PrintPath(Lst);
-void Dir_Destroy(void *);
-void * Dir_CopyDir(void *);
-
-#endif /* MAKE_DIR_H */
diff --git a/usr.bin/make/for.c b/usr.bin/make/for.c
deleted file mode 100644
index fffedda..0000000
--- a/usr.bin/make/for.c
+++ /dev/null
@@ -1,496 +0,0 @@
-/* $NetBSD: for.c,v 1.53 2017/04/16 21:04:44 riastradh Exp $ */
-
-/*
- * Copyright (c) 1992, The Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: for.c,v 1.53 2017/04/16 21:04:44 riastradh Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)for.c 8.1 (Berkeley) 6/6/93";
-#else
-__RCSID("$NetBSD: for.c,v 1.53 2017/04/16 21:04:44 riastradh Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * for.c --
- * Functions to handle loops in a makefile.
- *
- * Interface:
- * For_Eval Evaluate the loop in the passed line.
- * For_Run Run accumulated loop
- *
- */
-
-#include <assert.h>
-#include <ctype.h>
-
-#include "make.h"
-#include "hash.h"
-#include "dir.h"
-#include "buf.h"
-#include "strlist.h"
-
-#define FOR_SUB_ESCAPE_CHAR 1
-#define FOR_SUB_ESCAPE_BRACE 2
-#define FOR_SUB_ESCAPE_PAREN 4
-
-/*
- * For statements are of the form:
- *
- * .for <variable> in <varlist>
- * ...
- * .endfor
- *
- * The trick is to look for the matching end inside for for loop
- * To do that, we count the current nesting level of the for loops.
- * and the .endfor statements, accumulating all the statements between
- * the initial .for loop and the matching .endfor;
- * then we evaluate the for loop for each variable in the varlist.
- *
- * Note that any nested fors are just passed through; they get handled
- * recursively in For_Eval when we're expanding the enclosing for in
- * For_Run.
- */
-
-static int forLevel = 0; /* Nesting level */
-
-/*
- * State of a for loop.
- */
-typedef struct _For {
- Buffer buf; /* Body of loop */
- strlist_t vars; /* Iteration variables */
- strlist_t items; /* Substitution items */
- char *parse_buf;
- int short_var;
- int sub_next;
-} For;
-
-static For *accumFor; /* Loop being accumulated */
-
-
-
-static char *
-make_str(const char *ptr, int len)
-{
- char *new_ptr;
-
- new_ptr = bmake_malloc(len + 1);
- memcpy(new_ptr, ptr, len);
- new_ptr[len] = 0;
- return new_ptr;
-}
-
-static void
-For_Free(For *arg)
-{
- Buf_Destroy(&arg->buf, TRUE);
- strlist_clean(&arg->vars);
- strlist_clean(&arg->items);
- free(arg->parse_buf);
-
- free(arg);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * For_Eval --
- * Evaluate the for loop in the passed line. The line
- * looks like this:
- * .for <variable> in <varlist>
- *
- * Input:
- * line Line to parse
- *
- * Results:
- * 0: Not a .for statement, parse the line
- * 1: We found a for loop
- * -1: A .for statement with a bad syntax error, discard.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-int
-For_Eval(char *line)
-{
- For *new_for;
- char *ptr = line, *sub;
- int len;
- int escapes;
- unsigned char ch;
- char **words, *word_buf;
- int n, nwords;
-
- /* Skip the '.' and any following whitespace */
- for (ptr++; *ptr && isspace((unsigned char) *ptr); ptr++)
- continue;
-
- /*
- * If we are not in a for loop quickly determine if the statement is
- * a for.
- */
- if (ptr[0] != 'f' || ptr[1] != 'o' || ptr[2] != 'r' ||
- !isspace((unsigned char) ptr[3])) {
- if (ptr[0] == 'e' && strncmp(ptr+1, "ndfor", 5) == 0) {
- Parse_Error(PARSE_FATAL, "for-less endfor");
- return -1;
- }
- return 0;
- }
- ptr += 3;
-
- /*
- * we found a for loop, and now we are going to parse it.
- */
-
- new_for = bmake_malloc(sizeof *new_for);
- memset(new_for, 0, sizeof *new_for);
-
- /* Grab the variables. Terminate on "in". */
- for (;; ptr += len) {
- while (*ptr && isspace((unsigned char) *ptr))
- ptr++;
- if (*ptr == '\0') {
- Parse_Error(PARSE_FATAL, "missing `in' in for");
- For_Free(new_for);
- return -1;
- }
- for (len = 1; ptr[len] && !isspace((unsigned char)ptr[len]); len++)
- continue;
- if (len == 2 && ptr[0] == 'i' && ptr[1] == 'n') {
- ptr += 2;
- break;
- }
- if (len == 1)
- new_for->short_var = 1;
- strlist_add_str(&new_for->vars, make_str(ptr, len), len);
- }
-
- if (strlist_num(&new_for->vars) == 0) {
- Parse_Error(PARSE_FATAL, "no iteration variables in for");
- For_Free(new_for);
- return -1;
- }
-
- while (*ptr && isspace((unsigned char) *ptr))
- ptr++;
-
- /*
- * Make a list with the remaining words
- * The values are substituted as ${:U<value>...} so we must \ escape
- * characters that break that syntax.
- * Variables are fully expanded - so it is safe for escape $.
- * We can't do the escapes here - because we don't know whether
- * we are substuting into ${...} or $(...).
- */
- sub = Var_Subst(NULL, ptr, VAR_GLOBAL, VARF_WANTRES);
-
- /*
- * Split into words allowing for quoted strings.
- */
- words = brk_string(sub, &nwords, FALSE, &word_buf);
-
- free(sub);
-
- if (words != NULL) {
- for (n = 0; n < nwords; n++) {
- ptr = words[n];
- if (!*ptr)
- continue;
- escapes = 0;
- while ((ch = *ptr++)) {
- switch(ch) {
- case ':':
- case '$':
- case '\\':
- escapes |= FOR_SUB_ESCAPE_CHAR;
- break;
- case ')':
- escapes |= FOR_SUB_ESCAPE_PAREN;
- break;
- case /*{*/ '}':
- escapes |= FOR_SUB_ESCAPE_BRACE;
- break;
- }
- }
- /*
- * We have to dup words[n] to maintain the semantics of
- * strlist.
- */
- strlist_add_str(&new_for->items, bmake_strdup(words[n]), escapes);
- }
-
- free(words);
- free(word_buf);
-
- if ((len = strlist_num(&new_for->items)) > 0 &&
- len % (n = strlist_num(&new_for->vars))) {
- Parse_Error(PARSE_FATAL,
- "Wrong number of words (%d) in .for substitution list"
- " with %d vars", len, n);
- /*
- * Return 'success' so that the body of the .for loop is
- * accumulated.
- * Remove all items so that the loop doesn't iterate.
- */
- strlist_clean(&new_for->items);
- }
- }
-
- Buf_Init(&new_for->buf, 0);
- accumFor = new_for;
- forLevel = 1;
- return 1;
-}
-
-/*
- * Add another line to a .for loop.
- * Returns 0 when the matching .endfor is reached.
- */
-
-int
-For_Accum(char *line)
-{
- char *ptr = line;
-
- if (*ptr == '.') {
-
- for (ptr++; *ptr && isspace((unsigned char) *ptr); ptr++)
- continue;
-
- if (strncmp(ptr, "endfor", 6) == 0 &&
- (isspace((unsigned char) ptr[6]) || !ptr[6])) {
- if (DEBUG(FOR))
- (void)fprintf(debug_file, "For: end for %d\n", forLevel);
- if (--forLevel <= 0)
- return 0;
- } else if (strncmp(ptr, "for", 3) == 0 &&
- isspace((unsigned char) ptr[3])) {
- forLevel++;
- if (DEBUG(FOR))
- (void)fprintf(debug_file, "For: new loop %d\n", forLevel);
- }
- }
-
- Buf_AddBytes(&accumFor->buf, strlen(line), line);
- Buf_AddByte(&accumFor->buf, '\n');
- return 1;
-}
-
-
-/*-
- *-----------------------------------------------------------------------
- * For_Run --
- * Run the for loop, imitating the actions of an include file
- *
- * Results:
- * None.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-
-static int
-for_var_len(const char *var)
-{
- char ch, var_start, var_end;
- int depth;
- int len;
-
- var_start = *var;
- if (var_start == 0)
- /* just escape the $ */
- return 0;
-
- if (var_start == '(')
- var_end = ')';
- else if (var_start == '{')
- var_end = '}';
- else
- /* Single char variable */
- return 1;
-
- depth = 1;
- for (len = 1; (ch = var[len++]) != 0;) {
- if (ch == var_start)
- depth++;
- else if (ch == var_end && --depth == 0)
- return len;
- }
-
- /* Variable end not found, escape the $ */
- return 0;
-}
-
-static void
-for_substitute(Buffer *cmds, strlist_t *items, unsigned int item_no, char ech)
-{
- const char *item = strlist_str(items, item_no);
- int len;
- char ch;
-
- /* If there were no escapes, or the only escape is the other variable
- * terminator, then just substitute the full string */
- if (!(strlist_info(items, item_no) &
- (ech == ')' ? ~FOR_SUB_ESCAPE_BRACE : ~FOR_SUB_ESCAPE_PAREN))) {
- Buf_AddBytes(cmds, strlen(item), item);
- return;
- }
-
- /* Escape ':', '$', '\\' and 'ech' - removed by :U processing */
- while ((ch = *item++) != 0) {
- if (ch == '$') {
- len = for_var_len(item);
- if (len != 0) {
- Buf_AddBytes(cmds, len + 1, item - 1);
- item += len;
- continue;
- }
- Buf_AddByte(cmds, '\\');
- } else if (ch == ':' || ch == '\\' || ch == ech)
- Buf_AddByte(cmds, '\\');
- Buf_AddByte(cmds, ch);
- }
-}
-
-static char *
-For_Iterate(void *v_arg, size_t *ret_len)
-{
- For *arg = v_arg;
- int i, len;
- char *var;
- char *cp;
- char *cmd_cp;
- char *body_end;
- char ch;
- Buffer cmds;
-
- if (arg->sub_next + strlist_num(&arg->vars) > strlist_num(&arg->items)) {
- /* No more iterations */
- For_Free(arg);
- return NULL;
- }
-
- free(arg->parse_buf);
- arg->parse_buf = NULL;
-
- /*
- * Scan the for loop body and replace references to the loop variables
- * with variable references that expand to the required text.
- * Using variable expansions ensures that the .for loop can't generate
- * syntax, and that the later parsing will still see a variable.
- * We assume that the null variable will never be defined.
- *
- * The detection of substitions of the loop control variable is naive.
- * Many of the modifiers use \ to escape $ (not $) so it is possible
- * to contrive a makefile where an unwanted substitution happens.
- */
-
- cmd_cp = Buf_GetAll(&arg->buf, &len);
- body_end = cmd_cp + len;
- Buf_Init(&cmds, len + 256);
- for (cp = cmd_cp; (cp = strchr(cp, '$')) != NULL;) {
- char ech;
- ch = *++cp;
- if ((ch == '(' && (ech = ')', 1)) || (ch == '{' && (ech = '}', 1))) {
- cp++;
- /* Check variable name against the .for loop variables */
- STRLIST_FOREACH(var, &arg->vars, i) {
- len = strlist_info(&arg->vars, i);
- if (memcmp(cp, var, len) != 0)
- continue;
- if (cp[len] != ':' && cp[len] != ech && cp[len] != '\\')
- continue;
- /* Found a variable match. Replace with :U<value> */
- Buf_AddBytes(&cmds, cp - cmd_cp, cmd_cp);
- Buf_AddBytes(&cmds, 2, ":U");
- cp += len;
- cmd_cp = cp;
- for_substitute(&cmds, &arg->items, arg->sub_next + i, ech);
- break;
- }
- continue;
- }
- if (ch == 0)
- break;
- /* Probably a single character name, ignore $$ and stupid ones. {*/
- if (!arg->short_var || strchr("}):$", ch) != NULL) {
- cp++;
- continue;
- }
- STRLIST_FOREACH(var, &arg->vars, i) {
- if (var[0] != ch || var[1] != 0)
- continue;
- /* Found a variable match. Replace with ${:U<value>} */
- Buf_AddBytes(&cmds, cp - cmd_cp, cmd_cp);
- Buf_AddBytes(&cmds, 3, "{:U");
- cmd_cp = ++cp;
- for_substitute(&cmds, &arg->items, arg->sub_next + i, /*{*/ '}');
- Buf_AddBytes(&cmds, 1, "}");
- break;
- }
- }
- Buf_AddBytes(&cmds, body_end - cmd_cp, cmd_cp);
-
- cp = Buf_Destroy(&cmds, FALSE);
- if (DEBUG(FOR))
- (void)fprintf(debug_file, "For: loop body:\n%s", cp);
-
- arg->sub_next += strlist_num(&arg->vars);
-
- arg->parse_buf = cp;
- *ret_len = strlen(cp);
- return cp;
-}
-
-void
-For_Run(int lineno)
-{
- For *arg;
-
- arg = accumFor;
- accumFor = NULL;
-
- if (strlist_num(&arg->items) == 0) {
- /* Nothing to expand - possibly due to an earlier syntax error. */
- For_Free(arg);
- return;
- }
-
- Parse_SetInput(NULL, lineno, -1, For_Iterate, arg);
-}
diff --git a/usr.bin/make/hash.c b/usr.bin/make/hash.c
deleted file mode 100644
index ed23644..0000000
--- a/usr.bin/make/hash.c
+++ /dev/null
@@ -1,466 +0,0 @@
-/* $NetBSD: hash.c,v 1.20 2013/11/14 00:27:05 sjg Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-/*
- * Copyright (c) 1988, 1989 by Adam de Boor
- * Copyright (c) 1989 by Berkeley Softworks
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: hash.c,v 1.20 2013/11/14 00:27:05 sjg Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)hash.c 8.1 (Berkeley) 6/6/93";
-#else
-__RCSID("$NetBSD: hash.c,v 1.20 2013/11/14 00:27:05 sjg Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/* hash.c --
- *
- * This module contains routines to manipulate a hash table.
- * See hash.h for a definition of the structure of the hash
- * table. Hash tables grow automatically as the amount of
- * information increases.
- */
-#include "sprite.h"
-#include "make.h"
-#include "hash.h"
-
-/*
- * Forward references to local procedures that are used before they're
- * defined:
- */
-
-static void RebuildTable(Hash_Table *);
-
-/*
- * The following defines the ratio of # entries to # buckets
- * at which we rebuild the table to make it larger.
- */
-
-#define rebuildLimit 3
-
-/*
- *---------------------------------------------------------
- *
- * Hash_InitTable --
- *
- * This routine just sets up the hash table.
- *
- * Input:
- * t Structure to to hold table.
- * numBuckets How many buckets to create for starters. This
- * number is rounded up to a power of two. If
- * <= 0, a reasonable default is chosen. The
- * table will grow in size later as needed.
- *
- * Results:
- * None.
- *
- * Side Effects:
- * Memory is allocated for the initial bucket area.
- *
- *---------------------------------------------------------
- */
-
-void
-Hash_InitTable(Hash_Table *t, int numBuckets)
-{
- int i;
- struct Hash_Entry **hp;
-
- /*
- * Round up the size to a power of two.
- */
- if (numBuckets <= 0)
- i = 16;
- else {
- for (i = 2; i < numBuckets; i <<= 1)
- continue;
- }
- t->numEntries = 0;
- t->size = i;
- t->mask = i - 1;
- t->bucketPtr = hp = bmake_malloc(sizeof(*hp) * i);
- while (--i >= 0)
- *hp++ = NULL;
-}
-
-/*
- *---------------------------------------------------------
- *
- * Hash_DeleteTable --
- *
- * This routine removes everything from a hash table
- * and frees up the memory space it occupied (except for
- * the space in the Hash_Table structure).
- *
- * Results:
- * None.
- *
- * Side Effects:
- * Lots of memory is freed up.
- *
- *---------------------------------------------------------
- */
-
-void
-Hash_DeleteTable(Hash_Table *t)
-{
- struct Hash_Entry **hp, *h, *nexth = NULL;
- int i;
-
- for (hp = t->bucketPtr, i = t->size; --i >= 0;) {
- for (h = *hp++; h != NULL; h = nexth) {
- nexth = h->next;
- free(h);
- }
- }
- free(t->bucketPtr);
-
- /*
- * Set up the hash table to cause memory faults on any future access
- * attempts until re-initialization.
- */
- t->bucketPtr = NULL;
-}
-
-/*
- *---------------------------------------------------------
- *
- * Hash_FindEntry --
- *
- * Searches a hash table for an entry corresponding to key.
- *
- * Input:
- * t Hash table to search.
- * key A hash key.
- *
- * Results:
- * The return value is a pointer to the entry for key,
- * if key was present in the table. If key was not
- * present, NULL is returned.
- *
- * Side Effects:
- * None.
- *
- *---------------------------------------------------------
- */
-
-Hash_Entry *
-Hash_FindEntry(Hash_Table *t, const char *key)
-{
- Hash_Entry *e;
- unsigned h;
- const char *p;
-
- if (t == NULL || t->bucketPtr == NULL) {
- return NULL;
- }
- for (h = 0, p = key; *p;)
- h = (h << 5) - h + *p++;
- p = key;
- for (e = t->bucketPtr[h & t->mask]; e != NULL; e = e->next)
- if (e->namehash == h && strcmp(e->name, p) == 0)
- return (e);
- return NULL;
-}
-
-/*
- *---------------------------------------------------------
- *
- * Hash_CreateEntry --
- *
- * Searches a hash table for an entry corresponding to
- * key. If no entry is found, then one is created.
- *
- * Input:
- * t Hash table to search.
- * key A hash key.
- * newPtr Filled in with TRUE if new entry created,
- * FALSE otherwise.
- *
- * Results:
- * The return value is a pointer to the entry. If *newPtr
- * isn't NULL, then *newPtr is filled in with TRUE if a
- * new entry was created, and FALSE if an entry already existed
- * with the given key.
- *
- * Side Effects:
- * Memory may be allocated, and the hash buckets may be modified.
- *---------------------------------------------------------
- */
-
-Hash_Entry *
-Hash_CreateEntry(Hash_Table *t, const char *key, Boolean *newPtr)
-{
- Hash_Entry *e;
- unsigned h;
- const char *p;
- int keylen;
- struct Hash_Entry **hp;
-
- /*
- * Hash the key. As a side effect, save the length (strlen) of the
- * key in case we need to create the entry.
- */
- for (h = 0, p = key; *p;)
- h = (h << 5) - h + *p++;
- keylen = p - key;
- p = key;
- for (e = t->bucketPtr[h & t->mask]; e != NULL; e = e->next) {
- if (e->namehash == h && strcmp(e->name, p) == 0) {
- if (newPtr != NULL)
- *newPtr = FALSE;
- return (e);
- }
- }
-
- /*
- * The desired entry isn't there. Before allocating a new entry,
- * expand the table if necessary (and this changes the resulting
- * bucket chain).
- */
- if (t->numEntries >= rebuildLimit * t->size)
- RebuildTable(t);
- e = bmake_malloc(sizeof(*e) + keylen);
- hp = &t->bucketPtr[h & t->mask];
- e->next = *hp;
- *hp = e;
- Hash_SetValue(e, NULL);
- e->namehash = h;
- (void)strcpy(e->name, p);
- t->numEntries++;
-
- if (newPtr != NULL)
- *newPtr = TRUE;
- return (e);
-}
-
-/*
- *---------------------------------------------------------
- *
- * Hash_DeleteEntry --
- *
- * Delete the given hash table entry and free memory associated with
- * it.
- *
- * Results:
- * None.
- *
- * Side Effects:
- * Hash chain that entry lives in is modified and memory is freed.
- *
- *---------------------------------------------------------
- */
-
-void
-Hash_DeleteEntry(Hash_Table *t, Hash_Entry *e)
-{
- Hash_Entry **hp, *p;
-
- if (e == NULL)
- return;
- for (hp = &t->bucketPtr[e->namehash & t->mask];
- (p = *hp) != NULL; hp = &p->next) {
- if (p == e) {
- *hp = p->next;
- free(p);
- t->numEntries--;
- return;
- }
- }
- (void)write(2, "bad call to Hash_DeleteEntry\n", 29);
- abort();
-}
-
-/*
- *---------------------------------------------------------
- *
- * Hash_EnumFirst --
- * This procedure sets things up for a complete search
- * of all entries recorded in the hash table.
- *
- * Input:
- * t Table to be searched.
- * searchPtr Area in which to keep state about search.
- *
- * Results:
- * The return value is the address of the first entry in
- * the hash table, or NULL if the table is empty.
- *
- * Side Effects:
- * The information in searchPtr is initialized so that successive
- * calls to Hash_Next will return successive HashEntry's
- * from the table.
- *
- *---------------------------------------------------------
- */
-
-Hash_Entry *
-Hash_EnumFirst(Hash_Table *t, Hash_Search *searchPtr)
-{
- searchPtr->tablePtr = t;
- searchPtr->nextIndex = 0;
- searchPtr->hashEntryPtr = NULL;
- return Hash_EnumNext(searchPtr);
-}
-
-/*
- *---------------------------------------------------------
- *
- * Hash_EnumNext --
- * This procedure returns successive entries in the hash table.
- *
- * Input:
- * searchPtr Area used to keep state about search.
- *
- * Results:
- * The return value is a pointer to the next HashEntry
- * in the table, or NULL when the end of the table is
- * reached.
- *
- * Side Effects:
- * The information in searchPtr is modified to advance to the
- * next entry.
- *
- *---------------------------------------------------------
- */
-
-Hash_Entry *
-Hash_EnumNext(Hash_Search *searchPtr)
-{
- Hash_Entry *e;
- Hash_Table *t = searchPtr->tablePtr;
-
- /*
- * The hashEntryPtr field points to the most recently returned
- * entry, or is nil if we are starting up. If not nil, we have
- * to start at the next one in the chain.
- */
- e = searchPtr->hashEntryPtr;
- if (e != NULL)
- e = e->next;
- /*
- * If the chain ran out, or if we are starting up, we need to
- * find the next nonempty chain.
- */
- while (e == NULL) {
- if (searchPtr->nextIndex >= t->size)
- return NULL;
- e = t->bucketPtr[searchPtr->nextIndex++];
- }
- searchPtr->hashEntryPtr = e;
- return (e);
-}
-
-/*
- *---------------------------------------------------------
- *
- * RebuildTable --
- * This local routine makes a new hash table that
- * is larger than the old one.
- *
- * Results:
- * None.
- *
- * Side Effects:
- * The entire hash table is moved, so any bucket numbers
- * from the old table are invalid.
- *
- *---------------------------------------------------------
- */
-
-static void
-RebuildTable(Hash_Table *t)
-{
- Hash_Entry *e, *next = NULL, **hp, **xp;
- int i, mask;
- Hash_Entry **oldhp;
- int oldsize;
-
- oldhp = t->bucketPtr;
- oldsize = i = t->size;
- i <<= 1;
- t->size = i;
- t->mask = mask = i - 1;
- t->bucketPtr = hp = bmake_malloc(sizeof(*hp) * i);
- while (--i >= 0)
- *hp++ = NULL;
- for (hp = oldhp, i = oldsize; --i >= 0;) {
- for (e = *hp++; e != NULL; e = next) {
- next = e->next;
- xp = &t->bucketPtr[e->namehash & mask];
- e->next = *xp;
- *xp = e;
- }
- }
- free(oldhp);
-}
diff --git a/usr.bin/make/hash.h b/usr.bin/make/hash.h
deleted file mode 100644
index 8ab6ffd..0000000
--- a/usr.bin/make/hash.h
+++ /dev/null
@@ -1,149 +0,0 @@
-/* $NetBSD: hash.h,v 1.12 2017/05/31 21:07:03 maya Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- *
- * from: @(#)hash.h 8.1 (Berkeley) 6/6/93
- */
-
-/*
- * Copyright (c) 1988, 1989 by Adam de Boor
- * Copyright (c) 1989 by Berkeley Softworks
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. 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.
- *
- * from: @(#)hash.h 8.1 (Berkeley) 6/6/93
- */
-
-/* hash.h --
- *
- * This file contains definitions used by the hash module,
- * which maintains hash tables.
- */
-
-#ifndef _HASH_H
-#define _HASH_H
-
-/*
- * The following defines one entry in the hash table.
- */
-
-typedef struct Hash_Entry {
- struct Hash_Entry *next; /* Used to link together all the
- * entries associated with the same
- * bucket. */
- void *clientPtr; /* Arbitrary pointer */
- unsigned namehash; /* hash value of key */
- char name[1]; /* key string */
-} Hash_Entry;
-
-typedef struct Hash_Table {
- struct Hash_Entry **bucketPtr;/* Pointers to Hash_Entry, one
- * for each bucket in the table. */
- int size; /* Actual size of array. */
- int numEntries; /* Number of entries in the table. */
- int mask; /* Used to select bits for hashing. */
-} Hash_Table;
-
-/*
- * The following structure is used by the searching routines
- * to record where we are in the search.
- */
-
-typedef struct Hash_Search {
- Hash_Table *tablePtr; /* Table being searched. */
- int nextIndex; /* Next bucket to check (after current). */
- Hash_Entry *hashEntryPtr; /* Next entry to check in current bucket. */
-} Hash_Search;
-
-/*
- * Macros.
- */
-
-/*
- * void * Hash_GetValue(h)
- * Hash_Entry *h;
- */
-
-#define Hash_GetValue(h) ((h)->clientPtr)
-
-/*
- * Hash_SetValue(h, val);
- * Hash_Entry *h;
- * char *val;
- */
-
-#define Hash_SetValue(h, val) ((h)->clientPtr = (val))
-
-/*
- * Hash_Size(n) returns the number of words in an object of n bytes
- */
-
-#define Hash_Size(n) (((n) + sizeof (int) - 1) / sizeof (int))
-
-void Hash_InitTable(Hash_Table *, int);
-void Hash_DeleteTable(Hash_Table *);
-Hash_Entry *Hash_FindEntry(Hash_Table *, const char *);
-Hash_Entry *Hash_CreateEntry(Hash_Table *, const char *, Boolean *);
-void Hash_DeleteEntry(Hash_Table *, Hash_Entry *);
-Hash_Entry *Hash_EnumFirst(Hash_Table *, Hash_Search *);
-Hash_Entry *Hash_EnumNext(Hash_Search *);
-
-#endif /* _HASH_H */
diff --git a/usr.bin/make/job.c b/usr.bin/make/job.c
deleted file mode 100644
index 48ec284..0000000
--- a/usr.bin/make/job.c
+++ /dev/null
@@ -1,3070 +0,0 @@
-/* $NetBSD: job.c,v 1.195 2018/05/13 22:13:28 sjg Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-/*
- * Copyright (c) 1988, 1989 by Adam de Boor
- * Copyright (c) 1989 by Berkeley Softworks
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: job.c,v 1.195 2018/05/13 22:13:28 sjg Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)job.c 8.2 (Berkeley) 3/19/94";
-#else
-__RCSID("$NetBSD: job.c,v 1.195 2018/05/13 22:13:28 sjg Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * job.c --
- * handle the creation etc. of our child processes.
- *
- * Interface:
- * Job_Make Start the creation of the given target.
- *
- * Job_CatchChildren Check for and handle the termination of any
- * children. This must be called reasonably
- * frequently to keep the whole make going at
- * a decent clip, since job table entries aren't
- * removed until their process is caught this way.
- *
- * Job_CatchOutput Print any output our children have produced.
- * Should also be called fairly frequently to
- * keep the user informed of what's going on.
- * If no output is waiting, it will block for
- * a time given by the SEL_* constants, below,
- * or until output is ready.
- *
- * Job_Init Called to initialize this module. in addition,
- * any commands attached to the .BEGIN target
- * are executed before this function returns.
- * Hence, the makefile must have been parsed
- * before this function is called.
- *
- * Job_End Cleanup any memory used.
- *
- * Job_ParseShell Given the line following a .SHELL target, parse
- * the line as a shell specification. Returns
- * FAILURE if the spec was incorrect.
- *
- * Job_Finish Perform any final processing which needs doing.
- * This includes the execution of any commands
- * which have been/were attached to the .END
- * target. It should only be called when the
- * job table is empty.
- *
- * Job_AbortAll Abort all currently running jobs. It doesn't
- * handle output or do anything for the jobs,
- * just kills them. It should only be called in
- * an emergency, as it were.
- *
- * Job_CheckCommands Verify that the commands for a target are
- * ok. Provide them if necessary and possible.
- *
- * Job_Touch Update a target without really updating it.
- *
- * Job_Wait Wait for all currently-running jobs to finish.
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/file.h>
-#include <sys/time.h>
-#include <sys/wait.h>
-
-#include <assert.h>
-#include <errno.h>
-#ifndef USE_SELECT
-#include <poll.h>
-#endif
-#include <signal.h>
-#include <stdio.h>
-#include <string.h>
-#include <utime.h>
-
-#include "make.h"
-#include "hash.h"
-#include "dir.h"
-#include "job.h"
-#include "pathnames.h"
-#include "trace.h"
-# define STATIC static
-
-/*
- * error handling variables
- */
-static int errors = 0; /* number of errors reported */
-static int aborting = 0; /* why is the make aborting? */
-#define ABORT_ERROR 1 /* Because of an error */
-#define ABORT_INTERRUPT 2 /* Because it was interrupted */
-#define ABORT_WAIT 3 /* Waiting for jobs to finish */
-#define JOB_TOKENS "+EI+" /* Token to requeue for each abort state */
-
-/*
- * this tracks the number of tokens currently "out" to build jobs.
- */
-int jobTokensRunning = 0;
-int not_parallel = 0; /* set if .NOT_PARALLEL */
-
-/*
- * XXX: Avoid SunOS bug... FILENO() is fp->_file, and file
- * is a char! So when we go above 127 we turn negative!
- */
-#define FILENO(a) ((unsigned) fileno(a))
-
-/*
- * post-make command processing. The node postCommands is really just the
- * .END target but we keep it around to avoid having to search for it
- * all the time.
- */
-static GNode *postCommands = NULL;
- /* node containing commands to execute when
- * everything else is done */
-static int numCommands; /* The number of commands actually printed
- * for a target. Should this number be
- * 0, no shell will be executed. */
-
-/*
- * Return values from JobStart.
- */
-#define JOB_RUNNING 0 /* Job is running */
-#define JOB_ERROR 1 /* Error in starting the job */
-#define JOB_FINISHED 2 /* The job is already finished */
-
-/*
- * Descriptions for various shells.
- *
- * The build environment may set DEFSHELL_INDEX to one of
- * DEFSHELL_INDEX_SH, DEFSHELL_INDEX_KSH, or DEFSHELL_INDEX_CSH, to
- * select one of the prefedined shells as the default shell.
- *
- * Alternatively, the build environment may set DEFSHELL_CUSTOM to the
- * name or the full path of a sh-compatible shell, which will be used as
- * the default shell.
- *
- * ".SHELL" lines in Makefiles can choose the default shell from the
- # set defined here, or add additional shells.
- */
-
-#ifdef DEFSHELL_CUSTOM
-#define DEFSHELL_INDEX_CUSTOM 0
-#define DEFSHELL_INDEX_SH 1
-#define DEFSHELL_INDEX_KSH 2
-#define DEFSHELL_INDEX_CSH 3
-#else /* !DEFSHELL_CUSTOM */
-#define DEFSHELL_INDEX_SH 0
-#define DEFSHELL_INDEX_KSH 1
-#define DEFSHELL_INDEX_CSH 2
-#endif /* !DEFSHELL_CUSTOM */
-
-#ifndef DEFSHELL_INDEX
-#define DEFSHELL_INDEX 0 /* DEFSHELL_INDEX_CUSTOM or DEFSHELL_INDEX_SH */
-#endif /* !DEFSHELL_INDEX */
-
-static Shell shells[] = {
-#ifdef DEFSHELL_CUSTOM
- /*
- * An sh-compatible shell with a non-standard name.
- *
- * Keep this in sync with the "sh" description below, but avoid
- * non-portable features that might not be supplied by all
- * sh-compatible shells.
- */
-{
- DEFSHELL_CUSTOM,
- FALSE, "", "", "", 0,
- FALSE, "echo \"%s\"\n", "%s\n", "{ %s \n} || exit $?\n", "'\n'", '#',
- "",
- "",
-},
-#endif /* DEFSHELL_CUSTOM */
- /*
- * SH description. Echo control is also possible and, under
- * sun UNIX anyway, one can even control error checking.
- */
-{
- "sh",
- FALSE, "", "", "", 0,
- FALSE, "echo \"%s\"\n", "%s\n", "{ %s \n} || exit $?\n", "'\n'", '#',
-#if defined(MAKE_NATIVE) && defined(__NetBSD__)
- "q",
-#else
- "",
-#endif
- "",
-},
- /*
- * KSH description.
- */
-{
- "ksh",
- TRUE, "set +v", "set -v", "set +v", 6,
- FALSE, "echo \"%s\"\n", "%s\n", "{ %s \n} || exit $?\n", "'\n'", '#',
- "v",
- "",
-},
- /*
- * CSH description. The csh can do echo control by playing
- * with the setting of the 'echo' shell variable. Sadly,
- * however, it is unable to do error control nicely.
- */
-{
- "csh",
- TRUE, "unset verbose", "set verbose", "unset verbose", 10,
- FALSE, "echo \"%s\"\n", "csh -c \"%s || exit 0\"\n", "", "'\\\n'", '#',
- "v", "e",
-},
- /*
- * UNKNOWN.
- */
-{
- NULL,
- FALSE, NULL, NULL, NULL, 0,
- FALSE, NULL, NULL, NULL, NULL, 0,
- NULL, NULL,
-}
-};
-static Shell *commandShell = &shells[DEFSHELL_INDEX]; /* this is the shell to
- * which we pass all
- * commands in the Makefile.
- * It is set by the
- * Job_ParseShell function */
-const char *shellPath = NULL, /* full pathname of
- * executable image */
- *shellName = NULL; /* last component of shell */
-char *shellErrFlag = NULL;
-static const char *shellArgv = NULL; /* Custom shell args */
-
-
-STATIC Job *job_table; /* The structures that describe them */
-STATIC Job *job_table_end; /* job_table + maxJobs */
-static int wantToken; /* we want a token */
-static int lurking_children = 0;
-static int make_suspended = 0; /* non-zero if we've seen a SIGTSTP (etc) */
-
-/*
- * Set of descriptors of pipes connected to
- * the output channels of children
- */
-static struct pollfd *fds = NULL;
-static Job **jobfds = NULL;
-static int nfds = 0;
-static void watchfd(Job *);
-static void clearfd(Job *);
-static int readyfd(Job *);
-
-STATIC GNode *lastNode; /* The node for which output was most recently
- * produced. */
-static char *targPrefix = NULL; /* What we print at the start of TARG_FMT */
-static Job tokenWaitJob; /* token wait pseudo-job */
-
-static Job childExitJob; /* child exit pseudo-job */
-#define CHILD_EXIT "."
-#define DO_JOB_RESUME "R"
-
-#define TARG_FMT "%s %s ---\n" /* Default format */
-#define MESSAGE(fp, gn) \
- if (maxJobs != 1 && targPrefix && *targPrefix) \
- (void)fprintf(fp, TARG_FMT, targPrefix, gn->name)
-
-static sigset_t caught_signals; /* Set of signals we handle */
-
-static void JobChildSig(int);
-static void JobContinueSig(int);
-static Job *JobFindPid(int, int, Boolean);
-static int JobPrintCommand(void *, void *);
-static int JobSaveCommand(void *, void *);
-static void JobClose(Job *);
-static void JobExec(Job *, char **);
-static void JobMakeArgv(Job *, char **);
-static int JobStart(GNode *, int);
-static char *JobOutput(Job *, char *, char *, int);
-static void JobDoOutput(Job *, Boolean);
-static Shell *JobMatchShell(const char *);
-static void JobInterrupt(int, int) MAKE_ATTR_DEAD;
-static void JobRestartJobs(void);
-static void JobTokenAdd(void);
-static void JobSigLock(sigset_t *);
-static void JobSigUnlock(sigset_t *);
-static void JobSigReset(void);
-
-const char *malloc_options="A";
-
-static void
-job_table_dump(const char *where)
-{
- Job *job;
-
- fprintf(debug_file, "job table @ %s\n", where);
- for (job = job_table; job < job_table_end; job++) {
- fprintf(debug_file, "job %d, status %d, flags %d, pid %d\n",
- (int)(job - job_table), job->job_state, job->flags, job->pid);
- }
-}
-
-/*
- * Delete the target of a failed, interrupted, or otherwise
- * unsuccessful job unless inhibited by .PRECIOUS.
- */
-static void
-JobDeleteTarget(GNode *gn)
-{
- if ((gn->type & (OP_JOIN|OP_PHONY)) == 0 && !Targ_Precious(gn)) {
- char *file = (gn->path == NULL ? gn->name : gn->path);
- if (!noExecute && eunlink(file) != -1) {
- Error("*** %s removed", file);
- }
- }
-}
-
-/*
- * JobSigLock/JobSigUnlock
- *
- * Signal lock routines to get exclusive access. Currently used to
- * protect `jobs' and `stoppedJobs' list manipulations.
- */
-static void JobSigLock(sigset_t *omaskp)
-{
- if (sigprocmask(SIG_BLOCK, &caught_signals, omaskp) != 0) {
- Punt("JobSigLock: sigprocmask: %s", strerror(errno));
- sigemptyset(omaskp);
- }
-}
-
-static void JobSigUnlock(sigset_t *omaskp)
-{
- (void)sigprocmask(SIG_SETMASK, omaskp, NULL);
-}
-
-static void
-JobCreatePipe(Job *job, int minfd)
-{
- int i, fd, flags;
-
- if (pipe(job->jobPipe) == -1)
- Punt("Cannot create pipe: %s", strerror(errno));
-
- for (i = 0; i < 2; i++) {
- /* Avoid using low numbered fds */
- fd = fcntl(job->jobPipe[i], F_DUPFD, minfd);
- if (fd != -1) {
- close(job->jobPipe[i]);
- job->jobPipe[i] = fd;
- }
- }
-
- /* Set close-on-exec flag for both */
- if (fcntl(job->jobPipe[0], F_SETFD, FD_CLOEXEC) == -1)
- Punt("Cannot set close-on-exec: %s", strerror(errno));
- if (fcntl(job->jobPipe[1], F_SETFD, FD_CLOEXEC) == -1)
- Punt("Cannot set close-on-exec: %s", strerror(errno));
-
- /*
- * We mark the input side of the pipe non-blocking; we poll(2) the
- * pipe when we're waiting for a job token, but we might lose the
- * race for the token when a new one becomes available, so the read
- * from the pipe should not block.
- */
- flags = fcntl(job->jobPipe[0], F_GETFL, 0);
- if (flags == -1)
- Punt("Cannot get flags: %s", strerror(errno));
- flags |= O_NONBLOCK;
- if (fcntl(job->jobPipe[0], F_SETFL, flags) == -1)
- Punt("Cannot set flags: %s", strerror(errno));
-}
-
-/*-
- *-----------------------------------------------------------------------
- * JobCondPassSig --
- * Pass a signal to a job
- *
- * Input:
- * signop Signal to send it
- *
- * Side Effects:
- * None, except the job may bite it.
- *
- *-----------------------------------------------------------------------
- */
-static void
-JobCondPassSig(int signo)
-{
- Job *job;
-
- if (DEBUG(JOB)) {
- (void)fprintf(debug_file, "JobCondPassSig(%d) called.\n", signo);
- }
-
- for (job = job_table; job < job_table_end; job++) {
- if (job->job_state != JOB_ST_RUNNING)
- continue;
- if (DEBUG(JOB)) {
- (void)fprintf(debug_file,
- "JobCondPassSig passing signal %d to child %d.\n",
- signo, job->pid);
- }
- KILLPG(job->pid, signo);
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * JobChldSig --
- * SIGCHLD handler.
- *
- * Input:
- * signo The signal number we've received
- *
- * Results:
- * None.
- *
- * Side Effects:
- * Sends a token on the child exit pipe to wake us up from
- * select()/poll().
- *
- *-----------------------------------------------------------------------
- */
-static void
-JobChildSig(int signo MAKE_ATTR_UNUSED)
-{
- while (write(childExitJob.outPipe, CHILD_EXIT, 1) == -1 && errno == EAGAIN)
- continue;
-}
-
-
-/*-
- *-----------------------------------------------------------------------
- * JobContinueSig --
- * Resume all stopped jobs.
- *
- * Input:
- * signo The signal number we've received
- *
- * Results:
- * None.
- *
- * Side Effects:
- * Jobs start running again.
- *
- *-----------------------------------------------------------------------
- */
-static void
-JobContinueSig(int signo MAKE_ATTR_UNUSED)
-{
- /*
- * Defer sending to SIGCONT to our stopped children until we return
- * from the signal handler.
- */
- while (write(childExitJob.outPipe, DO_JOB_RESUME, 1) == -1 &&
- errno == EAGAIN)
- continue;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * JobPassSig --
- * Pass a signal on to all jobs, then resend to ourselves.
- *
- * Input:
- * signo The signal number we've received
- *
- * Results:
- * None.
- *
- * Side Effects:
- * We die by the same signal.
- *
- *-----------------------------------------------------------------------
- */
-MAKE_ATTR_DEAD static void
-JobPassSig_int(int signo)
-{
- /* Run .INTERRUPT target then exit */
- JobInterrupt(TRUE, signo);
-}
-
-MAKE_ATTR_DEAD static void
-JobPassSig_term(int signo)
-{
- /* Dont run .INTERRUPT target then exit */
- JobInterrupt(FALSE, signo);
-}
-
-static void
-JobPassSig_suspend(int signo)
-{
- sigset_t nmask, omask;
- struct sigaction act;
-
- /* Suppress job started/continued messages */
- make_suspended = 1;
-
- /* Pass the signal onto every job */
- JobCondPassSig(signo);
-
- /*
- * Send ourselves the signal now we've given the message to everyone else.
- * Note we block everything else possible while we're getting the signal.
- * This ensures that all our jobs get continued when we wake up before
- * we take any other signal.
- */
- sigfillset(&nmask);
- sigdelset(&nmask, signo);
- (void)sigprocmask(SIG_SETMASK, &nmask, &omask);
-
- act.sa_handler = SIG_DFL;
- sigemptyset(&act.sa_mask);
- act.sa_flags = 0;
- (void)sigaction(signo, &act, NULL);
-
- if (DEBUG(JOB)) {
- (void)fprintf(debug_file,
- "JobPassSig passing signal %d to self.\n", signo);
- }
-
- (void)kill(getpid(), signo);
-
- /*
- * We've been continued.
- *
- * A whole host of signals continue to happen!
- * SIGCHLD for any processes that actually suspended themselves.
- * SIGCHLD for any processes that exited while we were alseep.
- * The SIGCONT that actually caused us to wakeup.
- *
- * Since we defer passing the SIGCONT on to our children until
- * the main processing loop, we can be sure that all the SIGCHLD
- * events will have happened by then - and that the waitpid() will
- * collect the child 'suspended' events.
- * For correct sequencing we just need to ensure we process the
- * waitpid() before passign on the SIGCONT.
- *
- * In any case nothing else is needed here.
- */
-
- /* Restore handler and signal mask */
- act.sa_handler = JobPassSig_suspend;
- (void)sigaction(signo, &act, NULL);
- (void)sigprocmask(SIG_SETMASK, &omask, NULL);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * JobFindPid --
- * Compare the pid of the job with the given pid and return 0 if they
- * are equal. This function is called from Job_CatchChildren
- * to find the job descriptor of the finished job.
- *
- * Input:
- * job job to examine
- * pid process id desired
- *
- * Results:
- * Job with matching pid
- *
- * Side Effects:
- * None
- *-----------------------------------------------------------------------
- */
-static Job *
-JobFindPid(int pid, int status, Boolean isJobs)
-{
- Job *job;
-
- for (job = job_table; job < job_table_end; job++) {
- if ((job->job_state == status) && job->pid == pid)
- return job;
- }
- if (DEBUG(JOB) && isJobs)
- job_table_dump("no pid");
- return NULL;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * JobPrintCommand --
- * Put out another command for the given job. If the command starts
- * with an @ or a - we process it specially. In the former case,
- * so long as the -s and -n flags weren't given to make, we stick
- * a shell-specific echoOff command in the script. In the latter,
- * we ignore errors for the entire job, unless the shell has error
- * control.
- * If the command is just "..." we take all future commands for this
- * job to be commands to be executed once the entire graph has been
- * made and return non-zero to signal that the end of the commands
- * was reached. These commands are later attached to the postCommands
- * node and executed by Job_End when all things are done.
- * This function is called from JobStart via Lst_ForEach.
- *
- * Input:
- * cmdp command string to print
- * jobp job for which to print it
- *
- * Results:
- * Always 0, unless the command was "..."
- *
- * Side Effects:
- * If the command begins with a '-' and the shell has no error control,
- * the JOB_IGNERR flag is set in the job descriptor.
- * If the command is "..." and we're not ignoring such things,
- * tailCmds is set to the successor node of the cmd.
- * numCommands is incremented if the command is actually printed.
- *-----------------------------------------------------------------------
- */
-static int
-JobPrintCommand(void *cmdp, void *jobp)
-{
- Boolean noSpecials; /* true if we shouldn't worry about
- * inserting special commands into
- * the input stream. */
- Boolean shutUp = FALSE; /* true if we put a no echo command
- * into the command file */
- Boolean errOff = FALSE; /* true if we turned error checking
- * off before printing the command
- * and need to turn it back on */
- const char *cmdTemplate; /* Template to use when printing the
- * command */
- char *cmdStart; /* Start of expanded command */
- char *escCmd = NULL; /* Command with quotes/backticks escaped */
- char *cmd = (char *)cmdp;
- Job *job = (Job *)jobp;
- int i, j;
-
- noSpecials = NoExecute(job->node);
-
- if (strcmp(cmd, "...") == 0) {
- job->node->type |= OP_SAVE_CMDS;
- if ((job->flags & JOB_IGNDOTS) == 0) {
- job->tailCmds = Lst_Succ(Lst_Member(job->node->commands,
- cmd));
- return 1;
- }
- return 0;
- }
-
-#define DBPRINTF(fmt, arg) if (DEBUG(JOB)) { \
- (void)fprintf(debug_file, fmt, arg); \
- } \
- (void)fprintf(job->cmdFILE, fmt, arg); \
- (void)fflush(job->cmdFILE);
-
- numCommands += 1;
-
- cmdStart = cmd = Var_Subst(NULL, cmd, job->node, VARF_WANTRES);
-
- cmdTemplate = "%s\n";
-
- /*
- * Check for leading @' and -'s to control echoing and error checking.
- */
- while (*cmd == '@' || *cmd == '-' || (*cmd == '+')) {
- switch (*cmd) {
- case '@':
- shutUp = DEBUG(LOUD) ? FALSE : TRUE;
- break;
- case '-':
- errOff = TRUE;
- break;
- case '+':
- if (noSpecials) {
- /*
- * We're not actually executing anything...
- * but this one needs to be - use compat mode just for it.
- */
- CompatRunCommand(cmdp, job->node);
- free(cmdStart);
- return 0;
- }
- break;
- }
- cmd++;
- }
-
- while (isspace((unsigned char) *cmd))
- cmd++;
-
- /*
- * If the shell doesn't have error control the alternate echo'ing will
- * be done (to avoid showing additional error checking code)
- * and this will need the characters '$ ` \ "' escaped
- */
-
- if (!commandShell->hasErrCtl) {
- /* Worst that could happen is every char needs escaping. */
- escCmd = bmake_malloc((strlen(cmd) * 2) + 1);
- for (i = 0, j= 0; cmd[i] != '\0'; i++, j++) {
- if (cmd[i] == '$' || cmd[i] == '`' || cmd[i] == '\\' ||
- cmd[i] == '"')
- escCmd[j++] = '\\';
- escCmd[j] = cmd[i];
- }
- escCmd[j] = 0;
- }
-
- if (shutUp) {
- if (!(job->flags & JOB_SILENT) && !noSpecials &&
- commandShell->hasEchoCtl) {
- DBPRINTF("%s\n", commandShell->echoOff);
- } else {
- if (commandShell->hasErrCtl)
- shutUp = FALSE;
- }
- }
-
- if (errOff) {
- if (!noSpecials) {
- if (commandShell->hasErrCtl) {
- /*
- * we don't want the error-control commands showing
- * up either, so we turn off echoing while executing
- * them. We could put another field in the shell
- * structure to tell JobDoOutput to look for this
- * string too, but why make it any more complex than
- * it already is?
- */
- if (!(job->flags & JOB_SILENT) && !shutUp &&
- commandShell->hasEchoCtl) {
- DBPRINTF("%s\n", commandShell->echoOff);
- DBPRINTF("%s\n", commandShell->ignErr);
- DBPRINTF("%s\n", commandShell->echoOn);
- } else {
- DBPRINTF("%s\n", commandShell->ignErr);
- }
- } else if (commandShell->ignErr &&
- (*commandShell->ignErr != '\0'))
- {
- /*
- * The shell has no error control, so we need to be
- * weird to get it to ignore any errors from the command.
- * If echoing is turned on, we turn it off and use the
- * errCheck template to echo the command. Leave echoing
- * off so the user doesn't see the weirdness we go through
- * to ignore errors. Set cmdTemplate to use the weirdness
- * instead of the simple "%s\n" template.
- */
- job->flags |= JOB_IGNERR;
- if (!(job->flags & JOB_SILENT) && !shutUp) {
- if (commandShell->hasEchoCtl) {
- DBPRINTF("%s\n", commandShell->echoOff);
- }
- DBPRINTF(commandShell->errCheck, escCmd);
- shutUp = TRUE;
- } else {
- if (!shutUp) {
- DBPRINTF(commandShell->errCheck, escCmd);
- }
- }
- cmdTemplate = commandShell->ignErr;
- /*
- * The error ignoration (hee hee) is already taken care
- * of by the ignErr template, so pretend error checking
- * is still on.
- */
- errOff = FALSE;
- } else {
- errOff = FALSE;
- }
- } else {
- errOff = FALSE;
- }
- } else {
-
- /*
- * If errors are being checked and the shell doesn't have error control
- * but does supply an errOut template, then setup commands to run
- * through it.
- */
-
- if (!commandShell->hasErrCtl && commandShell->errOut &&
- (*commandShell->errOut != '\0')) {
- if (!(job->flags & JOB_SILENT) && !shutUp) {
- if (commandShell->hasEchoCtl) {
- DBPRINTF("%s\n", commandShell->echoOff);
- }
- DBPRINTF(commandShell->errCheck, escCmd);
- shutUp = TRUE;
- }
- /* If it's a comment line or blank, treat as an ignored error */
- if ((escCmd[0] == commandShell->commentChar) ||
- (escCmd[0] == 0))
- cmdTemplate = commandShell->ignErr;
- else
- cmdTemplate = commandShell->errOut;
- errOff = FALSE;
- }
- }
-
- if (DEBUG(SHELL) && strcmp(shellName, "sh") == 0 &&
- (job->flags & JOB_TRACED) == 0) {
- DBPRINTF("set -%s\n", "x");
- job->flags |= JOB_TRACED;
- }
-
- DBPRINTF(cmdTemplate, cmd);
- free(cmdStart);
- free(escCmd);
- if (errOff) {
- /*
- * If echoing is already off, there's no point in issuing the
- * echoOff command. Otherwise we issue it and pretend it was on
- * for the whole command...
- */
- if (!shutUp && !(job->flags & JOB_SILENT) && commandShell->hasEchoCtl){
- DBPRINTF("%s\n", commandShell->echoOff);
- shutUp = TRUE;
- }
- DBPRINTF("%s\n", commandShell->errCheck);
- }
- if (shutUp && commandShell->hasEchoCtl) {
- DBPRINTF("%s\n", commandShell->echoOn);
- }
- return 0;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * JobSaveCommand --
- * Save a command to be executed when everything else is done.
- * Callback function for JobFinish...
- *
- * Results:
- * Always returns 0
- *
- * Side Effects:
- * The command is tacked onto the end of postCommands's commands list.
- *
- *-----------------------------------------------------------------------
- */
-static int
-JobSaveCommand(void *cmd, void *gn)
-{
- cmd = Var_Subst(NULL, (char *)cmd, (GNode *)gn, VARF_WANTRES);
- (void)Lst_AtEnd(postCommands->commands, cmd);
- return(0);
-}
-
-
-/*-
- *-----------------------------------------------------------------------
- * JobClose --
- * Called to close both input and output pipes when a job is finished.
- *
- * Results:
- * Nada
- *
- * Side Effects:
- * The file descriptors associated with the job are closed.
- *
- *-----------------------------------------------------------------------
- */
-static void
-JobClose(Job *job)
-{
- clearfd(job);
- (void)close(job->outPipe);
- job->outPipe = -1;
-
- JobDoOutput(job, TRUE);
- (void)close(job->inPipe);
- job->inPipe = -1;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * JobFinish --
- * Do final processing for the given job including updating
- * parents and starting new jobs as available/necessary. Note
- * that we pay no attention to the JOB_IGNERR flag here.
- * This is because when we're called because of a noexecute flag
- * or something, jstat.w_status is 0 and when called from
- * Job_CatchChildren, the status is zeroed if it s/b ignored.
- *
- * Input:
- * job job to finish
- * status sub-why job went away
- *
- * Results:
- * None
- *
- * Side Effects:
- * Final commands for the job are placed on postCommands.
- *
- * If we got an error and are aborting (aborting == ABORT_ERROR) and
- * the job list is now empty, we are done for the day.
- * If we recognized an error (errors !=0), we set the aborting flag
- * to ABORT_ERROR so no more jobs will be started.
- *-----------------------------------------------------------------------
- */
-/*ARGSUSED*/
-static void
-JobFinish(Job *job, int status)
-{
- Boolean done, return_job_token;
-
- if (DEBUG(JOB)) {
- fprintf(debug_file, "Jobfinish: %d [%s], status %d\n",
- job->pid, job->node->name, status);
- }
-
- if ((WIFEXITED(status) &&
- (((WEXITSTATUS(status) != 0) && !(job->flags & JOB_IGNERR)))) ||
- WIFSIGNALED(status))
- {
- /*
- * If it exited non-zero and either we're doing things our
- * way or we're not ignoring errors, the job is finished.
- * Similarly, if the shell died because of a signal
- * the job is also finished. In these
- * cases, finish out the job's output before printing the exit
- * status...
- */
- JobClose(job);
- if (job->cmdFILE != NULL && job->cmdFILE != stdout) {
- (void)fclose(job->cmdFILE);
- job->cmdFILE = NULL;
- }
- done = TRUE;
- } else if (WIFEXITED(status)) {
- /*
- * Deal with ignored errors in -B mode. We need to print a message
- * telling of the ignored error as well as setting status.w_status
- * to 0 so the next command gets run. To do this, we set done to be
- * TRUE if in -B mode and the job exited non-zero.
- */
- done = WEXITSTATUS(status) != 0;
- /*
- * Old comment said: "Note we don't
- * want to close down any of the streams until we know we're at the
- * end."
- * But we do. Otherwise when are we going to print the rest of the
- * stuff?
- */
- JobClose(job);
- } else {
- /*
- * No need to close things down or anything.
- */
- done = FALSE;
- }
-
- if (done) {
- if (WIFEXITED(status)) {
- if (DEBUG(JOB)) {
- (void)fprintf(debug_file, "Process %d [%s] exited.\n",
- job->pid, job->node->name);
- }
- if (WEXITSTATUS(status) != 0) {
- if (job->node != lastNode) {
- MESSAGE(stdout, job->node);
- lastNode = job->node;
- }
-#ifdef USE_META
- if (useMeta) {
- meta_job_error(job, job->node, job->flags, WEXITSTATUS(status));
- }
-#endif
- (void)printf("*** [%s] Error code %d%s\n",
- job->node->name,
- WEXITSTATUS(status),
- (job->flags & JOB_IGNERR) ? " (ignored)" : "");
- if (job->flags & JOB_IGNERR) {
- status = 0;
- } else {
- if (deleteOnError) {
- JobDeleteTarget(job->node);
- }
- PrintOnError(job->node, NULL);
- }
- } else if (DEBUG(JOB)) {
- if (job->node != lastNode) {
- MESSAGE(stdout, job->node);
- lastNode = job->node;
- }
- (void)printf("*** [%s] Completed successfully\n",
- job->node->name);
- }
- } else {
- if (job->node != lastNode) {
- MESSAGE(stdout, job->node);
- lastNode = job->node;
- }
- (void)printf("*** [%s] Signal %d\n",
- job->node->name, WTERMSIG(status));
- if (deleteOnError) {
- JobDeleteTarget(job->node);
- }
- }
- (void)fflush(stdout);
- }
-
-#ifdef USE_META
- if (useMeta) {
- int x;
-
- if ((x = meta_job_finish(job)) != 0 && status == 0) {
- status = x;
- }
- }
-#endif
-
- return_job_token = FALSE;
-
- Trace_Log(JOBEND, job);
- if (!(job->flags & JOB_SPECIAL)) {
- if ((status != 0) ||
- (aborting == ABORT_ERROR) ||
- (aborting == ABORT_INTERRUPT))
- return_job_token = TRUE;
- }
-
- if ((aborting != ABORT_ERROR) && (aborting != ABORT_INTERRUPT) && (status == 0)) {
- /*
- * As long as we aren't aborting and the job didn't return a non-zero
- * status that we shouldn't ignore, we call Make_Update to update
- * the parents. In addition, any saved commands for the node are placed
- * on the .END target.
- */
- if (job->tailCmds != NULL) {
- Lst_ForEachFrom(job->node->commands, job->tailCmds,
- JobSaveCommand,
- job->node);
- }
- job->node->made = MADE;
- if (!(job->flags & JOB_SPECIAL))
- return_job_token = TRUE;
- Make_Update(job->node);
- job->job_state = JOB_ST_FREE;
- } else if (status != 0) {
- errors += 1;
- job->job_state = JOB_ST_FREE;
- }
-
- /*
- * Set aborting if any error.
- */
- if (errors && !keepgoing && (aborting != ABORT_INTERRUPT)) {
- /*
- * If we found any errors in this batch of children and the -k flag
- * wasn't given, we set the aborting flag so no more jobs get
- * started.
- */
- aborting = ABORT_ERROR;
- }
-
- if (return_job_token)
- Job_TokenReturn();
-
- if (aborting == ABORT_ERROR && jobTokensRunning == 0) {
- /*
- * If we are aborting and the job table is now empty, we finish.
- */
- Finish(errors);
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Job_Touch --
- * Touch the given target. Called by JobStart when the -t flag was
- * given
- *
- * Input:
- * gn the node of the file to touch
- * silent TRUE if should not print message
- *
- * Results:
- * None
- *
- * Side Effects:
- * The data modification of the file is changed. In addition, if the
- * file did not exist, it is created.
- *-----------------------------------------------------------------------
- */
-void
-Job_Touch(GNode *gn, Boolean silent)
-{
- int streamID; /* ID of stream opened to do the touch */
- struct utimbuf times; /* Times for utime() call */
-
- if (gn->type & (OP_JOIN|OP_USE|OP_USEBEFORE|OP_EXEC|OP_OPTIONAL|
- OP_SPECIAL|OP_PHONY)) {
- /*
- * .JOIN, .USE, .ZEROTIME and .OPTIONAL targets are "virtual" targets
- * and, as such, shouldn't really be created.
- */
- return;
- }
-
- if (!silent || NoExecute(gn)) {
- (void)fprintf(stdout, "touch %s\n", gn->name);
- (void)fflush(stdout);
- }
-
- if (NoExecute(gn)) {
- return;
- }
-
- if (gn->type & OP_ARCHV) {
- Arch_Touch(gn);
- } else if (gn->type & OP_LIB) {
- Arch_TouchLib(gn);
- } else {
- char *file = gn->path ? gn->path : gn->name;
-
- times.actime = times.modtime = now;
- if (utime(file, &times) < 0){
- streamID = open(file, O_RDWR | O_CREAT, 0666);
-
- if (streamID >= 0) {
- char c;
-
- /*
- * Read and write a byte to the file to change the
- * modification time, then close the file.
- */
- if (read(streamID, &c, 1) == 1) {
- (void)lseek(streamID, (off_t)0, SEEK_SET);
- while (write(streamID, &c, 1) == -1 && errno == EAGAIN)
- continue;
- }
-
- (void)close(streamID);
- } else {
- (void)fprintf(stdout, "*** couldn't touch %s: %s",
- file, strerror(errno));
- (void)fflush(stdout);
- }
- }
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Job_CheckCommands --
- * Make sure the given node has all the commands it needs.
- *
- * Input:
- * gn The target whose commands need verifying
- * abortProc Function to abort with message
- *
- * Results:
- * TRUE if the commands list is/was ok.
- *
- * Side Effects:
- * The node will have commands from the .DEFAULT rule added to it
- * if it needs them.
- *-----------------------------------------------------------------------
- */
-Boolean
-Job_CheckCommands(GNode *gn, void (*abortProc)(const char *, ...))
-{
- if (OP_NOP(gn->type) && Lst_IsEmpty(gn->commands) &&
- ((gn->type & OP_LIB) == 0 || Lst_IsEmpty(gn->children))) {
- /*
- * No commands. Look for .DEFAULT rule from which we might infer
- * commands
- */
- if ((DEFAULT != NULL) && !Lst_IsEmpty(DEFAULT->commands) &&
- (gn->type & OP_SPECIAL) == 0) {
- char *p1;
- /*
- * Make only looks for a .DEFAULT if the node was never the
- * target of an operator, so that's what we do too. If
- * a .DEFAULT was given, we substitute its commands for gn's
- * commands and set the IMPSRC variable to be the target's name
- * The DEFAULT node acts like a transformation rule, in that
- * gn also inherits any attributes or sources attached to
- * .DEFAULT itself.
- */
- Make_HandleUse(DEFAULT, gn);
- Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), gn, 0);
- free(p1);
- } else if (Dir_MTime(gn, 0) == 0 && (gn->type & OP_SPECIAL) == 0) {
- /*
- * The node wasn't the target of an operator we have no .DEFAULT
- * rule to go on and the target doesn't already exist. There's
- * nothing more we can do for this branch. If the -k flag wasn't
- * given, we stop in our tracks, otherwise we just don't update
- * this node's parents so they never get examined.
- */
- static const char msg[] = ": don't know how to make";
-
- if (gn->flags & FROM_DEPEND) {
- if (!Job_RunTarget(".STALE", gn->fname))
- fprintf(stdout, "%s: %s, %d: ignoring stale %s for %s\n",
- progname, gn->fname, gn->lineno, makeDependfile,
- gn->name);
- return TRUE;
- }
-
- if (gn->type & OP_OPTIONAL) {
- (void)fprintf(stdout, "%s%s %s (ignored)\n", progname,
- msg, gn->name);
- (void)fflush(stdout);
- } else if (keepgoing) {
- (void)fprintf(stdout, "%s%s %s (continuing)\n", progname,
- msg, gn->name);
- (void)fflush(stdout);
- return FALSE;
- } else {
- (*abortProc)("%s%s %s. Stop", progname, msg, gn->name);
- return FALSE;
- }
- }
- }
- return TRUE;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * JobExec --
- * Execute the shell for the given job. Called from JobStart
- *
- * Input:
- * job Job to execute
- *
- * Results:
- * None.
- *
- * Side Effects:
- * A shell is executed, outputs is altered and the Job structure added
- * to the job table.
- *
- *-----------------------------------------------------------------------
- */
-static void
-JobExec(Job *job, char **argv)
-{
- int cpid; /* ID of new child */
- sigset_t mask;
-
- job->flags &= ~JOB_TRACED;
-
- if (DEBUG(JOB)) {
- int i;
-
- (void)fprintf(debug_file, "Running %s %sly\n", job->node->name, "local");
- (void)fprintf(debug_file, "\tCommand: ");
- for (i = 0; argv[i] != NULL; i++) {
- (void)fprintf(debug_file, "%s ", argv[i]);
- }
- (void)fprintf(debug_file, "\n");
- }
-
- /*
- * Some jobs produce no output and it's disconcerting to have
- * no feedback of their running (since they produce no output, the
- * banner with their name in it never appears). This is an attempt to
- * provide that feedback, even if nothing follows it.
- */
- if ((lastNode != job->node) && !(job->flags & JOB_SILENT)) {
- MESSAGE(stdout, job->node);
- lastNode = job->node;
- }
-
- /* No interruptions until this job is on the `jobs' list */
- JobSigLock(&mask);
-
- /* Pre-emptively mark job running, pid still zero though */
- job->job_state = JOB_ST_RUNNING;
-
- cpid = vFork();
- if (cpid == -1)
- Punt("Cannot vfork: %s", strerror(errno));
-
- if (cpid == 0) {
- /* Child */
- sigset_t tmask;
-
-#ifdef USE_META
- if (useMeta) {
- meta_job_child(job);
- }
-#endif
- /*
- * Reset all signal handlers; this is necessary because we also
- * need to unblock signals before we exec(2).
- */
- JobSigReset();
-
- /* Now unblock signals */
- sigemptyset(&tmask);
- JobSigUnlock(&tmask);
-
- /*
- * Must duplicate the input stream down to the child's input and
- * reset it to the beginning (again). Since the stream was marked
- * close-on-exec, we must clear that bit in the new input.
- */
- if (dup2(FILENO(job->cmdFILE), 0) == -1) {
- execError("dup2", "job->cmdFILE");
- _exit(1);
- }
- if (fcntl(0, F_SETFD, 0) == -1) {
- execError("fcntl clear close-on-exec", "stdin");
- _exit(1);
- }
- if (lseek(0, (off_t)0, SEEK_SET) == -1) {
- execError("lseek to 0", "stdin");
- _exit(1);
- }
-
- if (job->node->type & (OP_MAKE | OP_SUBMAKE)) {
- /*
- * Pass job token pipe to submakes.
- */
- if (fcntl(tokenWaitJob.inPipe, F_SETFD, 0) == -1) {
- execError("clear close-on-exec", "tokenWaitJob.inPipe");
- _exit(1);
- }
- if (fcntl(tokenWaitJob.outPipe, F_SETFD, 0) == -1) {
- execError("clear close-on-exec", "tokenWaitJob.outPipe");
- _exit(1);
- }
- }
-
- /*
- * Set up the child's output to be routed through the pipe
- * we've created for it.
- */
- if (dup2(job->outPipe, 1) == -1) {
- execError("dup2", "job->outPipe");
- _exit(1);
- }
- /*
- * The output channels are marked close on exec. This bit was
- * duplicated by the dup2(on some systems), so we have to clear
- * it before routing the shell's error output to the same place as
- * its standard output.
- */
- if (fcntl(1, F_SETFD, 0) == -1) {
- execError("clear close-on-exec", "stdout");
- _exit(1);
- }
- if (dup2(1, 2) == -1) {
- execError("dup2", "1, 2");
- _exit(1);
- }
-
- /*
- * We want to switch the child into a different process family so
- * we can kill it and all its descendants in one fell swoop,
- * by killing its process family, but not commit suicide.
- */
-#if defined(MAKE_NATIVE) || defined(HAVE_SETPGID)
-#if defined(SYSV)
- /* XXX: dsl - I'm sure this should be setpgrp()... */
- (void)setsid();
-#else
- (void)setpgid(0, getpid());
-#endif
-#endif
-
- Var_ExportVars();
-
- (void)execv(shellPath, argv);
- execError("exec", shellPath);
- _exit(1);
- }
-
- /* Parent, continuing after the child exec */
- job->pid = cpid;
-
- Trace_Log(JOBSTART, job);
-
- /*
- * Set the current position in the buffer to the beginning
- * and mark another stream to watch in the outputs mask
- */
- job->curPos = 0;
-
- watchfd(job);
-
- if (job->cmdFILE != NULL && job->cmdFILE != stdout) {
- (void)fclose(job->cmdFILE);
- job->cmdFILE = NULL;
- }
-
- /*
- * Now the job is actually running, add it to the table.
- */
- if (DEBUG(JOB)) {
- fprintf(debug_file, "JobExec(%s): pid %d added to jobs table\n",
- job->node->name, job->pid);
- job_table_dump("job started");
- }
- JobSigUnlock(&mask);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * JobMakeArgv --
- * Create the argv needed to execute the shell for a given job.
- *
- *
- * Results:
- *
- * Side Effects:
- *
- *-----------------------------------------------------------------------
- */
-static void
-JobMakeArgv(Job *job, char **argv)
-{
- int argc;
- static char args[10]; /* For merged arguments */
-
- argv[0] = UNCONST(shellName);
- argc = 1;
-
- if ((commandShell->exit && (*commandShell->exit != '-')) ||
- (commandShell->echo && (*commandShell->echo != '-')))
- {
- /*
- * At least one of the flags doesn't have a minus before it, so
- * merge them together. Have to do this because the *(&(@*#*&#$#
- * Bourne shell thinks its second argument is a file to source.
- * Grrrr. Note the ten-character limitation on the combined arguments.
- */
- (void)snprintf(args, sizeof(args), "-%s%s",
- ((job->flags & JOB_IGNERR) ? "" :
- (commandShell->exit ? commandShell->exit : "")),
- ((job->flags & JOB_SILENT) ? "" :
- (commandShell->echo ? commandShell->echo : "")));
-
- if (args[1]) {
- argv[argc] = args;
- argc++;
- }
- } else {
- if (!(job->flags & JOB_IGNERR) && commandShell->exit) {
- argv[argc] = UNCONST(commandShell->exit);
- argc++;
- }
- if (!(job->flags & JOB_SILENT) && commandShell->echo) {
- argv[argc] = UNCONST(commandShell->echo);
- argc++;
- }
- }
- argv[argc] = NULL;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * JobStart --
- * Start a target-creation process going for the target described
- * by the graph node gn.
- *
- * Input:
- * gn target to create
- * flags flags for the job to override normal ones.
- * e.g. JOB_SPECIAL or JOB_IGNDOTS
- * previous The previous Job structure for this node, if any.
- *
- * Results:
- * JOB_ERROR if there was an error in the commands, JOB_FINISHED
- * if there isn't actually anything left to do for the job and
- * JOB_RUNNING if the job has been started.
- *
- * Side Effects:
- * A new Job node is created and added to the list of running
- * jobs. PMake is forked and a child shell created.
- *
- * NB: I'm fairly sure that this code is never called with JOB_SPECIAL set
- * JOB_IGNDOTS is never set (dsl)
- * Also the return value is ignored by everyone.
- *-----------------------------------------------------------------------
- */
-static int
-JobStart(GNode *gn, int flags)
-{
- Job *job; /* new job descriptor */
- char *argv[10]; /* Argument vector to shell */
- Boolean cmdsOK; /* true if the nodes commands were all right */
- Boolean noExec; /* Set true if we decide not to run the job */
- int tfd; /* File descriptor to the temp file */
-
- for (job = job_table; job < job_table_end; job++) {
- if (job->job_state == JOB_ST_FREE)
- break;
- }
- if (job >= job_table_end)
- Punt("JobStart no job slots vacant");
-
- memset(job, 0, sizeof *job);
- job->job_state = JOB_ST_SETUP;
- if (gn->type & OP_SPECIAL)
- flags |= JOB_SPECIAL;
-
- job->node = gn;
- job->tailCmds = NULL;
-
- /*
- * Set the initial value of the flags for this job based on the global
- * ones and the node's attributes... Any flags supplied by the caller
- * are also added to the field.
- */
- job->flags = 0;
- if (Targ_Ignore(gn)) {
- job->flags |= JOB_IGNERR;
- }
- if (Targ_Silent(gn)) {
- job->flags |= JOB_SILENT;
- }
- job->flags |= flags;
-
- /*
- * Check the commands now so any attributes from .DEFAULT have a chance
- * to migrate to the node
- */
- cmdsOK = Job_CheckCommands(gn, Error);
-
- job->inPollfd = NULL;
- /*
- * If the -n flag wasn't given, we open up OUR (not the child's)
- * temporary file to stuff commands in it. The thing is rd/wr so we don't
- * need to reopen it to feed it to the shell. If the -n flag *was* given,
- * we just set the file to be stdout. Cute, huh?
- */
- if (((gn->type & OP_MAKE) && !(noRecursiveExecute)) ||
- (!noExecute && !touchFlag)) {
- /*
- * tfile is the name of a file into which all shell commands are
- * put. It is removed before the child shell is executed, unless
- * DEBUG(SCRIPT) is set.
- */
- char *tfile;
- sigset_t mask;
- /*
- * We're serious here, but if the commands were bogus, we're
- * also dead...
- */
- if (!cmdsOK) {
- PrintOnError(gn, NULL); /* provide some clue */
- DieHorribly();
- }
-
- JobSigLock(&mask);
- tfd = mkTempFile(TMPPAT, &tfile);
- if (!DEBUG(SCRIPT))
- (void)eunlink(tfile);
- JobSigUnlock(&mask);
-
- job->cmdFILE = fdopen(tfd, "w+");
- if (job->cmdFILE == NULL) {
- Punt("Could not fdopen %s", tfile);
- }
- (void)fcntl(FILENO(job->cmdFILE), F_SETFD, FD_CLOEXEC);
- /*
- * Send the commands to the command file, flush all its buffers then
- * rewind and remove the thing.
- */
- noExec = FALSE;
-
-#ifdef USE_META
- if (useMeta) {
- meta_job_start(job, gn);
- if (Targ_Silent(gn)) { /* might have changed */
- job->flags |= JOB_SILENT;
- }
- }
-#endif
- /*
- * We can do all the commands at once. hooray for sanity
- */
- numCommands = 0;
- Lst_ForEach(gn->commands, JobPrintCommand, job);
-
- /*
- * If we didn't print out any commands to the shell script,
- * there's not much point in executing the shell, is there?
- */
- if (numCommands == 0) {
- noExec = TRUE;
- }
-
- free(tfile);
- } else if (NoExecute(gn)) {
- /*
- * Not executing anything -- just print all the commands to stdout
- * in one fell swoop. This will still set up job->tailCmds correctly.
- */
- if (lastNode != gn) {
- MESSAGE(stdout, gn);
- lastNode = gn;
- }
- job->cmdFILE = stdout;
- /*
- * Only print the commands if they're ok, but don't die if they're
- * not -- just let the user know they're bad and keep going. It
- * doesn't do any harm in this case and may do some good.
- */
- if (cmdsOK) {
- Lst_ForEach(gn->commands, JobPrintCommand, job);
- }
- /*
- * Don't execute the shell, thank you.
- */
- noExec = TRUE;
- } else {
- /*
- * Just touch the target and note that no shell should be executed.
- * Set cmdFILE to stdout to make life easier. Check the commands, too,
- * but don't die if they're no good -- it does no harm to keep working
- * up the graph.
- */
- job->cmdFILE = stdout;
- Job_Touch(gn, job->flags&JOB_SILENT);
- noExec = TRUE;
- }
- /* Just in case it isn't already... */
- (void)fflush(job->cmdFILE);
-
- /*
- * If we're not supposed to execute a shell, don't.
- */
- if (noExec) {
- if (!(job->flags & JOB_SPECIAL))
- Job_TokenReturn();
- /*
- * Unlink and close the command file if we opened one
- */
- if (job->cmdFILE != stdout) {
- if (job->cmdFILE != NULL) {
- (void)fclose(job->cmdFILE);
- job->cmdFILE = NULL;
- }
- }
-
- /*
- * We only want to work our way up the graph if we aren't here because
- * the commands for the job were no good.
- */
- if (cmdsOK && aborting == 0) {
- if (job->tailCmds != NULL) {
- Lst_ForEachFrom(job->node->commands, job->tailCmds,
- JobSaveCommand,
- job->node);
- }
- job->node->made = MADE;
- Make_Update(job->node);
- }
- job->job_state = JOB_ST_FREE;
- return cmdsOK ? JOB_FINISHED : JOB_ERROR;
- }
-
- /*
- * Set up the control arguments to the shell. This is based on the flags
- * set earlier for this job.
- */
- JobMakeArgv(job, argv);
-
- /* Create the pipe by which we'll get the shell's output. */
- JobCreatePipe(job, 3);
-
- JobExec(job, argv);
- return(JOB_RUNNING);
-}
-
-static char *
-JobOutput(Job *job, char *cp, char *endp, int msg)
-{
- char *ecp;
-
- if (commandShell->noPrint) {
- ecp = Str_FindSubstring(cp, commandShell->noPrint);
- while (ecp != NULL) {
- if (cp != ecp) {
- *ecp = '\0';
- if (!beSilent && msg && job->node != lastNode) {
- MESSAGE(stdout, job->node);
- lastNode = job->node;
- }
- /*
- * The only way there wouldn't be a newline after
- * this line is if it were the last in the buffer.
- * however, since the non-printable comes after it,
- * there must be a newline, so we don't print one.
- */
- (void)fprintf(stdout, "%s", cp);
- (void)fflush(stdout);
- }
- cp = ecp + commandShell->noPLen;
- if (cp != endp) {
- /*
- * Still more to print, look again after skipping
- * the whitespace following the non-printable
- * command....
- */
- cp++;
- while (*cp == ' ' || *cp == '\t' || *cp == '\n') {
- cp++;
- }
- ecp = Str_FindSubstring(cp, commandShell->noPrint);
- } else {
- return cp;
- }
- }
- }
- return cp;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * JobDoOutput --
- * This function is called at different times depending on
- * whether the user has specified that output is to be collected
- * via pipes or temporary files. In the former case, we are called
- * whenever there is something to read on the pipe. We collect more
- * output from the given job and store it in the job's outBuf. If
- * this makes up a line, we print it tagged by the job's identifier,
- * as necessary.
- * If output has been collected in a temporary file, we open the
- * file and read it line by line, transfering it to our own
- * output channel until the file is empty. At which point we
- * remove the temporary file.
- * In both cases, however, we keep our figurative eye out for the
- * 'noPrint' line for the shell from which the output came. If
- * we recognize a line, we don't print it. If the command is not
- * alone on the line (the character after it is not \0 or \n), we
- * do print whatever follows it.
- *
- * Input:
- * job the job whose output needs printing
- * finish TRUE if this is the last time we'll be called
- * for this job
- *
- * Results:
- * None
- *
- * Side Effects:
- * curPos may be shifted as may the contents of outBuf.
- *-----------------------------------------------------------------------
- */
-STATIC void
-JobDoOutput(Job *job, Boolean finish)
-{
- Boolean gotNL = FALSE; /* true if got a newline */
- Boolean fbuf; /* true if our buffer filled up */
- int nr; /* number of bytes read */
- int i; /* auxiliary index into outBuf */
- int max; /* limit for i (end of current data) */
- int nRead; /* (Temporary) number of bytes read */
-
- /*
- * Read as many bytes as will fit in the buffer.
- */
-end_loop:
- gotNL = FALSE;
- fbuf = FALSE;
-
- nRead = read(job->inPipe, &job->outBuf[job->curPos],
- JOB_BUFSIZE - job->curPos);
- if (nRead < 0) {
- if (errno == EAGAIN)
- return;
- if (DEBUG(JOB)) {
- perror("JobDoOutput(piperead)");
- }
- nr = 0;
- } else {
- nr = nRead;
- }
-
- /*
- * If we hit the end-of-file (the job is dead), we must flush its
- * remaining output, so pretend we read a newline if there's any
- * output remaining in the buffer.
- * Also clear the 'finish' flag so we stop looping.
- */
- if ((nr == 0) && (job->curPos != 0)) {
- job->outBuf[job->curPos] = '\n';
- nr = 1;
- finish = FALSE;
- } else if (nr == 0) {
- finish = FALSE;
- }
-
- /*
- * Look for the last newline in the bytes we just got. If there is
- * one, break out of the loop with 'i' as its index and gotNL set
- * TRUE.
- */
- max = job->curPos + nr;
- for (i = job->curPos + nr - 1; i >= job->curPos; i--) {
- if (job->outBuf[i] == '\n') {
- gotNL = TRUE;
- break;
- } else if (job->outBuf[i] == '\0') {
- /*
- * Why?
- */
- job->outBuf[i] = ' ';
- }
- }
-
- if (!gotNL) {
- job->curPos += nr;
- if (job->curPos == JOB_BUFSIZE) {
- /*
- * If we've run out of buffer space, we have no choice
- * but to print the stuff. sigh.
- */
- fbuf = TRUE;
- i = job->curPos;
- }
- }
- if (gotNL || fbuf) {
- /*
- * Need to send the output to the screen. Null terminate it
- * first, overwriting the newline character if there was one.
- * So long as the line isn't one we should filter (according
- * to the shell description), we print the line, preceded
- * by a target banner if this target isn't the same as the
- * one for which we last printed something.
- * The rest of the data in the buffer are then shifted down
- * to the start of the buffer and curPos is set accordingly.
- */
- job->outBuf[i] = '\0';
- if (i >= job->curPos) {
- char *cp;
-
- cp = JobOutput(job, job->outBuf, &job->outBuf[i], FALSE);
-
- /*
- * There's still more in that thar buffer. This time, though,
- * we know there's no newline at the end, so we add one of
- * our own free will.
- */
- if (*cp != '\0') {
- if (!beSilent && job->node != lastNode) {
- MESSAGE(stdout, job->node);
- lastNode = job->node;
- }
-#ifdef USE_META
- if (useMeta) {
- meta_job_output(job, cp, gotNL ? "\n" : "");
- }
-#endif
- (void)fprintf(stdout, "%s%s", cp, gotNL ? "\n" : "");
- (void)fflush(stdout);
- }
- }
- /*
- * max is the last offset still in the buffer. Move any remaining
- * characters to the start of the buffer and update the end marker
- * curPos.
- */
- if (i < max) {
- (void)memmove(job->outBuf, &job->outBuf[i + 1], max - (i + 1));
- job->curPos = max - (i + 1);
- } else {
- assert(i == max);
- job->curPos = 0;
- }
- }
- if (finish) {
- /*
- * If the finish flag is true, we must loop until we hit
- * end-of-file on the pipe. This is guaranteed to happen
- * eventually since the other end of the pipe is now closed
- * (we closed it explicitly and the child has exited). When
- * we do get an EOF, finish will be set FALSE and we'll fall
- * through and out.
- */
- goto end_loop;
- }
-}
-
-static void
-JobRun(GNode *targ)
-{
-#ifdef notyet
- /*
- * Unfortunately it is too complicated to run .BEGIN, .END,
- * and .INTERRUPT job in the parallel job module. This has
- * the nice side effect that it avoids a lot of other problems.
- */
- Lst lst = Lst_Init(FALSE);
- Lst_AtEnd(lst, targ);
- (void)Make_Run(lst);
- Lst_Destroy(lst, NULL);
- JobStart(targ, JOB_SPECIAL);
- while (jobTokensRunning) {
- Job_CatchOutput();
- }
-#else
- Compat_Make(targ, targ);
- if (targ->made == ERROR) {
- PrintOnError(targ, "\n\nStop.");
- exit(1);
- }
-#endif
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Job_CatchChildren --
- * Handle the exit of a child. Called from Make_Make.
- *
- * Input:
- * block TRUE if should block on the wait
- *
- * Results:
- * none.
- *
- * Side Effects:
- * The job descriptor is removed from the list of children.
- *
- * Notes:
- * We do waits, blocking or not, according to the wisdom of our
- * caller, until there are no more children to report. For each
- * job, call JobFinish to finish things off.
- *
- *-----------------------------------------------------------------------
- */
-
-void
-Job_CatchChildren(void)
-{
- int pid; /* pid of dead child */
- int status; /* Exit/termination status */
-
- /*
- * Don't even bother if we know there's no one around.
- */
- if (jobTokensRunning == 0)
- return;
-
- while ((pid = waitpid((pid_t) -1, &status, WNOHANG | WUNTRACED)) > 0) {
- if (DEBUG(JOB)) {
- (void)fprintf(debug_file, "Process %d exited/stopped status %x.\n", pid,
- status);
- }
- JobReapChild(pid, status, TRUE);
- }
-}
-
-/*
- * It is possible that wait[pid]() was called from elsewhere,
- * this lets us reap jobs regardless.
- */
-void
-JobReapChild(pid_t pid, int status, Boolean isJobs)
-{
- Job *job; /* job descriptor for dead child */
-
- /*
- * Don't even bother if we know there's no one around.
- */
- if (jobTokensRunning == 0)
- return;
-
- job = JobFindPid(pid, JOB_ST_RUNNING, isJobs);
- if (job == NULL) {
- if (isJobs) {
- if (!lurking_children)
- Error("Child (%d) status %x not in table?", pid, status);
- }
- return; /* not ours */
- }
- if (WIFSTOPPED(status)) {
- if (DEBUG(JOB)) {
- (void)fprintf(debug_file, "Process %d (%s) stopped.\n",
- job->pid, job->node->name);
- }
- if (!make_suspended) {
- switch (WSTOPSIG(status)) {
- case SIGTSTP:
- (void)printf("*** [%s] Suspended\n", job->node->name);
- break;
- case SIGSTOP:
- (void)printf("*** [%s] Stopped\n", job->node->name);
- break;
- default:
- (void)printf("*** [%s] Stopped -- signal %d\n",
- job->node->name, WSTOPSIG(status));
- }
- job->job_suspended = 1;
- }
- (void)fflush(stdout);
- return;
- }
-
- job->job_state = JOB_ST_FINISHED;
- job->exit_status = status;
-
- JobFinish(job, status);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Job_CatchOutput --
- * Catch the output from our children, if we're using
- * pipes do so. Otherwise just block time until we get a
- * signal(most likely a SIGCHLD) since there's no point in
- * just spinning when there's nothing to do and the reaping
- * of a child can wait for a while.
- *
- * Results:
- * None
- *
- * Side Effects:
- * Output is read from pipes if we're piping.
- * -----------------------------------------------------------------------
- */
-void
-Job_CatchOutput(void)
-{
- int nready;
- Job *job;
- int i;
-
- (void)fflush(stdout);
-
- /* The first fd in the list is the job token pipe */
- do {
- nready = poll(fds + 1 - wantToken, nfds - 1 + wantToken, POLL_MSEC);
- } while (nready < 0 && errno == EINTR);
-
- if (nready < 0)
- Punt("poll: %s", strerror(errno));
-
- if (nready > 0 && readyfd(&childExitJob)) {
- char token = 0;
- ssize_t count;
- count = read(childExitJob.inPipe, &token, 1);
- switch (count) {
- case 0:
- Punt("unexpected eof on token pipe");
- case -1:
- Punt("token pipe read: %s", strerror(errno));
- case 1:
- if (token == DO_JOB_RESUME[0])
- /* Complete relay requested from our SIGCONT handler */
- JobRestartJobs();
- break;
- default:
- abort();
- }
- --nready;
- }
-
- Job_CatchChildren();
- if (nready == 0)
- return;
-
- for (i = 2; i < nfds; i++) {
- if (!fds[i].revents)
- continue;
- job = jobfds[i];
- if (job->job_state == JOB_ST_RUNNING)
- JobDoOutput(job, FALSE);
- if (--nready == 0)
- return;
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Job_Make --
- * Start the creation of a target. Basically a front-end for
- * JobStart used by the Make module.
- *
- * Results:
- * None.
- *
- * Side Effects:
- * Another job is started.
- *
- *-----------------------------------------------------------------------
- */
-void
-Job_Make(GNode *gn)
-{
- (void)JobStart(gn, 0);
-}
-
-void
-Shell_Init(void)
-{
- if (shellPath == NULL) {
- /*
- * We are using the default shell, which may be an absolute
- * path if DEFSHELL_CUSTOM is defined.
- */
- shellName = commandShell->name;
-#ifdef DEFSHELL_CUSTOM
- if (*shellName == '/') {
- shellPath = shellName;
- shellName = strrchr(shellPath, '/');
- shellName++;
- } else
-#endif
- shellPath = str_concat(_PATH_DEFSHELLDIR, shellName, STR_ADDSLASH);
- }
- if (commandShell->exit == NULL) {
- commandShell->exit = "";
- }
- if (commandShell->echo == NULL) {
- commandShell->echo = "";
- }
- if (commandShell->hasErrCtl && *commandShell->exit) {
- if (shellErrFlag &&
- strcmp(commandShell->exit, &shellErrFlag[1]) != 0) {
- free(shellErrFlag);
- shellErrFlag = NULL;
- }
- if (!shellErrFlag) {
- int n = strlen(commandShell->exit) + 2;
-
- shellErrFlag = bmake_malloc(n);
- if (shellErrFlag) {
- snprintf(shellErrFlag, n, "-%s", commandShell->exit);
- }
- }
- } else if (shellErrFlag) {
- free(shellErrFlag);
- shellErrFlag = NULL;
- }
-}
-
-/*-
- * Returns the string literal that is used in the current command shell
- * to produce a newline character.
- */
-const char *
-Shell_GetNewline(void)
-{
-
- return commandShell->newline;
-}
-
-void
-Job_SetPrefix(void)
-{
-
- if (targPrefix) {
- free(targPrefix);
- } else if (!Var_Exists(MAKE_JOB_PREFIX, VAR_GLOBAL)) {
- Var_Set(MAKE_JOB_PREFIX, "---", VAR_GLOBAL, 0);
- }
-
- targPrefix = Var_Subst(NULL, "${" MAKE_JOB_PREFIX "}",
- VAR_GLOBAL, VARF_WANTRES);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Job_Init --
- * Initialize the process module
- *
- * Input:
- *
- * Results:
- * none
- *
- * Side Effects:
- * lists and counters are initialized
- *-----------------------------------------------------------------------
- */
-void
-Job_Init(void)
-{
- Job_SetPrefix();
- /* Allocate space for all the job info */
- job_table = bmake_malloc(maxJobs * sizeof *job_table);
- memset(job_table, 0, maxJobs * sizeof *job_table);
- job_table_end = job_table + maxJobs;
- wantToken = 0;
-
- aborting = 0;
- errors = 0;
-
- lastNode = NULL;
-
- /*
- * There is a non-zero chance that we already have children.
- * eg after 'make -f- <<EOF'
- * Since their termination causes a 'Child (pid) not in table' message,
- * Collect the status of any that are already dead, and suppress the
- * error message if there are any undead ones.
- */
- for (;;) {
- int rval, status;
- rval = waitpid((pid_t) -1, &status, WNOHANG);
- if (rval > 0)
- continue;
- if (rval == 0)
- lurking_children = 1;
- break;
- }
-
- Shell_Init();
-
- JobCreatePipe(&childExitJob, 3);
-
- /* We can only need to wait for tokens, children and output from each job */
- fds = bmake_malloc(sizeof (*fds) * (2 + maxJobs));
- jobfds = bmake_malloc(sizeof (*jobfds) * (2 + maxJobs));
-
- /* These are permanent entries and take slots 0 and 1 */
- watchfd(&tokenWaitJob);
- watchfd(&childExitJob);
-
- sigemptyset(&caught_signals);
- /*
- * Install a SIGCHLD handler.
- */
- (void)bmake_signal(SIGCHLD, JobChildSig);
- sigaddset(&caught_signals, SIGCHLD);
-
-#define ADDSIG(s,h) \
- if (bmake_signal(s, SIG_IGN) != SIG_IGN) { \
- sigaddset(&caught_signals, s); \
- (void)bmake_signal(s, h); \
- }
-
- /*
- * Catch the four signals that POSIX specifies if they aren't ignored.
- * JobPassSig will take care of calling JobInterrupt if appropriate.
- */
- ADDSIG(SIGINT, JobPassSig_int)
- ADDSIG(SIGHUP, JobPassSig_term)
- ADDSIG(SIGTERM, JobPassSig_term)
- ADDSIG(SIGQUIT, JobPassSig_term)
-
- /*
- * There are additional signals that need to be caught and passed if
- * either the export system wants to be told directly of signals or if
- * we're giving each job its own process group (since then it won't get
- * signals from the terminal driver as we own the terminal)
- */
- ADDSIG(SIGTSTP, JobPassSig_suspend)
- ADDSIG(SIGTTOU, JobPassSig_suspend)
- ADDSIG(SIGTTIN, JobPassSig_suspend)
- ADDSIG(SIGWINCH, JobCondPassSig)
- ADDSIG(SIGCONT, JobContinueSig)
-#undef ADDSIG
-
- (void)Job_RunTarget(".BEGIN", NULL);
- postCommands = Targ_FindNode(".END", TARG_CREATE);
-}
-
-static void JobSigReset(void)
-{
-#define DELSIG(s) \
- if (sigismember(&caught_signals, s)) { \
- (void)bmake_signal(s, SIG_DFL); \
- }
-
- DELSIG(SIGINT)
- DELSIG(SIGHUP)
- DELSIG(SIGQUIT)
- DELSIG(SIGTERM)
- DELSIG(SIGTSTP)
- DELSIG(SIGTTOU)
- DELSIG(SIGTTIN)
- DELSIG(SIGWINCH)
- DELSIG(SIGCONT)
-#undef DELSIG
- (void)bmake_signal(SIGCHLD, SIG_DFL);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * JobMatchShell --
- * Find a shell in 'shells' given its name.
- *
- * Results:
- * A pointer to the Shell structure.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-static Shell *
-JobMatchShell(const char *name)
-{
- Shell *sh;
-
- for (sh = shells; sh->name != NULL; sh++) {
- if (strcmp(name, sh->name) == 0)
- return (sh);
- }
- return NULL;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Job_ParseShell --
- * Parse a shell specification and set up commandShell, shellPath
- * and shellName appropriately.
- *
- * Input:
- * line The shell spec
- *
- * Results:
- * FAILURE if the specification was incorrect.
- *
- * Side Effects:
- * commandShell points to a Shell structure (either predefined or
- * created from the shell spec), shellPath is the full path of the
- * shell described by commandShell, while shellName is just the
- * final component of shellPath.
- *
- * Notes:
- * A shell specification consists of a .SHELL target, with dependency
- * operator, followed by a series of blank-separated words. Double
- * quotes can be used to use blanks in words. A backslash escapes
- * anything (most notably a double-quote and a space) and
- * provides the functionality it does in C. Each word consists of
- * keyword and value separated by an equal sign. There should be no
- * unnecessary spaces in the word. The keywords are as follows:
- * name Name of shell.
- * path Location of shell.
- * quiet Command to turn off echoing.
- * echo Command to turn echoing on
- * filter Result of turning off echoing that shouldn't be
- * printed.
- * echoFlag Flag to turn echoing on at the start
- * errFlag Flag to turn error checking on at the start
- * hasErrCtl True if shell has error checking control
- * newline String literal to represent a newline char
- * check Command to turn on error checking if hasErrCtl
- * is TRUE or template of command to echo a command
- * for which error checking is off if hasErrCtl is
- * FALSE.
- * ignore Command to turn off error checking if hasErrCtl
- * is TRUE or template of command to execute a
- * command so as to ignore any errors it returns if
- * hasErrCtl is FALSE.
- *
- *-----------------------------------------------------------------------
- */
-ReturnStatus
-Job_ParseShell(char *line)
-{
- char **words;
- char **argv;
- int argc;
- char *path;
- Shell newShell;
- Boolean fullSpec = FALSE;
- Shell *sh;
-
- while (isspace((unsigned char)*line)) {
- line++;
- }
-
- free(UNCONST(shellArgv));
-
- memset(&newShell, 0, sizeof(newShell));
-
- /*
- * Parse the specification by keyword
- */
- words = brk_string(line, &argc, TRUE, &path);
- if (words == NULL) {
- Error("Unterminated quoted string [%s]", line);
- return FAILURE;
- }
- shellArgv = path;
-
- for (path = NULL, argv = words; argc != 0; argc--, argv++) {
- if (strncmp(*argv, "path=", 5) == 0) {
- path = &argv[0][5];
- } else if (strncmp(*argv, "name=", 5) == 0) {
- newShell.name = &argv[0][5];
- } else {
- if (strncmp(*argv, "quiet=", 6) == 0) {
- newShell.echoOff = &argv[0][6];
- } else if (strncmp(*argv, "echo=", 5) == 0) {
- newShell.echoOn = &argv[0][5];
- } else if (strncmp(*argv, "filter=", 7) == 0) {
- newShell.noPrint = &argv[0][7];
- newShell.noPLen = strlen(newShell.noPrint);
- } else if (strncmp(*argv, "echoFlag=", 9) == 0) {
- newShell.echo = &argv[0][9];
- } else if (strncmp(*argv, "errFlag=", 8) == 0) {
- newShell.exit = &argv[0][8];
- } else if (strncmp(*argv, "hasErrCtl=", 10) == 0) {
- char c = argv[0][10];
- newShell.hasErrCtl = !((c != 'Y') && (c != 'y') &&
- (c != 'T') && (c != 't'));
- } else if (strncmp(*argv, "newline=", 8) == 0) {
- newShell.newline = &argv[0][8];
- } else if (strncmp(*argv, "check=", 6) == 0) {
- newShell.errCheck = &argv[0][6];
- } else if (strncmp(*argv, "ignore=", 7) == 0) {
- newShell.ignErr = &argv[0][7];
- } else if (strncmp(*argv, "errout=", 7) == 0) {
- newShell.errOut = &argv[0][7];
- } else if (strncmp(*argv, "comment=", 8) == 0) {
- newShell.commentChar = argv[0][8];
- } else {
- Parse_Error(PARSE_FATAL, "Unknown keyword \"%s\"",
- *argv);
- free(words);
- return(FAILURE);
- }
- fullSpec = TRUE;
- }
- }
-
- if (path == NULL) {
- /*
- * If no path was given, the user wants one of the pre-defined shells,
- * yes? So we find the one s/he wants with the help of JobMatchShell
- * and set things up the right way. shellPath will be set up by
- * Shell_Init.
- */
- if (newShell.name == NULL) {
- Parse_Error(PARSE_FATAL, "Neither path nor name specified");
- free(words);
- return(FAILURE);
- } else {
- if ((sh = JobMatchShell(newShell.name)) == NULL) {
- Parse_Error(PARSE_WARNING, "%s: No matching shell",
- newShell.name);
- free(words);
- return(FAILURE);
- }
- commandShell = sh;
- shellName = newShell.name;
- if (shellPath) {
- /* Shell_Init has already been called! Do it again. */
- free(UNCONST(shellPath));
- shellPath = NULL;
- Shell_Init();
- }
- }
- } else {
- /*
- * The user provided a path. If s/he gave nothing else (fullSpec is
- * FALSE), try and find a matching shell in the ones we know of.
- * Else we just take the specification at its word and copy it
- * to a new location. In either case, we need to record the
- * path the user gave for the shell.
- */
- shellPath = path;
- path = strrchr(path, '/');
- if (path == NULL) {
- path = UNCONST(shellPath);
- } else {
- path += 1;
- }
- if (newShell.name != NULL) {
- shellName = newShell.name;
- } else {
- shellName = path;
- }
- if (!fullSpec) {
- if ((sh = JobMatchShell(shellName)) == NULL) {
- Parse_Error(PARSE_WARNING, "%s: No matching shell",
- shellName);
- free(words);
- return(FAILURE);
- }
- commandShell = sh;
- } else {
- commandShell = bmake_malloc(sizeof(Shell));
- *commandShell = newShell;
- }
- /* this will take care of shellErrFlag */
- Shell_Init();
- }
-
- if (commandShell->echoOn && commandShell->echoOff) {
- commandShell->hasEchoCtl = TRUE;
- }
-
- if (!commandShell->hasErrCtl) {
- if (commandShell->errCheck == NULL) {
- commandShell->errCheck = "";
- }
- if (commandShell->ignErr == NULL) {
- commandShell->ignErr = "%s\n";
- }
- }
-
- /*
- * Do not free up the words themselves, since they might be in use by the
- * shell specification.
- */
- free(words);
- return SUCCESS;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * JobInterrupt --
- * Handle the receipt of an interrupt.
- *
- * Input:
- * runINTERRUPT Non-zero if commands for the .INTERRUPT target
- * should be executed
- * signo signal received
- *
- * Results:
- * None
- *
- * Side Effects:
- * All children are killed. Another job will be started if the
- * .INTERRUPT target was given.
- *-----------------------------------------------------------------------
- */
-static void
-JobInterrupt(int runINTERRUPT, int signo)
-{
- Job *job; /* job descriptor in that element */
- GNode *interrupt; /* the node describing the .INTERRUPT target */
- sigset_t mask;
- GNode *gn;
-
- aborting = ABORT_INTERRUPT;
-
- JobSigLock(&mask);
-
- for (job = job_table; job < job_table_end; job++) {
- if (job->job_state != JOB_ST_RUNNING)
- continue;
-
- gn = job->node;
-
- JobDeleteTarget(gn);
- if (job->pid) {
- if (DEBUG(JOB)) {
- (void)fprintf(debug_file,
- "JobInterrupt passing signal %d to child %d.\n",
- signo, job->pid);
- }
- KILLPG(job->pid, signo);
- }
- }
-
- JobSigUnlock(&mask);
-
- if (runINTERRUPT && !touchFlag) {
- interrupt = Targ_FindNode(".INTERRUPT", TARG_NOCREATE);
- if (interrupt != NULL) {
- ignoreErrors = FALSE;
- JobRun(interrupt);
- }
- }
- Trace_Log(MAKEINTR, 0);
- exit(signo);
-}
-
-/*
- *-----------------------------------------------------------------------
- * Job_Finish --
- * Do final processing such as the running of the commands
- * attached to the .END target.
- *
- * Results:
- * Number of errors reported.
- *
- * Side Effects:
- * None.
- *-----------------------------------------------------------------------
- */
-int
-Job_Finish(void)
-{
- if (postCommands != NULL &&
- (!Lst_IsEmpty(postCommands->commands) ||
- !Lst_IsEmpty(postCommands->children))) {
- if (errors) {
- Error("Errors reported so .END ignored");
- } else {
- JobRun(postCommands);
- }
- }
- return(errors);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Job_End --
- * Cleanup any memory used by the jobs module
- *
- * Results:
- * None.
- *
- * Side Effects:
- * Memory is freed
- *-----------------------------------------------------------------------
- */
-void
-Job_End(void)
-{
-#ifdef CLEANUP
- free(shellArgv);
-#endif
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Job_Wait --
- * Waits for all running jobs to finish and returns. Sets 'aborting'
- * to ABORT_WAIT to prevent other jobs from starting.
- *
- * Results:
- * None.
- *
- * Side Effects:
- * Currently running jobs finish.
- *
- *-----------------------------------------------------------------------
- */
-void
-Job_Wait(void)
-{
- aborting = ABORT_WAIT;
- while (jobTokensRunning != 0) {
- Job_CatchOutput();
- }
- aborting = 0;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Job_AbortAll --
- * Abort all currently running jobs without handling output or anything.
- * This function is to be called only in the event of a major
- * error. Most definitely NOT to be called from JobInterrupt.
- *
- * Results:
- * None
- *
- * Side Effects:
- * All children are killed, not just the firstborn
- *-----------------------------------------------------------------------
- */
-void
-Job_AbortAll(void)
-{
- Job *job; /* the job descriptor in that element */
- int foo;
-
- aborting = ABORT_ERROR;
-
- if (jobTokensRunning) {
- for (job = job_table; job < job_table_end; job++) {
- if (job->job_state != JOB_ST_RUNNING)
- continue;
- /*
- * kill the child process with increasingly drastic signals to make
- * darn sure it's dead.
- */
- KILLPG(job->pid, SIGINT);
- KILLPG(job->pid, SIGKILL);
- }
- }
-
- /*
- * Catch as many children as want to report in at first, then give up
- */
- while (waitpid((pid_t) -1, &foo, WNOHANG) > 0)
- continue;
-}
-
-
-/*-
- *-----------------------------------------------------------------------
- * JobRestartJobs --
- * Tries to restart stopped jobs if there are slots available.
- * Called in process context in response to a SIGCONT.
- *
- * Results:
- * None.
- *
- * Side Effects:
- * Resumes jobs.
- *
- *-----------------------------------------------------------------------
- */
-static void
-JobRestartJobs(void)
-{
- Job *job;
-
- for (job = job_table; job < job_table_end; job++) {
- if (job->job_state == JOB_ST_RUNNING &&
- (make_suspended || job->job_suspended)) {
- if (DEBUG(JOB)) {
- (void)fprintf(debug_file, "Restarting stopped job pid %d.\n",
- job->pid);
- }
- if (job->job_suspended) {
- (void)printf("*** [%s] Continued\n", job->node->name);
- (void)fflush(stdout);
- }
- job->job_suspended = 0;
- if (KILLPG(job->pid, SIGCONT) != 0 && DEBUG(JOB)) {
- fprintf(debug_file, "Failed to send SIGCONT to %d\n", job->pid);
- }
- }
- if (job->job_state == JOB_ST_FINISHED)
- /* Job exit deferred after calling waitpid() in a signal handler */
- JobFinish(job, job->exit_status);
- }
- make_suspended = 0;
-}
-
-static void
-watchfd(Job *job)
-{
- if (job->inPollfd != NULL)
- Punt("Watching watched job");
-
- fds[nfds].fd = job->inPipe;
- fds[nfds].events = POLLIN;
- jobfds[nfds] = job;
- job->inPollfd = &fds[nfds];
- nfds++;
-}
-
-static void
-clearfd(Job *job)
-{
- int i;
- if (job->inPollfd == NULL)
- Punt("Unwatching unwatched job");
- i = job->inPollfd - fds;
- nfds--;
- /*
- * Move last job in table into hole made by dead job.
- */
- if (nfds != i) {
- fds[i] = fds[nfds];
- jobfds[i] = jobfds[nfds];
- jobfds[i]->inPollfd = &fds[i];
- }
- job->inPollfd = NULL;
-}
-
-static int
-readyfd(Job *job)
-{
- if (job->inPollfd == NULL)
- Punt("Polling unwatched job");
- return (job->inPollfd->revents & POLLIN) != 0;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * JobTokenAdd --
- * Put a token into the job pipe so that some make process can start
- * another job.
- *
- * Side Effects:
- * Allows more build jobs to be spawned somewhere.
- *
- *-----------------------------------------------------------------------
- */
-
-static void
-JobTokenAdd(void)
-{
- char tok = JOB_TOKENS[aborting], tok1;
-
- /* If we are depositing an error token flush everything else */
- while (tok != '+' && read(tokenWaitJob.inPipe, &tok1, 1) == 1)
- continue;
-
- if (DEBUG(JOB))
- fprintf(debug_file, "(%d) aborting %d, deposit token %c\n",
- getpid(), aborting, JOB_TOKENS[aborting]);
- while (write(tokenWaitJob.outPipe, &tok, 1) == -1 && errno == EAGAIN)
- continue;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Job_ServerStartTokenAdd --
- * Prep the job token pipe in the root make process.
- *
- *-----------------------------------------------------------------------
- */
-
-void
-Job_ServerStart(int max_tokens, int jp_0, int jp_1)
-{
- int i;
- char jobarg[64];
-
- if (jp_0 >= 0 && jp_1 >= 0) {
- /* Pipe passed in from parent */
- tokenWaitJob.inPipe = jp_0;
- tokenWaitJob.outPipe = jp_1;
- (void)fcntl(jp_0, F_SETFD, FD_CLOEXEC);
- (void)fcntl(jp_1, F_SETFD, FD_CLOEXEC);
- return;
- }
-
- JobCreatePipe(&tokenWaitJob, 15);
-
- snprintf(jobarg, sizeof(jobarg), "%d,%d",
- tokenWaitJob.inPipe, tokenWaitJob.outPipe);
-
- Var_Append(MAKEFLAGS, "-J", VAR_GLOBAL);
- Var_Append(MAKEFLAGS, jobarg, VAR_GLOBAL);
-
- /*
- * Preload the job pipe with one token per job, save the one
- * "extra" token for the primary job.
- *
- * XXX should clip maxJobs against PIPE_BUF -- if max_tokens is
- * larger than the write buffer size of the pipe, we will
- * deadlock here.
- */
- for (i = 1; i < max_tokens; i++)
- JobTokenAdd();
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Job_TokenReturn --
- * Return a withdrawn token to the pool.
- *
- *-----------------------------------------------------------------------
- */
-
-void
-Job_TokenReturn(void)
-{
- jobTokensRunning--;
- if (jobTokensRunning < 0)
- Punt("token botch");
- if (jobTokensRunning || JOB_TOKENS[aborting] != '+')
- JobTokenAdd();
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Job_TokenWithdraw --
- * Attempt to withdraw a token from the pool.
- *
- * Results:
- * Returns TRUE if a token was withdrawn, and FALSE if the pool
- * is currently empty.
- *
- * Side Effects:
- * If pool is empty, set wantToken so that we wake up
- * when a token is released.
- *
- *-----------------------------------------------------------------------
- */
-
-
-Boolean
-Job_TokenWithdraw(void)
-{
- char tok, tok1;
- int count;
-
- wantToken = 0;
- if (DEBUG(JOB))
- fprintf(debug_file, "Job_TokenWithdraw(%d): aborting %d, running %d\n",
- getpid(), aborting, jobTokensRunning);
-
- if (aborting || (jobTokensRunning >= maxJobs))
- return FALSE;
-
- count = read(tokenWaitJob.inPipe, &tok, 1);
- if (count == 0)
- Fatal("eof on job pipe!");
- if (count < 0 && jobTokensRunning != 0) {
- if (errno != EAGAIN) {
- Fatal("job pipe read: %s", strerror(errno));
- }
- if (DEBUG(JOB))
- fprintf(debug_file, "(%d) blocked for token\n", getpid());
- return FALSE;
- }
-
- if (count == 1 && tok != '+') {
- /* make being abvorted - remove any other job tokens */
- if (DEBUG(JOB))
- fprintf(debug_file, "(%d) aborted by token %c\n", getpid(), tok);
- while (read(tokenWaitJob.inPipe, &tok1, 1) == 1)
- continue;
- /* And put the stopper back */
- while (write(tokenWaitJob.outPipe, &tok, 1) == -1 && errno == EAGAIN)
- continue;
- Fatal("A failure has been detected in another branch of the parallel make");
- }
-
- if (count == 1 && jobTokensRunning == 0)
- /* We didn't want the token really */
- while (write(tokenWaitJob.outPipe, &tok, 1) == -1 && errno == EAGAIN)
- continue;
-
- jobTokensRunning++;
- if (DEBUG(JOB))
- fprintf(debug_file, "(%d) withdrew token\n", getpid());
- return TRUE;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Job_RunTarget --
- * Run the named target if found. If a filename is specified, then
- * set that to the sources.
- *
- * Results:
- * None
- *
- * Side Effects:
- * exits if the target fails.
- *
- *-----------------------------------------------------------------------
- */
-Boolean
-Job_RunTarget(const char *target, const char *fname) {
- GNode *gn = Targ_FindNode(target, TARG_NOCREATE);
-
- if (gn == NULL)
- return FALSE;
-
- if (fname)
- Var_Set(ALLSRC, fname, gn, 0);
-
- JobRun(gn);
- if (gn->made == ERROR) {
- PrintOnError(gn, "\n\nStop.");
- exit(1);
- }
- return TRUE;
-}
-
-#ifdef USE_SELECT
-int
-emul_poll(struct pollfd *fd, int nfd, int timeout)
-{
- fd_set rfds, wfds;
- int i, maxfd, nselect, npoll;
- struct timeval tv, *tvp;
- long usecs;
-
- FD_ZERO(&rfds);
- FD_ZERO(&wfds);
-
- maxfd = -1;
- for (i = 0; i < nfd; i++) {
- fd[i].revents = 0;
-
- if (fd[i].events & POLLIN)
- FD_SET(fd[i].fd, &rfds);
-
- if (fd[i].events & POLLOUT)
- FD_SET(fd[i].fd, &wfds);
-
- if (fd[i].fd > maxfd)
- maxfd = fd[i].fd;
- }
-
- if (maxfd >= FD_SETSIZE) {
- Punt("Ran out of fd_set slots; "
- "recompile with a larger FD_SETSIZE.");
- }
-
- if (timeout < 0) {
- tvp = NULL;
- } else {
- usecs = timeout * 1000;
- tv.tv_sec = usecs / 1000000;
- tv.tv_usec = usecs % 1000000;
- tvp = &tv;
- }
-
- nselect = select(maxfd + 1, &rfds, &wfds, 0, tvp);
-
- if (nselect <= 0)
- return nselect;
-
- npoll = 0;
- for (i = 0; i < nfd; i++) {
- if (FD_ISSET(fd[i].fd, &rfds))
- fd[i].revents |= POLLIN;
-
- if (FD_ISSET(fd[i].fd, &wfds))
- fd[i].revents |= POLLOUT;
-
- if (fd[i].revents)
- npoll++;
- }
-
- return npoll;
-}
-#endif /* USE_SELECT */
diff --git a/usr.bin/make/job.h b/usr.bin/make/job.h
deleted file mode 100644
index 91e2c87..0000000
--- a/usr.bin/make/job.h
+++ /dev/null
@@ -1,274 +0,0 @@
-/* $NetBSD: job.h,v 1.42 2013/07/05 22:14:56 sjg Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- *
- * from: @(#)job.h 8.1 (Berkeley) 6/6/93
- */
-
-/*
- * Copyright (c) 1988, 1989 by Adam de Boor
- * Copyright (c) 1989 by Berkeley Softworks
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. 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.
- *
- * from: @(#)job.h 8.1 (Berkeley) 6/6/93
- */
-
-/*-
- * job.h --
- * Definitions pertaining to the running of jobs in parallel mode.
- */
-#ifndef _JOB_H_
-#define _JOB_H_
-
-#define TMPPAT "makeXXXXXX" /* relative to tmpdir */
-
-#ifdef USE_SELECT
-/*
- * Emulate poll() in terms of select(). This is not a complete
- * emulation but it is sufficient for make's purposes.
- */
-
-#define poll emul_poll
-#define pollfd emul_pollfd
-
-struct emul_pollfd {
- int fd;
- short events;
- short revents;
-};
-
-#define POLLIN 0x0001
-#define POLLOUT 0x0004
-
-int
-emul_poll(struct pollfd *fd, int nfd, int timeout);
-#endif
-
-/*
- * The POLL_MSEC constant determines the maximum number of milliseconds spent
- * in poll before coming out to see if a child has finished.
- */
-#define POLL_MSEC 5000
-
-
-/*-
- * Job Table definitions.
- *
- * Each job has several things associated with it:
- * 1) The process id of the child shell
- * 2) The graph node describing the target being made by this job
- * 3) A LstNode for the first command to be saved after the job
- * completes. This is NULL if there was no "..." in the job's
- * commands.
- * 4) An FILE* for writing out the commands. This is only
- * used before the job is actually started.
- * 5) The output is being caught via a pipe and
- * the descriptors of our pipe, an array in which output is line
- * buffered and the current position in that buffer are all
- * maintained for each job.
- * 6) A word of flags which determine how the module handles errors,
- * echoing, etc. for the job
- *
- * When a job is finished, the Make_Update function is called on each of the
- * parents of the node which was just remade. This takes care of the upward
- * traversal of the dependency graph.
- */
-struct pollfd;
-
-
-#ifdef USE_META
-# include "meta.h"
-#endif
-
-#define JOB_BUFSIZE 1024
-typedef struct Job {
- int pid; /* The child's process ID */
- GNode *node; /* The target the child is making */
- LstNode tailCmds; /* The node of the first command to be
- * saved when the job has been run */
- FILE *cmdFILE; /* When creating the shell script, this is
- * where the commands go */
- int exit_status; /* from wait4() in signal handler */
- char job_state; /* status of the job entry */
-#define JOB_ST_FREE 0 /* Job is available */
-#define JOB_ST_SETUP 1 /* Job is allocated but otherwise invalid */
-#define JOB_ST_RUNNING 3 /* Job is running, pid valid */
-#define JOB_ST_FINISHED 4 /* Job is done (ie after SIGCHILD) */
- char job_suspended;
- short flags; /* Flags to control treatment of job */
-#define JOB_IGNERR 0x001 /* Ignore non-zero exits */
-#define JOB_SILENT 0x002 /* no output */
-#define JOB_SPECIAL 0x004 /* Target is a special one. i.e. run it locally
- * if we can't export it and maxLocal is 0 */
-#define JOB_IGNDOTS 0x008 /* Ignore "..." lines when processing
- * commands */
-#define JOB_TRACED 0x400 /* we've sent 'set -x' */
-
- int jobPipe[2]; /* Pipe for readind output from job */
- struct pollfd *inPollfd; /* pollfd associated with inPipe */
- char outBuf[JOB_BUFSIZE + 1];
- /* Buffer for storing the output of the
- * job, line by line */
- int curPos; /* Current position in op_outBuf */
-
-#ifdef USE_META
- struct BuildMon bm;
-#endif
-} Job;
-
-#define inPipe jobPipe[0]
-#define outPipe jobPipe[1]
-
-
-/*-
- * Shell Specifications:
- * Each shell type has associated with it the following information:
- * 1) The string which must match the last character of the shell name
- * for the shell to be considered of this type. The longest match
- * wins.
- * 2) A command to issue to turn off echoing of command lines
- * 3) A command to issue to turn echoing back on again
- * 4) What the shell prints, and its length, when given the echo-off
- * command. This line will not be printed when received from the shell
- * 5) A boolean to tell if the shell has the ability to control
- * error checking for individual commands.
- * 6) The string to turn this checking on.
- * 7) The string to turn it off.
- * 8) The command-flag to give to cause the shell to start echoing
- * commands right away.
- * 9) The command-flag to cause the shell to Lib_Exit when an error is
- * detected in one of the commands.
- *
- * Some special stuff goes on if a shell doesn't have error control. In such
- * a case, errCheck becomes a printf template for echoing the command,
- * should echoing be on and ignErr becomes another printf template for
- * executing the command while ignoring the return status. Finally errOut
- * is a printf template for running the command and causing the shell to
- * exit on error. If any of these strings are empty when hasErrCtl is FALSE,
- * the command will be executed anyway as is and if it causes an error, so be
- * it. Any templates setup to echo the command will escape any '$ ` \ "'i
- * characters in the command string to avoid common problems with
- * echo "%s\n" as a template.
- */
-typedef struct Shell {
- const char *name; /* the name of the shell. For Bourne and C
- * shells, this is used only to find the
- * shell description when used as the single
- * source of a .SHELL target. For user-defined
- * shells, this is the full path of the shell.
- */
- Boolean hasEchoCtl; /* True if both echoOff and echoOn defined */
- const char *echoOff; /* command to turn off echo */
- const char *echoOn; /* command to turn it back on again */
- const char *noPrint; /* command to skip when printing output from
- * shell. This is usually the command which
- * was executed to turn off echoing */
- int noPLen; /* length of noPrint command */
- Boolean hasErrCtl; /* set if can control error checking for
- * individual commands */
- const char *errCheck; /* string to turn error checking on */
- const char *ignErr; /* string to turn off error checking */
- const char *errOut; /* string to use for testing exit code */
- const char *newline; /* string literal that results in a newline
- * character when it appears outside of any
- * 'quote' or "quote" characters */
- char commentChar; /* character used by shell for comment lines */
-
- /*
- * command-line flags
- */
- const char *echo; /* echo commands */
- const char *exit; /* exit on error */
-} Shell;
-
-extern const char *shellPath;
-extern const char *shellName;
-extern char *shellErrFlag;
-
-extern int jobTokensRunning; /* tokens currently "out" */
-extern int maxJobs; /* Max jobs we can run */
-
-void Shell_Init(void);
-const char *Shell_GetNewline(void);
-void Job_Touch(GNode *, Boolean);
-Boolean Job_CheckCommands(GNode *, void (*abortProc )(const char *, ...));
-#define CATCH_BLOCK 1
-void Job_CatchChildren(void);
-void Job_CatchOutput(void);
-void Job_Make(GNode *);
-void Job_Init(void);
-Boolean Job_Full(void);
-Boolean Job_Empty(void);
-ReturnStatus Job_ParseShell(char *);
-int Job_Finish(void);
-void Job_End(void);
-void Job_Wait(void);
-void Job_AbortAll(void);
-void JobFlagForMigration(int);
-void Job_TokenReturn(void);
-Boolean Job_TokenWithdraw(void);
-void Job_ServerStart(int, int, int);
-void Job_SetPrefix(void);
-Boolean Job_RunTarget(const char *, const char *);
-
-#endif /* _JOB_H_ */
diff --git a/usr.bin/make/lst.h b/usr.bin/make/lst.h
deleted file mode 100644
index e207bc8..0000000
--- a/usr.bin/make/lst.h
+++ /dev/null
@@ -1,189 +0,0 @@
-/* $NetBSD: lst.h,v 1.20 2014/09/07 20:55:34 joerg Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- *
- * from: @(#)lst.h 8.1 (Berkeley) 6/6/93
- */
-
-/*
- * Copyright (c) 1988, 1989 by Adam de Boor
- * Copyright (c) 1989 by Berkeley Softworks
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. 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.
- *
- * from: @(#)lst.h 8.1 (Berkeley) 6/6/93
- */
-
-/*-
- * lst.h --
- * Header for using the list library
- */
-#ifndef _LST_H_
-#define _LST_H_
-
-#include <sys/param.h>
-#include <stdlib.h>
-
-#include "sprite.h"
-
-/*
- * basic typedef. This is what the Lst_ functions handle
- */
-
-typedef struct List *Lst;
-typedef struct ListNode *LstNode;
-
-typedef void *DuplicateProc(void *);
-typedef void FreeProc(void *);
-
-#define LST_CONCNEW 0 /* create new LstNode's when using Lst_Concat */
-#define LST_CONCLINK 1 /* relink LstNode's when using Lst_Concat */
-
-/*
- * Creation/destruction functions
- */
-/* Create a new list */
-Lst Lst_Init(Boolean);
-/* Duplicate an existing list */
-Lst Lst_Duplicate(Lst, DuplicateProc *);
-/* Destroy an old one */
-void Lst_Destroy(Lst, FreeProc *);
-/* True if list is empty */
-Boolean Lst_IsEmpty(Lst);
-
-/*
- * Functions to modify a list
- */
-/* Insert an element before another */
-ReturnStatus Lst_InsertBefore(Lst, LstNode, void *);
-/* Insert an element after another */
-ReturnStatus Lst_InsertAfter(Lst, LstNode, void *);
-/* Place an element at the front of a lst. */
-ReturnStatus Lst_AtFront(Lst, void *);
-/* Place an element at the end of a lst. */
-ReturnStatus Lst_AtEnd(Lst, void *);
-/* Remove an element */
-ReturnStatus Lst_Remove(Lst, LstNode);
-/* Replace a node with a new value */
-ReturnStatus Lst_Replace(LstNode, void *);
-/* Concatenate two lists */
-ReturnStatus Lst_Concat(Lst, Lst, int);
-
-/*
- * Node-specific functions
- */
-/* Return first element in list */
-LstNode Lst_First(Lst);
-/* Return last element in list */
-LstNode Lst_Last(Lst);
-/* Return successor to given element */
-LstNode Lst_Succ(LstNode);
-/* Return predecessor to given element */
-LstNode Lst_Prev(LstNode);
-/* Get datum from LstNode */
-void *Lst_Datum(LstNode);
-
-/*
- * Functions for entire lists
- */
-/* Find an element in a list */
-LstNode Lst_Find(Lst, const void *, int (*)(const void *, const void *));
-/* Find an element starting from somewhere */
-LstNode Lst_FindFrom(Lst, LstNode, const void *,
- int (*cProc)(const void *, const void *));
-/*
- * See if the given datum is on the list. Returns the LstNode containing
- * the datum
- */
-LstNode Lst_Member(Lst, void *);
-/* Apply a function to all elements of a lst */
-int Lst_ForEach(Lst, int (*)(void *, void *), void *);
-/*
- * Apply a function to all elements of a lst starting from a certain point.
- * If the list is circular, the application will wrap around to the
- * beginning of the list again.
- */
-int Lst_ForEachFrom(Lst, LstNode, int (*)(void *, void *),
- void *);
-/*
- * these functions are for dealing with a list as a table, of sorts.
- * An idea of the "current element" is kept and used by all the functions
- * between Lst_Open() and Lst_Close().
- */
-/* Open the list */
-ReturnStatus Lst_Open(Lst);
-/* Next element please */
-LstNode Lst_Next(Lst);
-/* Done yet? */
-Boolean Lst_IsAtEnd(Lst);
-/* Finish table access */
-void Lst_Close(Lst);
-
-/*
- * for using the list as a queue
- */
-/* Place an element at tail of queue */
-ReturnStatus Lst_EnQueue(Lst, void *);
-/* Remove an element from head of queue */
-void *Lst_DeQueue(Lst);
-
-#endif /* _LST_H_ */
diff --git a/usr.bin/make/lst.lib/Makefile b/usr.bin/make/lst.lib/Makefile
deleted file mode 100644
index 5b33a50..0000000
--- a/usr.bin/make/lst.lib/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-# $NetBSD: Makefile,v 1.6 2006/11/11 21:23:36 dsl Exp $
-
-OBJ=lstAppend.o lstDupl.o lstInit.o lstOpen.o lstAtEnd.o lstEnQueue.o \
- lstInsert.o lstAtFront.o lstIsAtEnd.o lstClose.o lstFind.o lstIsEmpty.o \
- lstRemove.o lstConcat.o lstFindFrom.o lstLast.o lstReplace.o lstFirst.o \
- lstDatum.o lstForEach.o lstMember.o lstSucc.o lstDeQueue.o \
- lstForEachFrom.o lstDestroy.o lstNext.o lstPrev.o
-
-CPPFLAGS=-I${.CURDIR}/..
-all: ${OBJ}
diff --git a/usr.bin/make/lst.lib/lstAppend.c b/usr.bin/make/lst.lib/lstAppend.c
deleted file mode 100644
index 4dafe83..0000000
--- a/usr.bin/make/lst.lib/lstAppend.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/* $NetBSD: lstAppend.c,v 1.14 2009/01/23 21:26:30 dsl Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstAppend.c,v 1.14 2009/01/23 21:26:30 dsl Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)lstAppend.c 8.1 (Berkeley) 6/6/93";
-#else
-__RCSID("$NetBSD: lstAppend.c,v 1.14 2009/01/23 21:26:30 dsl Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * LstAppend.c --
- * Add a new node with a new datum after an existing node
- */
-
-#include "lstInt.h"
-
-/*-
- *-----------------------------------------------------------------------
- * Lst_InsertAfter --
- * Create a new node and add it to the given list after the given node.
- *
- * Input:
- * l affected list
- * ln node after which to append the datum
- * d said datum
- *
- * Results:
- * SUCCESS if all went well.
- *
- * Side Effects:
- * A new ListNode is created and linked in to the List. The lastPtr
- * field of the List will be altered if ln is the last node in the
- * list. lastPtr and firstPtr will alter if the list was empty and
- * ln was NULL.
- *
- *-----------------------------------------------------------------------
- */
-ReturnStatus
-Lst_InsertAfter(Lst l, LstNode ln, void *d)
-{
- List list;
- ListNode lNode;
- ListNode nLNode;
-
- if (LstValid (l) && (ln == NULL && LstIsEmpty (l))) {
- goto ok;
- }
-
- if (!LstValid (l) || LstIsEmpty (l) || ! LstNodeValid (ln, l)) {
- return (FAILURE);
- }
- ok:
-
- list = l;
- lNode = ln;
-
- PAlloc (nLNode, ListNode);
- nLNode->datum = d;
- nLNode->useCount = nLNode->flags = 0;
-
- if (lNode == NULL) {
- if (list->isCirc) {
- nLNode->nextPtr = nLNode->prevPtr = nLNode;
- } else {
- nLNode->nextPtr = nLNode->prevPtr = NULL;
- }
- list->firstPtr = list->lastPtr = nLNode;
- } else {
- nLNode->prevPtr = lNode;
- nLNode->nextPtr = lNode->nextPtr;
-
- lNode->nextPtr = nLNode;
- if (nLNode->nextPtr != NULL) {
- nLNode->nextPtr->prevPtr = nLNode;
- }
-
- if (lNode == list->lastPtr) {
- list->lastPtr = nLNode;
- }
- }
-
- return (SUCCESS);
-}
-
diff --git a/usr.bin/make/lst.lib/lstAtEnd.c b/usr.bin/make/lst.lib/lstAtEnd.c
deleted file mode 100644
index 10f191a..0000000
--- a/usr.bin/make/lst.lib/lstAtEnd.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/* $NetBSD: lstAtEnd.c,v 1.13 2009/01/23 21:26:30 dsl Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstAtEnd.c,v 1.13 2009/01/23 21:26:30 dsl Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)lstAtEnd.c 8.1 (Berkeley) 6/6/93";
-#else
-__RCSID("$NetBSD: lstAtEnd.c,v 1.13 2009/01/23 21:26:30 dsl Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * LstAtEnd.c --
- * Add a node at the end of the list
- */
-
-#include "lstInt.h"
-
-/*-
- *-----------------------------------------------------------------------
- * Lst_AtEnd --
- * Add a node to the end of the given list
- *
- * Input:
- * l List to which to add the datum
- * d Datum to add
- *
- * Results:
- * SUCCESS if life is good.
- *
- * Side Effects:
- * A new ListNode is created and added to the list.
- *
- *-----------------------------------------------------------------------
- */
-ReturnStatus
-Lst_AtEnd(Lst l, void *d)
-{
- LstNode end;
-
- end = Lst_Last(l);
- return (Lst_InsertAfter(l, end, d));
-}
diff --git a/usr.bin/make/lst.lib/lstAtFront.c b/usr.bin/make/lst.lib/lstAtFront.c
deleted file mode 100644
index d8be166..0000000
--- a/usr.bin/make/lst.lib/lstAtFront.c
+++ /dev/null
@@ -1,76 +0,0 @@
-/* $NetBSD: lstAtFront.c,v 1.13 2009/01/23 21:26:30 dsl Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstAtFront.c,v 1.13 2009/01/23 21:26:30 dsl Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)lstAtFront.c 8.1 (Berkeley) 6/6/93";
-#else
-__RCSID("$NetBSD: lstAtFront.c,v 1.13 2009/01/23 21:26:30 dsl Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * LstAtFront.c --
- * Add a node at the front of the list
- */
-
-#include "lstInt.h"
-
-/*-
- *-----------------------------------------------------------------------
- * Lst_AtFront --
- * Place a piece of data at the front of a list
- *
- * Results:
- * SUCCESS or FAILURE
- *
- * Side Effects:
- * A new ListNode is created and stuck at the front of the list.
- * hence, firstPtr (and possible lastPtr) in the list are altered.
- *
- *-----------------------------------------------------------------------
- */
-ReturnStatus
-Lst_AtFront(Lst l, void *d)
-{
- LstNode front;
-
- front = Lst_First(l);
- return (Lst_InsertBefore(l, front, d));
-}
diff --git a/usr.bin/make/lst.lib/lstClose.c b/usr.bin/make/lst.lib/lstClose.c
deleted file mode 100644
index 06b68c5..0000000
--- a/usr.bin/make/lst.lib/lstClose.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/* $NetBSD: lstClose.c,v 1.11 2006/10/27 21:37:25 dsl Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstClose.c,v 1.11 2006/10/27 21:37:25 dsl Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)lstClose.c 8.1 (Berkeley) 6/6/93";
-#else
-__RCSID("$NetBSD: lstClose.c,v 1.11 2006/10/27 21:37:25 dsl Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * LstClose.c --
- * Close a list for sequential access.
- * The sequential functions access the list in a slightly different way.
- * CurPtr points to their idea of the current node in the list and they
- * access the list based on it. Because the list is circular, Lst_Next
- * and Lst_Prev will go around the list forever. Lst_IsAtEnd must be
- * used to determine when to stop.
- */
-
-#include "lstInt.h"
-
-/*-
- *-----------------------------------------------------------------------
- * Lst_Close --
- * Close a list which was opened for sequential access.
- *
- * Input:
- * l The list to close
- *
- * Results:
- * None.
- *
- * Side Effects:
- * The list is closed.
- *
- *-----------------------------------------------------------------------
- */
-void
-Lst_Close(Lst l)
-{
- List list = l;
-
- if (LstValid(l) == TRUE) {
- list->isOpen = FALSE;
- list->atEnd = Unknown;
- }
-}
-
diff --git a/usr.bin/make/lst.lib/lstConcat.c b/usr.bin/make/lst.lib/lstConcat.c
deleted file mode 100644
index 534d34e..0000000
--- a/usr.bin/make/lst.lib/lstConcat.c
+++ /dev/null
@@ -1,185 +0,0 @@
-/* $NetBSD: lstConcat.c,v 1.16 2008/12/13 15:19:29 dsl Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstConcat.c,v 1.16 2008/12/13 15:19:29 dsl Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)lstConcat.c 8.1 (Berkeley) 6/6/93";
-#else
-__RCSID("$NetBSD: lstConcat.c,v 1.16 2008/12/13 15:19:29 dsl Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * listConcat.c --
- * Function to concatentate two lists.
- */
-
-#include "lstInt.h"
-
-/*-
- *-----------------------------------------------------------------------
- * Lst_Concat --
- * Concatenate two lists. New elements are created to hold the data
- * elements, if specified, but the elements themselves are not copied.
- * If the elements should be duplicated to avoid confusion with another
- * list, the Lst_Duplicate function should be called first.
- * If LST_CONCLINK is specified, the second list is destroyed since
- * its pointers have been corrupted and the list is no longer useable.
- *
- * Input:
- * l1 The list to which l2 is to be appended
- * l2 The list to append to l1
- * flags LST_CONCNEW if LstNode's should be duplicated
- * LST_CONCLINK if should just be relinked
- *
- * Results:
- * SUCCESS if all went well. FAILURE otherwise.
- *
- * Side Effects:
- * New elements are created and appended the first list.
- *-----------------------------------------------------------------------
- */
-ReturnStatus
-Lst_Concat(Lst l1, Lst l2, int flags)
-{
- ListNode ln; /* original LstNode */
- ListNode nln; /* new LstNode */
- ListNode last; /* the last element in the list. Keeps
- * bookkeeping until the end */
- List list1 = l1;
- List list2 = l2;
-
- if (!LstValid (l1) || !LstValid (l2)) {
- return (FAILURE);
- }
-
- if (flags == LST_CONCLINK) {
- if (list2->firstPtr != NULL) {
- /*
- * We set the nextPtr of the
- * last element of list two to be NIL to make the loop easier and
- * so we don't need an extra case should the first list turn
- * out to be non-circular -- the final element will already point
- * to NIL space and the first element will be untouched if it
- * existed before and will also point to NIL space if it didn't.
- */
- list2->lastPtr->nextPtr = NULL;
- /*
- * So long as the second list isn't empty, we just link the
- * first element of the second list to the last element of the
- * first list. If the first list isn't empty, we then link the
- * last element of the list to the first element of the second list
- * The last element of the second list, if it exists, then becomes
- * the last element of the first list.
- */
- list2->firstPtr->prevPtr = list1->lastPtr;
- if (list1->lastPtr != NULL) {
- list1->lastPtr->nextPtr = list2->firstPtr;
- } else {
- list1->firstPtr = list2->firstPtr;
- }
- list1->lastPtr = list2->lastPtr;
- }
- if (list1->isCirc && list1->firstPtr != NULL) {
- /*
- * If the first list is supposed to be circular and it is (now)
- * non-empty, we must make sure it's circular by linking the
- * first element to the last and vice versa
- */
- list1->firstPtr->prevPtr = list1->lastPtr;
- list1->lastPtr->nextPtr = list1->firstPtr;
- }
- free(l2);
- } else if (list2->firstPtr != NULL) {
- /*
- * We set the nextPtr of the last element of list 2 to be nil to make
- * the loop less difficult. The loop simply goes through the entire
- * second list creating new LstNodes and filling in the nextPtr, and
- * prevPtr to fit into l1 and its datum field from the
- * datum field of the corresponding element in l2. The 'last' node
- * follows the last of the new nodes along until the entire l2 has
- * been appended. Only then does the bookkeeping catch up with the
- * changes. During the first iteration of the loop, if 'last' is nil,
- * the first list must have been empty so the newly-created node is
- * made the first node of the list.
- */
- list2->lastPtr->nextPtr = NULL;
- for (last = list1->lastPtr, ln = list2->firstPtr;
- ln != NULL;
- ln = ln->nextPtr)
- {
- PAlloc (nln, ListNode);
- nln->datum = ln->datum;
- if (last != NULL) {
- last->nextPtr = nln;
- } else {
- list1->firstPtr = nln;
- }
- nln->prevPtr = last;
- nln->flags = nln->useCount = 0;
- last = nln;
- }
-
- /*
- * Finish bookkeeping. The last new element becomes the last element
- * of list one.
- */
- list1->lastPtr = last;
-
- /*
- * The circularity of both list one and list two must be corrected
- * for -- list one because of the new nodes added to it; list two
- * because of the alteration of list2->lastPtr's nextPtr to ease the
- * above for loop.
- */
- if (list1->isCirc) {
- list1->lastPtr->nextPtr = list1->firstPtr;
- list1->firstPtr->prevPtr = list1->lastPtr;
- } else {
- last->nextPtr = NULL;
- }
-
- if (list2->isCirc) {
- list2->lastPtr->nextPtr = list2->firstPtr;
- }
- }
-
- return (SUCCESS);
-}
-
diff --git a/usr.bin/make/lst.lib/lstDatum.c b/usr.bin/make/lst.lib/lstDatum.c
deleted file mode 100644
index 6e2d9ad..0000000
--- a/usr.bin/make/lst.lib/lstDatum.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/* $NetBSD: lstDatum.c,v 1.13 2009/01/23 21:26:30 dsl Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstDatum.c,v 1.13 2009/01/23 21:26:30 dsl Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)lstDatum.c 8.1 (Berkeley) 6/6/93";
-#else
-__RCSID("$NetBSD: lstDatum.c,v 1.13 2009/01/23 21:26:30 dsl Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * LstDatum.c --
- * Return the datum associated with a list node.
- */
-
-#include "lstInt.h"
-
-/*-
- *-----------------------------------------------------------------------
- * Lst_Datum --
- * Return the datum stored in the given node.
- *
- * Results:
- * The datum or NULL if the node is invalid.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-void *
-Lst_Datum(LstNode ln)
-{
- if (ln != NULL) {
- return ((ln)->datum);
- } else {
- return NULL;
- }
-}
-
diff --git a/usr.bin/make/lst.lib/lstDeQueue.c b/usr.bin/make/lst.lib/lstDeQueue.c
deleted file mode 100644
index bdb05cc..0000000
--- a/usr.bin/make/lst.lib/lstDeQueue.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/* $NetBSD: lstDeQueue.c,v 1.14 2009/01/23 21:26:30 dsl Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstDeQueue.c,v 1.14 2009/01/23 21:26:30 dsl Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)lstDeQueue.c 8.1 (Berkeley) 6/6/93";
-#else
-__RCSID("$NetBSD: lstDeQueue.c,v 1.14 2009/01/23 21:26:30 dsl Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * LstDeQueue.c --
- * Remove the node and return its datum from the head of the list
- */
-
-#include "lstInt.h"
-
-/*-
- *-----------------------------------------------------------------------
- * Lst_DeQueue --
- * Remove and return the datum at the head of the given list.
- *
- * Results:
- * The datum in the node at the head or NULL if the list
- * is empty.
- *
- * Side Effects:
- * The head node is removed from the list.
- *
- *-----------------------------------------------------------------------
- */
-void *
-Lst_DeQueue(Lst l)
-{
- void *rd;
- ListNode tln;
-
- tln = Lst_First(l);
- if (tln == NULL) {
- return NULL;
- }
-
- rd = tln->datum;
- if (Lst_Remove(l, tln) == FAILURE) {
- return NULL;
- } else {
- return (rd);
- }
-}
-
diff --git a/usr.bin/make/lst.lib/lstDestroy.c b/usr.bin/make/lst.lib/lstDestroy.c
deleted file mode 100644
index 92c5b2b..0000000
--- a/usr.bin/make/lst.lib/lstDestroy.c
+++ /dev/null
@@ -1,101 +0,0 @@
-/* $NetBSD: lstDestroy.c,v 1.16 2008/12/13 15:19:29 dsl Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstDestroy.c,v 1.16 2008/12/13 15:19:29 dsl Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)lstDestroy.c 8.1 (Berkeley) 6/6/93";
-#else
-__RCSID("$NetBSD: lstDestroy.c,v 1.16 2008/12/13 15:19:29 dsl Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * LstDestroy.c --
- * Nuke a list and all its resources
- */
-
-#include "lstInt.h"
-
-/*-
- *-----------------------------------------------------------------------
- * Lst_Destroy --
- * Destroy a list and free all its resources. If the freeProc is
- * given, it is called with the datum from each node in turn before
- * the node is freed.
- *
- * Results:
- * None.
- *
- * Side Effects:
- * The given list is freed in its entirety.
- *
- *-----------------------------------------------------------------------
- */
-void
-Lst_Destroy(Lst list, FreeProc *freeProc)
-{
- ListNode ln;
- ListNode tln = NULL;
-
- if (list == NULL)
- return;
-
- /* To ease scanning */
- if (list->lastPtr != NULL)
- list->lastPtr->nextPtr = NULL;
- else {
- free(list);
- return;
- }
-
- if (freeProc) {
- for (ln = list->firstPtr; ln != NULL; ln = tln) {
- tln = ln->nextPtr;
- freeProc(ln->datum);
- free(ln);
- }
- } else {
- for (ln = list->firstPtr; ln != NULL; ln = tln) {
- tln = ln->nextPtr;
- free(ln);
- }
- }
-
- free(list);
-}
diff --git a/usr.bin/make/lst.lib/lstDupl.c b/usr.bin/make/lst.lib/lstDupl.c
deleted file mode 100644
index 2174ff7..0000000
--- a/usr.bin/make/lst.lib/lstDupl.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/* $NetBSD: lstDupl.c,v 1.16 2009/01/23 21:26:30 dsl Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstDupl.c,v 1.16 2009/01/23 21:26:30 dsl Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)lstDupl.c 8.1 (Berkeley) 6/6/93";
-#else
-__RCSID("$NetBSD: lstDupl.c,v 1.16 2009/01/23 21:26:30 dsl Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * listDupl.c --
- * Duplicate a list. This includes duplicating the individual
- * elements.
- */
-
-#include "lstInt.h"
-
-/*-
- *-----------------------------------------------------------------------
- * Lst_Duplicate --
- * Duplicate an entire list. If a function to copy a void *is
- * given, the individual client elements will be duplicated as well.
- *
- * Input:
- * l the list to duplicate
- * copyProc A function to duplicate each void *
- *
- * Results:
- * The new Lst structure or NULL if failure.
- *
- * Side Effects:
- * A new list is created.
- *-----------------------------------------------------------------------
- */
-Lst
-Lst_Duplicate(Lst l, DuplicateProc *copyProc)
-{
- Lst nl;
- ListNode ln;
- List list = l;
-
- if (!LstValid (l)) {
- return NULL;
- }
-
- nl = Lst_Init(list->isCirc);
- if (nl == NULL) {
- return NULL;
- }
-
- ln = list->firstPtr;
- while (ln != NULL) {
- if (copyProc != NULL) {
- if (Lst_AtEnd(nl, copyProc(ln->datum)) == FAILURE) {
- return NULL;
- }
- } else if (Lst_AtEnd(nl, ln->datum) == FAILURE) {
- return NULL;
- }
-
- if (list->isCirc && ln == list->lastPtr) {
- ln = NULL;
- } else {
- ln = ln->nextPtr;
- }
- }
-
- return (nl);
-}
diff --git a/usr.bin/make/lst.lib/lstEnQueue.c b/usr.bin/make/lst.lib/lstEnQueue.c
deleted file mode 100644
index be386c9..0000000
--- a/usr.bin/make/lst.lib/lstEnQueue.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/* $NetBSD: lstEnQueue.c,v 1.13 2009/01/23 21:26:30 dsl Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstEnQueue.c,v 1.13 2009/01/23 21:26:30 dsl Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)lstEnQueue.c 8.1 (Berkeley) 6/6/93";
-#else
-__RCSID("$NetBSD: lstEnQueue.c,v 1.13 2009/01/23 21:26:30 dsl Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * LstEnQueue.c--
- * Treat the list as a queue and place a datum at its end
- */
-
-#include "lstInt.h"
-
-/*-
- *-----------------------------------------------------------------------
- * Lst_EnQueue --
- * Add the datum to the tail of the given list.
- *
- * Results:
- * SUCCESS or FAILURE as returned by Lst_InsertAfter.
- *
- * Side Effects:
- * the lastPtr field is altered all the time and the firstPtr field
- * will be altered if the list used to be empty.
- *
- *-----------------------------------------------------------------------
- */
-ReturnStatus
-Lst_EnQueue(Lst l, void *d)
-{
- if (LstValid (l) == FALSE) {
- return (FAILURE);
- }
-
- return (Lst_InsertAfter(l, Lst_Last(l), d));
-}
-
diff --git a/usr.bin/make/lst.lib/lstFind.c b/usr.bin/make/lst.lib/lstFind.c
deleted file mode 100644
index d07dbe7..0000000
--- a/usr.bin/make/lst.lib/lstFind.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/* $NetBSD: lstFind.c,v 1.15 2009/01/23 21:58:28 dsl Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstFind.c,v 1.15 2009/01/23 21:58:28 dsl Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)lstFind.c 8.1 (Berkeley) 6/6/93";
-#else
-__RCSID("$NetBSD: lstFind.c,v 1.15 2009/01/23 21:58:28 dsl Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * LstFind.c --
- * Find a node on a list.
- */
-
-#include "lstInt.h"
-
-/*-
- *-----------------------------------------------------------------------
- * Lst_Find --
- * Find a node on the given list using the given comparison function
- * and the given datum.
- *
- * Results:
- * The found node or NULL if none matches.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-LstNode
-Lst_Find(Lst l, const void *d, int (*cProc)(const void *, const void *))
-{
- return (Lst_FindFrom(l, Lst_First(l), d, cProc));
-}
-
diff --git a/usr.bin/make/lst.lib/lstFindFrom.c b/usr.bin/make/lst.lib/lstFindFrom.c
deleted file mode 100644
index e2beab6..0000000
--- a/usr.bin/make/lst.lib/lstFindFrom.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/* $NetBSD: lstFindFrom.c,v 1.15 2009/01/23 21:58:28 dsl Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstFindFrom.c,v 1.15 2009/01/23 21:58:28 dsl Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)lstFindFrom.c 8.1 (Berkeley) 6/6/93";
-#else
-__RCSID("$NetBSD: lstFindFrom.c,v 1.15 2009/01/23 21:58:28 dsl Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * LstFindFrom.c --
- * Find a node on a list from a given starting point. Used by Lst_Find.
- */
-
-#include "lstInt.h"
-
-/*-
- *-----------------------------------------------------------------------
- * Lst_FindFrom --
- * Search for a node starting and ending with the given one on the
- * given list using the passed datum and comparison function to
- * determine when it has been found.
- *
- * Results:
- * The found node or NULL
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-LstNode
-Lst_FindFrom(Lst l, LstNode ln, const void *d,
- int (*cProc)(const void *, const void *))
-{
- ListNode tln;
-
- if (!LstValid (l) || LstIsEmpty (l) || !LstNodeValid (ln, l)) {
- return NULL;
- }
-
- tln = ln;
-
- do {
- if ((*cProc)(tln->datum, d) == 0)
- return (tln);
- tln = tln->nextPtr;
- } while (tln != ln && tln != NULL);
-
- return NULL;
-}
-
diff --git a/usr.bin/make/lst.lib/lstFirst.c b/usr.bin/make/lst.lib/lstFirst.c
deleted file mode 100644
index 4e8334f..0000000
--- a/usr.bin/make/lst.lib/lstFirst.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/* $NetBSD: lstFirst.c,v 1.12 2008/12/13 15:19:29 dsl Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstFirst.c,v 1.12 2008/12/13 15:19:29 dsl Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)lstFirst.c 8.1 (Berkeley) 6/6/93";
-#else
-__RCSID("$NetBSD: lstFirst.c,v 1.12 2008/12/13 15:19:29 dsl Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * LstFirst.c --
- * Return the first node of a list
- */
-
-#include "lstInt.h"
-
-/*-
- *-----------------------------------------------------------------------
- * Lst_First --
- * Return the first node on the given list.
- *
- * Results:
- * The first node or NULL if the list is empty.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-LstNode
-Lst_First(Lst l)
-{
- if (!LstValid (l) || LstIsEmpty (l)) {
- return NULL;
- } else {
- return (l->firstPtr);
- }
-}
-
diff --git a/usr.bin/make/lst.lib/lstForEach.c b/usr.bin/make/lst.lib/lstForEach.c
deleted file mode 100644
index 917e4ea..0000000
--- a/usr.bin/make/lst.lib/lstForEach.c
+++ /dev/null
@@ -1,76 +0,0 @@
-/* $NetBSD: lstForEach.c,v 1.13 2009/01/23 21:26:30 dsl Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstForEach.c,v 1.13 2009/01/23 21:26:30 dsl Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)lstForEach.c 8.1 (Berkeley) 6/6/93";
-#else
-__RCSID("$NetBSD: lstForEach.c,v 1.13 2009/01/23 21:26:30 dsl Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * LstForeach.c --
- * Perform a given function on all elements of a list.
- */
-
-#include "lstInt.h"
-
-/*-
- *-----------------------------------------------------------------------
- * Lst_ForEach --
- * Apply the given function to each element of the given list. The
- * function should return 0 if Lst_ForEach should continue and non-
- * zero if it should abort.
- *
- * Results:
- * None.
- *
- * Side Effects:
- * Only those created by the passed-in function.
- *
- *-----------------------------------------------------------------------
- */
-/*VARARGS2*/
-int
-Lst_ForEach(Lst l, int (*proc)(void *, void *), void *d)
-{
- return Lst_ForEachFrom(l, Lst_First(l), proc, d);
-}
-
diff --git a/usr.bin/make/lst.lib/lstForEachFrom.c b/usr.bin/make/lst.lib/lstForEachFrom.c
deleted file mode 100644
index c7f44ad..0000000
--- a/usr.bin/make/lst.lib/lstForEachFrom.c
+++ /dev/null
@@ -1,125 +0,0 @@
-/* $NetBSD: lstForEachFrom.c,v 1.17 2009/01/23 21:26:30 dsl Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstForEachFrom.c,v 1.17 2009/01/23 21:26:30 dsl Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)lstForEachFrom.c 8.1 (Berkeley) 6/6/93";
-#else
-__RCSID("$NetBSD: lstForEachFrom.c,v 1.17 2009/01/23 21:26:30 dsl Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * lstForEachFrom.c --
- * Perform a given function on all elements of a list starting from
- * a given point.
- */
-
-#include "lstInt.h"
-
-/*-
- *-----------------------------------------------------------------------
- * Lst_ForEachFrom --
- * Apply the given function to each element of the given list. The
- * function should return 0 if traversal should continue and non-
- * zero if it should abort.
- *
- * Results:
- * None.
- *
- * Side Effects:
- * Only those created by the passed-in function.
- *
- *-----------------------------------------------------------------------
- */
-/*VARARGS2*/
-int
-Lst_ForEachFrom(Lst l, LstNode ln, int (*proc)(void *, void *),
- void *d)
-{
- ListNode tln = ln;
- List list = l;
- ListNode next;
- Boolean done;
- int result;
-
- if (!LstValid (list) || LstIsEmpty (list)) {
- return 0;
- }
-
- do {
- /*
- * Take care of having the current element deleted out from under
- * us.
- */
-
- next = tln->nextPtr;
-
- /*
- * We're done with the traversal if
- * - the next node to examine is the first in the queue or
- * doesn't exist and
- * - nothing's been added after the current node (check this
- * after proc() has been called).
- */
- done = (next == NULL || next == list->firstPtr);
-
- (void) tln->useCount++;
- result = (*proc) (tln->datum, d);
- (void) tln->useCount--;
-
- /*
- * Now check whether a node has been added.
- * Note: this doesn't work if this node was deleted before
- * the new node was added.
- */
- if (next != tln->nextPtr) {
- next = tln->nextPtr;
- done = 0;
- }
-
- if (tln->flags & LN_DELETED) {
- free((char *)tln);
- }
- tln = next;
- } while (!result && !LstIsEmpty(list) && !done);
-
- return result;
-}
-
diff --git a/usr.bin/make/lst.lib/lstInit.c b/usr.bin/make/lst.lib/lstInit.c
deleted file mode 100644
index f98ac42..0000000
--- a/usr.bin/make/lst.lib/lstInit.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/* $NetBSD: lstInit.c,v 1.12 2008/12/13 15:19:29 dsl Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstInit.c,v 1.12 2008/12/13 15:19:29 dsl Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)lstInit.c 8.1 (Berkeley) 6/6/93";
-#else
-__RCSID("$NetBSD: lstInit.c,v 1.12 2008/12/13 15:19:29 dsl Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * init.c --
- * Initialize a new linked list.
- */
-
-#include "lstInt.h"
-
-/*-
- *-----------------------------------------------------------------------
- * Lst_Init --
- * Create and initialize a new list.
- *
- * Input:
- * circ TRUE if the list should be made circular
- *
- * Results:
- * The created list.
- *
- * Side Effects:
- * A list is created, what else?
- *
- *-----------------------------------------------------------------------
- */
-Lst
-Lst_Init(Boolean circ)
-{
- List nList;
-
- PAlloc (nList, List);
-
- nList->firstPtr = NULL;
- nList->lastPtr = NULL;
- nList->isOpen = FALSE;
- nList->isCirc = circ;
- nList->atEnd = Unknown;
-
- return (nList);
-}
diff --git a/usr.bin/make/lst.lib/lstInsert.c b/usr.bin/make/lst.lib/lstInsert.c
deleted file mode 100644
index 77187bb..0000000
--- a/usr.bin/make/lst.lib/lstInsert.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/* $NetBSD: lstInsert.c,v 1.14 2009/01/23 21:26:30 dsl Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstInsert.c,v 1.14 2009/01/23 21:26:30 dsl Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)lstInsert.c 8.1 (Berkeley) 6/6/93";
-#else
-__RCSID("$NetBSD: lstInsert.c,v 1.14 2009/01/23 21:26:30 dsl Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * LstInsert.c --
- * Insert a new datum before an old one
- */
-
-#include "lstInt.h"
-
-/*-
- *-----------------------------------------------------------------------
- * Lst_InsertBefore --
- * Insert a new node with the given piece of data before the given
- * node in the given list.
- *
- * Input:
- * l list to manipulate
- * ln node before which to insert d
- * d datum to be inserted
- *
- * Results:
- * SUCCESS or FAILURE.
- *
- * Side Effects:
- * the firstPtr field will be changed if ln is the first node in the
- * list.
- *
- *-----------------------------------------------------------------------
- */
-ReturnStatus
-Lst_InsertBefore(Lst l, LstNode ln, void *d)
-{
- ListNode nLNode; /* new lnode for d */
- ListNode lNode = ln;
- List list = l;
-
-
- /*
- * check validity of arguments
- */
- if (LstValid (l) && (LstIsEmpty (l) && ln == NULL))
- goto ok;
-
- if (!LstValid (l) || LstIsEmpty (l) || !LstNodeValid (ln, l)) {
- return (FAILURE);
- }
-
- ok:
- PAlloc (nLNode, ListNode);
-
- nLNode->datum = d;
- nLNode->useCount = nLNode->flags = 0;
-
- if (ln == NULL) {
- if (list->isCirc) {
- nLNode->prevPtr = nLNode->nextPtr = nLNode;
- } else {
- nLNode->prevPtr = nLNode->nextPtr = NULL;
- }
- list->firstPtr = list->lastPtr = nLNode;
- } else {
- nLNode->prevPtr = lNode->prevPtr;
- nLNode->nextPtr = lNode;
-
- if (nLNode->prevPtr != NULL) {
- nLNode->prevPtr->nextPtr = nLNode;
- }
- lNode->prevPtr = nLNode;
-
- if (lNode == list->firstPtr) {
- list->firstPtr = nLNode;
- }
- }
-
- return (SUCCESS);
-}
-
diff --git a/usr.bin/make/lst.lib/lstInt.h b/usr.bin/make/lst.lib/lstInt.h
deleted file mode 100644
index ac53dcb..0000000
--- a/usr.bin/make/lst.lib/lstInt.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/* $NetBSD: lstInt.h,v 1.22 2014/09/07 20:55:34 joerg Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- *
- * from: @(#)lstInt.h 8.1 (Berkeley) 6/6/93
- */
-
-/*-
- * lstInt.h --
- * Internals for the list library
- */
-#ifndef _LSTINT_H_
-#define _LSTINT_H_
-
-#include "../lst.h"
-#include "../make_malloc.h"
-
-typedef struct ListNode {
- struct ListNode *prevPtr; /* previous element in list */
- struct ListNode *nextPtr; /* next in list */
- unsigned int useCount:8, /* Count of functions using the node.
- * node may not be deleted until count
- * goes to 0 */
- flags:8; /* Node status flags */
- void *datum; /* datum associated with this element */
-} *ListNode;
-/*
- * Flags required for synchronization
- */
-#define LN_DELETED 0x0001 /* List node should be removed when done */
-
-typedef enum {
- Head, Middle, Tail, Unknown
-} Where;
-
-typedef struct List {
- ListNode firstPtr; /* first node in list */
- ListNode lastPtr; /* last node in list */
- Boolean isCirc; /* true if the list should be considered
- * circular */
-/*
- * fields for sequential access
- */
- Where atEnd; /* Where in the list the last access was */
- Boolean isOpen; /* true if list has been Lst_Open'ed */
- ListNode curPtr; /* current node, if open. NULL if
- * *just* opened */
- ListNode prevPtr; /* Previous node, if open. Used by
- * Lst_Remove */
-} *List;
-
-/*
- * PAlloc (var, ptype) --
- * Allocate a pointer-typedef structure 'ptype' into the variable 'var'
- */
-#define PAlloc(var,ptype) var = (ptype) bmake_malloc(sizeof *(var))
-
-/*
- * LstValid (l) --
- * Return TRUE if the list l is valid
- */
-#define LstValid(l) ((Lst)(l) != NULL)
-
-/*
- * LstNodeValid (ln, l) --
- * Return TRUE if the LstNode ln is valid with respect to l
- */
-#define LstNodeValid(ln, l) ((ln) != NULL)
-
-/*
- * LstIsEmpty (l) --
- * TRUE if the list l is empty.
- */
-#define LstIsEmpty(l) (((List)(l))->firstPtr == NULL)
-
-#endif /* _LSTINT_H_ */
diff --git a/usr.bin/make/lst.lib/lstIsAtEnd.c b/usr.bin/make/lst.lib/lstIsAtEnd.c
deleted file mode 100644
index 70270d2..0000000
--- a/usr.bin/make/lst.lib/lstIsAtEnd.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/* $NetBSD: lstIsAtEnd.c,v 1.13 2008/02/15 21:29:50 christos Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstIsAtEnd.c,v 1.13 2008/02/15 21:29:50 christos Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)lstIsAtEnd.c 8.1 (Berkeley) 6/6/93";
-#else
-__RCSID("$NetBSD: lstIsAtEnd.c,v 1.13 2008/02/15 21:29:50 christos Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * LstIsAtEnd.c --
- * Tell if the current node is at the end of the list.
- * The sequential functions access the list in a slightly different way.
- * CurPtr points to their idea of the current node in the list and they
- * access the list based on it. Because the list is circular, Lst_Next
- * and Lst_Prev will go around the list forever. Lst_IsAtEnd must be
- * used to determine when to stop.
- */
-
-#include "lstInt.h"
-
-/*-
- *-----------------------------------------------------------------------
- * Lst_IsAtEnd --
- * Return true if have reached the end of the given list.
- *
- * Results:
- * TRUE if at the end of the list (this includes the list not being
- * open or being invalid) or FALSE if not. We return TRUE if the list
- * is invalid or unopend so as to cause the caller to exit its loop
- * asap, the assumption being that the loop is of the form
- * while (!Lst_IsAtEnd (l)) {
- * ...
- * }
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-Boolean
-Lst_IsAtEnd(Lst l)
-{
- List list = l;
-
- return (!LstValid (l) || !list->isOpen ||
- (list->atEnd == Head) || (list->atEnd == Tail));
-}
-
diff --git a/usr.bin/make/lst.lib/lstIsEmpty.c b/usr.bin/make/lst.lib/lstIsEmpty.c
deleted file mode 100644
index 8b1d6ed..0000000
--- a/usr.bin/make/lst.lib/lstIsEmpty.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/* $NetBSD: lstIsEmpty.c,v 1.11 2008/12/13 15:19:29 dsl Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstIsEmpty.c,v 1.11 2008/12/13 15:19:29 dsl Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)lstIsEmpty.c 8.1 (Berkeley) 6/6/93";
-#else
-__RCSID("$NetBSD: lstIsEmpty.c,v 1.11 2008/12/13 15:19:29 dsl Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * LstIsEmpty.c --
- * A single function to decide if a list is empty
- */
-
-#include "lstInt.h"
-
-/*-
- *-----------------------------------------------------------------------
- * Lst_IsEmpty --
- * Return TRUE if the given list is empty.
- *
- * Results:
- * TRUE if the list is empty, FALSE otherwise.
- *
- * Side Effects:
- * None.
- *
- * A list is considered empty if its firstPtr == NULL (or if
- * the list itself is NULL).
- *-----------------------------------------------------------------------
- */
-Boolean
-Lst_IsEmpty(Lst l)
-{
- return ( ! LstValid (l) || LstIsEmpty(l));
-}
-
diff --git a/usr.bin/make/lst.lib/lstLast.c b/usr.bin/make/lst.lib/lstLast.c
deleted file mode 100644
index 096ca24..0000000
--- a/usr.bin/make/lst.lib/lstLast.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/* $NetBSD: lstLast.c,v 1.12 2008/12/13 15:19:29 dsl Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstLast.c,v 1.12 2008/12/13 15:19:29 dsl Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)lstLast.c 8.1 (Berkeley) 6/6/93";
-#else
-__RCSID("$NetBSD: lstLast.c,v 1.12 2008/12/13 15:19:29 dsl Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * LstLast.c --
- * Return the last element of a list
- */
-
-#include "lstInt.h"
-
-/*-
- *-----------------------------------------------------------------------
- * Lst_Last --
- * Return the last node on the list l.
- *
- * Results:
- * The requested node or NULL if the list is empty.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-LstNode
-Lst_Last(Lst l)
-{
- if (!LstValid(l) || LstIsEmpty (l)) {
- return NULL;
- } else {
- return (l->lastPtr);
- }
-}
-
diff --git a/usr.bin/make/lst.lib/lstMember.c b/usr.bin/make/lst.lib/lstMember.c
deleted file mode 100644
index e9046ac..0000000
--- a/usr.bin/make/lst.lib/lstMember.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/* $NetBSD: lstMember.c,v 1.14 2013/11/14 00:01:28 sjg Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstMember.c,v 1.14 2013/11/14 00:01:28 sjg Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)lstMember.c 8.1 (Berkeley) 6/6/93";
-#else
-__RCSID("$NetBSD: lstMember.c,v 1.14 2013/11/14 00:01:28 sjg Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * lstMember.c --
- * See if a given datum is on a given list.
- */
-
-#include "lstInt.h"
-
-LstNode
-Lst_Member(Lst l, void *d)
-{
- List list = l;
- ListNode lNode;
-
- if (list == NULL) {
- return NULL;
- }
- lNode = list->firstPtr;
- if (lNode == NULL) {
- return NULL;
- }
-
- do {
- if (lNode->datum == d) {
- return lNode;
- }
- lNode = lNode->nextPtr;
- } while (lNode != NULL && lNode != list->firstPtr);
-
- return NULL;
-}
diff --git a/usr.bin/make/lst.lib/lstNext.c b/usr.bin/make/lst.lib/lstNext.c
deleted file mode 100644
index 5c2e0ee..0000000
--- a/usr.bin/make/lst.lib/lstNext.c
+++ /dev/null
@@ -1,120 +0,0 @@
-/* $NetBSD: lstNext.c,v 1.12 2008/12/13 15:19:29 dsl Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstNext.c,v 1.12 2008/12/13 15:19:29 dsl Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)lstNext.c 8.1 (Berkeley) 6/6/93";
-#else
-__RCSID("$NetBSD: lstNext.c,v 1.12 2008/12/13 15:19:29 dsl Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * LstNext.c --
- * Return the next node for a list.
- * The sequential functions access the list in a slightly different way.
- * CurPtr points to their idea of the current node in the list and they
- * access the list based on it. Because the list is circular, Lst_Next
- * and Lst_Prev will go around the list forever. Lst_IsAtEnd must be
- * used to determine when to stop.
- */
-
-#include "lstInt.h"
-
-/*-
- *-----------------------------------------------------------------------
- * Lst_Next --
- * Return the next node for the given list.
- *
- * Results:
- * The next node or NULL if the list has yet to be opened. Also
- * if the list is non-circular and the end has been reached, NULL
- * is returned.
- *
- * Side Effects:
- * the curPtr field is updated.
- *
- *-----------------------------------------------------------------------
- */
-LstNode
-Lst_Next(Lst l)
-{
- ListNode tln;
- List list = l;
-
- if ((LstValid (l) == FALSE) ||
- (list->isOpen == FALSE)) {
- return NULL;
- }
-
- list->prevPtr = list->curPtr;
-
- if (list->curPtr == NULL) {
- if (list->atEnd == Unknown) {
- /*
- * If we're just starting out, atEnd will be Unknown.
- * Then we want to start this thing off in the right
- * direction -- at the start with atEnd being Middle.
- */
- list->curPtr = tln = list->firstPtr;
- list->atEnd = Middle;
- } else {
- tln = NULL;
- list->atEnd = Tail;
- }
- } else {
- tln = list->curPtr->nextPtr;
- list->curPtr = tln;
-
- if (tln == list->firstPtr || tln == NULL) {
- /*
- * If back at the front, then we've hit the end...
- */
- list->atEnd = Tail;
- } else {
- /*
- * Reset to Middle if gone past first.
- */
- list->atEnd = Middle;
- }
- }
-
- return (tln);
-}
-
diff --git a/usr.bin/make/lst.lib/lstOpen.c b/usr.bin/make/lst.lib/lstOpen.c
deleted file mode 100644
index 941293e..0000000
--- a/usr.bin/make/lst.lib/lstOpen.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/* $NetBSD: lstOpen.c,v 1.12 2008/12/13 15:19:29 dsl Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstOpen.c,v 1.12 2008/12/13 15:19:29 dsl Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)lstOpen.c 8.1 (Berkeley) 6/6/93";
-#else
-__RCSID("$NetBSD: lstOpen.c,v 1.12 2008/12/13 15:19:29 dsl Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * LstOpen.c --
- * Open a list for sequential access. The sequential functions access the
- * list in a slightly different way. CurPtr points to their idea of the
- * current node in the list and they access the list based on it.
- * If the list is circular, Lst_Next and Lst_Prev will go around
- * the list forever. Lst_IsAtEnd must be used to determine when to stop.
- */
-
-#include "lstInt.h"
-
-/*-
- *-----------------------------------------------------------------------
- * Lst_Open --
- * Open a list for sequential access. A list can still be searched,
- * etc., without confusing these functions.
- *
- * Results:
- * SUCCESS or FAILURE.
- *
- * Side Effects:
- * isOpen is set TRUE and curPtr is set to NULL so the
- * other sequential functions no it was just opened and can choose
- * the first element accessed based on this.
- *
- *-----------------------------------------------------------------------
- */
-ReturnStatus
-Lst_Open(Lst l)
-{
- if (LstValid (l) == FALSE) {
- return (FAILURE);
- }
- (l)->isOpen = TRUE;
- (l)->atEnd = LstIsEmpty (l) ? Head : Unknown;
- (l)->curPtr = NULL;
-
- return (SUCCESS);
-}
-
diff --git a/usr.bin/make/lst.lib/lstPrev.c b/usr.bin/make/lst.lib/lstPrev.c
deleted file mode 100644
index 0ec865d..0000000
--- a/usr.bin/make/lst.lib/lstPrev.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/* $NetBSD: lstPrev.c,v 1.3 2008/12/13 15:19:29 dsl Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstPrev.c,v 1.3 2008/12/13 15:19:29 dsl Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)lstSucc.c 8.1 (Berkeley) 6/6/93";
-#else
-__RCSID("$NetBSD: lstPrev.c,v 1.3 2008/12/13 15:19:29 dsl Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * LstPrev.c --
- * return the predecessor to a given node
- */
-
-#include "lstInt.h"
-
-/*-
- *-----------------------------------------------------------------------
- * Lst_Prev --
- * Return the predecessor to the given node on its list.
- *
- * Results:
- * The predecessor of the node, if it exists (note that on a circular
- * list, if the node is the only one in the list, it is its own
- * predecessor).
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-LstNode
-Lst_Prev(LstNode ln)
-{
- if (ln == NULL) {
- return NULL;
- } else {
- return (ln->prevPtr);
- }
-}
-
diff --git a/usr.bin/make/lst.lib/lstRemove.c b/usr.bin/make/lst.lib/lstRemove.c
deleted file mode 100644
index 7480d30..0000000
--- a/usr.bin/make/lst.lib/lstRemove.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/* $NetBSD: lstRemove.c,v 1.16 2014/09/07 20:55:34 joerg Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstRemove.c,v 1.16 2014/09/07 20:55:34 joerg Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)lstRemove.c 8.1 (Berkeley) 6/6/93";
-#else
-__RCSID("$NetBSD: lstRemove.c,v 1.16 2014/09/07 20:55:34 joerg Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * LstRemove.c --
- * Remove an element from a list
- */
-
-#include "lstInt.h"
-
-/*-
- *-----------------------------------------------------------------------
- * Lst_Remove --
- * Remove the given node from the given list.
- *
- * Results:
- * SUCCESS or FAILURE.
- *
- * Side Effects:
- * The list's firstPtr will be set to NULL if ln is the last
- * node on the list. firsPtr and lastPtr will be altered if ln is
- * either the first or last node, respectively, on the list.
- *
- *-----------------------------------------------------------------------
- */
-ReturnStatus
-Lst_Remove(Lst l, LstNode ln)
-{
- List list = l;
- ListNode lNode = ln;
-
- if (!LstValid (l) ||
- !LstNodeValid (ln, l)) {
- return (FAILURE);
- }
-
- /*
- * unlink it from the list
- */
- if (lNode->nextPtr != NULL) {
- lNode->nextPtr->prevPtr = lNode->prevPtr;
- }
- if (lNode->prevPtr != NULL) {
- lNode->prevPtr->nextPtr = lNode->nextPtr;
- }
-
- /*
- * if either the firstPtr or lastPtr of the list point to this node,
- * adjust them accordingly
- */
- if (list->firstPtr == lNode) {
- list->firstPtr = lNode->nextPtr;
- }
- if (list->lastPtr == lNode) {
- list->lastPtr = lNode->prevPtr;
- }
-
- /*
- * Sequential access stuff. If the node we're removing is the current
- * node in the list, reset the current node to the previous one. If the
- * previous one was non-existent (prevPtr == NULL), we set the
- * end to be Unknown, since it is.
- */
- if (list->isOpen && (list->curPtr == lNode)) {
- list->curPtr = list->prevPtr;
- if (list->curPtr == NULL) {
- list->atEnd = Unknown;
- }
- }
-
- /*
- * the only way firstPtr can still point to ln is if ln is the last
- * node on the list (the list is circular, so lNode->nextptr == lNode in
- * this case). The list is, therefore, empty and is marked as such
- */
- if (list->firstPtr == lNode) {
- list->firstPtr = NULL;
- }
-
- /*
- * note that the datum is unmolested. The caller must free it as
- * necessary and as expected.
- */
- if (lNode->useCount == 0) {
- free(ln);
- } else {
- lNode->flags |= LN_DELETED;
- }
-
- return (SUCCESS);
-}
-
diff --git a/usr.bin/make/lst.lib/lstReplace.c b/usr.bin/make/lst.lib/lstReplace.c
deleted file mode 100644
index 090e91a..0000000
--- a/usr.bin/make/lst.lib/lstReplace.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/* $NetBSD: lstReplace.c,v 1.13 2009/01/23 21:26:30 dsl Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstReplace.c,v 1.13 2009/01/23 21:26:30 dsl Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)lstReplace.c 8.1 (Berkeley) 6/6/93";
-#else
-__RCSID("$NetBSD: lstReplace.c,v 1.13 2009/01/23 21:26:30 dsl Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * LstReplace.c --
- * Replace the datum in a node with a new datum
- */
-
-#include "lstInt.h"
-
-/*-
- *-----------------------------------------------------------------------
- * Lst_Replace --
- * Replace the datum in the given node with the new datum
- *
- * Results:
- * SUCCESS or FAILURE.
- *
- * Side Effects:
- * The datum field fo the node is altered.
- *
- *-----------------------------------------------------------------------
- */
-ReturnStatus
-Lst_Replace(LstNode ln, void *d)
-{
- if (ln == NULL) {
- return (FAILURE);
- } else {
- (ln)->datum = d;
- return (SUCCESS);
- }
-}
-
diff --git a/usr.bin/make/lst.lib/lstSucc.c b/usr.bin/make/lst.lib/lstSucc.c
deleted file mode 100644
index 3f13aa5..0000000
--- a/usr.bin/make/lst.lib/lstSucc.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/* $NetBSD: lstSucc.c,v 1.13 2008/12/13 15:19:29 dsl Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstSucc.c,v 1.13 2008/12/13 15:19:29 dsl Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)lstSucc.c 8.1 (Berkeley) 6/6/93";
-#else
-__RCSID("$NetBSD: lstSucc.c,v 1.13 2008/12/13 15:19:29 dsl Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * LstSucc.c --
- * return the successor to a given node
- */
-
-#include "lstInt.h"
-
-/*-
- *-----------------------------------------------------------------------
- * Lst_Succ --
- * Return the successor to the given node on its list.
- *
- * Results:
- * The successor of the node, if it exists (note that on a circular
- * list, if the node is the only one in the list, it is its own
- * successor).
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-LstNode
-Lst_Succ(LstNode ln)
-{
- if (ln == NULL) {
- return NULL;
- } else {
- return (ln->nextPtr);
- }
-}
-
diff --git a/usr.bin/make/main.c b/usr.bin/make/main.c
deleted file mode 100644
index a9e756a..0000000
--- a/usr.bin/make/main.c
+++ /dev/null
@@ -1,2189 +0,0 @@
-/* $NetBSD: main.c,v 1.273 2017/10/28 21:54:54 sjg Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-/*
- * Copyright (c) 1989 by Berkeley Softworks
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: main.c,v 1.273 2017/10/28 21:54:54 sjg Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-__COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993\
- The Regents of the University of California. All rights reserved.");
-#endif /* not lint */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)main.c 8.3 (Berkeley) 3/19/94";
-#else
-__RCSID("$NetBSD: main.c,v 1.273 2017/10/28 21:54:54 sjg Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * main.c --
- * The main file for this entire program. Exit routines etc
- * reside here.
- *
- * Utility functions defined in this file:
- * Main_ParseArgLine Takes a line of arguments, breaks them and
- * treats them as if they were given when first
- * invoked. Used by the parse module to implement
- * the .MFLAGS target.
- *
- * Error Print a tagged error message. The global
- * MAKE variable must have been defined. This
- * takes a format string and optional arguments
- * for it.
- *
- * Fatal Print an error message and exit. Also takes
- * a format string and arguments for it.
- *
- * Punt Aborts all jobs and exits with a message. Also
- * takes a format string and arguments for it.
- *
- * Finish Finish things up by printing the number of
- * errors which occurred, as passed to it, and
- * exiting.
- */
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/param.h>
-#include <sys/resource.h>
-#include <sys/stat.h>
-#ifdef MAKE_NATIVE
-#include <sys/sysctl.h>
-#endif
-#include <sys/utsname.h>
-#include <sys/wait.h>
-
-#include <errno.h>
-#include <signal.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <time.h>
-#include <ctype.h>
-
-#include "make.h"
-#include "hash.h"
-#include "dir.h"
-#include "job.h"
-#include "pathnames.h"
-#include "trace.h"
-
-#ifdef USE_IOVEC
-#include <sys/uio.h>
-#endif
-
-#ifndef DEFMAXLOCAL
-#define DEFMAXLOCAL DEFMAXJOBS
-#endif /* DEFMAXLOCAL */
-
-Lst create; /* Targets to be made */
-time_t now; /* Time at start of make */
-GNode *DEFAULT; /* .DEFAULT node */
-Boolean allPrecious; /* .PRECIOUS given on line by itself */
-Boolean deleteOnError; /* .DELETE_ON_ERROR: set */
-
-static Boolean noBuiltins; /* -r flag */
-static Lst makefiles; /* ordered list of makefiles to read */
-static int printVars; /* -[vV] argument */
-#define COMPAT_VARS 1
-#define EXPAND_VARS 2
-static Lst variables; /* list of variables to print */
-int maxJobs; /* -j argument */
-static int maxJobTokens; /* -j argument */
-Boolean compatMake; /* -B argument */
-int debug; /* -d argument */
-Boolean debugVflag; /* -dV */
-Boolean noExecute; /* -n flag */
-Boolean noRecursiveExecute; /* -N flag */
-Boolean keepgoing; /* -k flag */
-Boolean queryFlag; /* -q flag */
-Boolean touchFlag; /* -t flag */
-Boolean enterFlag; /* -w flag */
-Boolean enterFlagObj; /* -w and objdir != srcdir */
-Boolean ignoreErrors; /* -i flag */
-Boolean beSilent; /* -s flag */
-Boolean oldVars; /* variable substitution style */
-Boolean checkEnvFirst; /* -e flag */
-Boolean parseWarnFatal; /* -W flag */
-Boolean jobServer; /* -J flag */
-static int jp_0 = -1, jp_1 = -1; /* ends of parent job pipe */
-Boolean varNoExportEnv; /* -X flag */
-Boolean doing_depend; /* Set while reading .depend */
-static Boolean jobsRunning; /* TRUE if the jobs might be running */
-static const char * tracefile;
-static void MainParseArgs(int, char **);
-static int ReadMakefile(const void *, const void *);
-static void usage(void) MAKE_ATTR_DEAD;
-static void purge_cached_realpaths(void);
-
-static Boolean ignorePWD; /* if we use -C, PWD is meaningless */
-static char objdir[MAXPATHLEN + 1]; /* where we chdir'ed to */
-char curdir[MAXPATHLEN + 1]; /* Startup directory */
-char *progname; /* the program name */
-char *makeDependfile;
-pid_t myPid;
-int makelevel;
-
-Boolean forceJobs = FALSE;
-
-extern Lst parseIncPath;
-
-/*
- * For compatibility with the POSIX version of MAKEFLAGS that includes
- * all the options with out -, convert flags to -f -l -a -g -s.
- */
-static char *
-explode(const char *flags)
-{
- size_t len;
- char *nf, *st;
- const char *f;
-
- if (flags == NULL)
- return NULL;
-
- for (f = flags; *f; f++)
- if (!isalpha((unsigned char)*f))
- break;
-
- if (*f)
- return bmake_strdup(flags);
-
- len = strlen(flags);
- st = nf = bmake_malloc(len * 3 + 1);
- while (*flags) {
- *nf++ = '-';
- *nf++ = *flags++;
- *nf++ = ' ';
- }
- *nf = '\0';
- return st;
-}
-
-static void
-parse_debug_options(const char *argvalue)
-{
- const char *modules;
- const char *mode;
- char *fname;
- int len;
-
- for (modules = argvalue; *modules; ++modules) {
- switch (*modules) {
- case 'A':
- debug = ~0;
- break;
- case 'a':
- debug |= DEBUG_ARCH;
- break;
- case 'C':
- debug |= DEBUG_CWD;
- break;
- case 'c':
- debug |= DEBUG_COND;
- break;
- case 'd':
- debug |= DEBUG_DIR;
- break;
- case 'e':
- debug |= DEBUG_ERROR;
- break;
- case 'f':
- debug |= DEBUG_FOR;
- break;
- case 'g':
- if (modules[1] == '1') {
- debug |= DEBUG_GRAPH1;
- ++modules;
- }
- else if (modules[1] == '2') {
- debug |= DEBUG_GRAPH2;
- ++modules;
- }
- else if (modules[1] == '3') {
- debug |= DEBUG_GRAPH3;
- ++modules;
- }
- break;
- case 'j':
- debug |= DEBUG_JOB;
- break;
- case 'l':
- debug |= DEBUG_LOUD;
- break;
- case 'M':
- debug |= DEBUG_META;
- break;
- case 'm':
- debug |= DEBUG_MAKE;
- break;
- case 'n':
- debug |= DEBUG_SCRIPT;
- break;
- case 'p':
- debug |= DEBUG_PARSE;
- break;
- case 's':
- debug |= DEBUG_SUFF;
- break;
- case 't':
- debug |= DEBUG_TARG;
- break;
- case 'V':
- debugVflag = TRUE;
- break;
- case 'v':
- debug |= DEBUG_VAR;
- break;
- case 'x':
- debug |= DEBUG_SHELL;
- break;
- case 'F':
- if (debug_file != stdout && debug_file != stderr)
- fclose(debug_file);
- if (*++modules == '+') {
- modules++;
- mode = "a";
- } else
- mode = "w";
- if (strcmp(modules, "stdout") == 0) {
- debug_file = stdout;
- goto debug_setbuf;
- }
- if (strcmp(modules, "stderr") == 0) {
- debug_file = stderr;
- goto debug_setbuf;
- }
- len = strlen(modules);
- fname = bmake_malloc(len + 20);
- memcpy(fname, modules, len + 1);
- /* Let the filename be modified by the pid */
- if (strcmp(fname + len - 3, ".%d") == 0)
- snprintf(fname + len - 2, 20, "%d", getpid());
- debug_file = fopen(fname, mode);
- if (!debug_file) {
- fprintf(stderr, "Cannot open debug file %s\n",
- fname);
- usage();
- }
- free(fname);
- goto debug_setbuf;
- default:
- (void)fprintf(stderr,
- "%s: illegal argument to d option -- %c\n",
- progname, *modules);
- usage();
- }
- }
-debug_setbuf:
- /*
- * Make the debug_file unbuffered, and make
- * stdout line buffered (unless debugfile == stdout).
- */
- setvbuf(debug_file, NULL, _IONBF, 0);
- if (debug_file != stdout) {
- setvbuf(stdout, NULL, _IOLBF, 0);
- }
-}
-
-/*
- * does path contain any relative components
- */
-static int
-is_relpath(const char *path)
-{
- const char *cp;
-
- if (path[0] != '/')
- return TRUE;
- cp = path;
- do {
- cp = strstr(cp, "/.");
- if (!cp)
- break;
- cp += 2;
- if (cp[0] == '/' || cp[0] == '\0')
- return TRUE;
- else if (cp[0] == '.') {
- if (cp[1] == '/' || cp[1] == '\0')
- return TRUE;
- }
- } while (cp);
- return FALSE;
-}
-
-/*-
- * MainParseArgs --
- * Parse a given argument vector. Called from main() and from
- * Main_ParseArgLine() when the .MAKEFLAGS target is used.
- *
- * XXX: Deal with command line overriding .MAKEFLAGS in makefile
- *
- * Results:
- * None
- *
- * Side Effects:
- * Various global and local flags will be set depending on the flags
- * given
- */
-static void
-MainParseArgs(int argc, char **argv)
-{
- char *p;
- int c = '?';
- int arginc;
- char *argvalue;
- const char *getopt_def;
- struct stat sa, sb;
- char *optscan;
- Boolean inOption, dashDash = FALSE;
- char found_path[MAXPATHLEN + 1]; /* for searching for sys.mk */
-
-#define OPTFLAGS "BC:D:I:J:NST:V:WXd:ef:ij:km:nqrstv:w"
-/* Can't actually use getopt(3) because rescanning is not portable */
-
- getopt_def = OPTFLAGS;
-rearg:
- inOption = FALSE;
- optscan = NULL;
- while(argc > 1) {
- char *getopt_spec;
- if(!inOption)
- optscan = argv[1];
- c = *optscan++;
- arginc = 0;
- if(inOption) {
- if(c == '\0') {
- ++argv;
- --argc;
- inOption = FALSE;
- continue;
- }
- } else {
- if (c != '-' || dashDash)
- break;
- inOption = TRUE;
- c = *optscan++;
- }
- /* '-' found at some earlier point */
- getopt_spec = strchr(getopt_def, c);
- if(c != '\0' && getopt_spec != NULL && getopt_spec[1] == ':') {
- /* -<something> found, and <something> should have an arg */
- inOption = FALSE;
- arginc = 1;
- argvalue = optscan;
- if(*argvalue == '\0') {
- if (argc < 3)
- goto noarg;
- argvalue = argv[2];
- arginc = 2;
- }
- } else {
- argvalue = NULL;
- }
- switch(c) {
- case '\0':
- arginc = 1;
- inOption = FALSE;
- break;
- case 'B':
- compatMake = TRUE;
- Var_Append(MAKEFLAGS, "-B", VAR_GLOBAL);
- Var_Set(MAKE_MODE, "compat", VAR_GLOBAL, 0);
- break;
- case 'C':
- if (chdir(argvalue) == -1) {
- (void)fprintf(stderr,
- "%s: chdir %s: %s\n",
- progname, argvalue,
- strerror(errno));
- exit(1);
- }
- if (getcwd(curdir, MAXPATHLEN) == NULL) {
- (void)fprintf(stderr, "%s: %s.\n", progname, strerror(errno));
- exit(2);
- }
- if (!is_relpath(argvalue) &&
- stat(argvalue, &sa) != -1 &&
- stat(curdir, &sb) != -1 &&
- sa.st_ino == sb.st_ino &&
- sa.st_dev == sb.st_dev)
- strncpy(curdir, argvalue, MAXPATHLEN);
- ignorePWD = TRUE;
- break;
- case 'D':
- if (argvalue == NULL || argvalue[0] == 0) goto noarg;
- Var_Set(argvalue, "1", VAR_GLOBAL, 0);
- Var_Append(MAKEFLAGS, "-D", VAR_GLOBAL);
- Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
- break;
- case 'I':
- if (argvalue == NULL) goto noarg;
- Parse_AddIncludeDir(argvalue);
- Var_Append(MAKEFLAGS, "-I", VAR_GLOBAL);
- Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
- break;
- case 'J':
- if (argvalue == NULL) goto noarg;
- if (sscanf(argvalue, "%d,%d", &jp_0, &jp_1) != 2) {
- (void)fprintf(stderr,
- "%s: internal error -- J option malformed (%s)\n",
- progname, argvalue);
- usage();
- }
- if ((fcntl(jp_0, F_GETFD, 0) < 0) ||
- (fcntl(jp_1, F_GETFD, 0) < 0)) {
-#if 0
- (void)fprintf(stderr,
- "%s: ###### warning -- J descriptors were closed!\n",
- progname);
- exit(2);
-#endif
- jp_0 = -1;
- jp_1 = -1;
- compatMake = TRUE;
- } else {
- Var_Append(MAKEFLAGS, "-J", VAR_GLOBAL);
- Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
- jobServer = TRUE;
- }
- break;
- case 'N':
- noExecute = TRUE;
- noRecursiveExecute = TRUE;
- Var_Append(MAKEFLAGS, "-N", VAR_GLOBAL);
- break;
- case 'S':
- keepgoing = FALSE;
- Var_Append(MAKEFLAGS, "-S", VAR_GLOBAL);
- break;
- case 'T':
- if (argvalue == NULL) goto noarg;
- tracefile = bmake_strdup(argvalue);
- Var_Append(MAKEFLAGS, "-T", VAR_GLOBAL);
- Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
- break;
- case 'V':
- case 'v':
- if (argvalue == NULL) goto noarg;
- printVars = c == 'v' ? EXPAND_VARS : COMPAT_VARS;
- (void)Lst_AtEnd(variables, argvalue);
- Var_Append(MAKEFLAGS, "-V", VAR_GLOBAL);
- Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
- break;
- case 'W':
- parseWarnFatal = TRUE;
- break;
- case 'X':
- varNoExportEnv = TRUE;
- Var_Append(MAKEFLAGS, "-X", VAR_GLOBAL);
- break;
- case 'd':
- if (argvalue == NULL) goto noarg;
- /* If '-d-opts' don't pass to children */
- if (argvalue[0] == '-')
- argvalue++;
- else {
- Var_Append(MAKEFLAGS, "-d", VAR_GLOBAL);
- Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
- }
- parse_debug_options(argvalue);
- break;
- case 'e':
- checkEnvFirst = TRUE;
- Var_Append(MAKEFLAGS, "-e", VAR_GLOBAL);
- break;
- case 'f':
- if (argvalue == NULL) goto noarg;
- (void)Lst_AtEnd(makefiles, argvalue);
- break;
- case 'i':
- ignoreErrors = TRUE;
- Var_Append(MAKEFLAGS, "-i", VAR_GLOBAL);
- break;
- case 'j':
- if (argvalue == NULL) goto noarg;
- forceJobs = TRUE;
- maxJobs = strtol(argvalue, &p, 0);
- if (*p != '\0' || maxJobs < 1) {
- (void)fprintf(stderr, "%s: illegal argument to -j -- must be positive integer!\n",
- progname);
- exit(1);
- }
- Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL);
- Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
- Var_Set(".MAKE.JOBS", argvalue, VAR_GLOBAL, 0);
- maxJobTokens = maxJobs;
- break;
- case 'k':
- keepgoing = TRUE;
- Var_Append(MAKEFLAGS, "-k", VAR_GLOBAL);
- break;
- case 'm':
- if (argvalue == NULL) goto noarg;
- /* look for magic parent directory search string */
- if (strncmp(".../", argvalue, 4) == 0) {
- if (!Dir_FindHereOrAbove(curdir, argvalue+4,
- found_path, sizeof(found_path)))
- break; /* nothing doing */
- (void)Dir_AddDir(sysIncPath, found_path);
- } else {
- (void)Dir_AddDir(sysIncPath, argvalue);
- }
- Var_Append(MAKEFLAGS, "-m", VAR_GLOBAL);
- Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
- break;
- case 'n':
- noExecute = TRUE;
- Var_Append(MAKEFLAGS, "-n", VAR_GLOBAL);
- break;
- case 'q':
- queryFlag = TRUE;
- /* Kind of nonsensical, wot? */
- Var_Append(MAKEFLAGS, "-q", VAR_GLOBAL);
- break;
- case 'r':
- noBuiltins = TRUE;
- Var_Append(MAKEFLAGS, "-r", VAR_GLOBAL);
- break;
- case 's':
- beSilent = TRUE;
- Var_Append(MAKEFLAGS, "-s", VAR_GLOBAL);
- break;
- case 't':
- touchFlag = TRUE;
- Var_Append(MAKEFLAGS, "-t", VAR_GLOBAL);
- break;
- case 'w':
- enterFlag = TRUE;
- Var_Append(MAKEFLAGS, "-w", VAR_GLOBAL);
- break;
- case '-':
- dashDash = TRUE;
- break;
- default:
- case '?':
- usage();
- }
- argv += arginc;
- argc -= arginc;
- }
-
- oldVars = TRUE;
-
- /*
- * See if the rest of the arguments are variable assignments and
- * perform them if so. Else take them to be targets and stuff them
- * on the end of the "create" list.
- */
- for (; argc > 1; ++argv, --argc)
- if (Parse_IsVar(argv[1])) {
- Parse_DoVar(argv[1], VAR_CMD);
- } else {
- if (!*argv[1])
- Punt("illegal (null) argument.");
- if (*argv[1] == '-' && !dashDash)
- goto rearg;
- (void)Lst_AtEnd(create, bmake_strdup(argv[1]));
- }
-
- return;
-noarg:
- (void)fprintf(stderr, "%s: option requires an argument -- %c\n",
- progname, c);
- usage();
-}
-
-/*-
- * Main_ParseArgLine --
- * Used by the parse module when a .MFLAGS or .MAKEFLAGS target
- * is encountered and by main() when reading the .MAKEFLAGS envariable.
- * Takes a line of arguments and breaks it into its
- * component words and passes those words and the number of them to the
- * MainParseArgs function.
- * The line should have all its leading whitespace removed.
- *
- * Input:
- * line Line to fracture
- *
- * Results:
- * None
- *
- * Side Effects:
- * Only those that come from the various arguments.
- */
-void
-Main_ParseArgLine(const char *line)
-{
- char **argv; /* Manufactured argument vector */
- int argc; /* Number of arguments in argv */
- char *args; /* Space used by the args */
- char *buf, *p1;
- char *argv0 = Var_Value(".MAKE", VAR_GLOBAL, &p1);
- size_t len;
-
- if (line == NULL)
- return;
- for (; *line == ' '; ++line)
- continue;
- if (!*line)
- return;
-
- buf = bmake_malloc(len = strlen(line) + strlen(argv0) + 2);
- (void)snprintf(buf, len, "%s %s", argv0, line);
- free(p1);
-
- argv = brk_string(buf, &argc, TRUE, &args);
- if (argv == NULL) {
- Error("Unterminated quoted string [%s]", buf);
- free(buf);
- return;
- }
- free(buf);
- MainParseArgs(argc, argv);
-
- free(args);
- free(argv);
-}
-
-Boolean
-Main_SetObjdir(const char *fmt, ...)
-{
- struct stat sb;
- char *path;
- char buf[MAXPATHLEN + 1];
- char buf2[MAXPATHLEN + 1];
- Boolean rc = FALSE;
- va_list ap;
-
- va_start(ap, fmt);
- vsnprintf(path = buf, MAXPATHLEN, fmt, ap);
- va_end(ap);
-
- if (path[0] != '/') {
- snprintf(buf2, MAXPATHLEN, "%s/%s", curdir, path);
- path = buf2;
- }
-
- /* look for the directory and try to chdir there */
- if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) {
- if (chdir(path)) {
- (void)fprintf(stderr, "make warning: %s: %s.\n",
- path, strerror(errno));
- } else {
- strncpy(objdir, path, MAXPATHLEN);
- Var_Set(".OBJDIR", objdir, VAR_GLOBAL, 0);
- setenv("PWD", objdir, 1);
- Dir_InitDot();
- purge_cached_realpaths();
- rc = TRUE;
- if (enterFlag && strcmp(objdir, curdir) != 0)
- enterFlagObj = TRUE;
- }
- }
-
- return rc;
-}
-
-static Boolean
-Main_SetVarObjdir(const char *var, const char *suffix)
-{
- char *p, *path, *xpath;
-
- if ((path = Var_Value(var, VAR_CMD, &p)) == NULL ||
- *path == '\0')
- return FALSE;
-
- /* expand variable substitutions */
- if (strchr(path, '$') != 0)
- xpath = Var_Subst(NULL, path, VAR_GLOBAL, VARF_WANTRES);
- else
- xpath = path;
-
- (void)Main_SetObjdir("%s%s", xpath, suffix);
-
- if (xpath != path)
- free(xpath);
- free(p);
- return TRUE;
-}
-
-/*-
- * ReadAllMakefiles --
- * wrapper around ReadMakefile() to read all.
- *
- * Results:
- * TRUE if ok, FALSE on error
- */
-static int
-ReadAllMakefiles(const void *p, const void *q)
-{
- return (ReadMakefile(p, q) == 0);
-}
-
-int
-str2Lst_Append(Lst lp, char *str, const char *sep)
-{
- char *cp;
- int n;
-
- if (!sep)
- sep = " \t";
-
- for (n = 0, cp = strtok(str, sep); cp; cp = strtok(NULL, sep)) {
- (void)Lst_AtEnd(lp, cp);
- n++;
- }
- return (n);
-}
-
-#ifdef SIGINFO
-/*ARGSUSED*/
-static void
-siginfo(int signo MAKE_ATTR_UNUSED)
-{
- char dir[MAXPATHLEN];
- char str[2 * MAXPATHLEN];
- int len;
- if (getcwd(dir, sizeof(dir)) == NULL)
- return;
- len = snprintf(str, sizeof(str), "%s: Working in: %s\n", progname, dir);
- if (len > 0)
- (void)write(STDERR_FILENO, str, (size_t)len);
-}
-#endif
-
-/*
- * Allow makefiles some control over the mode we run in.
- */
-void
-MakeMode(const char *mode)
-{
- char *mp = NULL;
-
- if (!mode)
- mode = mp = Var_Subst(NULL, "${" MAKE_MODE ":tl}",
- VAR_GLOBAL, VARF_WANTRES);
-
- if (mode && *mode) {
- if (strstr(mode, "compat")) {
- compatMake = TRUE;
- forceJobs = FALSE;
- }
-#if USE_META
- if (strstr(mode, "meta"))
- meta_mode_init(mode);
-#endif
- }
-
- free(mp);
-}
-
-static void
-doPrintVars(void)
-{
- LstNode ln;
- Boolean expandVars;
-
- if (printVars == EXPAND_VARS)
- expandVars = TRUE;
- else if (debugVflag)
- expandVars = FALSE;
- else
- expandVars = getBoolean(".MAKE.EXPAND_VARIABLES", FALSE);
-
- for (ln = Lst_First(variables); ln != NULL;
- ln = Lst_Succ(ln)) {
- char *var = (char *)Lst_Datum(ln);
- char *value;
- char *p1;
-
- if (strchr(var, '$')) {
- value = p1 = Var_Subst(NULL, var, VAR_GLOBAL,
- VARF_WANTRES);
- } else if (expandVars) {
- char tmp[128];
- int len = snprintf(tmp, sizeof(tmp), "${%s}", var);
-
- if (len >= (int)sizeof(tmp))
- Fatal("%s: variable name too big: %s",
- progname, var);
- value = p1 = Var_Subst(NULL, tmp, VAR_GLOBAL,
- VARF_WANTRES);
- } else {
- value = Var_Value(var, VAR_GLOBAL, &p1);
- }
- printf("%s\n", value ? value : "");
- free(p1);
- }
-}
-
-static Boolean
-runTargets(void)
-{
- Lst targs; /* target nodes to create -- passed to Make_Init */
- Boolean outOfDate; /* FALSE if all targets up to date */
-
- /*
- * Have now read the entire graph and need to make a list of
- * targets to create. If none was given on the command line,
- * we consult the parsing module to find the main target(s)
- * to create.
- */
- if (Lst_IsEmpty(create))
- targs = Parse_MainName();
- else
- targs = Targ_FindList(create, TARG_CREATE);
-
- if (!compatMake) {
- /*
- * Initialize job module before traversing the graph
- * now that any .BEGIN and .END targets have been read.
- * This is done only if the -q flag wasn't given
- * (to prevent the .BEGIN from being executed should
- * it exist).
- */
- if (!queryFlag) {
- Job_Init();
- jobsRunning = TRUE;
- }
-
- /* Traverse the graph, checking on all the targets */
- outOfDate = Make_Run(targs);
- } else {
- /*
- * Compat_Init will take care of creating all the
- * targets as well as initializing the module.
- */
- Compat_Run(targs);
- outOfDate = FALSE;
- }
- Lst_Destroy(targs, NULL);
- return outOfDate;
-}
-
-/*-
- * main --
- * The main function, for obvious reasons. Initializes variables
- * and a few modules, then parses the arguments give it in the
- * environment and on the command line. Reads the system makefile
- * followed by either Makefile, makefile or the file given by the
- * -f argument. Sets the .MAKEFLAGS PMake variable based on all the
- * flags it has received by then uses either the Make or the Compat
- * module to create the initial list of targets.
- *
- * Results:
- * If -q was given, exits -1 if anything was out-of-date. Else it exits
- * 0.
- *
- * Side Effects:
- * The program exits when done. Targets are created. etc. etc. etc.
- */
-int
-main(int argc, char **argv)
-{
- Boolean outOfDate; /* FALSE if all targets up to date */
- struct stat sb, sa;
- char *p1, *path;
- char mdpath[MAXPATHLEN];
- const char *machine = getenv("MACHINE");
- const char *machine_arch = getenv("MACHINE_ARCH");
- char *syspath = getenv("MAKESYSPATH");
- Lst sysMkPath; /* Path of sys.mk */
- char *cp = NULL, *start;
- /* avoid faults on read-only strings */
- static char defsyspath[] = _PATH_DEFSYSPATH;
- char found_path[MAXPATHLEN + 1]; /* for searching for sys.mk */
- struct timeval rightnow; /* to initialize random seed */
- struct utsname utsname;
-
- /* default to writing debug to stderr */
- debug_file = stderr;
-
-#ifdef SIGINFO
- (void)bmake_signal(SIGINFO, siginfo);
-#endif
- /*
- * Set the seed to produce a different random sequence
- * on each program execution.
- */
- gettimeofday(&rightnow, NULL);
- srandom(rightnow.tv_sec + rightnow.tv_usec);
-
- if ((progname = strrchr(argv[0], '/')) != NULL)
- progname++;
- else
- progname = argv[0];
-#if defined(MAKE_NATIVE) || (defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE))
- /*
- * get rid of resource limit on file descriptors
- */
- {
- struct rlimit rl;
- if (getrlimit(RLIMIT_NOFILE, &rl) != -1 &&
- rl.rlim_cur != rl.rlim_max) {
- rl.rlim_cur = rl.rlim_max;
- (void)setrlimit(RLIMIT_NOFILE, &rl);
- }
- }
-#endif
-
- if (uname(&utsname) == -1) {
- (void)fprintf(stderr, "%s: uname failed (%s).\n", progname,
- strerror(errno));
- exit(2);
- }
-
- /*
- * Get the name of this type of MACHINE from utsname
- * so we can share an executable for similar machines.
- * (i.e. m68k: amiga hp300, mac68k, sun3, ...)
- *
- * Note that both MACHINE and MACHINE_ARCH are decided at
- * run-time.
- */
- if (!machine) {
-#ifdef MAKE_NATIVE
- machine = utsname.machine;
-#else
-#ifdef MAKE_MACHINE
- machine = MAKE_MACHINE;
-#else
- machine = "unknown";
-#endif
-#endif
- }
-
- if (!machine_arch) {
-#ifdef MAKE_NATIVE
- static char machine_arch_buf[sizeof(utsname.machine)];
- const int mib[2] = { CTL_HW, HW_MACHINE_ARCH };
- size_t len = sizeof(machine_arch_buf);
-
- if (sysctl(mib, __arraycount(mib), machine_arch_buf,
- &len, NULL, 0) < 0) {
- (void)fprintf(stderr, "%s: sysctl failed (%s).\n", progname,
- strerror(errno));
- exit(2);
- }
-
- machine_arch = machine_arch_buf;
-#else
-#ifndef MACHINE_ARCH
-#ifdef MAKE_MACHINE_ARCH
- machine_arch = MAKE_MACHINE_ARCH;
-#else
- machine_arch = "unknown";
-#endif
-#else
- machine_arch = MACHINE_ARCH;
-#endif
-#endif
- }
-
- myPid = getpid(); /* remember this for vFork() */
-
- /*
- * Just in case MAKEOBJDIR wants us to do something tricky.
- */
- Var_Init(); /* Initialize the lists of variables for
- * parsing arguments */
- Var_Set(".MAKE.OS", utsname.sysname, VAR_GLOBAL, 0);
- Var_Set("MACHINE", machine, VAR_GLOBAL, 0);
- Var_Set("MACHINE_ARCH", machine_arch, VAR_GLOBAL, 0);
-#ifdef MAKE_VERSION
- Var_Set("MAKE_VERSION", MAKE_VERSION, VAR_GLOBAL, 0);
-#endif
- Var_Set(".newline", "\n", VAR_GLOBAL, 0); /* handy for :@ loops */
- /*
- * This is the traditional preference for makefiles.
- */
-#ifndef MAKEFILE_PREFERENCE_LIST
-# define MAKEFILE_PREFERENCE_LIST "makefile Makefile"
-#endif
- Var_Set(MAKEFILE_PREFERENCE, MAKEFILE_PREFERENCE_LIST,
- VAR_GLOBAL, 0);
- Var_Set(MAKE_DEPENDFILE, ".depend", VAR_GLOBAL, 0);
-
- create = Lst_Init(FALSE);
- makefiles = Lst_Init(FALSE);
- printVars = 0;
- debugVflag = FALSE;
- variables = Lst_Init(FALSE);
- beSilent = FALSE; /* Print commands as executed */
- ignoreErrors = FALSE; /* Pay attention to non-zero returns */
- noExecute = FALSE; /* Execute all commands */
- noRecursiveExecute = FALSE; /* Execute all .MAKE targets */
- keepgoing = FALSE; /* Stop on error */
- allPrecious = FALSE; /* Remove targets when interrupted */
- deleteOnError = FALSE; /* Historical default behavior */
- queryFlag = FALSE; /* This is not just a check-run */
- noBuiltins = FALSE; /* Read the built-in rules */
- touchFlag = FALSE; /* Actually update targets */
- debug = 0; /* No debug verbosity, please. */
- jobsRunning = FALSE;
-
- maxJobs = DEFMAXLOCAL; /* Set default local max concurrency */
- maxJobTokens = maxJobs;
- compatMake = FALSE; /* No compat mode */
- ignorePWD = FALSE;
-
- /*
- * Initialize the parsing, directory and variable modules to prepare
- * for the reading of inclusion paths and variable settings on the
- * command line
- */
-
- /*
- * Initialize various variables.
- * MAKE also gets this name, for compatibility
- * .MAKEFLAGS gets set to the empty string just in case.
- * MFLAGS also gets initialized empty, for compatibility.
- */
- Parse_Init();
- if (argv[0][0] == '/' || strchr(argv[0], '/') == NULL) {
- /*
- * Leave alone if it is an absolute path, or if it does
- * not contain a '/' in which case we need to find it in
- * the path, like execvp(3) and the shells do.
- */
- p1 = argv[0];
- } else {
- /*
- * A relative path, canonicalize it.
- */
- p1 = cached_realpath(argv[0], mdpath);
- if (!p1 || *p1 != '/' || stat(p1, &sb) < 0) {
- p1 = argv[0]; /* realpath failed */
- }
- }
- Var_Set("MAKE", p1, VAR_GLOBAL, 0);
- Var_Set(".MAKE", p1, VAR_GLOBAL, 0);
- Var_Set(MAKEFLAGS, "", VAR_GLOBAL, 0);
- Var_Set(MAKEOVERRIDES, "", VAR_GLOBAL, 0);
- Var_Set("MFLAGS", "", VAR_GLOBAL, 0);
- Var_Set(".ALLTARGETS", "", VAR_GLOBAL, 0);
- /* some makefiles need to know this */
- Var_Set(MAKE_LEVEL ".ENV", MAKE_LEVEL_ENV, VAR_CMD, 0);
-
- /*
- * Set some other useful macros
- */
- {
- char tmp[64], *ep;
-
- makelevel = ((ep = getenv(MAKE_LEVEL_ENV)) && *ep) ? atoi(ep) : 0;
- if (makelevel < 0)
- makelevel = 0;
- snprintf(tmp, sizeof(tmp), "%d", makelevel);
- Var_Set(MAKE_LEVEL, tmp, VAR_GLOBAL, 0);
- snprintf(tmp, sizeof(tmp), "%u", myPid);
- Var_Set(".MAKE.PID", tmp, VAR_GLOBAL, 0);
- snprintf(tmp, sizeof(tmp), "%u", getppid());
- Var_Set(".MAKE.PPID", tmp, VAR_GLOBAL, 0);
- }
- if (makelevel > 0) {
- char pn[1024];
- snprintf(pn, sizeof(pn), "%s[%d]", progname, makelevel);
- progname = bmake_strdup(pn);
- }
-
-#ifdef USE_META
- meta_init();
-#endif
- Dir_Init(NULL); /* Dir_* safe to call from MainParseArgs */
-
- /*
- * First snag any flags out of the MAKE environment variable.
- * (Note this is *not* MAKEFLAGS since /bin/make uses that and it's
- * in a different format).
- */
-#ifdef POSIX
- p1 = explode(getenv("MAKEFLAGS"));
- Main_ParseArgLine(p1);
- free(p1);
-#else
- Main_ParseArgLine(getenv("MAKE"));
-#endif
-
- /*
- * Find where we are (now).
- * We take care of PWD for the automounter below...
- */
- if (getcwd(curdir, MAXPATHLEN) == NULL) {
- (void)fprintf(stderr, "%s: getcwd: %s.\n",
- progname, strerror(errno));
- exit(2);
- }
-
- MainParseArgs(argc, argv);
-
- if (enterFlag)
- printf("%s: Entering directory `%s'\n", progname, curdir);
-
- /*
- * Verify that cwd is sane.
- */
- if (stat(curdir, &sa) == -1) {
- (void)fprintf(stderr, "%s: %s: %s.\n",
- progname, curdir, strerror(errno));
- exit(2);
- }
-
- /*
- * All this code is so that we know where we are when we start up
- * on a different machine with pmake.
- * Overriding getcwd() with $PWD totally breaks MAKEOBJDIRPREFIX
- * since the value of curdir can vary depending on how we got
- * here. Ie sitting at a shell prompt (shell that provides $PWD)
- * or via subdir.mk in which case its likely a shell which does
- * not provide it.
- * So, to stop it breaking this case only, we ignore PWD if
- * MAKEOBJDIRPREFIX is set or MAKEOBJDIR contains a transform.
- */
-#ifndef NO_PWD_OVERRIDE
- if (!ignorePWD) {
- char *pwd, *ptmp1 = NULL, *ptmp2 = NULL;
-
- if ((pwd = getenv("PWD")) != NULL &&
- Var_Value("MAKEOBJDIRPREFIX", VAR_CMD, &ptmp1) == NULL) {
- const char *makeobjdir = Var_Value("MAKEOBJDIR",
- VAR_CMD, &ptmp2);
-
- if (makeobjdir == NULL || !strchr(makeobjdir, '$')) {
- if (stat(pwd, &sb) == 0 &&
- sa.st_ino == sb.st_ino &&
- sa.st_dev == sb.st_dev)
- (void)strncpy(curdir, pwd, MAXPATHLEN);
- }
- }
- free(ptmp1);
- free(ptmp2);
- }
-#endif
- Var_Set(".CURDIR", curdir, VAR_GLOBAL, 0);
-
- /*
- * Find the .OBJDIR. If MAKEOBJDIRPREFIX, or failing that,
- * MAKEOBJDIR is set in the environment, try only that value
- * and fall back to .CURDIR if it does not exist.
- *
- * Otherwise, try _PATH_OBJDIR.MACHINE-MACHINE_ARCH, _PATH_OBJDIR.MACHINE,
- * and * finally _PATH_OBJDIRPREFIX`pwd`, in that order. If none
- * of these paths exist, just use .CURDIR.
- */
- Dir_Init(curdir);
- (void)Main_SetObjdir("%s", curdir);
-
- if (!Main_SetVarObjdir("MAKEOBJDIRPREFIX", curdir) &&
- !Main_SetVarObjdir("MAKEOBJDIR", "") &&
- !Main_SetObjdir("%s.%s-%s", _PATH_OBJDIR, machine, machine_arch) &&
- !Main_SetObjdir("%s.%s", _PATH_OBJDIR, machine) &&
- !Main_SetObjdir("%s", _PATH_OBJDIR))
- (void)Main_SetObjdir("%s%s", _PATH_OBJDIRPREFIX, curdir);
-
- /*
- * Initialize archive, target and suffix modules in preparation for
- * parsing the makefile(s)
- */
- Arch_Init();
- Targ_Init();
- Suff_Init();
- Trace_Init(tracefile);
-
- DEFAULT = NULL;
- (void)time(&now);
-
- Trace_Log(MAKESTART, NULL);
-
- /*
- * Set up the .TARGETS variable to contain the list of targets to be
- * created. If none specified, make the variable empty -- the parser
- * will fill the thing in with the default or .MAIN target.
- */
- if (!Lst_IsEmpty(create)) {
- LstNode ln;
-
- for (ln = Lst_First(create); ln != NULL;
- ln = Lst_Succ(ln)) {
- char *name = (char *)Lst_Datum(ln);
-
- Var_Append(".TARGETS", name, VAR_GLOBAL);
- }
- } else
- Var_Set(".TARGETS", "", VAR_GLOBAL, 0);
-
-
- /*
- * If no user-supplied system path was given (through the -m option)
- * add the directories from the DEFSYSPATH (more than one may be given
- * as dir1:...:dirn) to the system include path.
- */
- if (syspath == NULL || *syspath == '\0')
- syspath = defsyspath;
- else
- syspath = bmake_strdup(syspath);
-
- for (start = syspath; *start != '\0'; start = cp) {
- for (cp = start; *cp != '\0' && *cp != ':'; cp++)
- continue;
- if (*cp == ':') {
- *cp++ = '\0';
- }
- /* look for magic parent directory search string */
- if (strncmp(".../", start, 4) != 0) {
- (void)Dir_AddDir(defIncPath, start);
- } else {
- if (Dir_FindHereOrAbove(curdir, start+4,
- found_path, sizeof(found_path))) {
- (void)Dir_AddDir(defIncPath, found_path);
- }
- }
- }
- if (syspath != defsyspath)
- free(syspath);
-
- /*
- * Read in the built-in rules first, followed by the specified
- * makefile, if it was (makefile != NULL), or the default
- * makefile and Makefile, in that order, if it wasn't.
- */
- if (!noBuiltins) {
- LstNode ln;
-
- sysMkPath = Lst_Init(FALSE);
- Dir_Expand(_PATH_DEFSYSMK,
- Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath,
- sysMkPath);
- if (Lst_IsEmpty(sysMkPath))
- Fatal("%s: no system rules (%s).", progname,
- _PATH_DEFSYSMK);
- ln = Lst_Find(sysMkPath, NULL, ReadMakefile);
- if (ln == NULL)
- Fatal("%s: cannot open %s.", progname,
- (char *)Lst_Datum(ln));
- }
-
- if (!Lst_IsEmpty(makefiles)) {
- LstNode ln;
-
- ln = Lst_Find(makefiles, NULL, ReadAllMakefiles);
- if (ln != NULL)
- Fatal("%s: cannot open %s.", progname,
- (char *)Lst_Datum(ln));
- } else {
- p1 = Var_Subst(NULL, "${" MAKEFILE_PREFERENCE "}",
- VAR_CMD, VARF_WANTRES);
- if (p1) {
- (void)str2Lst_Append(makefiles, p1, NULL);
- (void)Lst_Find(makefiles, NULL, ReadMakefile);
- free(p1);
- }
- }
-
- /* In particular suppress .depend for '-r -V .OBJDIR -f /dev/null' */
- if (!noBuiltins || !printVars) {
- makeDependfile = Var_Subst(NULL, "${.MAKE.DEPENDFILE:T}",
- VAR_CMD, VARF_WANTRES);
- doing_depend = TRUE;
- (void)ReadMakefile(makeDependfile, NULL);
- doing_depend = FALSE;
- }
-
- if (enterFlagObj)
- printf("%s: Entering directory `%s'\n", progname, objdir);
-
- MakeMode(NULL);
-
- Var_Append("MFLAGS", Var_Value(MAKEFLAGS, VAR_GLOBAL, &p1), VAR_GLOBAL);
- free(p1);
-
- if (!forceJobs && !compatMake &&
- Var_Exists(".MAKE.JOBS", VAR_GLOBAL)) {
- char *value;
- int n;
-
- value = Var_Subst(NULL, "${.MAKE.JOBS}", VAR_GLOBAL, VARF_WANTRES);
- n = strtol(value, NULL, 0);
- if (n < 1) {
- (void)fprintf(stderr, "%s: illegal value for .MAKE.JOBS -- must be positive integer!\n",
- progname);
- exit(1);
- }
- if (n != maxJobs) {
- Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL);
- Var_Append(MAKEFLAGS, value, VAR_GLOBAL);
- }
- maxJobs = n;
- maxJobTokens = maxJobs;
- forceJobs = TRUE;
- free(value);
- }
-
- /*
- * Be compatible if user did not specify -j and did not explicitly
- * turned compatibility on
- */
- if (!compatMake && !forceJobs) {
- compatMake = TRUE;
- }
-
- if (!compatMake)
- Job_ServerStart(maxJobTokens, jp_0, jp_1);
- if (DEBUG(JOB))
- fprintf(debug_file, "job_pipe %d %d, maxjobs %d, tokens %d, compat %d\n",
- jp_0, jp_1, maxJobs, maxJobTokens, compatMake);
-
- if (!printVars)
- Main_ExportMAKEFLAGS(TRUE); /* initial export */
-
-
- /*
- * For compatibility, look at the directories in the VPATH variable
- * and add them to the search path, if the variable is defined. The
- * variable's value is in the same format as the PATH envariable, i.e.
- * <directory>:<directory>:<directory>...
- */
- if (Var_Exists("VPATH", VAR_CMD)) {
- char *vpath, savec;
- /*
- * GCC stores string constants in read-only memory, but
- * Var_Subst will want to write this thing, so store it
- * in an array
- */
- static char VPATH[] = "${VPATH}";
-
- vpath = Var_Subst(NULL, VPATH, VAR_CMD, VARF_WANTRES);
- path = vpath;
- do {
- /* skip to end of directory */
- for (cp = path; *cp != ':' && *cp != '\0'; cp++)
- continue;
- /* Save terminator character so know when to stop */
- savec = *cp;
- *cp = '\0';
- /* Add directory to search path */
- (void)Dir_AddDir(dirSearchPath, path);
- *cp = savec;
- path = cp + 1;
- } while (savec == ':');
- free(vpath);
- }
-
- /*
- * Now that all search paths have been read for suffixes et al, it's
- * time to add the default search path to their lists...
- */
- Suff_DoPaths();
-
- /*
- * Propagate attributes through :: dependency lists.
- */
- Targ_Propagate();
-
- /* print the initial graph, if the user requested it */
- if (DEBUG(GRAPH1))
- Targ_PrintGraph(1);
-
- /* print the values of any variables requested by the user */
- if (printVars) {
- doPrintVars();
- outOfDate = FALSE;
- } else {
- outOfDate = runTargets();
- }
-
-#ifdef CLEANUP
- Lst_Destroy(variables, NULL);
- Lst_Destroy(makefiles, NULL);
- Lst_Destroy(create, (FreeProc *)free);
-#endif
-
- /* print the graph now it's been processed if the user requested it */
- if (DEBUG(GRAPH2))
- Targ_PrintGraph(2);
-
- Trace_Log(MAKEEND, 0);
-
- if (enterFlagObj)
- printf("%s: Leaving directory `%s'\n", progname, objdir);
- if (enterFlag)
- printf("%s: Leaving directory `%s'\n", progname, curdir);
-
-#ifdef USE_META
- meta_finish();
-#endif
- Suff_End();
- Targ_End();
- Arch_End();
- Var_End();
- Parse_End();
- Dir_End();
- Job_End();
- Trace_End();
-
- return outOfDate ? 1 : 0;
-}
-
-/*-
- * ReadMakefile --
- * Open and parse the given makefile.
- *
- * Results:
- * 0 if ok. -1 if couldn't open file.
- *
- * Side Effects:
- * lots
- */
-static int
-ReadMakefile(const void *p, const void *q MAKE_ATTR_UNUSED)
-{
- const char *fname = p; /* makefile to read */
- int fd;
- size_t len = MAXPATHLEN;
- char *name, *path = bmake_malloc(len);
-
- if (!strcmp(fname, "-")) {
- Parse_File(NULL /*stdin*/, -1);
- Var_Set("MAKEFILE", "", VAR_INTERNAL, 0);
- } else {
- /* if we've chdir'd, rebuild the path name */
- if (strcmp(curdir, objdir) && *fname != '/') {
- size_t plen = strlen(curdir) + strlen(fname) + 2;
- if (len < plen)
- path = bmake_realloc(path, len = 2 * plen);
-
- (void)snprintf(path, len, "%s/%s", curdir, fname);
- fd = open(path, O_RDONLY);
- if (fd != -1) {
- fname = path;
- goto found;
- }
-
- /* If curdir failed, try objdir (ala .depend) */
- plen = strlen(objdir) + strlen(fname) + 2;
- if (len < plen)
- path = bmake_realloc(path, len = 2 * plen);
- (void)snprintf(path, len, "%s/%s", objdir, fname);
- fd = open(path, O_RDONLY);
- if (fd != -1) {
- fname = path;
- goto found;
- }
- } else {
- fd = open(fname, O_RDONLY);
- if (fd != -1)
- goto found;
- }
- /* look in -I and system include directories. */
- name = Dir_FindFile(fname, parseIncPath);
- if (!name)
- name = Dir_FindFile(fname,
- Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath);
- if (!name || (fd = open(name, O_RDONLY)) == -1) {
- free(name);
- free(path);
- return(-1);
- }
- fname = name;
- /*
- * set the MAKEFILE variable desired by System V fans -- the
- * placement of the setting here means it gets set to the last
- * makefile specified, as it is set by SysV make.
- */
-found:
- if (!doing_depend)
- Var_Set("MAKEFILE", fname, VAR_INTERNAL, 0);
- Parse_File(fname, fd);
- }
- free(path);
- return(0);
-}
-
-
-
-/*-
- * Cmd_Exec --
- * Execute the command in cmd, and return the output of that command
- * in a string.
- *
- * Results:
- * A string containing the output of the command, or the empty string
- * If errnum is not NULL, it contains the reason for the command failure
- *
- * Side Effects:
- * The string must be freed by the caller.
- */
-char *
-Cmd_Exec(const char *cmd, const char **errnum)
-{
- const char *args[4]; /* Args for invoking the shell */
- int fds[2]; /* Pipe streams */
- int cpid; /* Child PID */
- int pid; /* PID from wait() */
- char *res; /* result */
- int status; /* command exit status */
- Buffer buf; /* buffer to store the result */
- char *cp;
- int cc; /* bytes read, or -1 */
- int savederr; /* saved errno */
-
-
- *errnum = NULL;
-
- if (!shellName)
- Shell_Init();
- /*
- * Set up arguments for shell
- */
- args[0] = shellName;
- args[1] = "-c";
- args[2] = cmd;
- args[3] = NULL;
-
- /*
- * Open a pipe for fetching its output
- */
- if (pipe(fds) == -1) {
- *errnum = "Couldn't create pipe for \"%s\"";
- goto bad;
- }
-
- /*
- * Fork
- */
- switch (cpid = vFork()) {
- case 0:
- /*
- * Close input side of pipe
- */
- (void)close(fds[0]);
-
- /*
- * Duplicate the output stream to the shell's output, then
- * shut the extra thing down. Note we don't fetch the error
- * stream...why not? Why?
- */
- (void)dup2(fds[1], 1);
- (void)close(fds[1]);
-
- Var_ExportVars();
-
- (void)execv(shellPath, UNCONST(args));
- _exit(1);
- /*NOTREACHED*/
-
- case -1:
- *errnum = "Couldn't exec \"%s\"";
- goto bad;
-
- default:
- /*
- * No need for the writing half
- */
- (void)close(fds[1]);
-
- savederr = 0;
- Buf_Init(&buf, 0);
-
- do {
- char result[BUFSIZ];
- cc = read(fds[0], result, sizeof(result));
- if (cc > 0)
- Buf_AddBytes(&buf, cc, result);
- }
- while (cc > 0 || (cc == -1 && errno == EINTR));
- if (cc == -1)
- savederr = errno;
-
- /*
- * Close the input side of the pipe.
- */
- (void)close(fds[0]);
-
- /*
- * Wait for the process to exit.
- */
- while(((pid = waitpid(cpid, &status, 0)) != cpid) && (pid >= 0)) {
- JobReapChild(pid, status, FALSE);
- continue;
- }
- cc = Buf_Size(&buf);
- res = Buf_Destroy(&buf, FALSE);
-
- if (savederr != 0)
- *errnum = "Couldn't read shell's output for \"%s\"";
-
- if (WIFSIGNALED(status))
- *errnum = "\"%s\" exited on a signal";
- else if (WEXITSTATUS(status) != 0)
- *errnum = "\"%s\" returned non-zero status";
-
- /*
- * Null-terminate the result, convert newlines to spaces and
- * install it in the variable.
- */
- res[cc] = '\0';
- cp = &res[cc];
-
- if (cc > 0 && *--cp == '\n') {
- /*
- * A final newline is just stripped
- */
- *cp-- = '\0';
- }
- while (cp >= res) {
- if (*cp == '\n') {
- *cp = ' ';
- }
- cp--;
- }
- break;
- }
- return res;
-bad:
- res = bmake_malloc(1);
- *res = '\0';
- return res;
-}
-
-/*-
- * Error --
- * Print an error message given its format.
- *
- * Results:
- * None.
- *
- * Side Effects:
- * The message is printed.
- */
-/* VARARGS */
-void
-Error(const char *fmt, ...)
-{
- va_list ap;
- FILE *err_file;
-
- err_file = debug_file;
- if (err_file == stdout)
- err_file = stderr;
- (void)fflush(stdout);
- for (;;) {
- va_start(ap, fmt);
- fprintf(err_file, "%s: ", progname);
- (void)vfprintf(err_file, fmt, ap);
- va_end(ap);
- (void)fprintf(err_file, "\n");
- (void)fflush(err_file);
- if (err_file == stderr)
- break;
- err_file = stderr;
- }
-}
-
-/*-
- * Fatal --
- * Produce a Fatal error message. If jobs are running, waits for them
- * to finish.
- *
- * Results:
- * None
- *
- * Side Effects:
- * The program exits
- */
-/* VARARGS */
-void
-Fatal(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- if (jobsRunning)
- Job_Wait();
-
- (void)fflush(stdout);
- (void)vfprintf(stderr, fmt, ap);
- va_end(ap);
- (void)fprintf(stderr, "\n");
- (void)fflush(stderr);
-
- PrintOnError(NULL, NULL);
-
- if (DEBUG(GRAPH2) || DEBUG(GRAPH3))
- Targ_PrintGraph(2);
- Trace_Log(MAKEERROR, 0);
- exit(2); /* Not 1 so -q can distinguish error */
-}
-
-/*
- * Punt --
- * Major exception once jobs are being created. Kills all jobs, prints
- * a message and exits.
- *
- * Results:
- * None
- *
- * Side Effects:
- * All children are killed indiscriminately and the program Lib_Exits
- */
-/* VARARGS */
-void
-Punt(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- (void)fflush(stdout);
- (void)fprintf(stderr, "%s: ", progname);
- (void)vfprintf(stderr, fmt, ap);
- va_end(ap);
- (void)fprintf(stderr, "\n");
- (void)fflush(stderr);
-
- PrintOnError(NULL, NULL);
-
- DieHorribly();
-}
-
-/*-
- * DieHorribly --
- * Exit without giving a message.
- *
- * Results:
- * None
- *
- * Side Effects:
- * A big one...
- */
-void
-DieHorribly(void)
-{
- if (jobsRunning)
- Job_AbortAll();
- if (DEBUG(GRAPH2))
- Targ_PrintGraph(2);
- Trace_Log(MAKEERROR, 0);
- exit(2); /* Not 1, so -q can distinguish error */
-}
-
-/*
- * Finish --
- * Called when aborting due to errors in child shell to signal
- * abnormal exit.
- *
- * Results:
- * None
- *
- * Side Effects:
- * The program exits
- */
-void
-Finish(int errors)
- /* number of errors encountered in Make_Make */
-{
- Fatal("%d error%s", errors, errors == 1 ? "" : "s");
-}
-
-/*
- * eunlink --
- * Remove a file carefully, avoiding directories.
- */
-int
-eunlink(const char *file)
-{
- struct stat st;
-
- if (lstat(file, &st) == -1)
- return -1;
-
- if (S_ISDIR(st.st_mode)) {
- errno = EISDIR;
- return -1;
- }
- return unlink(file);
-}
-
-/*
- * execError --
- * Print why exec failed, avoiding stdio.
- */
-void
-execError(const char *af, const char *av)
-{
-#ifdef USE_IOVEC
- int i = 0;
- struct iovec iov[8];
-#define IOADD(s) \
- (void)(iov[i].iov_base = UNCONST(s), \
- iov[i].iov_len = strlen(iov[i].iov_base), \
- i++)
-#else
-#define IOADD(void)write(2, s, strlen(s))
-#endif
-
- IOADD(progname);
- IOADD(": ");
- IOADD(af);
- IOADD("(");
- IOADD(av);
- IOADD(") failed (");
- IOADD(strerror(errno));
- IOADD(")\n");
-
-#ifdef USE_IOVEC
- while (writev(2, iov, 8) == -1 && errno == EAGAIN)
- continue;
-#endif
-}
-
-/*
- * usage --
- * exit with usage message
- */
-static void
-usage(void)
-{
- char *p;
- if ((p = strchr(progname, '[')) != NULL)
- *p = '\0';
-
- (void)fprintf(stderr,
-"usage: %s [-BeikNnqrstWwX] \n\
- [-C directory] [-D variable] [-d flags] [-f makefile]\n\
- [-I directory] [-J private] [-j max_jobs] [-m directory] [-T file]\n\
- [-V variable] [-v variable] [variable=value] [target ...]\n",
- progname);
- exit(2);
-}
-
-/*
- * realpath(3) can get expensive, cache results...
- */
-static GNode *cached_realpaths = NULL;
-
-static GNode *
-get_cached_realpaths(void)
-{
-
- if (!cached_realpaths) {
- cached_realpaths = Targ_NewGN("Realpath");
-#ifndef DEBUG_REALPATH_CACHE
- cached_realpaths->flags = INTERNAL;
-#endif
- }
-
- return cached_realpaths;
-}
-
-/* purge any relative paths */
-static void
-purge_cached_realpaths(void)
-{
- GNode *cache = get_cached_realpaths();
- Hash_Entry *he, *nhe;
- Hash_Search hs;
-
- he = Hash_EnumFirst(&cache->context, &hs);
- while (he) {
- nhe = Hash_EnumNext(&hs);
- if (he->name[0] != '/') {
- if (DEBUG(DIR))
- fprintf(stderr, "cached_realpath: purging %s\n", he->name);
- Hash_DeleteEntry(&cache->context, he);
- }
- he = nhe;
- }
-}
-
-char *
-cached_realpath(const char *pathname, char *resolved)
-{
- GNode *cache;
- char *rp, *cp;
-
- if (!pathname || !pathname[0])
- return NULL;
-
- cache = get_cached_realpaths();
-
- if ((rp = Var_Value(pathname, cache, &cp)) != NULL) {
- /* a hit */
- strncpy(resolved, rp, MAXPATHLEN);
- resolved[MAXPATHLEN - 1] = '\0';
- } else if ((rp = realpath(pathname, resolved)) != NULL) {
- Var_Set(pathname, rp, cache, 0);
- } /* else should we negative-cache? */
-
- free(cp);
- return rp ? resolved : NULL;
-}
-
-int
-PrintAddr(void *a, void *b)
-{
- printf("%lx ", (unsigned long) a);
- return b ? 0 : 0;
-}
-
-
-static int
-addErrorCMD(void *cmdp, void *gnp)
-{
- if (cmdp == NULL)
- return 1; /* stop */
- Var_Append(".ERROR_CMD", cmdp, VAR_GLOBAL);
- return 0;
-}
-
-void
-PrintOnError(GNode *gn, const char *s)
-{
- static GNode *en = NULL;
- char tmp[64];
- char *cp;
-
- if (s)
- printf("%s", s);
-
- printf("\n%s: stopped in %s\n", progname, curdir);
-
- if (en)
- return; /* we've been here! */
- if (gn) {
- /*
- * We can print this even if there is no .ERROR target.
- */
- Var_Set(".ERROR_TARGET", gn->name, VAR_GLOBAL, 0);
- Var_Delete(".ERROR_CMD", VAR_GLOBAL);
- Lst_ForEach(gn->commands, addErrorCMD, gn);
- }
- strncpy(tmp, "${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}",
- sizeof(tmp) - 1);
- cp = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES);
- if (cp) {
- if (*cp)
- printf("%s", cp);
- free(cp);
- }
- fflush(stdout);
-
- /*
- * Finally, see if there is a .ERROR target, and run it if so.
- */
- en = Targ_FindNode(".ERROR", TARG_NOCREATE);
- if (en) {
- en->type |= OP_SPECIAL;
- Compat_Make(en, en);
- }
-}
-
-void
-Main_ExportMAKEFLAGS(Boolean first)
-{
- static int once = 1;
- char tmp[64];
- char *s;
-
- if (once != first)
- return;
- once = 0;
-
- strncpy(tmp, "${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}",
- sizeof(tmp));
- s = Var_Subst(NULL, tmp, VAR_CMD, VARF_WANTRES);
- if (s && *s) {
-#ifdef POSIX
- setenv("MAKEFLAGS", s, 1);
-#else
- setenv("MAKE", s, 1);
-#endif
- }
-}
-
-char *
-getTmpdir(void)
-{
- static char *tmpdir = NULL;
-
- if (!tmpdir) {
- struct stat st;
-
- /*
- * Honor $TMPDIR but only if it is valid.
- * Ensure it ends with /.
- */
- tmpdir = Var_Subst(NULL, "${TMPDIR:tA:U" _PATH_TMP "}/", VAR_GLOBAL,
- VARF_WANTRES);
- if (stat(tmpdir, &st) < 0 || !S_ISDIR(st.st_mode)) {
- free(tmpdir);
- tmpdir = bmake_strdup(_PATH_TMP);
- }
- }
- return tmpdir;
-}
-
-/*
- * Create and open a temp file using "pattern".
- * If "fnamep" is provided set it to a copy of the filename created.
- * Otherwise unlink the file once open.
- */
-int
-mkTempFile(const char *pattern, char **fnamep)
-{
- static char *tmpdir = NULL;
- char tfile[MAXPATHLEN];
- int fd;
-
- if (!pattern)
- pattern = TMPPAT;
- if (!tmpdir)
- tmpdir = getTmpdir();
- if (pattern[0] == '/') {
- snprintf(tfile, sizeof(tfile), "%s", pattern);
- } else {
- snprintf(tfile, sizeof(tfile), "%s%s", tmpdir, pattern);
- }
- if ((fd = mkstemp(tfile)) < 0)
- Punt("Could not create temporary file %s: %s", tfile, strerror(errno));
- if (fnamep) {
- *fnamep = bmake_strdup(tfile);
- } else {
- unlink(tfile); /* we just want the descriptor */
- }
- return fd;
-}
-
-/*
- * Convert a string representation of a boolean.
- * Anything that looks like "No", "False", "Off", "0" etc,
- * is FALSE, otherwise TRUE.
- */
-Boolean
-s2Boolean(const char *s, Boolean bf)
-{
- if (s) {
- switch(*s) {
- case '\0': /* not set - the default wins */
- break;
- case '0':
- case 'F':
- case 'f':
- case 'N':
- case 'n':
- bf = FALSE;
- break;
- case 'O':
- case 'o':
- switch (s[1]) {
- case 'F':
- case 'f':
- bf = FALSE;
- break;
- default:
- bf = TRUE;
- break;
- }
- break;
- default:
- bf = TRUE;
- break;
- }
- }
- return (bf);
-}
-
-/*
- * Return a Boolean based on setting of a knob.
- *
- * If the knob is not set, the supplied default is the return value.
- * If set, anything that looks or smells like "No", "False", "Off", "0" etc,
- * is FALSE, otherwise TRUE.
- */
-Boolean
-getBoolean(const char *name, Boolean bf)
-{
- char tmp[64];
- char *cp;
-
- if (snprintf(tmp, sizeof(tmp), "${%s:U:tl}", name) < (int)(sizeof(tmp))) {
- cp = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES);
-
- if (cp) {
- bf = s2Boolean(cp, bf);
- free(cp);
- }
- }
- return (bf);
-}
diff --git a/usr.bin/make/make.1 b/usr.bin/make/make.1
deleted file mode 100644
index 866631c..0000000
--- a/usr.bin/make/make.1
+++ /dev/null
@@ -1,2413 +0,0 @@
-.\" $NetBSD: make.1,v 1.273 2018/05/27 01:14:51 christos Exp $
-.\"
-.\" Copyright (c) 1990, 1993
-.\" The Regents of the University of California. All rights reserved.
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions
-.\" are met:
-.\" 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.
-.\"
-.\" from: @(#)make.1 8.4 (Berkeley) 3/19/94
-.\"
-.Dd May 26, 2018
-.Dt MAKE 1
-.Os
-.Sh NAME
-.Nm make
-.Nd maintain program dependencies
-.Sh SYNOPSIS
-.Nm
-.Op Fl BeikNnqrstWwX
-.Op Fl C Ar directory
-.Op Fl D Ar variable
-.Op Fl d Ar flags
-.Op Fl f Ar makefile
-.Op Fl I Ar directory
-.Op Fl J Ar private
-.Op Fl j Ar max_jobs
-.Op Fl m Ar directory
-.Op Fl T Ar file
-.Op Fl V Ar variable
-.Op Fl v Ar variable
-.Op Ar variable=value
-.Op Ar target ...
-.Sh DESCRIPTION
-.Nm
-is a program designed to simplify the maintenance of other programs.
-Its input is a list of specifications as to the files upon which programs
-and other files depend.
-If no
-.Fl f Ar makefile
-makefile option is given,
-.Nm
-will try to open
-.Ql Pa makefile
-then
-.Ql Pa Makefile
-in order to find the specifications.
-If the file
-.Ql Pa .depend
-exists, it is read (see
-.Xr mkdep 1 ) .
-.Pp
-This manual page is intended as a reference document only.
-For a more thorough description of
-.Nm
-and makefiles, please refer to
-.%T "PMake \- A Tutorial" .
-.Pp
-.Nm
-will prepend the contents of the
-.Va MAKEFLAGS
-environment variable to the command line arguments before parsing them.
-.Pp
-The options are as follows:
-.Bl -tag -width Ds
-.It Fl B
-Try to be backwards compatible by executing a single shell per command and
-by executing the commands to make the sources of a dependency line in sequence.
-.It Fl C Ar directory
-Change to
-.Ar directory
-before reading the makefiles or doing anything else.
-If multiple
-.Fl C
-options are specified, each is interpreted relative to the previous one:
-.Fl C Pa / Fl C Pa etc
-is equivalent to
-.Fl C Pa /etc .
-.It Fl D Ar variable
-Define
-.Ar variable
-to be 1, in the global context.
-.It Fl d Ar [-]flags
-Turn on debugging, and specify which portions of
-.Nm
-are to print debugging information.
-Unless the flags are preceded by
-.Ql \-
-they are added to the
-.Va MAKEFLAGS
-environment variable and will be processed by any child make processes.
-By default, debugging information is printed to standard error,
-but this can be changed using the
-.Ar F
-debugging flag.
-The debugging output is always unbuffered; in addition, if debugging
-is enabled but debugging output is not directed to standard output,
-then the standard output is line buffered.
-.Ar Flags
-is one or more of the following:
-.Bl -tag -width Ds
-.It Ar A
-Print all possible debugging information;
-equivalent to specifying all of the debugging flags.
-.It Ar a
-Print debugging information about archive searching and caching.
-.It Ar C
-Print debugging information about current working directory.
-.It Ar c
-Print debugging information about conditional evaluation.
-.It Ar d
-Print debugging information about directory searching and caching.
-.It Ar e
-Print debugging information about failed commands and targets.
-.It Ar F Ns Oo Sy \&+ Oc Ns Ar filename
-Specify where debugging output is written.
-This must be the last flag, because it consumes the remainder of
-the argument.
-If the character immediately after the
-.Ql F
-flag is
-.Ql \&+ ,
-then the file will be opened in append mode;
-otherwise the file will be overwritten.
-If the file name is
-.Ql stdout
-or
-.Ql stderr
-then debugging output will be written to the
-standard output or standard error output file descriptors respectively
-(and the
-.Ql \&+
-option has no effect).
-Otherwise, the output will be written to the named file.
-If the file name ends
-.Ql .%d
-then the
-.Ql %d
-is replaced by the pid.
-.It Ar f
-Print debugging information about loop evaluation.
-.It Ar "g1"
-Print the input graph before making anything.
-.It Ar "g2"
-Print the input graph after making everything, or before exiting
-on error.
-.It Ar "g3"
-Print the input graph before exiting on error.
-.It Ar j
-Print debugging information about running multiple shells.
-.It Ar l
-Print commands in Makefiles regardless of whether or not they are prefixed by
-.Ql @
-or other "quiet" flags.
-Also known as "loud" behavior.
-.It Ar M
-Print debugging information about "meta" mode decisions about targets.
-.It Ar m
-Print debugging information about making targets, including modification
-dates.
-.It Ar n
-Don't delete the temporary command scripts created when running commands.
-These temporary scripts are created in the directory
-referred to by the
-.Ev TMPDIR
-environment variable, or in
-.Pa /tmp
-if
-.Ev TMPDIR
-is unset or set to the empty string.
-The temporary scripts are created by
-.Xr mkstemp 3 ,
-and have names of the form
-.Pa makeXXXXXX .
-.Em NOTE :
-This can create many files in
-.Ev TMPDIR
-or
-.Pa /tmp ,
-so use with care.
-.It Ar p
-Print debugging information about makefile parsing.
-.It Ar s
-Print debugging information about suffix-transformation rules.
-.It Ar t
-Print debugging information about target list maintenance.
-.It Ar V
-Force the
-.Fl V
-option to print raw values of variables, overriding the default behavior
-set via
-.Va .MAKE.EXPAND_VARIABLES .
-.It Ar v
-Print debugging information about variable assignment.
-.It Ar x
-Run shell commands with
-.Fl x
-so the actual commands are printed as they are executed.
-.El
-.It Fl e
-Specify that environment variables override macro assignments within
-makefiles.
-.It Fl f Ar makefile
-Specify a makefile to read instead of the default
-.Ql Pa makefile .
-If
-.Ar makefile
-is
-.Ql Fl ,
-standard input is read.
-Multiple makefiles may be specified, and are read in the order specified.
-.It Fl I Ar directory
-Specify a directory in which to search for makefiles and included makefiles.
-The system makefile directory (or directories, see the
-.Fl m
-option) is automatically included as part of this list.
-.It Fl i
-Ignore non-zero exit of shell commands in the makefile.
-Equivalent to specifying
-.Ql Fl
-before each command line in the makefile.
-.It Fl J Ar private
-This option should
-.Em not
-be specified by the user.
-.Pp
-When the
-.Ar j
-option is in use in a recursive build, this option is passed by a make
-to child makes to allow all the make processes in the build to
-cooperate to avoid overloading the system.
-.It Fl j Ar max_jobs
-Specify the maximum number of jobs that
-.Nm
-may have running at any one time.
-The value is saved in
-.Va .MAKE.JOBS .
-Turns compatibility mode off, unless the
-.Ar B
-flag is also specified.
-When compatibility mode is off, all commands associated with a
-target are executed in a single shell invocation as opposed to the
-traditional one shell invocation per line.
-This can break traditional scripts which change directories on each
-command invocation and then expect to start with a fresh environment
-on the next line.
-It is more efficient to correct the scripts rather than turn backwards
-compatibility on.
-.It Fl k
-Continue processing after errors are encountered, but only on those targets
-that do not depend on the target whose creation caused the error.
-.It Fl m Ar directory
-Specify a directory in which to search for sys.mk and makefiles included
-via the
-.Ao Ar file Ac Ns -style
-include statement.
-The
-.Fl m
-option can be used multiple times to form a search path.
-This path will override the default system include path: /usr/share/mk.
-Furthermore the system include path will be appended to the search path used
-for
-.Qo Ar file Qc Ns -style
-include statements (see the
-.Fl I
-option).
-.Pp
-If a file or directory name in the
-.Fl m
-argument (or the
-.Ev MAKESYSPATH
-environment variable) starts with the string
-.Qq \&.../
-then
-.Nm
-will search for the specified file or directory named in the remaining part
-of the argument string.
-The search starts with the current directory of
-the Makefile and then works upward towards the root of the file system.
-If the search is successful, then the resulting directory replaces the
-.Qq \&.../
-specification in the
-.Fl m
-argument.
-If used, this feature allows
-.Nm
-to easily search in the current source tree for customized sys.mk files
-(e.g., by using
-.Qq \&.../mk/sys.mk
-as an argument).
-.It Fl n
-Display the commands that would have been executed, but do not
-actually execute them unless the target depends on the .MAKE special
-source (see below).
-.It Fl N
-Display the commands which would have been executed, but do not
-actually execute any of them; useful for debugging top-level makefiles
-without descending into subdirectories.
-.It Fl q
-Do not execute any commands, but exit 0 if the specified targets are
-up-to-date and 1, otherwise.
-.It Fl r
-Do not use the built-in rules specified in the system makefile.
-.It Fl s
-Do not echo any commands as they are executed.
-Equivalent to specifying
-.Ql Ic @
-before each command line in the makefile.
-.It Fl T Ar tracefile
-When used with the
-.Fl j
-flag,
-append a trace record to
-.Ar tracefile
-for each job started and completed.
-.It Fl t
-Rather than re-building a target as specified in the makefile, create it
-or update its modification time to make it appear up-to-date.
-.It Fl V Ar variable
-Print the value of
-.Ar variable .
-Do not build any targets.
-Multiple instances of this option may be specified;
-the variables will be printed one per line,
-with a blank line for each null or undefined variable.
-The value printed is extracted from the global context after all
-makefiles have been read.
-By default, the raw variable contents (which may
-include additional unexpanded variable references) are shown.
-If
-.Ar variable
-contains a
-.Ql \&$
-then the value will be recursively expanded to its complete resultant
-text before printing.
-The expanded value will also be printed if
-.Va .MAKE.EXPAND_VARIABLES
-is set to true and
-the
-.Fl dV
-option has not been used to override it.
-Note that loop-local and target-local variables, as well as values
-taken temporarily by global variables during makefile processing, are
-not accessible via this option.
-The
-.Fl dv
-debug mode can be used to see these at the cost of generating
-substantial extraneous output.
-.It Fl v Ar variable
-Like
-.Fl V
-but the variable is always expanded to its complete value.
-.It Fl W
-Treat any warnings during makefile parsing as errors.
-.It Fl w
-Print entering and leaving directory messages, pre and post processing.
-.It Fl X
-Don't export variables passed on the command line to the environment
-individually.
-Variables passed on the command line are still exported
-via the
-.Va MAKEFLAGS
-environment variable.
-This option may be useful on systems which have a small limit on the
-size of command arguments.
-.It Ar variable=value
-Set the value of the variable
-.Ar variable
-to
-.Ar value .
-Normally, all values passed on the command line are also exported to
-sub-makes in the environment.
-The
-.Fl X
-flag disables this behavior.
-Variable assignments should follow options for POSIX compatibility
-but no ordering is enforced.
-.El
-.Pp
-There are seven different types of lines in a makefile: file dependency
-specifications, shell commands, variable assignments, include statements,
-conditional directives, for loops, and comments.
-.Pp
-In general, lines may be continued from one line to the next by ending
-them with a backslash
-.Pq Ql \e .
-The trailing newline character and initial whitespace on the following
-line are compressed into a single space.
-.Sh FILE DEPENDENCY SPECIFICATIONS
-Dependency lines consist of one or more targets, an operator, and zero
-or more sources.
-This creates a relationship where the targets
-.Dq depend
-on the sources
-and are usually created from them.
-The exact relationship between the target and the source is determined
-by the operator that separates them.
-The three operators are as follows:
-.Bl -tag -width flag
-.It Ic \&:
-A target is considered out-of-date if its modification time is less than
-those of any of its sources.
-Sources for a target accumulate over dependency lines when this operator
-is used.
-The target is removed if
-.Nm
-is interrupted.
-.It Ic \&!
-Targets are always re-created, but not until all sources have been
-examined and re-created as necessary.
-Sources for a target accumulate over dependency lines when this operator
-is used.
-The target is removed if
-.Nm
-is interrupted.
-.It Ic \&::
-If no sources are specified, the target is always re-created.
-Otherwise, a target is considered out-of-date if any of its sources has
-been modified more recently than the target.
-Sources for a target do not accumulate over dependency lines when this
-operator is used.
-The target will not be removed if
-.Nm
-is interrupted.
-.El
-.Pp
-Targets and sources may contain the shell wildcard values
-.Ql \&? ,
-.Ql * ,
-.Ql [] ,
-and
-.Ql {} .
-The values
-.Ql \&? ,
-.Ql * ,
-and
-.Ql []
-may only be used as part of the final
-component of the target or source, and must be used to describe existing
-files.
-The value
-.Ql {}
-need not necessarily be used to describe existing files.
-Expansion is in directory order, not alphabetically as done in the shell.
-.Sh SHELL COMMANDS
-Each target may have associated with it one or more lines of shell
-commands, normally
-used to create the target.
-Each of the lines in this script
-.Em must
-be preceded by a tab.
-(For historical reasons, spaces are not accepted.)
-While targets can appear in many dependency lines if desired, by
-default only one of these rules may be followed by a creation
-script.
-If the
-.Ql Ic \&::
-operator is used, however, all rules may include scripts and the
-scripts are executed in the order found.
-.Pp
-Each line is treated as a separate shell command, unless the end of
-line is escaped with a backslash
-.Pq Ql \e
-in which case that line and the next are combined.
-.\" The escaped newline is retained and passed to the shell, which
-.\" normally ignores it.
-.\" However, the tab at the beginning of the following line is removed.
-If the first characters of the command are any combination of
-.Ql Ic @ ,
-.Ql Ic + ,
-or
-.Ql Ic \- ,
-the command is treated specially.
-A
-.Ql Ic @
-causes the command not to be echoed before it is executed.
-A
-.Ql Ic +
-causes the command to be executed even when
-.Fl n
-is given.
-This is similar to the effect of the .MAKE special source,
-except that the effect can be limited to a single line of a script.
-A
-.Ql Ic \-
-in compatibility mode
-causes any non-zero exit status of the command line to be ignored.
-.Pp
-When
-.Nm
-is run in jobs mode with
-.Fl j Ar max_jobs ,
-the entire script for the target is fed to a
-single instance of the shell.
-In compatibility (non-jobs) mode, each command is run in a separate process.
-If the command contains any shell meta characters
-.Pq Ql #=|^(){};&<>*?[]:$`\e\en
-it will be passed to the shell; otherwise
-.Nm
-will attempt direct execution.
-If a line starts with
-.Ql Ic \-
-and the shell has ErrCtl enabled then failure of the command line
-will be ignored as in compatibility mode.
-Otherwise
-.Ql Ic \-
-affects the entire job;
-the script will stop at the first command line that fails,
-but the target will not be deemed to have failed.
-.Pp
-Makefiles should be written so that the mode of
-.Nm
-operation does not change their behavior.
-For example, any command which needs to use
-.Dq cd
-or
-.Dq chdir
-without potentially changing the directory for subsequent commands
-should be put in parentheses so it executes in a subshell.
-To force the use of one shell, escape the line breaks so as to make
-the whole script one command.
-For example:
-.Bd -literal -offset indent
-avoid-chdir-side-effects:
- @echo Building $@ in `pwd`
- @(cd ${.CURDIR} && ${MAKE} $@)
- @echo Back in `pwd`
-
-ensure-one-shell-regardless-of-mode:
- @echo Building $@ in `pwd`; \e
- (cd ${.CURDIR} && ${MAKE} $@); \e
- echo Back in `pwd`
-.Ed
-.Pp
-Since
-.Nm
-will
-.Xr chdir 2
-to
-.Ql Va .OBJDIR
-before executing any targets, each child process
-starts with that as its current working directory.
-.Sh VARIABLE ASSIGNMENTS
-Variables in make are much like variables in the shell, and, by tradition,
-consist of all upper-case letters.
-.Ss Variable assignment modifiers
-The five operators that can be used to assign values to variables are as
-follows:
-.Bl -tag -width Ds
-.It Ic \&=
-Assign the value to the variable.
-Any previous value is overridden.
-.It Ic \&+=
-Append the value to the current value of the variable.
-.It Ic \&?=
-Assign the value to the variable if it is not already defined.
-.It Ic \&:=
-Assign with expansion, i.e. expand the value before assigning it
-to the variable.
-Normally, expansion is not done until the variable is referenced.
-.Em NOTE :
-References to undefined variables are
-.Em not
-expanded.
-This can cause problems when variable modifiers are used.
-.It Ic \&!=
-Expand the value and pass it to the shell for execution and assign
-the result to the variable.
-Any newlines in the result are replaced with spaces.
-.El
-.Pp
-Any white-space before the assigned
-.Ar value
-is removed; if the value is being appended, a single space is inserted
-between the previous contents of the variable and the appended value.
-.Pp
-Variables are expanded by surrounding the variable name with either
-curly braces
-.Pq Ql {}
-or parentheses
-.Pq Ql ()
-and preceding it with
-a dollar sign
-.Pq Ql \&$ .
-If the variable name contains only a single letter, the surrounding
-braces or parentheses are not required.
-This shorter form is not recommended.
-.Pp
-If the variable name contains a dollar, then the name itself is expanded first.
-This allows almost arbitrary variable names, however names containing dollar,
-braces, parenthesis, or whitespace are really best avoided!
-.Pp
-If the result of expanding a variable contains a dollar sign
-.Pq Ql \&$
-the string is expanded again.
-.Pp
-Variable substitution occurs at three distinct times, depending on where
-the variable is being used.
-.Bl -enum
-.It
-Variables in dependency lines are expanded as the line is read.
-.It
-Variables in shell commands are expanded when the shell command is
-executed.
-.It
-.Dq .for
-loop index variables are expanded on each loop iteration.
-Note that other variables are not expanded inside loops so
-the following example code:
-.Bd -literal -offset indent
-
-.Dv .for i in 1 2 3
-a+= ${i}
-j= ${i}
-b+= ${j}
-.Dv .endfor
-
-all:
- @echo ${a}
- @echo ${b}
-
-.Ed
-will print:
-.Bd -literal -offset indent
-1 2 3
-3 3 3
-
-.Ed
-Because while ${a} contains
-.Dq 1 2 3
-after the loop is executed, ${b}
-contains
-.Dq ${j} ${j} ${j}
-which expands to
-.Dq 3 3 3
-since after the loop completes ${j} contains
-.Dq 3 .
-.El
-.Ss Variable classes
-The four different classes of variables (in order of increasing precedence)
-are:
-.Bl -tag -width Ds
-.It Environment variables
-Variables defined as part of
-.Nm Ns 's
-environment.
-.It Global variables
-Variables defined in the makefile or in included makefiles.
-.It Command line variables
-Variables defined as part of the command line.
-.It Local variables
-Variables that are defined specific to a certain target.
-.El
-.Pp
-Local variables are all built in and their values vary magically from
-target to target.
-It is not currently possible to define new local variables.
-The seven local variables are as follows:
-.Bl -tag -width ".ARCHIVE" -offset indent
-.It Va .ALLSRC
-The list of all sources for this target; also known as
-.Ql Va \&> .
-.It Va .ARCHIVE
-The name of the archive file; also known as
-.Ql Va \&! .
-.It Va .IMPSRC
-In suffix-transformation rules, the name/path of the source from which the
-target is to be transformed (the
-.Dq implied
-source); also known as
-.Ql Va \&< .
-It is not defined in explicit rules.
-.It Va .MEMBER
-The name of the archive member; also known as
-.Ql Va % .
-.It Va .OODATE
-The list of sources for this target that were deemed out-of-date; also
-known as
-.Ql Va \&? .
-.It Va .PREFIX
-The file prefix of the target, containing only the file portion, no suffix
-or preceding directory components; also known as
-.Ql Va * .
-The suffix must be one of the known suffixes declared with
-.Ic .SUFFIXES
-or it will not be recognized.
-.It Va .TARGET
-The name of the target; also known as
-.Ql Va @ .
-For compatibility with other makes this is an alias for
-.Ic .ARCHIVE
-in archive member rules.
-.El
-.Pp
-The shorter forms
-.Ql ( Va > ,
-.Ql Va \&! ,
-.Ql Va < ,
-.Ql Va % ,
-.Ql Va \&? ,
-.Ql Va * ,
-and
-.Ql Va @ )
-are permitted for backward
-compatibility with historical makefiles and legacy POSIX make and are
-not recommended.
-.Pp
-Variants of these variables with the punctuation followed immediately by
-.Ql D
-or
-.Ql F ,
-e.g.
-.Ql Va $(@D) ,
-are legacy forms equivalent to using the
-.Ql :H
-and
-.Ql :T
-modifiers.
-These forms are accepted for compatibility with
-.At V
-makefiles and POSIX but are not recommended.
-.Pp
-Four of the local variables may be used in sources on dependency lines
-because they expand to the proper value for each target on the line.
-These variables are
-.Ql Va .TARGET ,
-.Ql Va .PREFIX ,
-.Ql Va .ARCHIVE ,
-and
-.Ql Va .MEMBER .
-.Ss Additional built-in variables
-In addition,
-.Nm
-sets or knows about the following variables:
-.Bl -tag -width .MAKEOVERRIDES
-.It Va \&$
-A single dollar sign
-.Ql \&$ ,
-i.e.
-.Ql \&$$
-expands to a single dollar
-sign.
-.It Va .ALLTARGETS
-The list of all targets encountered in the Makefile.
-If evaluated during
-Makefile parsing, lists only those targets encountered thus far.
-.It Va .CURDIR
-A path to the directory where
-.Nm
-was executed.
-Refer to the description of
-.Ql Ev PWD
-for more details.
-.It Va .INCLUDEDFROMDIR
-The directory of the file this Makefile was included from.
-.It Va .INCLUDEDFROMFILE
-The filename of the file this Makefile was included from.
-.It Ev MAKE
-The name that
-.Nm
-was executed with
-.Pq Va argv[0] .
-For compatibility
-.Nm
-also sets
-.Va .MAKE
-with the same value.
-The preferred variable to use is the environment variable
-.Ev MAKE
-because it is more compatible with other versions of
-.Nm
-and cannot be confused with the special target with the same name.
-.It Va .MAKE.DEPENDFILE
-Names the makefile (default
-.Ql Pa .depend )
-from which generated dependencies are read.
-.It Va .MAKE.EXPAND_VARIABLES
-A boolean that controls the default behavior of the
-.Fl V
-option.
-If true, variable values printed with
-.Fl V
-are fully expanded; if false, the raw variable contents (which may
-include additional unexpanded variable references) are shown.
-.It Va .MAKE.EXPORTED
-The list of variables exported by
-.Nm .
-.It Va .MAKE.JOBS
-The argument to the
-.Fl j
-option.
-.It Va .MAKE.JOB.PREFIX
-If
-.Nm
-is run with
-.Ar j
-then output for each target is prefixed with a token
-.Ql --- target ---
-the first part of which can be controlled via
-.Va .MAKE.JOB.PREFIX .
-If
-.Va .MAKE.JOB.PREFIX
-is empty, no token is printed.
-.br
-For example:
-.Li .MAKE.JOB.PREFIX=${.newline}---${.MAKE:T}[${.MAKE.PID}]
-would produce tokens like
-.Ql ---make[1234] target ---
-making it easier to track the degree of parallelism being achieved.
-.It Ev MAKEFLAGS
-The environment variable
-.Ql Ev MAKEFLAGS
-may contain anything that
-may be specified on
-.Nm Ns 's
-command line.
-Anything specified on
-.Nm Ns 's
-command line is appended to the
-.Ql Ev MAKEFLAGS
-variable which is then
-entered into the environment for all programs which
-.Nm
-executes.
-.It Va .MAKE.LEVEL
-The recursion depth of
-.Nm .
-The initial instance of
-.Nm
-will be 0, and an incremented value is put into the environment
-to be seen by the next generation.
-This allows tests like:
-.Li .if ${.MAKE.LEVEL} == 0
-to protect things which should only be evaluated in the initial instance of
-.Nm .
-.It Va .MAKE.MAKEFILE_PREFERENCE
-The ordered list of makefile names
-(default
-.Ql Pa makefile ,
-.Ql Pa Makefile )
-that
-.Nm
-will look for.
-.It Va .MAKE.MAKEFILES
-The list of makefiles read by
-.Nm ,
-which is useful for tracking dependencies.
-Each makefile is recorded only once, regardless of the number of times read.
-.It Va .MAKE.MODE
-Processed after reading all makefiles.
-Can affect the mode that
-.Nm
-runs in.
-It can contain a number of keywords:
-.Bl -hang -width missing-filemon=bf.
-.It Pa compat
-Like
-.Fl B ,
-puts
-.Nm
-into "compat" mode.
-.It Pa meta
-Puts
-.Nm
-into "meta" mode, where meta files are created for each target
-to capture the command run, the output generated and if
-.Xr filemon 4
-is available, the system calls which are of interest to
-.Nm .
-The captured output can be very useful when diagnosing errors.
-.It Pa curdirOk= Ar bf
-Normally
-.Nm
-will not create .meta files in
-.Ql Va .CURDIR .
-This can be overridden by setting
-.Va bf
-to a value which represents True.
-.It Pa missing-meta= Ar bf
-If
-.Va bf
-is True, then a missing .meta file makes the target out-of-date.
-.It Pa missing-filemon= Ar bf
-If
-.Va bf
-is True, then missing filemon data makes the target out-of-date.
-.It Pa nofilemon
-Do not use
-.Xr filemon 4 .
-.It Pa env
-For debugging, it can be useful to include the environment
-in the .meta file.
-.It Pa verbose
-If in "meta" mode, print a clue about the target being built.
-This is useful if the build is otherwise running silently.
-The message printed the value of:
-.Va .MAKE.META.PREFIX .
-.It Pa ignore-cmd
-Some makefiles have commands which are simply not stable.
-This keyword causes them to be ignored for
-determining whether a target is out of date in "meta" mode.
-See also
-.Ic .NOMETA_CMP .
-.It Pa silent= Ar bf
-If
-.Va bf
-is True, when a .meta file is created, mark the target
-.Ic .SILENT .
-.El
-.It Va .MAKE.META.BAILIWICK
-In "meta" mode, provides a list of prefixes which
-match the directories controlled by
-.Nm .
-If a file that was generated outside of
-.Va .OBJDIR
-but within said bailiwick is missing,
-the current target is considered out-of-date.
-.It Va .MAKE.META.CREATED
-In "meta" mode, this variable contains a list of all the meta files
-updated.
-If not empty, it can be used to trigger processing of
-.Va .MAKE.META.FILES .
-.It Va .MAKE.META.FILES
-In "meta" mode, this variable contains a list of all the meta files
-used (updated or not).
-This list can be used to process the meta files to extract dependency
-information.
-.It Va .MAKE.META.IGNORE_PATHS
-Provides a list of path prefixes that should be ignored;
-because the contents are expected to change over time.
-The default list includes:
-.Ql Pa /dev /etc /proc /tmp /var/run /var/tmp
-.It Va .MAKE.META.IGNORE_PATTERNS
-Provides a list of patterns to match against pathnames.
-Ignore any that match.
-.It Va .MAKE.META.IGNORE_FILTER
-Provides a list of variable modifiers to apply to each pathname.
-Ignore if the expansion is an empty string.
-.It Va .MAKE.META.PREFIX
-Defines the message printed for each meta file updated in "meta verbose" mode.
-The default value is:
-.Dl Building ${.TARGET:H:tA}/${.TARGET:T}
-.It Va .MAKEOVERRIDES
-This variable is used to record the names of variables assigned to
-on the command line, so that they may be exported as part of
-.Ql Ev MAKEFLAGS .
-This behavior can be disabled by assigning an empty value to
-.Ql Va .MAKEOVERRIDES
-within a makefile.
-Extra variables can be exported from a makefile
-by appending their names to
-.Ql Va .MAKEOVERRIDES .
-.Ql Ev MAKEFLAGS
-is re-exported whenever
-.Ql Va .MAKEOVERRIDES
-is modified.
-.It Va .MAKE.PATH_FILEMON
-If
-.Nm
-was built with
-.Xr filemon 4
-support, this is set to the path of the device node.
-This allows makefiles to test for this support.
-.It Va .MAKE.PID
-The process-id of
-.Nm .
-.It Va .MAKE.PPID
-The parent process-id of
-.Nm .
-.It Va .MAKE.SAVE_DOLLARS
-value should be a boolean that controls whether
-.Ql $$
-are preserved when doing
-.Ql :=
-assignments.
-The default is true, for compatibility with other makes.
-If set to false,
-.Ql $$
-becomes
-.Ql $
-per normal evaluation rules.
-.It Va MAKE_PRINT_VAR_ON_ERROR
-When
-.Nm
-stops due to an error, it sets
-.Ql Va .ERROR_TARGET
-to the name of the target that failed,
-.Ql Va .ERROR_CMD
-to the commands of the failed target,
-and in "meta" mode, it also sets
-.Ql Va .ERROR_CWD
-to the
-.Xr getcwd 3 ,
-and
-.Ql Va .ERROR_META_FILE
-to the path of the meta file (if any) describing the failed target.
-It then prints its name and the value of
-.Ql Va .CURDIR
-as well as the value of any variables named in
-.Ql Va MAKE_PRINT_VAR_ON_ERROR .
-.It Va .newline
-This variable is simply assigned a newline character as its value.
-This allows expansions using the
-.Cm \&:@
-modifier to put a newline between
-iterations of the loop rather than a space.
-For example, the printing of
-.Ql Va MAKE_PRINT_VAR_ON_ERROR
-could be done as ${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'${.newline}@}.
-.It Va .OBJDIR
-A path to the directory where the targets are built.
-Its value is determined by trying to
-.Xr chdir 2
-to the following directories in order and using the first match:
-.Bl -enum
-.It
-.Ev ${MAKEOBJDIRPREFIX}${.CURDIR}
-.Pp
-(Only if
-.Ql Ev MAKEOBJDIRPREFIX
-is set in the environment or on the command line.)
-.It
-.Ev ${MAKEOBJDIR}
-.Pp
-(Only if
-.Ql Ev MAKEOBJDIR
-is set in the environment or on the command line.)
-.It
-.Ev ${.CURDIR} Ns Pa /obj. Ns Ev ${MACHINE}
-.It
-.Ev ${.CURDIR} Ns Pa /obj
-.It
-.Pa /usr/obj/ Ns Ev ${.CURDIR}
-.It
-.Ev ${.CURDIR}
-.El
-.Pp
-Variable expansion is performed on the value before it's used,
-so expressions such as
-.Dl ${.CURDIR:S,^/usr/src,/var/obj,}
-may be used.
-This is especially useful with
-.Ql Ev MAKEOBJDIR .
-.Pp
-.Ql Va .OBJDIR
-may be modified in the makefile via the special target
-.Ql Ic .OBJDIR .
-In all cases,
-.Nm
-will
-.Xr chdir 2
-to the specified directory if it exists, and set
-.Ql Va .OBJDIR
-and
-.Ql Ev PWD
-to that directory before executing any targets.
-.
-.It Va .PARSEDIR
-A path to the directory of the current
-.Ql Pa Makefile
-being parsed.
-.It Va .PARSEFILE
-The basename of the current
-.Ql Pa Makefile
-being parsed.
-This variable and
-.Ql Va .PARSEDIR
-are both set only while the
-.Ql Pa Makefiles
-are being parsed.
-If you want to retain their current values, assign them to a variable
-using assignment with expansion:
-.Pq Ql Cm \&:= .
-.It Va .PATH
-A variable that represents the list of directories that
-.Nm
-will search for files.
-The search list should be updated using the target
-.Ql Va .PATH
-rather than the variable.
-.It Ev PWD
-Alternate path to the current directory.
-.Nm
-normally sets
-.Ql Va .CURDIR
-to the canonical path given by
-.Xr getcwd 3 .
-However, if the environment variable
-.Ql Ev PWD
-is set and gives a path to the current directory, then
-.Nm
-sets
-.Ql Va .CURDIR
-to the value of
-.Ql Ev PWD
-instead.
-This behavior is disabled if
-.Ql Ev MAKEOBJDIRPREFIX
-is set or
-.Ql Ev MAKEOBJDIR
-contains a variable transform.
-.Ql Ev PWD
-is set to the value of
-.Ql Va .OBJDIR
-for all programs which
-.Nm
-executes.
-.It Ev .TARGETS
-The list of targets explicitly specified on the command line, if any.
-.It Ev VPATH
-Colon-separated
-.Pq Dq \&:
-lists of directories that
-.Nm
-will search for files.
-The variable is supported for compatibility with old make programs only,
-use
-.Ql Va .PATH
-instead.
-.El
-.Ss Variable modifiers
-Variable expansion may be modified to select or modify each word of the
-variable (where a
-.Dq word
-is white-space delimited sequence of characters).
-The general format of a variable expansion is as follows:
-.Pp
-.Dl ${variable[:modifier[:...]]}
-.Pp
-Each modifier begins with a colon,
-which may be escaped with a backslash
-.Pq Ql \e .
-.Pp
-A set of modifiers can be specified via a variable, as follows:
-.Pp
-.Dl modifier_variable=modifier[:...]
-.Dl ${variable:${modifier_variable}[:...]}
-.Pp
-In this case the first modifier in the modifier_variable does not
-start with a colon, since that must appear in the referencing
-variable.
-If any of the modifiers in the modifier_variable contain a dollar sign
-.Pq Ql $ ,
-these must be doubled to avoid early expansion.
-.Pp
-The supported modifiers are:
-.Bl -tag -width EEE
-.It Cm \&:E
-Replaces each word in the variable with its suffix.
-.It Cm \&:H
-Replaces each word in the variable with everything but the last component.
-.It Cm \&:M Ns Ar pattern
-Select only those words that match
-.Ar pattern .
-The standard shell wildcard characters
-.Pf ( Ql * ,
-.Ql \&? ,
-and
-.Ql Oo Oc )
-may
-be used.
-The wildcard characters may be escaped with a backslash
-.Pq Ql \e .
-As a consequence of the way values are split into words, matched,
-and then joined, a construct like
-.Dl ${VAR:M*}
-will normalize the inter-word spacing, removing all leading and
-trailing space, and converting multiple consecutive spaces
-to single spaces.
-.
-.It Cm \&:N Ns Ar pattern
-This is identical to
-.Ql Cm \&:M ,
-but selects all words which do not match
-.Ar pattern .
-.It Cm \&:O
-Order every word in variable alphabetically.
-To sort words in
-reverse order use the
-.Ql Cm \&:O:[-1..1]
-combination of modifiers.
-.It Cm \&:Ox
-Randomize words in variable.
-The results will be different each time you are referring to the
-modified variable; use the assignment with expansion
-.Pq Ql Cm \&:=
-to prevent such behavior.
-For example,
-.Bd -literal -offset indent
-LIST= uno due tre quattro
-RANDOM_LIST= ${LIST:Ox}
-STATIC_RANDOM_LIST:= ${LIST:Ox}
-
-all:
- @echo "${RANDOM_LIST}"
- @echo "${RANDOM_LIST}"
- @echo "${STATIC_RANDOM_LIST}"
- @echo "${STATIC_RANDOM_LIST}"
-.Ed
-may produce output similar to:
-.Bd -literal -offset indent
-quattro due tre uno
-tre due quattro uno
-due uno quattro tre
-due uno quattro tre
-.Ed
-.It Cm \&:Q
-Quotes every shell meta-character in the variable, so that it can be passed
-safely to the shell.
-.It Cm \&:q
-Quotes every shell meta-character in the variable, and also doubles
-.Sq $
-characters so that it can be passed
-safely through recursive invocations of
-.Nm .
-This is equivalent to:
-.Sq \&:S/\e\&$/&&/g:Q .
-.It Cm \&:R
-Replaces each word in the variable with everything but its suffix.
-.It Cm \&:range[=count]
-The value is an integer sequence representing the words of the original
-value, or the supplied
-.Va count .
-.It Cm \&:gmtime[=utc]
-The value is a format string for
-.Xr strftime 3 ,
-using
-.Xr gmtime 3 .
-If a
-.Va utc
-value is not provided or is 0, the current time is used.
-.It Cm \&:hash
-Compute a 32-bit hash of the value and encode it as hex digits.
-.It Cm \&:localtime[=utc]
-The value is a format string for
-.Xr strftime 3 ,
-using
-.Xr localtime 3 .
-If a
-.Va utc
-value is not provided or is 0, the current time is used.
-.It Cm \&:tA
-Attempt to convert variable to an absolute path using
-.Xr realpath 3 ,
-if that fails, the value is unchanged.
-.It Cm \&:tl
-Converts variable to lower-case letters.
-.It Cm \&:ts Ns Ar c
-Words in the variable are normally separated by a space on expansion.
-This modifier sets the separator to the character
-.Ar c .
-If
-.Ar c
-is omitted, then no separator is used.
-The common escapes (including octal numeric codes), work as expected.
-.It Cm \&:tu
-Converts variable to upper-case letters.
-.It Cm \&:tW
-Causes the value to be treated as a single word
-(possibly containing embedded white space).
-See also
-.Ql Cm \&:[*] .
-.It Cm \&:tw
-Causes the value to be treated as a sequence of
-words delimited by white space.
-See also
-.Ql Cm \&:[@] .
-.Sm off
-.It Cm \&:S No \&/ Ar old_string No \&/ Ar new_string No \&/ Op Cm 1gW
-.Sm on
-Modify the first occurrence of
-.Ar old_string
-in the variable's value, replacing it with
-.Ar new_string .
-If a
-.Ql g
-is appended to the last slash of the pattern, all occurrences
-in each word are replaced.
-If a
-.Ql 1
-is appended to the last slash of the pattern, only the first word
-is affected.
-If a
-.Ql W
-is appended to the last slash of the pattern,
-then the value is treated as a single word
-(possibly containing embedded white space).
-If
-.Ar old_string
-begins with a caret
-.Pq Ql ^ ,
-.Ar old_string
-is anchored at the beginning of each word.
-If
-.Ar old_string
-ends with a dollar sign
-.Pq Ql \&$ ,
-it is anchored at the end of each word.
-Inside
-.Ar new_string ,
-an ampersand
-.Pq Ql &
-is replaced by
-.Ar old_string
-(without any
-.Ql ^
-or
-.Ql \&$ ) .
-Any character may be used as a delimiter for the parts of the modifier
-string.
-The anchoring, ampersand and delimiter characters may be escaped with a
-backslash
-.Pq Ql \e .
-.Pp
-Variable expansion occurs in the normal fashion inside both
-.Ar old_string
-and
-.Ar new_string
-with the single exception that a backslash is used to prevent the expansion
-of a dollar sign
-.Pq Ql \&$ ,
-not a preceding dollar sign as is usual.
-.Sm off
-.It Cm \&:C No \&/ Ar pattern No \&/ Ar replacement No \&/ Op Cm 1gW
-.Sm on
-The
-.Cm \&:C
-modifier is just like the
-.Cm \&:S
-modifier except that the old and new strings, instead of being
-simple strings, are an extended regular expression (see
-.Xr regex 3 )
-string
-.Ar pattern
-and an
-.Xr ed 1 Ns \-style
-string
-.Ar replacement .
-Normally, the first occurrence of the pattern
-.Ar pattern
-in each word of the value is substituted with
-.Ar replacement .
-The
-.Ql 1
-modifier causes the substitution to apply to at most one word; the
-.Ql g
-modifier causes the substitution to apply to as many instances of the
-search pattern
-.Ar pattern
-as occur in the word or words it is found in; the
-.Ql W
-modifier causes the value to be treated as a single word
-(possibly containing embedded white space).
-Note that
-.Ql 1
-and
-.Ql g
-are orthogonal; the former specifies whether multiple words are
-potentially affected, the latter whether multiple substitutions can
-potentially occur within each affected word.
-.Pp
-As for the
-.Cm \&:S
-modifier, the
-.Ar pattern
-and
-.Ar replacement
-are subjected to variable expansion before being parsed as
-regular expressions.
-.It Cm \&:T
-Replaces each word in the variable with its last component.
-.It Cm \&:u
-Remove adjacent duplicate words (like
-.Xr uniq 1 ) .
-.Sm off
-.It Cm \&:\&? Ar true_string Cm \&: Ar false_string
-.Sm on
-If the variable name (not its value), when parsed as a .if conditional
-expression, evaluates to true, return as its value the
-.Ar true_string ,
-otherwise return the
-.Ar false_string .
-Since the variable name is used as the expression, \&:\&? must be the
-first modifier after the variable name itself - which will, of course,
-usually contain variable expansions.
-A common error is trying to use expressions like
-.Dl ${NUMBERS:M42:?match:no}
-which actually tests defined(NUMBERS),
-to determine is any words match "42" you need to use something like:
-.Dl ${"${NUMBERS:M42}" != \&"\&":?match:no} .
-.It Ar :old_string=new_string
-This is the
-.At V
-style variable substitution.
-It must be the last modifier specified.
-If
-.Ar old_string
-or
-.Ar new_string
-do not contain the pattern matching character
-.Ar %
-then it is assumed that they are
-anchored at the end of each word, so only suffixes or entire
-words may be replaced.
-Otherwise
-.Ar %
-is the substring of
-.Ar old_string
-to be replaced in
-.Ar new_string .
-.Pp
-Variable expansion occurs in the normal fashion inside both
-.Ar old_string
-and
-.Ar new_string
-with the single exception that a backslash is used to prevent the
-expansion of a dollar sign
-.Pq Ql \&$ ,
-not a preceding dollar sign as is usual.
-.Sm off
-.It Cm \&:@ Ar temp Cm @ Ar string Cm @
-.Sm on
-This is the loop expansion mechanism from the OSF Development
-Environment (ODE) make.
-Unlike
-.Cm \&.for
-loops expansion occurs at the time of
-reference.
-Assign
-.Ar temp
-to each word in the variable and evaluate
-.Ar string .
-The ODE convention is that
-.Ar temp
-should start and end with a period.
-For example.
-.Dl ${LINKS:@.LINK.@${LN} ${TARGET} ${.LINK.}@}
-.Pp
-However a single character variable is often more readable:
-.Dl ${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'${.newline}@}
-.It Cm \&:_[=var]
-Save the current variable value in
-.Ql $_
-or the named
-.Va var
-for later reference.
-Example usage:
-.Bd -literal -offset indent
-M_cmpv.units = 1 1000 1000000
-M_cmpv = S,., ,g:_:range:@i@+ $${_:[-$$i]} \&\\
-\\* $${M_cmpv.units:[$$i]}@:S,^,expr 0 ,1:sh
-
-.Dv .if ${VERSION:${M_cmpv}} < ${3.1.12:L:${M_cmpv}}
-
-.Ed
-Here
-.Ql $_
-is used to save the result of the
-.Ql :S
-modifier which is later referenced using the index values from
-.Ql :range .
-.It Cm \&:U Ns Ar newval
-If the variable is undefined
-.Ar newval
-is the value.
-If the variable is defined, the existing value is returned.
-This is another ODE make feature.
-It is handy for setting per-target CFLAGS for instance:
-.Dl ${_${.TARGET:T}_CFLAGS:U${DEF_CFLAGS}}
-If a value is only required if the variable is undefined, use:
-.Dl ${VAR:D:Unewval}
-.It Cm \&:D Ns Ar newval
-If the variable is defined
-.Ar newval
-is the value.
-.It Cm \&:L
-The name of the variable is the value.
-.It Cm \&:P
-The path of the node which has the same name as the variable
-is the value.
-If no such node exists or its path is null, then the
-name of the variable is used.
-In order for this modifier to work, the name (node) must at least have
-appeared on the rhs of a dependency.
-.Sm off
-.It Cm \&:\&! Ar cmd Cm \&!
-.Sm on
-The output of running
-.Ar cmd
-is the value.
-.It Cm \&:sh
-If the variable is non-empty it is run as a command and the output
-becomes the new value.
-.It Cm \&::= Ns Ar str
-The variable is assigned the value
-.Ar str
-after substitution.
-This modifier and its variations are useful in
-obscure situations such as wanting to set a variable when shell commands
-are being parsed.
-These assignment modifiers always expand to
-nothing, so if appearing in a rule line by themselves should be
-preceded with something to keep
-.Nm
-happy.
-.Pp
-The
-.Ql Cm \&::
-helps avoid false matches with the
-.At V
-style
-.Cm \&:=
-modifier and since substitution always occurs the
-.Cm \&::=
-form is vaguely appropriate.
-.It Cm \&::?= Ns Ar str
-As for
-.Cm \&::=
-but only if the variable does not already have a value.
-.It Cm \&::+= Ns Ar str
-Append
-.Ar str
-to the variable.
-.It Cm \&::!= Ns Ar cmd
-Assign the output of
-.Ar cmd
-to the variable.
-.It Cm \&:\&[ Ns Ar range Ns Cm \&]
-Selects one or more words from the value,
-or performs other operations related to the way in which the
-value is divided into words.
-.Pp
-Ordinarily, a value is treated as a sequence of words
-delimited by white space.
-Some modifiers suppress this behavior,
-causing a value to be treated as a single word
-(possibly containing embedded white space).
-An empty value, or a value that consists entirely of white-space,
-is treated as a single word.
-For the purposes of the
-.Ql Cm \&:[]
-modifier, the words are indexed both forwards using positive integers
-(where index 1 represents the first word),
-and backwards using negative integers
-(where index \-1 represents the last word).
-.Pp
-The
-.Ar range
-is subjected to variable expansion, and the expanded result is
-then interpreted as follows:
-.Bl -tag -width index
-.\" :[n]
-.It Ar index
-Selects a single word from the value.
-.\" :[start..end]
-.It Ar start Ns Cm \&.. Ns Ar end
-Selects all words from
-.Ar start
-to
-.Ar end ,
-inclusive.
-For example,
-.Ql Cm \&:[2..-1]
-selects all words from the second word to the last word.
-If
-.Ar start
-is greater than
-.Ar end ,
-then the words are output in reverse order.
-For example,
-.Ql Cm \&:[-1..1]
-selects all the words from last to first.
-.\" :[*]
-.It Cm \&*
-Causes subsequent modifiers to treat the value as a single word
-(possibly containing embedded white space).
-Analogous to the effect of
-\&"$*\&"
-in Bourne shell.
-.\" :[0]
-.It 0
-Means the same as
-.Ql Cm \&:[*] .
-.\" :[*]
-.It Cm \&@
-Causes subsequent modifiers to treat the value as a sequence of words
-delimited by white space.
-Analogous to the effect of
-\&"$@\&"
-in Bourne shell.
-.\" :[#]
-.It Cm \&#
-Returns the number of words in the value.
-.El \" :[range]
-.El
-.Sh INCLUDE STATEMENTS, CONDITIONALS AND FOR LOOPS
-Makefile inclusion, conditional structures and for loops reminiscent
-of the C programming language are provided in
-.Nm .
-All such structures are identified by a line beginning with a single
-dot
-.Pq Ql \&.
-character.
-Files are included with either
-.Cm \&.include Aq Ar file
-or
-.Cm \&.include Pf \*q Ar file Ns \*q .
-Variables between the angle brackets or double quotes are expanded
-to form the file name.
-If angle brackets are used, the included makefile is expected to be in
-the system makefile directory.
-If double quotes are used, the including makefile's directory and any
-directories specified using the
-.Fl I
-option are searched before the system
-makefile directory.
-For compatibility with other versions of
-.Nm
-.Ql include file ...
-is also accepted.
-.Pp
-If the include statement is written as
-.Cm .-include
-or as
-.Cm .sinclude
-then errors locating and/or opening include files are ignored.
-.Pp
-If the include statement is written as
-.Cm .dinclude
-not only are errors locating and/or opening include files ignored,
-but stale dependencies within the included file will be ignored
-just like
-.Va .MAKE.DEPENDFILE .
-.Pp
-Conditional expressions are also preceded by a single dot as the first
-character of a line.
-The possible conditionals are as follows:
-.Bl -tag -width Ds
-.It Ic .error Ar message
-The message is printed along with the name of the makefile and line number,
-then
-.Nm
-will exit.
-.It Ic .export Ar variable ...
-Export the specified global variable.
-If no variable list is provided, all globals are exported
-except for internal variables (those that start with
-.Ql \&. ) .
-This is not affected by the
-.Fl X
-flag, so should be used with caution.
-For compatibility with other
-.Nm
-programs
-.Ql export variable=value
-is also accepted.
-.Pp
-Appending a variable name to
-.Va .MAKE.EXPORTED
-is equivalent to exporting a variable.
-.It Ic .export-env Ar variable ...
-The same as
-.Ql .export ,
-except that the variable is not appended to
-.Va .MAKE.EXPORTED .
-This allows exporting a value to the environment which is different from that
-used by
-.Nm
-internally.
-.It Ic .export-literal Ar variable ...
-The same as
-.Ql .export-env ,
-except that variables in the value are not expanded.
-.It Ic .info Ar message
-The message is printed along with the name of the makefile and line number.
-.It Ic .undef Ar variable
-Un-define the specified global variable.
-Only global variables may be un-defined.
-.It Ic .unexport Ar variable ...
-The opposite of
-.Ql .export .
-The specified global
-.Va variable
-will be removed from
-.Va .MAKE.EXPORTED .
-If no variable list is provided, all globals are unexported,
-and
-.Va .MAKE.EXPORTED
-deleted.
-.It Ic .unexport-env
-Unexport all globals previously exported and
-clear the environment inherited from the parent.
-This operation will cause a memory leak of the original environment,
-so should be used sparingly.
-Testing for
-.Va .MAKE.LEVEL
-being 0, would make sense.
-Also note that any variables which originated in the parent environment
-should be explicitly preserved if desired.
-For example:
-.Bd -literal -offset indent
-.Li .if ${.MAKE.LEVEL} == 0
-PATH := ${PATH}
-.Li .unexport-env
-.Li .export PATH
-.Li .endif
-.Pp
-.Ed
-Would result in an environment containing only
-.Ql Ev PATH ,
-which is the minimal useful environment.
-Actually
-.Ql Ev .MAKE.LEVEL
-will also be pushed into the new environment.
-.It Ic .warning Ar message
-The message prefixed by
-.Ql Pa warning:
-is printed along with the name of the makefile and line number.
-.It Ic \&.if Oo \&! Oc Ns Ar expression Op Ar operator expression ...
-Test the value of an expression.
-.It Ic .ifdef Oo \&! Oc Ns Ar variable Op Ar operator variable ...
-Test the value of a variable.
-.It Ic .ifndef Oo \&! Oc Ns Ar variable Op Ar operator variable ...
-Test the value of a variable.
-.It Ic .ifmake Oo \&! Oc Ns Ar target Op Ar operator target ...
-Test the target being built.
-.It Ic .ifnmake Oo \&! Ns Oc Ar target Op Ar operator target ...
-Test the target being built.
-.It Ic .else
-Reverse the sense of the last conditional.
-.It Ic .elif Oo \&! Ns Oc Ar expression Op Ar operator expression ...
-A combination of
-.Ql Ic .else
-followed by
-.Ql Ic .if .
-.It Ic .elifdef Oo \&! Oc Ns Ar variable Op Ar operator variable ...
-A combination of
-.Ql Ic .else
-followed by
-.Ql Ic .ifdef .
-.It Ic .elifndef Oo \&! Oc Ns Ar variable Op Ar operator variable ...
-A combination of
-.Ql Ic .else
-followed by
-.Ql Ic .ifndef .
-.It Ic .elifmake Oo \&! Oc Ns Ar target Op Ar operator target ...
-A combination of
-.Ql Ic .else
-followed by
-.Ql Ic .ifmake .
-.It Ic .elifnmake Oo \&! Oc Ns Ar target Op Ar operator target ...
-A combination of
-.Ql Ic .else
-followed by
-.Ql Ic .ifnmake .
-.It Ic .endif
-End the body of the conditional.
-.El
-.Pp
-The
-.Ar operator
-may be any one of the following:
-.Bl -tag -width "Cm XX"
-.It Cm \&|\&|
-Logical OR.
-.It Cm \&&&
-Logical
-.Tn AND ;
-of higher precedence than
-.Dq \&|\&| .
-.El
-.Pp
-As in C,
-.Nm
-will only evaluate a conditional as far as is necessary to determine
-its value.
-Parentheses may be used to change the order of evaluation.
-The boolean operator
-.Ql Ic \&!
-may be used to logically negate an entire
-conditional.
-It is of higher precedence than
-.Ql Ic \&&& .
-.Pp
-The value of
-.Ar expression
-may be any of the following:
-.Bl -tag -width defined
-.It Ic defined
-Takes a variable name as an argument and evaluates to true if the variable
-has been defined.
-.It Ic make
-Takes a target name as an argument and evaluates to true if the target
-was specified as part of
-.Nm Ns 's
-command line or was declared the default target (either implicitly or
-explicitly, see
-.Va .MAIN )
-before the line containing the conditional.
-.It Ic empty
-Takes a variable, with possible modifiers, and evaluates to true if
-the expansion of the variable would result in an empty string.
-.It Ic exists
-Takes a file name as an argument and evaluates to true if the file exists.
-The file is searched for on the system search path (see
-.Va .PATH ) .
-.It Ic target
-Takes a target name as an argument and evaluates to true if the target
-has been defined.
-.It Ic commands
-Takes a target name as an argument and evaluates to true if the target
-has been defined and has commands associated with it.
-.El
-.Pp
-.Ar Expression
-may also be an arithmetic or string comparison.
-Variable expansion is
-performed on both sides of the comparison, after which the integral
-values are compared.
-A value is interpreted as hexadecimal if it is
-preceded by 0x, otherwise it is decimal; octal numbers are not supported.
-The standard C relational operators are all supported.
-If after
-variable expansion, either the left or right hand side of a
-.Ql Ic ==
-or
-.Ql Ic "!="
-operator is not an integral value, then
-string comparison is performed between the expanded
-variables.
-If no relational operator is given, it is assumed that the expanded
-variable is being compared against 0 or an empty string in the case
-of a string comparison.
-.Pp
-When
-.Nm
-is evaluating one of these conditional expressions, and it encounters
-a (white-space separated) word it doesn't recognize, either the
-.Dq make
-or
-.Dq defined
-expression is applied to it, depending on the form of the conditional.
-If the form is
-.Ql Ic .ifdef ,
-.Ql Ic .ifndef ,
-or
-.Ql Ic .if
-the
-.Dq defined
-expression is applied.
-Similarly, if the form is
-.Ql Ic .ifmake
-or
-.Ql Ic .ifnmake ,
-the
-.Dq make
-expression is applied.
-.Pp
-If the conditional evaluates to true the parsing of the makefile continues
-as before.
-If it evaluates to false, the following lines are skipped.
-In both cases this continues until a
-.Ql Ic .else
-or
-.Ql Ic .endif
-is found.
-.Pp
-For loops are typically used to apply a set of rules to a list of files.
-The syntax of a for loop is:
-.Pp
-.Bl -tag -compact -width Ds
-.It Ic \&.for Ar variable Oo Ar variable ... Oc Ic in Ar expression
-.It Aq make-rules
-.It Ic \&.endfor
-.El
-.Pp
-After the for
-.Ic expression
-is evaluated, it is split into words.
-On each iteration of the loop, one word is taken and assigned to each
-.Ic variable ,
-in order, and these
-.Ic variables
-are substituted into the
-.Ic make-rules
-inside the body of the for loop.
-The number of words must come out even; that is, if there are three
-iteration variables, the number of words provided must be a multiple
-of three.
-.Sh COMMENTS
-Comments begin with a hash
-.Pq Ql \&#
-character, anywhere but in a shell
-command line, and continue to the end of an unescaped new line.
-.Sh SPECIAL SOURCES (ATTRIBUTES)
-.Bl -tag -width .IGNOREx
-.It Ic .EXEC
-Target is never out of date, but always execute commands anyway.
-.It Ic .IGNORE
-Ignore any errors from the commands associated with this target, exactly
-as if they all were preceded by a dash
-.Pq Ql \- .
-.\" .It Ic .INVISIBLE
-.\" XXX
-.\" .It Ic .JOIN
-.\" XXX
-.It Ic .MADE
-Mark all sources of this target as being up-to-date.
-.It Ic .MAKE
-Execute the commands associated with this target even if the
-.Fl n
-or
-.Fl t
-options were specified.
-Normally used to mark recursive
-.Nm Ns s .
-.It Ic .META
-Create a meta file for the target, even if it is flagged as
-.Ic .PHONY ,
-.Ic .MAKE ,
-or
-.Ic .SPECIAL .
-Usage in conjunction with
-.Ic .MAKE
-is the most likely case.
-In "meta" mode, the target is out-of-date if the meta file is missing.
-.It Ic .NOMETA
-Do not create a meta file for the target.
-Meta files are also not created for
-.Ic .PHONY ,
-.Ic .MAKE ,
-or
-.Ic .SPECIAL
-targets.
-.It Ic .NOMETA_CMP
-Ignore differences in commands when deciding if target is out of date.
-This is useful if the command contains a value which always changes.
-If the number of commands change, though, the target will still be out of date.
-The same effect applies to any command line that uses the variable
-.Va .OODATE ,
-which can be used for that purpose even when not otherwise needed or desired:
-.Bd -literal -offset indent
-
-skip-compare-for-some:
- @echo this will be compared
- @echo this will not ${.OODATE:M.NOMETA_CMP}
- @echo this will also be compared
-
-.Ed
-The
-.Cm \&:M
-pattern suppresses any expansion of the unwanted variable.
-.It Ic .NOPATH
-Do not search for the target in the directories specified by
-.Ic .PATH .
-.It Ic .NOTMAIN
-Normally
-.Nm
-selects the first target it encounters as the default target to be built
-if no target was specified.
-This source prevents this target from being selected.
-.It Ic .OPTIONAL
-If a target is marked with this attribute and
-.Nm
-can't figure out how to create it, it will ignore this fact and assume
-the file isn't needed or already exists.
-.It Ic .PHONY
-The target does not
-correspond to an actual file; it is always considered to be out of date,
-and will not be created with the
-.Fl t
-option.
-Suffix-transformation rules are not applied to
-.Ic .PHONY
-targets.
-.It Ic .PRECIOUS
-When
-.Nm
-is interrupted, it normally removes any partially made targets.
-This source prevents the target from being removed.
-.It Ic .RECURSIVE
-Synonym for
-.Ic .MAKE .
-.It Ic .SILENT
-Do not echo any of the commands associated with this target, exactly
-as if they all were preceded by an at sign
-.Pq Ql @ .
-.It Ic .USE
-Turn the target into
-.Nm Ns 's
-version of a macro.
-When the target is used as a source for another target, the other target
-acquires the commands, sources, and attributes (except for
-.Ic .USE )
-of the
-source.
-If the target already has commands, the
-.Ic .USE
-target's commands are appended
-to them.
-.It Ic .USEBEFORE
-Exactly like
-.Ic .USE ,
-but prepend the
-.Ic .USEBEFORE
-target commands to the target.
-.It Ic .WAIT
-If
-.Ic .WAIT
-appears in a dependency line, the sources that precede it are
-made before the sources that succeed it in the line.
-Since the dependents of files are not made until the file itself
-could be made, this also stops the dependents being built unless they
-are needed for another branch of the dependency tree.
-So given:
-.Bd -literal
-x: a .WAIT b
- echo x
-a:
- echo a
-b: b1
- echo b
-b1:
- echo b1
-
-.Ed
-the output is always
-.Ql a ,
-.Ql b1 ,
-.Ql b ,
-.Ql x .
-.br
-The ordering imposed by
-.Ic .WAIT
-is only relevant for parallel makes.
-.El
-.Sh SPECIAL TARGETS
-Special targets may not be included with other targets, i.e. they must be
-the only target specified.
-.Bl -tag -width .BEGINx
-.It Ic .BEGIN
-Any command lines attached to this target are executed before anything
-else is done.
-.It Ic .DEFAULT
-This is sort of a
-.Ic .USE
-rule for any target (that was used only as a
-source) that
-.Nm
-can't figure out any other way to create.
-Only the shell script is used.
-The
-.Ic .IMPSRC
-variable of a target that inherits
-.Ic .DEFAULT Ns 's
-commands is set
-to the target's own name.
-.It Ic .DELETE_ON_ERROR
-If this target is present in the makefile, it globally causes make to
-delete targets whose commands fail.
-(By default, only targets whose commands are interrupted during
-execution are deleted.
-This is the historical behavior.)
-This setting can be used to help prevent half-finished or malformed
-targets from being left around and corrupting future rebuilds.
-.It Ic .END
-Any command lines attached to this target are executed after everything
-else is done.
-.It Ic .ERROR
-Any command lines attached to this target are executed when another target fails.
-The
-.Ic .ERROR_TARGET
-variable is set to the target that failed.
-See also
-.Ic MAKE_PRINT_VAR_ON_ERROR .
-.It Ic .IGNORE
-Mark each of the sources with the
-.Ic .IGNORE
-attribute.
-If no sources are specified, this is the equivalent of specifying the
-.Fl i
-option.
-.It Ic .INTERRUPT
-If
-.Nm
-is interrupted, the commands for this target will be executed.
-.It Ic .MAIN
-If no target is specified when
-.Nm
-is invoked, this target will be built.
-.It Ic .MAKEFLAGS
-This target provides a way to specify flags for
-.Nm
-when the makefile is used.
-The flags are as if typed to the shell, though the
-.Fl f
-option will have
-no effect.
-.\" XXX: NOT YET!!!!
-.\" .It Ic .NOTPARALLEL
-.\" The named targets are executed in non parallel mode.
-.\" If no targets are
-.\" specified, then all targets are executed in non parallel mode.
-.It Ic .NOPATH
-Apply the
-.Ic .NOPATH
-attribute to any specified sources.
-.It Ic .NOTPARALLEL
-Disable parallel mode.
-.It Ic .NO_PARALLEL
-Synonym for
-.Ic .NOTPARALLEL ,
-for compatibility with other pmake variants.
-.It Ic .OBJDIR
-The source is a new value for
-.Ql Va .OBJDIR .
-If it exists,
-.Nm
-will
-.Xr chdir 2
-to it and update the value of
-.Ql Va .OBJDIR .
-.It Ic .ORDER
-The named targets are made in sequence.
-This ordering does not add targets to the list of targets to be made.
-Since the dependents of a target do not get built until the target itself
-could be built, unless
-.Ql a
-is built by another part of the dependency graph,
-the following is a dependency loop:
-.Bd -literal
-\&.ORDER: b a
-b: a
-.Ed
-.Pp
-The ordering imposed by
-.Ic .ORDER
-is only relevant for parallel makes.
-.\" XXX: NOT YET!!!!
-.\" .It Ic .PARALLEL
-.\" The named targets are executed in parallel mode.
-.\" If no targets are
-.\" specified, then all targets are executed in parallel mode.
-.It Ic .PATH
-The sources are directories which are to be searched for files not
-found in the current directory.
-If no sources are specified, any previously specified directories are
-deleted.
-If the source is the special
-.Ic .DOTLAST
-target, then the current working
-directory is searched last.
-.It Ic .PATH. Ns Va suffix
-Like
-.Ic .PATH
-but applies only to files with a particular suffix.
-The suffix must have been previously declared with
-.Ic .SUFFIXES .
-.It Ic .PHONY
-Apply the
-.Ic .PHONY
-attribute to any specified sources.
-.It Ic .PRECIOUS
-Apply the
-.Ic .PRECIOUS
-attribute to any specified sources.
-If no sources are specified, the
-.Ic .PRECIOUS
-attribute is applied to every
-target in the file.
-.It Ic .SHELL
-Sets the shell that
-.Nm
-will use to execute commands.
-The sources are a set of
-.Ar field=value
-pairs.
-.Bl -tag -width hasErrCtls
-.It Ar name
-This is the minimal specification, used to select one of the built-in
-shell specs;
-.Ar sh ,
-.Ar ksh ,
-and
-.Ar csh .
-.It Ar path
-Specifies the path to the shell.
-.It Ar hasErrCtl
-Indicates whether the shell supports exit on error.
-.It Ar check
-The command to turn on error checking.
-.It Ar ignore
-The command to disable error checking.
-.It Ar echo
-The command to turn on echoing of commands executed.
-.It Ar quiet
-The command to turn off echoing of commands executed.
-.It Ar filter
-The output to filter after issuing the
-.Ar quiet
-command.
-It is typically identical to
-.Ar quiet .
-.It Ar errFlag
-The flag to pass the shell to enable error checking.
-.It Ar echoFlag
-The flag to pass the shell to enable command echoing.
-.It Ar newline
-The string literal to pass the shell that results in a single newline
-character when used outside of any quoting characters.
-.El
-Example:
-.Bd -literal
-\&.SHELL: name=ksh path=/bin/ksh hasErrCtl=true \e
- check="set \-e" ignore="set +e" \e
- echo="set \-v" quiet="set +v" filter="set +v" \e
- echoFlag=v errFlag=e newline="'\en'"
-.Ed
-.It Ic .SILENT
-Apply the
-.Ic .SILENT
-attribute to any specified sources.
-If no sources are specified, the
-.Ic .SILENT
-attribute is applied to every
-command in the file.
-.It Ic .STALE
-This target gets run when a dependency file contains stale entries, having
-.Va .ALLSRC
-set to the name of that dependency file.
-.It Ic .SUFFIXES
-Each source specifies a suffix to
-.Nm .
-If no sources are specified, any previously specified suffixes are deleted.
-It allows the creation of suffix-transformation rules.
-.Pp
-Example:
-.Bd -literal
-\&.SUFFIXES: .o
-\&.c.o:
- cc \-o ${.TARGET} \-c ${.IMPSRC}
-.Ed
-.El
-.Sh ENVIRONMENT
-.Nm
-uses the following environment variables, if they exist:
-.Ev MACHINE ,
-.Ev MACHINE_ARCH ,
-.Ev MAKE ,
-.Ev MAKEFLAGS ,
-.Ev MAKEOBJDIR ,
-.Ev MAKEOBJDIRPREFIX ,
-.Ev MAKESYSPATH ,
-.Ev PWD ,
-and
-.Ev TMPDIR .
-.Pp
-.Ev MAKEOBJDIRPREFIX
-and
-.Ev MAKEOBJDIR
-may only be set in the environment or on the command line to
-.Nm
-and not as makefile variables;
-see the description of
-.Ql Va .OBJDIR
-for more details.
-.Sh FILES
-.Bl -tag -width /usr/share/mk -compact
-.It .depend
-list of dependencies
-.It Makefile
-list of dependencies
-.It makefile
-list of dependencies
-.It sys.mk
-system makefile
-.It /usr/share/mk
-system makefile directory
-.El
-.Sh COMPATIBILITY
-The basic make syntax is compatible between different versions of make;
-however the special variables, variable modifiers and conditionals are not.
-.Ss Older versions
-An incomplete list of changes in older versions of
-.Nm :
-.Pp
-The way that .for loop variables are substituted changed after
-.Nx 5.0
-so that they still appear to be variable expansions.
-In particular this stops them being treated as syntax, and removes some
-obscure problems using them in .if statements.
-.Pp
-The way that parallel makes are scheduled changed in
-.Nx 4.0
-so that .ORDER and .WAIT apply recursively to the dependent nodes.
-The algorithms used may change again in the future.
-.Ss Other make dialects
-Other make dialects (GNU make, SVR4 make, POSIX make, etc.) do not
-support most of the features of
-.Nm
-as described in this manual.
-Most notably:
-.Bl -bullet -offset indent
-.It
-The
-.Ic .WAIT
-and
-.Ic .ORDER
-declarations and most functionality pertaining to parallelization.
-(GNU make supports parallelization but lacks these features needed to
-control it effectively.)
-.It
-Directives, including for loops and conditionals and most of the
-forms of include files.
-(GNU make has its own incompatible and less powerful syntax for
-conditionals.)
-.It
-All built-in variables that begin with a dot.
-.It
-Most of the special sources and targets that begin with a dot,
-with the notable exception of
-.Ic .PHONY ,
-.Ic .PRECIOUS ,
-and
-.Ic .SUFFIXES .
-.It
-Variable modifiers, except for the
-.Dl :old=new
-string substitution, which does not portably support globbing with
-.Ql %
-and historically only works on declared suffixes.
-.It
-The
-.Ic $>
-variable even in its short form; most makes support this functionality
-but its name varies.
-.El
-.Pp
-Some features are somewhat more portable, such as assignment with
-.Ic += ,
-.Ic ?= ,
-and
-.Ic != .
-The
-.Ic .PATH
-functionality is based on an older feature
-.Ic VPATH
-found in GNU make and many versions of SVR4 make; however,
-historically its behavior is too ill-defined (and too buggy) to rely
-upon.
-.Pp
-The
-.Ic $@
-and
-.Ic $<
-variables are more or less universally portable, as is the
-.Ic $(MAKE)
-variable.
-Basic use of suffix rules (for files only in the current directory,
-not trying to chain transformations together, etc.) is also reasonably
-portable.
-.Sh SEE ALSO
-.Xr mkdep 1
-.Sh HISTORY
-A
-.Nm
-command appeared in
-.At v7 .
-This
-.Nm
-implementation is based on Adam De Boor's pmake program which was written
-for Sprite at Berkeley.
-It was designed to be a parallel distributed make running jobs on different
-machines using a daemon called
-.Dq customs .
-.Pp
-Historically the target/dependency
-.Dq FRC
-has been used to FoRCe rebuilding (since the target/dependency
-does not exist... unless someone creates an
-.Dq FRC
-file).
-.Sh BUGS
-The
-.Nm
-syntax is difficult to parse without actually acting of the data.
-For instance finding the end of a variable use should involve scanning each
-the modifiers using the correct terminator for each field.
-In many places
-.Nm
-just counts {} and () in order to find the end of a variable expansion.
-.Pp
-There is no way of escaping a space character in a filename.
diff --git a/usr.bin/make/make.c b/usr.bin/make/make.c
deleted file mode 100644
index 8947582..0000000
--- a/usr.bin/make/make.c
+++ /dev/null
@@ -1,1555 +0,0 @@
-/* $NetBSD: make.c,v 1.96 2016/11/10 23:41:58 sjg Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-/*
- * Copyright (c) 1989 by Berkeley Softworks
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: make.c,v 1.96 2016/11/10 23:41:58 sjg Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)make.c 8.1 (Berkeley) 6/6/93";
-#else
-__RCSID("$NetBSD: make.c,v 1.96 2016/11/10 23:41:58 sjg Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * make.c --
- * The functions which perform the examination of targets and
- * their suitability for creation
- *
- * Interface:
- * Make_Run Initialize things for the module and recreate
- * whatever needs recreating. Returns TRUE if
- * work was (or would have been) done and FALSE
- * otherwise.
- *
- * Make_Update Update all parents of a given child. Performs
- * various bookkeeping chores like the updating
- * of the cmgn field of the parent, filling
- * of the IMPSRC context variable, etc. It will
- * place the parent on the toBeMade queue if it
- * should be.
- *
- * Make_TimeStamp Function to set the parent's cmgn field
- * based on a child's modification time.
- *
- * Make_DoAllVar Set up the various local variables for a
- * target, including the .ALLSRC variable, making
- * sure that any variable that needs to exist
- * at the very least has the empty value.
- *
- * Make_OODate Determine if a target is out-of-date.
- *
- * Make_HandleUse See if a child is a .USE node for a parent
- * and perform the .USE actions if so.
- *
- * Make_ExpandUse Expand .USE nodes
- */
-
-#include "make.h"
-#include "hash.h"
-#include "dir.h"
-#include "job.h"
-
-static unsigned int checked = 1;/* Sequence # to detect recursion */
-static Lst toBeMade; /* The current fringe of the graph. These
- * are nodes which await examination by
- * MakeOODate. It is added to by
- * Make_Update and subtracted from by
- * MakeStartJobs */
-
-static int MakeAddChild(void *, void *);
-static int MakeFindChild(void *, void *);
-static int MakeUnmark(void *, void *);
-static int MakeAddAllSrc(void *, void *);
-static int MakeTimeStamp(void *, void *);
-static int MakeHandleUse(void *, void *);
-static Boolean MakeStartJobs(void);
-static int MakePrintStatus(void *, void *);
-static int MakeCheckOrder(void *, void *);
-static int MakeBuildChild(void *, void *);
-static int MakeBuildParent(void *, void *);
-
-MAKE_ATTR_DEAD static void
-make_abort(GNode *gn, int line)
-{
- static int two = 2;
-
- fprintf(debug_file, "make_abort from line %d\n", line);
- Targ_PrintNode(gn, &two);
- Lst_ForEach(toBeMade, Targ_PrintNode, &two);
- Targ_PrintGraph(3);
- abort();
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Make_TimeStamp --
- * Set the cmgn field of a parent node based on the mtime stamp in its
- * child. Called from MakeOODate via Lst_ForEach.
- *
- * Input:
- * pgn the current parent
- * cgn the child we've just examined
- *
- * Results:
- * Always returns 0.
- *
- * Side Effects:
- * The cmgn of the parent node will be changed if the mtime
- * field of the child is greater than it.
- *-----------------------------------------------------------------------
- */
-int
-Make_TimeStamp(GNode *pgn, GNode *cgn)
-{
- if (pgn->cmgn == NULL || cgn->mtime > pgn->cmgn->mtime) {
- pgn->cmgn = cgn;
- }
- return (0);
-}
-
-/*
- * Input:
- * pgn the current parent
- * cgn the child we've just examined
- *
- */
-static int
-MakeTimeStamp(void *pgn, void *cgn)
-{
- return Make_TimeStamp((GNode *)pgn, (GNode *)cgn);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Make_OODate --
- * See if a given node is out of date with respect to its sources.
- * Used by Make_Run when deciding which nodes to place on the
- * toBeMade queue initially and by Make_Update to screen out USE and
- * EXEC nodes. In the latter case, however, any other sort of node
- * must be considered out-of-date since at least one of its children
- * will have been recreated.
- *
- * Input:
- * gn the node to check
- *
- * Results:
- * TRUE if the node is out of date. FALSE otherwise.
- *
- * Side Effects:
- * The mtime field of the node and the cmgn field of its parents
- * will/may be changed.
- *-----------------------------------------------------------------------
- */
-Boolean
-Make_OODate(GNode *gn)
-{
- Boolean oodate;
-
- /*
- * Certain types of targets needn't even be sought as their datedness
- * doesn't depend on their modification time...
- */
- if ((gn->type & (OP_JOIN|OP_USE|OP_USEBEFORE|OP_EXEC)) == 0) {
- (void)Dir_MTime(gn, 1);
- if (DEBUG(MAKE)) {
- if (gn->mtime != 0) {
- fprintf(debug_file, "modified %s...", Targ_FmtTime(gn->mtime));
- } else {
- fprintf(debug_file, "non-existent...");
- }
- }
- }
-
- /*
- * A target is remade in one of the following circumstances:
- * its modification time is smaller than that of its youngest child
- * and it would actually be run (has commands or type OP_NOP)
- * it's the object of a force operator
- * it has no children, was on the lhs of an operator and doesn't exist
- * already.
- *
- * Libraries are only considered out-of-date if the archive module says
- * they are.
- *
- * These weird rules are brought to you by Backward-Compatibility and
- * the strange people who wrote 'Make'.
- */
- if (gn->type & (OP_USE|OP_USEBEFORE)) {
- /*
- * If the node is a USE node it is *never* out of date
- * no matter *what*.
- */
- if (DEBUG(MAKE)) {
- fprintf(debug_file, ".USE node...");
- }
- oodate = FALSE;
- } else if ((gn->type & OP_LIB) &&
- ((gn->mtime==0) || Arch_IsLib(gn))) {
- if (DEBUG(MAKE)) {
- fprintf(debug_file, "library...");
- }
-
- /*
- * always out of date if no children and :: target
- * or non-existent.
- */
- oodate = (gn->mtime == 0 || Arch_LibOODate(gn) ||
- (gn->cmgn == NULL && (gn->type & OP_DOUBLEDEP)));
- } else if (gn->type & OP_JOIN) {
- /*
- * A target with the .JOIN attribute is only considered
- * out-of-date if any of its children was out-of-date.
- */
- if (DEBUG(MAKE)) {
- fprintf(debug_file, ".JOIN node...");
- }
- if (DEBUG(MAKE)) {
- fprintf(debug_file, "source %smade...", gn->flags & CHILDMADE ? "" : "not ");
- }
- oodate = (gn->flags & CHILDMADE) ? TRUE : FALSE;
- } else if (gn->type & (OP_FORCE|OP_EXEC|OP_PHONY)) {
- /*
- * A node which is the object of the force (!) operator or which has
- * the .EXEC attribute is always considered out-of-date.
- */
- if (DEBUG(MAKE)) {
- if (gn->type & OP_FORCE) {
- fprintf(debug_file, "! operator...");
- } else if (gn->type & OP_PHONY) {
- fprintf(debug_file, ".PHONY node...");
- } else {
- fprintf(debug_file, ".EXEC node...");
- }
- }
- oodate = TRUE;
- } else if ((gn->cmgn != NULL && gn->mtime < gn->cmgn->mtime) ||
- (gn->cmgn == NULL &&
- ((gn->mtime == 0 && !(gn->type & OP_OPTIONAL))
- || gn->type & OP_DOUBLEDEP)))
- {
- /*
- * A node whose modification time is less than that of its
- * youngest child or that has no children (cmgn == NULL) and
- * either doesn't exist (mtime == 0) and it isn't optional
- * or was the object of a * :: operator is out-of-date.
- * Why? Because that's the way Make does it.
- */
- if (DEBUG(MAKE)) {
- if (gn->cmgn != NULL && gn->mtime < gn->cmgn->mtime) {
- fprintf(debug_file, "modified before source %s...",
- gn->cmgn->path ? gn->cmgn->path : gn->cmgn->name);
- } else if (gn->mtime == 0) {
- fprintf(debug_file, "non-existent and no sources...");
- } else {
- fprintf(debug_file, ":: operator and no sources...");
- }
- }
- oodate = TRUE;
- } else {
- /*
- * When a non-existing child with no sources
- * (such as a typically used FORCE source) has been made and
- * the target of the child (usually a directory) has the same
- * timestamp as the timestamp just given to the non-existing child
- * after it was considered made.
- */
- if (DEBUG(MAKE)) {
- if (gn->flags & FORCE)
- fprintf(debug_file, "non existing child...");
- }
- oodate = (gn->flags & FORCE) ? TRUE : FALSE;
- }
-
-#ifdef USE_META
- if (useMeta) {
- oodate = meta_oodate(gn, oodate);
- }
-#endif
-
- /*
- * If the target isn't out-of-date, the parents need to know its
- * modification time. Note that targets that appear to be out-of-date
- * but aren't, because they have no commands and aren't of type OP_NOP,
- * have their mtime stay below their children's mtime to keep parents from
- * thinking they're out-of-date.
- */
- if (!oodate) {
- Lst_ForEach(gn->parents, MakeTimeStamp, gn);
- }
-
- return (oodate);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * MakeAddChild --
- * Function used by Make_Run to add a child to the list l.
- * It will only add the child if its make field is FALSE.
- *
- * Input:
- * gnp the node to add
- * lp the list to which to add it
- *
- * Results:
- * Always returns 0
- *
- * Side Effects:
- * The given list is extended
- *-----------------------------------------------------------------------
- */
-static int
-MakeAddChild(void *gnp, void *lp)
-{
- GNode *gn = (GNode *)gnp;
- Lst l = (Lst) lp;
-
- if ((gn->flags & REMAKE) == 0 && !(gn->type & (OP_USE|OP_USEBEFORE))) {
- if (DEBUG(MAKE))
- fprintf(debug_file, "MakeAddChild: need to examine %s%s\n",
- gn->name, gn->cohort_num);
- (void)Lst_EnQueue(l, gn);
- }
- return (0);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * MakeFindChild --
- * Function used by Make_Run to find the pathname of a child
- * that was already made.
- *
- * Input:
- * gnp the node to find
- *
- * Results:
- * Always returns 0
- *
- * Side Effects:
- * The path and mtime of the node and the cmgn of the parent are
- * updated; the unmade children count of the parent is decremented.
- *-----------------------------------------------------------------------
- */
-static int
-MakeFindChild(void *gnp, void *pgnp)
-{
- GNode *gn = (GNode *)gnp;
- GNode *pgn = (GNode *)pgnp;
-
- (void)Dir_MTime(gn, 0);
- Make_TimeStamp(pgn, gn);
- pgn->unmade--;
-
- return (0);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Make_HandleUse --
- * Function called by Make_Run and SuffApplyTransform on the downward
- * pass to handle .USE and transformation nodes. It implements the
- * .USE and transformation functionality by copying the node's commands,
- * type flags and children to the parent node.
- *
- * A .USE node is much like an explicit transformation rule, except
- * its commands are always added to the target node, even if the
- * target already has commands.
- *
- * Input:
- * cgn The .USE node
- * pgn The target of the .USE node
- *
- * Results:
- * none
- *
- * Side Effects:
- * Children and commands may be added to the parent and the parent's
- * type may be changed.
- *
- *-----------------------------------------------------------------------
- */
-void
-Make_HandleUse(GNode *cgn, GNode *pgn)
-{
- LstNode ln; /* An element in the children list */
-
-#ifdef DEBUG_SRC
- if ((cgn->type & (OP_USE|OP_USEBEFORE|OP_TRANSFORM)) == 0) {
- fprintf(debug_file, "Make_HandleUse: called for plain node %s\n", cgn->name);
- return;
- }
-#endif
-
- if ((cgn->type & (OP_USE|OP_USEBEFORE)) || Lst_IsEmpty(pgn->commands)) {
- if (cgn->type & OP_USEBEFORE) {
- /*
- * .USEBEFORE --
- * prepend the child's commands to the parent.
- */
- Lst cmds = pgn->commands;
- pgn->commands = Lst_Duplicate(cgn->commands, NULL);
- (void)Lst_Concat(pgn->commands, cmds, LST_CONCNEW);
- Lst_Destroy(cmds, NULL);
- } else {
- /*
- * .USE or target has no commands --
- * append the child's commands to the parent.
- */
- (void)Lst_Concat(pgn->commands, cgn->commands, LST_CONCNEW);
- }
- }
-
- if (Lst_Open(cgn->children) == SUCCESS) {
- while ((ln = Lst_Next(cgn->children)) != NULL) {
- GNode *tgn, *gn = (GNode *)Lst_Datum(ln);
-
- /*
- * Expand variables in the .USE node's name
- * and save the unexpanded form.
- * We don't need to do this for commands.
- * They get expanded properly when we execute.
- */
- if (gn->uname == NULL) {
- gn->uname = gn->name;
- } else {
- free(gn->name);
- }
- gn->name = Var_Subst(NULL, gn->uname, pgn, VARF_WANTRES);
- if (gn->name && gn->uname && strcmp(gn->name, gn->uname) != 0) {
- /* See if we have a target for this node. */
- tgn = Targ_FindNode(gn->name, TARG_NOCREATE);
- if (tgn != NULL)
- gn = tgn;
- }
-
- (void)Lst_AtEnd(pgn->children, gn);
- (void)Lst_AtEnd(gn->parents, pgn);
- pgn->unmade += 1;
- }
- Lst_Close(cgn->children);
- }
-
- pgn->type |= cgn->type & ~(OP_OPMASK|OP_USE|OP_USEBEFORE|OP_TRANSFORM);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * MakeHandleUse --
- * Callback function for Lst_ForEach, used by Make_Run on the downward
- * pass to handle .USE nodes. Should be called before the children
- * are enqueued to be looked at by MakeAddChild.
- * This function calls Make_HandleUse to copy the .USE node's commands,
- * type flags and children to the parent node.
- *
- * Input:
- * cgnp the child we've just examined
- * pgnp the current parent
- *
- * Results:
- * returns 0.
- *
- * Side Effects:
- * After expansion, .USE child nodes are removed from the parent
- *
- *-----------------------------------------------------------------------
- */
-static int
-MakeHandleUse(void *cgnp, void *pgnp)
-{
- GNode *cgn = (GNode *)cgnp;
- GNode *pgn = (GNode *)pgnp;
- LstNode ln; /* An element in the children list */
- int unmarked;
-
- unmarked = ((cgn->type & OP_MARK) == 0);
- cgn->type |= OP_MARK;
-
- if ((cgn->type & (OP_USE|OP_USEBEFORE)) == 0)
- return (0);
-
- if (unmarked)
- Make_HandleUse(cgn, pgn);
-
- /*
- * This child node is now "made", so we decrement the count of
- * unmade children in the parent... We also remove the child
- * from the parent's list to accurately reflect the number of decent
- * children the parent has. This is used by Make_Run to decide
- * whether to queue the parent or examine its children...
- */
- if ((ln = Lst_Member(pgn->children, cgn)) != NULL) {
- Lst_Remove(pgn->children, ln);
- pgn->unmade--;
- }
- return (0);
-}
-
-
-/*-
- *-----------------------------------------------------------------------
- * Make_Recheck --
- * Check the modification time of a gnode, and update it as described
- * in the comments below.
- *
- * Results:
- * returns 0 if the gnode does not exist, or its filesystem
- * time if it does.
- *
- * Side Effects:
- * the gnode's modification time and path name are affected.
- *
- *-----------------------------------------------------------------------
- */
-time_t
-Make_Recheck(GNode *gn)
-{
- time_t mtime = Dir_MTime(gn, 1);
-
-#ifndef RECHECK
- /*
- * We can't re-stat the thing, but we can at least take care of rules
- * where a target depends on a source that actually creates the
- * target, but only if it has changed, e.g.
- *
- * parse.h : parse.o
- *
- * parse.o : parse.y
- * yacc -d parse.y
- * cc -c y.tab.c
- * mv y.tab.o parse.o
- * cmp -s y.tab.h parse.h || mv y.tab.h parse.h
- *
- * In this case, if the definitions produced by yacc haven't changed
- * from before, parse.h won't have been updated and gn->mtime will
- * reflect the current modification time for parse.h. This is
- * something of a kludge, I admit, but it's a useful one..
- * XXX: People like to use a rule like
- *
- * FRC:
- *
- * To force things that depend on FRC to be made, so we have to
- * check for gn->children being empty as well...
- */
- if (!Lst_IsEmpty(gn->commands) || Lst_IsEmpty(gn->children)) {
- gn->mtime = now;
- }
-#else
- /*
- * This is what Make does and it's actually a good thing, as it
- * allows rules like
- *
- * cmp -s y.tab.h parse.h || cp y.tab.h parse.h
- *
- * to function as intended. Unfortunately, thanks to the stateless
- * nature of NFS (by which I mean the loose coupling of two clients
- * using the same file from a common server), there are times
- * when the modification time of a file created on a remote
- * machine will not be modified before the local stat() implied by
- * the Dir_MTime occurs, thus leading us to believe that the file
- * is unchanged, wreaking havoc with files that depend on this one.
- *
- * I have decided it is better to make too much than to make too
- * little, so this stuff is commented out unless you're sure it's ok.
- * -- ardeb 1/12/88
- */
- /*
- * Christos, 4/9/92: If we are saving commands pretend that
- * the target is made now. Otherwise archives with ... rules
- * don't work!
- */
- if (NoExecute(gn) || (gn->type & OP_SAVE_CMDS) ||
- (mtime == 0 && !(gn->type & OP_WAIT))) {
- if (DEBUG(MAKE)) {
- fprintf(debug_file, " recheck(%s): update time from %s to now\n",
- gn->name, Targ_FmtTime(gn->mtime));
- }
- gn->mtime = now;
- }
- else {
- if (DEBUG(MAKE)) {
- fprintf(debug_file, " recheck(%s): current update time: %s\n",
- gn->name, Targ_FmtTime(gn->mtime));
- }
- }
-#endif
- return mtime;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Make_Update --
- * Perform update on the parents of a node. Used by JobFinish once
- * a node has been dealt with and by MakeStartJobs if it finds an
- * up-to-date node.
- *
- * Input:
- * cgn the child node
- *
- * Results:
- * Always returns 0
- *
- * Side Effects:
- * The unmade field of pgn is decremented and pgn may be placed on
- * the toBeMade queue if this field becomes 0.
- *
- * If the child was made, the parent's flag CHILDMADE field will be
- * set true.
- *
- * If the child is not up-to-date and still does not exist,
- * set the FORCE flag on the parents.
- *
- * If the child wasn't made, the cmgn field of the parent will be
- * altered if the child's mtime is big enough.
- *
- * Finally, if the child is the implied source for the parent, the
- * parent's IMPSRC variable is set appropriately.
- *
- *-----------------------------------------------------------------------
- */
-void
-Make_Update(GNode *cgn)
-{
- GNode *pgn; /* the parent node */
- char *cname; /* the child's name */
- LstNode ln; /* Element in parents and iParents lists */
- time_t mtime = -1;
- char *p1;
- Lst parents;
- GNode *centurion;
-
- /* It is save to re-examine any nodes again */
- checked++;
-
- cname = Var_Value(TARGET, cgn, &p1);
- free(p1);
-
- if (DEBUG(MAKE))
- fprintf(debug_file, "Make_Update: %s%s\n", cgn->name, cgn->cohort_num);
-
- /*
- * If the child was actually made, see what its modification time is
- * now -- some rules won't actually update the file. If the file still
- * doesn't exist, make its mtime now.
- */
- if (cgn->made != UPTODATE) {
- mtime = Make_Recheck(cgn);
- }
-
- /*
- * If this is a `::' node, we must consult its first instance
- * which is where all parents are linked.
- */
- if ((centurion = cgn->centurion) != NULL) {
- if (!Lst_IsEmpty(cgn->parents))
- Punt("%s%s: cohort has parents", cgn->name, cgn->cohort_num);
- centurion->unmade_cohorts -= 1;
- if (centurion->unmade_cohorts < 0)
- Error("Graph cycles through centurion %s", centurion->name);
- } else {
- centurion = cgn;
- }
- parents = centurion->parents;
-
- /* If this was a .ORDER node, schedule the RHS */
- Lst_ForEach(centurion->order_succ, MakeBuildParent, Lst_First(toBeMade));
-
- /* Now mark all the parents as having one less unmade child */
- if (Lst_Open(parents) == SUCCESS) {
- while ((ln = Lst_Next(parents)) != NULL) {
- pgn = (GNode *)Lst_Datum(ln);
- if (DEBUG(MAKE))
- fprintf(debug_file, "inspect parent %s%s: flags %x, "
- "type %x, made %d, unmade %d ",
- pgn->name, pgn->cohort_num, pgn->flags,
- pgn->type, pgn->made, pgn->unmade-1);
-
- if (!(pgn->flags & REMAKE)) {
- /* This parent isn't needed */
- if (DEBUG(MAKE))
- fprintf(debug_file, "- not needed\n");
- continue;
- }
- if (mtime == 0 && !(cgn->type & OP_WAIT))
- pgn->flags |= FORCE;
-
- /*
- * If the parent has the .MADE attribute, its timestamp got
- * updated to that of its newest child, and its unmake
- * child count got set to zero in Make_ExpandUse().
- * However other things might cause us to build one of its
- * children - and so we mustn't do any processing here when
- * the child build finishes.
- */
- if (pgn->type & OP_MADE) {
- if (DEBUG(MAKE))
- fprintf(debug_file, "- .MADE\n");
- continue;
- }
-
- if ( ! (cgn->type & (OP_EXEC|OP_USE|OP_USEBEFORE))) {
- if (cgn->made == MADE)
- pgn->flags |= CHILDMADE;
- (void)Make_TimeStamp(pgn, cgn);
- }
-
- /*
- * A parent must wait for the completion of all instances
- * of a `::' dependency.
- */
- if (centurion->unmade_cohorts != 0 || centurion->made < MADE) {
- if (DEBUG(MAKE))
- fprintf(debug_file,
- "- centurion made %d, %d unmade cohorts\n",
- centurion->made, centurion->unmade_cohorts);
- continue;
- }
-
- /* One more child of this parent is now made */
- pgn->unmade -= 1;
- if (pgn->unmade < 0) {
- if (DEBUG(MAKE)) {
- fprintf(debug_file, "Graph cycles through %s%s\n",
- pgn->name, pgn->cohort_num);
- Targ_PrintGraph(2);
- }
- Error("Graph cycles through %s%s", pgn->name, pgn->cohort_num);
- }
-
- /* We must always rescan the parents of .WAIT and .ORDER nodes. */
- if (pgn->unmade != 0 && !(centurion->type & OP_WAIT)
- && !(centurion->flags & DONE_ORDER)) {
- if (DEBUG(MAKE))
- fprintf(debug_file, "- unmade children\n");
- continue;
- }
- if (pgn->made != DEFERRED) {
- /*
- * Either this parent is on a different branch of the tree,
- * or it on the RHS of a .WAIT directive
- * or it is already on the toBeMade list.
- */
- if (DEBUG(MAKE))
- fprintf(debug_file, "- not deferred\n");
- continue;
- }
- if (pgn->order_pred
- && Lst_ForEach(pgn->order_pred, MakeCheckOrder, 0)) {
- /* A .ORDER rule stops us building this */
- continue;
- }
- if (DEBUG(MAKE)) {
- static int two = 2;
- fprintf(debug_file, "- %s%s made, schedule %s%s (made %d)\n",
- cgn->name, cgn->cohort_num,
- pgn->name, pgn->cohort_num, pgn->made);
- Targ_PrintNode(pgn, &two);
- }
- /* Ok, we can schedule the parent again */
- pgn->made = REQUESTED;
- (void)Lst_EnQueue(toBeMade, pgn);
- }
- Lst_Close(parents);
- }
-
- /*
- * Set the .PREFIX and .IMPSRC variables for all the implied parents
- * of this node.
- */
- if (Lst_Open(cgn->iParents) == SUCCESS) {
- char *cpref = Var_Value(PREFIX, cgn, &p1);
-
- while ((ln = Lst_Next(cgn->iParents)) != NULL) {
- pgn = (GNode *)Lst_Datum(ln);
- if (pgn->flags & REMAKE) {
- Var_Set(IMPSRC, cname, pgn, 0);
- if (cpref != NULL)
- Var_Set(PREFIX, cpref, pgn, 0);
- }
- }
- free(p1);
- Lst_Close(cgn->iParents);
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * MakeAddAllSrc --
- * Add a child's name to the ALLSRC and OODATE variables of the given
- * node. Called from Make_DoAllVar via Lst_ForEach. A child is added only
- * if it has not been given the .EXEC, .USE or .INVISIBLE attributes.
- * .EXEC and .USE children are very rarely going to be files, so...
- * If the child is a .JOIN node, its ALLSRC is propagated to the parent.
- *
- * A child is added to the OODATE variable if its modification time is
- * later than that of its parent, as defined by Make, except if the
- * parent is a .JOIN node. In that case, it is only added to the OODATE
- * variable if it was actually made (since .JOIN nodes don't have
- * modification times, the comparison is rather unfair...)..
- *
- * Results:
- * Always returns 0
- *
- * Side Effects:
- * The ALLSRC variable for the given node is extended.
- *-----------------------------------------------------------------------
- */
-static int
-MakeUnmark(void *cgnp, void *pgnp MAKE_ATTR_UNUSED)
-{
- GNode *cgn = (GNode *)cgnp;
-
- cgn->type &= ~OP_MARK;
- return (0);
-}
-
-/*
- * Input:
- * cgnp The child to add
- * pgnp The parent to whose ALLSRC variable it should
- * be added
- *
- */
-static int
-MakeAddAllSrc(void *cgnp, void *pgnp)
-{
- GNode *cgn = (GNode *)cgnp;
- GNode *pgn = (GNode *)pgnp;
-
- if (cgn->type & OP_MARK)
- return (0);
- cgn->type |= OP_MARK;
-
- if ((cgn->type & (OP_EXEC|OP_USE|OP_USEBEFORE|OP_INVISIBLE)) == 0) {
- char *child, *allsrc;
- char *p1 = NULL, *p2 = NULL;
-
- if (cgn->type & OP_ARCHV)
- child = Var_Value(MEMBER, cgn, &p1);
- else
- child = cgn->path ? cgn->path : cgn->name;
- if (cgn->type & OP_JOIN) {
- allsrc = Var_Value(ALLSRC, cgn, &p2);
- } else {
- allsrc = child;
- }
- if (allsrc != NULL)
- Var_Append(ALLSRC, allsrc, pgn);
- free(p2);
- if (pgn->type & OP_JOIN) {
- if (cgn->made == MADE) {
- Var_Append(OODATE, child, pgn);
- }
- } else if ((pgn->mtime < cgn->mtime) ||
- (cgn->mtime >= now && cgn->made == MADE))
- {
- /*
- * It goes in the OODATE variable if the parent is younger than the
- * child or if the child has been modified more recently than
- * the start of the make. This is to keep pmake from getting
- * confused if something else updates the parent after the
- * make starts (shouldn't happen, I know, but sometimes it
- * does). In such a case, if we've updated the kid, the parent
- * is likely to have a modification time later than that of
- * the kid and anything that relies on the OODATE variable will
- * be hosed.
- *
- * XXX: This will cause all made children to go in the OODATE
- * variable, even if they're not touched, if RECHECK isn't defined,
- * since cgn->mtime is set to now in Make_Update. According to
- * some people, this is good...
- */
- Var_Append(OODATE, child, pgn);
- }
- free(p1);
- }
- return (0);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Make_DoAllVar --
- * Set up the ALLSRC and OODATE variables. Sad to say, it must be
- * done separately, rather than while traversing the graph. This is
- * because Make defined OODATE to contain all sources whose modification
- * times were later than that of the target, *not* those sources that
- * were out-of-date. Since in both compatibility and native modes,
- * the modification time of the parent isn't found until the child
- * has been dealt with, we have to wait until now to fill in the
- * variable. As for ALLSRC, the ordering is important and not
- * guaranteed when in native mode, so it must be set here, too.
- *
- * Results:
- * None
- *
- * Side Effects:
- * The ALLSRC and OODATE variables of the given node is filled in.
- * If the node is a .JOIN node, its TARGET variable will be set to
- * match its ALLSRC variable.
- *-----------------------------------------------------------------------
- */
-void
-Make_DoAllVar(GNode *gn)
-{
- if (gn->flags & DONE_ALLSRC)
- return;
-
- Lst_ForEach(gn->children, MakeUnmark, gn);
- Lst_ForEach(gn->children, MakeAddAllSrc, gn);
-
- if (!Var_Exists (OODATE, gn)) {
- Var_Set(OODATE, "", gn, 0);
- }
- if (!Var_Exists (ALLSRC, gn)) {
- Var_Set(ALLSRC, "", gn, 0);
- }
-
- if (gn->type & OP_JOIN) {
- char *p1;
- Var_Set(TARGET, Var_Value(ALLSRC, gn, &p1), gn, 0);
- free(p1);
- }
- gn->flags |= DONE_ALLSRC;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * MakeStartJobs --
- * Start as many jobs as possible.
- *
- * Results:
- * If the query flag was given to pmake, no job will be started,
- * but as soon as an out-of-date target is found, this function
- * returns TRUE. At all other times, this function returns FALSE.
- *
- * Side Effects:
- * Nodes are removed from the toBeMade queue and job table slots
- * are filled.
- *
- *-----------------------------------------------------------------------
- */
-
-static int
-MakeCheckOrder(void *v_bn, void *ignore MAKE_ATTR_UNUSED)
-{
- GNode *bn = v_bn;
-
- if (bn->made >= MADE || !(bn->flags & REMAKE))
- return 0;
- if (DEBUG(MAKE))
- fprintf(debug_file, "MakeCheckOrder: Waiting for .ORDER node %s%s\n",
- bn->name, bn->cohort_num);
- return 1;
-}
-
-static int
-MakeBuildChild(void *v_cn, void *toBeMade_next)
-{
- GNode *cn = v_cn;
-
- if (DEBUG(MAKE))
- fprintf(debug_file, "MakeBuildChild: inspect %s%s, made %d, type %x\n",
- cn->name, cn->cohort_num, cn->made, cn->type);
- if (cn->made > DEFERRED)
- return 0;
-
- /* If this node is on the RHS of a .ORDER, check LHSs. */
- if (cn->order_pred && Lst_ForEach(cn->order_pred, MakeCheckOrder, 0)) {
- /* Can't build this (or anything else in this child list) yet */
- cn->made = DEFERRED;
- return 0; /* but keep looking */
- }
-
- if (DEBUG(MAKE))
- fprintf(debug_file, "MakeBuildChild: schedule %s%s\n",
- cn->name, cn->cohort_num);
-
- cn->made = REQUESTED;
- if (toBeMade_next == NULL)
- Lst_AtEnd(toBeMade, cn);
- else
- Lst_InsertBefore(toBeMade, toBeMade_next, cn);
-
- if (cn->unmade_cohorts != 0)
- Lst_ForEach(cn->cohorts, MakeBuildChild, toBeMade_next);
-
- /*
- * If this node is a .WAIT node with unmade chlidren
- * then don't add the next sibling.
- */
- return cn->type & OP_WAIT && cn->unmade > 0;
-}
-
-/* When a .ORDER LHS node completes we do this on each RHS */
-static int
-MakeBuildParent(void *v_pn, void *toBeMade_next)
-{
- GNode *pn = v_pn;
-
- if (pn->made != DEFERRED)
- return 0;
-
- if (MakeBuildChild(pn, toBeMade_next) == 0) {
- /* Mark so that when this node is built we reschedule its parents */
- pn->flags |= DONE_ORDER;
- }
-
- return 0;
-}
-
-static Boolean
-MakeStartJobs(void)
-{
- GNode *gn;
- int have_token = 0;
-
- while (!Lst_IsEmpty (toBeMade)) {
- /* Get token now to avoid cycling job-list when we only have 1 token */
- if (!have_token && !Job_TokenWithdraw())
- break;
- have_token = 1;
-
- gn = (GNode *)Lst_DeQueue(toBeMade);
- if (DEBUG(MAKE))
- fprintf(debug_file, "Examining %s%s...\n",
- gn->name, gn->cohort_num);
-
- if (gn->made != REQUESTED) {
- if (DEBUG(MAKE))
- fprintf(debug_file, "state %d\n", gn->made);
-
- make_abort(gn, __LINE__);
- }
-
- if (gn->checked == checked) {
- /* We've already looked at this node since a job finished... */
- if (DEBUG(MAKE))
- fprintf(debug_file, "already checked %s%s\n",
- gn->name, gn->cohort_num);
- gn->made = DEFERRED;
- continue;
- }
- gn->checked = checked;
-
- if (gn->unmade != 0) {
- /*
- * We can't build this yet, add all unmade children to toBeMade,
- * just before the current first element.
- */
- gn->made = DEFERRED;
- Lst_ForEach(gn->children, MakeBuildChild, Lst_First(toBeMade));
- /* and drop this node on the floor */
- if (DEBUG(MAKE))
- fprintf(debug_file, "dropped %s%s\n", gn->name, gn->cohort_num);
- continue;
- }
-
- gn->made = BEINGMADE;
- if (Make_OODate(gn)) {
- if (DEBUG(MAKE)) {
- fprintf(debug_file, "out-of-date\n");
- }
- if (queryFlag) {
- return (TRUE);
- }
- Make_DoAllVar(gn);
- Job_Make(gn);
- have_token = 0;
- } else {
- if (DEBUG(MAKE)) {
- fprintf(debug_file, "up-to-date\n");
- }
- gn->made = UPTODATE;
- if (gn->type & OP_JOIN) {
- /*
- * Even for an up-to-date .JOIN node, we need it to have its
- * context variables so references to it get the correct
- * value for .TARGET when building up the context variables
- * of its parent(s)...
- */
- Make_DoAllVar(gn);
- }
- Make_Update(gn);
- }
- }
-
- if (have_token)
- Job_TokenReturn();
-
- return (FALSE);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * MakePrintStatus --
- * Print the status of a top-level node, viz. it being up-to-date
- * already or not created due to an error in a lower level.
- * Callback function for Make_Run via Lst_ForEach.
- *
- * Input:
- * gnp Node to examine
- * cyclep True if gn->unmade being non-zero implies a
- * cycle in the graph, not an error in an
- * inferior.
- *
- * Results:
- * Always returns 0.
- *
- * Side Effects:
- * A message may be printed.
- *
- *-----------------------------------------------------------------------
- */
-static int
-MakePrintStatusOrder(void *ognp, void *gnp)
-{
- GNode *ogn = ognp;
- GNode *gn = gnp;
-
- if (!(ogn->flags & REMAKE) || ogn->made > REQUESTED)
- /* not waiting for this one */
- return 0;
-
- printf(" `%s%s' has .ORDER dependency against %s%s "
- "(made %d, flags %x, type %x)\n",
- gn->name, gn->cohort_num,
- ogn->name, ogn->cohort_num, ogn->made, ogn->flags, ogn->type);
- if (DEBUG(MAKE) && debug_file != stdout)
- fprintf(debug_file, " `%s%s' has .ORDER dependency against %s%s "
- "(made %d, flags %x, type %x)\n",
- gn->name, gn->cohort_num,
- ogn->name, ogn->cohort_num, ogn->made, ogn->flags, ogn->type);
- return 0;
-}
-
-static int
-MakePrintStatus(void *gnp, void *v_errors)
-{
- GNode *gn = (GNode *)gnp;
- int *errors = v_errors;
-
- if (gn->flags & DONECYCLE)
- /* We've completely processed this node before, don't do it again. */
- return 0;
-
- if (gn->unmade == 0) {
- gn->flags |= DONECYCLE;
- switch (gn->made) {
- case UPTODATE:
- printf("`%s%s' is up to date.\n", gn->name, gn->cohort_num);
- break;
- case MADE:
- break;
- case UNMADE:
- case DEFERRED:
- case REQUESTED:
- case BEINGMADE:
- (*errors)++;
- printf("`%s%s' was not built (made %d, flags %x, type %x)!\n",
- gn->name, gn->cohort_num, gn->made, gn->flags, gn->type);
- if (DEBUG(MAKE) && debug_file != stdout)
- fprintf(debug_file,
- "`%s%s' was not built (made %d, flags %x, type %x)!\n",
- gn->name, gn->cohort_num, gn->made, gn->flags, gn->type);
- /* Most likely problem is actually caused by .ORDER */
- Lst_ForEach(gn->order_pred, MakePrintStatusOrder, gn);
- break;
- default:
- /* Errors - already counted */
- printf("`%s%s' not remade because of errors.\n",
- gn->name, gn->cohort_num);
- if (DEBUG(MAKE) && debug_file != stdout)
- fprintf(debug_file, "`%s%s' not remade because of errors.\n",
- gn->name, gn->cohort_num);
- break;
- }
- return 0;
- }
-
- if (DEBUG(MAKE))
- fprintf(debug_file, "MakePrintStatus: %s%s has %d unmade children\n",
- gn->name, gn->cohort_num, gn->unmade);
- /*
- * If printing cycles and came to one that has unmade children,
- * print out the cycle by recursing on its children.
- */
- if (!(gn->flags & CYCLE)) {
- /* Fist time we've seen this node, check all children */
- gn->flags |= CYCLE;
- Lst_ForEach(gn->children, MakePrintStatus, errors);
- /* Mark that this node needn't be processed again */
- gn->flags |= DONECYCLE;
- return 0;
- }
-
- /* Only output the error once per node */
- gn->flags |= DONECYCLE;
- Error("Graph cycles through `%s%s'", gn->name, gn->cohort_num);
- if ((*errors)++ > 100)
- /* Abandon the whole error report */
- return 1;
-
- /* Reporting for our children will give the rest of the loop */
- Lst_ForEach(gn->children, MakePrintStatus, errors);
- return 0;
-}
-
-
-/*-
- *-----------------------------------------------------------------------
- * Make_ExpandUse --
- * Expand .USE nodes and create a new targets list
- *
- * Input:
- * targs the initial list of targets
- *
- * Side Effects:
- *-----------------------------------------------------------------------
- */
-void
-Make_ExpandUse(Lst targs)
-{
- GNode *gn; /* a temporary pointer */
- Lst examine; /* List of targets to examine */
-
- examine = Lst_Duplicate(targs, NULL);
-
- /*
- * Make an initial downward pass over the graph, marking nodes to be made
- * as we go down. We call Suff_FindDeps to find where a node is and
- * to get some children for it if it has none and also has no commands.
- * If the node is a leaf, we stick it on the toBeMade queue to
- * be looked at in a minute, otherwise we add its children to our queue
- * and go on about our business.
- */
- while (!Lst_IsEmpty (examine)) {
- gn = (GNode *)Lst_DeQueue(examine);
-
- if (gn->flags & REMAKE)
- /* We've looked at this one already */
- continue;
- gn->flags |= REMAKE;
- if (DEBUG(MAKE))
- fprintf(debug_file, "Make_ExpandUse: examine %s%s\n",
- gn->name, gn->cohort_num);
-
- if ((gn->type & OP_DOUBLEDEP) && !Lst_IsEmpty (gn->cohorts)) {
- /* Append all the 'cohorts' to the list of things to examine */
- Lst new;
- new = Lst_Duplicate(gn->cohorts, NULL);
- Lst_Concat(new, examine, LST_CONCLINK);
- examine = new;
- }
-
- /*
- * Apply any .USE rules before looking for implicit dependencies
- * to make sure everything has commands that should...
- * Make sure that the TARGET is set, so that we can make
- * expansions.
- */
- if (gn->type & OP_ARCHV) {
- char *eoa, *eon;
- eoa = strchr(gn->name, '(');
- eon = strchr(gn->name, ')');
- if (eoa == NULL || eon == NULL)
- continue;
- *eoa = '\0';
- *eon = '\0';
- Var_Set(MEMBER, eoa + 1, gn, 0);
- Var_Set(ARCHIVE, gn->name, gn, 0);
- *eoa = '(';
- *eon = ')';
- }
-
- (void)Dir_MTime(gn, 0);
- Var_Set(TARGET, gn->path ? gn->path : gn->name, gn, 0);
- Lst_ForEach(gn->children, MakeUnmark, gn);
- Lst_ForEach(gn->children, MakeHandleUse, gn);
-
- if ((gn->type & OP_MADE) == 0)
- Suff_FindDeps(gn);
- else {
- /* Pretend we made all this node's children */
- Lst_ForEach(gn->children, MakeFindChild, gn);
- if (gn->unmade != 0)
- printf("Warning: %s%s still has %d unmade children\n",
- gn->name, gn->cohort_num, gn->unmade);
- }
-
- if (gn->unmade != 0)
- Lst_ForEach(gn->children, MakeAddChild, examine);
- }
-
- Lst_Destroy(examine, NULL);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Make_ProcessWait --
- * Convert .WAIT nodes into dependencies
- *
- * Input:
- * targs the initial list of targets
- *
- *-----------------------------------------------------------------------
- */
-
-static int
-link_parent(void *cnp, void *pnp)
-{
- GNode *cn = cnp;
- GNode *pn = pnp;
-
- Lst_AtEnd(pn->children, cn);
- Lst_AtEnd(cn->parents, pn);
- pn->unmade++;
- return 0;
-}
-
-static int
-add_wait_dep(void *v_cn, void *v_wn)
-{
- GNode *cn = v_cn;
- GNode *wn = v_wn;
-
- if (cn == wn)
- return 1;
-
- if (cn == NULL || wn == NULL) {
- printf("bad wait dep %p %p\n", cn, wn);
- exit(4);
- }
- if (DEBUG(MAKE))
- fprintf(debug_file, ".WAIT: add dependency %s%s -> %s\n",
- cn->name, cn->cohort_num, wn->name);
-
- Lst_AtEnd(wn->children, cn);
- wn->unmade++;
- Lst_AtEnd(cn->parents, wn);
- return 0;
-}
-
-static void
-Make_ProcessWait(Lst targs)
-{
- GNode *pgn; /* 'parent' node we are examining */
- GNode *cgn; /* Each child in turn */
- LstNode owln; /* Previous .WAIT node */
- Lst examine; /* List of targets to examine */
- LstNode ln;
-
- /*
- * We need all the nodes to have a common parent in order for the
- * .WAIT and .ORDER scheduling to work.
- * Perhaps this should be done earlier...
- */
-
- pgn = Targ_NewGN(".MAIN");
- pgn->flags = REMAKE;
- pgn->type = OP_PHONY | OP_DEPENDS;
- /* Get it displayed in the diag dumps */
- Lst_AtFront(Targ_List(), pgn);
-
- Lst_ForEach(targs, link_parent, pgn);
-
- /* Start building with the 'dummy' .MAIN' node */
- MakeBuildChild(pgn, NULL);
-
- examine = Lst_Init(FALSE);
- Lst_AtEnd(examine, pgn);
-
- while (!Lst_IsEmpty (examine)) {
- pgn = Lst_DeQueue(examine);
-
- /* We only want to process each child-list once */
- if (pgn->flags & DONE_WAIT)
- continue;
- pgn->flags |= DONE_WAIT;
- if (DEBUG(MAKE))
- fprintf(debug_file, "Make_ProcessWait: examine %s\n", pgn->name);
-
- if ((pgn->type & OP_DOUBLEDEP) && !Lst_IsEmpty (pgn->cohorts)) {
- /* Append all the 'cohorts' to the list of things to examine */
- Lst new;
- new = Lst_Duplicate(pgn->cohorts, NULL);
- Lst_Concat(new, examine, LST_CONCLINK);
- examine = new;
- }
-
- owln = Lst_First(pgn->children);
- Lst_Open(pgn->children);
- for (; (ln = Lst_Next(pgn->children)) != NULL; ) {
- cgn = Lst_Datum(ln);
- if (cgn->type & OP_WAIT) {
- /* Make the .WAIT node depend on the previous children */
- Lst_ForEachFrom(pgn->children, owln, add_wait_dep, cgn);
- owln = ln;
- } else {
- Lst_AtEnd(examine, cgn);
- }
- }
- Lst_Close(pgn->children);
- }
-
- Lst_Destroy(examine, NULL);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Make_Run --
- * Initialize the nodes to remake and the list of nodes which are
- * ready to be made by doing a breadth-first traversal of the graph
- * starting from the nodes in the given list. Once this traversal
- * is finished, all the 'leaves' of the graph are in the toBeMade
- * queue.
- * Using this queue and the Job module, work back up the graph,
- * calling on MakeStartJobs to keep the job table as full as
- * possible.
- *
- * Input:
- * targs the initial list of targets
- *
- * Results:
- * TRUE if work was done. FALSE otherwise.
- *
- * Side Effects:
- * The make field of all nodes involved in the creation of the given
- * targets is set to 1. The toBeMade list is set to contain all the
- * 'leaves' of these subgraphs.
- *-----------------------------------------------------------------------
- */
-Boolean
-Make_Run(Lst targs)
-{
- int errors; /* Number of errors the Job module reports */
-
- /* Start trying to make the current targets... */
- toBeMade = Lst_Init(FALSE);
-
- Make_ExpandUse(targs);
- Make_ProcessWait(targs);
-
- if (DEBUG(MAKE)) {
- fprintf(debug_file, "#***# full graph\n");
- Targ_PrintGraph(1);
- }
-
- if (queryFlag) {
- /*
- * We wouldn't do any work unless we could start some jobs in the
- * next loop... (we won't actually start any, of course, this is just
- * to see if any of the targets was out of date)
- */
- return (MakeStartJobs());
- }
- /*
- * Initialization. At the moment, no jobs are running and until some
- * get started, nothing will happen since the remaining upward
- * traversal of the graph is performed by the routines in job.c upon
- * the finishing of a job. So we fill the Job table as much as we can
- * before going into our loop.
- */
- (void)MakeStartJobs();
-
- /*
- * Main Loop: The idea here is that the ending of jobs will take
- * care of the maintenance of data structures and the waiting for output
- * will cause us to be idle most of the time while our children run as
- * much as possible. Because the job table is kept as full as possible,
- * the only time when it will be empty is when all the jobs which need
- * running have been run, so that is the end condition of this loop.
- * Note that the Job module will exit if there were any errors unless the
- * keepgoing flag was given.
- */
- while (!Lst_IsEmpty(toBeMade) || jobTokensRunning > 0) {
- Job_CatchOutput();
- (void)MakeStartJobs();
- }
-
- errors = Job_Finish();
-
- /*
- * Print the final status of each target. E.g. if it wasn't made
- * because some inferior reported an error.
- */
- if (DEBUG(MAKE))
- fprintf(debug_file, "done: errors %d\n", errors);
- if (errors == 0) {
- Lst_ForEach(targs, MakePrintStatus, &errors);
- if (DEBUG(MAKE)) {
- fprintf(debug_file, "done: errors %d\n", errors);
- if (errors)
- Targ_PrintGraph(4);
- }
- }
- return errors != 0;
-}
diff --git a/usr.bin/make/make.h b/usr.bin/make/make.h
deleted file mode 100644
index 53e1895..0000000
--- a/usr.bin/make/make.h
+++ /dev/null
@@ -1,535 +0,0 @@
-/* $NetBSD: make.h,v 1.104 2018/02/12 21:38:09 sjg Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- *
- * from: @(#)make.h 8.3 (Berkeley) 6/13/95
- */
-
-/*
- * Copyright (c) 1989 by Berkeley Softworks
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. 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.
- *
- * from: @(#)make.h 8.3 (Berkeley) 6/13/95
- */
-
-/*-
- * make.h --
- * The global definitions for pmake
- */
-
-#ifndef _MAKE_H_
-#define _MAKE_H_
-
-#include <sys/types.h>
-#include <sys/param.h>
-
-#include <ctype.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#ifdef BSD4_4
-# include <sys/cdefs.h>
-#endif
-
-#ifndef FD_CLOEXEC
-#define FD_CLOEXEC 1
-#endif
-
-#if defined(__GNUC__)
-#define MAKE_GNUC_PREREQ(x, y) \
- ((__GNUC__ == (x) && __GNUC_MINOR__ >= (y)) || \
- (__GNUC__ > (x)))
-#else /* defined(__GNUC__) */
-#define MAKE_GNUC_PREREQ(x, y) 0
-#endif /* defined(__GNUC__) */
-
-#if MAKE_GNUC_PREREQ(2, 7)
-#define MAKE_ATTR_UNUSED __attribute__((__unused__))
-#else
-#define MAKE_ATTR_UNUSED /* delete */
-#endif
-
-#if MAKE_GNUC_PREREQ(2, 5)
-#define MAKE_ATTR_DEAD __attribute__((__noreturn__))
-#elif defined(__GNUC__)
-#define MAKE_ATTR_DEAD __volatile
-#else
-#define MAKE_ATTR_DEAD /* delete */
-#endif
-
-#if MAKE_GNUC_PREREQ(2, 7)
-#define MAKE_ATTR_PRINTFLIKE(fmtarg, firstvararg) \
- __attribute__((__format__ (__printf__, fmtarg, firstvararg)))
-#else
-#define MAKE_ATTR_PRINTFLIKE(fmtarg, firstvararg) /* delete */
-#endif
-
-#include "sprite.h"
-#include "lst.h"
-#include "hash.h"
-#include "config.h"
-#include "buf.h"
-#include "make_malloc.h"
-
-/*-
- * The structure for an individual graph node. Each node has several
- * pieces of data associated with it.
- * 1) the name of the target it describes
- * 2) the location of the target file in the file system.
- * 3) the type of operator used to define its sources (qv. parse.c)
- * 4) whether it is involved in this invocation of make
- * 5) whether the target has been remade
- * 6) whether any of its children has been remade
- * 7) the number of its children that are, as yet, unmade
- * 8) its modification time
- * 9) the modification time of its youngest child (qv. make.c)
- * 10) a list of nodes for which this is a source (parents)
- * 11) a list of nodes on which this depends (children)
- * 12) a list of nodes that depend on this, as gleaned from the
- * transformation rules (iParents)
- * 13) a list of ancestor nodes, which includes parents, iParents,
- * and recursive parents of parents
- * 14) a list of nodes of the same name created by the :: operator
- * 15) a list of nodes that must be made (if they're made) before
- * this node can be, but that do not enter into the datedness of
- * this node.
- * 16) a list of nodes that must be made (if they're made) before
- * this node or any child of this node can be, but that do not
- * enter into the datedness of this node.
- * 17) a list of nodes that must be made (if they're made) after
- * this node is, but that do not depend on this node, in the
- * normal sense.
- * 18) a Lst of ``local'' variables that are specific to this target
- * and this target only (qv. var.c [$@ $< $?, etc.])
- * 19) a Lst of strings that are commands to be given to a shell
- * to create this target.
- */
-typedef struct GNode {
- char *name; /* The target's name */
- char *uname; /* The unexpanded name of a .USE node */
- char *path; /* The full pathname of the file */
- int type; /* Its type (see the OP flags, below) */
-
- int flags;
-#define REMAKE 0x1 /* this target needs to be (re)made */
-#define CHILDMADE 0x2 /* children of this target were made */
-#define FORCE 0x4 /* children don't exist, and we pretend made */
-#define DONE_WAIT 0x8 /* Set by Make_ProcessWait() */
-#define DONE_ORDER 0x10 /* Build requested by .ORDER processing */
-#define FROM_DEPEND 0x20 /* Node created from .depend */
-#define DONE_ALLSRC 0x40 /* We do it once only */
-#define CYCLE 0x1000 /* Used by MakePrintStatus */
-#define DONECYCLE 0x2000 /* Used by MakePrintStatus */
-#define INTERNAL 0x4000 /* Internal use only */
- enum enum_made {
- UNMADE, DEFERRED, REQUESTED, BEINGMADE,
- MADE, UPTODATE, ERROR, ABORTED
- } made; /* Set to reflect the state of processing
- * on this node:
- * UNMADE - Not examined yet
- * DEFERRED - Examined once (building child)
- * REQUESTED - on toBeMade list
- * BEINGMADE - Target is already being made.
- * Indicates a cycle in the graph.
- * MADE - Was out-of-date and has been made
- * UPTODATE - Was already up-to-date
- * ERROR - An error occurred while it was being
- * made (used only in compat mode)
- * ABORTED - The target was aborted due to
- * an error making an inferior (compat).
- */
- int unmade; /* The number of unmade children */
-
- time_t mtime; /* Its modification time */
- struct GNode *cmgn; /* The youngest child */
-
- Lst iParents; /* Links to parents for which this is an
- * implied source, if any */
- Lst cohorts; /* Other nodes for the :: operator */
- Lst parents; /* Nodes that depend on this one */
- Lst children; /* Nodes on which this one depends */
- Lst order_pred; /* .ORDER nodes we need made */
- Lst order_succ; /* .ORDER nodes who need us */
-
- char cohort_num[8]; /* #n for this cohort */
- int unmade_cohorts;/* # of unmade instances on the
- cohorts list */
- struct GNode *centurion; /* Pointer to the first instance of a ::
- node; only set when on a cohorts list */
- unsigned int checked; /* Last time we tried to makle this node */
-
- Hash_Table context; /* The local variables */
- Lst commands; /* Creation commands */
-
- struct _Suff *suffix; /* Suffix for the node (determined by
- * Suff_FindDeps and opaque to everyone
- * but the Suff module) */
- const char *fname; /* filename where the GNode got defined */
- int lineno; /* line number where the GNode got defined */
-} GNode;
-
-/*
- * The OP_ constants are used when parsing a dependency line as a way of
- * communicating to other parts of the program the way in which a target
- * should be made. These constants are bitwise-OR'ed together and
- * placed in the 'type' field of each node. Any node that has
- * a 'type' field which satisfies the OP_NOP function was never never on
- * the lefthand side of an operator, though it may have been on the
- * righthand side...
- */
-#define OP_DEPENDS 0x00000001 /* Execution of commands depends on
- * kids (:) */
-#define OP_FORCE 0x00000002 /* Always execute commands (!) */
-#define OP_DOUBLEDEP 0x00000004 /* Execution of commands depends on kids
- * per line (::) */
-#define OP_OPMASK (OP_DEPENDS|OP_FORCE|OP_DOUBLEDEP)
-
-#define OP_OPTIONAL 0x00000008 /* Don't care if the target doesn't
- * exist and can't be created */
-#define OP_USE 0x00000010 /* Use associated commands for parents */
-#define OP_EXEC 0x00000020 /* Target is never out of date, but always
- * execute commands anyway. Its time
- * doesn't matter, so it has none...sort
- * of */
-#define OP_IGNORE 0x00000040 /* Ignore errors when creating the node */
-#define OP_PRECIOUS 0x00000080 /* Don't remove the target when
- * interrupted */
-#define OP_SILENT 0x00000100 /* Don't echo commands when executed */
-#define OP_MAKE 0x00000200 /* Target is a recursive make so its
- * commands should always be executed when
- * it is out of date, regardless of the
- * state of the -n or -t flags */
-#define OP_JOIN 0x00000400 /* Target is out-of-date only if any of its
- * children was out-of-date */
-#define OP_MADE 0x00000800 /* Assume the children of the node have
- * been already made */
-#define OP_SPECIAL 0x00001000 /* Special .BEGIN, .END, .INTERRUPT */
-#define OP_USEBEFORE 0x00002000 /* Like .USE, only prepend commands */
-#define OP_INVISIBLE 0x00004000 /* The node is invisible to its parents.
- * I.e. it doesn't show up in the parents's
- * local variables. */
-#define OP_NOTMAIN 0x00008000 /* The node is exempt from normal 'main
- * target' processing in parse.c */
-#define OP_PHONY 0x00010000 /* Not a file target; run always */
-#define OP_NOPATH 0x00020000 /* Don't search for file in the path */
-#define OP_WAIT 0x00040000 /* .WAIT phony node */
-#define OP_NOMETA 0x00080000 /* .NOMETA do not create a .meta file */
-#define OP_META 0x00100000 /* .META we _do_ want a .meta file */
-#define OP_NOMETA_CMP 0x00200000 /* Do not compare commands in .meta file */
-#define OP_SUBMAKE 0x00400000 /* Possibly a submake node */
-/* Attributes applied by PMake */
-#define OP_TRANSFORM 0x80000000 /* The node is a transformation rule */
-#define OP_MEMBER 0x40000000 /* Target is a member of an archive */
-#define OP_LIB 0x20000000 /* Target is a library */
-#define OP_ARCHV 0x10000000 /* Target is an archive construct */
-#define OP_HAS_COMMANDS 0x08000000 /* Target has all the commands it should.
- * Used when parsing to catch multiple
- * commands for a target */
-#define OP_SAVE_CMDS 0x04000000 /* Saving commands on .END (Compat) */
-#define OP_DEPS_FOUND 0x02000000 /* Already processed by Suff_FindDeps */
-#define OP_MARK 0x01000000 /* Node found while expanding .ALLSRC */
-
-#define NoExecute(gn) ((gn->type & OP_MAKE) ? noRecursiveExecute : noExecute)
-/*
- * OP_NOP will return TRUE if the node with the given type was not the
- * object of a dependency operator
- */
-#define OP_NOP(t) (((t) & OP_OPMASK) == 0x00000000)
-
-#define OP_NOTARGET (OP_NOTMAIN|OP_USE|OP_EXEC|OP_TRANSFORM)
-
-/*
- * The TARG_ constants are used when calling the Targ_FindNode and
- * Targ_FindList functions in targ.c. They simply tell the functions what to
- * do if the desired node(s) is (are) not found. If the TARG_CREATE constant
- * is given, a new, empty node will be created for the target, placed in the
- * table of all targets and its address returned. If TARG_NOCREATE is given,
- * a NULL pointer will be returned.
- */
-#define TARG_NOCREATE 0x00 /* don't create it */
-#define TARG_CREATE 0x01 /* create node if not found */
-#define TARG_NOHASH 0x02 /* don't look in/add to hash table */
-
-/*
- * These constants are all used by the Str_Concat function to decide how the
- * final string should look. If STR_ADDSPACE is given, a space will be
- * placed between the two strings. If STR_ADDSLASH is given, a '/' will
- * be used instead of a space. If neither is given, no intervening characters
- * will be placed between the two strings in the final output. If the
- * STR_DOFREE bit is set, the two input strings will be freed before
- * Str_Concat returns.
- */
-#define STR_ADDSPACE 0x01 /* add a space when Str_Concat'ing */
-#define STR_ADDSLASH 0x02 /* add a slash when Str_Concat'ing */
-
-/*
- * Error levels for parsing. PARSE_FATAL means the process cannot continue
- * once the makefile has been parsed. PARSE_WARNING means it can. Passed
- * as the first argument to Parse_Error.
- */
-#define PARSE_INFO 3
-#define PARSE_WARNING 2
-#define PARSE_FATAL 1
-
-/*
- * Values returned by Cond_Eval.
- */
-#define COND_PARSE 0 /* Parse the next lines */
-#define COND_SKIP 1 /* Skip the next lines */
-#define COND_INVALID 2 /* Not a conditional statement */
-
-/*
- * Definitions for the "local" variables. Used only for clarity.
- */
-#define TARGET "@" /* Target of dependency */
-#define OODATE "?" /* All out-of-date sources */
-#define ALLSRC ">" /* All sources */
-#define IMPSRC "<" /* Source implied by transformation */
-#define PREFIX "*" /* Common prefix */
-#define ARCHIVE "!" /* Archive in "archive(member)" syntax */
-#define MEMBER "%" /* Member in "archive(member)" syntax */
-
-#define FTARGET "@F" /* file part of TARGET */
-#define DTARGET "@D" /* directory part of TARGET */
-#define FIMPSRC "<F" /* file part of IMPSRC */
-#define DIMPSRC "<D" /* directory part of IMPSRC */
-#define FPREFIX "*F" /* file part of PREFIX */
-#define DPREFIX "*D" /* directory part of PREFIX */
-
-/*
- * Global Variables
- */
-extern Lst create; /* The list of target names specified on the
- * command line. used to resolve #if
- * make(...) statements */
-extern Lst dirSearchPath; /* The list of directories to search when
- * looking for targets */
-
-extern Boolean compatMake; /* True if we are make compatible */
-extern Boolean ignoreErrors; /* True if should ignore all errors */
-extern Boolean beSilent; /* True if should print no commands */
-extern Boolean noExecute; /* True if should execute nothing */
-extern Boolean noRecursiveExecute; /* True if should execute nothing */
-extern Boolean allPrecious; /* True if every target is precious */
-extern Boolean deleteOnError; /* True if failed targets should be deleted */
-extern Boolean keepgoing; /* True if should continue on unaffected
- * portions of the graph when have an error
- * in one portion */
-extern Boolean touchFlag; /* TRUE if targets should just be 'touched'
- * if out of date. Set by the -t flag */
-extern Boolean queryFlag; /* TRUE if we aren't supposed to really make
- * anything, just see if the targets are out-
- * of-date */
-extern Boolean doing_depend; /* TRUE if processing .depend */
-
-extern Boolean checkEnvFirst; /* TRUE if environment should be searched for
- * variables before the global context */
-extern Boolean jobServer; /* a jobServer already exists */
-
-extern Boolean parseWarnFatal; /* TRUE if makefile parsing warnings are
- * treated as errors */
-
-extern Boolean varNoExportEnv; /* TRUE if we should not export variables
- * set on the command line to the env. */
-
-extern GNode *DEFAULT; /* .DEFAULT rule */
-
-extern GNode *VAR_INTERNAL; /* Variables defined internally by make
- * which should not override those set by
- * makefiles.
- */
-extern GNode *VAR_GLOBAL; /* Variables defined in a global context, e.g
- * in the Makefile itself */
-extern GNode *VAR_CMD; /* Variables defined on the command line */
-extern GNode *VAR_FOR; /* Iteration variables */
-extern char var_Error[]; /* Value returned by Var_Parse when an error
- * is encountered. It actually points to
- * an empty string, so naive callers needn't
- * worry about it. */
-
-extern time_t now; /* The time at the start of this whole
- * process */
-
-extern Boolean oldVars; /* Do old-style variable substitution */
-
-extern Lst sysIncPath; /* The system include path. */
-extern Lst defIncPath; /* The default include path. */
-
-extern char curdir[]; /* Startup directory */
-extern char *progname; /* The program name */
-extern char *makeDependfile; /* .depend */
-extern char **savedEnv; /* if we replaced environ this will be non-NULL */
-
-/*
- * We cannot vfork() in a child of vfork().
- * Most systems do not enforce this but some do.
- */
-#define vFork() ((getpid() == myPid) ? vfork() : fork())
-extern pid_t myPid;
-
-#define MAKEFLAGS ".MAKEFLAGS"
-#define MAKEOVERRIDES ".MAKEOVERRIDES"
-#define MAKE_JOB_PREFIX ".MAKE.JOB.PREFIX" /* prefix for job target output */
-#define MAKE_EXPORTED ".MAKE.EXPORTED" /* variables we export */
-#define MAKE_MAKEFILES ".MAKE.MAKEFILES" /* all the makefiles we read */
-#define MAKE_LEVEL ".MAKE.LEVEL" /* recursion level */
-#define MAKEFILE_PREFERENCE ".MAKE.MAKEFILE_PREFERENCE"
-#define MAKE_DEPENDFILE ".MAKE.DEPENDFILE" /* .depend */
-#define MAKE_MODE ".MAKE.MODE"
-#ifndef MAKE_LEVEL_ENV
-# define MAKE_LEVEL_ENV "MAKELEVEL"
-#endif
-
-/*
- * debug control:
- * There is one bit per module. It is up to the module what debug
- * information to print.
- */
-FILE *debug_file; /* Output written here - default stdout */
-extern int debug;
-#define DEBUG_ARCH 0x00001
-#define DEBUG_COND 0x00002
-#define DEBUG_DIR 0x00004
-#define DEBUG_GRAPH1 0x00008
-#define DEBUG_GRAPH2 0x00010
-#define DEBUG_JOB 0x00020
-#define DEBUG_MAKE 0x00040
-#define DEBUG_SUFF 0x00080
-#define DEBUG_TARG 0x00100
-#define DEBUG_VAR 0x00200
-#define DEBUG_FOR 0x00400
-#define DEBUG_SHELL 0x00800
-#define DEBUG_ERROR 0x01000
-#define DEBUG_LOUD 0x02000
-#define DEBUG_META 0x04000
-
-#define DEBUG_GRAPH3 0x10000
-#define DEBUG_SCRIPT 0x20000
-#define DEBUG_PARSE 0x40000
-#define DEBUG_CWD 0x80000
-
-#define CONCAT(a,b) a##b
-
-#define DEBUG(module) (debug & CONCAT(DEBUG_,module))
-
-#include "nonints.h"
-
-int Make_TimeStamp(GNode *, GNode *);
-Boolean Make_OODate(GNode *);
-void Make_ExpandUse(Lst);
-time_t Make_Recheck(GNode *);
-void Make_HandleUse(GNode *, GNode *);
-void Make_Update(GNode *);
-void Make_DoAllVar(GNode *);
-Boolean Make_Run(Lst);
-char * Check_Cwd_Cmd(const char *);
-void Check_Cwd(const char **);
-void PrintOnError(GNode *, const char *);
-void Main_ExportMAKEFLAGS(Boolean);
-Boolean Main_SetObjdir(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2);
-int mkTempFile(const char *, char **);
-int str2Lst_Append(Lst, char *, const char *);
-int cached_lstat(const char *, void *);
-int cached_stat(const char *, void *);
-
-#define VARF_UNDEFERR 1
-#define VARF_WANTRES 2
-#define VARF_ASSIGN 4
-
-#ifdef __GNUC__
-#define UNCONST(ptr) ({ \
- union __unconst { \
- const void *__cp; \
- void *__p; \
- } __d; \
- __d.__cp = ptr, __d.__p; })
-#else
-#define UNCONST(ptr) (void *)(ptr)
-#endif
-
-#ifndef MIN
-#define MIN(a, b) ((a < b) ? a : b)
-#endif
-#ifndef MAX
-#define MAX(a, b) ((a > b) ? a : b)
-#endif
-
-/* At least GNU/Hurd systems lack hardcoded MAXPATHLEN/PATH_MAX */
-#include <limits.h>
-#ifndef MAXPATHLEN
-#define MAXPATHLEN 4096
-#endif
-#ifndef PATH_MAX
-#define PATH_MAX MAXPATHLEN
-#endif
-
-#if defined(SYSV)
-#define KILLPG(pid, sig) kill(-(pid), (sig))
-#else
-#define KILLPG(pid, sig) killpg((pid), (sig))
-#endif
-
-#endif /* _MAKE_H_ */
diff --git a/usr.bin/make/make_malloc.c b/usr.bin/make/make_malloc.c
deleted file mode 100644
index 035d519..0000000
--- a/usr.bin/make/make_malloc.c
+++ /dev/null
@@ -1,119 +0,0 @@
-/* $NetBSD: make_malloc.c,v 1.11 2017/04/16 20:20:24 dholland Exp $ */
-
-/*-
- * Copyright (c) 2009 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
- */
-
-#ifdef MAKE_NATIVE
-#include <sys/cdefs.h>
-__RCSID("$NetBSD: make_malloc.c,v 1.11 2017/04/16 20:20:24 dholland Exp $");
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-#include "make.h"
-
-#ifndef USE_EMALLOC
-static MAKE_ATTR_DEAD void enomem(void);
-
-/*
- * enomem --
- * die when out of memory.
- */
-static MAKE_ATTR_DEAD void
-enomem(void)
-{
- (void)fprintf(stderr, "%s: %s.\n", progname, strerror(ENOMEM));
- exit(2);
-}
-
-/*
- * bmake_malloc --
- * malloc, but die on error.
- */
-void *
-bmake_malloc(size_t len)
-{
- void *p;
-
- if ((p = malloc(len)) == NULL)
- enomem();
- return(p);
-}
-
-/*
- * bmake_strdup --
- * strdup, but die on error.
- */
-char *
-bmake_strdup(const char *str)
-{
- size_t len;
- char *p;
-
- len = strlen(str) + 1;
- if ((p = malloc(len)) == NULL)
- enomem();
- return memcpy(p, str, len);
-}
-
-/*
- * bmake_strndup --
- * strndup, but die on error.
- */
-char *
-bmake_strndup(const char *str, size_t max_len)
-{
- size_t len;
- char *p;
-
- if (str == NULL)
- return NULL;
-
- len = strlen(str);
- if (len > max_len)
- len = max_len;
- p = bmake_malloc(len + 1);
- memcpy(p, str, len);
- p[len] = '\0';
-
- return(p);
-}
-
-/*
- * bmake_realloc --
- * realloc, but die on error.
- */
-void *
-bmake_realloc(void *ptr, size_t size)
-{
- if ((ptr = realloc(ptr, size)) == NULL)
- enomem();
- return(ptr);
-}
-#endif
diff --git a/usr.bin/make/make_malloc.h b/usr.bin/make/make_malloc.h
deleted file mode 100644
index 36d3eff..0000000
--- a/usr.bin/make/make_malloc.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* $NetBSD: make_malloc.h,v 1.4 2009/01/24 14:43:29 dsl Exp $ */
-
-/*-
- * Copyright (c) 2009 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
- */
-
-#ifndef USE_EMALLOC
-void *bmake_malloc(size_t);
-void *bmake_realloc(void *, size_t);
-char *bmake_strdup(const char *);
-char *bmake_strndup(const char *, size_t);
-#else
-#include <util.h>
-#define bmake_malloc(x) emalloc(x)
-#define bmake_realloc(x,y) erealloc(x,y)
-#define bmake_strdup(x) estrdup(x)
-#define bmake_strndup(x,y) estrndup(x,y)
-#endif
-
diff --git a/usr.bin/make/meta.c b/usr.bin/make/meta.c
deleted file mode 100644
index 4a3f41d..0000000
--- a/usr.bin/make/meta.c
+++ /dev/null
@@ -1,1641 +0,0 @@
-/* $NetBSD: meta.c,v 1.70 2018/02/13 19:37:30 sjg Exp $ */
-
-/*
- * Implement 'meta' mode.
- * Adapted from John Birrell's patches to FreeBSD make.
- * --sjg
- */
-/*
- * Copyright (c) 2009-2016, Juniper Networks, Inc.
- * Portions Copyright (c) 2009, John Birrell.
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
- * OWNER 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.
- */
-#if defined(USE_META)
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <libgen.h>
-#include <errno.h>
-#if !defined(HAVE_CONFIG_H) || defined(HAVE_ERR_H)
-#include <err.h>
-#endif
-
-#include "make.h"
-#include "job.h"
-
-#ifdef HAVE_FILEMON_H
-# include <filemon.h>
-#endif
-#if !defined(USE_FILEMON) && defined(FILEMON_SET_FD)
-# define USE_FILEMON
-#endif
-
-static BuildMon Mybm; /* for compat */
-static Lst metaBailiwick; /* our scope of control */
-static char *metaBailiwickStr; /* string storage for the list */
-static Lst metaIgnorePaths; /* paths we deliberately ignore */
-static char *metaIgnorePathsStr; /* string storage for the list */
-
-#ifndef MAKE_META_IGNORE_PATHS
-#define MAKE_META_IGNORE_PATHS ".MAKE.META.IGNORE_PATHS"
-#endif
-#ifndef MAKE_META_IGNORE_PATTERNS
-#define MAKE_META_IGNORE_PATTERNS ".MAKE.META.IGNORE_PATTERNS"
-#endif
-#ifndef MAKE_META_IGNORE_FILTER
-#define MAKE_META_IGNORE_FILTER ".MAKE.META.IGNORE_FILTER"
-#endif
-
-Boolean useMeta = FALSE;
-static Boolean useFilemon = FALSE;
-static Boolean writeMeta = FALSE;
-static Boolean metaMissing = FALSE; /* oodate if missing */
-static Boolean filemonMissing = FALSE; /* oodate if missing */
-static Boolean metaEnv = FALSE; /* don't save env unless asked */
-static Boolean metaVerbose = FALSE;
-static Boolean metaIgnoreCMDs = FALSE; /* ignore CMDs in .meta files */
-static Boolean metaIgnorePatterns = FALSE; /* do we need to do pattern matches */
-static Boolean metaIgnoreFilter = FALSE; /* do we have more complex filtering? */
-static Boolean metaCurdirOk = FALSE; /* write .meta in .CURDIR Ok? */
-static Boolean metaSilent = FALSE; /* if we have a .meta be SILENT */
-
-extern Boolean forceJobs;
-extern Boolean comatMake;
-extern char **environ;
-
-#define MAKE_META_PREFIX ".MAKE.META.PREFIX"
-
-#ifndef N2U
-# define N2U(n, u) (((n) + ((u) - 1)) / (u))
-#endif
-#ifndef ROUNDUP
-# define ROUNDUP(n, u) (N2U((n), (u)) * (u))
-#endif
-
-#if !defined(HAVE_STRSEP)
-# define strsep(s, d) stresep((s), (d), 0)
-#endif
-
-/*
- * Filemon is a kernel module which snoops certain syscalls.
- *
- * C chdir
- * E exec
- * F [v]fork
- * L [sym]link
- * M rename
- * R read
- * W write
- * S stat
- *
- * See meta_oodate below - we mainly care about 'E' and 'R'.
- *
- * We can still use meta mode without filemon, but
- * the benefits are more limited.
- */
-#ifdef USE_FILEMON
-# ifndef _PATH_FILEMON
-# define _PATH_FILEMON "/dev/filemon"
-# endif
-
-/*
- * Open the filemon device.
- */
-static void
-filemon_open(BuildMon *pbm)
-{
- int retry;
-
- pbm->mon_fd = pbm->filemon_fd = -1;
- if (!useFilemon)
- return;
-
- for (retry = 5; retry >= 0; retry--) {
- if ((pbm->filemon_fd = open(_PATH_FILEMON, O_RDWR)) >= 0)
- break;
- }
-
- if (pbm->filemon_fd < 0) {
- useFilemon = FALSE;
- warn("Could not open %s", _PATH_FILEMON);
- return;
- }
-
- /*
- * We use a file outside of '.'
- * to avoid a FreeBSD kernel bug where unlink invalidates
- * cwd causing getcwd to do a lot more work.
- * We only care about the descriptor.
- */
- pbm->mon_fd = mkTempFile("filemon.XXXXXX", NULL);
- if (ioctl(pbm->filemon_fd, FILEMON_SET_FD, &pbm->mon_fd) < 0) {
- err(1, "Could not set filemon file descriptor!");
- }
- /* we don't need these once we exec */
- (void)fcntl(pbm->mon_fd, F_SETFD, FD_CLOEXEC);
- (void)fcntl(pbm->filemon_fd, F_SETFD, FD_CLOEXEC);
-}
-
-/*
- * Read the build monitor output file and write records to the target's
- * metadata file.
- */
-static int
-filemon_read(FILE *mfp, int fd)
-{
- char buf[BUFSIZ];
- int n;
- int error;
-
- /* Check if we're not writing to a meta data file.*/
- if (mfp == NULL) {
- if (fd >= 0)
- close(fd); /* not interested */
- return 0;
- }
- /* rewind */
- (void)lseek(fd, (off_t)0, SEEK_SET);
-
- error = 0;
- fprintf(mfp, "\n-- filemon acquired metadata --\n");
-
- while ((n = read(fd, buf, sizeof(buf))) > 0) {
- if ((int)fwrite(buf, 1, n, mfp) < n)
- error = EIO;
- }
- fflush(mfp);
- if (close(fd) < 0)
- error = errno;
- return error;
-}
-#endif
-
-/*
- * when realpath() fails,
- * we use this, to clean up ./ and ../
- */
-static void
-eat_dots(char *buf, size_t bufsz, int dots)
-{
- char *cp;
- char *cp2;
- const char *eat;
- size_t eatlen;
-
- switch (dots) {
- case 1:
- eat = "/./";
- eatlen = 2;
- break;
- case 2:
- eat = "/../";
- eatlen = 3;
- break;
- default:
- return;
- }
-
- do {
- cp = strstr(buf, eat);
- if (cp) {
- cp2 = cp + eatlen;
- if (dots == 2 && cp > buf) {
- do {
- cp--;
- } while (cp > buf && *cp != '/');
- }
- if (*cp == '/') {
- strlcpy(cp, cp2, bufsz - (cp - buf));
- } else {
- return; /* can't happen? */
- }
- }
- } while (cp);
-}
-
-static char *
-meta_name(struct GNode *gn, char *mname, size_t mnamelen,
- const char *dname,
- const char *tname,
- const char *cwd)
-{
- char buf[MAXPATHLEN];
- char *rp;
- char *cp;
- char *tp;
- char *dtp;
- size_t ldname;
-
- /*
- * Weed out relative paths from the target file name.
- * We have to be careful though since if target is a
- * symlink, the result will be unstable.
- * So we use realpath() just to get the dirname, and leave the
- * basename as given to us.
- */
- if ((cp = strrchr(tname, '/'))) {
- if (cached_realpath(tname, buf)) {
- if ((rp = strrchr(buf, '/'))) {
- rp++;
- cp++;
- if (strcmp(cp, rp) != 0)
- strlcpy(rp, cp, sizeof(buf) - (rp - buf));
- }
- tname = buf;
- } else {
- /*
- * We likely have a directory which is about to be made.
- * We pretend realpath() succeeded, to have a chance
- * of generating the same meta file name that we will
- * next time through.
- */
- if (tname[0] == '/') {
- strlcpy(buf, tname, sizeof(buf));
- } else {
- snprintf(buf, sizeof(buf), "%s/%s", cwd, tname);
- }
- eat_dots(buf, sizeof(buf), 1); /* ./ */
- eat_dots(buf, sizeof(buf), 2); /* ../ */
- tname = buf;
- }
- }
- /* on some systems dirname may modify its arg */
- tp = bmake_strdup(tname);
- dtp = dirname(tp);
- if (strcmp(dname, dtp) == 0)
- snprintf(mname, mnamelen, "%s.meta", tname);
- else {
- ldname = strlen(dname);
- if (strncmp(dname, dtp, ldname) == 0 && dtp[ldname] == '/')
- snprintf(mname, mnamelen, "%s/%s.meta", dname, &tname[ldname+1]);
- else
- snprintf(mname, mnamelen, "%s/%s.meta", dname, tname);
-
- /*
- * Replace path separators in the file name after the
- * current object directory path.
- */
- cp = mname + strlen(dname) + 1;
-
- while (*cp != '\0') {
- if (*cp == '/')
- *cp = '_';
- cp++;
- }
- }
- free(tp);
- return (mname);
-}
-
-/*
- * Return true if running ${.MAKE}
- * Bypassed if target is flagged .MAKE
- */
-static int
-is_submake(void *cmdp, void *gnp)
-{
- static char *p_make = NULL;
- static int p_len;
- char *cmd = cmdp;
- GNode *gn = gnp;
- char *mp = NULL;
- char *cp;
- char *cp2;
- int rc = 0; /* keep looking */
-
- if (!p_make) {
- p_make = Var_Value(".MAKE", gn, &cp);
- p_len = strlen(p_make);
- }
- cp = strchr(cmd, '$');
- if ((cp)) {
- mp = Var_Subst(NULL, cmd, gn, VARF_WANTRES);
- cmd = mp;
- }
- cp2 = strstr(cmd, p_make);
- if ((cp2)) {
- switch (cp2[p_len]) {
- case '\0':
- case ' ':
- case '\t':
- case '\n':
- rc = 1;
- break;
- }
- if (cp2 > cmd && rc > 0) {
- switch (cp2[-1]) {
- case ' ':
- case '\t':
- case '\n':
- break;
- default:
- rc = 0; /* no match */
- break;
- }
- }
- }
- free(mp);
- return (rc);
-}
-
-typedef struct meta_file_s {
- FILE *fp;
- GNode *gn;
-} meta_file_t;
-
-static int
-printCMD(void *cmdp, void *mfpp)
-{
- meta_file_t *mfp = mfpp;
- char *cmd = cmdp;
- char *cp = NULL;
-
- if (strchr(cmd, '$')) {
- cmd = cp = Var_Subst(NULL, cmd, mfp->gn, VARF_WANTRES);
- }
- fprintf(mfp->fp, "CMD %s\n", cmd);
- free(cp);
- return 0;
-}
-
-/*
- * Certain node types never get a .meta file
- */
-#define SKIP_META_TYPE(_type) do { \
- if ((gn->type & __CONCAT(OP_, _type))) { \
- if (verbose) { \
- fprintf(debug_file, "Skipping meta for %s: .%s\n", \
- gn->name, __STRING(_type)); \
- } \
- return FALSE; \
- } \
-} while (0)
-
-
-/*
- * Do we need/want a .meta file ?
- */
-static Boolean
-meta_needed(GNode *gn, const char *dname, const char *tname,
- char *objdir, int verbose)
-{
- struct stat fs;
-
- if (verbose)
- verbose = DEBUG(META);
-
- /* This may be a phony node which we don't want meta data for... */
- /* Skip .meta for .BEGIN, .END, .ERROR etc as well. */
- /* Or it may be explicitly flagged as .NOMETA */
- SKIP_META_TYPE(NOMETA);
- /* Unless it is explicitly flagged as .META */
- if (!(gn->type & OP_META)) {
- SKIP_META_TYPE(PHONY);
- SKIP_META_TYPE(SPECIAL);
- SKIP_META_TYPE(MAKE);
- }
-
- /* Check if there are no commands to execute. */
- if (Lst_IsEmpty(gn->commands)) {
- if (verbose)
- fprintf(debug_file, "Skipping meta for %s: no commands\n",
- gn->name);
- return FALSE;
- }
- if ((gn->type & (OP_META|OP_SUBMAKE)) == OP_SUBMAKE) {
- /* OP_SUBMAKE is a bit too aggressive */
- if (Lst_ForEach(gn->commands, is_submake, gn)) {
- if (DEBUG(META))
- fprintf(debug_file, "Skipping meta for %s: .SUBMAKE\n",
- gn->name);
- return FALSE;
- }
- }
-
- /* The object directory may not exist. Check it.. */
- if (cached_stat(dname, &fs) != 0) {
- if (verbose)
- fprintf(debug_file, "Skipping meta for %s: no .OBJDIR\n",
- gn->name);
- return FALSE;
- }
-
- /* make sure these are canonical */
- if (cached_realpath(dname, objdir))
- dname = objdir;
-
- /* If we aren't in the object directory, don't create a meta file. */
- if (!metaCurdirOk && strcmp(curdir, dname) == 0) {
- if (verbose)
- fprintf(debug_file, "Skipping meta for %s: .OBJDIR == .CURDIR\n",
- gn->name);
- return FALSE;
- }
- return TRUE;
-}
-
-
-static FILE *
-meta_create(BuildMon *pbm, GNode *gn)
-{
- meta_file_t mf;
- char buf[MAXPATHLEN];
- char objdir[MAXPATHLEN];
- char **ptr;
- const char *dname;
- const char *tname;
- char *fname;
- const char *cp;
- char *p[4]; /* >= possible uses */
- int i;
-
- mf.fp = NULL;
- i = 0;
-
- dname = Var_Value(".OBJDIR", gn, &p[i++]);
- tname = Var_Value(TARGET, gn, &p[i++]);
-
- /* if this succeeds objdir is realpath of dname */
- if (!meta_needed(gn, dname, tname, objdir, TRUE))
- goto out;
- dname = objdir;
-
- if (metaVerbose) {
- char *mp;
-
- /* Describe the target we are building */
- mp = Var_Subst(NULL, "${" MAKE_META_PREFIX "}", gn, VARF_WANTRES);
- if (*mp)
- fprintf(stdout, "%s\n", mp);
- free(mp);
- }
- /* Get the basename of the target */
- if ((cp = strrchr(tname, '/')) == NULL) {
- cp = tname;
- } else {
- cp++;
- }
-
- fflush(stdout);
-
- if (!writeMeta)
- /* Don't create meta data. */
- goto out;
-
- fname = meta_name(gn, pbm->meta_fname, sizeof(pbm->meta_fname),
- dname, tname, objdir);
-
-#ifdef DEBUG_META_MODE
- if (DEBUG(META))
- fprintf(debug_file, "meta_create: %s\n", fname);
-#endif
-
- if ((mf.fp = fopen(fname, "w")) == NULL)
- err(1, "Could not open meta file '%s'", fname);
-
- fprintf(mf.fp, "# Meta data file %s\n", fname);
-
- mf.gn = gn;
-
- Lst_ForEach(gn->commands, printCMD, &mf);
-
- fprintf(mf.fp, "CWD %s\n", getcwd(buf, sizeof(buf)));
- fprintf(mf.fp, "TARGET %s\n", tname);
-
- if (metaEnv) {
- for (ptr = environ; *ptr != NULL; ptr++)
- fprintf(mf.fp, "ENV %s\n", *ptr);
- }
-
- fprintf(mf.fp, "-- command output --\n");
- fflush(mf.fp);
-
- Var_Append(".MAKE.META.FILES", fname, VAR_GLOBAL);
- Var_Append(".MAKE.META.CREATED", fname, VAR_GLOBAL);
-
- gn->type |= OP_META; /* in case anyone wants to know */
- if (metaSilent) {
- gn->type |= OP_SILENT;
- }
- out:
- for (i--; i >= 0; i--) {
- free(p[i]);
- }
-
- return (mf.fp);
-}
-
-static Boolean
-boolValue(char *s)
-{
- switch(*s) {
- case '0':
- case 'N':
- case 'n':
- case 'F':
- case 'f':
- return FALSE;
- }
- return TRUE;
-}
-
-/*
- * Initialization we need before reading makefiles.
- */
-void
-meta_init(void)
-{
-#ifdef USE_FILEMON
- /* this allows makefiles to test if we have filemon support */
- Var_Set(".MAKE.PATH_FILEMON", _PATH_FILEMON, VAR_GLOBAL, 0);
-#endif
-}
-
-
-#define get_mode_bf(bf, token) \
- if ((cp = strstr(make_mode, token))) \
- bf = boolValue(&cp[sizeof(token) - 1])
-
-/*
- * Initialization we need after reading makefiles.
- */
-void
-meta_mode_init(const char *make_mode)
-{
- static int once = 0;
- char *cp;
-
- useMeta = TRUE;
- useFilemon = TRUE;
- writeMeta = TRUE;
-
- if (make_mode) {
- if (strstr(make_mode, "env"))
- metaEnv = TRUE;
- if (strstr(make_mode, "verb"))
- metaVerbose = TRUE;
- if (strstr(make_mode, "read"))
- writeMeta = FALSE;
- if (strstr(make_mode, "nofilemon"))
- useFilemon = FALSE;
- if (strstr(make_mode, "ignore-cmd"))
- metaIgnoreCMDs = TRUE;
- if (useFilemon)
- get_mode_bf(filemonMissing, "missing-filemon=");
- get_mode_bf(metaCurdirOk, "curdirok=");
- get_mode_bf(metaMissing, "missing-meta=");
- get_mode_bf(metaSilent, "silent=");
- }
- if (metaVerbose && !Var_Exists(MAKE_META_PREFIX, VAR_GLOBAL)) {
- /*
- * The default value for MAKE_META_PREFIX
- * prints the absolute path of the target.
- * This works be cause :H will generate '.' if there is no /
- * and :tA will resolve that to cwd.
- */
- Var_Set(MAKE_META_PREFIX, "Building ${.TARGET:H:tA}/${.TARGET:T}", VAR_GLOBAL, 0);
- }
- if (once)
- return;
- once = 1;
- memset(&Mybm, 0, sizeof(Mybm));
- /*
- * We consider ourselves master of all within ${.MAKE.META.BAILIWICK}
- */
- metaBailiwick = Lst_Init(FALSE);
- metaBailiwickStr = Var_Subst(NULL, "${.MAKE.META.BAILIWICK:O:u:tA}",
- VAR_GLOBAL, VARF_WANTRES);
- if (metaBailiwickStr) {
- str2Lst_Append(metaBailiwick, metaBailiwickStr, NULL);
- }
- /*
- * We ignore any paths that start with ${.MAKE.META.IGNORE_PATHS}
- */
- metaIgnorePaths = Lst_Init(FALSE);
- Var_Append(MAKE_META_IGNORE_PATHS,
- "/dev /etc /proc /tmp /var/run /var/tmp ${TMPDIR}", VAR_GLOBAL);
- metaIgnorePathsStr = Var_Subst(NULL,
- "${" MAKE_META_IGNORE_PATHS ":O:u:tA}", VAR_GLOBAL,
- VARF_WANTRES);
- if (metaIgnorePathsStr) {
- str2Lst_Append(metaIgnorePaths, metaIgnorePathsStr, NULL);
- }
-
- /*
- * We ignore any paths that match ${.MAKE.META.IGNORE_PATTERNS}
- */
- cp = NULL;
- if (Var_Value(MAKE_META_IGNORE_PATTERNS, VAR_GLOBAL, &cp)) {
- metaIgnorePatterns = TRUE;
- free(cp);
- }
- cp = NULL;
- if (Var_Value(MAKE_META_IGNORE_FILTER, VAR_GLOBAL, &cp)) {
- metaIgnoreFilter = TRUE;
- free(cp);
- }
-}
-
-/*
- * In each case below we allow for job==NULL
- */
-void
-meta_job_start(Job *job, GNode *gn)
-{
- BuildMon *pbm;
-
- if (job != NULL) {
- pbm = &job->bm;
- } else {
- pbm = &Mybm;
- }
- pbm->mfp = meta_create(pbm, gn);
-#ifdef USE_FILEMON_ONCE
- /* compat mode we open the filemon dev once per command */
- if (job == NULL)
- return;
-#endif
-#ifdef USE_FILEMON
- if (pbm->mfp != NULL && useFilemon) {
- filemon_open(pbm);
- } else {
- pbm->mon_fd = pbm->filemon_fd = -1;
- }
-#endif
-}
-
-/*
- * The child calls this before doing anything.
- * It does not disturb our state.
- */
-void
-meta_job_child(Job *job)
-{
-#ifdef USE_FILEMON
- BuildMon *pbm;
-
- if (job != NULL) {
- pbm = &job->bm;
- } else {
- pbm = &Mybm;
- }
- if (pbm->mfp != NULL) {
- close(fileno(pbm->mfp));
- if (useFilemon) {
- pid_t pid;
-
- pid = getpid();
- if (ioctl(pbm->filemon_fd, FILEMON_SET_PID, &pid) < 0) {
- err(1, "Could not set filemon pid!");
- }
- }
- }
-#endif
-}
-
-void
-meta_job_error(Job *job, GNode *gn, int flags, int status)
-{
- char cwd[MAXPATHLEN];
- BuildMon *pbm;
-
- if (job != NULL) {
- pbm = &job->bm;
- if (!gn)
- gn = job->node;
- } else {
- pbm = &Mybm;
- }
- if (pbm->mfp != NULL) {
- fprintf(pbm->mfp, "\n*** Error code %d%s\n",
- status,
- (flags & JOB_IGNERR) ?
- "(ignored)" : "");
- }
- if (gn) {
- Var_Set(".ERROR_TARGET", gn->path ? gn->path : gn->name, VAR_GLOBAL, 0);
- }
- getcwd(cwd, sizeof(cwd));
- Var_Set(".ERROR_CWD", cwd, VAR_GLOBAL, 0);
- if (pbm->meta_fname[0]) {
- Var_Set(".ERROR_META_FILE", pbm->meta_fname, VAR_GLOBAL, 0);
- }
- meta_job_finish(job);
-}
-
-void
-meta_job_output(Job *job, char *cp, const char *nl)
-{
- BuildMon *pbm;
-
- if (job != NULL) {
- pbm = &job->bm;
- } else {
- pbm = &Mybm;
- }
- if (pbm->mfp != NULL) {
- if (metaVerbose) {
- static char *meta_prefix = NULL;
- static int meta_prefix_len;
-
- if (!meta_prefix) {
- char *cp2;
-
- meta_prefix = Var_Subst(NULL, "${" MAKE_META_PREFIX "}",
- VAR_GLOBAL, VARF_WANTRES);
- if ((cp2 = strchr(meta_prefix, '$')))
- meta_prefix_len = cp2 - meta_prefix;
- else
- meta_prefix_len = strlen(meta_prefix);
- }
- if (strncmp(cp, meta_prefix, meta_prefix_len) == 0) {
- cp = strchr(cp+1, '\n');
- if (!cp++)
- return;
- }
- }
- fprintf(pbm->mfp, "%s%s", cp, nl);
- }
-}
-
-int
-meta_cmd_finish(void *pbmp)
-{
- int error = 0;
- BuildMon *pbm = pbmp;
-#ifdef USE_FILEMON
- int x;
-#endif
-
- if (!pbm)
- pbm = &Mybm;
-
-#ifdef USE_FILEMON
- if (pbm->filemon_fd >= 0) {
- if (close(pbm->filemon_fd) < 0)
- error = errno;
- x = filemon_read(pbm->mfp, pbm->mon_fd);
- if (error == 0 && x != 0)
- error = x;
- pbm->filemon_fd = pbm->mon_fd = -1;
- } else
-#endif
- fprintf(pbm->mfp, "\n"); /* ensure end with newline */
- return error;
-}
-
-int
-meta_job_finish(Job *job)
-{
- BuildMon *pbm;
- int error = 0;
- int x;
-
- if (job != NULL) {
- pbm = &job->bm;
- } else {
- pbm = &Mybm;
- }
- if (pbm->mfp != NULL) {
- error = meta_cmd_finish(pbm);
- x = fclose(pbm->mfp);
- if (error == 0 && x != 0)
- error = errno;
- pbm->mfp = NULL;
- pbm->meta_fname[0] = '\0';
- }
- return error;
-}
-
-void
-meta_finish(void)
-{
- Lst_Destroy(metaBailiwick, NULL);
- free(metaBailiwickStr);
- Lst_Destroy(metaIgnorePaths, NULL);
- free(metaIgnorePathsStr);
-}
-
-/*
- * Fetch a full line from fp - growing bufp if needed
- * Return length in bufp.
- */
-static int
-fgetLine(char **bufp, size_t *szp, int o, FILE *fp)
-{
- char *buf = *bufp;
- size_t bufsz = *szp;
- struct stat fs;
- int x;
-
- if (fgets(&buf[o], bufsz - o, fp) != NULL) {
- check_newline:
- x = o + strlen(&buf[o]);
- if (buf[x - 1] == '\n')
- return x;
- /*
- * We need to grow the buffer.
- * The meta file can give us a clue.
- */
- if (fstat(fileno(fp), &fs) == 0) {
- size_t newsz;
- char *p;
-
- newsz = ROUNDUP((fs.st_size / 2), BUFSIZ);
- if (newsz <= bufsz)
- newsz = ROUNDUP(fs.st_size, BUFSIZ);
- if (newsz <= bufsz)
- return x; /* truncated */
- if (DEBUG(META))
- fprintf(debug_file, "growing buffer %zu -> %zu\n",
- bufsz, newsz);
- p = bmake_realloc(buf, newsz);
- if (p) {
- *bufp = buf = p;
- *szp = bufsz = newsz;
- /* fetch the rest */
- if (!fgets(&buf[x], bufsz - x, fp))
- return x; /* truncated! */
- goto check_newline;
- }
- }
- }
- return 0;
-}
-
-/* Lst_ForEach wants 1 to stop search */
-static int
-prefix_match(void *p, void *q)
-{
- const char *prefix = p;
- const char *path = q;
- size_t n = strlen(prefix);
-
- return (0 == strncmp(path, prefix, n));
-}
-
-/*
- * looking for exact or prefix/ match to
- * Lst_Find wants 0 to stop search
- */
-static int
-path_match(const void *p, const void *q)
-{
- const char *prefix = q;
- const char *path = p;
- size_t n = strlen(prefix);
- int rc;
-
- if ((rc = strncmp(path, prefix, n)) == 0) {
- switch (path[n]) {
- case '\0':
- case '/':
- break;
- default:
- rc = 1;
- break;
- }
- }
- return rc;
-}
-
-/* Lst_Find wants 0 to stop search */
-static int
-string_match(const void *p, const void *q)
-{
- const char *p1 = p;
- const char *p2 = q;
-
- return strcmp(p1, p2);
-}
-
-
-static int
-meta_ignore(GNode *gn, const char *p)
-{
- char fname[MAXPATHLEN];
-
- if (p == NULL)
- return TRUE;
-
- if (*p == '/') {
- cached_realpath(p, fname); /* clean it up */
- if (Lst_ForEach(metaIgnorePaths, prefix_match, fname)) {
-#ifdef DEBUG_META_MODE
- if (DEBUG(META))
- fprintf(debug_file, "meta_oodate: ignoring path: %s\n",
- p);
-#endif
- return TRUE;
- }
- }
-
- if (metaIgnorePatterns) {
- char *pm;
-
- Var_Set(".p.", p, gn, 0);
- pm = Var_Subst(NULL,
- "${" MAKE_META_IGNORE_PATTERNS ":@m@${.p.:M$m}@}",
- gn, VARF_WANTRES);
- if (*pm) {
-#ifdef DEBUG_META_MODE
- if (DEBUG(META))
- fprintf(debug_file, "meta_oodate: ignoring pattern: %s\n",
- p);
-#endif
- free(pm);
- return TRUE;
- }
- free(pm);
- }
-
- if (metaIgnoreFilter) {
- char *fm;
-
- /* skip if filter result is empty */
- snprintf(fname, sizeof(fname),
- "${%s:L:${%s:ts:}}",
- p, MAKE_META_IGNORE_FILTER);
- fm = Var_Subst(NULL, fname, gn, VARF_WANTRES);
- if (*fm == '\0') {
-#ifdef DEBUG_META_MODE
- if (DEBUG(META))
- fprintf(debug_file, "meta_oodate: ignoring filtered: %s\n",
- p);
-#endif
- free(fm);
- return TRUE;
- }
- free(fm);
- }
- return FALSE;
-}
-
-/*
- * When running with 'meta' functionality, a target can be out-of-date
- * if any of the references in its meta data file is more recent.
- * We have to track the latestdir on a per-process basis.
- */
-#define LCWD_VNAME_FMT ".meta.%d.lcwd"
-#define LDIR_VNAME_FMT ".meta.%d.ldir"
-
-/*
- * It is possible that a .meta file is corrupted,
- * if we detect this we want to reproduce it.
- * Setting oodate TRUE will have that effect.
- */
-#define CHECK_VALID_META(p) if (!(p && *p)) { \
- warnx("%s: %d: malformed", fname, lineno); \
- oodate = TRUE; \
- continue; \
- }
-
-#define DEQUOTE(p) if (*p == '\'') { \
- char *ep; \
- p++; \
- if ((ep = strchr(p, '\''))) \
- *ep = '\0'; \
- }
-
-Boolean
-meta_oodate(GNode *gn, Boolean oodate)
-{
- static char *tmpdir = NULL;
- static char cwd[MAXPATHLEN];
- char lcwd_vname[64];
- char ldir_vname[64];
- char lcwd[MAXPATHLEN];
- char latestdir[MAXPATHLEN];
- char fname[MAXPATHLEN];
- char fname1[MAXPATHLEN];
- char fname2[MAXPATHLEN];
- char fname3[MAXPATHLEN];
- const char *dname;
- const char *tname;
- char *p;
- char *cp;
- char *link_src;
- char *move_target;
- static size_t cwdlen = 0;
- static size_t tmplen = 0;
- FILE *fp;
- Boolean needOODATE = FALSE;
- Lst missingFiles;
- char *pa[4]; /* >= possible uses */
- int i;
- int have_filemon = FALSE;
-
- if (oodate)
- return oodate; /* we're done */
-
- i = 0;
-
- dname = Var_Value(".OBJDIR", gn, &pa[i++]);
- tname = Var_Value(TARGET, gn, &pa[i++]);
-
- /* if this succeeds fname3 is realpath of dname */
- if (!meta_needed(gn, dname, tname, fname3, FALSE))
- goto oodate_out;
- dname = fname3;
-
- missingFiles = Lst_Init(FALSE);
-
- /*
- * We need to check if the target is out-of-date. This includes
- * checking if the expanded command has changed. This in turn
- * requires that all variables are set in the same way that they
- * would be if the target needs to be re-built.
- */
- Make_DoAllVar(gn);
-
- meta_name(gn, fname, sizeof(fname), dname, tname, dname);
-
-#ifdef DEBUG_META_MODE
- if (DEBUG(META))
- fprintf(debug_file, "meta_oodate: %s\n", fname);
-#endif
-
- if ((fp = fopen(fname, "r")) != NULL) {
- static char *buf = NULL;
- static size_t bufsz;
- int lineno = 0;
- int lastpid = 0;
- int pid;
- int x;
- LstNode ln;
- struct stat fs;
-
- if (!buf) {
- bufsz = 8 * BUFSIZ;
- buf = bmake_malloc(bufsz);
- }
-
- if (!cwdlen) {
- if (getcwd(cwd, sizeof(cwd)) == NULL)
- err(1, "Could not get current working directory");
- cwdlen = strlen(cwd);
- }
- strlcpy(lcwd, cwd, sizeof(lcwd));
- strlcpy(latestdir, cwd, sizeof(latestdir));
-
- if (!tmpdir) {
- tmpdir = getTmpdir();
- tmplen = strlen(tmpdir);
- }
-
- /* we want to track all the .meta we read */
- Var_Append(".MAKE.META.FILES", fname, VAR_GLOBAL);
-
- ln = Lst_First(gn->commands);
- while (!oodate && (x = fgetLine(&buf, &bufsz, 0, fp)) > 0) {
- lineno++;
- if (buf[x - 1] == '\n')
- buf[x - 1] = '\0';
- else {
- warnx("%s: %d: line truncated at %u", fname, lineno, x);
- oodate = TRUE;
- break;
- }
- link_src = NULL;
- move_target = NULL;
- /* Find the start of the build monitor section. */
- if (!have_filemon) {
- if (strncmp(buf, "-- filemon", 10) == 0) {
- have_filemon = TRUE;
- continue;
- }
- if (strncmp(buf, "# buildmon", 10) == 0) {
- have_filemon = TRUE;
- continue;
- }
- }
-
- /* Delimit the record type. */
- p = buf;
-#ifdef DEBUG_META_MODE
- if (DEBUG(META))
- fprintf(debug_file, "%s: %d: %s\n", fname, lineno, buf);
-#endif
- strsep(&p, " ");
- if (have_filemon) {
- /*
- * We are in the 'filemon' output section.
- * Each record from filemon follows the general form:
- *
- * <key> <pid> <data>
- *
- * Where:
- * <key> is a single letter, denoting the syscall.
- * <pid> is the process that made the syscall.
- * <data> is the arguments (of interest).
- */
- switch(buf[0]) {
- case '#': /* comment */
- case 'V': /* version */
- break;
- default:
- /*
- * We need to track pathnames per-process.
- *
- * Each process run by make, starts off in the 'CWD'
- * recorded in the .meta file, if it chdirs ('C')
- * elsewhere we need to track that - but only for
- * that process. If it forks ('F'), we initialize
- * the child to have the same cwd as its parent.
- *
- * We also need to track the 'latestdir' of
- * interest. This is usually the same as cwd, but
- * not if a process is reading directories.
- *
- * Each time we spot a different process ('pid')
- * we save the current value of 'latestdir' in a
- * variable qualified by 'lastpid', and
- * re-initialize 'latestdir' to any pre-saved
- * value for the current 'pid' and 'CWD' if none.
- */
- CHECK_VALID_META(p);
- pid = atoi(p);
- if (pid > 0 && pid != lastpid) {
- char *ldir;
- char *tp;
-
- if (lastpid > 0) {
- /* We need to remember these. */
- Var_Set(lcwd_vname, lcwd, VAR_GLOBAL, 0);
- Var_Set(ldir_vname, latestdir, VAR_GLOBAL, 0);
- }
- snprintf(lcwd_vname, sizeof(lcwd_vname), LCWD_VNAME_FMT, pid);
- snprintf(ldir_vname, sizeof(ldir_vname), LDIR_VNAME_FMT, pid);
- lastpid = pid;
- ldir = Var_Value(ldir_vname, VAR_GLOBAL, &tp);
- if (ldir) {
- strlcpy(latestdir, ldir, sizeof(latestdir));
- free(tp);
- }
- ldir = Var_Value(lcwd_vname, VAR_GLOBAL, &tp);
- if (ldir) {
- strlcpy(lcwd, ldir, sizeof(lcwd));
- free(tp);
- }
- }
- /* Skip past the pid. */
- if (strsep(&p, " ") == NULL)
- continue;
-#ifdef DEBUG_META_MODE
- if (DEBUG(META))
- fprintf(debug_file, "%s: %d: %d: %c: cwd=%s lcwd=%s ldir=%s\n",
- fname, lineno,
- pid, buf[0], cwd, lcwd, latestdir);
-#endif
- break;
- }
-
- CHECK_VALID_META(p);
-
- /* Process according to record type. */
- switch (buf[0]) {
- case 'X': /* eXit */
- Var_Delete(lcwd_vname, VAR_GLOBAL);
- Var_Delete(ldir_vname, VAR_GLOBAL);
- lastpid = 0; /* no need to save ldir_vname */
- break;
-
- case 'F': /* [v]Fork */
- {
- char cldir[64];
- int child;
-
- child = atoi(p);
- if (child > 0) {
- snprintf(cldir, sizeof(cldir), LCWD_VNAME_FMT, child);
- Var_Set(cldir, lcwd, VAR_GLOBAL, 0);
- snprintf(cldir, sizeof(cldir), LDIR_VNAME_FMT, child);
- Var_Set(cldir, latestdir, VAR_GLOBAL, 0);
-#ifdef DEBUG_META_MODE
- if (DEBUG(META))
- fprintf(debug_file, "%s: %d: %d: cwd=%s lcwd=%s ldir=%s\n",
- fname, lineno,
- child, cwd, lcwd, latestdir);
-#endif
- }
- }
- break;
-
- case 'C': /* Chdir */
- /* Update lcwd and latest directory. */
- strlcpy(latestdir, p, sizeof(latestdir));
- strlcpy(lcwd, p, sizeof(lcwd));
- Var_Set(lcwd_vname, lcwd, VAR_GLOBAL, 0);
- Var_Set(ldir_vname, lcwd, VAR_GLOBAL, 0);
-#ifdef DEBUG_META_MODE
- if (DEBUG(META))
- fprintf(debug_file, "%s: %d: cwd=%s ldir=%s\n", fname, lineno, cwd, lcwd);
-#endif
- break;
-
- case 'M': /* renaMe */
- /*
- * For 'M'oves we want to check
- * the src as for 'R'ead
- * and the target as for 'W'rite.
- */
- cp = p; /* save this for a second */
- /* now get target */
- if (strsep(&p, " ") == NULL)
- continue;
- CHECK_VALID_META(p);
- move_target = p;
- p = cp;
- /* 'L' and 'M' put single quotes around the args */
- DEQUOTE(p);
- DEQUOTE(move_target);
- /* FALLTHROUGH */
- case 'D': /* unlink */
- if (*p == '/' && !Lst_IsEmpty(missingFiles)) {
- /* remove any missingFiles entries that match p */
- if ((ln = Lst_Find(missingFiles, p,
- path_match)) != NULL) {
- LstNode nln;
- char *tp;
-
- do {
- nln = Lst_FindFrom(missingFiles, Lst_Succ(ln),
- p, path_match);
- tp = Lst_Datum(ln);
- Lst_Remove(missingFiles, ln);
- free(tp);
- } while ((ln = nln) != NULL);
- }
- }
- if (buf[0] == 'M') {
- /* the target of the mv is a file 'W'ritten */
-#ifdef DEBUG_META_MODE
- if (DEBUG(META))
- fprintf(debug_file, "meta_oodate: M %s -> %s\n",
- p, move_target);
-#endif
- p = move_target;
- goto check_write;
- }
- break;
- case 'L': /* Link */
- /*
- * For 'L'inks check
- * the src as for 'R'ead
- * and the target as for 'W'rite.
- */
- link_src = p;
- /* now get target */
- if (strsep(&p, " ") == NULL)
- continue;
- CHECK_VALID_META(p);
- /* 'L' and 'M' put single quotes around the args */
- DEQUOTE(p);
- DEQUOTE(link_src);
-#ifdef DEBUG_META_MODE
- if (DEBUG(META))
- fprintf(debug_file, "meta_oodate: L %s -> %s\n",
- link_src, p);
-#endif
- /* FALLTHROUGH */
- case 'W': /* Write */
- check_write:
- /*
- * If a file we generated within our bailiwick
- * but outside of .OBJDIR is missing,
- * we need to do it again.
- */
- /* ignore non-absolute paths */
- if (*p != '/')
- break;
-
- if (Lst_IsEmpty(metaBailiwick))
- break;
-
- /* ignore cwd - normal dependencies handle those */
- if (strncmp(p, cwd, cwdlen) == 0)
- break;
-
- if (!Lst_ForEach(metaBailiwick, prefix_match, p))
- break;
-
- /* tmpdir might be within */
- if (tmplen > 0 && strncmp(p, tmpdir, tmplen) == 0)
- break;
-
- /* ignore anything containing the string "tmp" */
- if ((strstr("tmp", p)))
- break;
-
- if ((link_src != NULL && cached_lstat(p, &fs) < 0) ||
- (link_src == NULL && cached_stat(p, &fs) < 0)) {
- if (!meta_ignore(gn, p)) {
- if (Lst_Find(missingFiles, p, string_match) == NULL)
- Lst_AtEnd(missingFiles, bmake_strdup(p));
- }
- }
- break;
- check_link_src:
- p = link_src;
- link_src = NULL;
-#ifdef DEBUG_META_MODE
- if (DEBUG(META))
- fprintf(debug_file, "meta_oodate: L src %s\n", p);
-#endif
- /* FALLTHROUGH */
- case 'R': /* Read */
- case 'E': /* Exec */
- /*
- * Check for runtime files that can't
- * be part of the dependencies because
- * they are _expected_ to change.
- */
- if (meta_ignore(gn, p))
- break;
-
- /*
- * The rest of the record is the file name.
- * Check if it's not an absolute path.
- */
- {
- char *sdirs[4];
- char **sdp;
- int sdx = 0;
- int found = 0;
-
- if (*p == '/') {
- sdirs[sdx++] = p; /* done */
- } else {
- if (strcmp(".", p) == 0)
- continue; /* no point */
-
- /* Check vs latestdir */
- snprintf(fname1, sizeof(fname1), "%s/%s", latestdir, p);
- sdirs[sdx++] = fname1;
-
- if (strcmp(latestdir, lcwd) != 0) {
- /* Check vs lcwd */
- snprintf(fname2, sizeof(fname2), "%s/%s", lcwd, p);
- sdirs[sdx++] = fname2;
- }
- if (strcmp(lcwd, cwd) != 0) {
- /* Check vs cwd */
- snprintf(fname3, sizeof(fname3), "%s/%s", cwd, p);
- sdirs[sdx++] = fname3;
- }
- }
- sdirs[sdx++] = NULL;
-
- for (sdp = sdirs; *sdp && !found; sdp++) {
-#ifdef DEBUG_META_MODE
- if (DEBUG(META))
- fprintf(debug_file, "%s: %d: looking for: %s\n", fname, lineno, *sdp);
-#endif
- if (cached_stat(*sdp, &fs) == 0) {
- found = 1;
- p = *sdp;
- }
- }
- if (found) {
-#ifdef DEBUG_META_MODE
- if (DEBUG(META))
- fprintf(debug_file, "%s: %d: found: %s\n", fname, lineno, p);
-#endif
- if (!S_ISDIR(fs.st_mode) &&
- fs.st_mtime > gn->mtime) {
- if (DEBUG(META))
- fprintf(debug_file, "%s: %d: file '%s' is newer than the target...\n", fname, lineno, p);
- oodate = TRUE;
- } else if (S_ISDIR(fs.st_mode)) {
- /* Update the latest directory. */
- cached_realpath(p, latestdir);
- }
- } else if (errno == ENOENT && *p == '/' &&
- strncmp(p, cwd, cwdlen) != 0) {
- /*
- * A referenced file outside of CWD is missing.
- * We cannot catch every eventuality here...
- */
- if (Lst_Find(missingFiles, p, string_match) == NULL)
- Lst_AtEnd(missingFiles, bmake_strdup(p));
- }
- }
- if (buf[0] == 'E') {
- /* previous latestdir is no longer relevant */
- strlcpy(latestdir, lcwd, sizeof(latestdir));
- }
- break;
- default:
- break;
- }
- if (!oodate && buf[0] == 'L' && link_src != NULL)
- goto check_link_src;
- } else if (strcmp(buf, "CMD") == 0) {
- /*
- * Compare the current command with the one in the
- * meta data file.
- */
- if (ln == NULL) {
- if (DEBUG(META))
- fprintf(debug_file, "%s: %d: there were more build commands in the meta data file than there are now...\n", fname, lineno);
- oodate = TRUE;
- } else {
- char *cmd = (char *)Lst_Datum(ln);
- Boolean hasOODATE = FALSE;
-
- if (strstr(cmd, "$?"))
- hasOODATE = TRUE;
- else if ((cp = strstr(cmd, ".OODATE"))) {
- /* check for $[{(].OODATE[:)}] */
- if (cp > cmd + 2 && cp[-2] == '$')
- hasOODATE = TRUE;
- }
- if (hasOODATE) {
- needOODATE = TRUE;
- if (DEBUG(META))
- fprintf(debug_file, "%s: %d: cannot compare command using .OODATE\n", fname, lineno);
- }
- cmd = Var_Subst(NULL, cmd, gn, VARF_WANTRES|VARF_UNDEFERR);
-
- if ((cp = strchr(cmd, '\n'))) {
- int n;
-
- /*
- * This command contains newlines, we need to
- * fetch more from the .meta file before we
- * attempt a comparison.
- */
- /* first put the newline back at buf[x - 1] */
- buf[x - 1] = '\n';
- do {
- /* now fetch the next line */
- if ((n = fgetLine(&buf, &bufsz, x, fp)) <= 0)
- break;
- x = n;
- lineno++;
- if (buf[x - 1] != '\n') {
- warnx("%s: %d: line truncated at %u", fname, lineno, x);
- break;
- }
- cp = strchr(++cp, '\n');
- } while (cp);
- if (buf[x - 1] == '\n')
- buf[x - 1] = '\0';
- }
- if (!hasOODATE &&
- !(gn->type & OP_NOMETA_CMP) &&
- strcmp(p, cmd) != 0) {
- if (DEBUG(META))
- fprintf(debug_file, "%s: %d: a build command has changed\n%s\nvs\n%s\n", fname, lineno, p, cmd);
- if (!metaIgnoreCMDs)
- oodate = TRUE;
- }
- free(cmd);
- ln = Lst_Succ(ln);
- }
- } else if (strcmp(buf, "CWD") == 0) {
- /*
- * Check if there are extra commands now
- * that weren't in the meta data file.
- */
- if (!oodate && ln != NULL) {
- if (DEBUG(META))
- fprintf(debug_file, "%s: %d: there are extra build commands now that weren't in the meta data file\n", fname, lineno);
- oodate = TRUE;
- }
- if (strcmp(p, cwd) != 0) {
- if (DEBUG(META))
- fprintf(debug_file, "%s: %d: the current working directory has changed from '%s' to '%s'\n", fname, lineno, p, curdir);
- oodate = TRUE;
- }
- }
- }
-
- fclose(fp);
- if (!Lst_IsEmpty(missingFiles)) {
- if (DEBUG(META))
- fprintf(debug_file, "%s: missing files: %s...\n",
- fname, (char *)Lst_Datum(Lst_First(missingFiles)));
- oodate = TRUE;
- }
- if (!oodate && !have_filemon && filemonMissing) {
- if (DEBUG(META))
- fprintf(debug_file, "%s: missing filemon data\n", fname);
- oodate = TRUE;
- }
- } else {
- if (writeMeta && metaMissing) {
- cp = NULL;
-
- /* if target is in .CURDIR we do not need a meta file */
- if (gn->path && (cp = strrchr(gn->path, '/')) && cp > gn->path) {
- if (strncmp(curdir, gn->path, (cp - gn->path)) != 0) {
- cp = NULL; /* not in .CURDIR */
- }
- }
- if (!cp) {
- if (DEBUG(META))
- fprintf(debug_file, "%s: required but missing\n", fname);
- oodate = TRUE;
- needOODATE = TRUE; /* assume the worst */
- }
- }
- }
-
- Lst_Destroy(missingFiles, (FreeProc *)free);
-
- if (oodate && needOODATE) {
- /*
- * Target uses .OODATE which is empty; or we wouldn't be here.
- * We have decided it is oodate, so .OODATE needs to be set.
- * All we can sanely do is set it to .ALLSRC.
- */
- Var_Delete(OODATE, gn);
- Var_Set(OODATE, Var_Value(ALLSRC, gn, &cp), gn, 0);
- free(cp);
- }
-
- oodate_out:
- for (i--; i >= 0; i--) {
- free(pa[i]);
- }
- return oodate;
-}
-
-/* support for compat mode */
-
-static int childPipe[2];
-
-void
-meta_compat_start(void)
-{
-#ifdef USE_FILEMON_ONCE
- /*
- * We need to re-open filemon for each cmd.
- */
- BuildMon *pbm = &Mybm;
-
- if (pbm->mfp != NULL && useFilemon) {
- filemon_open(pbm);
- } else {
- pbm->mon_fd = pbm->filemon_fd = -1;
- }
-#endif
- if (pipe(childPipe) < 0)
- Punt("Cannot create pipe: %s", strerror(errno));
- /* Set close-on-exec flag for both */
- (void)fcntl(childPipe[0], F_SETFD, FD_CLOEXEC);
- (void)fcntl(childPipe[1], F_SETFD, FD_CLOEXEC);
-}
-
-void
-meta_compat_child(void)
-{
- meta_job_child(NULL);
- if (dup2(childPipe[1], 1) < 0 ||
- dup2(1, 2) < 0) {
- execError("dup2", "pipe");
- _exit(1);
- }
-}
-
-void
-meta_compat_parent(void)
-{
- FILE *fp;
- char buf[BUFSIZ];
-
- close(childPipe[1]); /* child side */
- fp = fdopen(childPipe[0], "r");
- while (fgets(buf, sizeof(buf), fp)) {
- meta_job_output(NULL, buf, "");
- printf("%s", buf);
- fflush(stdout);
- }
- fclose(fp);
-}
-
-#endif /* USE_META */
diff --git a/usr.bin/make/meta.h b/usr.bin/make/meta.h
deleted file mode 100644
index 8f1018e..0000000
--- a/usr.bin/make/meta.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/* $NetBSD: meta.h,v 1.5 2016/05/12 20:28:34 sjg Exp $ */
-
-/*
- * Things needed for 'meta' mode.
- */
-/*
- * Copyright (c) 2009-2010, Juniper Networks, Inc.
- *
- * 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 copyright holders 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 COPYRIGHT HOLDERS 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 COPYRIGHT
- * OWNER 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.
- */
-
-typedef struct BuildMon {
- char meta_fname[MAXPATHLEN];
- int filemon_fd;
- int mon_fd;
- FILE *mfp;
-} BuildMon;
-
-extern Boolean useMeta;
-
-struct Job; /* not defined yet */
-void meta_init(void);
-void meta_finish(void);
-void meta_mode_init(const char *);
-void meta_job_start(struct Job *, GNode *);
-void meta_job_child(struct Job *);
-void meta_job_error(struct Job *, GNode *, int, int);
-void meta_job_output(struct Job *, char *, const char *);
-int meta_cmd_finish(void *);
-int meta_job_finish(struct Job *);
-Boolean meta_oodate(GNode *, Boolean);
-void meta_compat_start(void);
-void meta_compat_child(void);
-void meta_compat_parent(void);
diff --git a/usr.bin/make/metachar.c b/usr.bin/make/metachar.c
deleted file mode 100644
index 4960338..0000000
--- a/usr.bin/make/metachar.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/* $NetBSD: metachar.c,v 1.5 2015/06/19 08:03:35 mlelstv Exp $ */
-
-/*-
- * Copyright (c) 2015 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * This code is derived from software contributed to The NetBSD Foundation
- * by Christos Zoulas.
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
- */
-
-#if HAVE_NBTOOL_CONFIG_H
-#include "nbtool_config.h"
-#endif
-
-#if defined(MAKE_NATIVE) || defined(HAVE_NBTOOL_CONFIG_H)
-#include <sys/cdefs.h>
-#endif
-
-#if defined(__RCSID) && !defined(lint)
-__RCSID("$NetBSD: metachar.c,v 1.5 2015/06/19 08:03:35 mlelstv Exp $");
-#endif
-
-#include "metachar.h"
-/*
- * The following array is used to make a fast determination of which
- * characters are interpreted specially by the shell. If a command
- * contains any of these characters, it is executed by the shell, not
- * directly by us.
- *
- * perhaps move it to ctype?
- */
-
-unsigned char _metachar[128] = {
-// nul soh stx etx eot enq ack bel
- 1, 0, 0, 0, 0, 0, 0, 0,
-// bs ht nl vt np cr so si
- 0, 0, 1, 0, 0, 0, 0, 0,
-// dle dc1 dc2 dc3 dc4 nak syn etb
- 0, 0, 0, 0, 0, 0, 0, 0,
-// can em sub esc fs gs rs us
- 0, 0, 0, 0, 0, 0, 0, 0,
-// sp ! " # $ % & '
- 0, 1, 1, 1, 1, 0, 1, 1,
-// ( ) * + , - . /
- 1, 1, 1, 0, 0, 0, 0, 0,
-// 0 1 2 3 4 5 6 7
- 0, 0, 0, 0, 0, 0, 0, 0,
-// 8 9 : ; < = > ?
- 0, 0, 0, 1, 1, 0, 1, 1,
-// @ A B C D E F G
- 0, 0, 0, 0, 0, 0, 0, 0,
-// H I J K L M N O
- 0, 0, 0, 0, 0, 0, 0, 0,
-// P Q R S T U V W
- 0, 0, 0, 0, 0, 0, 0, 0,
-// X Y Z [ \ ] ^ _
- 0, 0, 0, 1, 1, 1, 1, 0,
-// ` a b c d e f g
- 1, 0, 0, 0, 0, 0, 0, 0,
-// h i j k l m n o
- 0, 0, 0, 0, 0, 0, 0, 0,
-// p q r s t u v w
- 0, 0, 0, 0, 0, 0, 0, 0,
-// x y z { | } ~ del
- 0, 0, 0, 1, 1, 1, 1, 0,
-};
-
diff --git a/usr.bin/make/metachar.h b/usr.bin/make/metachar.h
deleted file mode 100644
index db88d67..0000000
--- a/usr.bin/make/metachar.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/* $NetBSD: metachar.h,v 1.4 2015/06/21 20:26:02 christos Exp $ */
-
-/*-
- * Copyright (c) 2015 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * This code is derived from software contributed to The NetBSD Foundation
- * by Christos Zoulas.
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
- */
-#ifndef _METACHAR_H
-#define _METACHAR_H
-
-#include <ctype.h>
-
-extern unsigned char _metachar[];
-
-#define ismeta(c) _metachar[(c) & 0x7f]
-
-static inline int
-hasmeta(const char *cmd)
-{
- while (!ismeta(*cmd))
- cmd++;
-
- return *cmd != '\0';
-}
-
-static inline int
-needshell(const char *cmd, int white)
-{
- while (!ismeta(*cmd) && *cmd != ':' && *cmd != '=') {
- if (white && isspace((unsigned char)*cmd))
- break;
- cmd++;
- }
-
- return *cmd != '\0';
-}
-
-#endif /* _METACHAR_H */
diff --git a/usr.bin/make/nonints.h b/usr.bin/make/nonints.h
deleted file mode 100644
index 2fe2330..0000000
--- a/usr.bin/make/nonints.h
+++ /dev/null
@@ -1,198 +0,0 @@
-/* $NetBSD: nonints.h,v 1.74 2016/09/05 00:40:29 sevan Exp $ */
-
-/*-
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- *
- * from: @(#)nonints.h 8.3 (Berkeley) 3/19/94
- */
-
-/*-
- * Copyright (c) 1989 by Berkeley Softworks
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. 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.
- *
- * from: @(#)nonints.h 8.3 (Berkeley) 3/19/94
- */
-
-/* arch.c */
-ReturnStatus Arch_ParseArchive(char **, Lst, GNode *);
-void Arch_Touch(GNode *);
-void Arch_TouchLib(GNode *);
-time_t Arch_MTime(GNode *);
-time_t Arch_MemMTime(GNode *);
-void Arch_FindLib(GNode *, Lst);
-Boolean Arch_LibOODate(GNode *);
-void Arch_Init(void);
-void Arch_End(void);
-int Arch_IsLib(GNode *);
-
-/* compat.c */
-int CompatRunCommand(void *, void *);
-void Compat_Run(Lst);
-int Compat_Make(void *, void *);
-
-/* cond.c */
-struct If;
-int Cond_EvalExpression(const struct If *, char *, Boolean *, int, Boolean);
-int Cond_Eval(char *);
-void Cond_restore_depth(unsigned int);
-unsigned int Cond_save_depth(void);
-
-/* for.c */
-int For_Eval(char *);
-int For_Accum(char *);
-void For_Run(int);
-
-/* job.c */
-void JobReapChild(pid_t, int, Boolean);
-
-/* main.c */
-void Main_ParseArgLine(const char *);
-void MakeMode(const char *);
-char *Cmd_Exec(const char *, const char **);
-void Error(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2);
-void Fatal(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2) MAKE_ATTR_DEAD;
-void Punt(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2) MAKE_ATTR_DEAD;
-void DieHorribly(void) MAKE_ATTR_DEAD;
-int PrintAddr(void *, void *);
-void Finish(int) MAKE_ATTR_DEAD;
-int eunlink(const char *);
-void execError(const char *, const char *);
-char *getTmpdir(void);
-Boolean s2Boolean(const char *, Boolean);
-Boolean getBoolean(const char *, Boolean);
-char *cached_realpath(const char *, char *);
-
-/* parse.c */
-void Parse_Error(int, const char *, ...) MAKE_ATTR_PRINTFLIKE(2, 3);
-Boolean Parse_AnyExport(void);
-Boolean Parse_IsVar(char *);
-void Parse_DoVar(char *, GNode *);
-void Parse_AddIncludeDir(char *);
-void Parse_File(const char *, int);
-void Parse_Init(void);
-void Parse_End(void);
-void Parse_SetInput(const char *, int, int, char *(*)(void *, size_t *), void *);
-Lst Parse_MainName(void);
-
-/* str.c */
-char *str_concat(const char *, const char *, int);
-char **brk_string(const char *, int *, Boolean, char **);
-char *Str_FindSubstring(const char *, const char *);
-int Str_Match(const char *, const char *);
-char *Str_SYSVMatch(const char *, const char *, int *len);
-void Str_SYSVSubst(Buffer *, char *, char *, int);
-
-/* suff.c */
-void Suff_ClearSuffixes(void);
-Boolean Suff_IsTransform(char *);
-GNode *Suff_AddTransform(char *);
-int Suff_EndTransform(void *, void *);
-void Suff_AddSuffix(char *, GNode **);
-Lst Suff_GetPath(char *);
-void Suff_DoPaths(void);
-void Suff_AddInclude(char *);
-void Suff_AddLib(char *);
-void Suff_FindDeps(GNode *);
-Lst Suff_FindPath(GNode *);
-void Suff_SetNull(char *);
-void Suff_Init(void);
-void Suff_End(void);
-void Suff_PrintAll(void);
-
-/* targ.c */
-void Targ_Init(void);
-void Targ_End(void);
-Lst Targ_List(void);
-GNode *Targ_NewGN(const char *);
-GNode *Targ_FindNode(const char *, int);
-Lst Targ_FindList(Lst, int);
-Boolean Targ_Ignore(GNode *);
-Boolean Targ_Silent(GNode *);
-Boolean Targ_Precious(GNode *);
-void Targ_SetMain(GNode *);
-int Targ_PrintCmd(void *, void *);
-int Targ_PrintNode(void *, void *);
-char *Targ_FmtTime(time_t);
-void Targ_PrintType(int);
-void Targ_PrintGraph(int);
-void Targ_Propagate(void);
-void Targ_Propagate_Wait(void);
-
-/* var.c */
-void Var_Delete(const char *, GNode *);
-void Var_Set(const char *, const char *, GNode *, int);
-void Var_Append(const char *, const char *, GNode *);
-Boolean Var_Exists(const char *, GNode *);
-char *Var_Value(const char *, GNode *, char **);
-char *Var_Parse(const char *, GNode *, int, int *, void **);
-char *Var_Subst(const char *, const char *, GNode *, int);
-char *Var_GetTail(const char *);
-char *Var_GetHead(const char *);
-void Var_Init(void);
-void Var_End(void);
-void Var_Dump(GNode *);
-void Var_ExportVars(void);
-void Var_Export(char *, int);
-void Var_UnExport(char *);
-
-/* util.c */
-void (*bmake_signal(int, void (*)(int)))(int);
diff --git a/usr.bin/make/parse.c b/usr.bin/make/parse.c
deleted file mode 100644
index d7cecec..0000000
--- a/usr.bin/make/parse.c
+++ /dev/null
@@ -1,3357 +0,0 @@
-/* $NetBSD: parse.c,v 1.231 2018/12/22 00:36:32 sjg Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-/*
- * Copyright (c) 1989 by Berkeley Softworks
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: parse.c,v 1.231 2018/12/22 00:36:32 sjg Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)parse.c 8.3 (Berkeley) 3/19/94";
-#else
-__RCSID("$NetBSD: parse.c,v 1.231 2018/12/22 00:36:32 sjg Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * parse.c --
- * Functions to parse a makefile.
- *
- * One function, Parse_Init, must be called before any functions
- * in this module are used. After that, the function Parse_File is the
- * main entry point and controls most of the other functions in this
- * module.
- *
- * Most important structures are kept in Lsts. Directories for
- * the .include "..." function are kept in the 'parseIncPath' Lst, while
- * those for the .include <...> are kept in the 'sysIncPath' Lst. The
- * targets currently being defined are kept in the 'targets' Lst.
- *
- * The variables 'fname' and 'lineno' are used to track the name
- * of the current file and the line number in that file so that error
- * messages can be more meaningful.
- *
- * Interface:
- * Parse_Init Initialization function which must be
- * called before anything else in this module
- * is used.
- *
- * Parse_End Cleanup the module
- *
- * Parse_File Function used to parse a makefile. It must
- * be given the name of the file, which should
- * already have been opened, and a function
- * to call to read a character from the file.
- *
- * Parse_IsVar Returns TRUE if the given line is a
- * variable assignment. Used by MainParseArgs
- * to determine if an argument is a target
- * or a variable assignment. Used internally
- * for pretty much the same thing...
- *
- * Parse_Error Function called when an error occurs in
- * parsing. Used by the variable and
- * conditional modules.
- * Parse_MainName Returns a Lst of the main target to create.
- */
-
-#include <sys/types.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdint.h>
-
-#ifndef MAP_FILE
-#define MAP_FILE 0
-#endif
-#ifndef MAP_COPY
-#define MAP_COPY MAP_PRIVATE
-#endif
-
-#include "make.h"
-#include "hash.h"
-#include "dir.h"
-#include "job.h"
-#include "buf.h"
-#include "pathnames.h"
-
-////////////////////////////////////////////////////////////
-// types and constants
-
-/*
- * Structure for a file being read ("included file")
- */
-typedef struct IFile {
- char *fname; /* name of file */
- int lineno; /* current line number in file */
- int first_lineno; /* line number of start of text */
- int cond_depth; /* 'if' nesting when file opened */
- Boolean depending; /* state of doing_depend on EOF */
- char *P_str; /* point to base of string buffer */
- char *P_ptr; /* point to next char of string buffer */
- char *P_end; /* point to the end of string buffer */
- char *(*nextbuf)(void *, size_t *); /* Function to get more data */
- void *nextbuf_arg; /* Opaque arg for nextbuf() */
- struct loadedfile *lf; /* loadedfile object, if any */
-} IFile;
-
-
-/*
- * These values are returned by ParseEOF to tell Parse_File whether to
- * CONTINUE parsing, i.e. it had only reached the end of an include file,
- * or if it's DONE.
- */
-#define CONTINUE 1
-#define DONE 0
-
-/*
- * Tokens for target attributes
- */
-typedef enum {
- Begin, /* .BEGIN */
- Default, /* .DEFAULT */
- DeleteOnError, /* .DELETE_ON_ERROR */
- End, /* .END */
- dotError, /* .ERROR */
- Ignore, /* .IGNORE */
- Includes, /* .INCLUDES */
- Interrupt, /* .INTERRUPT */
- Libs, /* .LIBS */
- Meta, /* .META */
- MFlags, /* .MFLAGS or .MAKEFLAGS */
- Main, /* .MAIN and we don't have anything user-specified to
- * make */
- NoExport, /* .NOEXPORT */
- NoMeta, /* .NOMETA */
- NoMetaCmp, /* .NOMETA_CMP */
- NoPath, /* .NOPATH */
- Not, /* Not special */
- NotParallel, /* .NOTPARALLEL */
- Null, /* .NULL */
- ExObjdir, /* .OBJDIR */
- Order, /* .ORDER */
- Parallel, /* .PARALLEL */
- ExPath, /* .PATH */
- Phony, /* .PHONY */
-#ifdef POSIX
- Posix, /* .POSIX */
-#endif
- Precious, /* .PRECIOUS */
- ExShell, /* .SHELL */
- Silent, /* .SILENT */
- SingleShell, /* .SINGLESHELL */
- Stale, /* .STALE */
- Suffixes, /* .SUFFIXES */
- Wait, /* .WAIT */
- Attribute /* Generic attribute */
-} ParseSpecial;
-
-/*
- * Other tokens
- */
-#define LPAREN '('
-#define RPAREN ')'
-
-
-////////////////////////////////////////////////////////////
-// result data
-
-/*
- * The main target to create. This is the first target on the first
- * dependency line in the first makefile.
- */
-static GNode *mainNode;
-
-////////////////////////////////////////////////////////////
-// eval state
-
-/* targets we're working on */
-static Lst targets;
-
-#ifdef CLEANUP
-/* command lines for targets */
-static Lst targCmds;
-#endif
-
-/*
- * specType contains the SPECial TYPE of the current target. It is
- * Not if the target is unspecial. If it *is* special, however, the children
- * are linked as children of the parent but not vice versa. This variable is
- * set in ParseDoDependency
- */
-static ParseSpecial specType;
-
-/*
- * Predecessor node for handling .ORDER. Initialized to NULL when .ORDER
- * seen, then set to each successive source on the line.
- */
-static GNode *predecessor;
-
-////////////////////////////////////////////////////////////
-// parser state
-
-/* true if currently in a dependency line or its commands */
-static Boolean inLine;
-
-/* number of fatal errors */
-static int fatals = 0;
-
-/*
- * Variables for doing includes
- */
-
-/* current file being read */
-static IFile *curFile;
-
-/* stack of IFiles generated by .includes */
-static Lst includes;
-
-/* include paths (lists of directories) */
-Lst parseIncPath; /* dirs for "..." includes */
-Lst sysIncPath; /* dirs for <...> includes */
-Lst defIncPath; /* default for sysIncPath */
-
-////////////////////////////////////////////////////////////
-// parser tables
-
-/*
- * The parseKeywords table is searched using binary search when deciding
- * if a target or source is special. The 'spec' field is the ParseSpecial
- * type of the keyword ("Not" if the keyword isn't special as a target) while
- * the 'op' field is the operator to apply to the list of targets if the
- * keyword is used as a source ("0" if the keyword isn't special as a source)
- */
-static const struct {
- const char *name; /* Name of keyword */
- ParseSpecial spec; /* Type when used as a target */
- int op; /* Operator when used as a source */
-} parseKeywords[] = {
-{ ".BEGIN", Begin, 0 },
-{ ".DEFAULT", Default, 0 },
-{ ".DELETE_ON_ERROR", DeleteOnError, 0 },
-{ ".END", End, 0 },
-{ ".ERROR", dotError, 0 },
-{ ".EXEC", Attribute, OP_EXEC },
-{ ".IGNORE", Ignore, OP_IGNORE },
-{ ".INCLUDES", Includes, 0 },
-{ ".INTERRUPT", Interrupt, 0 },
-{ ".INVISIBLE", Attribute, OP_INVISIBLE },
-{ ".JOIN", Attribute, OP_JOIN },
-{ ".LIBS", Libs, 0 },
-{ ".MADE", Attribute, OP_MADE },
-{ ".MAIN", Main, 0 },
-{ ".MAKE", Attribute, OP_MAKE },
-{ ".MAKEFLAGS", MFlags, 0 },
-{ ".META", Meta, OP_META },
-{ ".MFLAGS", MFlags, 0 },
-{ ".NOMETA", NoMeta, OP_NOMETA },
-{ ".NOMETA_CMP", NoMetaCmp, OP_NOMETA_CMP },
-{ ".NOPATH", NoPath, OP_NOPATH },
-{ ".NOTMAIN", Attribute, OP_NOTMAIN },
-{ ".NOTPARALLEL", NotParallel, 0 },
-{ ".NO_PARALLEL", NotParallel, 0 },
-{ ".NULL", Null, 0 },
-{ ".OBJDIR", ExObjdir, 0 },
-{ ".OPTIONAL", Attribute, OP_OPTIONAL },
-{ ".ORDER", Order, 0 },
-{ ".PARALLEL", Parallel, 0 },
-{ ".PATH", ExPath, 0 },
-{ ".PHONY", Phony, OP_PHONY },
-#ifdef POSIX
-{ ".POSIX", Posix, 0 },
-#endif
-{ ".PRECIOUS", Precious, OP_PRECIOUS },
-{ ".RECURSIVE", Attribute, OP_MAKE },
-{ ".SHELL", ExShell, 0 },
-{ ".SILENT", Silent, OP_SILENT },
-{ ".SINGLESHELL", SingleShell, 0 },
-{ ".STALE", Stale, 0 },
-{ ".SUFFIXES", Suffixes, 0 },
-{ ".USE", Attribute, OP_USE },
-{ ".USEBEFORE", Attribute, OP_USEBEFORE },
-{ ".WAIT", Wait, 0 },
-};
-
-////////////////////////////////////////////////////////////
-// local functions
-
-static int ParseIsEscaped(const char *, const char *);
-static void ParseErrorInternal(const char *, size_t, int, const char *, ...)
- MAKE_ATTR_PRINTFLIKE(4,5);
-static void ParseVErrorInternal(FILE *, const char *, size_t, int, const char *, va_list)
- MAKE_ATTR_PRINTFLIKE(5, 0);
-static int ParseFindKeyword(const char *);
-static int ParseLinkSrc(void *, void *);
-static int ParseDoOp(void *, void *);
-static void ParseDoSrc(int, const char *);
-static int ParseFindMain(void *, void *);
-static int ParseAddDir(void *, void *);
-static int ParseClearPath(void *, void *);
-static void ParseDoDependency(char *);
-static int ParseAddCmd(void *, void *);
-static void ParseHasCommands(void *);
-static void ParseDoInclude(char *);
-static void ParseSetParseFile(const char *);
-static void ParseSetIncludedFile(void);
-#ifdef GMAKEEXPORT
-static void ParseGmakeExport(char *);
-#endif
-static int ParseEOF(void);
-static char *ParseReadLine(void);
-static void ParseFinishLine(void);
-static void ParseMark(GNode *);
-
-////////////////////////////////////////////////////////////
-// file loader
-
-struct loadedfile {
- const char *path; /* name, for error reports */
- char *buf; /* contents buffer */
- size_t len; /* length of contents */
- size_t maplen; /* length of mmap area, or 0 */
- Boolean used; /* XXX: have we used the data yet */
-};
-
-/*
- * Constructor/destructor for loadedfile
- */
-static struct loadedfile *
-loadedfile_create(const char *path)
-{
- struct loadedfile *lf;
-
- lf = bmake_malloc(sizeof(*lf));
- lf->path = (path == NULL ? "(stdin)" : path);
- lf->buf = NULL;
- lf->len = 0;
- lf->maplen = 0;
- lf->used = FALSE;
- return lf;
-}
-
-static void
-loadedfile_destroy(struct loadedfile *lf)
-{
- if (lf->buf != NULL) {
- if (lf->maplen > 0) {
- munmap(lf->buf, lf->maplen);
- } else {
- free(lf->buf);
- }
- }
- free(lf);
-}
-
-/*
- * nextbuf() operation for loadedfile, as needed by the weird and twisted
- * logic below. Once that's cleaned up, we can get rid of lf->used...
- */
-static char *
-loadedfile_nextbuf(void *x, size_t *len)
-{
- struct loadedfile *lf = x;
-
- if (lf->used) {
- return NULL;
- }
- lf->used = TRUE;
- *len = lf->len;
- return lf->buf;
-}
-
-/*
- * Try to get the size of a file.
- */
-static ReturnStatus
-load_getsize(int fd, size_t *ret)
-{
- struct stat st;
-
- if (fstat(fd, &st) < 0) {
- return FAILURE;
- }
-
- if (!S_ISREG(st.st_mode)) {
- return FAILURE;
- }
-
- /*
- * st_size is an off_t, which is 64 bits signed; *ret is
- * size_t, which might be 32 bits unsigned or 64 bits
- * unsigned. Rather than being elaborate, just punt on
- * files that are more than 2^31 bytes. We should never
- * see a makefile that size in practice...
- *
- * While we're at it reject negative sizes too, just in case.
- */
- if (st.st_size < 0 || st.st_size > 0x7fffffff) {
- return FAILURE;
- }
-
- *ret = (size_t) st.st_size;
- return SUCCESS;
-}
-
-/*
- * Read in a file.
- *
- * Until the path search logic can be moved under here instead of
- * being in the caller in another source file, we need to have the fd
- * passed in already open. Bleh.
- *
- * If the path is NULL use stdin and (to insure against fd leaks)
- * assert that the caller passed in -1.
- */
-static struct loadedfile *
-loadfile(const char *path, int fd)
-{
- struct loadedfile *lf;
- static long pagesize = 0;
- ssize_t result;
- size_t bufpos;
-
- lf = loadedfile_create(path);
-
- if (path == NULL) {
- assert(fd == -1);
- fd = STDIN_FILENO;
- } else {
-#if 0 /* notyet */
- fd = open(path, O_RDONLY);
- if (fd < 0) {
- ...
- Error("%s: %s", path, strerror(errno));
- exit(1);
- }
-#endif
- }
-
- if (load_getsize(fd, &lf->len) == SUCCESS) {
- /* found a size, try mmap */
- if (pagesize == 0)
- pagesize = sysconf(_SC_PAGESIZE);
- if (pagesize <= 0) {
- pagesize = 0x1000;
- }
- /* round size up to a page */
- lf->maplen = pagesize * ((lf->len + pagesize - 1)/pagesize);
-
- /*
- * XXX hack for dealing with empty files; remove when
- * we're no longer limited by interfacing to the old
- * logic elsewhere in this file.
- */
- if (lf->maplen == 0) {
- lf->maplen = pagesize;
- }
-
- /*
- * FUTURE: remove PROT_WRITE when the parser no longer
- * needs to scribble on the input.
- */
- lf->buf = mmap(NULL, lf->maplen, PROT_READ|PROT_WRITE,
- MAP_FILE|MAP_COPY, fd, 0);
- if (lf->buf != MAP_FAILED) {
- /* succeeded */
- if (lf->len == lf->maplen && lf->buf[lf->len - 1] != '\n') {
- char *b = bmake_malloc(lf->len + 1);
- b[lf->len] = '\n';
- memcpy(b, lf->buf, lf->len++);
- munmap(lf->buf, lf->maplen);
- lf->maplen = 0;
- lf->buf = b;
- }
- goto done;
- }
- }
-
- /* cannot mmap; load the traditional way */
-
- lf->maplen = 0;
- lf->len = 1024;
- lf->buf = bmake_malloc(lf->len);
-
- bufpos = 0;
- while (1) {
- assert(bufpos <= lf->len);
- if (bufpos == lf->len) {
- if (lf->len > SIZE_MAX/2) {
- errno = EFBIG;
- Error("%s: file too large", path);
- exit(1);
- }
- lf->len *= 2;
- lf->buf = bmake_realloc(lf->buf, lf->len);
- }
- assert(bufpos < lf->len);
- result = read(fd, lf->buf + bufpos, lf->len - bufpos);
- if (result < 0) {
- Error("%s: read error: %s", path, strerror(errno));
- exit(1);
- }
- if (result == 0) {
- break;
- }
- bufpos += result;
- }
- assert(bufpos <= lf->len);
- lf->len = bufpos;
-
- /* truncate malloc region to actual length (maybe not useful) */
- if (lf->len > 0) {
- /* as for mmap case, ensure trailing \n */
- if (lf->buf[lf->len - 1] != '\n')
- lf->len++;
- lf->buf = bmake_realloc(lf->buf, lf->len);
- lf->buf[lf->len - 1] = '\n';
- }
-
-done:
- if (path != NULL) {
- close(fd);
- }
- return lf;
-}
-
-////////////////////////////////////////////////////////////
-// old code
-
-/*-
- *----------------------------------------------------------------------
- * ParseIsEscaped --
- * Check if the current character is escaped on the current line
- *
- * Results:
- * 0 if the character is not backslash escaped, 1 otherwise
- *
- * Side Effects:
- * None
- *----------------------------------------------------------------------
- */
-static int
-ParseIsEscaped(const char *line, const char *c)
-{
- int active = 0;
- for (;;) {
- if (line == c)
- return active;
- if (*--c != '\\')
- return active;
- active = !active;
- }
-}
-
-/*-
- *----------------------------------------------------------------------
- * ParseFindKeyword --
- * Look in the table of keywords for one matching the given string.
- *
- * Input:
- * str String to find
- *
- * Results:
- * The index of the keyword, or -1 if it isn't there.
- *
- * Side Effects:
- * None
- *----------------------------------------------------------------------
- */
-static int
-ParseFindKeyword(const char *str)
-{
- int start, end, cur;
- int diff;
-
- start = 0;
- end = (sizeof(parseKeywords)/sizeof(parseKeywords[0])) - 1;
-
- do {
- cur = start + ((end - start) / 2);
- diff = strcmp(str, parseKeywords[cur].name);
-
- if (diff == 0) {
- return (cur);
- } else if (diff < 0) {
- end = cur - 1;
- } else {
- start = cur + 1;
- }
- } while (start <= end);
- return (-1);
-}
-
-/*-
- * ParseVErrorInternal --
- * Error message abort function for parsing. Prints out the context
- * of the error (line number and file) as well as the message with
- * two optional arguments.
- *
- * Results:
- * None
- *
- * Side Effects:
- * "fatals" is incremented if the level is PARSE_FATAL.
- */
-/* VARARGS */
-static void
-ParseVErrorInternal(FILE *f, const char *cfname, size_t clineno, int type,
- const char *fmt, va_list ap)
-{
- static Boolean fatal_warning_error_printed = FALSE;
-
- (void)fprintf(f, "%s: ", progname);
-
- if (cfname != NULL) {
- (void)fprintf(f, "\"");
- if (*cfname != '/' && strcmp(cfname, "(stdin)") != 0) {
- char *cp, *cp2;
- const char *dir, *fname;
-
- /*
- * Nothing is more annoying than not knowing
- * which Makefile is the culprit; we try ${.PARSEDIR}
- * and apply realpath(3) if not absolute.
- */
- dir = Var_Value(".PARSEDIR", VAR_GLOBAL, &cp);
- if (dir == NULL)
- dir = ".";
- if (*dir != '/') {
- dir = cp2 = realpath(dir, NULL);
- free(cp);
- cp = cp2; /* cp2 set to NULL by Var_Value */
- }
- fname = Var_Value(".PARSEFILE", VAR_GLOBAL, &cp2);
- if (fname == NULL) {
- if ((fname = strrchr(cfname, '/')))
- fname++;
- else
- fname = cfname;
- }
- (void)fprintf(f, "%s/%s", dir, fname);
- free(cp2);
- free(cp);
- } else
- (void)fprintf(f, "%s", cfname);
-
- (void)fprintf(f, "\" line %d: ", (int)clineno);
- }
- if (type == PARSE_WARNING)
- (void)fprintf(f, "warning: ");
- (void)vfprintf(f, fmt, ap);
- (void)fprintf(f, "\n");
- (void)fflush(f);
- if (type == PARSE_INFO)
- return;
- if (type == PARSE_FATAL || parseWarnFatal)
- fatals += 1;
- if (parseWarnFatal && !fatal_warning_error_printed) {
- Error("parsing warnings being treated as errors");
- fatal_warning_error_printed = TRUE;
- }
-}
-
-/*-
- * ParseErrorInternal --
- * Error function
- *
- * Results:
- * None
- *
- * Side Effects:
- * None
- */
-/* VARARGS */
-static void
-ParseErrorInternal(const char *cfname, size_t clineno, int type,
- const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- (void)fflush(stdout);
- ParseVErrorInternal(stderr, cfname, clineno, type, fmt, ap);
- va_end(ap);
-
- if (debug_file != stderr && debug_file != stdout) {
- va_start(ap, fmt);
- ParseVErrorInternal(debug_file, cfname, clineno, type, fmt, ap);
- va_end(ap);
- }
-}
-
-/*-
- * Parse_Error --
- * External interface to ParseErrorInternal; uses the default filename
- * Line number.
- *
- * Results:
- * None
- *
- * Side Effects:
- * None
- */
-/* VARARGS */
-void
-Parse_Error(int type, const char *fmt, ...)
-{
- va_list ap;
- const char *fname;
- size_t lineno;
-
- if (curFile == NULL) {
- fname = NULL;
- lineno = 0;
- } else {
- fname = curFile->fname;
- lineno = curFile->lineno;
- }
-
- va_start(ap, fmt);
- (void)fflush(stdout);
- ParseVErrorInternal(stderr, fname, lineno, type, fmt, ap);
- va_end(ap);
-
- if (debug_file != stderr && debug_file != stdout) {
- va_start(ap, fmt);
- ParseVErrorInternal(debug_file, fname, lineno, type, fmt, ap);
- va_end(ap);
- }
-}
-
-
-/*
- * ParseMessage
- * Parse a .info .warning or .error directive
- *
- * The input is the line minus the ".". We substitute
- * variables, print the message and exit(1) (for .error) or just print
- * a warning if the directive is malformed.
- */
-static Boolean
-ParseMessage(char *line)
-{
- int mtype;
-
- switch(*line) {
- case 'i':
- mtype = PARSE_INFO;
- break;
- case 'w':
- mtype = PARSE_WARNING;
- break;
- case 'e':
- mtype = PARSE_FATAL;
- break;
- default:
- Parse_Error(PARSE_WARNING, "invalid syntax: \".%s\"", line);
- return FALSE;
- }
-
- while (isalpha((unsigned char)*line))
- line++;
- if (!isspace((unsigned char)*line))
- return FALSE; /* not for us */
- while (isspace((unsigned char)*line))
- line++;
-
- line = Var_Subst(NULL, line, VAR_CMD, VARF_WANTRES);
- Parse_Error(mtype, "%s", line);
- free(line);
-
- if (mtype == PARSE_FATAL) {
- /* Terminate immediately. */
- exit(1);
- }
- return TRUE;
-}
-
-/*-
- *---------------------------------------------------------------------
- * ParseLinkSrc --
- * Link the parent node to its new child. Used in a Lst_ForEach by
- * ParseDoDependency. If the specType isn't 'Not', the parent
- * isn't linked as a parent of the child.
- *
- * Input:
- * pgnp The parent node
- * cgpn The child node
- *
- * Results:
- * Always = 0
- *
- * Side Effects:
- * New elements are added to the parents list of cgn and the
- * children list of cgn. the unmade field of pgn is updated
- * to reflect the additional child.
- *---------------------------------------------------------------------
- */
-static int
-ParseLinkSrc(void *pgnp, void *cgnp)
-{
- GNode *pgn = (GNode *)pgnp;
- GNode *cgn = (GNode *)cgnp;
-
- if ((pgn->type & OP_DOUBLEDEP) && !Lst_IsEmpty (pgn->cohorts))
- pgn = (GNode *)Lst_Datum(Lst_Last(pgn->cohorts));
- (void)Lst_AtEnd(pgn->children, cgn);
- if (specType == Not)
- (void)Lst_AtEnd(cgn->parents, pgn);
- pgn->unmade += 1;
- if (DEBUG(PARSE)) {
- fprintf(debug_file, "# %s: added child %s - %s\n", __func__,
- pgn->name, cgn->name);
- Targ_PrintNode(pgn, 0);
- Targ_PrintNode(cgn, 0);
- }
- return (0);
-}
-
-/*-
- *---------------------------------------------------------------------
- * ParseDoOp --
- * Apply the parsed operator to the given target node. Used in a
- * Lst_ForEach call by ParseDoDependency once all targets have
- * been found and their operator parsed. If the previous and new
- * operators are incompatible, a major error is taken.
- *
- * Input:
- * gnp The node to which the operator is to be applied
- * opp The operator to apply
- *
- * Results:
- * Always 0
- *
- * Side Effects:
- * The type field of the node is altered to reflect any new bits in
- * the op.
- *---------------------------------------------------------------------
- */
-static int
-ParseDoOp(void *gnp, void *opp)
-{
- GNode *gn = (GNode *)gnp;
- int op = *(int *)opp;
- /*
- * If the dependency mask of the operator and the node don't match and
- * the node has actually had an operator applied to it before, and
- * the operator actually has some dependency information in it, complain.
- */
- if (((op & OP_OPMASK) != (gn->type & OP_OPMASK)) &&
- !OP_NOP(gn->type) && !OP_NOP(op))
- {
- Parse_Error(PARSE_FATAL, "Inconsistent operator for %s", gn->name);
- return (1);
- }
-
- if ((op == OP_DOUBLEDEP) && ((gn->type & OP_OPMASK) == OP_DOUBLEDEP)) {
- /*
- * If the node was the object of a :: operator, we need to create a
- * new instance of it for the children and commands on this dependency
- * line. The new instance is placed on the 'cohorts' list of the
- * initial one (note the initial one is not on its own cohorts list)
- * and the new instance is linked to all parents of the initial
- * instance.
- */
- GNode *cohort;
-
- /*
- * Propagate copied bits to the initial node. They'll be propagated
- * back to the rest of the cohorts later.
- */
- gn->type |= op & ~OP_OPMASK;
-
- cohort = Targ_FindNode(gn->name, TARG_NOHASH);
- if (doing_depend)
- ParseMark(cohort);
- /*
- * Make the cohort invisible as well to avoid duplicating it into
- * other variables. True, parents of this target won't tend to do
- * anything with their local variables, but better safe than
- * sorry. (I think this is pointless now, since the relevant list
- * traversals will no longer see this node anyway. -mycroft)
- */
- cohort->type = op | OP_INVISIBLE;
- (void)Lst_AtEnd(gn->cohorts, cohort);
- cohort->centurion = gn;
- gn->unmade_cohorts += 1;
- snprintf(cohort->cohort_num, sizeof cohort->cohort_num, "#%d",
- gn->unmade_cohorts);
- } else {
- /*
- * We don't want to nuke any previous flags (whatever they were) so we
- * just OR the new operator into the old
- */
- gn->type |= op;
- }
-
- return (0);
-}
-
-/*-
- *---------------------------------------------------------------------
- * ParseDoSrc --
- * Given the name of a source, figure out if it is an attribute
- * and apply it to the targets if it is. Else decide if there is
- * some attribute which should be applied *to* the source because
- * of some special target and apply it if so. Otherwise, make the
- * source be a child of the targets in the list 'targets'
- *
- * Input:
- * tOp operator (if any) from special targets
- * src name of the source to handle
- *
- * Results:
- * None
- *
- * Side Effects:
- * Operator bits may be added to the list of targets or to the source.
- * The targets may have a new source added to their lists of children.
- *---------------------------------------------------------------------
- */
-static void
-ParseDoSrc(int tOp, const char *src)
-{
- GNode *gn = NULL;
- static int wait_number = 0;
- char wait_src[16];
-
- if (*src == '.' && isupper ((unsigned char)src[1])) {
- int keywd = ParseFindKeyword(src);
- if (keywd != -1) {
- int op = parseKeywords[keywd].op;
- if (op != 0) {
- Lst_ForEach(targets, ParseDoOp, &op);
- return;
- }
- if (parseKeywords[keywd].spec == Wait) {
- /*
- * We add a .WAIT node in the dependency list.
- * After any dynamic dependencies (and filename globbing)
- * have happened, it is given a dependency on the each
- * previous child back to and previous .WAIT node.
- * The next child won't be scheduled until the .WAIT node
- * is built.
- * We give each .WAIT node a unique name (mainly for diag).
- */
- snprintf(wait_src, sizeof wait_src, ".WAIT_%u", ++wait_number);
- gn = Targ_FindNode(wait_src, TARG_NOHASH);
- if (doing_depend)
- ParseMark(gn);
- gn->type = OP_WAIT | OP_PHONY | OP_DEPENDS | OP_NOTMAIN;
- Lst_ForEach(targets, ParseLinkSrc, gn);
- return;
- }
- }
- }
-
- switch (specType) {
- case Main:
- /*
- * If we have noted the existence of a .MAIN, it means we need
- * to add the sources of said target to the list of things
- * to create. The string 'src' is likely to be free, so we
- * must make a new copy of it. Note that this will only be
- * invoked if the user didn't specify a target on the command
- * line. This is to allow #ifmake's to succeed, or something...
- */
- (void)Lst_AtEnd(create, bmake_strdup(src));
- /*
- * Add the name to the .TARGETS variable as well, so the user can
- * employ that, if desired.
- */
- Var_Append(".TARGETS", src, VAR_GLOBAL);
- return;
-
- case Order:
- /*
- * Create proper predecessor/successor links between the previous
- * source and the current one.
- */
- gn = Targ_FindNode(src, TARG_CREATE);
- if (doing_depend)
- ParseMark(gn);
- if (predecessor != NULL) {
- (void)Lst_AtEnd(predecessor->order_succ, gn);
- (void)Lst_AtEnd(gn->order_pred, predecessor);
- if (DEBUG(PARSE)) {
- fprintf(debug_file, "# %s: added Order dependency %s - %s\n",
- __func__, predecessor->name, gn->name);
- Targ_PrintNode(predecessor, 0);
- Targ_PrintNode(gn, 0);
- }
- }
- /*
- * The current source now becomes the predecessor for the next one.
- */
- predecessor = gn;
- break;
-
- default:
- /*
- * If the source is not an attribute, we need to find/create
- * a node for it. After that we can apply any operator to it
- * from a special target or link it to its parents, as
- * appropriate.
- *
- * In the case of a source that was the object of a :: operator,
- * the attribute is applied to all of its instances (as kept in
- * the 'cohorts' list of the node) or all the cohorts are linked
- * to all the targets.
- */
-
- /* Find/create the 'src' node and attach to all targets */
- gn = Targ_FindNode(src, TARG_CREATE);
- if (doing_depend)
- ParseMark(gn);
- if (tOp) {
- gn->type |= tOp;
- } else {
- Lst_ForEach(targets, ParseLinkSrc, gn);
- }
- break;
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * ParseFindMain --
- * Find a real target in the list and set it to be the main one.
- * Called by ParseDoDependency when a main target hasn't been found
- * yet.
- *
- * Input:
- * gnp Node to examine
- *
- * Results:
- * 0 if main not found yet, 1 if it is.
- *
- * Side Effects:
- * mainNode is changed and Targ_SetMain is called.
- *
- *-----------------------------------------------------------------------
- */
-static int
-ParseFindMain(void *gnp, void *dummy MAKE_ATTR_UNUSED)
-{
- GNode *gn = (GNode *)gnp;
- if ((gn->type & OP_NOTARGET) == 0) {
- mainNode = gn;
- Targ_SetMain(gn);
- return 1;
- } else {
- return 0;
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * ParseAddDir --
- * Front-end for Dir_AddDir to make sure Lst_ForEach keeps going
- *
- * Results:
- * === 0
- *
- * Side Effects:
- * See Dir_AddDir.
- *
- *-----------------------------------------------------------------------
- */
-static int
-ParseAddDir(void *path, void *name)
-{
- (void)Dir_AddDir((Lst) path, (char *)name);
- return(0);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * ParseClearPath --
- * Front-end for Dir_ClearPath to make sure Lst_ForEach keeps going
- *
- * Results:
- * === 0
- *
- * Side Effects:
- * See Dir_ClearPath
- *
- *-----------------------------------------------------------------------
- */
-static int
-ParseClearPath(void *path, void *dummy MAKE_ATTR_UNUSED)
-{
- Dir_ClearPath((Lst) path);
- return 0;
-}
-
-/*-
- *---------------------------------------------------------------------
- * ParseDoDependency --
- * Parse the dependency line in line.
- *
- * Input:
- * line the line to parse
- *
- * Results:
- * None
- *
- * Side Effects:
- * The nodes of the sources are linked as children to the nodes of the
- * targets. Some nodes may be created.
- *
- * We parse a dependency line by first extracting words from the line and
- * finding nodes in the list of all targets with that name. This is done
- * until a character is encountered which is an operator character. Currently
- * these are only ! and :. At this point the operator is parsed and the
- * pointer into the line advanced until the first source is encountered.
- * The parsed operator is applied to each node in the 'targets' list,
- * which is where the nodes found for the targets are kept, by means of
- * the ParseDoOp function.
- * The sources are read in much the same way as the targets were except
- * that now they are expanded using the wildcarding scheme of the C-Shell
- * and all instances of the resulting words in the list of all targets
- * are found. Each of the resulting nodes is then linked to each of the
- * targets as one of its children.
- * Certain targets are handled specially. These are the ones detailed
- * by the specType variable.
- * The storing of transformation rules is also taken care of here.
- * A target is recognized as a transformation rule by calling
- * Suff_IsTransform. If it is a transformation rule, its node is gotten
- * from the suffix module via Suff_AddTransform rather than the standard
- * Targ_FindNode in the target module.
- *---------------------------------------------------------------------
- */
-static void
-ParseDoDependency(char *line)
-{
- char *cp; /* our current position */
- GNode *gn = NULL; /* a general purpose temporary node */
- int op; /* the operator on the line */
- char savec; /* a place to save a character */
- Lst paths; /* List of search paths to alter when parsing
- * a list of .PATH targets */
- int tOp; /* operator from special target */
- Lst sources; /* list of archive source names after
- * expansion */
- Lst curTargs; /* list of target names to be found and added
- * to the targets list */
- char *lstart = line;
-
- if (DEBUG(PARSE))
- fprintf(debug_file, "ParseDoDependency(%s)\n", line);
- tOp = 0;
-
- specType = Not;
- paths = NULL;
-
- curTargs = Lst_Init(FALSE);
-
- /*
- * First, grind through the targets.
- */
-
- do {
- /*
- * Here LINE points to the beginning of the next word, and
- * LSTART points to the actual beginning of the line.
- */
-
- /* Find the end of the next word. */
- for (cp = line; *cp && (ParseIsEscaped(lstart, cp) ||
- !(isspace((unsigned char)*cp) ||
- *cp == '!' || *cp == ':' || *cp == LPAREN));
- cp++) {
- if (*cp == '$') {
- /*
- * Must be a dynamic source (would have been expanded
- * otherwise), so call the Var module to parse the puppy
- * so we can safely advance beyond it...There should be
- * no errors in this, as they would have been discovered
- * in the initial Var_Subst and we wouldn't be here.
- */
- int length;
- void *freeIt;
-
- (void)Var_Parse(cp, VAR_CMD, VARF_UNDEFERR|VARF_WANTRES,
- &length, &freeIt);
- free(freeIt);
- cp += length-1;
- }
- }
-
- /*
- * If the word is followed by a left parenthesis, it's the
- * name of an object file inside an archive (ar file).
- */
- if (!ParseIsEscaped(lstart, cp) && *cp == LPAREN) {
- /*
- * Archives must be handled specially to make sure the OP_ARCHV
- * flag is set in their 'type' field, for one thing, and because
- * things like "archive(file1.o file2.o file3.o)" are permissible.
- * Arch_ParseArchive will set 'line' to be the first non-blank
- * after the archive-spec. It creates/finds nodes for the members
- * and places them on the given list, returning SUCCESS if all
- * went well and FAILURE if there was an error in the
- * specification. On error, line should remain untouched.
- */
- if (Arch_ParseArchive(&line, targets, VAR_CMD) != SUCCESS) {
- Parse_Error(PARSE_FATAL,
- "Error in archive specification: \"%s\"", line);
- goto out;
- } else {
- /* Done with this word; on to the next. */
- cp = line;
- continue;
- }
- }
-
- if (!*cp) {
- /*
- * We got to the end of the line while we were still
- * looking at targets.
- *
- * Ending a dependency line without an operator is a Bozo
- * no-no. As a heuristic, this is also often triggered by
- * undetected conflicts from cvs/rcs merges.
- */
- if ((strncmp(line, "<<<<<<", 6) == 0) ||
- (strncmp(line, "======", 6) == 0) ||
- (strncmp(line, ">>>>>>", 6) == 0))
- Parse_Error(PARSE_FATAL,
- "Makefile appears to contain unresolved cvs/rcs/??? merge conflicts");
- else
- Parse_Error(PARSE_FATAL, lstart[0] == '.' ? "Unknown directive"
- : "Need an operator");
- goto out;
- }
-
- /* Insert a null terminator. */
- savec = *cp;
- *cp = '\0';
-
- /*
- * Got the word. See if it's a special target and if so set
- * specType to match it.
- */
- if (*line == '.' && isupper ((unsigned char)line[1])) {
- /*
- * See if the target is a special target that must have it
- * or its sources handled specially.
- */
- int keywd = ParseFindKeyword(line);
- if (keywd != -1) {
- if (specType == ExPath && parseKeywords[keywd].spec != ExPath) {
- Parse_Error(PARSE_FATAL, "Mismatched special targets");
- goto out;
- }
-
- specType = parseKeywords[keywd].spec;
- tOp = parseKeywords[keywd].op;
-
- /*
- * Certain special targets have special semantics:
- * .PATH Have to set the dirSearchPath
- * variable too
- * .MAIN Its sources are only used if
- * nothing has been specified to
- * create.
- * .DEFAULT Need to create a node to hang
- * commands on, but we don't want
- * it in the graph, nor do we want
- * it to be the Main Target, so we
- * create it, set OP_NOTMAIN and
- * add it to the list, setting
- * DEFAULT to the new node for
- * later use. We claim the node is
- * A transformation rule to make
- * life easier later, when we'll
- * use Make_HandleUse to actually
- * apply the .DEFAULT commands.
- * .PHONY The list of targets
- * .NOPATH Don't search for file in the path
- * .STALE
- * .BEGIN
- * .END
- * .ERROR
- * .DELETE_ON_ERROR
- * .INTERRUPT Are not to be considered the
- * main target.
- * .NOTPARALLEL Make only one target at a time.
- * .SINGLESHELL Create a shell for each command.
- * .ORDER Must set initial predecessor to NULL
- */
- switch (specType) {
- case ExPath:
- if (paths == NULL) {
- paths = Lst_Init(FALSE);
- }
- (void)Lst_AtEnd(paths, dirSearchPath);
- break;
- case Main:
- if (!Lst_IsEmpty(create)) {
- specType = Not;
- }
- break;
- case Begin:
- case End:
- case Stale:
- case dotError:
- case Interrupt:
- gn = Targ_FindNode(line, TARG_CREATE);
- if (doing_depend)
- ParseMark(gn);
- gn->type |= OP_NOTMAIN|OP_SPECIAL;
- (void)Lst_AtEnd(targets, gn);
- break;
- case Default:
- gn = Targ_NewGN(".DEFAULT");
- gn->type |= (OP_NOTMAIN|OP_TRANSFORM);
- (void)Lst_AtEnd(targets, gn);
- DEFAULT = gn;
- break;
- case DeleteOnError:
- deleteOnError = TRUE;
- break;
- case NotParallel:
- maxJobs = 1;
- break;
- case SingleShell:
- compatMake = TRUE;
- break;
- case Order:
- predecessor = NULL;
- break;
- default:
- break;
- }
- } else if (strncmp(line, ".PATH", 5) == 0) {
- /*
- * .PATH<suffix> has to be handled specially.
- * Call on the suffix module to give us a path to
- * modify.
- */
- Lst path;
-
- specType = ExPath;
- path = Suff_GetPath(&line[5]);
- if (path == NULL) {
- Parse_Error(PARSE_FATAL,
- "Suffix '%s' not defined (yet)",
- &line[5]);
- goto out;
- } else {
- if (paths == NULL) {
- paths = Lst_Init(FALSE);
- }
- (void)Lst_AtEnd(paths, path);
- }
- }
- }
-
- /*
- * Have word in line. Get or create its node and stick it at
- * the end of the targets list
- */
- if ((specType == Not) && (*line != '\0')) {
- if (Dir_HasWildcards(line)) {
- /*
- * Targets are to be sought only in the current directory,
- * so create an empty path for the thing. Note we need to
- * use Dir_Destroy in the destruction of the path as the
- * Dir module could have added a directory to the path...
- */
- Lst emptyPath = Lst_Init(FALSE);
-
- Dir_Expand(line, emptyPath, curTargs);
-
- Lst_Destroy(emptyPath, Dir_Destroy);
- } else {
- /*
- * No wildcards, but we want to avoid code duplication,
- * so create a list with the word on it.
- */
- (void)Lst_AtEnd(curTargs, line);
- }
-
- /* Apply the targets. */
-
- while(!Lst_IsEmpty(curTargs)) {
- char *targName = (char *)Lst_DeQueue(curTargs);
-
- if (!Suff_IsTransform (targName)) {
- gn = Targ_FindNode(targName, TARG_CREATE);
- } else {
- gn = Suff_AddTransform(targName);
- }
- if (doing_depend)
- ParseMark(gn);
-
- (void)Lst_AtEnd(targets, gn);
- }
- } else if (specType == ExPath && *line != '.' && *line != '\0') {
- Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", line);
- }
-
- /* Don't need the inserted null terminator any more. */
- *cp = savec;
-
- /*
- * If it is a special type and not .PATH, it's the only target we
- * allow on this line...
- */
- if (specType != Not && specType != ExPath) {
- Boolean warning = FALSE;
-
- while (*cp && (ParseIsEscaped(lstart, cp) ||
- ((*cp != '!') && (*cp != ':')))) {
- if (ParseIsEscaped(lstart, cp) ||
- (*cp != ' ' && *cp != '\t')) {
- warning = TRUE;
- }
- cp++;
- }
- if (warning) {
- Parse_Error(PARSE_WARNING, "Extra target ignored");
- }
- } else {
- while (*cp && isspace ((unsigned char)*cp)) {
- cp++;
- }
- }
- line = cp;
- } while (*line && (ParseIsEscaped(lstart, line) ||
- ((*line != '!') && (*line != ':'))));
-
- /*
- * Don't need the list of target names anymore...
- */
- Lst_Destroy(curTargs, NULL);
- curTargs = NULL;
-
- if (!Lst_IsEmpty(targets)) {
- switch(specType) {
- default:
- Parse_Error(PARSE_WARNING, "Special and mundane targets don't mix. Mundane ones ignored");
- break;
- case Default:
- case Stale:
- case Begin:
- case End:
- case dotError:
- case Interrupt:
- /*
- * These four create nodes on which to hang commands, so
- * targets shouldn't be empty...
- */
- case Not:
- /*
- * Nothing special here -- targets can be empty if it wants.
- */
- break;
- }
- }
-
- /*
- * Have now parsed all the target names. Must parse the operator next. The
- * result is left in op .
- */
- if (*cp == '!') {
- op = OP_FORCE;
- } else if (*cp == ':') {
- if (cp[1] == ':') {
- op = OP_DOUBLEDEP;
- cp++;
- } else {
- op = OP_DEPENDS;
- }
- } else {
- Parse_Error(PARSE_FATAL, lstart[0] == '.' ? "Unknown directive"
- : "Missing dependency operator");
- goto out;
- }
-
- /* Advance beyond the operator */
- cp++;
-
- /*
- * Apply the operator to the target. This is how we remember which
- * operator a target was defined with. It fails if the operator
- * used isn't consistent across all references.
- */
- Lst_ForEach(targets, ParseDoOp, &op);
-
- /*
- * Onward to the sources.
- *
- * LINE will now point to the first source word, if any, or the
- * end of the string if not.
- */
- while (*cp && isspace ((unsigned char)*cp)) {
- cp++;
- }
- line = cp;
-
- /*
- * Several special targets take different actions if present with no
- * sources:
- * a .SUFFIXES line with no sources clears out all old suffixes
- * a .PRECIOUS line makes all targets precious
- * a .IGNORE line ignores errors for all targets
- * a .SILENT line creates silence when making all targets
- * a .PATH removes all directories from the search path(s).
- */
- if (!*line) {
- switch (specType) {
- case Suffixes:
- Suff_ClearSuffixes();
- break;
- case Precious:
- allPrecious = TRUE;
- break;
- case Ignore:
- ignoreErrors = TRUE;
- break;
- case Silent:
- beSilent = TRUE;
- break;
- case ExPath:
- Lst_ForEach(paths, ParseClearPath, NULL);
- Dir_SetPATH();
- break;
-#ifdef POSIX
- case Posix:
- Var_Set("%POSIX", "1003.2", VAR_GLOBAL, 0);
- break;
-#endif
- default:
- break;
- }
- } else if (specType == MFlags) {
- /*
- * Call on functions in main.c to deal with these arguments and
- * set the initial character to a null-character so the loop to
- * get sources won't get anything
- */
- Main_ParseArgLine(line);
- *line = '\0';
- } else if (specType == ExShell) {
- if (Job_ParseShell(line) != SUCCESS) {
- Parse_Error(PARSE_FATAL, "improper shell specification");
- goto out;
- }
- *line = '\0';
- } else if ((specType == NotParallel) || (specType == SingleShell) ||
- (specType == DeleteOnError)) {
- *line = '\0';
- }
-
- /*
- * NOW GO FOR THE SOURCES
- */
- if ((specType == Suffixes) || (specType == ExPath) ||
- (specType == Includes) || (specType == Libs) ||
- (specType == Null) || (specType == ExObjdir))
- {
- while (*line) {
- /*
- * If the target was one that doesn't take files as its sources
- * but takes something like suffixes, we take each
- * space-separated word on the line as a something and deal
- * with it accordingly.
- *
- * If the target was .SUFFIXES, we take each source as a
- * suffix and add it to the list of suffixes maintained by the
- * Suff module.
- *
- * If the target was a .PATH, we add the source as a directory
- * to search on the search path.
- *
- * If it was .INCLUDES, the source is taken to be the suffix of
- * files which will be #included and whose search path should
- * be present in the .INCLUDES variable.
- *
- * If it was .LIBS, the source is taken to be the suffix of
- * files which are considered libraries and whose search path
- * should be present in the .LIBS variable.
- *
- * If it was .NULL, the source is the suffix to use when a file
- * has no valid suffix.
- *
- * If it was .OBJDIR, the source is a new definition for .OBJDIR,
- * and will cause make to do a new chdir to that path.
- */
- while (*cp && !isspace ((unsigned char)*cp)) {
- cp++;
- }
- savec = *cp;
- *cp = '\0';
- switch (specType) {
- case Suffixes:
- Suff_AddSuffix(line, &mainNode);
- break;
- case ExPath:
- Lst_ForEach(paths, ParseAddDir, line);
- break;
- case Includes:
- Suff_AddInclude(line);
- break;
- case Libs:
- Suff_AddLib(line);
- break;
- case Null:
- Suff_SetNull(line);
- break;
- case ExObjdir:
- Main_SetObjdir("%s", line);
- break;
- default:
- break;
- }
- *cp = savec;
- if (savec != '\0') {
- cp++;
- }
- while (*cp && isspace ((unsigned char)*cp)) {
- cp++;
- }
- line = cp;
- }
- if (paths) {
- Lst_Destroy(paths, NULL);
- paths = NULL;
- }
- if (specType == ExPath)
- Dir_SetPATH();
- } else {
- assert(paths == NULL);
- while (*line) {
- /*
- * The targets take real sources, so we must beware of archive
- * specifications (i.e. things with left parentheses in them)
- * and handle them accordingly.
- */
- for (; *cp && !isspace ((unsigned char)*cp); cp++) {
- if ((*cp == LPAREN) && (cp > line) && (cp[-1] != '$')) {
- /*
- * Only stop for a left parenthesis if it isn't at the
- * start of a word (that'll be for variable changes
- * later) and isn't preceded by a dollar sign (a dynamic
- * source).
- */
- break;
- }
- }
-
- if (*cp == LPAREN) {
- sources = Lst_Init(FALSE);
- if (Arch_ParseArchive(&line, sources, VAR_CMD) != SUCCESS) {
- Parse_Error(PARSE_FATAL,
- "Error in source archive spec \"%s\"", line);
- goto out;
- }
-
- while (!Lst_IsEmpty (sources)) {
- gn = (GNode *)Lst_DeQueue(sources);
- ParseDoSrc(tOp, gn->name);
- }
- Lst_Destroy(sources, NULL);
- cp = line;
- } else {
- if (*cp) {
- *cp = '\0';
- cp += 1;
- }
-
- ParseDoSrc(tOp, line);
- }
- while (*cp && isspace ((unsigned char)*cp)) {
- cp++;
- }
- line = cp;
- }
- }
-
- if (mainNode == NULL) {
- /*
- * If we have yet to decide on a main target to make, in the
- * absence of any user input, we want the first target on
- * the first dependency line that is actually a real target
- * (i.e. isn't a .USE or .EXEC rule) to be made.
- */
- Lst_ForEach(targets, ParseFindMain, NULL);
- }
-
-out:
- assert(paths == NULL);
- if (curTargs)
- Lst_Destroy(curTargs, NULL);
-}
-
-/*-
- *---------------------------------------------------------------------
- * Parse_IsVar --
- * Return TRUE if the passed line is a variable assignment. A variable
- * assignment consists of a single word followed by optional whitespace
- * followed by either a += or an = operator.
- * This function is used both by the Parse_File function and main when
- * parsing the command-line arguments.
- *
- * Input:
- * line the line to check
- *
- * Results:
- * TRUE if it is. FALSE if it ain't
- *
- * Side Effects:
- * none
- *---------------------------------------------------------------------
- */
-Boolean
-Parse_IsVar(char *line)
-{
- Boolean wasSpace = FALSE; /* set TRUE if found a space */
- char ch;
- int level = 0;
-#define ISEQOPERATOR(c) \
- (((c) == '+') || ((c) == ':') || ((c) == '?') || ((c) == '!'))
-
- /*
- * Skip to variable name
- */
- for (;(*line == ' ') || (*line == '\t'); line++)
- continue;
-
- /* Scan for one of the assignment operators outside a variable expansion */
- while ((ch = *line++) != 0) {
- if (ch == '(' || ch == '{') {
- level++;
- continue;
- }
- if (ch == ')' || ch == '}') {
- level--;
- continue;
- }
- if (level != 0)
- continue;
- while (ch == ' ' || ch == '\t') {
- ch = *line++;
- wasSpace = TRUE;
- }
-#ifdef SUNSHCMD
- if (ch == ':' && strncmp(line, "sh", 2) == 0) {
- line += 2;
- continue;
- }
-#endif
- if (ch == '=')
- return TRUE;
- if (*line == '=' && ISEQOPERATOR(ch))
- return TRUE;
- if (wasSpace)
- return FALSE;
- }
-
- return FALSE;
-}
-
-/*-
- *---------------------------------------------------------------------
- * Parse_DoVar --
- * Take the variable assignment in the passed line and do it in the
- * global context.
- *
- * Note: There is a lexical ambiguity with assignment modifier characters
- * in variable names. This routine interprets the character before the =
- * as a modifier. Therefore, an assignment like
- * C++=/usr/bin/CC
- * is interpreted as "C+ +=" instead of "C++ =".
- *
- * Input:
- * line a line guaranteed to be a variable assignment.
- * This reduces error checks
- * ctxt Context in which to do the assignment
- *
- * Results:
- * none
- *
- * Side Effects:
- * the variable structure of the given variable name is altered in the
- * global context.
- *---------------------------------------------------------------------
- */
-void
-Parse_DoVar(char *line, GNode *ctxt)
-{
- char *cp; /* pointer into line */
- enum {
- VAR_SUBST, VAR_APPEND, VAR_SHELL, VAR_NORMAL
- } type; /* Type of assignment */
- char *opc; /* ptr to operator character to
- * null-terminate the variable name */
- Boolean freeCp = FALSE; /* TRUE if cp needs to be freed,
- * i.e. if any variable expansion was
- * performed */
- int depth;
-
- /*
- * Skip to variable name
- */
- while ((*line == ' ') || (*line == '\t')) {
- line++;
- }
-
- /*
- * Skip to operator character, nulling out whitespace as we go
- * XXX Rather than counting () and {} we should look for $ and
- * then expand the variable.
- */
- for (depth = 0, cp = line + 1; depth > 0 || *cp != '='; cp++) {
- if (*cp == '(' || *cp == '{') {
- depth++;
- continue;
- }
- if (*cp == ')' || *cp == '}') {
- depth--;
- continue;
- }
- if (depth == 0 && isspace ((unsigned char)*cp)) {
- *cp = '\0';
- }
- }
- opc = cp-1; /* operator is the previous character */
- *cp++ = '\0'; /* nuke the = */
-
- /*
- * Check operator type
- */
- switch (*opc) {
- case '+':
- type = VAR_APPEND;
- *opc = '\0';
- break;
-
- case '?':
- /*
- * If the variable already has a value, we don't do anything.
- */
- *opc = '\0';
- if (Var_Exists(line, ctxt)) {
- return;
- } else {
- type = VAR_NORMAL;
- }
- break;
-
- case ':':
- type = VAR_SUBST;
- *opc = '\0';
- break;
-
- case '!':
- type = VAR_SHELL;
- *opc = '\0';
- break;
-
- default:
-#ifdef SUNSHCMD
- while (opc > line && *opc != ':')
- opc--;
-
- if (strncmp(opc, ":sh", 3) == 0) {
- type = VAR_SHELL;
- *opc = '\0';
- break;
- }
-#endif
- type = VAR_NORMAL;
- break;
- }
-
- while (isspace ((unsigned char)*cp)) {
- cp++;
- }
-
- if (type == VAR_APPEND) {
- Var_Append(line, cp, ctxt);
- } else if (type == VAR_SUBST) {
- /*
- * Allow variables in the old value to be undefined, but leave their
- * invocation alone -- this is done by forcing oldVars to be false.
- * XXX: This can cause recursive variables, but that's not hard to do,
- * and this allows someone to do something like
- *
- * CFLAGS = $(.INCLUDES)
- * CFLAGS := -I.. $(CFLAGS)
- *
- * And not get an error.
- */
- Boolean oldOldVars = oldVars;
-
- oldVars = FALSE;
-
- /*
- * make sure that we set the variable the first time to nothing
- * so that it gets substituted!
- */
- if (!Var_Exists(line, ctxt))
- Var_Set(line, "", ctxt, 0);
-
- cp = Var_Subst(NULL, cp, ctxt, VARF_WANTRES|VARF_ASSIGN);
- oldVars = oldOldVars;
- freeCp = TRUE;
-
- Var_Set(line, cp, ctxt, 0);
- } else if (type == VAR_SHELL) {
- char *res;
- const char *error;
-
- if (strchr(cp, '$') != NULL) {
- /*
- * There's a dollar sign in the command, so perform variable
- * expansion on the whole thing. The resulting string will need
- * freeing when we're done, so set freeCmd to TRUE.
- */
- cp = Var_Subst(NULL, cp, VAR_CMD, VARF_UNDEFERR|VARF_WANTRES);
- freeCp = TRUE;
- }
-
- res = Cmd_Exec(cp, &error);
- Var_Set(line, res, ctxt, 0);
- free(res);
-
- if (error)
- Parse_Error(PARSE_WARNING, error, cp);
- } else {
- /*
- * Normal assignment -- just do it.
- */
- Var_Set(line, cp, ctxt, 0);
- }
- if (strcmp(line, MAKEOVERRIDES) == 0)
- Main_ExportMAKEFLAGS(FALSE); /* re-export MAKEFLAGS */
- else if (strcmp(line, ".CURDIR") == 0) {
- /*
- * Somone is being (too?) clever...
- * Let's pretend they know what they are doing and
- * re-initialize the 'cur' Path.
- */
- Dir_InitCur(cp);
- Dir_SetPATH();
- } else if (strcmp(line, MAKE_JOB_PREFIX) == 0) {
- Job_SetPrefix();
- } else if (strcmp(line, MAKE_EXPORTED) == 0) {
- Var_Export(cp, 0);
- }
- if (freeCp)
- free(cp);
-}
-
-
-/*
- * ParseMaybeSubMake --
- * Scan the command string to see if it a possible submake node
- * Input:
- * cmd the command to scan
- * Results:
- * TRUE if the command is possibly a submake, FALSE if not.
- */
-static Boolean
-ParseMaybeSubMake(const char *cmd)
-{
- size_t i;
- static struct {
- const char *name;
- size_t len;
- } vals[] = {
-#define MKV(A) { A, sizeof(A) - 1 }
- MKV("${MAKE}"),
- MKV("${.MAKE}"),
- MKV("$(MAKE)"),
- MKV("$(.MAKE)"),
- MKV("make"),
- };
- for (i = 0; i < sizeof(vals)/sizeof(vals[0]); i++) {
- char *ptr;
- if ((ptr = strstr(cmd, vals[i].name)) == NULL)
- continue;
- if ((ptr == cmd || !isalnum((unsigned char)ptr[-1]))
- && !isalnum((unsigned char)ptr[vals[i].len]))
- return TRUE;
- }
- return FALSE;
-}
-
-/*-
- * ParseAddCmd --
- * Lst_ForEach function to add a command line to all targets
- *
- * Input:
- * gnp the node to which the command is to be added
- * cmd the command to add
- *
- * Results:
- * Always 0
- *
- * Side Effects:
- * A new element is added to the commands list of the node,
- * and the node can be marked as a submake node if the command is
- * determined to be that.
- */
-static int
-ParseAddCmd(void *gnp, void *cmd)
-{
- GNode *gn = (GNode *)gnp;
-
- /* Add to last (ie current) cohort for :: targets */
- if ((gn->type & OP_DOUBLEDEP) && !Lst_IsEmpty (gn->cohorts))
- gn = (GNode *)Lst_Datum(Lst_Last(gn->cohorts));
-
- /* if target already supplied, ignore commands */
- if (!(gn->type & OP_HAS_COMMANDS)) {
- (void)Lst_AtEnd(gn->commands, cmd);
- if (ParseMaybeSubMake(cmd))
- gn->type |= OP_SUBMAKE;
- ParseMark(gn);
- } else {
-#ifdef notyet
- /* XXX: We cannot do this until we fix the tree */
- (void)Lst_AtEnd(gn->commands, cmd);
- Parse_Error(PARSE_WARNING,
- "overriding commands for target \"%s\"; "
- "previous commands defined at %s: %d ignored",
- gn->name, gn->fname, gn->lineno);
-#else
- Parse_Error(PARSE_WARNING,
- "duplicate script for target \"%s\" ignored",
- gn->name);
- ParseErrorInternal(gn->fname, gn->lineno, PARSE_WARNING,
- "using previous script for \"%s\" defined here",
- gn->name);
-#endif
- }
- return(0);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * ParseHasCommands --
- * Callback procedure for Parse_File when destroying the list of
- * targets on the last dependency line. Marks a target as already
- * having commands if it does, to keep from having shell commands
- * on multiple dependency lines.
- *
- * Input:
- * gnp Node to examine
- *
- * Results:
- * None
- *
- * Side Effects:
- * OP_HAS_COMMANDS may be set for the target.
- *
- *-----------------------------------------------------------------------
- */
-static void
-ParseHasCommands(void *gnp)
-{
- GNode *gn = (GNode *)gnp;
- if (!Lst_IsEmpty(gn->commands)) {
- gn->type |= OP_HAS_COMMANDS;
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Parse_AddIncludeDir --
- * Add a directory to the path searched for included makefiles
- * bracketed by double-quotes. Used by functions in main.c
- *
- * Input:
- * dir The name of the directory to add
- *
- * Results:
- * None.
- *
- * Side Effects:
- * The directory is appended to the list.
- *
- *-----------------------------------------------------------------------
- */
-void
-Parse_AddIncludeDir(char *dir)
-{
- (void)Dir_AddDir(parseIncPath, dir);
-}
-
-/*-
- *---------------------------------------------------------------------
- * ParseDoInclude --
- * Push to another file.
- *
- * The input is the line minus the `.'. A file spec is a string
- * enclosed in <> or "". The former is looked for only in sysIncPath.
- * The latter in . and the directories specified by -I command line
- * options
- *
- * Results:
- * None
- *
- * Side Effects:
- * A structure is added to the includes Lst and readProc, lineno,
- * fname and curFILE are altered for the new file
- *---------------------------------------------------------------------
- */
-
-static void
-Parse_include_file(char *file, Boolean isSystem, Boolean depinc, int silent)
-{
- struct loadedfile *lf;
- char *fullname; /* full pathname of file */
- char *newName;
- char *prefEnd, *incdir;
- int fd;
- int i;
-
- /*
- * Now we know the file's name and its search path, we attempt to
- * find the durn thing. A return of NULL indicates the file don't
- * exist.
- */
- fullname = file[0] == '/' ? bmake_strdup(file) : NULL;
-
- if (fullname == NULL && !isSystem) {
- /*
- * Include files contained in double-quotes are first searched for
- * relative to the including file's location. We don't want to
- * cd there, of course, so we just tack on the old file's
- * leading path components and call Dir_FindFile to see if
- * we can locate the beast.
- */
-
- incdir = bmake_strdup(curFile->fname);
- prefEnd = strrchr(incdir, '/');
- if (prefEnd != NULL) {
- *prefEnd = '\0';
- /* Now do lexical processing of leading "../" on the filename */
- for (i = 0; strncmp(file + i, "../", 3) == 0; i += 3) {
- prefEnd = strrchr(incdir + 1, '/');
- if (prefEnd == NULL || strcmp(prefEnd, "/..") == 0)
- break;
- *prefEnd = '\0';
- }
- newName = str_concat(incdir, file + i, STR_ADDSLASH);
- fullname = Dir_FindFile(newName, parseIncPath);
- if (fullname == NULL)
- fullname = Dir_FindFile(newName, dirSearchPath);
- free(newName);
- }
- free(incdir);
-
- if (fullname == NULL) {
- /*
- * Makefile wasn't found in same directory as included makefile.
- * Search for it first on the -I search path,
- * then on the .PATH search path, if not found in a -I directory.
- * If we have a suffix specific path we should use that.
- */
- char *suff;
- Lst suffPath = NULL;
-
- if ((suff = strrchr(file, '.'))) {
- suffPath = Suff_GetPath(suff);
- if (suffPath != NULL) {
- fullname = Dir_FindFile(file, suffPath);
- }
- }
- if (fullname == NULL) {
- fullname = Dir_FindFile(file, parseIncPath);
- if (fullname == NULL) {
- fullname = Dir_FindFile(file, dirSearchPath);
- }
- }
- }
- }
-
- /* Looking for a system file or file still not found */
- if (fullname == NULL) {
- /*
- * Look for it on the system path
- */
- fullname = Dir_FindFile(file,
- Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath);
- }
-
- if (fullname == NULL) {
- if (!silent)
- Parse_Error(PARSE_FATAL, "Could not find %s", file);
- return;
- }
-
- /* Actually open the file... */
- fd = open(fullname, O_RDONLY);
- if (fd == -1) {
- if (!silent)
- Parse_Error(PARSE_FATAL, "Cannot open %s", fullname);
- free(fullname);
- return;
- }
-
- /* load it */
- lf = loadfile(fullname, fd);
-
- ParseSetIncludedFile();
- /* Start reading from this file next */
- Parse_SetInput(fullname, 0, -1, loadedfile_nextbuf, lf);
- curFile->lf = lf;
- if (depinc)
- doing_depend = depinc; /* only turn it on */
-}
-
-static void
-ParseDoInclude(char *line)
-{
- char endc; /* the character which ends the file spec */
- char *cp; /* current position in file spec */
- int silent = (*line != 'i') ? 1 : 0;
- char *file = &line[7 + silent];
-
- /* Skip to delimiter character so we know where to look */
- while (*file == ' ' || *file == '\t')
- file++;
-
- if (*file != '"' && *file != '<') {
- Parse_Error(PARSE_FATAL,
- ".include filename must be delimited by '\"' or '<'");
- return;
- }
-
- /*
- * Set the search path on which to find the include file based on the
- * characters which bracket its name. Angle-brackets imply it's
- * a system Makefile while double-quotes imply it's a user makefile
- */
- if (*file == '<') {
- endc = '>';
- } else {
- endc = '"';
- }
-
- /* Skip to matching delimiter */
- for (cp = ++file; *cp && *cp != endc; cp++)
- continue;
-
- if (*cp != endc) {
- Parse_Error(PARSE_FATAL,
- "Unclosed %cinclude filename. '%c' expected",
- '.', endc);
- return;
- }
- *cp = '\0';
-
- /*
- * Substitute for any variables in the file name before trying to
- * find the thing.
- */
- file = Var_Subst(NULL, file, VAR_CMD, VARF_WANTRES);
-
- Parse_include_file(file, endc == '>', (*line == 'd'), silent);
- free(file);
-}
-
-
-/*-
- *---------------------------------------------------------------------
- * ParseSetIncludedFile --
- * Set the .INCLUDEDFROMFILE variable to the contents of .PARSEFILE
- * and the .INCLUDEDFROMDIR variable to the contents of .PARSEDIR
- *
- * Results:
- * None
- *
- * Side Effects:
- * The .INCLUDEDFROMFILE variable is overwritten by the contents
- * of .PARSEFILE and the .INCLUDEDFROMDIR variable is overwriten
- * by the contents of .PARSEDIR
- *---------------------------------------------------------------------
- */
-static void
-ParseSetIncludedFile(void)
-{
- char *pf, *fp = NULL;
- char *pd, *dp = NULL;
-
- pf = Var_Value(".PARSEFILE", VAR_GLOBAL, &fp);
- Var_Set(".INCLUDEDFROMFILE", pf, VAR_GLOBAL, 0);
- pd = Var_Value(".PARSEDIR", VAR_GLOBAL, &dp);
- Var_Set(".INCLUDEDFROMDIR", pd, VAR_GLOBAL, 0);
-
- if (DEBUG(PARSE))
- fprintf(debug_file, "%s: ${.INCLUDEDFROMDIR} = `%s' "
- "${.INCLUDEDFROMFILE} = `%s'\n", __func__, pd, pf);
-
- free(fp);
- free(dp);
-}
-/*-
- *---------------------------------------------------------------------
- * ParseSetParseFile --
- * Set the .PARSEDIR and .PARSEFILE variables to the dirname and
- * basename of the given filename
- *
- * Results:
- * None
- *
- * Side Effects:
- * The .PARSEDIR and .PARSEFILE variables are overwritten by the
- * dirname and basename of the given filename.
- *---------------------------------------------------------------------
- */
-static void
-ParseSetParseFile(const char *filename)
-{
- char *slash, *dirname;
- const char *pd, *pf;
- int len;
-
- slash = strrchr(filename, '/');
- if (slash == NULL) {
- Var_Set(".PARSEDIR", pd = curdir, VAR_GLOBAL, 0);
- Var_Set(".PARSEFILE", pf = filename, VAR_GLOBAL, 0);
- dirname= NULL;
- } else {
- len = slash - filename;
- dirname = bmake_malloc(len + 1);
- memcpy(dirname, filename, len);
- dirname[len] = '\0';
- Var_Set(".PARSEDIR", pd = dirname, VAR_GLOBAL, 0);
- Var_Set(".PARSEFILE", pf = slash + 1, VAR_GLOBAL, 0);
- }
- if (DEBUG(PARSE))
- fprintf(debug_file, "%s: ${.PARSEDIR} = `%s' ${.PARSEFILE} = `%s'\n",
- __func__, pd, pf);
- free(dirname);
-}
-
-/*
- * Track the makefiles we read - so makefiles can
- * set dependencies on them.
- * Avoid adding anything more than once.
- */
-
-static void
-ParseTrackInput(const char *name)
-{
- char *old;
- char *ep;
- char *fp = NULL;
- size_t name_len = strlen(name);
-
- old = Var_Value(MAKE_MAKEFILES, VAR_GLOBAL, &fp);
- if (old) {
- ep = old + strlen(old) - name_len;
- /* does it contain name? */
- for (; old != NULL; old = strchr(old, ' ')) {
- if (*old == ' ')
- old++;
- if (old >= ep)
- break; /* cannot contain name */
- if (memcmp(old, name, name_len) == 0
- && (old[name_len] == 0 || old[name_len] == ' '))
- goto cleanup;
- }
- }
- Var_Append (MAKE_MAKEFILES, name, VAR_GLOBAL);
- cleanup:
- if (fp) {
- free(fp);
- }
-}
-
-
-/*-
- *---------------------------------------------------------------------
- * Parse_setInput --
- * Start Parsing from the given source
- *
- * Results:
- * None
- *
- * Side Effects:
- * A structure is added to the includes Lst and readProc, lineno,
- * fname and curFile are altered for the new file
- *---------------------------------------------------------------------
- */
-void
-Parse_SetInput(const char *name, int line, int fd,
- char *(*nextbuf)(void *, size_t *), void *arg)
-{
- char *buf;
- size_t len;
-
- if (name == NULL)
- name = curFile->fname;
- else
- ParseTrackInput(name);
-
- if (DEBUG(PARSE))
- fprintf(debug_file, "%s: file %s, line %d, fd %d, nextbuf %p, arg %p\n",
- __func__, name, line, fd, nextbuf, arg);
-
- if (fd == -1 && nextbuf == NULL)
- /* sanity */
- return;
-
- if (curFile != NULL)
- /* Save exiting file info */
- Lst_AtFront(includes, curFile);
-
- /* Allocate and fill in new structure */
- curFile = bmake_malloc(sizeof *curFile);
-
- /*
- * Once the previous state has been saved, we can get down to reading
- * the new file. We set up the name of the file to be the absolute
- * name of the include file so error messages refer to the right
- * place.
- */
- curFile->fname = bmake_strdup(name);
- curFile->lineno = line;
- curFile->first_lineno = line;
- curFile->nextbuf = nextbuf;
- curFile->nextbuf_arg = arg;
- curFile->lf = NULL;
- curFile->depending = doing_depend; /* restore this on EOF */
-
- assert(nextbuf != NULL);
-
- /* Get first block of input data */
- buf = curFile->nextbuf(curFile->nextbuf_arg, &len);
- if (buf == NULL) {
- /* Was all a waste of time ... */
- if (curFile->fname)
- free(curFile->fname);
- free(curFile);
- return;
- }
- curFile->P_str = buf;
- curFile->P_ptr = buf;
- curFile->P_end = buf+len;
-
- curFile->cond_depth = Cond_save_depth();
- ParseSetParseFile(name);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * IsInclude --
- * Check if the line is an include directive
- *
- * Results:
- * TRUE if it is.
- *
- * Side Effects:
- * None
- *
- *-----------------------------------------------------------------------
- */
-static Boolean
-IsInclude(const char *line, Boolean sysv)
-{
- static const char inc[] = "include";
- static const size_t inclen = sizeof(inc) - 1;
-
- // 'd' is not valid for sysv
- int o = strchr(&("ds-"[sysv]), *line) != NULL;
-
- if (strncmp(line + o, inc, inclen) != 0)
- return FALSE;
-
- // Space is not mandatory for BSD .include
- return !sysv || isspace((unsigned char)line[inclen + o]);
-}
-
-
-#ifdef SYSVINCLUDE
-/*-
- *-----------------------------------------------------------------------
- * IsSysVInclude --
- * Check if the line is a SYSV include directive
- *
- * Results:
- * TRUE if it is.
- *
- * Side Effects:
- * None
- *
- *-----------------------------------------------------------------------
- */
-static Boolean
-IsSysVInclude(const char *line)
-{
- const char *p;
-
- if (!IsInclude(line, TRUE))
- return FALSE;
-
- /* Avoid interpeting a dependency line as an include */
- for (p = line; (p = strchr(p, ':')) != NULL;) {
- if (*++p == '\0') {
- /* end of line -> dependency */
- return FALSE;
- }
- if (*p == ':' || isspace((unsigned char)*p)) {
- /* :: operator or ': ' -> dependency */
- return FALSE;
- }
- }
- return TRUE;
-}
-
-/*-
- *---------------------------------------------------------------------
- * ParseTraditionalInclude --
- * Push to another file.
- *
- * The input is the current line. The file name(s) are
- * following the "include".
- *
- * Results:
- * None
- *
- * Side Effects:
- * A structure is added to the includes Lst and readProc, lineno,
- * fname and curFILE are altered for the new file
- *---------------------------------------------------------------------
- */
-static void
-ParseTraditionalInclude(char *line)
-{
- char *cp; /* current position in file spec */
- int done = 0;
- int silent = (line[0] != 'i') ? 1 : 0;
- char *file = &line[silent + 7];
- char *all_files;
-
- if (DEBUG(PARSE)) {
- fprintf(debug_file, "%s: %s\n", __func__, file);
- }
-
- /*
- * Skip over whitespace
- */
- while (isspace((unsigned char)*file))
- file++;
-
- /*
- * Substitute for any variables in the file name before trying to
- * find the thing.
- */
- all_files = Var_Subst(NULL, file, VAR_CMD, VARF_WANTRES);
-
- if (*file == '\0') {
- Parse_Error(PARSE_FATAL,
- "Filename missing from \"include\"");
- goto out;
- }
-
- for (file = all_files; !done; file = cp + 1) {
- /* Skip to end of line or next whitespace */
- for (cp = file; *cp && !isspace((unsigned char) *cp); cp++)
- continue;
-
- if (*cp)
- *cp = '\0';
- else
- done = 1;
-
- Parse_include_file(file, FALSE, FALSE, silent);
- }
-out:
- free(all_files);
-}
-#endif
-
-#ifdef GMAKEEXPORT
-/*-
- *---------------------------------------------------------------------
- * ParseGmakeExport --
- * Parse export <variable>=<value>
- *
- * And set the environment with it.
- *
- * Results:
- * None
- *
- * Side Effects:
- * None
- *---------------------------------------------------------------------
- */
-static void
-ParseGmakeExport(char *line)
-{
- char *variable = &line[6];
- char *value;
-
- if (DEBUG(PARSE)) {
- fprintf(debug_file, "%s: %s\n", __func__, variable);
- }
-
- /*
- * Skip over whitespace
- */
- while (isspace((unsigned char)*variable))
- variable++;
-
- for (value = variable; *value && *value != '='; value++)
- continue;
-
- if (*value != '=') {
- Parse_Error(PARSE_FATAL,
- "Variable/Value missing from \"export\"");
- return;
- }
- *value++ = '\0'; /* terminate variable */
-
- /*
- * Expand the value before putting it in the environment.
- */
- value = Var_Subst(NULL, value, VAR_CMD, VARF_WANTRES);
- setenv(variable, value, 1);
- free(value);
-}
-#endif
-
-/*-
- *---------------------------------------------------------------------
- * ParseEOF --
- * Called when EOF is reached in the current file. If we were reading
- * an include file, the includes stack is popped and things set up
- * to go back to reading the previous file at the previous location.
- *
- * Results:
- * CONTINUE if there's more to do. DONE if not.
- *
- * Side Effects:
- * The old curFILE, is closed. The includes list is shortened.
- * lineno, curFILE, and fname are changed if CONTINUE is returned.
- *---------------------------------------------------------------------
- */
-static int
-ParseEOF(void)
-{
- char *ptr;
- size_t len;
-
- assert(curFile->nextbuf != NULL);
-
- doing_depend = curFile->depending; /* restore this */
- /* get next input buffer, if any */
- ptr = curFile->nextbuf(curFile->nextbuf_arg, &len);
- curFile->P_ptr = ptr;
- curFile->P_str = ptr;
- curFile->P_end = ptr + len;
- curFile->lineno = curFile->first_lineno;
- if (ptr != NULL) {
- /* Iterate again */
- return CONTINUE;
- }
-
- /* Ensure the makefile (or loop) didn't have mismatched conditionals */
- Cond_restore_depth(curFile->cond_depth);
-
- if (curFile->lf != NULL) {
- loadedfile_destroy(curFile->lf);
- curFile->lf = NULL;
- }
-
- /* Dispose of curFile info */
- /* Leak curFile->fname because all the gnodes have pointers to it */
- free(curFile->P_str);
- free(curFile);
-
- curFile = Lst_DeQueue(includes);
-
- if (curFile == NULL) {
- /* We've run out of input */
- Var_Delete(".PARSEDIR", VAR_GLOBAL);
- Var_Delete(".PARSEFILE", VAR_GLOBAL);
- Var_Delete(".INCLUDEDFROMDIR", VAR_GLOBAL);
- Var_Delete(".INCLUDEDFROMFILE", VAR_GLOBAL);
- return DONE;
- }
-
- if (DEBUG(PARSE))
- fprintf(debug_file, "ParseEOF: returning to file %s, line %d\n",
- curFile->fname, curFile->lineno);
-
- /* Restore the PARSEDIR/PARSEFILE variables */
- ParseSetParseFile(curFile->fname);
- return (CONTINUE);
-}
-
-#define PARSE_RAW 1
-#define PARSE_SKIP 2
-
-static char *
-ParseGetLine(int flags, int *length)
-{
- IFile *cf = curFile;
- char *ptr;
- char ch;
- char *line;
- char *line_end;
- char *escaped;
- char *comment;
- char *tp;
-
- /* Loop through blank lines and comment lines */
- for (;;) {
- cf->lineno++;
- line = cf->P_ptr;
- ptr = line;
- line_end = line;
- escaped = NULL;
- comment = NULL;
- for (;;) {
- if (cf->P_end != NULL && ptr == cf->P_end) {
- /* end of buffer */
- ch = 0;
- break;
- }
- ch = *ptr;
- if (ch == 0 || (ch == '\\' && ptr[1] == 0)) {
- if (cf->P_end == NULL)
- /* End of string (aka for loop) data */
- break;
- /* see if there is more we can parse */
- while (ptr++ < cf->P_end) {
- if ((ch = *ptr) == '\n') {
- if (ptr > line && ptr[-1] == '\\')
- continue;
- Parse_Error(PARSE_WARNING,
- "Zero byte read from file, skipping rest of line.");
- break;
- }
- }
- if (cf->nextbuf != NULL) {
- /*
- * End of this buffer; return EOF and outer logic
- * will get the next one. (eww)
- */
- break;
- }
- Parse_Error(PARSE_FATAL, "Zero byte read from file");
- return NULL;
- }
-
- if (ch == '\\') {
- /* Don't treat next character as special, remember first one */
- if (escaped == NULL)
- escaped = ptr;
- if (ptr[1] == '\n')
- cf->lineno++;
- ptr += 2;
- line_end = ptr;
- continue;
- }
- if (ch == '#' && comment == NULL) {
- /* Remember first '#' for comment stripping */
- /* Unless previous char was '[', as in modifier :[#] */
- if (!(ptr > line && ptr[-1] == '['))
- comment = line_end;
- }
- ptr++;
- if (ch == '\n')
- break;
- if (!isspace((unsigned char)ch))
- /* We are not interested in trailing whitespace */
- line_end = ptr;
- }
-
- /* Save next 'to be processed' location */
- cf->P_ptr = ptr;
-
- /* Check we have a non-comment, non-blank line */
- if (line_end == line || comment == line) {
- if (ch == 0)
- /* At end of file */
- return NULL;
- /* Parse another line */
- continue;
- }
-
- /* We now have a line of data */
- *line_end = 0;
-
- if (flags & PARSE_RAW) {
- /* Leave '\' (etc) in line buffer (eg 'for' lines) */
- *length = line_end - line;
- return line;
- }
-
- if (flags & PARSE_SKIP) {
- /* Completely ignore non-directives */
- if (line[0] != '.')
- continue;
- /* We could do more of the .else/.elif/.endif checks here */
- }
- break;
- }
-
- /* Brutally ignore anything after a non-escaped '#' in non-commands */
- if (comment != NULL && line[0] != '\t') {
- line_end = comment;
- *line_end = 0;
- }
-
- /* If we didn't see a '\\' then the in-situ data is fine */
- if (escaped == NULL) {
- *length = line_end - line;
- return line;
- }
-
- /* Remove escapes from '\n' and '#' */
- tp = ptr = escaped;
- escaped = line;
- for (; ; *tp++ = ch) {
- ch = *ptr++;
- if (ch != '\\') {
- if (ch == 0)
- break;
- continue;
- }
-
- ch = *ptr++;
- if (ch == 0) {
- /* Delete '\\' at end of buffer */
- tp--;
- break;
- }
-
- if (ch == '#' && line[0] != '\t')
- /* Delete '\\' from before '#' on non-command lines */
- continue;
-
- if (ch != '\n') {
- /* Leave '\\' in buffer for later */
- *tp++ = '\\';
- /* Make sure we don't delete an escaped ' ' from the line end */
- escaped = tp + 1;
- continue;
- }
-
- /* Escaped '\n' replace following whitespace with a single ' ' */
- while (ptr[0] == ' ' || ptr[0] == '\t')
- ptr++;
- ch = ' ';
- }
-
- /* Delete any trailing spaces - eg from empty continuations */
- while (tp > escaped && isspace((unsigned char)tp[-1]))
- tp--;
-
- *tp = 0;
- *length = tp - line;
- return line;
-}
-
-/*-
- *---------------------------------------------------------------------
- * ParseReadLine --
- * Read an entire line from the input file. Called only by Parse_File.
- *
- * Results:
- * A line w/o its newline
- *
- * Side Effects:
- * Only those associated with reading a character
- *---------------------------------------------------------------------
- */
-static char *
-ParseReadLine(void)
-{
- char *line; /* Result */
- int lineLength; /* Length of result */
- int lineno; /* Saved line # */
- int rval;
-
- for (;;) {
- line = ParseGetLine(0, &lineLength);
- if (line == NULL)
- return NULL;
-
- if (line[0] != '.')
- return line;
-
- /*
- * The line might be a conditional. Ask the conditional module
- * about it and act accordingly
- */
- switch (Cond_Eval(line)) {
- case COND_SKIP:
- /* Skip to next conditional that evaluates to COND_PARSE. */
- do {
- line = ParseGetLine(PARSE_SKIP, &lineLength);
- } while (line && Cond_Eval(line) != COND_PARSE);
- if (line == NULL)
- break;
- continue;
- case COND_PARSE:
- continue;
- case COND_INVALID: /* Not a conditional line */
- /* Check for .for loops */
- rval = For_Eval(line);
- if (rval == 0)
- /* Not a .for line */
- break;
- if (rval < 0)
- /* Syntax error - error printed, ignore line */
- continue;
- /* Start of a .for loop */
- lineno = curFile->lineno;
- /* Accumulate loop lines until matching .endfor */
- do {
- line = ParseGetLine(PARSE_RAW, &lineLength);
- if (line == NULL) {
- Parse_Error(PARSE_FATAL,
- "Unexpected end of file in for loop.");
- break;
- }
- } while (For_Accum(line));
- /* Stash each iteration as a new 'input file' */
- For_Run(lineno);
- /* Read next line from for-loop buffer */
- continue;
- }
- return (line);
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * ParseFinishLine --
- * Handle the end of a dependency group.
- *
- * Results:
- * Nothing.
- *
- * Side Effects:
- * inLine set FALSE. 'targets' list destroyed.
- *
- *-----------------------------------------------------------------------
- */
-static void
-ParseFinishLine(void)
-{
- if (inLine) {
- Lst_ForEach(targets, Suff_EndTransform, NULL);
- Lst_Destroy(targets, ParseHasCommands);
- targets = NULL;
- inLine = FALSE;
- }
-}
-
-
-/*-
- *---------------------------------------------------------------------
- * Parse_File --
- * Parse a file into its component parts, incorporating it into the
- * current dependency graph. This is the main function and controls
- * almost every other function in this module
- *
- * Input:
- * name the name of the file being read
- * fd Open file to makefile to parse
- *
- * Results:
- * None
- *
- * Side Effects:
- * closes fd.
- * Loads. Nodes are added to the list of all targets, nodes and links
- * are added to the dependency graph. etc. etc. etc.
- *---------------------------------------------------------------------
- */
-void
-Parse_File(const char *name, int fd)
-{
- char *cp; /* pointer into the line */
- char *line; /* the line we're working on */
- struct loadedfile *lf;
-
- lf = loadfile(name, fd);
-
- inLine = FALSE;
- fatals = 0;
-
- if (name == NULL) {
- name = "(stdin)";
- }
-
- Parse_SetInput(name, 0, -1, loadedfile_nextbuf, lf);
- curFile->lf = lf;
-
- do {
- for (; (line = ParseReadLine()) != NULL; ) {
- if (DEBUG(PARSE))
- fprintf(debug_file, "ParseReadLine (%d): '%s'\n",
- curFile->lineno, line);
- if (*line == '.') {
- /*
- * Lines that begin with the special character may be
- * include or undef directives.
- * On the other hand they can be suffix rules (.c.o: ...)
- * or just dependencies for filenames that start '.'.
- */
- for (cp = line + 1; isspace((unsigned char)*cp); cp++) {
- continue;
- }
- if (IsInclude(cp, FALSE)) {
- ParseDoInclude(cp);
- continue;
- }
- if (strncmp(cp, "undef", 5) == 0) {
- char *cp2;
- for (cp += 5; isspace((unsigned char) *cp); cp++)
- continue;
- for (cp2 = cp; !isspace((unsigned char) *cp2) &&
- (*cp2 != '\0'); cp2++)
- continue;
- *cp2 = '\0';
- Var_Delete(cp, VAR_GLOBAL);
- continue;
- } else if (strncmp(cp, "export", 6) == 0) {
- for (cp += 6; isspace((unsigned char) *cp); cp++)
- continue;
- Var_Export(cp, 1);
- continue;
- } else if (strncmp(cp, "unexport", 8) == 0) {
- Var_UnExport(cp);
- continue;
- } else if (strncmp(cp, "info", 4) == 0 ||
- strncmp(cp, "error", 5) == 0 ||
- strncmp(cp, "warning", 7) == 0) {
- if (ParseMessage(cp))
- continue;
- }
- }
-
- if (*line == '\t') {
- /*
- * If a line starts with a tab, it can only hope to be
- * a creation command.
- */
- cp = line + 1;
- shellCommand:
- for (; isspace ((unsigned char)*cp); cp++) {
- continue;
- }
- if (*cp) {
- if (!inLine)
- Parse_Error(PARSE_FATAL,
- "Unassociated shell command \"%s\"",
- cp);
- /*
- * So long as it's not a blank line and we're actually
- * in a dependency spec, add the command to the list of
- * commands of all targets in the dependency spec
- */
- if (targets) {
- cp = bmake_strdup(cp);
- Lst_ForEach(targets, ParseAddCmd, cp);
-#ifdef CLEANUP
- Lst_AtEnd(targCmds, cp);
-#endif
- }
- }
- continue;
- }
-
-#ifdef SYSVINCLUDE
- if (IsSysVInclude(line)) {
- /*
- * It's an S3/S5-style "include".
- */
- ParseTraditionalInclude(line);
- continue;
- }
-#endif
-#ifdef GMAKEEXPORT
- if (strncmp(line, "export", 6) == 0 &&
- isspace((unsigned char) line[6]) &&
- strchr(line, ':') == NULL) {
- /*
- * It's a Gmake "export".
- */
- ParseGmakeExport(line);
- continue;
- }
-#endif
- if (Parse_IsVar(line)) {
- ParseFinishLine();
- Parse_DoVar(line, VAR_GLOBAL);
- continue;
- }
-
-#ifndef POSIX
- /*
- * To make life easier on novices, if the line is indented we
- * first make sure the line has a dependency operator in it.
- * If it doesn't have an operator and we're in a dependency
- * line's script, we assume it's actually a shell command
- * and add it to the current list of targets.
- */
- cp = line;
- if (isspace((unsigned char) line[0])) {
- while ((*cp != '\0') && isspace((unsigned char) *cp))
- cp++;
- while (*cp && (ParseIsEscaped(line, cp) ||
- (*cp != ':') && (*cp != '!'))) {
- cp++;
- }
- if (*cp == '\0') {
- if (inLine) {
- Parse_Error(PARSE_WARNING,
- "Shell command needs a leading tab");
- goto shellCommand;
- }
- }
- }
-#endif
- ParseFinishLine();
-
- /*
- * For some reason - probably to make the parser impossible -
- * a ';' can be used to separate commands from dependencies.
- * Attempt to avoid ';' inside substitution patterns.
- */
- {
- int level = 0;
-
- for (cp = line; *cp != 0; cp++) {
- if (*cp == '\\' && cp[1] != 0) {
- cp++;
- continue;
- }
- if (*cp == '$' &&
- (cp[1] == '(' || cp[1] == '{')) {
- level++;
- continue;
- }
- if (level > 0) {
- if (*cp == ')' || *cp == '}') {
- level--;
- continue;
- }
- } else if (*cp == ';') {
- break;
- }
- }
- }
- if (*cp != 0)
- /* Terminate the dependency list at the ';' */
- *cp++ = 0;
- else
- cp = NULL;
-
- /*
- * We now know it's a dependency line so it needs to have all
- * variables expanded before being parsed. Tell the variable
- * module to complain if some variable is undefined...
- */
- line = Var_Subst(NULL, line, VAR_CMD, VARF_UNDEFERR|VARF_WANTRES);
-
- /*
- * Need a non-circular list for the target nodes
- */
- if (targets)
- Lst_Destroy(targets, NULL);
-
- targets = Lst_Init(FALSE);
- inLine = TRUE;
-
- ParseDoDependency(line);
- free(line);
-
- /* If there were commands after a ';', add them now */
- if (cp != NULL) {
- goto shellCommand;
- }
- }
- /*
- * Reached EOF, but it may be just EOF of an include file...
- */
- } while (ParseEOF() == CONTINUE);
-
- if (fatals) {
- (void)fflush(stdout);
- (void)fprintf(stderr,
- "%s: Fatal errors encountered -- cannot continue",
- progname);
- PrintOnError(NULL, NULL);
- exit(1);
- }
-}
-
-/*-
- *---------------------------------------------------------------------
- * Parse_Init --
- * initialize the parsing module
- *
- * Results:
- * none
- *
- * Side Effects:
- * the parseIncPath list is initialized...
- *---------------------------------------------------------------------
- */
-void
-Parse_Init(void)
-{
- mainNode = NULL;
- parseIncPath = Lst_Init(FALSE);
- sysIncPath = Lst_Init(FALSE);
- defIncPath = Lst_Init(FALSE);
- includes = Lst_Init(FALSE);
-#ifdef CLEANUP
- targCmds = Lst_Init(FALSE);
-#endif
-}
-
-void
-Parse_End(void)
-{
-#ifdef CLEANUP
- Lst_Destroy(targCmds, (FreeProc *)free);
- if (targets)
- Lst_Destroy(targets, NULL);
- Lst_Destroy(defIncPath, Dir_Destroy);
- Lst_Destroy(sysIncPath, Dir_Destroy);
- Lst_Destroy(parseIncPath, Dir_Destroy);
- Lst_Destroy(includes, NULL); /* Should be empty now */
-#endif
-}
-
-
-/*-
- *-----------------------------------------------------------------------
- * Parse_MainName --
- * Return a Lst of the main target to create for main()'s sake. If
- * no such target exists, we Punt with an obnoxious error message.
- *
- * Results:
- * A Lst of the single node to create.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-Lst
-Parse_MainName(void)
-{
- Lst mainList; /* result list */
-
- mainList = Lst_Init(FALSE);
-
- if (mainNode == NULL) {
- Punt("no target to make.");
- /*NOTREACHED*/
- } else if (mainNode->type & OP_DOUBLEDEP) {
- (void)Lst_AtEnd(mainList, mainNode);
- Lst_Concat(mainList, mainNode->cohorts, LST_CONCNEW);
- }
- else
- (void)Lst_AtEnd(mainList, mainNode);
- Var_Append(".TARGETS", mainNode->name, VAR_GLOBAL);
- return (mainList);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * ParseMark --
- * Add the filename and lineno to the GNode so that we remember
- * where it was first defined.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-static void
-ParseMark(GNode *gn)
-{
- gn->fname = curFile->fname;
- gn->lineno = curFile->lineno;
-}
diff --git a/usr.bin/make/pathnames.h b/usr.bin/make/pathnames.h
deleted file mode 100644
index 12c4f3d..0000000
--- a/usr.bin/make/pathnames.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* $NetBSD: pathnames.h,v 1.17 2009/04/11 09:41:18 apb Exp $ */
-
-/*
- * Copyright (c) 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 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.
- *
- * from: @(#)pathnames.h 5.2 (Berkeley) 6/1/90
- */
-
-#ifndef MAKE_NATIVE
-#if HAVE_NBTOOL_CONFIG_H
-#include "nbtool_config.h"
-#endif
-#else
-#include <paths.h>
-#endif
-
-#define _PATH_OBJDIR "obj"
-#define _PATH_OBJDIRPREFIX "/usr/obj"
-#ifndef _PATH_DEFSHELLDIR
-#define _PATH_DEFSHELLDIR "/bin"
-#endif
-#define _PATH_DEFSYSMK "sys.mk"
-#ifndef _PATH_DEFSYSPATH
-#define _PATH_DEFSYSPATH "/usr/share/mk"
-#endif
-#ifndef _PATH_TMP
-#define _PATH_TMP "/tmp/" /* with trailing slash */
-#endif
diff --git a/usr.bin/make/sprite.h b/usr.bin/make/sprite.h
deleted file mode 100644
index cdcffd9..0000000
--- a/usr.bin/make/sprite.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/* $NetBSD: sprite.h,v 1.14 2017/05/31 22:02:06 maya Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- *
- * from: @(#)sprite.h 8.1 (Berkeley) 6/6/93
- */
-
-/*
- * Copyright (c) 1989 by Berkeley Softworks
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. 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.
- *
- * from: @(#)sprite.h 8.1 (Berkeley) 6/6/93
- */
-
-/*
- * sprite.h --
- *
- * Common constants and type declarations for Sprite.
- */
-
-#ifndef MAKE_SPRITE_H
-#define MAKE_SPRITE_H
-
-
-/*
- * A boolean type is defined as an integer, not an enum. This allows a
- * boolean argument to be an expression that isn't strictly 0 or 1 valued.
- */
-
-typedef int Boolean;
-#ifndef TRUE
-#define TRUE 1
-#endif /* TRUE */
-#ifndef FALSE
-#define FALSE 0
-#endif /* FALSE */
-
-/*
- * Functions that must return a status can return a ReturnStatus to
- * indicate success or type of failure.
- */
-
-typedef int ReturnStatus;
-
-/*
- * The following statuses overlap with the first 2 generic statuses
- * defined in status.h:
- *
- * SUCCESS There was no error.
- * FAILURE There was a general error.
- */
-
-#define SUCCESS 0x00000000
-#define FAILURE 0x00000001
-
-#endif /* MAKE_SPRITE_H */
diff --git a/usr.bin/make/str.c b/usr.bin/make/str.c
deleted file mode 100644
index b5255bc..0000000
--- a/usr.bin/make/str.c
+++ /dev/null
@@ -1,526 +0,0 @@
-/* $NetBSD: str.c,v 1.38 2017/04/21 22:15:44 sjg Exp $ */
-
-/*-
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-/*-
- * Copyright (c) 1989 by Berkeley Softworks
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: str.c,v 1.38 2017/04/21 22:15:44 sjg Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)str.c 5.8 (Berkeley) 6/1/90";
-#else
-__RCSID("$NetBSD: str.c,v 1.38 2017/04/21 22:15:44 sjg Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-#include "make.h"
-
-/*-
- * str_concat --
- * concatenate the two strings, inserting a space or slash between them,
- * freeing them if requested.
- *
- * returns --
- * the resulting string in allocated space.
- */
-char *
-str_concat(const char *s1, const char *s2, int flags)
-{
- int len1, len2;
- char *result;
-
- /* get the length of both strings */
- len1 = strlen(s1);
- len2 = strlen(s2);
-
- /* allocate length plus separator plus EOS */
- result = bmake_malloc((unsigned int)(len1 + len2 + 2));
-
- /* copy first string into place */
- memcpy(result, s1, len1);
-
- /* add separator character */
- if (flags & STR_ADDSPACE) {
- result[len1] = ' ';
- ++len1;
- } else if (flags & STR_ADDSLASH) {
- result[len1] = '/';
- ++len1;
- }
-
- /* copy second string plus EOS into place */
- memcpy(result + len1, s2, len2 + 1);
-
- return(result);
-}
-
-/*-
- * brk_string --
- * Fracture a string into an array of words (as delineated by tabs or
- * spaces) taking quotation marks into account. Leading tabs/spaces
- * are ignored.
- *
- * If expand is TRUE, quotes are removed and escape sequences
- * such as \r, \t, etc... are expanded.
- *
- * returns --
- * Pointer to the array of pointers to the words.
- * Memory containing the actual words in *buffer.
- * Both of these must be free'd by the caller.
- * Number of words in *store_argc.
- */
-char **
-brk_string(const char *str, int *store_argc, Boolean expand, char **buffer)
-{
- int argc, ch;
- char inquote, *start, *t;
- const char *p;
- int len;
- int argmax = 50, curlen = 0;
- char **argv;
-
- /* skip leading space chars. */
- for (; *str == ' ' || *str == '\t'; ++str)
- continue;
-
- /* allocate room for a copy of the string */
- if ((len = strlen(str) + 1) > curlen)
- *buffer = bmake_malloc(curlen = len);
-
- /*
- * initial argmax based on len
- */
- argmax = MAX((len / 5), 50);
- argv = bmake_malloc((argmax + 1) * sizeof(char *));
-
- /*
- * copy the string; at the same time, parse backslashes,
- * quotes and build the argument list.
- */
- argc = 0;
- inquote = '\0';
- for (p = str, start = t = *buffer;; ++p) {
- switch(ch = *p) {
- case '"':
- case '\'':
- if (inquote) {
- if (inquote == ch)
- inquote = '\0';
- else
- break;
- }
- else {
- inquote = (char) ch;
- /* Don't miss "" or '' */
- if (start == NULL && p[1] == inquote) {
- if (!expand) {
- start = t;
- *t++ = ch;
- } else
- start = t + 1;
- p++;
- inquote = '\0';
- break;
- }
- }
- if (!expand) {
- if (!start)
- start = t;
- *t++ = ch;
- }
- continue;
- case ' ':
- case '\t':
- case '\n':
- if (inquote)
- break;
- if (!start)
- continue;
- /* FALLTHROUGH */
- case '\0':
- /*
- * end of a token -- make sure there's enough argv
- * space and save off a pointer.
- */
- if (!start)
- goto done;
-
- *t++ = '\0';
- if (argc == argmax) {
- argmax *= 2; /* ramp up fast */
- argv = (char **)bmake_realloc(argv,
- (argmax + 1) * sizeof(char *));
- }
- argv[argc++] = start;
- start = NULL;
- if (ch == '\n' || ch == '\0') {
- if (expand && inquote) {
- free(argv);
- free(*buffer);
- *buffer = NULL;
- return NULL;
- }
- goto done;
- }
- continue;
- case '\\':
- if (!expand) {
- if (!start)
- start = t;
- *t++ = '\\';
- if (*(p+1) == '\0') /* catch '\' at end of line */
- continue;
- ch = *++p;
- break;
- }
-
- switch (ch = *++p) {
- case '\0':
- case '\n':
- /* hmmm; fix it up as best we can */
- ch = '\\';
- --p;
- break;
- case 'b':
- ch = '\b';
- break;
- case 'f':
- ch = '\f';
- break;
- case 'n':
- ch = '\n';
- break;
- case 'r':
- ch = '\r';
- break;
- case 't':
- ch = '\t';
- break;
- }
- break;
- }
- if (!start)
- start = t;
- *t++ = (char) ch;
- }
-done: argv[argc] = NULL;
- *store_argc = argc;
- return(argv);
-}
-
-/*
- * Str_FindSubstring -- See if a string contains a particular substring.
- *
- * Input:
- * string String to search.
- * substring Substring to find in string.
- *
- * Results: If string contains substring, the return value is the location of
- * the first matching instance of substring in string. If string doesn't
- * contain substring, the return value is NULL. Matching is done on an exact
- * character-for-character basis with no wildcards or special characters.
- *
- * Side effects: None.
- */
-char *
-Str_FindSubstring(const char *string, const char *substring)
-{
- const char *a, *b;
-
- /*
- * First scan quickly through the two strings looking for a single-
- * character match. When it's found, then compare the rest of the
- * substring.
- */
-
- for (b = substring; *string != 0; string += 1) {
- if (*string != *b)
- continue;
- a = string;
- for (;;) {
- if (*b == 0)
- return UNCONST(string);
- if (*a++ != *b++)
- break;
- }
- b = substring;
- }
- return NULL;
-}
-
-/*
- * Str_Match --
- *
- * See if a particular string matches a particular pattern.
- *
- * Results: Non-zero is returned if string matches pattern, 0 otherwise. The
- * matching operation permits the following special characters in the
- * pattern: *?\[] (see the man page for details on what these mean).
- *
- * XXX this function does not detect or report malformed patterns.
- *
- * Side effects: None.
- */
-int
-Str_Match(const char *string, const char *pattern)
-{
- char c2;
-
- for (;;) {
- /*
- * See if we're at the end of both the pattern and the
- * string. If, we succeeded. If we're at the end of the
- * pattern but not at the end of the string, we failed.
- */
- if (*pattern == 0)
- return(!*string);
- if (*string == 0 && *pattern != '*')
- return(0);
- /*
- * Check for a "*" as the next pattern character. It matches
- * any substring. We handle this by calling ourselves
- * recursively for each postfix of string, until either we
- * match or we reach the end of the string.
- */
- if (*pattern == '*') {
- pattern += 1;
- if (*pattern == 0)
- return(1);
- while (*string != 0) {
- if (Str_Match(string, pattern))
- return(1);
- ++string;
- }
- return(0);
- }
- /*
- * Check for a "?" as the next pattern character. It matches
- * any single character.
- */
- if (*pattern == '?')
- goto thisCharOK;
- /*
- * Check for a "[" as the next pattern character. It is
- * followed by a list of characters that are acceptable, or
- * by a range (two characters separated by "-").
- */
- if (*pattern == '[') {
- int nomatch;
-
- ++pattern;
- if (*pattern == '^') {
- ++pattern;
- nomatch = 1;
- } else
- nomatch = 0;
- for (;;) {
- if ((*pattern == ']') || (*pattern == 0)) {
- if (nomatch)
- break;
- return(0);
- }
- if (*pattern == *string)
- break;
- if (pattern[1] == '-') {
- c2 = pattern[2];
- if (c2 == 0)
- return(nomatch);
- if ((*pattern <= *string) &&
- (c2 >= *string))
- break;
- if ((*pattern >= *string) &&
- (c2 <= *string))
- break;
- pattern += 2;
- }
- ++pattern;
- }
- if (nomatch && (*pattern != ']') && (*pattern != 0))
- return 0;
- while ((*pattern != ']') && (*pattern != 0))
- ++pattern;
- goto thisCharOK;
- }
- /*
- * If the next pattern character is '/', just strip off the
- * '/' so we do exact matching on the character that follows.
- */
- if (*pattern == '\\') {
- ++pattern;
- if (*pattern == 0)
- return(0);
- }
- /*
- * There's no special character. Just make sure that the
- * next characters of each string match.
- */
- if (*pattern != *string)
- return(0);
-thisCharOK: ++pattern;
- ++string;
- }
-}
-
-
-/*-
- *-----------------------------------------------------------------------
- * Str_SYSVMatch --
- * Check word against pattern for a match (% is wild),
- *
- * Input:
- * word Word to examine
- * pattern Pattern to examine against
- * len Number of characters to substitute
- *
- * Results:
- * Returns the beginning position of a match or null. The number
- * of characters matched is returned in len.
- *
- * Side Effects:
- * None
- *
- *-----------------------------------------------------------------------
- */
-char *
-Str_SYSVMatch(const char *word, const char *pattern, int *len)
-{
- const char *p = pattern;
- const char *w = word;
- const char *m;
-
- if (*p == '\0') {
- /* Null pattern is the whole string */
- *len = strlen(w);
- return UNCONST(w);
- }
-
- if ((m = strchr(p, '%')) != NULL) {
- /* check that the prefix matches */
- for (; p != m && *w && *w == *p; w++, p++)
- continue;
-
- if (p != m)
- return NULL; /* No match */
-
- if (*++p == '\0') {
- /* No more pattern, return the rest of the string */
- *len = strlen(w);
- return UNCONST(w);
- }
- }
-
- m = w;
-
- /* Find a matching tail */
- do
- if (strcmp(p, w) == 0) {
- *len = w - m;
- return UNCONST(m);
- }
- while (*w++ != '\0');
-
- return NULL;
-}
-
-
-/*-
- *-----------------------------------------------------------------------
- * Str_SYSVSubst --
- * Substitute '%' on the pattern with len characters from src.
- * If the pattern does not contain a '%' prepend len characters
- * from src.
- *
- * Results:
- * None
- *
- * Side Effects:
- * Places result on buf
- *
- *-----------------------------------------------------------------------
- */
-void
-Str_SYSVSubst(Buffer *buf, char *pat, char *src, int len)
-{
- char *m;
-
- if ((m = strchr(pat, '%')) != NULL) {
- /* Copy the prefix */
- Buf_AddBytes(buf, m - pat, pat);
- /* skip the % */
- pat = m + 1;
- }
-
- /* Copy the pattern */
- Buf_AddBytes(buf, len, src);
-
- /* append the rest */
- Buf_AddBytes(buf, strlen(pat), pat);
-}
diff --git a/usr.bin/make/strlist.c b/usr.bin/make/strlist.c
deleted file mode 100644
index 3fb2f7d..0000000
--- a/usr.bin/make/strlist.c
+++ /dev/null
@@ -1,93 +0,0 @@
-/* $NetBSD: strlist.c,v 1.4 2009/01/24 11:59:39 dsl Exp $ */
-
-/*-
- * Copyright (c) 2008 - 2009 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * This code is derived from software contributed to The NetBSD Foundation
- * by David Laight.
- *
- * 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 NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: strlist.c,v 1.4 2009/01/24 11:59:39 dsl Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-__RCSID("$NetBSD: strlist.c,v 1.4 2009/01/24 11:59:39 dsl Exp $");
-#endif /* not lint */
-#endif
-
-#include <stddef.h>
-#include <stdlib.h>
-#include "strlist.h"
-#include "make_malloc.h"
-
-void
-strlist_init(strlist_t *sl)
-{
- sl->sl_num = 0;
- sl->sl_max = 0;
- sl->sl_items = NULL;
-}
-
-void
-strlist_clean(strlist_t *sl)
-{
- char *str;
- int i;
-
- STRLIST_FOREACH(str, sl, i)
- free(str);
- free(sl->sl_items);
-
- sl->sl_num = 0;
- sl->sl_max = 0;
- sl->sl_items = NULL;
-}
-
-void
-strlist_add_str(strlist_t *sl, char *str, unsigned int info)
-{
- unsigned int n;
- strlist_item_t *items;
-
- if (str == NULL)
- return;
-
- n = sl->sl_num + 1;
- sl->sl_num = n;
- items = sl->sl_items;
- if (n >= sl->sl_max) {
- items = bmake_realloc(items, (n + 7) * sizeof *sl->sl_items);
- sl->sl_items = items;
- sl->sl_max = n + 6;
- }
- items += n - 1;
- items->si_str = str;
- items->si_info = info;
- items[1].si_str = NULL; /* STRLIST_FOREACH() terminator */
-}
diff --git a/usr.bin/make/strlist.h b/usr.bin/make/strlist.h
deleted file mode 100644
index 2fc049e..0000000
--- a/usr.bin/make/strlist.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/* $NetBSD: strlist.h,v 1.3 2009/01/16 21:15:34 dsl Exp $ */
-
-/*-
- * Copyright (c) 2008 - 2009 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * This code is derived from software contributed to The NetBSD Foundation
- * by David Laight.
- *
- * 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 NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
- */
-
-#ifndef _STRLIST_H
-#define _STRLIST_H
-
-typedef struct {
- char *si_str;
- unsigned int si_info;
-} strlist_item_t;
-
-typedef struct {
- unsigned int sl_num;
- unsigned int sl_max;
- strlist_item_t *sl_items;
-} strlist_t;
-
-void strlist_init(strlist_t *);
-void strlist_clean(strlist_t *);
-void strlist_add_str(strlist_t *, char *, unsigned int);
-
-#define strlist_num(sl) ((sl)->sl_num)
-#define strlist_str(sl, n) ((sl)->sl_items[n].si_str)
-#define strlist_info(sl, n) ((sl)->sl_items[n].si_info)
-#define strlist_set_info(sl, n, v) ((void)((sl)->sl_items[n].si_info = (v)))
-
-#define STRLIST_FOREACH(v, sl, index) \
- if ((sl)->sl_items != NULL) \
- for (index = 0; (v = strlist_str(sl, index)) != NULL; index++)
-
-#endif /* _STRLIST_H */
diff --git a/usr.bin/make/suff.c b/usr.bin/make/suff.c
deleted file mode 100644
index df0306a..0000000
--- a/usr.bin/make/suff.c
+++ /dev/null
@@ -1,2676 +0,0 @@
-/* $NetBSD: suff.c,v 1.86 2017/04/16 20:38:18 riastradh Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-/*
- * Copyright (c) 1989 by Berkeley Softworks
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: suff.c,v 1.86 2017/04/16 20:38:18 riastradh Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)suff.c 8.4 (Berkeley) 3/21/94";
-#else
-__RCSID("$NetBSD: suff.c,v 1.86 2017/04/16 20:38:18 riastradh Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * suff.c --
- * Functions to maintain suffix lists and find implicit dependents
- * using suffix transformation rules
- *
- * Interface:
- * Suff_Init Initialize all things to do with suffixes.
- *
- * Suff_End Cleanup the module
- *
- * Suff_DoPaths This function is used to make life easier
- * when searching for a file according to its
- * suffix. It takes the global search path,
- * as defined using the .PATH: target, and appends
- * its directories to the path of each of the
- * defined suffixes, as specified using
- * .PATH<suffix>: targets. In addition, all
- * directories given for suffixes labeled as
- * include files or libraries, using the .INCLUDES
- * or .LIBS targets, are played with using
- * Dir_MakeFlags to create the .INCLUDES and
- * .LIBS global variables.
- *
- * Suff_ClearSuffixes Clear out all the suffixes and defined
- * transformations.
- *
- * Suff_IsTransform Return TRUE if the passed string is the lhs
- * of a transformation rule.
- *
- * Suff_AddSuffix Add the passed string as another known suffix.
- *
- * Suff_GetPath Return the search path for the given suffix.
- *
- * Suff_AddInclude Mark the given suffix as denoting an include
- * file.
- *
- * Suff_AddLib Mark the given suffix as denoting a library.
- *
- * Suff_AddTransform Add another transformation to the suffix
- * graph. Returns GNode suitable for framing, I
- * mean, tacking commands, attributes, etc. on.
- *
- * Suff_SetNull Define the suffix to consider the suffix of
- * any file that doesn't have a known one.
- *
- * Suff_FindDeps Find implicit sources for and the location of
- * a target based on its suffix. Returns the
- * bottom-most node added to the graph or NULL
- * if the target had no implicit sources.
- *
- * Suff_FindPath Return the appropriate path to search in
- * order to find the node.
- */
-
-#include <assert.h>
-#include <stdio.h>
-#include "make.h"
-#include "hash.h"
-#include "dir.h"
-
-static Lst sufflist; /* Lst of suffixes */
-#ifdef CLEANUP
-static Lst suffClean; /* Lst of suffixes to be cleaned */
-#endif
-static Lst srclist; /* Lst of sources */
-static Lst transforms; /* Lst of transformation rules */
-
-static int sNum = 0; /* Counter for assigning suffix numbers */
-
-/*
- * Structure describing an individual suffix.
- */
-typedef struct _Suff {
- char *name; /* The suffix itself */
- int nameLen; /* Length of the suffix */
- short flags; /* Type of suffix */
-#define SUFF_INCLUDE 0x01 /* One which is #include'd */
-#define SUFF_LIBRARY 0x02 /* One which contains a library */
-#define SUFF_NULL 0x04 /* The empty suffix */
- Lst searchPath; /* The path along which files of this suffix
- * may be found */
- int sNum; /* The suffix number */
- int refCount; /* Reference count of list membership */
- Lst parents; /* Suffixes we have a transformation to */
- Lst children; /* Suffixes we have a transformation from */
- Lst ref; /* List of lists this suffix is referenced */
-} Suff;
-
-/*
- * for SuffSuffIsSuffix
- */
-typedef struct {
- char *ename; /* The end of the name */
- int len; /* Length of the name */
-} SuffixCmpData;
-
-/*
- * Structure used in the search for implied sources.
- */
-typedef struct _Src {
- char *file; /* The file to look for */
- char *pref; /* Prefix from which file was formed */
- Suff *suff; /* The suffix on the file */
- struct _Src *parent; /* The Src for which this is a source */
- GNode *node; /* The node describing the file */
- int children; /* Count of existing children (so we don't free
- * this thing too early or never nuke it) */
-#ifdef DEBUG_SRC
- Lst cp; /* Debug; children list */
-#endif
-} Src;
-
-/*
- * A structure for passing more than one argument to the Lst-library-invoked
- * function...
- */
-typedef struct {
- Lst l;
- Src *s;
-} LstSrc;
-
-typedef struct {
- GNode **gn;
- Suff *s;
- Boolean r;
-} GNodeSuff;
-
-static Suff *suffNull; /* The NULL suffix for this run */
-static Suff *emptySuff; /* The empty suffix required for POSIX
- * single-suffix transformation rules */
-
-
-static const char *SuffStrIsPrefix(const char *, const char *);
-static char *SuffSuffIsSuffix(const Suff *, const SuffixCmpData *);
-static int SuffSuffIsSuffixP(const void *, const void *);
-static int SuffSuffHasNameP(const void *, const void *);
-static int SuffSuffIsPrefix(const void *, const void *);
-static int SuffGNHasNameP(const void *, const void *);
-static void SuffUnRef(void *, void *);
-static void SuffFree(void *);
-static void SuffInsert(Lst, Suff *);
-static void SuffRemove(Lst, Suff *);
-static Boolean SuffParseTransform(char *, Suff **, Suff **);
-static int SuffRebuildGraph(void *, void *);
-static int SuffScanTargets(void *, void *);
-static int SuffAddSrc(void *, void *);
-static int SuffRemoveSrc(Lst);
-static void SuffAddLevel(Lst, Src *);
-static Src *SuffFindThem(Lst, Lst);
-static Src *SuffFindCmds(Src *, Lst);
-static void SuffExpandChildren(LstNode, GNode *);
-static void SuffExpandWildcards(LstNode, GNode *);
-static Boolean SuffApplyTransform(GNode *, GNode *, Suff *, Suff *);
-static void SuffFindDeps(GNode *, Lst);
-static void SuffFindArchiveDeps(GNode *, Lst);
-static void SuffFindNormalDeps(GNode *, Lst);
-static int SuffPrintName(void *, void *);
-static int SuffPrintSuff(void *, void *);
-static int SuffPrintTrans(void *, void *);
-
- /*************** Lst Predicates ****************/
-/*-
- *-----------------------------------------------------------------------
- * SuffStrIsPrefix --
- * See if pref is a prefix of str.
- *
- * Input:
- * pref possible prefix
- * str string to check
- *
- * Results:
- * NULL if it ain't, pointer to character in str after prefix if so
- *
- * Side Effects:
- * None
- *-----------------------------------------------------------------------
- */
-static const char *
-SuffStrIsPrefix(const char *pref, const char *str)
-{
- while (*str && *pref == *str) {
- pref++;
- str++;
- }
-
- return (*pref ? NULL : str);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * SuffSuffIsSuffix --
- * See if suff is a suffix of str. sd->ename should point to THE END
- * of the string to check. (THE END == the null byte)
- *
- * Input:
- * s possible suffix
- * sd string to examine
- *
- * Results:
- * NULL if it ain't, pointer to character in str before suffix if
- * it is.
- *
- * Side Effects:
- * None
- *-----------------------------------------------------------------------
- */
-static char *
-SuffSuffIsSuffix(const Suff *s, const SuffixCmpData *sd)
-{
- char *p1; /* Pointer into suffix name */
- char *p2; /* Pointer into string being examined */
-
- if (sd->len < s->nameLen)
- return NULL; /* this string is shorter than the suffix */
-
- p1 = s->name + s->nameLen;
- p2 = sd->ename;
-
- while (p1 >= s->name && *p1 == *p2) {
- p1--;
- p2--;
- }
-
- return (p1 == s->name - 1 ? p2 : NULL);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * SuffSuffIsSuffixP --
- * Predicate form of SuffSuffIsSuffix. Passed as the callback function
- * to Lst_Find.
- *
- * Results:
- * 0 if the suffix is the one desired, non-zero if not.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-static int
-SuffSuffIsSuffixP(const void *s, const void *sd)
-{
- return(!SuffSuffIsSuffix(s, sd));
-}
-
-/*-
- *-----------------------------------------------------------------------
- * SuffSuffHasNameP --
- * Callback procedure for finding a suffix based on its name. Used by
- * Suff_GetPath.
- *
- * Input:
- * s Suffix to check
- * sd Desired name
- *
- * Results:
- * 0 if the suffix is of the given name. non-zero otherwise.
- *
- * Side Effects:
- * None
- *-----------------------------------------------------------------------
- */
-static int
-SuffSuffHasNameP(const void *s, const void *sname)
-{
- return (strcmp(sname, ((const Suff *)s)->name));
-}
-
-/*-
- *-----------------------------------------------------------------------
- * SuffSuffIsPrefix --
- * See if the suffix described by s is a prefix of the string. Care
- * must be taken when using this to search for transformations and
- * what-not, since there could well be two suffixes, one of which
- * is a prefix of the other...
- *
- * Input:
- * s suffix to compare
- * str string to examine
- *
- * Results:
- * 0 if s is a prefix of str. non-zero otherwise
- *
- * Side Effects:
- * None
- *-----------------------------------------------------------------------
- */
-static int
-SuffSuffIsPrefix(const void *s, const void *str)
-{
- return SuffStrIsPrefix(((const Suff *)s)->name, str) == NULL;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * SuffGNHasNameP --
- * See if the graph node has the desired name
- *
- * Input:
- * gn current node we're looking at
- * name name we're looking for
- *
- * Results:
- * 0 if it does. non-zero if it doesn't
- *
- * Side Effects:
- * None
- *-----------------------------------------------------------------------
- */
-static int
-SuffGNHasNameP(const void *gn, const void *name)
-{
- return (strcmp(name, ((const GNode *)gn)->name));
-}
-
- /*********** Maintenance Functions ************/
-
-static void
-SuffUnRef(void *lp, void *sp)
-{
- Lst l = (Lst) lp;
-
- LstNode ln = Lst_Member(l, sp);
- if (ln != NULL) {
- Lst_Remove(l, ln);
- ((Suff *)sp)->refCount--;
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * SuffFree --
- * Free up all memory associated with the given suffix structure.
- *
- * Results:
- * none
- *
- * Side Effects:
- * the suffix entry is detroyed
- *-----------------------------------------------------------------------
- */
-static void
-SuffFree(void *sp)
-{
- Suff *s = (Suff *)sp;
-
- if (s == suffNull)
- suffNull = NULL;
-
- if (s == emptySuff)
- emptySuff = NULL;
-
-#ifdef notdef
- /* We don't delete suffixes in order, so we cannot use this */
- if (s->refCount)
- Punt("Internal error deleting suffix `%s' with refcount = %d", s->name,
- s->refCount);
-#endif
-
- Lst_Destroy(s->ref, NULL);
- Lst_Destroy(s->children, NULL);
- Lst_Destroy(s->parents, NULL);
- Lst_Destroy(s->searchPath, Dir_Destroy);
-
- free(s->name);
- free(s);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * SuffRemove --
- * Remove the suffix into the list
- *
- * Results:
- * None
- *
- * Side Effects:
- * The reference count for the suffix is decremented and the
- * suffix is possibly freed
- *-----------------------------------------------------------------------
- */
-static void
-SuffRemove(Lst l, Suff *s)
-{
- SuffUnRef(l, s);
- if (s->refCount == 0) {
- SuffUnRef(sufflist, s);
- SuffFree(s);
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * SuffInsert --
- * Insert the suffix into the list keeping the list ordered by suffix
- * numbers.
- *
- * Input:
- * l the list where in s should be inserted
- * s the suffix to insert
- *
- * Results:
- * None
- *
- * Side Effects:
- * The reference count of the suffix is incremented
- *-----------------------------------------------------------------------
- */
-static void
-SuffInsert(Lst l, Suff *s)
-{
- LstNode ln; /* current element in l we're examining */
- Suff *s2 = NULL; /* the suffix descriptor in this element */
-
- if (Lst_Open(l) == FAILURE) {
- return;
- }
- while ((ln = Lst_Next(l)) != NULL) {
- s2 = (Suff *)Lst_Datum(ln);
- if (s2->sNum >= s->sNum) {
- break;
- }
- }
-
- Lst_Close(l);
- if (DEBUG(SUFF)) {
- fprintf(debug_file, "inserting %s(%d)...", s->name, s->sNum);
- }
- if (ln == NULL) {
- if (DEBUG(SUFF)) {
- fprintf(debug_file, "at end of list\n");
- }
- (void)Lst_AtEnd(l, s);
- s->refCount++;
- (void)Lst_AtEnd(s->ref, l);
- } else if (s2->sNum != s->sNum) {
- if (DEBUG(SUFF)) {
- fprintf(debug_file, "before %s(%d)\n", s2->name, s2->sNum);
- }
- (void)Lst_InsertBefore(l, ln, s);
- s->refCount++;
- (void)Lst_AtEnd(s->ref, l);
- } else if (DEBUG(SUFF)) {
- fprintf(debug_file, "already there\n");
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Suff_ClearSuffixes --
- * This is gross. Nuke the list of suffixes but keep all transformation
- * rules around. The transformation graph is destroyed in this process,
- * but we leave the list of rules so when a new graph is formed the rules
- * will remain.
- * This function is called from the parse module when a
- * .SUFFIXES:\n line is encountered.
- *
- * Results:
- * none
- *
- * Side Effects:
- * the sufflist and its graph nodes are destroyed
- *-----------------------------------------------------------------------
- */
-void
-Suff_ClearSuffixes(void)
-{
-#ifdef CLEANUP
- Lst_Concat(suffClean, sufflist, LST_CONCLINK);
-#endif
- sufflist = Lst_Init(FALSE);
- sNum = 0;
- if (suffNull)
- SuffFree(suffNull);
- emptySuff = suffNull = bmake_malloc(sizeof(Suff));
-
- suffNull->name = bmake_strdup("");
- suffNull->nameLen = 0;
- suffNull->searchPath = Lst_Init(FALSE);
- Dir_Concat(suffNull->searchPath, dirSearchPath);
- suffNull->children = Lst_Init(FALSE);
- suffNull->parents = Lst_Init(FALSE);
- suffNull->ref = Lst_Init(FALSE);
- suffNull->sNum = sNum++;
- suffNull->flags = SUFF_NULL;
- suffNull->refCount = 1;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * SuffParseTransform --
- * Parse a transformation string to find its two component suffixes.
- *
- * Input:
- * str String being parsed
- * srcPtr Place to store source of trans.
- * targPtr Place to store target of trans.
- *
- * Results:
- * TRUE if the string is a valid transformation and FALSE otherwise.
- *
- * Side Effects:
- * The passed pointers are overwritten.
- *
- *-----------------------------------------------------------------------
- */
-static Boolean
-SuffParseTransform(char *str, Suff **srcPtr, Suff **targPtr)
-{
- LstNode srcLn; /* element in suffix list of trans source*/
- Suff *src; /* Source of transformation */
- LstNode targLn; /* element in suffix list of trans target*/
- char *str2; /* Extra pointer (maybe target suffix) */
- LstNode singleLn; /* element in suffix list of any suffix
- * that exactly matches str */
- Suff *single = NULL;/* Source of possible transformation to
- * null suffix */
-
- srcLn = NULL;
- singleLn = NULL;
-
- /*
- * Loop looking first for a suffix that matches the start of the
- * string and then for one that exactly matches the rest of it. If
- * we can find two that meet these criteria, we've successfully
- * parsed the string.
- */
- for (;;) {
- if (srcLn == NULL) {
- srcLn = Lst_Find(sufflist, str, SuffSuffIsPrefix);
- } else {
- srcLn = Lst_FindFrom(sufflist, Lst_Succ(srcLn), str,
- SuffSuffIsPrefix);
- }
- if (srcLn == NULL) {
- /*
- * Ran out of source suffixes -- no such rule
- */
- if (singleLn != NULL) {
- /*
- * Not so fast Mr. Smith! There was a suffix that encompassed
- * the entire string, so we assume it was a transformation
- * to the null suffix (thank you POSIX). We still prefer to
- * find a double rule over a singleton, hence we leave this
- * check until the end.
- *
- * XXX: Use emptySuff over suffNull?
- */
- *srcPtr = single;
- *targPtr = suffNull;
- return(TRUE);
- }
- return (FALSE);
- }
- src = (Suff *)Lst_Datum(srcLn);
- str2 = str + src->nameLen;
- if (*str2 == '\0') {
- single = src;
- singleLn = srcLn;
- } else {
- targLn = Lst_Find(sufflist, str2, SuffSuffHasNameP);
- if (targLn != NULL) {
- *srcPtr = src;
- *targPtr = (Suff *)Lst_Datum(targLn);
- return (TRUE);
- }
- }
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Suff_IsTransform --
- * Return TRUE if the given string is a transformation rule
- *
- *
- * Input:
- * str string to check
- *
- * Results:
- * TRUE if the string is a concatenation of two known suffixes.
- * FALSE otherwise
- *
- * Side Effects:
- * None
- *-----------------------------------------------------------------------
- */
-Boolean
-Suff_IsTransform(char *str)
-{
- Suff *src, *targ;
-
- return (SuffParseTransform(str, &src, &targ));
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Suff_AddTransform --
- * Add the transformation rule described by the line to the
- * list of rules and place the transformation itself in the graph
- *
- * Input:
- * line name of transformation to add
- *
- * Results:
- * The node created for the transformation in the transforms list
- *
- * Side Effects:
- * The node is placed on the end of the transforms Lst and links are
- * made between the two suffixes mentioned in the target name
- *-----------------------------------------------------------------------
- */
-GNode *
-Suff_AddTransform(char *line)
-{
- GNode *gn; /* GNode of transformation rule */
- Suff *s, /* source suffix */
- *t; /* target suffix */
- LstNode ln; /* Node for existing transformation */
-
- ln = Lst_Find(transforms, line, SuffGNHasNameP);
- if (ln == NULL) {
- /*
- * Make a new graph node for the transformation. It will be filled in
- * by the Parse module.
- */
- gn = Targ_NewGN(line);
- (void)Lst_AtEnd(transforms, gn);
- } else {
- /*
- * New specification for transformation rule. Just nuke the old list
- * of commands so they can be filled in again... We don't actually
- * free the commands themselves, because a given command can be
- * attached to several different transformations.
- */
- gn = (GNode *)Lst_Datum(ln);
- Lst_Destroy(gn->commands, NULL);
- Lst_Destroy(gn->children, NULL);
- gn->commands = Lst_Init(FALSE);
- gn->children = Lst_Init(FALSE);
- }
-
- gn->type = OP_TRANSFORM;
-
- (void)SuffParseTransform(line, &s, &t);
-
- /*
- * link the two together in the proper relationship and order
- */
- if (DEBUG(SUFF)) {
- fprintf(debug_file, "defining transformation from `%s' to `%s'\n",
- s->name, t->name);
- }
- SuffInsert(t->children, s);
- SuffInsert(s->parents, t);
-
- return (gn);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Suff_EndTransform --
- * Handle the finish of a transformation definition, removing the
- * transformation from the graph if it has neither commands nor
- * sources. This is a callback procedure for the Parse module via
- * Lst_ForEach
- *
- * Input:
- * gnp Node for transformation
- * dummy Node for transformation
- *
- * Results:
- * === 0
- *
- * Side Effects:
- * If the node has no commands or children, the children and parents
- * lists of the affected suffixes are altered.
- *
- *-----------------------------------------------------------------------
- */
-int
-Suff_EndTransform(void *gnp, void *dummy MAKE_ATTR_UNUSED)
-{
- GNode *gn = (GNode *)gnp;
-
- if ((gn->type & OP_DOUBLEDEP) && !Lst_IsEmpty (gn->cohorts))
- gn = (GNode *)Lst_Datum(Lst_Last(gn->cohorts));
- if ((gn->type & OP_TRANSFORM) && Lst_IsEmpty(gn->commands) &&
- Lst_IsEmpty(gn->children))
- {
- Suff *s, *t;
-
- /*
- * SuffParseTransform() may fail for special rules which are not
- * actual transformation rules. (e.g. .DEFAULT)
- */
- if (SuffParseTransform(gn->name, &s, &t)) {
- Lst p;
-
- if (DEBUG(SUFF)) {
- fprintf(debug_file, "deleting transformation from `%s' to `%s'\n",
- s->name, t->name);
- }
-
- /*
- * Store s->parents because s could be deleted in SuffRemove
- */
- p = s->parents;
-
- /*
- * Remove the source from the target's children list. We check for a
- * nil return to handle a beanhead saying something like
- * .c.o .c.o:
- *
- * We'll be called twice when the next target is seen, but .c and .o
- * are only linked once...
- */
- SuffRemove(t->children, s);
-
- /*
- * Remove the target from the source's parents list
- */
- SuffRemove(p, t);
- }
- } else if ((gn->type & OP_TRANSFORM) && DEBUG(SUFF)) {
- fprintf(debug_file, "transformation %s complete\n", gn->name);
- }
-
- return 0;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * SuffRebuildGraph --
- * Called from Suff_AddSuffix via Lst_ForEach to search through the
- * list of existing transformation rules and rebuild the transformation
- * graph when it has been destroyed by Suff_ClearSuffixes. If the
- * given rule is a transformation involving this suffix and another,
- * existing suffix, the proper relationship is established between
- * the two.
- *
- * Input:
- * transformp Transformation to test
- * sp Suffix to rebuild
- *
- * Results:
- * Always 0.
- *
- * Side Effects:
- * The appropriate links will be made between this suffix and
- * others if transformation rules exist for it.
- *
- *-----------------------------------------------------------------------
- */
-static int
-SuffRebuildGraph(void *transformp, void *sp)
-{
- GNode *transform = (GNode *)transformp;
- Suff *s = (Suff *)sp;
- char *cp;
- LstNode ln;
- Suff *s2;
- SuffixCmpData sd;
-
- /*
- * First see if it is a transformation from this suffix.
- */
- cp = UNCONST(SuffStrIsPrefix(s->name, transform->name));
- if (cp != NULL) {
- ln = Lst_Find(sufflist, cp, SuffSuffHasNameP);
- if (ln != NULL) {
- /*
- * Found target. Link in and return, since it can't be anything
- * else.
- */
- s2 = (Suff *)Lst_Datum(ln);
- SuffInsert(s2->children, s);
- SuffInsert(s->parents, s2);
- return(0);
- }
- }
-
- /*
- * Not from, maybe to?
- */
- sd.len = strlen(transform->name);
- sd.ename = transform->name + sd.len;
- cp = SuffSuffIsSuffix(s, &sd);
- if (cp != NULL) {
- /*
- * Null-terminate the source suffix in order to find it.
- */
- cp[1] = '\0';
- ln = Lst_Find(sufflist, transform->name, SuffSuffHasNameP);
- /*
- * Replace the start of the target suffix
- */
- cp[1] = s->name[0];
- if (ln != NULL) {
- /*
- * Found it -- establish the proper relationship
- */
- s2 = (Suff *)Lst_Datum(ln);
- SuffInsert(s->children, s2);
- SuffInsert(s2->parents, s);
- }
- }
- return(0);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * SuffScanTargets --
- * Called from Suff_AddSuffix via Lst_ForEach to search through the
- * list of existing targets and find if any of the existing targets
- * can be turned into a transformation rule.
- *
- * Results:
- * 1 if a new main target has been selected, 0 otherwise.
- *
- * Side Effects:
- * If such a target is found and the target is the current main
- * target, the main target is set to NULL and the next target
- * examined (if that exists) becomes the main target.
- *
- *-----------------------------------------------------------------------
- */
-static int
-SuffScanTargets(void *targetp, void *gsp)
-{
- GNode *target = (GNode *)targetp;
- GNodeSuff *gs = (GNodeSuff *)gsp;
- Suff *s, *t;
- char *ptr;
-
- if (*gs->gn == NULL && gs->r && (target->type & OP_NOTARGET) == 0) {
- *gs->gn = target;
- Targ_SetMain(target);
- return 1;
- }
-
- if ((unsigned int)target->type == OP_TRANSFORM)
- return 0;
-
- if ((ptr = strstr(target->name, gs->s->name)) == NULL ||
- ptr == target->name)
- return 0;
-
- if (SuffParseTransform(target->name, &s, &t)) {
- if (*gs->gn == target) {
- gs->r = TRUE;
- *gs->gn = NULL;
- Targ_SetMain(NULL);
- }
- Lst_Destroy(target->children, NULL);
- target->children = Lst_Init(FALSE);
- target->type = OP_TRANSFORM;
- /*
- * link the two together in the proper relationship and order
- */
- if (DEBUG(SUFF)) {
- fprintf(debug_file, "defining transformation from `%s' to `%s'\n",
- s->name, t->name);
- }
- SuffInsert(t->children, s);
- SuffInsert(s->parents, t);
- }
- return 0;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Suff_AddSuffix --
- * Add the suffix in string to the end of the list of known suffixes.
- * Should we restructure the suffix graph? Make doesn't...
- *
- * Input:
- * str the name of the suffix to add
- *
- * Results:
- * None
- *
- * Side Effects:
- * A GNode is created for the suffix and a Suff structure is created and
- * added to the suffixes list unless the suffix was already known.
- * The mainNode passed can be modified if a target mutated into a
- * transform and that target happened to be the main target.
- *-----------------------------------------------------------------------
- */
-void
-Suff_AddSuffix(char *str, GNode **gn)
-{
- Suff *s; /* new suffix descriptor */
- LstNode ln;
- GNodeSuff gs;
-
- ln = Lst_Find(sufflist, str, SuffSuffHasNameP);
- if (ln == NULL) {
- s = bmake_malloc(sizeof(Suff));
-
- s->name = bmake_strdup(str);
- s->nameLen = strlen(s->name);
- s->searchPath = Lst_Init(FALSE);
- s->children = Lst_Init(FALSE);
- s->parents = Lst_Init(FALSE);
- s->ref = Lst_Init(FALSE);
- s->sNum = sNum++;
- s->flags = 0;
- s->refCount = 1;
-
- (void)Lst_AtEnd(sufflist, s);
- /*
- * We also look at our existing targets list to see if adding
- * this suffix will make one of our current targets mutate into
- * a suffix rule. This is ugly, but other makes treat all targets
- * that start with a . as suffix rules.
- */
- gs.gn = gn;
- gs.s = s;
- gs.r = FALSE;
- Lst_ForEach(Targ_List(), SuffScanTargets, &gs);
- /*
- * Look for any existing transformations from or to this suffix.
- * XXX: Only do this after a Suff_ClearSuffixes?
- */
- Lst_ForEach(transforms, SuffRebuildGraph, s);
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Suff_GetPath --
- * Return the search path for the given suffix, if it's defined.
- *
- * Results:
- * The searchPath for the desired suffix or NULL if the suffix isn't
- * defined.
- *
- * Side Effects:
- * None
- *-----------------------------------------------------------------------
- */
-Lst
-Suff_GetPath(char *sname)
-{
- LstNode ln;
- Suff *s;
-
- ln = Lst_Find(sufflist, sname, SuffSuffHasNameP);
- if (ln == NULL) {
- return NULL;
- } else {
- s = (Suff *)Lst_Datum(ln);
- return (s->searchPath);
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Suff_DoPaths --
- * Extend the search paths for all suffixes to include the default
- * search path.
- *
- * Results:
- * None.
- *
- * Side Effects:
- * The searchPath field of all the suffixes is extended by the
- * directories in dirSearchPath. If paths were specified for the
- * ".h" suffix, the directories are stuffed into a global variable
- * called ".INCLUDES" with each directory preceded by a -I. The same
- * is done for the ".a" suffix, except the variable is called
- * ".LIBS" and the flag is -L.
- *-----------------------------------------------------------------------
- */
-void
-Suff_DoPaths(void)
-{
- Suff *s;
- LstNode ln;
- char *ptr;
- Lst inIncludes; /* Cumulative .INCLUDES path */
- Lst inLibs; /* Cumulative .LIBS path */
-
- if (Lst_Open(sufflist) == FAILURE) {
- return;
- }
-
- inIncludes = Lst_Init(FALSE);
- inLibs = Lst_Init(FALSE);
-
- while ((ln = Lst_Next(sufflist)) != NULL) {
- s = (Suff *)Lst_Datum(ln);
- if (!Lst_IsEmpty (s->searchPath)) {
-#ifdef INCLUDES
- if (s->flags & SUFF_INCLUDE) {
- Dir_Concat(inIncludes, s->searchPath);
- }
-#endif /* INCLUDES */
-#ifdef LIBRARIES
- if (s->flags & SUFF_LIBRARY) {
- Dir_Concat(inLibs, s->searchPath);
- }
-#endif /* LIBRARIES */
- Dir_Concat(s->searchPath, dirSearchPath);
- } else {
- Lst_Destroy(s->searchPath, Dir_Destroy);
- s->searchPath = Lst_Duplicate(dirSearchPath, Dir_CopyDir);
- }
- }
-
- Var_Set(".INCLUDES", ptr = Dir_MakeFlags("-I", inIncludes), VAR_GLOBAL, 0);
- free(ptr);
- Var_Set(".LIBS", ptr = Dir_MakeFlags("-L", inLibs), VAR_GLOBAL, 0);
- free(ptr);
-
- Lst_Destroy(inIncludes, Dir_Destroy);
- Lst_Destroy(inLibs, Dir_Destroy);
-
- Lst_Close(sufflist);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Suff_AddInclude --
- * Add the given suffix as a type of file which gets included.
- * Called from the parse module when a .INCLUDES line is parsed.
- * The suffix must have already been defined.
- *
- * Input:
- * sname Name of the suffix to mark
- *
- * Results:
- * None.
- *
- * Side Effects:
- * The SUFF_INCLUDE bit is set in the suffix's flags field
- *
- *-----------------------------------------------------------------------
- */
-void
-Suff_AddInclude(char *sname)
-{
- LstNode ln;
- Suff *s;
-
- ln = Lst_Find(sufflist, sname, SuffSuffHasNameP);
- if (ln != NULL) {
- s = (Suff *)Lst_Datum(ln);
- s->flags |= SUFF_INCLUDE;
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Suff_AddLib --
- * Add the given suffix as a type of file which is a library.
- * Called from the parse module when parsing a .LIBS line. The
- * suffix must have been defined via .SUFFIXES before this is
- * called.
- *
- * Input:
- * sname Name of the suffix to mark
- *
- * Results:
- * None.
- *
- * Side Effects:
- * The SUFF_LIBRARY bit is set in the suffix's flags field
- *
- *-----------------------------------------------------------------------
- */
-void
-Suff_AddLib(char *sname)
-{
- LstNode ln;
- Suff *s;
-
- ln = Lst_Find(sufflist, sname, SuffSuffHasNameP);
- if (ln != NULL) {
- s = (Suff *)Lst_Datum(ln);
- s->flags |= SUFF_LIBRARY;
- }
-}
-
- /********** Implicit Source Search Functions *********/
-
-/*-
- *-----------------------------------------------------------------------
- * SuffAddSrc --
- * Add a suffix as a Src structure to the given list with its parent
- * being the given Src structure. If the suffix is the null suffix,
- * the prefix is used unaltered as the file name in the Src structure.
- *
- * Input:
- * sp suffix for which to create a Src structure
- * lsp list and parent for the new Src
- *
- * Results:
- * always returns 0
- *
- * Side Effects:
- * A Src structure is created and tacked onto the end of the list
- *-----------------------------------------------------------------------
- */
-static int
-SuffAddSrc(void *sp, void *lsp)
-{
- Suff *s = (Suff *)sp;
- LstSrc *ls = (LstSrc *)lsp;
- Src *s2; /* new Src structure */
- Src *targ; /* Target structure */
-
- targ = ls->s;
-
- if ((s->flags & SUFF_NULL) && (*s->name != '\0')) {
- /*
- * If the suffix has been marked as the NULL suffix, also create a Src
- * structure for a file with no suffix attached. Two birds, and all
- * that...
- */
- s2 = bmake_malloc(sizeof(Src));
- s2->file = bmake_strdup(targ->pref);
- s2->pref = targ->pref;
- s2->parent = targ;
- s2->node = NULL;
- s2->suff = s;
- s->refCount++;
- s2->children = 0;
- targ->children += 1;
- (void)Lst_AtEnd(ls->l, s2);
-#ifdef DEBUG_SRC
- s2->cp = Lst_Init(FALSE);
- Lst_AtEnd(targ->cp, s2);
- fprintf(debug_file, "1 add %p %p to %p:", targ, s2, ls->l);
- Lst_ForEach(ls->l, PrintAddr, NULL);
- fprintf(debug_file, "\n");
-#endif
- }
- s2 = bmake_malloc(sizeof(Src));
- s2->file = str_concat(targ->pref, s->name, 0);
- s2->pref = targ->pref;
- s2->parent = targ;
- s2->node = NULL;
- s2->suff = s;
- s->refCount++;
- s2->children = 0;
- targ->children += 1;
- (void)Lst_AtEnd(ls->l, s2);
-#ifdef DEBUG_SRC
- s2->cp = Lst_Init(FALSE);
- Lst_AtEnd(targ->cp, s2);
- fprintf(debug_file, "2 add %p %p to %p:", targ, s2, ls->l);
- Lst_ForEach(ls->l, PrintAddr, NULL);
- fprintf(debug_file, "\n");
-#endif
-
- return(0);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * SuffAddLevel --
- * Add all the children of targ as Src structures to the given list
- *
- * Input:
- * l list to which to add the new level
- * targ Src structure to use as the parent
- *
- * Results:
- * None
- *
- * Side Effects:
- * Lots of structures are created and added to the list
- *-----------------------------------------------------------------------
- */
-static void
-SuffAddLevel(Lst l, Src *targ)
-{
- LstSrc ls;
-
- ls.s = targ;
- ls.l = l;
-
- Lst_ForEach(targ->suff->children, SuffAddSrc, &ls);
-}
-
-/*-
- *----------------------------------------------------------------------
- * SuffRemoveSrc --
- * Free all src structures in list that don't have a reference count
- *
- * Results:
- * Ture if an src was removed
- *
- * Side Effects:
- * The memory is free'd.
- *----------------------------------------------------------------------
- */
-static int
-SuffRemoveSrc(Lst l)
-{
- LstNode ln;
- Src *s;
- int t = 0;
-
- if (Lst_Open(l) == FAILURE) {
- return 0;
- }
-#ifdef DEBUG_SRC
- fprintf(debug_file, "cleaning %lx: ", (unsigned long) l);
- Lst_ForEach(l, PrintAddr, NULL);
- fprintf(debug_file, "\n");
-#endif
-
-
- while ((ln = Lst_Next(l)) != NULL) {
- s = (Src *)Lst_Datum(ln);
- if (s->children == 0) {
- free(s->file);
- if (!s->parent)
- free(s->pref);
- else {
-#ifdef DEBUG_SRC
- LstNode ln2 = Lst_Member(s->parent->cp, s);
- if (ln2 != NULL)
- Lst_Remove(s->parent->cp, ln2);
-#endif
- --s->parent->children;
- }
-#ifdef DEBUG_SRC
- fprintf(debug_file, "free: [l=%p] p=%p %d\n", l, s, s->children);
- Lst_Destroy(s->cp, NULL);
-#endif
- Lst_Remove(l, ln);
- free(s);
- t |= 1;
- Lst_Close(l);
- return TRUE;
- }
-#ifdef DEBUG_SRC
- else {
- fprintf(debug_file, "keep: [l=%p] p=%p %d: ", l, s, s->children);
- Lst_ForEach(s->cp, PrintAddr, NULL);
- fprintf(debug_file, "\n");
- }
-#endif
- }
-
- Lst_Close(l);
-
- return t;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * SuffFindThem --
- * Find the first existing file/target in the list srcs
- *
- * Input:
- * srcs list of Src structures to search through
- *
- * Results:
- * The lowest structure in the chain of transformations
- *
- * Side Effects:
- * None
- *-----------------------------------------------------------------------
- */
-static Src *
-SuffFindThem(Lst srcs, Lst slst)
-{
- Src *s; /* current Src */
- Src *rs; /* returned Src */
- char *ptr;
-
- rs = NULL;
-
- while (!Lst_IsEmpty (srcs)) {
- s = (Src *)Lst_DeQueue(srcs);
-
- if (DEBUG(SUFF)) {
- fprintf(debug_file, "\ttrying %s...", s->file);
- }
-
- /*
- * A file is considered to exist if either a node exists in the
- * graph for it or the file actually exists.
- */
- if (Targ_FindNode(s->file, TARG_NOCREATE) != NULL) {
-#ifdef DEBUG_SRC
- fprintf(debug_file, "remove %p from %p\n", s, srcs);
-#endif
- rs = s;
- break;
- }
-
- if ((ptr = Dir_FindFile(s->file, s->suff->searchPath)) != NULL) {
- rs = s;
-#ifdef DEBUG_SRC
- fprintf(debug_file, "remove %p from %p\n", s, srcs);
-#endif
- free(ptr);
- break;
- }
-
- if (DEBUG(SUFF)) {
- fprintf(debug_file, "not there\n");
- }
-
- SuffAddLevel(srcs, s);
- Lst_AtEnd(slst, s);
- }
-
- if (DEBUG(SUFF) && rs) {
- fprintf(debug_file, "got it\n");
- }
- return (rs);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * SuffFindCmds --
- * See if any of the children of the target in the Src structure is
- * one from which the target can be transformed. If there is one,
- * a Src structure is put together for it and returned.
- *
- * Input:
- * targ Src structure to play with
- *
- * Results:
- * The Src structure of the "winning" child, or NULL if no such beast.
- *
- * Side Effects:
- * A Src structure may be allocated.
- *
- *-----------------------------------------------------------------------
- */
-static Src *
-SuffFindCmds(Src *targ, Lst slst)
-{
- LstNode ln; /* General-purpose list node */
- GNode *t, /* Target GNode */
- *s; /* Source GNode */
- int prefLen;/* The length of the defined prefix */
- Suff *suff; /* Suffix on matching beastie */
- Src *ret; /* Return value */
- char *cp;
-
- t = targ->node;
- (void)Lst_Open(t->children);
- prefLen = strlen(targ->pref);
-
- for (;;) {
- ln = Lst_Next(t->children);
- if (ln == NULL) {
- Lst_Close(t->children);
- return NULL;
- }
- s = (GNode *)Lst_Datum(ln);
-
- if (s->type & OP_OPTIONAL && Lst_IsEmpty(t->commands)) {
- /*
- * We haven't looked to see if .OPTIONAL files exist yet, so
- * don't use one as the implicit source.
- * This allows us to use .OPTIONAL in .depend files so make won't
- * complain "don't know how to make xxx.h' when a dependent file
- * has been moved/deleted.
- */
- continue;
- }
-
- cp = strrchr(s->name, '/');
- if (cp == NULL) {
- cp = s->name;
- } else {
- cp++;
- }
- if (strncmp(cp, targ->pref, prefLen) != 0)
- continue;
- /*
- * The node matches the prefix ok, see if it has a known
- * suffix.
- */
- ln = Lst_Find(sufflist, &cp[prefLen], SuffSuffHasNameP);
- if (ln == NULL)
- continue;
- /*
- * It even has a known suffix, see if there's a transformation
- * defined between the node's suffix and the target's suffix.
- *
- * XXX: Handle multi-stage transformations here, too.
- */
- suff = (Suff *)Lst_Datum(ln);
-
- if (Lst_Member(suff->parents, targ->suff) != NULL)
- break;
- }
-
- /*
- * Hot Damn! Create a new Src structure to describe
- * this transformation (making sure to duplicate the
- * source node's name so Suff_FindDeps can free it
- * again (ick)), and return the new structure.
- */
- ret = bmake_malloc(sizeof(Src));
- ret->file = bmake_strdup(s->name);
- ret->pref = targ->pref;
- ret->suff = suff;
- suff->refCount++;
- ret->parent = targ;
- ret->node = s;
- ret->children = 0;
- targ->children += 1;
-#ifdef DEBUG_SRC
- ret->cp = Lst_Init(FALSE);
- fprintf(debug_file, "3 add %p %p\n", targ, ret);
- Lst_AtEnd(targ->cp, ret);
-#endif
- Lst_AtEnd(slst, ret);
- if (DEBUG(SUFF)) {
- fprintf(debug_file, "\tusing existing source %s\n", s->name);
- }
- return (ret);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * SuffExpandChildren --
- * Expand the names of any children of a given node that contain
- * variable invocations or file wildcards into actual targets.
- *
- * Input:
- * cln Child to examine
- * pgn Parent node being processed
- *
- * Results:
- * === 0 (continue)
- *
- * Side Effects:
- * The expanded node is removed from the parent's list of children,
- * and the parent's unmade counter is decremented, but other nodes
- * may be added.
- *
- *-----------------------------------------------------------------------
- */
-static void
-SuffExpandChildren(LstNode cln, GNode *pgn)
-{
- GNode *cgn = (GNode *)Lst_Datum(cln);
- GNode *gn; /* New source 8) */
- char *cp; /* Expanded value */
-
- if (!Lst_IsEmpty(cgn->order_pred) || !Lst_IsEmpty(cgn->order_succ))
- /* It is all too hard to process the result of .ORDER */
- return;
-
- if (cgn->type & OP_WAIT)
- /* Ignore these (& OP_PHONY ?) */
- return;
-
- /*
- * First do variable expansion -- this takes precedence over
- * wildcard expansion. If the result contains wildcards, they'll be gotten
- * to later since the resulting words are tacked on to the end of
- * the children list.
- */
- if (strchr(cgn->name, '$') == NULL) {
- SuffExpandWildcards(cln, pgn);
- return;
- }
-
- if (DEBUG(SUFF)) {
- fprintf(debug_file, "Expanding \"%s\"...", cgn->name);
- }
- cp = Var_Subst(NULL, cgn->name, pgn, VARF_UNDEFERR|VARF_WANTRES);
-
- if (cp != NULL) {
- Lst members = Lst_Init(FALSE);
-
- if (cgn->type & OP_ARCHV) {
- /*
- * Node was an archive(member) target, so we want to call
- * on the Arch module to find the nodes for us, expanding
- * variables in the parent's context.
- */
- char *sacrifice = cp;
-
- (void)Arch_ParseArchive(&sacrifice, members, pgn);
- } else {
- /*
- * Break the result into a vector of strings whose nodes
- * we can find, then add those nodes to the members list.
- * Unfortunately, we can't use brk_string b/c it
- * doesn't understand about variable specifications with
- * spaces in them...
- */
- char *start;
- char *initcp = cp; /* For freeing... */
-
- for (start = cp; *start == ' ' || *start == '\t'; start++)
- continue;
- for (cp = start; *cp != '\0'; cp++) {
- if (*cp == ' ' || *cp == '\t') {
- /*
- * White-space -- terminate element, find the node,
- * add it, skip any further spaces.
- */
- *cp++ = '\0';
- gn = Targ_FindNode(start, TARG_CREATE);
- (void)Lst_AtEnd(members, gn);
- while (*cp == ' ' || *cp == '\t') {
- cp++;
- }
- /*
- * Adjust cp for increment at start of loop, but
- * set start to first non-space.
- */
- start = cp--;
- } else if (*cp == '$') {
- /*
- * Start of a variable spec -- contact variable module
- * to find the end so we can skip over it.
- */
- char *junk;
- int len;
- void *freeIt;
-
- junk = Var_Parse(cp, pgn, VARF_UNDEFERR|VARF_WANTRES,
- &len, &freeIt);
- if (junk != var_Error) {
- cp += len - 1;
- }
-
- free(freeIt);
- } else if (*cp == '\\' && cp[1] != '\0') {
- /*
- * Escaped something -- skip over it
- */
- cp++;
- }
- }
-
- if (cp != start) {
- /*
- * Stuff left over -- add it to the list too
- */
- gn = Targ_FindNode(start, TARG_CREATE);
- (void)Lst_AtEnd(members, gn);
- }
- /*
- * Point cp back at the beginning again so the variable value
- * can be freed.
- */
- cp = initcp;
- }
-
- /*
- * Add all elements of the members list to the parent node.
- */
- while(!Lst_IsEmpty(members)) {
- gn = (GNode *)Lst_DeQueue(members);
-
- if (DEBUG(SUFF)) {
- fprintf(debug_file, "%s...", gn->name);
- }
- /* Add gn to the parents child list before the original child */
- (void)Lst_InsertBefore(pgn->children, cln, gn);
- (void)Lst_AtEnd(gn->parents, pgn);
- pgn->unmade++;
- /* Expand wildcards on new node */
- SuffExpandWildcards(Lst_Prev(cln), pgn);
- }
- Lst_Destroy(members, NULL);
-
- /*
- * Free the result
- */
- free(cp);
- }
- if (DEBUG(SUFF)) {
- fprintf(debug_file, "\n");
- }
-
- /*
- * Now the source is expanded, remove it from the list of children to
- * keep it from being processed.
- */
- pgn->unmade--;
- Lst_Remove(pgn->children, cln);
- Lst_Remove(cgn->parents, Lst_Member(cgn->parents, pgn));
-}
-
-static void
-SuffExpandWildcards(LstNode cln, GNode *pgn)
-{
- GNode *cgn = (GNode *)Lst_Datum(cln);
- GNode *gn; /* New source 8) */
- char *cp; /* Expanded value */
- Lst explist; /* List of expansions */
-
- if (!Dir_HasWildcards(cgn->name))
- return;
-
- /*
- * Expand the word along the chosen path
- */
- explist = Lst_Init(FALSE);
- Dir_Expand(cgn->name, Suff_FindPath(cgn), explist);
-
- while (!Lst_IsEmpty(explist)) {
- /*
- * Fetch next expansion off the list and find its GNode
- */
- cp = (char *)Lst_DeQueue(explist);
-
- if (DEBUG(SUFF)) {
- fprintf(debug_file, "%s...", cp);
- }
- gn = Targ_FindNode(cp, TARG_CREATE);
-
- /* Add gn to the parents child list before the original child */
- (void)Lst_InsertBefore(pgn->children, cln, gn);
- (void)Lst_AtEnd(gn->parents, pgn);
- pgn->unmade++;
- }
-
- /*
- * Nuke what's left of the list
- */
- Lst_Destroy(explist, NULL);
-
- if (DEBUG(SUFF)) {
- fprintf(debug_file, "\n");
- }
-
- /*
- * Now the source is expanded, remove it from the list of children to
- * keep it from being processed.
- */
- pgn->unmade--;
- Lst_Remove(pgn->children, cln);
- Lst_Remove(cgn->parents, Lst_Member(cgn->parents, pgn));
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Suff_FindPath --
- * Find a path along which to expand the node.
- *
- * If the word has a known suffix, use that path.
- * If it has no known suffix, use the default system search path.
- *
- * Input:
- * gn Node being examined
- *
- * Results:
- * The appropriate path to search for the GNode.
- *
- * Side Effects:
- * XXX: We could set the suffix here so that we don't have to scan
- * again.
- *
- *-----------------------------------------------------------------------
- */
-Lst
-Suff_FindPath(GNode* gn)
-{
- Suff *suff = gn->suffix;
-
- if (suff == NULL) {
- SuffixCmpData sd; /* Search string data */
- LstNode ln;
- sd.len = strlen(gn->name);
- sd.ename = gn->name + sd.len;
- ln = Lst_Find(sufflist, &sd, SuffSuffIsSuffixP);
-
- if (DEBUG(SUFF)) {
- fprintf(debug_file, "Wildcard expanding \"%s\"...", gn->name);
- }
- if (ln != NULL)
- suff = (Suff *)Lst_Datum(ln);
- /* XXX: Here we can save the suffix so we don't have to do this again */
- }
-
- if (suff != NULL) {
- if (DEBUG(SUFF)) {
- fprintf(debug_file, "suffix is \"%s\"...", suff->name);
- }
- return suff->searchPath;
- } else {
- /*
- * Use default search path
- */
- return dirSearchPath;
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * SuffApplyTransform --
- * Apply a transformation rule, given the source and target nodes
- * and suffixes.
- *
- * Input:
- * tGn Target node
- * sGn Source node
- * t Target suffix
- * s Source suffix
- *
- * Results:
- * TRUE if successful, FALSE if not.
- *
- * Side Effects:
- * The source and target are linked and the commands from the
- * transformation are added to the target node's commands list.
- * All attributes but OP_DEPMASK and OP_TRANSFORM are applied
- * to the target. The target also inherits all the sources for
- * the transformation rule.
- *
- *-----------------------------------------------------------------------
- */
-static Boolean
-SuffApplyTransform(GNode *tGn, GNode *sGn, Suff *t, Suff *s)
-{
- LstNode ln, nln; /* General node */
- char *tname; /* Name of transformation rule */
- GNode *gn; /* Node for same */
-
- /*
- * Form the proper links between the target and source.
- */
- (void)Lst_AtEnd(tGn->children, sGn);
- (void)Lst_AtEnd(sGn->parents, tGn);
- tGn->unmade += 1;
-
- /*
- * Locate the transformation rule itself
- */
- tname = str_concat(s->name, t->name, 0);
- ln = Lst_Find(transforms, tname, SuffGNHasNameP);
- free(tname);
-
- if (ln == NULL) {
- /*
- * Not really such a transformation rule (can happen when we're
- * called to link an OP_MEMBER and OP_ARCHV node), so return
- * FALSE.
- */
- return(FALSE);
- }
-
- gn = (GNode *)Lst_Datum(ln);
-
- if (DEBUG(SUFF)) {
- fprintf(debug_file, "\tapplying %s -> %s to \"%s\"\n", s->name, t->name, tGn->name);
- }
-
- /*
- * Record last child for expansion purposes
- */
- ln = Lst_Last(tGn->children);
-
- /*
- * Pass the buck to Make_HandleUse to apply the rule
- */
- (void)Make_HandleUse(gn, tGn);
-
- /*
- * Deal with wildcards and variables in any acquired sources
- */
- for (ln = Lst_Succ(ln); ln != NULL; ln = nln) {
- nln = Lst_Succ(ln);
- SuffExpandChildren(ln, tGn);
- }
-
- /*
- * Keep track of another parent to which this beast is transformed so
- * the .IMPSRC variable can be set correctly for the parent.
- */
- (void)Lst_AtEnd(sGn->iParents, tGn);
-
- return(TRUE);
-}
-
-
-/*-
- *-----------------------------------------------------------------------
- * SuffFindArchiveDeps --
- * Locate dependencies for an OP_ARCHV node.
- *
- * Input:
- * gn Node for which to locate dependencies
- *
- * Results:
- * None
- *
- * Side Effects:
- * Same as Suff_FindDeps
- *
- *-----------------------------------------------------------------------
- */
-static void
-SuffFindArchiveDeps(GNode *gn, Lst slst)
-{
- char *eoarch; /* End of archive portion */
- char *eoname; /* End of member portion */
- GNode *mem; /* Node for member */
- static const char *copy[] = {
- /* Variables to be copied from the member node */
- TARGET, /* Must be first */
- PREFIX, /* Must be second */
- };
- LstNode ln, nln; /* Next suffix node to check */
- int i; /* Index into copy and vals */
- Suff *ms; /* Suffix descriptor for member */
- char *name; /* Start of member's name */
-
- /*
- * The node is an archive(member) pair. so we must find a
- * suffix for both of them.
- */
- eoarch = strchr(gn->name, '(');
- eoname = strchr(eoarch, ')');
-
- /*
- * Caller guarantees the format `libname(member)', via
- * Arch_ParseArchive.
- */
- assert(eoarch != NULL);
- assert(eoname != NULL);
-
- *eoname = '\0'; /* Nuke parentheses during suffix search */
- *eoarch = '\0'; /* So a suffix can be found */
-
- name = eoarch + 1;
-
- /*
- * To simplify things, call Suff_FindDeps recursively on the member now,
- * so we can simply compare the member's .PREFIX and .TARGET variables
- * to locate its suffix. This allows us to figure out the suffix to
- * use for the archive without having to do a quadratic search over the
- * suffix list, backtracking for each one...
- */
- mem = Targ_FindNode(name, TARG_CREATE);
- SuffFindDeps(mem, slst);
-
- /*
- * Create the link between the two nodes right off
- */
- (void)Lst_AtEnd(gn->children, mem);
- (void)Lst_AtEnd(mem->parents, gn);
- gn->unmade += 1;
-
- /*
- * Copy in the variables from the member node to this one.
- */
- for (i = (sizeof(copy)/sizeof(copy[0]))-1; i >= 0; i--) {
- char *p1;
- Var_Set(copy[i], Var_Value(copy[i], mem, &p1), gn, 0);
- free(p1);
-
- }
-
- ms = mem->suffix;
- if (ms == NULL) {
- /*
- * Didn't know what it was -- use .NULL suffix if not in make mode
- */
- if (DEBUG(SUFF)) {
- fprintf(debug_file, "using null suffix\n");
- }
- ms = suffNull;
- }
-
-
- /*
- * Set the other two local variables required for this target.
- */
- Var_Set(MEMBER, name, gn, 0);
- Var_Set(ARCHIVE, gn->name, gn, 0);
-
- /*
- * Set $@ for compatibility with other makes
- */
- Var_Set(TARGET, gn->name, gn, 0);
-
- /*
- * Now we've got the important local variables set, expand any sources
- * that still contain variables or wildcards in their names.
- */
- for (ln = Lst_First(gn->children); ln != NULL; ln = nln) {
- nln = Lst_Succ(ln);
- SuffExpandChildren(ln, gn);
- }
-
- if (ms != NULL) {
- /*
- * Member has a known suffix, so look for a transformation rule from
- * it to a possible suffix of the archive. Rather than searching
- * through the entire list, we just look at suffixes to which the
- * member's suffix may be transformed...
- */
- SuffixCmpData sd; /* Search string data */
-
- /*
- * Use first matching suffix...
- */
- sd.len = eoarch - gn->name;
- sd.ename = eoarch;
- ln = Lst_Find(ms->parents, &sd, SuffSuffIsSuffixP);
-
- if (ln != NULL) {
- /*
- * Got one -- apply it
- */
- if (!SuffApplyTransform(gn, mem, (Suff *)Lst_Datum(ln), ms) &&
- DEBUG(SUFF))
- {
- fprintf(debug_file, "\tNo transformation from %s -> %s\n",
- ms->name, ((Suff *)Lst_Datum(ln))->name);
- }
- }
- }
-
- /*
- * Replace the opening and closing parens now we've no need of the separate
- * pieces.
- */
- *eoarch = '('; *eoname = ')';
-
- /*
- * Pretend gn appeared to the left of a dependency operator so
- * the user needn't provide a transformation from the member to the
- * archive.
- */
- if (OP_NOP(gn->type)) {
- gn->type |= OP_DEPENDS;
- }
-
- /*
- * Flag the member as such so we remember to look in the archive for
- * its modification time. The OP_JOIN | OP_MADE is needed because this
- * target should never get made.
- */
- mem->type |= OP_MEMBER | OP_JOIN | OP_MADE;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * SuffFindNormalDeps --
- * Locate implicit dependencies for regular targets.
- *
- * Input:
- * gn Node for which to find sources
- *
- * Results:
- * None.
- *
- * Side Effects:
- * Same as Suff_FindDeps...
- *
- *-----------------------------------------------------------------------
- */
-static void
-SuffFindNormalDeps(GNode *gn, Lst slst)
-{
- char *eoname; /* End of name */
- char *sopref; /* Start of prefix */
- LstNode ln, nln; /* Next suffix node to check */
- Lst srcs; /* List of sources at which to look */
- Lst targs; /* List of targets to which things can be
- * transformed. They all have the same file,
- * but different suff and pref fields */
- Src *bottom; /* Start of found transformation path */
- Src *src; /* General Src pointer */
- char *pref; /* Prefix to use */
- Src *targ; /* General Src target pointer */
- SuffixCmpData sd; /* Search string data */
-
-
- sd.len = strlen(gn->name);
- sd.ename = eoname = gn->name + sd.len;
-
- sopref = gn->name;
-
- /*
- * Begin at the beginning...
- */
- ln = Lst_First(sufflist);
- srcs = Lst_Init(FALSE);
- targs = Lst_Init(FALSE);
-
- /*
- * We're caught in a catch-22 here. On the one hand, we want to use any
- * transformation implied by the target's sources, but we can't examine
- * the sources until we've expanded any variables/wildcards they may hold,
- * and we can't do that until we've set up the target's local variables
- * and we can't do that until we know what the proper suffix for the
- * target is (in case there are two suffixes one of which is a suffix of
- * the other) and we can't know that until we've found its implied
- * source, which we may not want to use if there's an existing source
- * that implies a different transformation.
- *
- * In an attempt to get around this, which may not work all the time,
- * but should work most of the time, we look for implied sources first,
- * checking transformations to all possible suffixes of the target,
- * use what we find to set the target's local variables, expand the
- * children, then look for any overriding transformations they imply.
- * Should we find one, we discard the one we found before.
- */
- bottom = NULL;
- targ = NULL;
-
- if (!(gn->type & OP_PHONY)) {
-
- while (ln != NULL) {
- /*
- * Look for next possible suffix...
- */
- ln = Lst_FindFrom(sufflist, ln, &sd, SuffSuffIsSuffixP);
-
- if (ln != NULL) {
- int prefLen; /* Length of the prefix */
-
- /*
- * Allocate a Src structure to which things can be transformed
- */
- targ = bmake_malloc(sizeof(Src));
- targ->file = bmake_strdup(gn->name);
- targ->suff = (Suff *)Lst_Datum(ln);
- targ->suff->refCount++;
- targ->node = gn;
- targ->parent = NULL;
- targ->children = 0;
-#ifdef DEBUG_SRC
- targ->cp = Lst_Init(FALSE);
-#endif
-
- /*
- * Allocate room for the prefix, whose end is found by
- * subtracting the length of the suffix from
- * the end of the name.
- */
- prefLen = (eoname - targ->suff->nameLen) - sopref;
- targ->pref = bmake_malloc(prefLen + 1);
- memcpy(targ->pref, sopref, prefLen);
- targ->pref[prefLen] = '\0';
-
- /*
- * Add nodes from which the target can be made
- */
- SuffAddLevel(srcs, targ);
-
- /*
- * Record the target so we can nuke it
- */
- (void)Lst_AtEnd(targs, targ);
-
- /*
- * Search from this suffix's successor...
- */
- ln = Lst_Succ(ln);
- }
- }
-
- /*
- * Handle target of unknown suffix...
- */
- if (Lst_IsEmpty(targs) && suffNull != NULL) {
- if (DEBUG(SUFF)) {
- fprintf(debug_file, "\tNo known suffix on %s. Using .NULL suffix\n", gn->name);
- }
-
- targ = bmake_malloc(sizeof(Src));
- targ->file = bmake_strdup(gn->name);
- targ->suff = suffNull;
- targ->suff->refCount++;
- targ->node = gn;
- targ->parent = NULL;
- targ->children = 0;
- targ->pref = bmake_strdup(sopref);
-#ifdef DEBUG_SRC
- targ->cp = Lst_Init(FALSE);
-#endif
-
- /*
- * Only use the default suffix rules if we don't have commands
- * defined for this gnode; traditional make programs used to
- * not define suffix rules if the gnode had children but we
- * don't do this anymore.
- */
- if (Lst_IsEmpty(gn->commands))
- SuffAddLevel(srcs, targ);
- else {
- if (DEBUG(SUFF))
- fprintf(debug_file, "not ");
- }
-
- if (DEBUG(SUFF))
- fprintf(debug_file, "adding suffix rules\n");
-
- (void)Lst_AtEnd(targs, targ);
- }
-
- /*
- * Using the list of possible sources built up from the target
- * suffix(es), try and find an existing file/target that matches.
- */
- bottom = SuffFindThem(srcs, slst);
-
- if (bottom == NULL) {
- /*
- * No known transformations -- use the first suffix found
- * for setting the local variables.
- */
- if (!Lst_IsEmpty(targs)) {
- targ = (Src *)Lst_Datum(Lst_First(targs));
- } else {
- targ = NULL;
- }
- } else {
- /*
- * Work up the transformation path to find the suffix of the
- * target to which the transformation was made.
- */
- for (targ = bottom; targ->parent != NULL; targ = targ->parent)
- continue;
- }
- }
-
- Var_Set(TARGET, gn->path ? gn->path : gn->name, gn, 0);
-
- pref = (targ != NULL) ? targ->pref : gn->name;
- Var_Set(PREFIX, pref, gn, 0);
-
- /*
- * Now we've got the important local variables set, expand any sources
- * that still contain variables or wildcards in their names.
- */
- for (ln = Lst_First(gn->children); ln != NULL; ln = nln) {
- nln = Lst_Succ(ln);
- SuffExpandChildren(ln, gn);
- }
-
- if (targ == NULL) {
- if (DEBUG(SUFF)) {
- fprintf(debug_file, "\tNo valid suffix on %s\n", gn->name);
- }
-
-sfnd_abort:
- /*
- * Deal with finding the thing on the default search path. We
- * always do that, not only if the node is only a source (not
- * on the lhs of a dependency operator or [XXX] it has neither
- * children or commands) as the old pmake did.
- */
- if ((gn->type & (OP_PHONY|OP_NOPATH)) == 0) {
- free(gn->path);
- gn->path = Dir_FindFile(gn->name,
- (targ == NULL ? dirSearchPath :
- targ->suff->searchPath));
- if (gn->path != NULL) {
- char *ptr;
- Var_Set(TARGET, gn->path, gn, 0);
-
- if (targ != NULL) {
- /*
- * Suffix known for the thing -- trim the suffix off
- * the path to form the proper .PREFIX variable.
- */
- int savep = strlen(gn->path) - targ->suff->nameLen;
- char savec;
-
- if (gn->suffix)
- gn->suffix->refCount--;
- gn->suffix = targ->suff;
- gn->suffix->refCount++;
-
- savec = gn->path[savep];
- gn->path[savep] = '\0';
-
- if ((ptr = strrchr(gn->path, '/')) != NULL)
- ptr++;
- else
- ptr = gn->path;
-
- Var_Set(PREFIX, ptr, gn, 0);
-
- gn->path[savep] = savec;
- } else {
- /*
- * The .PREFIX gets the full path if the target has
- * no known suffix.
- */
- if (gn->suffix)
- gn->suffix->refCount--;
- gn->suffix = NULL;
-
- if ((ptr = strrchr(gn->path, '/')) != NULL)
- ptr++;
- else
- ptr = gn->path;
-
- Var_Set(PREFIX, ptr, gn, 0);
- }
- }
- }
-
- goto sfnd_return;
- }
-
- /*
- * If the suffix indicates that the target is a library, mark that in
- * the node's type field.
- */
- if (targ->suff->flags & SUFF_LIBRARY) {
- gn->type |= OP_LIB;
- }
-
- /*
- * Check for overriding transformation rule implied by sources
- */
- if (!Lst_IsEmpty(gn->children)) {
- src = SuffFindCmds(targ, slst);
-
- if (src != NULL) {
- /*
- * Free up all the Src structures in the transformation path
- * up to, but not including, the parent node.
- */
- while (bottom && bottom->parent != NULL) {
- if (Lst_Member(slst, bottom) == NULL) {
- Lst_AtEnd(slst, bottom);
- }
- bottom = bottom->parent;
- }
- bottom = src;
- }
- }
-
- if (bottom == NULL) {
- /*
- * No idea from where it can come -- return now.
- */
- goto sfnd_abort;
- }
-
- /*
- * We now have a list of Src structures headed by 'bottom' and linked via
- * their 'parent' pointers. What we do next is create links between
- * source and target nodes (which may or may not have been created)
- * and set the necessary local variables in each target. The
- * commands for each target are set from the commands of the
- * transformation rule used to get from the src suffix to the targ
- * suffix. Note that this causes the commands list of the original
- * node, gn, to be replaced by the commands of the final
- * transformation rule. Also, the unmade field of gn is incremented.
- * Etc.
- */
- if (bottom->node == NULL) {
- bottom->node = Targ_FindNode(bottom->file, TARG_CREATE);
- }
-
- for (src = bottom; src->parent != NULL; src = src->parent) {
- targ = src->parent;
-
- if (src->node->suffix)
- src->node->suffix->refCount--;
- src->node->suffix = src->suff;
- src->node->suffix->refCount++;
-
- if (targ->node == NULL) {
- targ->node = Targ_FindNode(targ->file, TARG_CREATE);
- }
-
- SuffApplyTransform(targ->node, src->node,
- targ->suff, src->suff);
-
- if (targ->node != gn) {
- /*
- * Finish off the dependency-search process for any nodes
- * between bottom and gn (no point in questing around the
- * filesystem for their implicit source when it's already
- * known). Note that the node can't have any sources that
- * need expanding, since SuffFindThem will stop on an existing
- * node, so all we need to do is set the standard and System V
- * variables.
- */
- targ->node->type |= OP_DEPS_FOUND;
-
- Var_Set(PREFIX, targ->pref, targ->node, 0);
-
- Var_Set(TARGET, targ->node->name, targ->node, 0);
- }
- }
-
- if (gn->suffix)
- gn->suffix->refCount--;
- gn->suffix = src->suff;
- gn->suffix->refCount++;
-
- /*
- * Nuke the transformation path and the Src structures left over in the
- * two lists.
- */
-sfnd_return:
- if (bottom)
- if (Lst_Member(slst, bottom) == NULL)
- Lst_AtEnd(slst, bottom);
-
- while (SuffRemoveSrc(srcs) || SuffRemoveSrc(targs))
- continue;
-
- Lst_Concat(slst, srcs, LST_CONCLINK);
- Lst_Concat(slst, targs, LST_CONCLINK);
-}
-
-
-/*-
- *-----------------------------------------------------------------------
- * Suff_FindDeps --
- * Find implicit sources for the target described by the graph node
- * gn
- *
- * Results:
- * Nothing.
- *
- * Side Effects:
- * Nodes are added to the graph below the passed-in node. The nodes
- * are marked to have their IMPSRC variable filled in. The
- * PREFIX variable is set for the given node and all its
- * implied children.
- *
- * Notes:
- * The path found by this target is the shortest path in the
- * transformation graph, which may pass through non-existent targets,
- * to an existing target. The search continues on all paths from the
- * root suffix until a file is found. I.e. if there's a path
- * .o -> .c -> .l -> .l,v from the root and the .l,v file exists but
- * the .c and .l files don't, the search will branch out in
- * all directions from .o and again from all the nodes on the
- * next level until the .l,v node is encountered.
- *
- *-----------------------------------------------------------------------
- */
-
-void
-Suff_FindDeps(GNode *gn)
-{
-
- SuffFindDeps(gn, srclist);
- while (SuffRemoveSrc(srclist))
- continue;
-}
-
-
-/*
- * Input:
- * gn node we're dealing with
- *
- */
-static void
-SuffFindDeps(GNode *gn, Lst slst)
-{
- if (gn->type & OP_DEPS_FOUND) {
- /*
- * If dependencies already found, no need to do it again...
- */
- return;
- } else {
- gn->type |= OP_DEPS_FOUND;
- }
- /*
- * Make sure we have these set, may get revised below.
- */
- Var_Set(TARGET, gn->path ? gn->path : gn->name, gn, 0);
- Var_Set(PREFIX, gn->name, gn, 0);
-
- if (DEBUG(SUFF)) {
- fprintf(debug_file, "SuffFindDeps (%s)\n", gn->name);
- }
-
- if (gn->type & OP_ARCHV) {
- SuffFindArchiveDeps(gn, slst);
- } else if (gn->type & OP_LIB) {
- /*
- * If the node is a library, it is the arch module's job to find it
- * and set the TARGET variable accordingly. We merely provide the
- * search path, assuming all libraries end in ".a" (if the suffix
- * hasn't been defined, there's nothing we can do for it, so we just
- * set the TARGET variable to the node's name in order to give it a
- * value).
- */
- LstNode ln;
- Suff *s;
-
- ln = Lst_Find(sufflist, LIBSUFF, SuffSuffHasNameP);
- if (gn->suffix)
- gn->suffix->refCount--;
- if (ln != NULL) {
- gn->suffix = s = (Suff *)Lst_Datum(ln);
- gn->suffix->refCount++;
- Arch_FindLib(gn, s->searchPath);
- } else {
- gn->suffix = NULL;
- Var_Set(TARGET, gn->name, gn, 0);
- }
- /*
- * Because a library (-lfoo) target doesn't follow the standard
- * filesystem conventions, we don't set the regular variables for
- * the thing. .PREFIX is simply made empty...
- */
- Var_Set(PREFIX, "", gn, 0);
- } else {
- SuffFindNormalDeps(gn, slst);
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Suff_SetNull --
- * Define which suffix is the null suffix.
- *
- * Input:
- * name Name of null suffix
- *
- * Results:
- * None.
- *
- * Side Effects:
- * 'suffNull' is altered.
- *
- * Notes:
- * Need to handle the changing of the null suffix gracefully so the
- * old transformation rules don't just go away.
- *
- *-----------------------------------------------------------------------
- */
-void
-Suff_SetNull(char *name)
-{
- Suff *s;
- LstNode ln;
-
- ln = Lst_Find(sufflist, name, SuffSuffHasNameP);
- if (ln != NULL) {
- s = (Suff *)Lst_Datum(ln);
- if (suffNull != NULL) {
- suffNull->flags &= ~SUFF_NULL;
- }
- s->flags |= SUFF_NULL;
- /*
- * XXX: Here's where the transformation mangling would take place
- */
- suffNull = s;
- } else {
- Parse_Error(PARSE_WARNING, "Desired null suffix %s not defined.",
- name);
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Suff_Init --
- * Initialize suffixes module
- *
- * Results:
- * None
- *
- * Side Effects:
- * Many
- *-----------------------------------------------------------------------
- */
-void
-Suff_Init(void)
-{
-#ifdef CLEANUP
- suffClean = Lst_Init(FALSE);
-#endif
- srclist = Lst_Init(FALSE);
- transforms = Lst_Init(FALSE);
-
- /*
- * Create null suffix for single-suffix rules (POSIX). The thing doesn't
- * actually go on the suffix list or everyone will think that's its
- * suffix.
- */
- Suff_ClearSuffixes();
-}
-
-
-/*-
- *----------------------------------------------------------------------
- * Suff_End --
- * Cleanup the this module
- *
- * Results:
- * None
- *
- * Side Effects:
- * The memory is free'd.
- *----------------------------------------------------------------------
- */
-
-void
-Suff_End(void)
-{
-#ifdef CLEANUP
- Lst_Destroy(sufflist, SuffFree);
- Lst_Destroy(suffClean, SuffFree);
- if (suffNull)
- SuffFree(suffNull);
- Lst_Destroy(srclist, NULL);
- Lst_Destroy(transforms, NULL);
-#endif
-}
-
-
-/********************* DEBUGGING FUNCTIONS **********************/
-
-static int SuffPrintName(void *s, void *dummy MAKE_ATTR_UNUSED)
-{
-
- fprintf(debug_file, "%s ", ((Suff *)s)->name);
- return 0;
-}
-
-static int
-SuffPrintSuff(void *sp, void *dummy MAKE_ATTR_UNUSED)
-{
- Suff *s = (Suff *)sp;
- int flags;
- int flag;
-
- fprintf(debug_file, "# `%s' [%d] ", s->name, s->refCount);
-
- flags = s->flags;
- if (flags) {
- fputs(" (", debug_file);
- while (flags) {
- flag = 1 << (ffs(flags) - 1);
- flags &= ~flag;
- switch (flag) {
- case SUFF_NULL:
- fprintf(debug_file, "NULL");
- break;
- case SUFF_INCLUDE:
- fprintf(debug_file, "INCLUDE");
- break;
- case SUFF_LIBRARY:
- fprintf(debug_file, "LIBRARY");
- break;
- }
- fputc(flags ? '|' : ')', debug_file);
- }
- }
- fputc('\n', debug_file);
- fprintf(debug_file, "#\tTo: ");
- Lst_ForEach(s->parents, SuffPrintName, NULL);
- fputc('\n', debug_file);
- fprintf(debug_file, "#\tFrom: ");
- Lst_ForEach(s->children, SuffPrintName, NULL);
- fputc('\n', debug_file);
- fprintf(debug_file, "#\tSearch Path: ");
- Dir_PrintPath(s->searchPath);
- fputc('\n', debug_file);
- return 0;
-}
-
-static int
-SuffPrintTrans(void *tp, void *dummy MAKE_ATTR_UNUSED)
-{
- GNode *t = (GNode *)tp;
-
- fprintf(debug_file, "%-16s: ", t->name);
- Targ_PrintType(t->type);
- fputc('\n', debug_file);
- Lst_ForEach(t->commands, Targ_PrintCmd, NULL);
- fputc('\n', debug_file);
- return 0;
-}
-
-void
-Suff_PrintAll(void)
-{
- fprintf(debug_file, "#*** Suffixes:\n");
- Lst_ForEach(sufflist, SuffPrintSuff, NULL);
-
- fprintf(debug_file, "#*** Transformations:\n");
- Lst_ForEach(transforms, SuffPrintTrans, NULL);
-}
diff --git a/usr.bin/make/targ.c b/usr.bin/make/targ.c
deleted file mode 100644
index 01c3d1c..0000000
--- a/usr.bin/make/targ.c
+++ /dev/null
@@ -1,846 +0,0 @@
-/* $NetBSD: targ.c,v 1.62 2017/04/16 19:53:58 riastradh Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-/*
- * Copyright (c) 1989 by Berkeley Softworks
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: targ.c,v 1.62 2017/04/16 19:53:58 riastradh Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)targ.c 8.2 (Berkeley) 3/19/94";
-#else
-__RCSID("$NetBSD: targ.c,v 1.62 2017/04/16 19:53:58 riastradh Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * targ.c --
- * Functions for maintaining the Lst allTargets. Target nodes are
- * kept in two structures: a Lst, maintained by the list library, and a
- * hash table, maintained by the hash library.
- *
- * Interface:
- * Targ_Init Initialization procedure.
- *
- * Targ_End Cleanup the module
- *
- * Targ_List Return the list of all targets so far.
- *
- * Targ_NewGN Create a new GNode for the passed target
- * (string). The node is *not* placed in the
- * hash table, though all its fields are
- * initialized.
- *
- * Targ_FindNode Find the node for a given target, creating
- * and storing it if it doesn't exist and the
- * flags are right (TARG_CREATE)
- *
- * Targ_FindList Given a list of names, find nodes for all
- * of them. If a name doesn't exist and the
- * TARG_NOCREATE flag was given, an error message
- * is printed. Else, if a name doesn't exist,
- * its node is created.
- *
- * Targ_Ignore Return TRUE if errors should be ignored when
- * creating the given target.
- *
- * Targ_Silent Return TRUE if we should be silent when
- * creating the given target.
- *
- * Targ_Precious Return TRUE if the target is precious and
- * should not be removed if we are interrupted.
- *
- * Targ_Propagate Propagate information between related
- * nodes. Should be called after the
- * makefiles are parsed but before any
- * action is taken.
- *
- * Debugging:
- * Targ_PrintGraph Print out the entire graphm all variables
- * and statistics for the directory cache. Should
- * print something for suffixes, too, but...
- */
-
-#include <stdio.h>
-#include <time.h>
-
-#include "make.h"
-#include "hash.h"
-#include "dir.h"
-
-static Lst allTargets; /* the list of all targets found so far */
-#ifdef CLEANUP
-static Lst allGNs; /* List of all the GNodes */
-#endif
-static Hash_Table targets; /* a hash table of same */
-
-#define HTSIZE 191 /* initial size of hash table */
-
-static int TargPrintOnlySrc(void *, void *);
-static int TargPrintName(void *, void *);
-#ifdef CLEANUP
-static void TargFreeGN(void *);
-#endif
-static int TargPropagateCohort(void *, void *);
-static int TargPropagateNode(void *, void *);
-
-/*-
- *-----------------------------------------------------------------------
- * Targ_Init --
- * Initialize this module
- *
- * Results:
- * None
- *
- * Side Effects:
- * The allTargets list and the targets hash table are initialized
- *-----------------------------------------------------------------------
- */
-void
-Targ_Init(void)
-{
- allTargets = Lst_Init(FALSE);
- Hash_InitTable(&targets, HTSIZE);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Targ_End --
- * Finalize this module
- *
- * Results:
- * None
- *
- * Side Effects:
- * All lists and gnodes are cleared
- *-----------------------------------------------------------------------
- */
-void
-Targ_End(void)
-{
-#ifdef CLEANUP
- Lst_Destroy(allTargets, NULL);
- if (allGNs)
- Lst_Destroy(allGNs, TargFreeGN);
- Hash_DeleteTable(&targets);
-#endif
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Targ_List --
- * Return the list of all targets
- *
- * Results:
- * The list of all targets.
- *
- * Side Effects:
- * None
- *-----------------------------------------------------------------------
- */
-Lst
-Targ_List(void)
-{
- return allTargets;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Targ_NewGN --
- * Create and initialize a new graph node
- *
- * Input:
- * name the name to stick in the new node
- *
- * Results:
- * An initialized graph node with the name field filled with a copy
- * of the passed name
- *
- * Side Effects:
- * The gnode is added to the list of all gnodes.
- *-----------------------------------------------------------------------
- */
-GNode *
-Targ_NewGN(const char *name)
-{
- GNode *gn;
-
- gn = bmake_malloc(sizeof(GNode));
- gn->name = bmake_strdup(name);
- gn->uname = NULL;
- gn->path = NULL;
- if (name[0] == '-' && name[1] == 'l') {
- gn->type = OP_LIB;
- } else {
- gn->type = 0;
- }
- gn->unmade = 0;
- gn->unmade_cohorts = 0;
- gn->cohort_num[0] = 0;
- gn->centurion = NULL;
- gn->made = UNMADE;
- gn->flags = 0;
- gn->checked = 0;
- gn->mtime = 0;
- gn->cmgn = NULL;
- gn->iParents = Lst_Init(FALSE);
- gn->cohorts = Lst_Init(FALSE);
- gn->parents = Lst_Init(FALSE);
- gn->children = Lst_Init(FALSE);
- gn->order_pred = Lst_Init(FALSE);
- gn->order_succ = Lst_Init(FALSE);
- Hash_InitTable(&gn->context, 0);
- gn->commands = Lst_Init(FALSE);
- gn->suffix = NULL;
- gn->lineno = 0;
- gn->fname = NULL;
-
-#ifdef CLEANUP
- if (allGNs == NULL)
- allGNs = Lst_Init(FALSE);
- Lst_AtEnd(allGNs, gn);
-#endif
-
- return (gn);
-}
-
-#ifdef CLEANUP
-/*-
- *-----------------------------------------------------------------------
- * TargFreeGN --
- * Destroy a GNode
- *
- * Results:
- * None.
- *
- * Side Effects:
- * None.
- *-----------------------------------------------------------------------
- */
-static void
-TargFreeGN(void *gnp)
-{
- GNode *gn = (GNode *)gnp;
-
-
- free(gn->name);
- free(gn->uname);
- free(gn->path);
- /* gn->fname points to name allocated when file was opened, don't free */
-
- Lst_Destroy(gn->iParents, NULL);
- Lst_Destroy(gn->cohorts, NULL);
- Lst_Destroy(gn->parents, NULL);
- Lst_Destroy(gn->children, NULL);
- Lst_Destroy(gn->order_succ, NULL);
- Lst_Destroy(gn->order_pred, NULL);
- Hash_DeleteTable(&gn->context);
- Lst_Destroy(gn->commands, NULL);
- free(gn);
-}
-#endif
-
-
-/*-
- *-----------------------------------------------------------------------
- * Targ_FindNode --
- * Find a node in the list using the given name for matching
- *
- * Input:
- * name the name to find
- * flags flags governing events when target not
- * found
- *
- * Results:
- * The node in the list if it was. If it wasn't, return NULL of
- * flags was TARG_NOCREATE or the newly created and initialized node
- * if it was TARG_CREATE
- *
- * Side Effects:
- * Sometimes a node is created and added to the list
- *-----------------------------------------------------------------------
- */
-GNode *
-Targ_FindNode(const char *name, int flags)
-{
- GNode *gn; /* node in that element */
- Hash_Entry *he = NULL; /* New or used hash entry for node */
- Boolean isNew; /* Set TRUE if Hash_CreateEntry had to create */
- /* an entry for the node */
-
- if (!(flags & (TARG_CREATE | TARG_NOHASH))) {
- he = Hash_FindEntry(&targets, name);
- if (he == NULL)
- return NULL;
- return (GNode *)Hash_GetValue(he);
- }
-
- if (!(flags & TARG_NOHASH)) {
- he = Hash_CreateEntry(&targets, name, &isNew);
- if (!isNew)
- return (GNode *)Hash_GetValue(he);
- }
-
- gn = Targ_NewGN(name);
- if (!(flags & TARG_NOHASH))
- Hash_SetValue(he, gn);
- Var_Append(".ALLTARGETS", name, VAR_GLOBAL);
- (void)Lst_AtEnd(allTargets, gn);
- if (doing_depend)
- gn->flags |= FROM_DEPEND;
- return gn;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Targ_FindList --
- * Make a complete list of GNodes from the given list of names
- *
- * Input:
- * name list of names to find
- * flags flags used if no node is found for a given name
- *
- * Results:
- * A complete list of graph nodes corresponding to all instances of all
- * the names in names.
- *
- * Side Effects:
- * If flags is TARG_CREATE, nodes will be created for all names in
- * names which do not yet have graph nodes. If flags is TARG_NOCREATE,
- * an error message will be printed for each name which can't be found.
- * -----------------------------------------------------------------------
- */
-Lst
-Targ_FindList(Lst names, int flags)
-{
- Lst nodes; /* result list */
- LstNode ln; /* name list element */
- GNode *gn; /* node in tLn */
- char *name;
-
- nodes = Lst_Init(FALSE);
-
- if (Lst_Open(names) == FAILURE) {
- return (nodes);
- }
- while ((ln = Lst_Next(names)) != NULL) {
- name = (char *)Lst_Datum(ln);
- gn = Targ_FindNode(name, flags);
- if (gn != NULL) {
- /*
- * Note: Lst_AtEnd must come before the Lst_Concat so the nodes
- * are added to the list in the order in which they were
- * encountered in the makefile.
- */
- (void)Lst_AtEnd(nodes, gn);
- } else if (flags == TARG_NOCREATE) {
- Error("\"%s\" -- target unknown.", name);
- }
- }
- Lst_Close(names);
- return (nodes);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Targ_Ignore --
- * Return true if should ignore errors when creating gn
- *
- * Input:
- * gn node to check for
- *
- * Results:
- * TRUE if should ignore errors
- *
- * Side Effects:
- * None
- *-----------------------------------------------------------------------
- */
-Boolean
-Targ_Ignore(GNode *gn)
-{
- if (ignoreErrors || gn->type & OP_IGNORE) {
- return (TRUE);
- } else {
- return (FALSE);
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Targ_Silent --
- * Return true if be silent when creating gn
- *
- * Input:
- * gn node to check for
- *
- * Results:
- * TRUE if should be silent
- *
- * Side Effects:
- * None
- *-----------------------------------------------------------------------
- */
-Boolean
-Targ_Silent(GNode *gn)
-{
- if (beSilent || gn->type & OP_SILENT) {
- return (TRUE);
- } else {
- return (FALSE);
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Targ_Precious --
- * See if the given target is precious
- *
- * Input:
- * gn the node to check
- *
- * Results:
- * TRUE if it is precious. FALSE otherwise
- *
- * Side Effects:
- * None
- *-----------------------------------------------------------------------
- */
-Boolean
-Targ_Precious(GNode *gn)
-{
- if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP))) {
- return (TRUE);
- } else {
- return (FALSE);
- }
-}
-
-/******************* DEBUG INFO PRINTING ****************/
-
-static GNode *mainTarg; /* the main target, as set by Targ_SetMain */
-/*-
- *-----------------------------------------------------------------------
- * Targ_SetMain --
- * Set our idea of the main target we'll be creating. Used for
- * debugging output.
- *
- * Input:
- * gn The main target we'll create
- *
- * Results:
- * None.
- *
- * Side Effects:
- * "mainTarg" is set to the main target's node.
- *-----------------------------------------------------------------------
- */
-void
-Targ_SetMain(GNode *gn)
-{
- mainTarg = gn;
-}
-
-static int
-TargPrintName(void *gnp, void *pflags MAKE_ATTR_UNUSED)
-{
- GNode *gn = (GNode *)gnp;
-
- fprintf(debug_file, "%s%s ", gn->name, gn->cohort_num);
-
- return 0;
-}
-
-
-int
-Targ_PrintCmd(void *cmd, void *dummy MAKE_ATTR_UNUSED)
-{
- fprintf(debug_file, "\t%s\n", (char *)cmd);
- return 0;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Targ_FmtTime --
- * Format a modification time in some reasonable way and return it.
- *
- * Results:
- * The time reformatted.
- *
- * Side Effects:
- * The time is placed in a static area, so it is overwritten
- * with each call.
- *
- *-----------------------------------------------------------------------
- */
-char *
-Targ_FmtTime(time_t tm)
-{
- struct tm *parts;
- static char buf[128];
-
- parts = localtime(&tm);
- (void)strftime(buf, sizeof buf, "%k:%M:%S %b %d, %Y", parts);
- return(buf);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Targ_PrintType --
- * Print out a type field giving only those attributes the user can
- * set.
- *
- * Results:
- *
- * Side Effects:
- *
- *-----------------------------------------------------------------------
- */
-void
-Targ_PrintType(int type)
-{
- int tbit;
-
-#define PRINTBIT(attr) case CONCAT(OP_,attr): fprintf(debug_file, "." #attr " "); break
-#define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG))fprintf(debug_file, "." #attr " "); break
-
- type &= ~OP_OPMASK;
-
- while (type) {
- tbit = 1 << (ffs(type) - 1);
- type &= ~tbit;
-
- switch(tbit) {
- PRINTBIT(OPTIONAL);
- PRINTBIT(USE);
- PRINTBIT(EXEC);
- PRINTBIT(IGNORE);
- PRINTBIT(PRECIOUS);
- PRINTBIT(SILENT);
- PRINTBIT(MAKE);
- PRINTBIT(JOIN);
- PRINTBIT(INVISIBLE);
- PRINTBIT(NOTMAIN);
- PRINTDBIT(LIB);
- /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */
- case OP_MEMBER: if (DEBUG(TARG))fprintf(debug_file, ".MEMBER "); break;
- PRINTDBIT(ARCHV);
- PRINTDBIT(MADE);
- PRINTDBIT(PHONY);
- }
- }
-}
-
-static const char *
-made_name(enum enum_made made)
-{
- switch (made) {
- case UNMADE: return "unmade";
- case DEFERRED: return "deferred";
- case REQUESTED: return "requested";
- case BEINGMADE: return "being made";
- case MADE: return "made";
- case UPTODATE: return "up-to-date";
- case ERROR: return "error when made";
- case ABORTED: return "aborted";
- default: return "unknown enum_made value";
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * TargPrintNode --
- * print the contents of a node
- *-----------------------------------------------------------------------
- */
-int
-Targ_PrintNode(void *gnp, void *passp)
-{
- GNode *gn = (GNode *)gnp;
- int pass = passp ? *(int *)passp : 0;
-
- fprintf(debug_file, "# %s%s, flags %x, type %x, made %d\n",
- gn->name, gn->cohort_num, gn->flags, gn->type, gn->made);
- if (gn->flags == 0)
- return 0;
-
- if (!OP_NOP(gn->type)) {
- fprintf(debug_file, "#\n");
- if (gn == mainTarg) {
- fprintf(debug_file, "# *** MAIN TARGET ***\n");
- }
- if (pass >= 2) {
- if (gn->unmade) {
- fprintf(debug_file, "# %d unmade children\n", gn->unmade);
- } else {
- fprintf(debug_file, "# No unmade children\n");
- }
- if (! (gn->type & (OP_JOIN|OP_USE|OP_USEBEFORE|OP_EXEC))) {
- if (gn->mtime != 0) {
- fprintf(debug_file, "# last modified %s: %s\n",
- Targ_FmtTime(gn->mtime),
- made_name(gn->made));
- } else if (gn->made != UNMADE) {
- fprintf(debug_file, "# non-existent (maybe): %s\n",
- made_name(gn->made));
- } else {
- fprintf(debug_file, "# unmade\n");
- }
- }
- if (!Lst_IsEmpty (gn->iParents)) {
- fprintf(debug_file, "# implicit parents: ");
- Lst_ForEach(gn->iParents, TargPrintName, NULL);
- fprintf(debug_file, "\n");
- }
- } else {
- if (gn->unmade)
- fprintf(debug_file, "# %d unmade children\n", gn->unmade);
- }
- if (!Lst_IsEmpty (gn->parents)) {
- fprintf(debug_file, "# parents: ");
- Lst_ForEach(gn->parents, TargPrintName, NULL);
- fprintf(debug_file, "\n");
- }
- if (!Lst_IsEmpty (gn->order_pred)) {
- fprintf(debug_file, "# order_pred: ");
- Lst_ForEach(gn->order_pred, TargPrintName, NULL);
- fprintf(debug_file, "\n");
- }
- if (!Lst_IsEmpty (gn->order_succ)) {
- fprintf(debug_file, "# order_succ: ");
- Lst_ForEach(gn->order_succ, TargPrintName, NULL);
- fprintf(debug_file, "\n");
- }
-
- fprintf(debug_file, "%-16s", gn->name);
- switch (gn->type & OP_OPMASK) {
- case OP_DEPENDS:
- fprintf(debug_file, ": "); break;
- case OP_FORCE:
- fprintf(debug_file, "! "); break;
- case OP_DOUBLEDEP:
- fprintf(debug_file, ":: "); break;
- }
- Targ_PrintType(gn->type);
- Lst_ForEach(gn->children, TargPrintName, NULL);
- fprintf(debug_file, "\n");
- Lst_ForEach(gn->commands, Targ_PrintCmd, NULL);
- fprintf(debug_file, "\n\n");
- if (gn->type & OP_DOUBLEDEP) {
- Lst_ForEach(gn->cohorts, Targ_PrintNode, &pass);
- }
- }
- return (0);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * TargPrintOnlySrc --
- * Print only those targets that are just a source.
- *
- * Results:
- * 0.
- *
- * Side Effects:
- * The name of each file is printed preceded by #\t
- *
- *-----------------------------------------------------------------------
- */
-static int
-TargPrintOnlySrc(void *gnp, void *dummy MAKE_ATTR_UNUSED)
-{
- GNode *gn = (GNode *)gnp;
- if (!OP_NOP(gn->type))
- return 0;
-
- fprintf(debug_file, "#\t%s [%s] ",
- gn->name, gn->path ? gn->path : gn->name);
- Targ_PrintType(gn->type);
- fprintf(debug_file, "\n");
-
- return 0;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Targ_PrintGraph --
- * print the entire graph. heh heh
- *
- * Input:
- * pass Which pass this is. 1 => no processing
- * 2 => processing done
- *
- * Results:
- * none
- *
- * Side Effects:
- * lots o' output
- *-----------------------------------------------------------------------
- */
-void
-Targ_PrintGraph(int pass)
-{
- fprintf(debug_file, "#*** Input graph:\n");
- Lst_ForEach(allTargets, Targ_PrintNode, &pass);
- fprintf(debug_file, "\n\n");
- fprintf(debug_file, "#\n# Files that are only sources:\n");
- Lst_ForEach(allTargets, TargPrintOnlySrc, NULL);
- fprintf(debug_file, "#*** Global Variables:\n");
- Var_Dump(VAR_GLOBAL);
- fprintf(debug_file, "#*** Command-line Variables:\n");
- Var_Dump(VAR_CMD);
- fprintf(debug_file, "\n");
- Dir_PrintDirectories();
- fprintf(debug_file, "\n");
- Suff_PrintAll();
-}
-
-/*-
- *-----------------------------------------------------------------------
- * TargPropagateNode --
- * Propagate information from a single node to related nodes if
- * appropriate.
- *
- * Input:
- * gnp The node that we are processing.
- *
- * Results:
- * Always returns 0, for the benefit of Lst_ForEach().
- *
- * Side Effects:
- * Information is propagated from this node to cohort or child
- * nodes.
- *
- * If the node was defined with "::", then TargPropagateCohort()
- * will be called for each cohort node.
- *
- * If the node has recursive predecessors, then
- * TargPropagateRecpred() will be called for each recursive
- * predecessor.
- *-----------------------------------------------------------------------
- */
-static int
-TargPropagateNode(void *gnp, void *junk MAKE_ATTR_UNUSED)
-{
- GNode *gn = (GNode *)gnp;
-
- if (gn->type & OP_DOUBLEDEP)
- Lst_ForEach(gn->cohorts, TargPropagateCohort, gnp);
- return (0);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * TargPropagateCohort --
- * Propagate some bits in the type mask from a node to
- * a related cohort node.
- *
- * Input:
- * cnp The node that we are processing.
- * gnp Another node that has cnp as a cohort.
- *
- * Results:
- * Always returns 0, for the benefit of Lst_ForEach().
- *
- * Side Effects:
- * cnp's type bitmask is modified to incorporate some of the
- * bits from gnp's type bitmask. (XXX need a better explanation.)
- *-----------------------------------------------------------------------
- */
-static int
-TargPropagateCohort(void *cgnp, void *pgnp)
-{
- GNode *cgn = (GNode *)cgnp;
- GNode *pgn = (GNode *)pgnp;
-
- cgn->type |= pgn->type & ~OP_OPMASK;
- return (0);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Targ_Propagate --
- * Propagate information between related nodes. Should be called
- * after the makefiles are parsed but before any action is taken.
- *
- * Results:
- * none
- *
- * Side Effects:
- * Information is propagated between related nodes throughout the
- * graph.
- *-----------------------------------------------------------------------
- */
-void
-Targ_Propagate(void)
-{
- Lst_ForEach(allTargets, TargPropagateNode, NULL);
-}
diff --git a/usr.bin/make/trace.c b/usr.bin/make/trace.c
deleted file mode 100644
index 267177f..0000000
--- a/usr.bin/make/trace.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/* $NetBSD: trace.c,v 1.11 2008/12/28 18:31:51 christos Exp $ */
-
-/*-
- * Copyright (c) 2000 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * This code is derived from software contributed to The NetBSD Foundation
- * by Bill Sommerfeld
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
- */
-
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: trace.c,v 1.11 2008/12/28 18:31:51 christos Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-__RCSID("$NetBSD: trace.c,v 1.11 2008/12/28 18:31:51 christos Exp $");
-#endif /* not lint */
-#endif
-
-/*-
- * trace.c --
- * handle logging of trace events generated by various parts of make.
- *
- * Interface:
- * Trace_Init Initialize tracing (called once during
- * the lifetime of the process)
- *
- * Trace_End Finalize tracing (called before make exits)
- *
- * Trace_Log Log an event about a particular make job.
- */
-
-#include <sys/time.h>
-
-#include <stdio.h>
-#include <unistd.h>
-
-#include "make.h"
-#include "job.h"
-#include "trace.h"
-
-static FILE *trfile;
-static pid_t trpid;
-char *trwd;
-
-static const char *evname[] = {
- "BEG",
- "END",
- "ERR",
- "JOB",
- "DON",
- "INT",
-};
-
-void
-Trace_Init(const char *pathname)
-{
- char *p1;
- if (pathname != NULL) {
- trpid = getpid();
- trwd = Var_Value(".CURDIR", VAR_GLOBAL, &p1);
-
- trfile = fopen(pathname, "a");
- }
-}
-
-void
-Trace_Log(TrEvent event, Job *job)
-{
- struct timeval rightnow;
-
- if (trfile == NULL)
- return;
-
- gettimeofday(&rightnow, NULL);
-
- fprintf(trfile, "%lld.%06ld %d %s %d %s",
- (long long)rightnow.tv_sec, (long)rightnow.tv_usec,
- jobTokensRunning,
- evname[event], trpid, trwd);
- if (job != NULL) {
- fprintf(trfile, " %s %d %x %x", job->node->name,
- job->pid, job->flags, job->node->type);
- }
- fputc('\n', trfile);
- fflush(trfile);
-}
-
-void
-Trace_End(void)
-{
- if (trfile != NULL)
- fclose(trfile);
-}
diff --git a/usr.bin/make/trace.h b/usr.bin/make/trace.h
deleted file mode 100644
index dc0fc6c..0000000
--- a/usr.bin/make/trace.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* $NetBSD: trace.h,v 1.3 2008/04/28 20:24:14 martin Exp $ */
-
-/*-
- * Copyright (c) 2000 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * This code is derived from software contributed to The NetBSD Foundation
- * by Bill Sommerfeld
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
- */
-
-/*-
- * trace.h --
- * Definitions pertaining to the tracing of jobs in parallel mode.
- */
-
-typedef enum {
- MAKESTART,
- MAKEEND,
- MAKEERROR,
- JOBSTART,
- JOBEND,
- MAKEINTR
-} TrEvent;
-
-void Trace_Init(const char *);
-void Trace_Log(TrEvent, Job *);
-void Trace_End(void);
-
diff --git a/usr.bin/make/unit-tests/Makefile b/usr.bin/make/unit-tests/Makefile
deleted file mode 100644
index 07aaceb..0000000
--- a/usr.bin/make/unit-tests/Makefile
+++ /dev/null
@@ -1,139 +0,0 @@
-# $NetBSD: Makefile,v 1.53 2018/05/24 00:25:44 christos Exp $
-#
-# Unit tests for make(1)
-# The main targets are:
-#
-# all: run all the tests
-# test: run 'all', and compare to expected results
-# accept: move generated output to expected results
-#
-# Adding a test case.
-# Each feature should get its own set of tests in its own suitably
-# named makefile (*.mk), with its own set of expected results (*.exp),
-# and it should be added to the TESTNAMES list.
-#
-
-.MAIN: all
-
-UNIT_TESTS:= ${.PARSEDIR}
-.PATH: ${UNIT_TESTS}
-
-# Each test is in a sub-makefile.
-# Keep the list sorted.
-TESTNAMES= \
- comment \
- cond1 \
- cond2 \
- error \
- export \
- export-all \
- export-env \
- doterror \
- dotwait \
- forloop \
- forsubst \
- hash \
- misc \
- moderrs \
- modmatch \
- modmisc \
- modorder \
- modts \
- modword \
- order \
- posix \
- qequals \
- sunshcmd \
- sysv \
- ternary \
- unexport \
- unexport-env \
- varcmd \
- varmisc \
- varquote \
- varshell
-
-# these tests were broken by referting POSIX chanegs
-STRICT_POSIX_TESTS = \
- escape \
- impsrc \
- phony-end \
- posix1 \
- suffixes
-
-# Override make flags for certain tests
-flags.doterror=
-flags.order=-j1
-
-OUTFILES= ${TESTNAMES:S/$/.out/}
-
-all: ${OUTFILES}
-
-CLEANFILES += *.rawout *.out *.status *.tmp *.core *.tmp
-CLEANFILES += obj*.[och] lib*.a # posix1.mk
-CLEANFILES += issue* .[ab]* # suffixes.mk
-CLEANRECURSIVE += dir dummy # posix1.mk
-
-clean:
- rm -f ${CLEANFILES}
-.if !empty(CLEANRECURSIVE)
- rm -rf ${CLEANRECURSIVE}
-.endif
-
-TEST_MAKE?= ${.MAKE}
-TOOL_SED?= sed
-
-# ensure consistent results from sort(1)
-LC_ALL= C
-LANG= C
-.export LANG LC_ALL
-
-# the tests are actually done with sub-makes.
-.SUFFIXES: .mk .rawout .out
-.mk.rawout:
- @echo ${TEST_MAKE} ${flags.${.TARGET:R}:U-k} -f ${.IMPSRC}
- -@cd ${.OBJDIR} && \
- { ${TEST_MAKE} ${flags.${.TARGET:R}:U-k} -f ${.IMPSRC} \
- 2>&1 ; echo $$? >${.TARGET:R}.status ; } > ${.TARGET}.tmp
- @mv ${.TARGET}.tmp ${.TARGET}
-
-# We always pretend .MAKE was called 'make'
-# and strip ${.CURDIR}/ from the output
-# and replace anything after 'stopped in' with unit-tests
-# so the results can be compared.
-.rawout.out:
- @echo postprocess ${.TARGET}
- @${TOOL_SED} -e 's,^${TEST_MAKE:T:C/\./\\\./g}[][0-9]*:,make:,' \
- -e 's,${TEST_MAKE:C/\./\\\./g},make,' \
- -e '/stopped/s, /.*, unit-tests,' \
- -e 's,${.CURDIR:C/\./\\\./g}/,,g' \
- -e 's,${UNIT_TESTS:C/\./\\\./g}/,,g' \
- < ${.IMPSRC} > ${.TARGET}.tmp
- @echo "exit status `cat ${.TARGET:R}.status`" >> ${.TARGET}.tmp
- @mv ${.TARGET}.tmp ${.TARGET}
-
-# Compare all output files
-test: ${OUTFILES} .PHONY
- @failed= ; \
- for test in ${TESTNAMES}; do \
- diff -u ${UNIT_TESTS}/$${test}.exp $${test}.out \
- || failed="$${failed}$${failed:+ }$${test}" ; \
- done ; \
- if [ -n "$${failed}" ]; then \
- echo "Failed tests: $${failed}" ; false ; \
- else \
- echo "All tests passed" ; \
- fi
-
-accept:
- @for test in ${TESTNAMES}; do \
- cmp -s ${UNIT_TESTS}/$${test}.exp $${test}.out \
- || { echo "Replacing $${test}.exp" ; \
- cp $${test}.out ${UNIT_TESTS}/$${test}.exp ; } \
- done
-
-.if exists(${TEST_MAKE})
-${TESTNAMES:S/$/.rawout/}: ${TEST_MAKE}
-.endif
-
-.-include <bsd.obj.mk>
diff --git a/usr.bin/make/unit-tests/comment.exp b/usr.bin/make/unit-tests/comment.exp
deleted file mode 100644
index 9a97df0..0000000
--- a/usr.bin/make/unit-tests/comment.exp
+++ /dev/null
@@ -1,5 +0,0 @@
-comment testing start
-this is foo
-This is how a comment looks: # comment
-comment testing done
-exit status 0
diff --git a/usr.bin/make/unit-tests/comment.mk b/usr.bin/make/unit-tests/comment.mk
deleted file mode 100644
index 7dd7dbb..0000000
--- a/usr.bin/make/unit-tests/comment.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-# This is a comment
-.if ${MACHINE_ARCH} == something
-FOO=bar
-.endif
-
-#\
- Multiline comment
-
-BAR=# defined
-FOOBAR= # defined
-
-# This is an escaped comment \
-that keeps going until the end of this line
-
-# Another escaped comment \
-that \
-goes \
-on
-
-# This is NOT an escaped comment due to the double backslashes \\
-all: hi foo bar
- @echo comment testing done
-
-hi:
- @echo comment testing start
-
-foo:
- @echo this is $@
-
-bar:
- @echo This is how a comment looks: '# comment'
diff --git a/usr.bin/make/unit-tests/cond1.exp b/usr.bin/make/unit-tests/cond1.exp
deleted file mode 100644
index 701d504..0000000
--- a/usr.bin/make/unit-tests/cond1.exp
+++ /dev/null
@@ -1,23 +0,0 @@
-make: "cond1.mk" line 75: warning: extra else
-make: "cond1.mk" line 85: warning: extra else
-2 is prime
-A='other' B='unknown' C='clever' o='no,no'
-Passed:
- var
- ("var")
- (var != var)
- var != var
- !((var != var) && defined(name))
- var == quoted
-
-1 is not prime
-2 is prime
-3 is prime
-4 is not prime
-5 is prime
-
-make: warning: String comparison operator should be either == or !=
-make: Bad conditional expression `"0" > 0' in "0" > 0?OK:No
-
-OK
-exit status 0
diff --git a/usr.bin/make/unit-tests/cond1.mk b/usr.bin/make/unit-tests/cond1.mk
deleted file mode 100644
index e361832..0000000
--- a/usr.bin/make/unit-tests/cond1.mk
+++ /dev/null
@@ -1,109 +0,0 @@
-# $Id: cond1.mk,v 1.1 2014/08/21 13:44:51 apb Exp $
-
-# hard code these!
-TEST_UNAME_S= NetBSD
-TEST_UNAME_M= sparc
-TEST_MACHINE= i386
-
-.if ${TEST_UNAME_S}
-Ok=var,
-.endif
-.if ("${TEST_UNAME_S}")
-Ok+=(\"var\"),
-.endif
-.if (${TEST_UNAME_M} != ${TEST_MACHINE})
-Ok+=(var != var),
-.endif
-.if ${TEST_UNAME_M} != ${TEST_MACHINE}
-Ok+= var != var,
-.endif
-.if !((${TEST_UNAME_M} != ${TEST_MACHINE}) && defined(X))
-Ok+= !((var != var) && defined(name)),
-.endif
-# from bsd.obj.mk
-MKOBJ?=no
-.if ${MKOBJ} == "no"
-o= no
-Ok+= var == "quoted",
-.else
-.if defined(notMAKEOBJDIRPREFIX) || defined(norMAKEOBJDIR)
-.if defined(notMAKEOBJDIRPREFIX)
-o=${MAKEOBJDIRPREFIX}${__curdir}
-.else
-o= ${MAKEOBJDIR}
-.endif
-.endif
-o= o
-.endif
-
-# repeat the above to check we get the same result
-.if ${MKOBJ} == "no"
-o2= no
-.else
-.if defined(notMAKEOBJDIRPREFIX) || defined(norMAKEOBJDIR)
-.if defined(notMAKEOBJDIRPREFIX)
-o2=${MAKEOBJDIRPREFIX}${__curdir}
-.else
-o2= ${MAKEOBJDIR}
-.endif
-.endif
-o2= o
-.endif
-
-PRIMES=2 3 5 7 11
-NUMBERS=1 2 3 4 5
-
-n=2
-.if ${PRIMES:M$n} == ""
-X=not
-.else
-X=
-.endif
-
-.if ${MACHINE_ARCH} == no-such
-A=one
-.else
-.if ${MACHINE_ARCH} == not-this
-.if ${MACHINE_ARCH} == something-else
-A=unlikely
-.else
-A=no
-.endif
-.endif
-A=other
-# We expect an extra else warning - we're not skipping here
-.else
-A=this should be an error
-.endif
-
-.if $X != ""
-.if $X == not
-B=one
-.else
-B=other
-# We expect an extra else warning - we are skipping here
-.else
-B=this should be an error
-.endif
-.else
-B=unknown
-.endif
-
-.if "quoted" == quoted
-C=clever
-.else
-C=dim
-.endif
-
-.if defined(nosuch) && ${nosuch:Mx} != ""
-# this should not happen
-.info nosuch is x
-.endif
-
-all:
- @echo "$n is $X prime"
- @echo "A='$A' B='$B' C='$C' o='$o,${o2}'"
- @echo "Passed:${.newline} ${Ok:S/,/${.newline}/}"
- @echo "${NUMBERS:@n@$n is ${("${PRIMES:M$n}" == ""):?not:} prime${.newline}@}"
- @echo "${"${DoNotQuoteHere:U0}" > 0:?OK:No}"
- @echo "${${NoSuchNumber:U42} > 0:?OK:No}"
diff --git a/usr.bin/make/unit-tests/cond2.exp b/usr.bin/make/unit-tests/cond2.exp
deleted file mode 100644
index 22e76a5..0000000
--- a/usr.bin/make/unit-tests/cond2.exp
+++ /dev/null
@@ -1,7 +0,0 @@
-make: Bad conditional expression ` == "empty"' in == "empty"?oops:ok
-make: "cond2.mk" line 13: Malformed conditional ({TEST_TYPO} == "Ok")
-TEST_NOT_SET is empty or not defined
-make: "cond2.mk" line 20: Malformed conditional (${TEST_NOT_SET} == "empty")
-make: Fatal errors encountered -- cannot continue
-make: stopped in unit-tests
-exit status 1
diff --git a/usr.bin/make/unit-tests/cond2.mk b/usr.bin/make/unit-tests/cond2.mk
deleted file mode 100644
index aeb5a8c..0000000
--- a/usr.bin/make/unit-tests/cond2.mk
+++ /dev/null
@@ -1,29 +0,0 @@
-# $Id: cond2.mk,v 1.2 2015/12/02 00:28:24 sjg Exp $
-
-TEST_UNAME_S= NetBSD
-
-# this should be ok
-X:= ${${TEST_UNAME_S} == "NetBSD":?Ok:fail}
-.if $X == "Ok"
-Y= good
-.endif
-# expect: Bad conditional expression ` == "empty"' in == "empty"?oops:ok
-X:= ${${TEST_NOT_SET} == "empty":?oops:ok}
-# expect: Malformed conditional ({TEST_TYPO} == "Ok")
-.if {TEST_TYPO} == "Ok"
-Y= oops
-.endif
-.if empty(TEST_NOT_SET)
-Y!= echo TEST_NOT_SET is empty or not defined >&2; echo
-.endif
-# expect: Malformed conditional (${TEST_NOT_SET} == "empty")
-.if ${TEST_NOT_SET} == "empty"
-Y= oops
-.endif
-
-.if defined(.NDEF) && ${.NDEF} > 0
-Z= yes
-.endif
-
-all:
- @echo $@
diff --git a/usr.bin/make/unit-tests/doterror.exp b/usr.bin/make/unit-tests/doterror.exp
deleted file mode 100644
index 5655644..0000000
--- a/usr.bin/make/unit-tests/doterror.exp
+++ /dev/null
@@ -1,9 +0,0 @@
-At first, I am
-happy
-and now: sad
-*** Error code 1
-
-Stop.
-make: stopped in unit-tests
-.ERROR: Looks like 'sad' is upset.
-exit status 1
diff --git a/usr.bin/make/unit-tests/doterror.mk b/usr.bin/make/unit-tests/doterror.mk
deleted file mode 100644
index 7f1c78f..0000000
--- a/usr.bin/make/unit-tests/doterror.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-# $Id: doterror.mk,v 1.1 2014/08/21 13:44:51 apb Exp $
-
-
-.BEGIN:
- @echo At first, I am
-
-.END:
- @echo not reached
-
-.ERROR:
- @echo "$@: Looks like '${.ERROR_TARGET}' is upset."
-
-all: happy sad
-
-happy:
- @echo $@
-
-sad:
- @echo and now: $@; exit 1
-
diff --git a/usr.bin/make/unit-tests/dotwait.exp b/usr.bin/make/unit-tests/dotwait.exp
deleted file mode 100644
index bdc0a0e..0000000
--- a/usr.bin/make/unit-tests/dotwait.exp
+++ /dev/null
@@ -1,30 +0,0 @@
-simple.1
-simple.1
-simple.2
-simple.2
-recursive.1.1.*
-recursive.1.1.*
-recursive.1.1.*
-recursive.1.1.*
-recursive.1.99
-recursive.1.99
-recursive.2.1.*
-recursive.2.1.*
-recursive.2.1.*
-recursive.2.1.*
-recursive.2.99
-recursive.2.99
-shared.0
-shared.0
-shared.1.99
-shared.1.99
-shared.2.1
-shared.2.1
-shared.2.99
-shared.2.99
-cycle.1.99
-cycle.1.99
-make: Graph cycles through `cycle.2.99'
-make: Graph cycles through `cycle.2.98'
-make: Graph cycles through `cycle.2.97'
-exit status 0
diff --git a/usr.bin/make/unit-tests/dotwait.mk b/usr.bin/make/unit-tests/dotwait.mk
deleted file mode 100644
index bab5993..0000000
--- a/usr.bin/make/unit-tests/dotwait.mk
+++ /dev/null
@@ -1,61 +0,0 @@
-# $NetBSD: dotwait.mk,v 1.2 2017/10/08 20:44:19 sjg Exp $
-
-THISMAKEFILE:= ${.PARSEDIR}/${.PARSEFILE}
-
-TESTS= simple recursive shared cycle
-PAUSE= sleep 1
-
-# Use a .for loop rather than dependencies here, to ensure
-# that the tests are run one by one, with parallelism
-# only within tests.
-# Ignore "--- target ---" lines printed by parallel make.
-all:
-.for t in ${TESTS}
- @${.MAKE} -f ${THISMAKEFILE} -j4 $t 2>&1 | grep -v "^--- "
-.endfor
-
-#
-# Within each test, the names of the sub-targets follow these
-# conventions:
-# * If it's expected that two or more targets may be made in parallel,
-# then the target names will differ only in an alphabetic component
-# such as ".a" or ".b".
-# * If it's expected that two or more targets should be made in sequence
-# then the target names will differ in numeric components, such that
-# lexical ordering of the target names matches the expected order
-# in which the targets should be made.
-#
-# Targets may echo ${PARALLEL_TARG} to print a modified version
-# of their own name, in which alphabetic components like ".a" or ".b"
-# are converted to ".*". Two targets that are expected to
-# be made in parallel will thus print the same strings, so that the
-# output is independent of the order in which these targets are made.
-#
-PARALLEL_TARG= ${.TARGET:C/\.[a-z]/.*/g:Q}
-.DEFAULT:
- @echo ${PARALLEL_TARG}; ${PAUSE}; echo ${PARALLEL_TARG}
-_ECHOUSE: .USE
- @echo ${PARALLEL_TARG}; ${PAUSE}; echo ${PARALLEL_TARG}
-
-# simple: no recursion, no cycles
-simple: simple.1 .WAIT simple.2
-
-# recursive: all children of the left hand side of the .WAIT
-# must be made before any child of the right hand side.
-recursive: recursive.1.99 .WAIT recursive.2.99
-recursive.1.99: recursive.1.1.a recursive.1.1.b _ECHOUSE
-recursive.2.99: recursive.2.1.a recursive.2.1.b _ECHOUSE
-
-# shared: both shared.1.99 and shared.2.99 depend on shared.0.
-# shared.0 must be made first, even though it is a child of
-# the right hand side of the .WAIT.
-shared: shared.1.99 .WAIT shared.2.99
-shared.1.99: shared.0 _ECHOUSE
-shared.2.99: shared.2.1 shared.0 _ECHOUSE
-
-# cycle: the cyclic dependency must not cause infinite recursion
-# leading to stack overflow and a crash.
-cycle: cycle.1.99 .WAIT cycle.2.99
-cycle.2.99: cycle.2.98 _ECHOUSE
-cycle.2.98: cycle.2.97 _ECHOUSE
-cycle.2.97: cycle.2.99 _ECHOUSE
diff --git a/usr.bin/make/unit-tests/error.exp b/usr.bin/make/unit-tests/error.exp
deleted file mode 100644
index a2bf71b..0000000
--- a/usr.bin/make/unit-tests/error.exp
+++ /dev/null
@@ -1,4 +0,0 @@
-make: "error.mk" line 3: just FYI
-make: "error.mk" line 4: warning: this could be serious
-make: "error.mk" line 5: this is fatal
-exit status 1
diff --git a/usr.bin/make/unit-tests/error.mk b/usr.bin/make/unit-tests/error.mk
deleted file mode 100644
index 721ed50..0000000
--- a/usr.bin/make/unit-tests/error.mk
+++ /dev/null
@@ -1,10 +0,0 @@
-# $Id: error.mk,v 1.1 2014/08/21 13:44:51 apb Exp $
-
-.info just FYI
-.warning this could be serious
-.error this is fatal
-
-all:
-
-.info.html:
- @echo this should be ignored
diff --git a/usr.bin/make/unit-tests/escape.exp b/usr.bin/make/unit-tests/escape.exp
deleted file mode 100644
index 6238e27..0000000
--- a/usr.bin/make/unit-tests/escape.exp
+++ /dev/null
@@ -1,104 +0,0 @@
-var-1bs
-printf "%s=:%s:\n" VAR1BS 111\\111; printf "%s=:%s:\n" VAR1BSa 111\\aaa; printf "%s=:%s:\n" VAR1BSA 111\\aaa; printf "%s=:%s:\n" VAR1BSda 111\\\$\{a\}; printf "%s=:%s:\n" VAR1BSdA 111\\\$\{A\}; printf "%s=:%s:\n" VAR1BSc 111\#\ backslash\ escapes\ comment\ char,\ so\ this\ is\ part\ of\ the\ value; printf "%s=:%s:\n" VAR1BSsc 111\\\ ;
-VAR1BS=:111\111:
-VAR1BSa=:111\aaa:
-VAR1BSA=:111\aaa:
-VAR1BSda=:111\${a}:
-VAR1BSdA=:111\${A}:
-VAR1BSc=:111# backslash escapes comment char, so this is part of the value:
-VAR1BSsc=:111\ :
-var-2bs
-printf "%s=:%s:\n" VAR2BS 222\\\\222; printf "%s=:%s:\n" VAR2BSa 222\\\\aaa; printf "%s=:%s:\n" VAR2BSA 222\\\\aaa; printf "%s=:%s:\n" VAR2BSda 222\\\\\$\{a\}; printf "%s=:%s:\n" VAR2BSdA 222\\\\\$\{A\}; printf "%s=:%s:\n" VAR2BSc 222\\\\; printf "%s=:%s:\n" VAR2BSsc 222\\\\;
-VAR2BS=:222\\222:
-VAR2BSa=:222\\aaa:
-VAR2BSA=:222\\aaa:
-VAR2BSda=:222\\${a}:
-VAR2BSdA=:222\\${A}:
-VAR2BSc=:222\\:
-VAR2BSsc=:222\\:
-var-1bsnl
-printf "%s=:%s:\n" VAR1BSNL 111\ 111; printf "%s=:%s:\n" VAR1BSNLa 111\ aaa; printf "%s=:%s:\n" VAR1BSNLA 111\ aaa; printf "%s=:%s:\n" VAR1BSNLda 111\ \$\{a\}; printf "%s=:%s:\n" VAR1BSNLdA 111\ \$\{A\}; printf "%s=:%s:\n" VAR1BSNLc 111; printf "%s=:%s:\n" VAR1BSNLsc 111;
-VAR1BSNL=:111 111:
-VAR1BSNLa=:111 aaa:
-VAR1BSNLA=:111 aaa:
-VAR1BSNLda=:111 ${a}:
-VAR1BSNLdA=:111 ${A}:
-VAR1BSNLc=:111:
-VAR1BSNLsc=:111:
-var-2bsnl
-printf "%s=:%s:\n" VAR2BSNL 222\\\\; printf "%s=:%s:\n" VAR2BSNLa 222\\\\; printf "%s=:%s:\n" VAR2BSNLA 222\\\\; printf "%s=:%s:\n" VAR2BSNLda 222\\\\; printf "%s=:%s:\n" VAR2BSNLdA 222\\\\; printf "%s=:%s:\n" VAR2BSNLc 222\\\\; printf "%s=:%s:\n" VAR2BSNLsc 222\\\\;
-VAR2BSNL=:222\\:
-VAR2BSNLa=:222\\:
-VAR2BSNLA=:222\\:
-VAR2BSNLda=:222\\:
-VAR2BSNLdA=:222\\:
-VAR2BSNLc=:222\\:
-VAR2BSNLsc=:222\\:
-var-3bsnl
-printf "%s=:%s:\n" VAR3BSNL 333\\\\\ 333=; printf "%s=:%s:\n" VAR3BSNLa 333\\\\\ aaa=; printf "%s=:%s:\n" VAR3BSNLA 333\\\\\ aaa=; printf "%s=:%s:\n" VAR3BSNLda 333\\\\\ \$\{a\}=; printf "%s=:%s:\n" VAR3BSNLdA 333\\\\\ \$\{A\}=; printf "%s=:%s:\n" VAR3BSNLc 333\\\\; printf "%s=:%s:\n" VAR3BSNLsc 333\\\\;
-VAR3BSNL=:333\\ 333=:
-VAR3BSNLa=:333\\ aaa=:
-VAR3BSNLA=:333\\ aaa=:
-VAR3BSNLda=:333\\ ${a}=:
-VAR3BSNLdA=:333\\ ${A}=:
-VAR3BSNLc=:333\\:
-VAR3BSNLsc=:333\\:
-var-1bsnl-space
-printf "%s=:%s:\n" VAR1BSNL00 first\ line; printf "%s=:%s:\n" VAR1BSNL0 first\ line\ no\ space\ on\ second\ line; printf "%s=:%s:\n" VAR1BSNLs first\ line\ one\ space\ on\ second\ line; printf "%s=:%s:\n" VAR1BSNLss first\ line\ two\ spaces\ on\ second\ line; printf "%s=:%s:\n" VAR1BSNLt first\ line\ one\ tab\ on\ second\ line; printf "%s=:%s:\n" VAR1BSNLtt first\ line\ two\ tabs\ on\ second\ line; printf "%s=:%s:\n" VAR1BSNLxx first\ line\ many\ spaces\ and\ tabs\ \[\ \ \ \ \]\ on\ second\ line;
-VAR1BSNL00=:first line:
-VAR1BSNL0=:first line no space on second line:
-VAR1BSNLs=:first line one space on second line:
-VAR1BSNLss=:first line two spaces on second line:
-VAR1BSNLt=:first line one tab on second line:
-VAR1BSNLtt=:first line two tabs on second line:
-VAR1BSNLxx=:first line many spaces and tabs [ ] on second line:
-cmd-1bsnl
-echo :'first line\
-#second line without space\
-third line':
-:first line\
-#second line without space\
-third line:
-echo :'first line\
- second line spaces should be retained':
-:first line\
- second line spaces should be retained:
-echo :'first line\
-second line tab should be elided':
-:first line\
-second line tab should be elided:
-echo :'first line\
- only one tab should be elided, second tab remains'
-:first line\
- only one tab should be elided, second tab remains
-cmd-1bsnl-eof
-echo :'command ending with backslash-newline'; \
-
-:command ending with backslash-newline
-cmd-2bsnl
-echo take one\\
-take one\
-echo take two\\
-take two\
-echo take three\\
-take three\
-cmd-3bsnl
-echo :'first line\\\
-#second line without space\\\
-third line':
-:first line\\\
-#second line without space\\\
-third line:
-echo :'first line\\\
- second line spaces should be retained':
-:first line\\\
- second line spaces should be retained:
-echo :'first line\\\
-second line tab should be elided':
-:first line\\\
-second line tab should be elided:
-echo :'first line\\\
- only one tab should be elided, second tab remains'
-:first line\\\
- only one tab should be elided, second tab remains
-exit status 0
diff --git a/usr.bin/make/unit-tests/escape.mk b/usr.bin/make/unit-tests/escape.mk
deleted file mode 100644
index 829403d..0000000
--- a/usr.bin/make/unit-tests/escape.mk
+++ /dev/null
@@ -1,246 +0,0 @@
-# $Id: escape.mk,v 1.10 2014/09/09 10:22:27 apb Exp $
-#
-# Test backslash escaping.
-
-# Extracts from the POSIX 2008 specification
-# <http://pubs.opengroup.org/onlinepubs/9699919799/utilities/make.html>:
-#
-# Comments start with a <number-sign> ( '#' ) and continue until an
-# unescaped <newline> is reached.
-#
-# When an escaped <newline> (one preceded by a <backslash>) is found
-# anywhere in the makefile except in a command line, an include
-# line, or a line immediately preceding an include line, it shall
-# be replaced, along with any leading white space on the following
-# line, with a single <space>.
-#
-# When an escaped <newline> is found in a command line in a
-# makefile, the command line shall contain the <backslash>, the
-# <newline>, and the next line, except that the first character of
-# the next line shall not be included if it is a <tab>.
-#
-# When an escaped <newline> is found in an include line or in a
-# line immediately preceding an include line, the behavior is
-# unspecified.
-#
-# Notice that the behaviour of <backslash><backslash> or
-# <backslash><anything other than newline> is not mentioned. I think
-# this implies that <backslash> should be taken literally everywhere
-# except before <newline>.
-#
-# Our practice, despite what POSIX might say, is that "\#"
-# in a variable assignment stores "#" as part of the value.
-# The "\" is not taken literally, and the "#" does not begin a comment.
-#
-# Also, our practice is that an even number of backslashes before a
-# newline in a variable assignment simply stores the backslashes as part
-# of the value, and treats the newline as though it was not escaped.
-# Similarly, ann even number of backslashes before a newline in a
-# command simply uses the backslashes as part of the command test, but
-# does not escape the newline. This is compatible with GNU make.
-
-all: .PHONY
-# We will add dependencies like "all: yet-another-test" later.
-
-# Some variables to be expanded in tests
-#
-a = aaa
-A = ${a}
-
-# Backslash at end of line in a comment\
-should continue the comment. \
-# This is also tested in comment.mk.
-
-__printvars: .USE .MADE
- @echo ${.TARGET}
- ${.ALLSRC:@v@ printf "%s=:%s:\n" ${v:Q} ${${v}:Q}; @}
-
-# Embedded backslash in variable should be taken literally.
-#
-VAR1BS = 111\111
-VAR1BSa = 111\${a}
-VAR1BSA = 111\${A}
-VAR1BSda = 111\$${a}
-VAR1BSdA = 111\$${A}
-VAR1BSc = 111\# backslash escapes comment char, so this is part of the value
-VAR1BSsc = 111\ # This is a comment. Value ends with <backslash><space>
-
-all: var-1bs
-var-1bs: .PHONY __printvars VAR1BS VAR1BSa VAR1BSA VAR1BSda VAR1BSdA \
- VAR1BSc VAR1BSsc
-
-# Double backslash in variable should be taken as two literal backslashes.
-#
-VAR2BS = 222\\222
-VAR2BSa = 222\\${a}
-VAR2BSA = 222\\${A}
-VAR2BSda = 222\\$${a}
-VAR2BSdA = 222\\$${A}
-VAR2BSc = 222\\# backslash does not escape comment char, so this is a comment
-VAR2BSsc = 222\\ # This is a comment. Value ends with <backslash><backslash>
-
-all: var-2bs
-var-2bs: .PHONY __printvars VAR2BS VAR2BSa VAR2BSA VAR2BSda VAR2BSdA \
- VAR2BSc VAR2BSsc
-
-# Backslash-newline in a variable setting is replaced by a single space.
-#
-VAR1BSNL = 111\
-111
-VAR1BSNLa = 111\
-${a}
-VAR1BSNLA = 111\
-${A}
-VAR1BSNLda = 111\
-$${a}
-VAR1BSNLdA = 111\
-$${A}
-VAR1BSNLc = 111\
-# this should be processed as a comment
-VAR1BSNLsc = 111\
- # this should be processed as a comment
-
-all: var-1bsnl
-var-1bsnl: .PHONY
-var-1bsnl: .PHONY __printvars \
- VAR1BSNL VAR1BSNLa VAR1BSNLA VAR1BSNLda VAR1BSNLdA \
- VAR1BSNLc VAR1BSNLsc
-
-# Double-backslash-newline in a variable setting.
-# Both backslashes should be taken literally, and the newline is NOT escaped.
-#
-# The second lines below each end with '=' so that they will not
-# generate syntax errors regardless of whether or not they are
-# treated as part of the value.
-#
-VAR2BSNL = 222\\
-222=
-VAR2BSNLa = 222\\
-${a}=
-VAR2BSNLA = 222\\
-${A}=
-VAR2BSNLda = 222\\
-$${a}=
-VAR2BSNLdA = 222\\
-$${A}=
-VAR2BSNLc = 222\\
-# this should be processed as a comment
-VAR2BSNLsc = 222\\
- # this should be processed as a comment
-
-all: var-2bsnl
-var-2bsnl: .PHONY __printvars \
- VAR2BSNL VAR2BSNLa VAR2BSNLA VAR2BSNLda VAR2BSNLdA \
- VAR2BSNLc VAR2BSNLsc
-
-# Triple-backslash-newline in a variable setting.
-# First two should be taken literally, and last should escape the newline.
-#
-# The second lines below each end with '=' so that they will not
-# generate syntax errors regardless of whether or not they are
-# treated as part of the value.
-#
-VAR3BSNL = 333\\\
-333=
-VAR3BSNLa = 333\\\
-${a}=
-VAR3BSNLA = 333\\\
-${A}=
-VAR3BSNLda = 333\\\
-$${a}=
-VAR3BSNLdA = 333\\\
-$${A}=
-VAR3BSNLc = 333\\\
-# this should be processed as a comment
-VAR3BSNLsc = 333\\\
- # this should be processed as a comment
-
-all: var-3bsnl
-var-3bsnl: .PHONY __printvars \
- VAR3BSNL VAR3BSNLa VAR3BSNLA VAR3BSNLda VAR3BSNLdA \
- VAR3BSNLc VAR3BSNLsc
-
-# Backslash-newline in a variable setting, plus any amount of white space
-# on the next line, is replaced by a single space.
-#
-VAR1BSNL00= first line\
-
-# above line is entirely empty, and this is a comment
-VAR1BSNL0= first line\
-no space on second line
-VAR1BSNLs= first line\
- one space on second line
-VAR1BSNLss= first line\
- two spaces on second line
-VAR1BSNLt= first line\
- one tab on second line
-VAR1BSNLtt= first line\
- two tabs on second line
-VAR1BSNLxx= first line\
- many spaces and tabs [ ] on second line
-
-all: var-1bsnl-space
-var-1bsnl-space: .PHONY __printvars \
- VAR1BSNL00 VAR1BSNL0 VAR1BSNLs VAR1BSNLss VAR1BSNLt VAR1BSNLtt \
- VAR1BSNLxx
-
-# Backslash-newline in a command is retained.
-#
-# The "#" in "# second line without space" makes it a comment instead
-# of a syntax error if the preceding line is parsed incorretly.
-# The ":" in "third line':" makes it look like the start of a
-# target instead of a syntax error if the first line is parsed incorrectly.
-#
-all: cmd-1bsnl
-cmd-1bsnl: .PHONY
- @echo ${.TARGET}
- echo :'first line\
-#second line without space\
-third line':
- echo :'first line\
- second line spaces should be retained':
- echo :'first line\
- second line tab should be elided':
- echo :'first line\
- only one tab should be elided, second tab remains'
-
-# When backslash-newline appears at the end of a command script,
-# both the backslash and the newline should be passed to the shell.
-# The shell should elide the backslash-newline.
-#
-all: cmd-1bsnl-eof
-cmd-1bsnl-eof:
- @echo ${.TARGET}
- echo :'command ending with backslash-newline'; \
-
-# above line must be blank
-
-# Double-backslash-newline in a command.
-# Both backslashes are retained, but the newline is not escaped.
-# XXX: This may differ from POSIX, but matches gmake.
-#
-# When make passes two backslashes to the shell, the shell will pass one
-# backslash to the echo commant.
-#
-all: cmd-2bsnl
-cmd-2bsnl: .PHONY
- @echo ${.TARGET}
- echo take one\\
-# this should be a comment
- echo take two\\
- echo take three\\
-
-# Triple-backslash-newline in a command is retained.
-#
-all: cmd-3bsnl
-cmd-3bsnl: .PHONY
- @echo ${.TARGET}
- echo :'first line\\\
-#second line without space\\\
-third line':
- echo :'first line\\\
- second line spaces should be retained':
- echo :'first line\\\
- second line tab should be elided':
- echo :'first line\\\
- only one tab should be elided, second tab remains'
diff --git a/usr.bin/make/unit-tests/export-all.exp b/usr.bin/make/unit-tests/export-all.exp
deleted file mode 100644
index e3aefd4..0000000
--- a/usr.bin/make/unit-tests/export-all.exp
+++ /dev/null
@@ -1,12 +0,0 @@
-UT_ALL=even this gets exported
-UT_BADDIR=unit-tests
-UT_DOLLAR=This is $UT_FU
-UT_F=fine
-UT_FOO=foobar is fubar
-UT_FU=fubar
-UT_NO=all
-UT_OK=good
-UT_OKDIR=unit-tests
-UT_TEST=export-all
-UT_ZOO=hoopie
-exit status 0
diff --git a/usr.bin/make/unit-tests/export-all.mk b/usr.bin/make/unit-tests/export-all.mk
deleted file mode 100644
index 576487b..0000000
--- a/usr.bin/make/unit-tests/export-all.mk
+++ /dev/null
@@ -1,23 +0,0 @@
-# $Id: export-all.mk,v 1.2 2015/04/10 20:41:59 sjg Exp $
-
-UT_OK=good
-UT_F=fine
-
-# the old way to do :tA
-M_tAbad = C,.*,cd & \&\& 'pwd',:sh
-# the new
-M_tA = tA
-
-here := ${.PARSEDIR}
-
-# this will cause trouble (recursing if we let it)
-UT_BADDIR = ${${here}/../${here:T}:L:${M_tAbad}:T}
-# this will be ok
-UT_OKDIR = ${${here}/../${here:T}:L:${M_tA}:T}
-
-.export
-
-.include "export.mk"
-
-UT_TEST=export-all
-UT_ALL=even this gets exported
diff --git a/usr.bin/make/unit-tests/export-env.exp b/usr.bin/make/unit-tests/export-env.exp
deleted file mode 100644
index 8a779e6..0000000
--- a/usr.bin/make/unit-tests/export-env.exp
+++ /dev/null
@@ -1,11 +0,0 @@
-make:
-UT_TEST=export-env.mk
-UT_ENV=not-exported
-UT_EXP=not-exported
-UT_LIT=literal export-env.mk
-env:
-UT_TEST=export-env.mk
-UT_ENV=exported
-UT_EXP=exported
-UT_LIT=literal ${UT_TEST}
-exit status 0
diff --git a/usr.bin/make/unit-tests/export-env.mk b/usr.bin/make/unit-tests/export-env.mk
deleted file mode 100644
index c4d3e75..0000000
--- a/usr.bin/make/unit-tests/export-env.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-# $Id: export-env.mk,v 1.2 2016/02/18 20:25:08 sjg Exp $
-
-# our normal .export, subsequent changes affect the environment
-UT_TEST=this
-.export UT_TEST
-UT_TEST:= ${.PARSEFILE}
-
-# not so with .export-env
-UT_ENV=exported
-.export-env UT_ENV
-UT_ENV=not-exported
-
-# gmake style export goes further; affects nothing but the environment
-UT_EXP=before-export
-export UT_EXP=exported
-UT_EXP=not-exported
-
-UT_LIT= literal ${UT_TEST}
-.export-literal UT_LIT
-
-all:
- @echo make:; ${UT_TEST UT_ENV UT_EXP UT_LIT:L:@v@echo $v=${$v};@}
- @echo env:; ${UT_TEST UT_ENV UT_EXP UT_LIT:L:@v@echo $v=$${$v};@}
-
-
-
-
diff --git a/usr.bin/make/unit-tests/export.exp b/usr.bin/make/unit-tests/export.exp
deleted file mode 100644
index 143771c..0000000
--- a/usr.bin/make/unit-tests/export.exp
+++ /dev/null
@@ -1,6 +0,0 @@
-UT_DOLLAR=This is $UT_FU
-UT_FOO=foobar is fubar
-UT_FU=fubar
-UT_TEST=export
-UT_ZOO=hoopie
-exit status 0
diff --git a/usr.bin/make/unit-tests/export.mk b/usr.bin/make/unit-tests/export.mk
deleted file mode 100644
index 1b4ee72..0000000
--- a/usr.bin/make/unit-tests/export.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-# $Id: export.mk,v 1.1 2014/08/21 13:44:51 apb Exp $
-
-UT_TEST=export
-UT_FOO=foo${BAR}
-UT_FU=fubar
-UT_ZOO=hoopie
-UT_NO=all
-# belive it or not, we expect this one to come out with $UT_FU unexpanded.
-UT_DOLLAR= This is $$UT_FU
-
-.export UT_FU UT_FOO
-.export UT_DOLLAR
-# this one will be ignored
-.export .MAKE.PID
-
-BAR=bar is ${UT_FU}
-
-.MAKE.EXPORTED+= UT_ZOO UT_TEST
-
-all:
- @env | grep '^UT_' | sort
-
diff --git a/usr.bin/make/unit-tests/forloop.exp b/usr.bin/make/unit-tests/forloop.exp
deleted file mode 100644
index df14b75..0000000
--- a/usr.bin/make/unit-tests/forloop.exp
+++ /dev/null
@@ -1,19 +0,0 @@
-x=one
-x="two and three"
-x=four
-x="five"
-x=-I/this
-x=-I"This or that"
-x=-Ithat
-x="-DTHIS=\"this and that\""
-cfl=-I/this -I"This or that" -Ithat "-DTHIS=\"this and that\""
-a=one b="two and three"
-a=four b="five"
-a=ONE b="TWO AND THREE"
-a=FOUR b="FIVE"
-We expect an error next:
-make: "forloop.mk" line 38: Wrong number of words (9) in .for substitution list with 2 vars
-make: Fatal errors encountered -- cannot continue
-make: stopped in unit-tests
-OK
-exit status 0
diff --git a/usr.bin/make/unit-tests/forloop.mk b/usr.bin/make/unit-tests/forloop.mk
deleted file mode 100644
index e0399f3..0000000
--- a/usr.bin/make/unit-tests/forloop.mk
+++ /dev/null
@@ -1,45 +0,0 @@
-# $Id: forloop.mk,v 1.1 2014/08/21 13:44:51 apb Exp $
-
-all: for-loop
-
-LIST = one "two and three" four "five"
-
-.if make(for-fail)
-for-fail:
-
-XTRA_LIST = xtra
-.else
-
-.for x in ${LIST}
-X!= echo 'x=$x' >&2; echo
-.endfor
-
-CFL = -I/this -I"This or that" -Ithat "-DTHIS=\"this and that\""
-cfl=
-.for x in ${CFL}
-X!= echo 'x=$x' >&2; echo
-.if empty(cfl)
-cfl= $x
-.else
-cfl+= $x
-.endif
-.endfor
-X!= echo 'cfl=${cfl}' >&2; echo
-
-.if ${cfl} != ${CFL}
-.error ${.newline}'${cfl}' != ${.newline}'${CFL}'
-.endif
-
-.for a b in ${EMPTY}
-X!= echo 'a=$a b=$b' >&2; echo
-.endfor
-.endif
-
-.for a b in ${LIST} ${LIST:tu} ${XTRA_LIST}
-X!= echo 'a=$a b=$b' >&2; echo
-.endfor
-
-for-loop:
- @echo We expect an error next:
- @(cd ${.CURDIR} && ${.MAKE} -f ${MAKEFILE} for-fail) && \
- { echo "Oops that should have failed!"; exit 1; } || echo OK
diff --git a/usr.bin/make/unit-tests/forsubst.exp b/usr.bin/make/unit-tests/forsubst.exp
deleted file mode 100644
index 0a98c00..0000000
--- a/usr.bin/make/unit-tests/forsubst.exp
+++ /dev/null
@@ -1,2 +0,0 @@
-.for with :S;... OK
-exit status 0
diff --git a/usr.bin/make/unit-tests/forsubst.mk b/usr.bin/make/unit-tests/forsubst.mk
deleted file mode 100644
index 00cd9b6..0000000
--- a/usr.bin/make/unit-tests/forsubst.mk
+++ /dev/null
@@ -1,10 +0,0 @@
-# $Id: forsubst.mk,v 1.1 2014/08/21 13:44:51 apb Exp $
-
-all: for-subst
-
-here := ${.PARSEDIR}
-# this should not run foul of the parser
-.for file in ${.PARSEFILE}
-for-subst: ${file:S;^;${here}/;g}
- @echo ".for with :S;... OK"
-.endfor
diff --git a/usr.bin/make/unit-tests/hash.exp b/usr.bin/make/unit-tests/hash.exp
deleted file mode 100644
index 0a24234..0000000
--- a/usr.bin/make/unit-tests/hash.exp
+++ /dev/null
@@ -1,9 +0,0 @@
-b2af338b
-3360ac65
-7747f046
-9ca87054
-880fe816
-208fcbd3
-d5d376eb
-de41416c
-exit status 0
diff --git a/usr.bin/make/unit-tests/hash.mk b/usr.bin/make/unit-tests/hash.mk
deleted file mode 100644
index 1ed84e7..0000000
--- a/usr.bin/make/unit-tests/hash.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-STR1=
-STR2= a
-STR3= ab
-STR4= abc
-STR5= abcd
-STR6= abcde
-STR7= abcdef
-STR8= abcdefghijklmnopqrstuvwxyz
-
-all:
- @echo ${STR1:hash}
- @echo ${STR2:hash}
- @echo ${STR3:hash}
- @echo ${STR4:hash}
- @echo ${STR5:hash}
- @echo ${STR6:hash}
- @echo ${STR7:hash}
- @echo ${STR8:hash}
diff --git a/usr.bin/make/unit-tests/impsrc.exp b/usr.bin/make/unit-tests/impsrc.exp
deleted file mode 100644
index 23e8347..0000000
--- a/usr.bin/make/unit-tests/impsrc.exp
+++ /dev/null
@@ -1,13 +0,0 @@
-expected: source4
-actual: source4
-expected: target1.x
-actual: target1.x
-expected: target1.y
-actual: target1.y
-expected: source1
-actual: source1
-expected: source2
-actual: source2
-expected: source1
-actual: source1
-exit status 0
diff --git a/usr.bin/make/unit-tests/impsrc.mk b/usr.bin/make/unit-tests/impsrc.mk
deleted file mode 100644
index 95ae0c3..0000000
--- a/usr.bin/make/unit-tests/impsrc.mk
+++ /dev/null
@@ -1,43 +0,0 @@
-# $NetBSD: impsrc.mk,v 1.2 2014/08/30 22:21:07 sjg Exp $
-
-# Does ${.IMPSRC} work properly?
-# It should be set, in order of precedence, to ${.TARGET} of:
-# 1) the implied source of a transformation rule,
-# 2) the first prerequisite from the dependency line of an explicit rule, or
-# 3) the first prerequisite of an explicit rule.
-#
-
-all: target1.z target2 target3 target4
-
-.SUFFIXES: .x .y .z
-
-.x.y: source1
- @echo 'expected: target1.x'
- @echo 'actual: $<'
-
-.y.z: source2
- @echo 'expected: target1.y'
- @echo 'actual: $<'
-
-target1.y: source3
-
-target1.x: source4
- @echo 'expected: source4'
- @echo 'actual: $<'
-
-target2: source1 source2
- @echo 'expected: source1'
- @echo 'actual: $<'
-
-target3: source1
-target3: source2 source3
- @echo 'expected: source2'
- @echo 'actual: $<'
-
-target4: source1
-target4:
- @echo 'expected: source1'
- @echo 'actual: $<'
-
-source1 source2 source3 source4:
-
diff --git a/usr.bin/make/unit-tests/misc.exp b/usr.bin/make/unit-tests/misc.exp
deleted file mode 100644
index 39a9383..0000000
--- a/usr.bin/make/unit-tests/misc.exp
+++ /dev/null
@@ -1 +0,0 @@
-exit status 0
diff --git a/usr.bin/make/unit-tests/misc.mk b/usr.bin/make/unit-tests/misc.mk
deleted file mode 100644
index 2773e30..0000000
--- a/usr.bin/make/unit-tests/misc.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-# $Id: misc.mk,v 1.1 2014/08/21 13:44:51 apb Exp $
-
-.if !exists(${.CURDIR}/)
-.warning ${.CURDIR}/ doesn't exist ?
-.endif
-
-.if !exists(${.CURDIR}/.)
-.warning ${.CURDIR}/. doesn't exist ?
-.endif
-
-.if !exists(${.CURDIR}/..)
-.warning ${.CURDIR}/.. doesn't exist ?
-.endif
-
-all:
- @: all is well
diff --git a/usr.bin/make/unit-tests/moderrs.exp b/usr.bin/make/unit-tests/moderrs.exp
deleted file mode 100644
index cb51aa0..0000000
--- a/usr.bin/make/unit-tests/moderrs.exp
+++ /dev/null
@@ -1,16 +0,0 @@
-Expect: Unknown modifier 'Z'
-make: Unknown modifier 'Z'
-VAR:Z=
-Expect: Unknown modifier 'Z'
-make: Unknown modifier 'Z'
-VAR:Z=
-Expect: Unclosed variable specification for VAR
-make: Unclosed variable specification (expecting '}') for "VAR" (value "Thevariable") modifier S
-VAR:S,V,v,=Thevariable
-Expect: Unclosed variable specification for VAR
-make: Unclosed variable specification after complex modifier (expecting '}') for VAR
-VAR:S,V,v,=Thevariable
-Expect: Unclosed substitution for VAR (, missing)
-make: Unclosed substitution for VAR (, missing)
-VAR:S,V,v=
-exit status 0
diff --git a/usr.bin/make/unit-tests/moderrs.mk b/usr.bin/make/unit-tests/moderrs.mk
deleted file mode 100644
index 825e6c7..0000000
--- a/usr.bin/make/unit-tests/moderrs.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-# $Id: moderrs.mk,v 1.1 2014/08/21 13:44:51 apb Exp $
-#
-# various modifier error tests
-
-VAR=TheVariable
-# incase we have to change it ;-)
-MOD_UNKN=Z
-MOD_TERM=S,V,v
-MOD_S:= ${MOD_TERM},
-
-all: modunkn modunknV varterm vartermV modtermV
-
-modunkn:
- @echo "Expect: Unknown modifier 'Z'"
- @echo "VAR:Z=${VAR:Z}"
-
-modunknV:
- @echo "Expect: Unknown modifier 'Z'"
- @echo "VAR:${MOD_UNKN}=${VAR:${MOD_UNKN}}"
-
-varterm:
- @echo "Expect: Unclosed variable specification for VAR"
- @echo VAR:S,V,v,=${VAR:S,V,v,
-
-vartermV:
- @echo "Expect: Unclosed variable specification for VAR"
- @echo VAR:${MOD_TERM},=${VAR:${MOD_S}
-
-modtermV:
- @echo "Expect: Unclosed substitution for VAR (, missing)"
- -@echo "VAR:${MOD_TERM}=${VAR:${MOD_TERM}}"
diff --git a/usr.bin/make/unit-tests/modmatch.exp b/usr.bin/make/unit-tests/modmatch.exp
deleted file mode 100644
index a7bf8b7..0000000
--- a/usr.bin/make/unit-tests/modmatch.exp
+++ /dev/null
@@ -1,20 +0,0 @@
-LIB=a X_LIBS:M${LIB${LIB:tu}} is "/tmp/liba.a"
-LIB=a X_LIBS:M*/lib${LIB}.a is "/tmp/liba.a"
-LIB=a X_LIBS:M*/lib${LIB}.a:tu is "/TMP/LIBA.A"
-LIB=b X_LIBS:M${LIB${LIB:tu}} is ""
-LIB=b X_LIBS:M*/lib${LIB}.a is ""
-LIB=b X_LIBS:M*/lib${LIB}.a:tu is ""
-LIB=c X_LIBS:M${LIB${LIB:tu}} is ""
-LIB=c X_LIBS:M*/lib${LIB}.a is ""
-LIB=c X_LIBS:M*/lib${LIB}.a:tu is ""
-LIB=d X_LIBS:M${LIB${LIB:tu}} is "/tmp/libd.a"
-LIB=d X_LIBS:M*/lib${LIB}.a is "/tmp/libd.a"
-LIB=d X_LIBS:M*/lib${LIB}.a:tu is "/TMP/LIBD.A"
-LIB=e X_LIBS:M${LIB${LIB:tu}} is "/tmp/libe.a"
-LIB=e X_LIBS:M*/lib${LIB}.a is "/tmp/libe.a"
-LIB=e X_LIBS:M*/lib${LIB}.a:tu is "/TMP/LIBE.A"
-Mscanner=OK
-Upper=One Two Three Four
-Lower=five six seven
-nose=One Three five
-exit status 0
diff --git a/usr.bin/make/unit-tests/modmatch.mk b/usr.bin/make/unit-tests/modmatch.mk
deleted file mode 100644
index 4519928..0000000
--- a/usr.bin/make/unit-tests/modmatch.mk
+++ /dev/null
@@ -1,34 +0,0 @@
-
-X=a b c d e
-
-.for x in $X
-LIB${x:tu}=/tmp/lib$x.a
-.endfor
-
-X_LIBS= ${LIBA} ${LIBD} ${LIBE}
-
-LIB?=a
-
-var = head
-res = no
-.if !empty(var:M${:Uhead\:tail:C/:.*//})
-res = OK
-.endif
-
-all: show-libs check-cclass
-
-show-libs:
- @for x in $X; do ${.MAKE} -f ${MAKEFILE} show LIB=$$x; done
- @echo "Mscanner=${res}"
-
-show:
- @echo 'LIB=${LIB} X_LIBS:M$${LIB$${LIB:tu}} is "${X_LIBS:M${LIB${LIB:tu}}}"'
- @echo 'LIB=${LIB} X_LIBS:M*/lib$${LIB}.a is "${X_LIBS:M*/lib${LIB}.a}"'
- @echo 'LIB=${LIB} X_LIBS:M*/lib$${LIB}.a:tu is "${X_LIBS:M*/lib${LIB}.a:tu}"'
-
-LIST= One Two Three Four five six seven
-
-check-cclass:
- @echo Upper=${LIST:M[A-Z]*}
- @echo Lower=${LIST:M[^A-Z]*}
- @echo nose=${LIST:M[^s]*[ex]}
diff --git a/usr.bin/make/unit-tests/modmisc.exp b/usr.bin/make/unit-tests/modmisc.exp
deleted file mode 100644
index e406647..0000000
--- a/usr.bin/make/unit-tests/modmisc.exp
+++ /dev/null
@@ -1,10 +0,0 @@
-path=':/bin:/tmp::/:.:/no/such/dir:.'
-path='/bin:/tmp:/:/no/such/dir'
-path='/bin:/tmp:/:/no/such/dir'
-path='/bin':'/tmp':'/':'/no/such/dir'
-path='/bin':'/tmp':'/':'/no/such/dir'
-path_/usr/xbin=/opt/xbin/
-paths=/bin /tmp / /no/such/dir /opt/xbin
-PATHS=/BIN /TMP / /NO/SUCH/DIR /OPT/XBIN
-The answer is 42
-exit status 0
diff --git a/usr.bin/make/unit-tests/modmisc.mk b/usr.bin/make/unit-tests/modmisc.mk
deleted file mode 100644
index a292b96..0000000
--- a/usr.bin/make/unit-tests/modmisc.mk
+++ /dev/null
@@ -1,38 +0,0 @@
-# $Id: modmisc.mk,v 1.1 2014/08/21 13:44:51 apb Exp $
-#
-# miscellaneous modifier tests
-
-# do not put any dirs in this list which exist on some
-# but not all target systems - an exists() check is below.
-path=:/bin:/tmp::/:.:/no/such/dir:.
-# strip cwd from path.
-MOD_NODOT=S/:/ /g:N.:ts:
-# and decorate, note that $'s need to be doubled. Also note that
-# the modifier_variable can be used with other modifiers.
-MOD_NODOTX=S/:/ /g:N.:@d@'$$d'@
-# another mod - pretend it is more interesting
-MOD_HOMES=S,/home/,/homes/,
-MOD_OPT=@d@$${exists($$d):?$$d:$${d:S,/usr,/opt,}}@
-MOD_SEP=S,:, ,g
-
-all: modvar modvarloop modsysv
-
-modsysv:
- @echo "The answer is ${libfoo.a:L:libfoo.a=42}"
-
-modvar:
- @echo "path='${path}'"
- @echo "path='${path:${MOD_NODOT}}'"
- @echo "path='${path:S,home,homes,:${MOD_NODOT}}'"
- @echo "path=${path:${MOD_NODOTX}:ts:}"
- @echo "path=${path:${MOD_HOMES}:${MOD_NODOTX}:ts:}"
-
-.for d in ${path:${MOD_SEP}:N.} /usr/xbin
-path_$d?= ${d:${MOD_OPT}:${MOD_HOMES}}/
-paths+= ${d:${MOD_OPT}:${MOD_HOMES}}
-.endfor
-
-modvarloop:
- @echo "path_/usr/xbin=${path_/usr/xbin}"
- @echo "paths=${paths}"
- @echo "PATHS=${paths:tu}"
diff --git a/usr.bin/make/unit-tests/modorder.exp b/usr.bin/make/unit-tests/modorder.exp
deleted file mode 100644
index 4117427..0000000
--- a/usr.bin/make/unit-tests/modorder.exp
+++ /dev/null
@@ -1,11 +0,0 @@
-LIST = one two three four five six seven eight nine ten
-LIST:O = eight five four nine one seven six ten three two
-LIST:Ox = Ok
-LIST:O:Ox = Ok
-LISTX = Ok
-LISTSX = Ok
-make: Bad modifier `:OX' for LIST
-BADMOD 1 = }
-make: Bad modifier `:OxXX' for LIST
-BADMOD 2 = XX}
-exit status 0
diff --git a/usr.bin/make/unit-tests/modorder.mk b/usr.bin/make/unit-tests/modorder.mk
deleted file mode 100644
index bc24d33..0000000
--- a/usr.bin/make/unit-tests/modorder.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-# $NetBSD: modorder.mk,v 1.1 2014/08/21 13:44:51 apb Exp $
-
-LIST= one two three four five six seven eight nine ten
-LISTX= ${LIST:Ox}
-LISTSX:= ${LIST:Ox}
-TEST_RESULT= && echo Ok || echo Failed
-
-# unit-tests have to produce the same results on each run
-# so we cannot actually include :Ox output.
-all:
- @echo "LIST = ${LIST}"
- @echo "LIST:O = ${LIST:O}"
- # Note that 1 in every 10! trials two independently generated
- # randomized orderings will be the same. The test framework doesn't
- # support checking probabilistic output, so we accept that the test
- # will incorrectly fail with probability 2.8E-7.
- @echo "LIST:Ox = `test '${LIST:Ox}' != '${LIST:Ox}' ${TEST_RESULT}`"
- @echo "LIST:O:Ox = `test '${LIST:O:Ox}' != '${LIST:O:Ox}' ${TEST_RESULT}`"
- @echo "LISTX = `test '${LISTX}' != '${LISTX}' ${TEST_RESULT}`"
- @echo "LISTSX = `test '${LISTSX}' = '${LISTSX}' ${TEST_RESULT}`"
- @echo "BADMOD 1 = ${LIST:OX}"
- @echo "BADMOD 2 = ${LIST:OxXX}"
diff --git a/usr.bin/make/unit-tests/modts.exp b/usr.bin/make/unit-tests/modts.exp
deleted file mode 100644
index 3389649..0000000
--- a/usr.bin/make/unit-tests/modts.exp
+++ /dev/null
@@ -1,39 +0,0 @@
-LIST="one two three four five six"
-LIST:ts,="one,two,three,four,five,six"
-LIST:ts/:tu="ONE/TWO/THREE/FOUR/FIVE/SIX"
-LIST:ts::tu="ONE:TWO:THREE:FOUR:FIVE:SIX"
-LIST:ts:tu="ONETWOTHREEFOURFIVESIX"
-LIST:tu:ts/="ONE/TWO/THREE/FOUR/FIVE/SIX"
-LIST:ts:="one:two:three:four:five:six"
-LIST:ts="onetwothreefourfivesix"
-LIST:ts:S/two/2/="one2threefourfivesix"
-LIST:S/two/2/:ts="one2threefourfivesix"
-LIST:ts/:S/two/2/="one/2/three/four/five/six"
-Pretend the '/' in '/n' etc. below are back-slashes.
-LIST:ts/n="one
-two
-three
-four
-five
-six"
-LIST:ts/t="one two three four five six"
-LIST:ts/012:tu="ONE
-TWO
-THREE
-FOUR
-FIVE
-SIX"
-LIST:ts/xa:tu="ONE
-TWO
-THREE
-FOUR
-FIVE
-SIX"
-make: Bad modifier `:tx' for LIST
-LIST:tx="}"
-make: Bad modifier `:ts\X' for LIST
-LIST:ts/x:tu="\X:tu}"
-FU_mod-ts="a/b/cool"
-FU_mod-ts:ts:T="cool" == cool?
-B.${AAA:ts}="Baaa" == Baaa?
-exit status 0
diff --git a/usr.bin/make/unit-tests/modts.mk b/usr.bin/make/unit-tests/modts.mk
deleted file mode 100644
index 254aa42..0000000
--- a/usr.bin/make/unit-tests/modts.mk
+++ /dev/null
@@ -1,44 +0,0 @@
-
-LIST= one two three
-LIST+= four five six
-
-FU_mod-ts = a / b / cool
-
-AAA= a a a
-B.aaa= Baaa
-
-all: mod-ts
-
-# Use print or printf iff they are builtin.
-# XXX note that this causes problems, when make decides
-# there is no need to use a shell, so avoid where possible.
-.if ${type print 2> /dev/null || echo:L:sh:Mbuiltin} != ""
-PRINT= print -r --
-.elif ${type printf 2> /dev/null || echo:L:sh:Mbuiltin} != ""
-PRINT= printf '%s\n'
-.else
-PRINT= echo
-.endif
-
-mod-ts:
- @echo 'LIST="${LIST}"'
- @echo 'LIST:ts,="${LIST:ts,}"'
- @echo 'LIST:ts/:tu="${LIST:ts/:tu}"'
- @echo 'LIST:ts::tu="${LIST:ts::tu}"'
- @echo 'LIST:ts:tu="${LIST:ts:tu}"'
- @echo 'LIST:tu:ts/="${LIST:tu:ts/}"'
- @echo 'LIST:ts:="${LIST:ts:}"'
- @echo 'LIST:ts="${LIST:ts}"'
- @echo 'LIST:ts:S/two/2/="${LIST:ts:S/two/2/}"'
- @echo 'LIST:S/two/2/:ts="${LIST:S/two/2/:ts}"'
- @echo 'LIST:ts/:S/two/2/="${LIST:ts/:S/two/2/}"'
- @echo "Pretend the '/' in '/n' etc. below are back-slashes."
- @${PRINT} 'LIST:ts/n="${LIST:ts\n}"'
- @${PRINT} 'LIST:ts/t="${LIST:ts\t}"'
- @${PRINT} 'LIST:ts/012:tu="${LIST:ts\012:tu}"'
- @${PRINT} 'LIST:ts/xa:tu="${LIST:ts\xa:tu}"'
- @${PRINT} 'LIST:tx="${LIST:tx}"'
- @${PRINT} 'LIST:ts/x:tu="${LIST:ts\X:tu}"'
- @${PRINT} 'FU_$@="${FU_${@:ts}:ts}"'
- @${PRINT} 'FU_$@:ts:T="${FU_${@:ts}:ts:T}" == cool?'
- @${PRINT} 'B.$${AAA:ts}="${B.${AAA:ts}}" == Baaa?'
diff --git a/usr.bin/make/unit-tests/modword.exp b/usr.bin/make/unit-tests/modword.exp
deleted file mode 100644
index 258d7ea..0000000
--- a/usr.bin/make/unit-tests/modword.exp
+++ /dev/null
@@ -1,122 +0,0 @@
-make: Bad modifier `:[]' for LIST
-LIST:[]="" is an error
-LIST:[0]="one two three four five six"
-LIST:[0x0]="one two three four five six"
-LIST:[000]="one two three four five six"
-LIST:[*]="one two three four five six"
-LIST:[@]="one two three four five six"
-LIST:[0]:C/ /,/="one,two three four five six"
-LIST:[0]:C/ /,/g="one,two,three,four,five,six"
-LIST:[0]:C/ /,/1g="one,two,three,four,five,six"
-LIST:[*]:C/ /,/="one,two three four five six"
-LIST:[*]:C/ /,/g="one,two,three,four,five,six"
-LIST:[*]:C/ /,/1g="one,two,three,four,five,six"
-LIST:[@]:C/ /,/="one two three four five six"
-LIST:[@]:C/ /,/g="one two three four five six"
-LIST:[@]:C/ /,/1g="one two three four five six"
-LIST:[@]:[0]:C/ /,/="one,two three four five six"
-LIST:[0]:[@]:C/ /,/="one two three four five six"
-LIST:[@]:[*]:C/ /,/="one,two three four five six"
-LIST:[*]:[@]:C/ /,/="one two three four five six"
-EMPTY=""
-EMPTY:[#]="1" == 1 ?
-ESCAPEDSPACE="\ "
-ESCAPEDSPACE:[#]="1" == 1 ?
-REALLYSPACE=" "
-REALLYSPACE:[#]="1" == 1 ?
-LIST:[#]="6"
-LIST:[0]:[#]="1" == 1 ?
-LIST:[*]:[#]="1" == 1 ?
-LIST:[@]:[#]="6"
-LIST:[1]:[#]="1"
-LIST:[1..3]:[#]="3"
-EMPTY:[1]=""
-ESCAPEDSPACE="\ "
-ESCAPEDSPACE:[1]="\ "
-REALLYSPACE=" "
-REALLYSPACE:[1]="" == "" ?
-REALLYSPACE:[*]:[1]=" " == " " ?
-LIST:[1]="one"
-make: Bad modifier `:[1.]' for LIST
-LIST:[1.]="" is an error
-make: Bad modifier `:[1].' for LIST
-LIST:[1].="}" is an error
-LIST:[2]="two"
-LIST:[6]="six"
-LIST:[7]=""
-LIST:[999]=""
-make: Bad modifier `:[-]' for LIST
-LIST:[-]="" is an error
-make: Bad modifier `:[--]' for LIST
-LIST:[--]="" is an error
-LIST:[-1]="six"
-LIST:[-2]="five"
-LIST:[-6]="one"
-LIST:[-7]=""
-LIST:[-999]=""
-LONGLIST:[17]="17"
-LONGLIST:[0x11]="17"
-LONGLIST:[021]="17"
-LIST:[0]:[1]="one two three four five six"
-LIST:[*]:[1]="one two three four five six"
-LIST:[@]:[1]="one"
-LIST:[0]:[2]=""
-LIST:[*]:[2]=""
-LIST:[@]:[2]="two"
-LIST:[*]:C/ /,/:[2]=""
-LIST:[*]:C/ /,/:[*]:[2]=""
-LIST:[*]:C/ /,/:[@]:[2]="three"
-make: Bad modifier `:[1.]' for LIST
-LIST:[1.]="" is an error
-make: Bad modifier `:[1..]' for LIST
-LIST:[1..]="" is an error
-LIST:[1..1]="one"
-make: Bad modifier `:[1..1.]' for LIST
-LIST:[1..1.]="" is an error
-LIST:[1..2]="one two"
-LIST:[2..1]="two one"
-LIST:[3..-2]="three four five"
-LIST:[-4..4]="three four"
-make: Bad modifier `:[0..1]' for LIST
-LIST:[0..1]="" is an error
-make: Bad modifier `:[-1..0]' for LIST
-LIST:[-1..0]="" is an error
-LIST:[-1..1]="six five four three two one"
-LIST:[0..0]="one two three four five six"
-LIST:[3..99]="three four five six"
-LIST:[-3..-99]="four three two one"
-LIST:[-99..-3]="one two three four"
-HASH="#" == "#" ?
-LIST:[${HASH}]="6"
-LIST:[${ZERO}]="one two three four five six"
-LIST:[${ZERO}x${ONE}]="one"
-LIST:[${ONE}]="one"
-LIST:[${MINUSONE}]="six"
-LIST:[${STAR}]="one two three four five six"
-LIST:[${AT}]="one two three four five six"
-make: Bad modifier `:[${EMPTY' for LIST
-LIST:[${EMPTY}]="" is an error
-LIST:[${LONGLIST:[21]:S/2//}]="one"
-LIST:[${LIST:[#]}]="six"
-LIST:[${LIST:[${HASH}]}]="six"
-LIST:S/ /,/="one two three four five six"
-LIST:S/ /,/W="one,two three four five six"
-LIST:S/ /,/gW="one,two,three,four,five,six"
-EMPTY:S/^/,/=","
-EMPTY:S/^/,/W=","
-LIST:C/ /,/="one two three four five six"
-LIST:C/ /,/W="one,two three four five six"
-LIST:C/ /,/gW="one,two,three,four,five,six"
-EMPTY:C/^/,/=","
-EMPTY:C/^/,/W=","
-LIST:tW="one two three four five six"
-LIST:tw="one two three four five six"
-LIST:tW:C/ /,/="one,two three four five six"
-LIST:tW:C/ /,/g="one,two,three,four,five,six"
-LIST:tW:C/ /,/1g="one,two,three,four,five,six"
-LIST:tw:C/ /,/="one two three four five six"
-LIST:tw:C/ /,/g="one two three four five six"
-LIST:tw:C/ /,/1g="one two three four five six"
-LIST:tw:tW:C/ /,/="one,two three four five six"
-LIST:tW:tw:C/ /,/="one two three four five six"
-exit status 0
diff --git a/usr.bin/make/unit-tests/modword.mk b/usr.bin/make/unit-tests/modword.mk
deleted file mode 100644
index 00a56de..0000000
--- a/usr.bin/make/unit-tests/modword.mk
+++ /dev/null
@@ -1,151 +0,0 @@
-# $Id: modword.mk,v 1.1 2014/08/21 13:44:51 apb Exp $
-#
-# Test behaviour of new :[] modifier
-
-all: mod-squarebrackets mod-S-W mod-C-W mod-tW-tw
-
-LIST= one two three
-LIST+= four five six
-LONGLIST= 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
-
-EMPTY= # the space should be ignored
-ESCAPEDSPACE=\ # escaped space before the '#'
-REALLYSPACE:=${EMPTY:C/^/ /W}
-HASH= \#
-AT= @
-STAR= *
-ZERO= 0
-ONE= 1
-MINUSONE= -1
-
-mod-squarebrackets: mod-squarebrackets-0-star-at \
- mod-squarebrackets-hash \
- mod-squarebrackets-n \
- mod-squarebrackets-start-end \
- mod-squarebrackets-nested
-
-mod-squarebrackets-0-star-at:
- @echo 'LIST:[]="${LIST:[]}" is an error'
- @echo 'LIST:[0]="${LIST:[0]}"'
- @echo 'LIST:[0x0]="${LIST:[0x0]}"'
- @echo 'LIST:[000]="${LIST:[000]}"'
- @echo 'LIST:[*]="${LIST:[*]}"'
- @echo 'LIST:[@]="${LIST:[@]}"'
- @echo 'LIST:[0]:C/ /,/="${LIST:[0]:C/ /,/}"'
- @echo 'LIST:[0]:C/ /,/g="${LIST:[0]:C/ /,/g}"'
- @echo 'LIST:[0]:C/ /,/1g="${LIST:[0]:C/ /,/1g}"'
- @echo 'LIST:[*]:C/ /,/="${LIST:[*]:C/ /,/}"'
- @echo 'LIST:[*]:C/ /,/g="${LIST:[*]:C/ /,/g}"'
- @echo 'LIST:[*]:C/ /,/1g="${LIST:[*]:C/ /,/1g}"'
- @echo 'LIST:[@]:C/ /,/="${LIST:[@]:C/ /,/}"'
- @echo 'LIST:[@]:C/ /,/g="${LIST:[@]:C/ /,/g}"'
- @echo 'LIST:[@]:C/ /,/1g="${LIST:[@]:C/ /,/1g}"'
- @echo 'LIST:[@]:[0]:C/ /,/="${LIST:[@]:[0]:C/ /,/}"'
- @echo 'LIST:[0]:[@]:C/ /,/="${LIST:[0]:[@]:C/ /,/}"'
- @echo 'LIST:[@]:[*]:C/ /,/="${LIST:[@]:[*]:C/ /,/}"'
- @echo 'LIST:[*]:[@]:C/ /,/="${LIST:[*]:[@]:C/ /,/}"'
-
-mod-squarebrackets-hash:
- @echo 'EMPTY="${EMPTY}"'
- @echo 'EMPTY:[#]="${EMPTY:[#]}" == 1 ?'
- @echo 'ESCAPEDSPACE="${ESCAPEDSPACE}"'
- @echo 'ESCAPEDSPACE:[#]="${ESCAPEDSPACE:[#]}" == 1 ?'
- @echo 'REALLYSPACE="${REALLYSPACE}"'
- @echo 'REALLYSPACE:[#]="${REALLYSPACE:[#]}" == 1 ?'
- @echo 'LIST:[#]="${LIST:[#]}"'
- @echo 'LIST:[0]:[#]="${LIST:[0]:[#]}" == 1 ?'
- @echo 'LIST:[*]:[#]="${LIST:[*]:[#]}" == 1 ?'
- @echo 'LIST:[@]:[#]="${LIST:[@]:[#]}"'
- @echo 'LIST:[1]:[#]="${LIST:[1]:[#]}"'
- @echo 'LIST:[1..3]:[#]="${LIST:[1..3]:[#]}"'
-
-mod-squarebrackets-n:
- @echo 'EMPTY:[1]="${EMPTY:[1]}"'
- @echo 'ESCAPEDSPACE="${ESCAPEDSPACE}"'
- @echo 'ESCAPEDSPACE:[1]="${ESCAPEDSPACE:[1]}"'
- @echo 'REALLYSPACE="${REALLYSPACE}"'
- @echo 'REALLYSPACE:[1]="${REALLYSPACE:[1]}" == "" ?'
- @echo 'REALLYSPACE:[*]:[1]="${REALLYSPACE:[*]:[1]}" == " " ?'
- @echo 'LIST:[1]="${LIST:[1]}"'
- @echo 'LIST:[1.]="${LIST:[1.]}" is an error'
- @echo 'LIST:[1].="${LIST:[1].}" is an error'
- @echo 'LIST:[2]="${LIST:[2]}"'
- @echo 'LIST:[6]="${LIST:[6]}"'
- @echo 'LIST:[7]="${LIST:[7]}"'
- @echo 'LIST:[999]="${LIST:[999]}"'
- @echo 'LIST:[-]="${LIST:[-]}" is an error'
- @echo 'LIST:[--]="${LIST:[--]}" is an error'
- @echo 'LIST:[-1]="${LIST:[-1]}"'
- @echo 'LIST:[-2]="${LIST:[-2]}"'
- @echo 'LIST:[-6]="${LIST:[-6]}"'
- @echo 'LIST:[-7]="${LIST:[-7]}"'
- @echo 'LIST:[-999]="${LIST:[-999]}"'
- @echo 'LONGLIST:[17]="${LONGLIST:[17]}"'
- @echo 'LONGLIST:[0x11]="${LONGLIST:[0x11]}"'
- @echo 'LONGLIST:[021]="${LONGLIST:[021]}"'
- @echo 'LIST:[0]:[1]="${LIST:[0]:[1]}"'
- @echo 'LIST:[*]:[1]="${LIST:[*]:[1]}"'
- @echo 'LIST:[@]:[1]="${LIST:[@]:[1]}"'
- @echo 'LIST:[0]:[2]="${LIST:[0]:[2]}"'
- @echo 'LIST:[*]:[2]="${LIST:[*]:[2]}"'
- @echo 'LIST:[@]:[2]="${LIST:[@]:[2]}"'
- @echo 'LIST:[*]:C/ /,/:[2]="${LIST:[*]:C/ /,/:[2]}"'
- @echo 'LIST:[*]:C/ /,/:[*]:[2]="${LIST:[*]:C/ /,/:[*]:[2]}"'
- @echo 'LIST:[*]:C/ /,/:[@]:[2]="${LIST:[*]:C/ /,/:[@]:[2]}"'
-
-mod-squarebrackets-start-end:
- @echo 'LIST:[1.]="${LIST:[1.]}" is an error'
- @echo 'LIST:[1..]="${LIST:[1..]}" is an error'
- @echo 'LIST:[1..1]="${LIST:[1..1]}"'
- @echo 'LIST:[1..1.]="${LIST:[1..1.]}" is an error'
- @echo 'LIST:[1..2]="${LIST:[1..2]}"'
- @echo 'LIST:[2..1]="${LIST:[2..1]}"'
- @echo 'LIST:[3..-2]="${LIST:[3..-2]}"'
- @echo 'LIST:[-4..4]="${LIST:[-4..4]}"'
- @echo 'LIST:[0..1]="${LIST:[0..1]}" is an error'
- @echo 'LIST:[-1..0]="${LIST:[-1..0]}" is an error'
- @echo 'LIST:[-1..1]="${LIST:[-1..1]}"'
- @echo 'LIST:[0..0]="${LIST:[0..0]}"'
- @echo 'LIST:[3..99]="${LIST:[3..99]}"'
- @echo 'LIST:[-3..-99]="${LIST:[-3..-99]}"'
- @echo 'LIST:[-99..-3]="${LIST:[-99..-3]}"'
-
-mod-squarebrackets-nested:
- @echo 'HASH="${HASH}" == "#" ?'
- @echo 'LIST:[$${HASH}]="${LIST:[${HASH}]}"'
- @echo 'LIST:[$${ZERO}]="${LIST:[${ZERO}]}"'
- @echo 'LIST:[$${ZERO}x$${ONE}]="${LIST:[${ZERO}x${ONE}]}"'
- @echo 'LIST:[$${ONE}]="${LIST:[${ONE}]}"'
- @echo 'LIST:[$${MINUSONE}]="${LIST:[${MINUSONE}]}"'
- @echo 'LIST:[$${STAR}]="${LIST:[${STAR}]}"'
- @echo 'LIST:[$${AT}]="${LIST:[${AT}]}"'
- @echo 'LIST:[$${EMPTY}]="${LIST:[${EMPTY}]}" is an error'
- @echo 'LIST:[$${LONGLIST:[21]:S/2//}]="${LIST:[${LONGLIST:[21]:S/2//}]}"'
- @echo 'LIST:[$${LIST:[#]}]="${LIST:[${LIST:[#]}]}"'
- @echo 'LIST:[$${LIST:[$${HASH}]}]="${LIST:[${LIST:[${HASH}]}]}"'
-
-mod-C-W:
- @echo 'LIST:C/ /,/="${LIST:C/ /,/}"'
- @echo 'LIST:C/ /,/W="${LIST:C/ /,/W}"'
- @echo 'LIST:C/ /,/gW="${LIST:C/ /,/gW}"'
- @echo 'EMPTY:C/^/,/="${EMPTY:C/^/,/}"'
- @echo 'EMPTY:C/^/,/W="${EMPTY:C/^/,/W}"'
-
-mod-S-W:
- @echo 'LIST:S/ /,/="${LIST:S/ /,/}"'
- @echo 'LIST:S/ /,/W="${LIST:S/ /,/W}"'
- @echo 'LIST:S/ /,/gW="${LIST:S/ /,/gW}"'
- @echo 'EMPTY:S/^/,/="${EMPTY:S/^/,/}"'
- @echo 'EMPTY:S/^/,/W="${EMPTY:S/^/,/W}"'
-
-mod-tW-tw:
- @echo 'LIST:tW="${LIST:tW}"'
- @echo 'LIST:tw="${LIST:tw}"'
- @echo 'LIST:tW:C/ /,/="${LIST:tW:C/ /,/}"'
- @echo 'LIST:tW:C/ /,/g="${LIST:tW:C/ /,/g}"'
- @echo 'LIST:tW:C/ /,/1g="${LIST:tW:C/ /,/1g}"'
- @echo 'LIST:tw:C/ /,/="${LIST:tw:C/ /,/}"'
- @echo 'LIST:tw:C/ /,/g="${LIST:tw:C/ /,/g}"'
- @echo 'LIST:tw:C/ /,/1g="${LIST:tw:C/ /,/1g}"'
- @echo 'LIST:tw:tW:C/ /,/="${LIST:tw:tW:C/ /,/}"'
- @echo 'LIST:tW:tw:C/ /,/="${LIST:tW:tw:C/ /,/}"'
diff --git a/usr.bin/make/unit-tests/order.exp b/usr.bin/make/unit-tests/order.exp
deleted file mode 100644
index d876914..0000000
--- a/usr.bin/make/unit-tests/order.exp
+++ /dev/null
@@ -1,4 +0,0 @@
-Making the.c
-Making the.h
-Making the.o from the.h the.c
-exit status 0
diff --git a/usr.bin/make/unit-tests/order.mk b/usr.bin/make/unit-tests/order.mk
deleted file mode 100644
index f90b627..0000000
--- a/usr.bin/make/unit-tests/order.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-# $NetBSD: order.mk,v 1.1 2014/08/21 13:44:51 apb Exp $
-
-# Test that .ORDER is handled correctly.
-# The explicit dependency the.o: the.h will make us examine the.h
-# the .ORDER will prevent us building it immediately,
-# we should then examine the.c rather than stop.
-
-all: the.o
-
-.ORDER: the.c the.h
-
-the.c the.h:
- @echo Making $@
-
-.SUFFIXES: .o .c
-
-.c.o:
- @echo Making $@ from $?
-
-the.o: the.h
diff --git a/usr.bin/make/unit-tests/phony-end.exp b/usr.bin/make/unit-tests/phony-end.exp
deleted file mode 100644
index c3c517c..0000000
--- a/usr.bin/make/unit-tests/phony-end.exp
+++ /dev/null
@@ -1,6 +0,0 @@
-.TARGET="phony" .PREFIX="phony" .IMPSRC=""
-.TARGET="all" .PREFIX="all" .IMPSRC="phony"
-.TARGET="ok" .PREFIX="ok" .IMPSRC=""
-.TARGET="also.ok" .PREFIX="also.ok" .IMPSRC=""
-.TARGET="bug" .PREFIX="bug" .IMPSRC=""
-exit status 0
diff --git a/usr.bin/make/unit-tests/phony-end.mk b/usr.bin/make/unit-tests/phony-end.mk
deleted file mode 100644
index 92cc0e6..0000000
--- a/usr.bin/make/unit-tests/phony-end.mk
+++ /dev/null
@@ -1,9 +0,0 @@
-# $Id: phony-end.mk,v 1.1 2014/08/21 13:44:51 apb Exp $
-
-all ok also.ok bug phony:
- @echo '${.TARGET .PREFIX .IMPSRC:L:@v@$v="${$v}"@}'
-
-.END: ok also.ok bug
-
-phony bug: .PHONY
-all: phony
diff --git a/usr.bin/make/unit-tests/posix.exp b/usr.bin/make/unit-tests/posix.exp
deleted file mode 100644
index 7e74cab..0000000
--- a/usr.bin/make/unit-tests/posix.exp
+++ /dev/null
@@ -1,23 +0,0 @@
-Posix says we should execute the command as if run by system(3)
-Expect 'Hello,' and 'World!'
-Hello,
-World!
-a command
-a command prefixed by '+' executes even with -n
-another command
-make -n
-echo a command
-echo "a command prefixed by '+' executes even with -n"
-a command prefixed by '+' executes even with -n
-echo another command
-make -n -j1
-{ echo a command
-} || exit $?
-echo "a command prefixed by '+' executes even with -n"
-a command prefixed by '+' executes even with -n
-{ echo another command
-} || exit $?
-Now we expect an error...
-*** Error code 1 (continuing)
-`all' not remade because of errors.
-exit status 0
diff --git a/usr.bin/make/unit-tests/posix.mk b/usr.bin/make/unit-tests/posix.mk
deleted file mode 100644
index a73e2e5..0000000
--- a/usr.bin/make/unit-tests/posix.mk
+++ /dev/null
@@ -1,24 +0,0 @@
-# $Id: posix.mk,v 1.1 2014/08/21 13:44:51 apb Exp $
-
-all: x plus subs err
-
-x:
- @echo "Posix says we should execute the command as if run by system(3)"
- @echo "Expect 'Hello,' and 'World!'"
- @echo Hello,; false; echo "World!"
-
-plus:
- @echo a command
- +@echo "a command prefixed by '+' executes even with -n"
- @echo another command
-
-subs:
- @echo make -n
- @${.MAKE} -f ${MAKEFILE} -n plus
- @echo make -n -j1
- @${.MAKE} -f ${MAKEFILE} -n -j1 plus
-
-err:
- @(echo Now we expect an error...; exit 1)
- @echo "Oops! you shouldn't see this!"
-
diff --git a/usr.bin/make/unit-tests/posix1.exp b/usr.bin/make/unit-tests/posix1.exp
deleted file mode 100644
index fa1f15d..0000000
--- a/usr.bin/make/unit-tests/posix1.exp
+++ /dev/null
@@ -1,186 +0,0 @@
-${VAR} = "foo bar baz"
-a
-b
-c
-foo baR baz, bar baz, foo bar baz, fooadd baradd bazadd
-mkdir -p 'dir'
-touch 'dir/obj_1.h'
-mkdir -p 'dir'
-printf '#include "obj_1.h"\nconst char* obj_1 = "dir/obj_1.c";\n' \
- >'dir/obj_1.c'
-Local variables
- ${@}="dir/obj_1.o" ${<}="dir/obj_1.c"
- ${*}="dir/obj_1" ${?}="dir/obj_1.h dir/obj_1.c"
- ${%}=""
-
-Directory and filename parts of local variables
- ${@D}="dir" ${@F}="obj_1.o"
- ${<D}="dir" ${<F}="obj_1.c"
- ${*D}="dir" ${*F}="obj_1"
- ${?D}="dir dir" ${?F}="obj_1.h obj_1.c"
- ${%D}="" ${%F}=""
-
-Local variable substitutions
- ${@:.o=}="dir/obj_1" ${<:.c=.C}="dir/obj_1.C"
- ${*:=.h}="dir/obj_1.h" ${?:.h=.H}="dir/obj_1.H dir/obj_1.c"
- ${%:=}=""
-
-Target with suffix transformations
- ${@D:=append}="dirappend"
- ${@F:.o=.O}="obj_1.O"
-
- Implied source with suffix transformations
- ${<D:r=rr}="dirr"
- ${<F:.c=.C}="obj_1.C"
-
- Suffixless target with suffix transformations
- ${*D:.=dot}="dir"
- ${*F:.a=}="obj_1"
-
- Out-of-date dependencies with suffix transformations
- ${?D:ir=}="d d"
- ${?F:.h=.H}="obj_1.H obj_1.c"
-
- Member with suffix transformations
- ${%D:.=}=""
- ${%F:${VAR2}=${VAR}}=""
-
-cc -c -o 'dir/obj_1.o' 'dir/obj_1.c'
-mkdir -p '.'
-touch 'dummy'
-Local variables
- ${@}="lib.a" ${<}="dir/obj_1.o"
- ${*}="obj1" ${?}="dir/obj_1.o dummy"
- ${%}="obj1.o"
-
-Directory and filename parts of local variables
- ${@D}="." ${@F}="lib.a"
- ${<D}="dir" ${<F}="obj_1.o"
- ${*D}="." ${*F}="obj1"
- ${?D}="dir ." ${?F}="obj_1.o dummy"
- ${%D}="." ${%F}="obj1.o"
-
-Local variable substitutions
- ${@:.o=}="lib.a" ${<:.c=.C}="dir/obj_1.o"
- ${*:=.h}="obj1.h" ${?:.h=.H}="dir/obj_1.o dummy"
- ${%:=}="obj1.o"
-
-Target with suffix transformations
- ${@D:=append}=".append"
- ${@F:.o=.O}="lib.a"
-
- Implied source with suffix transformations
- ${<D:r=rr}="dirr"
- ${<F:.c=.C}="obj_1.o"
-
- Suffixless target with suffix transformations
- ${*D:.=dot}="dot"
- ${*F:.a=}="obj1"
-
- Out-of-date dependencies with suffix transformations
- ${?D:ir=}="d ."
- ${?F:.h=.H}="obj_1.o dummy"
-
- Member with suffix transformations
- ${%D:.=}=""
- ${%F:${VAR2}=${VAR}}="obj1foo bar baz"
-
-cp 'dir/obj_1.o' 'obj1.o'
-ar -rcv 'lib.a' 'obj1.o'
-a - obj1.o
-rm -f 'obj1.o'
-mkdir -p '.'
-printf '#include "obj_2.h"\nconst char* obj_2 = "obj_2.c";\n' \
- >'obj_2.c'
-mkdir -p '.'
-touch 'obj_2.h'
-Local variables
- ${@}="obj2.o" ${<}="obj_2.c"
- ${*}="obj2" ${?}="obj_2.c obj_2.h dir/obj_1.h"
- ${%}=""
-
-Directory and filename parts of local variables
- ${@D}="." ${@F}="obj2.o"
- ${<D}="." ${<F}="obj_2.c"
- ${*D}="." ${*F}="obj2"
- ${?D}=". . dir" ${?F}="obj_2.c obj_2.h obj_1.h"
- ${%D}="" ${%F}=""
-
-Local variable substitutions
- ${@:.o=}="obj2" ${<:.c=.C}="obj_2.C"
- ${*:=.h}="obj2.h" ${?:.h=.H}="obj_2.c obj_2.H dir/obj_1.H"
- ${%:=}=""
-
-Target with suffix transformations
- ${@D:=append}=".append"
- ${@F:.o=.O}="obj2.O"
-
- Implied source with suffix transformations
- ${<D:r=rr}="."
- ${<F:.c=.C}="obj_2.C"
-
- Suffixless target with suffix transformations
- ${*D:.=dot}="dot"
- ${*F:.a=}="obj2"
-
- Out-of-date dependencies with suffix transformations
- ${?D:ir=}=". . d"
- ${?F:.h=.H}="obj_2.c obj_2.H obj_1.H"
-
- Member with suffix transformations
- ${%D:.=}=""
- ${%F:${VAR2}=${VAR}}=""
-
-cc -c -o 'obj2.o' 'obj_2.c'
-ar -rcv 'lib.a' 'obj2.o'
-a - obj2.o
-mkdir -p '.'
-touch 'obj3.h'
-mkdir -p 'dir'
-touch 'dir/dummy'
-mkdir -p '.'
-printf '#include "obj3.h"\nconst char* obj3 = "obj3.c";\n' \
- >'obj3.c'
-Local variables
- ${@}="lib.a" ${<}="obj3.c"
- ${*}="obj3" ${?}="obj3.h dir/dummy obj3.c"
- ${%}="obj3.o"
-
-Directory and filename parts of local variables
- ${@D}="." ${@F}="lib.a"
- ${<D}="." ${<F}="obj3.c"
- ${*D}="." ${*F}="obj3"
- ${?D}=". dir ." ${?F}="obj3.h dummy obj3.c"
- ${%D}="." ${%F}="obj3.o"
-
-Local variable substitutions
- ${@:.o=}="lib.a" ${<:.c=.C}="obj3.C"
- ${*:=.h}="obj3.h" ${?:.h=.H}="obj3.H dir/dummy obj3.c"
- ${%:=}="obj3.o"
-
-Target with suffix transformations
- ${@D:=append}=".append"
- ${@F:.o=.O}="lib.a"
-
- Implied source with suffix transformations
- ${<D:r=rr}="."
- ${<F:.c=.C}="obj3.C"
-
- Suffixless target with suffix transformations
- ${*D:.=dot}="dot"
- ${*F:.a=}="obj3"
-
- Out-of-date dependencies with suffix transformations
- ${?D:ir=}=". d ."
- ${?F:.h=.H}="obj3.H dummy obj3.c"
-
- Member with suffix transformations
- ${%D:.=}=""
- ${%F:${VAR2}=${VAR}}="obj3foo bar baz"
-
-cc -c -o 'obj3.o' 'obj3.c'
-ar -rcv 'lib.a' 'obj3.o'
-a - obj3.o
-rm -f 'obj3.o'
-ar -s 'lib.a'
-exit status 0
diff --git a/usr.bin/make/unit-tests/posix1.mk b/usr.bin/make/unit-tests/posix1.mk
deleted file mode 100644
index 1bf6a56..0000000
--- a/usr.bin/make/unit-tests/posix1.mk
+++ /dev/null
@@ -1,184 +0,0 @@
-# $NetBSD: posix1.mk,v 1.3 2014/08/30 22:21:08 sjg Exp $
-
-# Keep the default suffixes from interfering, just in case.
-.SUFFIXES:
-
-all: line-continuations suffix-substitution localvars
-
-# we need to clean for repeatable results
-.BEGIN: clean
-clean:
- @rm -f lib.a dir/* dummy obj*
-
-#
-# Line continuations
-#
-
-# Escaped newlines and leading whitespace from the next line are replaced
-# with single space, except in commands, where the escape and the newline
-# are retained, but a single leading tab (if any) from the next line is
-# removed. (PR 49085)
-# Expect:
-# ${VAR} = "foo bar baz"
-# a
-# b
-# c
-VAR = foo\
-\
- bar\
- baz
-
-line-continuations:
- @echo '$${VAR} = "${VAR}"'
- @echo 'aXbXc' | sed -e 's/X/\
- /g'
-
-
-#
-# Suffix substitution
-#
-
-# The only variable modifier accepted by POSIX.
-# ${VAR:s1=s2}: replace s1, if found, with s2 at end of each word in
-# ${VAR}. s1 and s2 may contain macro expansions.
-# Expect: foo baR baz, bar baz, foo bar baz, fooadd baradd bazadd
-suffix-substitution:
- @echo '${VAR:r=R}, ${VAR:foo=}, ${VAR:not_there=wrong}, ${VAR:=add}'
-
-
-#
-# Local variables: regular forms, D/F forms and suffix substitution.
-#
-
-# In the past substitutions did not work with the D/F forms and those
-# forms were not available for $?. (PR 49085)
-
-ARFLAGS = -rcv
-
-localvars: lib.a
-
-# $@ = target or archive name $< = implied source
-# $* = target without suffix $? = sources newer than target
-# $% = archive member name
-LOCALS = \
- "Local variables\n\
- \$${@}=\"${@}\" \$${<}=\"${<}\"\n\
- \$${*}=\"${*}\" \$${?}=\"${?}\"\n\
- \$${%%}=\"${%}\"\n\n"
-
-# $XD = directory part of X $XF = file part of X
-# X is one of the local variables.
-LOCAL_ALTERNATIVES = \
- "Directory and filename parts of local variables\n\
- \$${@D}=\"${@D}\" \$${@F}=\"${@F}\"\n\
- \$${<D}=\"${<D}\" \$${<F}=\"${<F}\"\n\
- \$${*D}=\"${*D}\" \$${*F}=\"${*F}\"\n\
- \$${?D}=\"${?D}\" \$${?F}=\"${?F}\"\n\
- \$${%%D}=\"${%D}\" \$${%%F}=\"${%F}\"\n\n"
-
-# Do all kinds of meaningless substitutions on local variables to see
-# if they work. Add, remove and replace things.
-VAR2 = .o
-VAR3 = foo
-LOCAL_SUBSTITUTIONS = \
- "Local variable substitutions\n\
- \$${@:.o=}=\"${@:.o=}\" \$${<:.c=.C}=\"${<:.c=.C}\"\n\
- \$${*:=.h}=\"${*:=.h}\" \$${?:.h=.H}=\"${?:.h=.H}\"\n\
- \$${%%:=}=\"${%:=}\"\n\n"
-
-LOCAL_ALTERNATIVE_SUBSTITUTIONS = \
- "Target with suffix transformations\n\
- \$${@D:=append}=\"${@D:=append}\"\n\
- \$${@F:.o=.O}=\"${@F:.o=.O}\"\n\
- \n\
- Implied source with suffix transformations\n\
- \$${<D:r=rr}=\"${<D:r=rr}\"\n\
- \$${<F:.c=.C}=\"${<F:.c=.C}\"\n\
- \n\
- Suffixless target with suffix transformations\n\
- \$${*D:.=dot}=\"${*D:.=dot}\"\n\
- \$${*F:.a=}=\"${*F:.a=}\"\n\
- \n\
- Out-of-date dependencies with suffix transformations\n\
- \$${?D:ir=}=\"${?D:ir=}\"\n\
- \$${?F:.h=.H}=\"${?F:.h=.H}\"\n\
- \n\
- Member with suffix transformations\n\
- \$${%%D:.=}=\"${%D:.=}\"\n\
- \$${%%F:\$${VAR2}=\$${VAR}}=\"${%F:${VAR2}=${VAR}}\"\n\n"
-
-.SUFFIXES: .c .o .a
-
-# The system makefiles make the .c.a rule .PRECIOUS with a special source,
-# but such a thing is not POSIX compatible. It's also somewhat useless
-# in a test makefile.
-.c.a:
- @printf ${LOCALS}
- @printf ${LOCAL_ALTERNATIVES}
- @printf ${LOCAL_SUBSTITUTIONS}
- @printf ${LOCAL_ALTERNATIVE_SUBSTITUTIONS}
- cc -c -o '${%}' '${<}'
- ar ${ARFLAGS} '${@}' '${%}'
- rm -f '${%}'
-
-.c.o:
- @printf ${LOCALS}
- @printf ${LOCAL_ALTERNATIVES}
- @printf ${LOCAL_SUBSTITUTIONS}
- @printf ${LOCAL_ALTERNATIVE_SUBSTITUTIONS}
- cc -c -o '${@}' '${<}'
-
-# Some of these rules are padded with useless extra dependencies just so
-# that ${?} has more than one file.
-
-lib.a: lib.a(obj1.o) lib.a(obj2.o) lib.a(obj3.o)
- ar -s '${@}'
-
-# Explicit rule where the dependency is an inferred file. The dependency
-# object's name differs from the member's because there was a bug which
-# forced a dependency on member even when no such dependency was specified
-# (PR 49086).
-lib.a(obj1.o): dir/obj_1.o dummy
- @printf ${LOCALS}
- @printf ${LOCAL_ALTERNATIVES}
- @printf ${LOCAL_SUBSTITUTIONS}
- @printf ${LOCAL_ALTERNATIVE_SUBSTITUTIONS}
- cp 'dir/obj_1.o' '$%'
- ar ${ARFLAGS} '${@}' '$%'
- rm -f '$%'
-
-# Excplicit rule where the dependency also has an explicit rule.
-lib.a(obj2.o): obj2.o
- ar ${ARFLAGS} '${@}' '${%}'
-
-# Use .c.a inference with an extra dependency.
-lib.a(obj3.o): obj3.h dir/dummy
-
-# Use .c.o inference with an extra dependency.
-dir/obj_1.o: dir/obj_1.h
-
-# According to POSIX, $* is only required for inference rules and $<'s
-# value is unspecified outside of inference rules. Strictly speaking
-# we shouldn't be expanding them here but who cares. At least we get
-# to check that the program does nothing stupid (like crash) with them.
-# The C file is named differently from the object file because there
-# was a bug which forced dependencies based on inference rules on all
-# applicable targets (PR 49086).
-obj2.o: obj_2.c obj_2.h dir/obj_1.h
- @printf ${LOCALS}
- @printf ${LOCAL_ALTERNATIVES}
- @printf ${LOCAL_SUBSTITUTIONS}
- @printf ${LOCAL_ALTERNATIVE_SUBSTITUTIONS}
- cc -c -o '${@}' 'obj_2.c'
-
-# Hey, this is make, we can make our own test data setup! obj1.c
-# and obj2.c are not used, so they should not get created. They're here
-# as a bait for a regression into the forced dependencies discussed earlier.
-obj1.c dir/obj_1.c obj2.c obj_2.c obj3.c:
- mkdir -p '${@D}'
- printf '#include "${@F:.c=.h}"\nconst char* ${@F:.c=} = "${@}";\n' \
- >'${@}'
-
-dir/obj_1.h obj_2.h obj3.h dummy dir/dummy:
- mkdir -p '${@D}'
- touch '${@}'
diff --git a/usr.bin/make/unit-tests/qequals.exp b/usr.bin/make/unit-tests/qequals.exp
deleted file mode 100644
index 6b2f4dc..0000000
--- a/usr.bin/make/unit-tests/qequals.exp
+++ /dev/null
@@ -1,2 +0,0 @@
-V.i386 ?= OK
-exit status 0
diff --git a/usr.bin/make/unit-tests/qequals.mk b/usr.bin/make/unit-tests/qequals.mk
deleted file mode 100644
index db6d9c3..0000000
--- a/usr.bin/make/unit-tests/qequals.mk
+++ /dev/null
@@ -1,8 +0,0 @@
-# $Id: qequals.mk,v 1.1 2014/08/21 13:44:51 apb Exp $
-
-M= i386
-V.i386= OK
-V.$M ?= bug
-
-all:
- @echo 'V.$M ?= ${V.$M}'
diff --git a/usr.bin/make/unit-tests/suffixes.exp b/usr.bin/make/unit-tests/suffixes.exp
deleted file mode 100644
index 2a46e1c..0000000
--- a/usr.bin/make/unit-tests/suffixes.exp
+++ /dev/null
@@ -1,35 +0,0 @@
-make: don't know how to make issue3 (continuing)
-There should be no text after the colon:
-touch .a
-There should be no text after the colon:
-touch .a.b
-There should be no text after the colon:
-touch .b.a
-touch issue5a.c
-first set
-cp issue5a.c issue5a.d
-touch issue5b.d
-first set
-cp issue5b.d issue5b.c
-touch issue5c.d
-first set
-cp issue5c.d issue5c
-touch issue5d.d
-first set
-cp issue5d.d issue5d.e
-touch issue5e.e
-first set
-cp issue5e.e issue5e.d
-make: don't know how to make issue6.f (continuing)
-touch issue10.d
-first set
-cp issue10.d issue10.e
-touch issue11.h
-touch issue11.first
-.ALLSRC: issue11.h issue11.first
-cp issue11.h issue11.i
-touch issue11.second
-.ALLSRC: issue11.i issue11.second
-cp issue11.i issue11.j
-`all' not remade because of errors.
-exit status 0
diff --git a/usr.bin/make/unit-tests/suffixes.mk b/usr.bin/make/unit-tests/suffixes.mk
deleted file mode 100644
index 113484a..0000000
--- a/usr.bin/make/unit-tests/suffixes.mk
+++ /dev/null
@@ -1,89 +0,0 @@
-# $NetBSD: suffixes.mk,v 1.3 2014/08/30 22:21:08 sjg Exp $
-
-# Issues from PR 49086
-
-# Issue 3: single suffix rules remain active after .SUFFIXES is cleared
-#
-# There's a rule for issue3.a, but .a is no longer a known suffix when
-# targets are being made, so issue3 should not get made.
-all: issue3
-
-# Issue 4: suffix rules do not become regular rules when .SUFFIXES is cleared
-#
-# When the rules were encountered, .a and .b were known suffices, but later
-# on they were forgotten. These should get created as regular targets.
-all: .a .a.b .b.a
-
-# Issue 5: adding more suffixes does not make existing rules into suffix rules
-#
-# When the targets .c.d, .d.c, .d, .d.e, and .e.d were encountered, only .a,
-# .b and .c were known suffixes, so all of them were regular rules. Later
-# rest of the suffixes were made known, so they should all be suffix
-# transformation rules.
-all: issue5a.d issue5b.c issue5c issue5d.e issue5e.d
-
-# Issue 6: transformation search can end up in an infinite loop
-#
-# There is no file or target from which issue6.f could be made from so
-# this should fail. The bug was that because rules .e.f, .d.e and .e.d
-# exist, make would try to make .f from .e and then infinitely try
-# to do .e from .d and vice versa.
-all: issue6.f
-
-# Issue 10: explicit dependencies affect transformation rule selection
-#
-# If issue10.e is wanted and both issue10.d and issue10.f are available,
-# make should choose the .d.e rule, because .d is before .f in .SUFFIXES.
-# The bug was that if issue10.d had an explicit dependency on issue10.f,
-# it would choose .f.e instead.
-all: issue10.e
-
-# Issue 11: sources from transformation rules are expanded incorrectly
-#
-# issue11.j should depend on issue11.i and issue11.second and issue11.i
-# should depend on issue11.h and issue11.first. The bug was that
-# the dynamic sources were expanded before ${.PREFIX} and ${.TARGET} were
-# available, so they would have expanded to a null string.
-all: issue11.j
-
-# we need to clean for repeatable results
-.BEGIN: clean
-clean:
- @rm -f issue* .[ab]*
-
-.SUFFIXES: .a .b .c
-
-.a .a.b .b.a:
- @echo 'There should be no text after the colon: ${.IMPSRC}'
- touch ${.TARGET}
-
-.c.d .d.c .d .d.e .e.d:
- @echo 'first set'
- cp ${.IMPSRC} ${.TARGET}
-
-.SUFFIXES:
-.SUFFIXES: .c .d .e .f .g
-
-.e .e.f .f.e:
- @echo 'second set'
- cp ${.IMPSRC} ${.TARGET}
-
-issue3.a:
- @echo 'There is a bug if you see this.'
- touch ${.TARGET}
-
-issue5a.c issue5b.d issue5c.d issue5d.d issue5e.e issue10.d issue10.f:
- touch ${.TARGET}
-
-.SUFFIXES: .h .i .j
-
-.h.i: ${.PREFIX}.first
- @echo '.ALLSRC: ${.ALLSRC}'
- cp ${.IMPSRC} ${.TARGET}
-
-.i.j: ${.PREFIX}.second
- @echo '.ALLSRC: ${.ALLSRC}'
- cp ${.IMPSRC} ${.TARGET}
-
-issue11.h issue11.first issue11.second:
- touch ${.TARGET}
diff --git a/usr.bin/make/unit-tests/sunshcmd.exp b/usr.bin/make/unit-tests/sunshcmd.exp
deleted file mode 100644
index b14f6b6..0000000
--- a/usr.bin/make/unit-tests/sunshcmd.exp
+++ /dev/null
@@ -1,4 +0,0 @@
-TEST1=hello
-TEST2=bye
-TEST3=later
-exit status 0
diff --git a/usr.bin/make/unit-tests/sunshcmd.mk b/usr.bin/make/unit-tests/sunshcmd.mk
deleted file mode 100644
index e3baf90..0000000
--- a/usr.bin/make/unit-tests/sunshcmd.mk
+++ /dev/null
@@ -1,10 +0,0 @@
-BYECMD = echo bye
-LATERCMD = echo later
-TEST1 :sh = echo hello
-TEST2 :sh = ${BYECMD}
-TEST3 = ${LATERCMD:sh}
-
-all:
- @echo "TEST1=${TEST1}"
- @echo "TEST2=${TEST2}"
- @echo "TEST3=${TEST3}"
diff --git a/usr.bin/make/unit-tests/sysv.exp b/usr.bin/make/unit-tests/sysv.exp
deleted file mode 100644
index 4cce2de..0000000
--- a/usr.bin/make/unit-tests/sysv.exp
+++ /dev/null
@@ -1,7 +0,0 @@
-FOOBAR =
-FOOBAR = foobar fubar
-fun
-fun
-fun
-In the Sun
-exit status 0
diff --git a/usr.bin/make/unit-tests/sysv.mk b/usr.bin/make/unit-tests/sysv.mk
deleted file mode 100644
index 3651eda..0000000
--- a/usr.bin/make/unit-tests/sysv.mk
+++ /dev/null
@@ -1,26 +0,0 @@
-# $Id: sysv.mk,v 1.2 2014/08/30 22:21:08 sjg Exp $
-
-FOO ?=
-FOOBAR = ${FOO:=bar}
-
-_this := ${.PARSEDIR}/${.PARSEFILE}
-
-B = /b
-S = /
-FUN = ${B}${S}fun
-SUN = the Sun
-
-# we expect nothing when FOO is empty
-all: foo fun
-
-foo:
- @echo FOOBAR = ${FOOBAR}
-.if empty(FOO)
- @FOO="foo fu" ${.MAKE} -f ${_this} foo
-.endif
-
-fun:
- @echo ${FUN:T}
- @echo ${FUN:${B}${S}fun=fun}
- @echo ${FUN:${B}${S}%=%}
- @echo ${In:L:%=% ${SUN}}
diff --git a/usr.bin/make/unit-tests/ternary.exp b/usr.bin/make/unit-tests/ternary.exp
deleted file mode 100644
index ed9c1bd..0000000
--- a/usr.bin/make/unit-tests/ternary.exp
+++ /dev/null
@@ -1,10 +0,0 @@
-The answer is unknown
-The answer is unknown
-The answer is empty
-The answer is known
-The answer is
-The answer is empty
-The answer is known
-The answer is 42
-The answer is 42
-exit status 0
diff --git a/usr.bin/make/unit-tests/ternary.mk b/usr.bin/make/unit-tests/ternary.mk
deleted file mode 100644
index 77f8349..0000000
--- a/usr.bin/make/unit-tests/ternary.mk
+++ /dev/null
@@ -1,8 +0,0 @@
-
-all:
- @for x in "" A= A=42; do ${.MAKE} -f ${MAKEFILE} show $$x; done
-
-show:
- @echo "The answer is ${A:?known:unknown}"
- @echo "The answer is ${A:?$A:unknown}"
- @echo "The answer is ${empty(A):?empty:$A}"
diff --git a/usr.bin/make/unit-tests/unexport-env.exp b/usr.bin/make/unit-tests/unexport-env.exp
deleted file mode 100644
index 6d43cab..0000000
--- a/usr.bin/make/unit-tests/unexport-env.exp
+++ /dev/null
@@ -1,2 +0,0 @@
-UT_TEST=unexport-env
-exit status 0
diff --git a/usr.bin/make/unit-tests/unexport-env.mk b/usr.bin/make/unit-tests/unexport-env.mk
deleted file mode 100644
index b8192f1..0000000
--- a/usr.bin/make/unit-tests/unexport-env.mk
+++ /dev/null
@@ -1,14 +0,0 @@
-# $Id: unexport-env.mk,v 1.1 2014/08/21 13:44:52 apb Exp $
-
-# pick up a bunch of exported vars
-.include "export.mk"
-
-# an example of setting up a minimal environment.
-PATH = /bin:/usr/bin:/sbin:/usr/sbin
-
-# now clobber the environment to just PATH and UT_TEST
-UT_TEST = unexport-env
-
-# this removes everything
-.unexport-env
-.export PATH UT_TEST
diff --git a/usr.bin/make/unit-tests/unexport.exp b/usr.bin/make/unit-tests/unexport.exp
deleted file mode 100644
index 7b16ea3..0000000
--- a/usr.bin/make/unit-tests/unexport.exp
+++ /dev/null
@@ -1,4 +0,0 @@
-UT_DOLLAR=This is $UT_FU
-UT_FU=fubar
-UT_TEST=unexport
-exit status 0
diff --git a/usr.bin/make/unit-tests/unexport.mk b/usr.bin/make/unit-tests/unexport.mk
deleted file mode 100644
index b3d7d34..0000000
--- a/usr.bin/make/unit-tests/unexport.mk
+++ /dev/null
@@ -1,8 +0,0 @@
-# $Id: unexport.mk,v 1.1 2014/08/21 13:44:52 apb Exp $
-
-# pick up a bunch of exported vars
-.include "export.mk"
-
-.unexport UT_ZOO UT_FOO
-
-UT_TEST = unexport
diff --git a/usr.bin/make/unit-tests/varcmd.exp b/usr.bin/make/unit-tests/varcmd.exp
deleted file mode 100644
index 7803c2b..0000000
--- a/usr.bin/make/unit-tests/varcmd.exp
+++ /dev/null
@@ -1,11 +0,0 @@
-default FU=<v>fu</v> FOO=<v>foo</v> VAR=<v></v>
-two FU=<v>bar</v> FOO=<v>goo</v> VAR=<v></v>
-immutable FU='bar'
-immutable FOO='goo'
-three FU=<v>bar</v> FOO=<v>goo</v> VAR=<v></v>
-four FU=<v>bar</v> FOO=<v>goo</v> VAR=<v>Internal</v>
-five FU=<v>bar</v> FOO=<v>goo</v> VAR=<v>Internal</v>
-five v=is x k=is x
-six v=is y k=is y
-show-v v=override k=override
-exit status 0
diff --git a/usr.bin/make/unit-tests/varcmd.mk b/usr.bin/make/unit-tests/varcmd.mk
deleted file mode 100644
index 005ed47..0000000
--- a/usr.bin/make/unit-tests/varcmd.mk
+++ /dev/null
@@ -1,60 +0,0 @@
-# $Id: varcmd.mk,v 1.3 2017/12/08 03:36:42 sjg Exp $
-#
-# Test behaviour of recursive make and vars set on command line.
-
-FU=fu
-FOO?=foo
-.if !empty(.TARGETS)
-TAG=${.TARGETS}
-.endif
-TAG?=default
-
-all: one
-
-show:
- @echo "${TAG} FU=<v>${FU}</v> FOO=<v>${FOO}</v> VAR=<v>${VAR}</v>"
-
-one: show
- @${.MAKE} -f ${MAKEFILE} FU=bar FOO+=goo two
-
-two: show
- @${.MAKE} -f ${MAKEFILE} three
-
-three: show
- @${.MAKE} -f ${MAKEFILE} four
-
-
-.ifmake two
-# this should not work
-FU+= oops
-FOO+= oops
-_FU:= ${FU}
-_FOO:= ${FOO}
-two: immutable
-immutable:
- @echo "$@ FU='${_FU}'"
- @echo "$@ FOO='${_FOO}'"
-.endif
-.ifmake four
-VAR=Internal
-.MAKEOVERRIDES+= VAR
-.endif
-
-four: show
- @${.MAKE} -f ${MAKEFILE} five
-
-M = x
-V.y = is y
-V.x = is x
-V := ${V.$M}
-K := ${V}
-
-show-v:
- @echo '${TAG} v=${V} k=${K}'
-
-five: show show-v
- @${.MAKE} -f ${MAKEFILE} M=y six
-
-six: show-v
- @${.MAKE} -f ${MAKEFILE} V=override show-v
-
diff --git a/usr.bin/make/unit-tests/varmisc.exp b/usr.bin/make/unit-tests/varmisc.exp
deleted file mode 100644
index ffe8f8b..0000000
--- a/usr.bin/make/unit-tests/varmisc.exp
+++ /dev/null
@@ -1,25 +0,0 @@
-
-:D expanded when var set
-true
-TRUE
-:U expanded when var undef
-true
-TRUE
-:D skipped if var undef
-
-:U skipped when var set
-is set
-:? only lhs when value true
-true
-TRUE
-:? only rhs when value false
-false
-FALSE
-do not evaluate or expand :? if discarding
-is set
-year=2016 month=04 day=01
-date=20160401
-Version=123.456.789 == 123456789
-Literal=3.4.5 == 3004005
-We have target specific vars
-exit status 0
diff --git a/usr.bin/make/unit-tests/varmisc.mk b/usr.bin/make/unit-tests/varmisc.mk
deleted file mode 100644
index 34d32cc..0000000
--- a/usr.bin/make/unit-tests/varmisc.mk
+++ /dev/null
@@ -1,62 +0,0 @@
-# $Id: varmisc.mk,v 1.8 2017/01/31 18:56:35 sjg Exp $
-#
-# Miscellaneous variable tests.
-
-all: unmatched_var_paren D_true U_true D_false U_false Q_lhs Q_rhs NQ_none \
- strftime cmpv
-
-unmatched_var_paren:
- @echo ${foo::=foo-text}
-
-True = ${echo true >&2:L:sh}TRUE
-False= ${echo false >&2:L:sh}FALSE
-
-VSET= is set
-.undef UNDEF
-
-U_false:
- @echo :U skipped when var set
- @echo ${VSET:U${False}}
-
-D_false:
- @echo :D skipped if var undef
- @echo ${UNDEF:D${False}}
-
-U_true:
- @echo :U expanded when var undef
- @echo ${UNDEF:U${True}}
-
-D_true:
- @echo :D expanded when var set
- @echo ${VSET:D${True}}
-
-Q_lhs:
- @echo :? only lhs when value true
- @echo ${1:L:?${True}:${False}}
-
-Q_rhs:
- @echo :? only rhs when value false
- @echo ${0:L:?${True}:${False}}
-
-NQ_none:
- @echo do not evaluate or expand :? if discarding
- @echo ${VSET:U${1:L:?${True}:${False}}}
-
-April1= 1459494000
-
-# slightly contorted syntax to use utc via variable
-strftime:
- @echo ${year=%Y month=%m day=%d:L:gmtime=1459494000}
- @echo date=${%Y%m%d:L:${gmtime=${April1}:L}}
-
-# big jumps to handle 3 digits per step
-M_cmpv.units = 1 1000 1000000
-M_cmpv = S,., ,g:_:range:@i@+ $${_:[-$$i]} \* $${M_cmpv.units:[$$i]}@:S,^,expr 0 ,1:sh
-
-Version = 123.456.789
-cmpv.only = target specific vars
-
-cmpv:
- @echo Version=${Version} == ${Version:${M_cmpv}}
- @echo Literal=3.4.5 == ${3.4.5:L:${M_cmpv}}
- @echo We have ${${.TARGET:T}.only}
diff --git a/usr.bin/make/unit-tests/varquote.exp b/usr.bin/make/unit-tests/varquote.exp
deleted file mode 100644
index 63107bf..0000000
--- a/usr.bin/make/unit-tests/varquote.exp
+++ /dev/null
@@ -1,3 +0,0 @@
--fdebug-prefix-map=$NETBSDSRCDIR=/usr/src -fdebug-regex-map=/usr/src/(.*)/obj$=/usr/obj/\1
--fdebug-prefix-map=$NETBSDSRCDIR=/usr/src -fdebug-regex-map=/usr/src/(.*)/obj$=/usr/obj/\1
-exit status 0
diff --git a/usr.bin/make/unit-tests/varquote.mk b/usr.bin/make/unit-tests/varquote.mk
deleted file mode 100644
index fb8b106..0000000
--- a/usr.bin/make/unit-tests/varquote.mk
+++ /dev/null
@@ -1,14 +0,0 @@
-# $NetBSD: varquote.mk,v 1.4 2018/12/16 18:53:34 christos Exp $
-#
-# Test VAR:q modifier
-
-.if !defined(REPROFLAGS)
-REPROFLAGS+= -fdebug-prefix-map=\$$NETBSDSRCDIR=/usr/src
-REPROFLAGS+= -fdebug-regex-map='/usr/src/(.*)/obj$$=/usr/obj/\1'
-all:
- @${MAKE} -f ${MAKEFILE} REPROFLAGS=${REPROFLAGS:S/\$/&&/g:Q}
- @${MAKE} -f ${MAKEFILE} REPROFLAGS=${REPROFLAGS:q}
-.else
-all:
- @printf "%s %s\n" ${REPROFLAGS}
-.endif
diff --git a/usr.bin/make/unit-tests/varshell.exp b/usr.bin/make/unit-tests/varshell.exp
deleted file mode 100644
index 6ac8c88..0000000
--- a/usr.bin/make/unit-tests/varshell.exp
+++ /dev/null
@@ -1,12 +0,0 @@
-sh: /bin/no/such/command: not found
-make: "varshell.mk" line 5: warning: "/bin/no/such/command" returned non-zero status
-make: "varshell.mk" line 6: warning: "kill -14 $$" exited on a signal
-make: "varshell.mk" line 7: warning: "false" returned non-zero status
-make: "varshell.mk" line 8: warning: "echo "output before the error"; false" returned non-zero status
-EXEC_FAILED=''
-TERMINATED_BY_SIGNAL=''
-ERROR_NO_OUTPUT=''
-ERROR_WITH_OUTPUT='output before the error'
-NO_ERROR_NO_OUTPUT=''
-NO_ERROR_WITH_OUTPUT='this is good'
-exit status 0
diff --git a/usr.bin/make/unit-tests/varshell.mk b/usr.bin/make/unit-tests/varshell.mk
deleted file mode 100644
index a006736..0000000
--- a/usr.bin/make/unit-tests/varshell.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-# $Id: varshell.mk,v 1.2 2015/04/10 20:41:59 sjg Exp $
-#
-# Test VAR != shell command
-
-EXEC_FAILED != /bin/no/such/command
-TERMINATED_BY_SIGNAL != kill -14 $$$$
-ERROR_NO_OUTPUT != false
-ERROR_WITH_OUTPUT != echo "output before the error"; false
-NO_ERROR_NO_OUTPUT != true
-NO_ERROR_WITH_OUTPUT != echo "this is good"
-
-allvars= EXEC_FAILED TERMINATED_BY_SIGNAL ERROR_NO_OUTPUT ERROR_WITH_OUTPUT \
- NO_ERROR_NO_OUTPUT NO_ERROR_WITH_OUTPUT
-
-all:
-.for v in ${allvars}
- @echo ${v}=\'${${v}}\'
-.endfor
diff --git a/usr.bin/make/util.c b/usr.bin/make/util.c
deleted file mode 100644
index 506fb4d..0000000
--- a/usr.bin/make/util.c
+++ /dev/null
@@ -1,494 +0,0 @@
-/* $NetBSD: util.c,v 1.54 2013/11/26 13:44:41 joerg Exp $ */
-
-/*
- * Missing stuff from OS's
- */
-#if defined(__MINT__) || defined(__linux__)
-#include <signal.h>
-#endif
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: util.c,v 1.54 2013/11/26 13:44:41 joerg Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-__RCSID("$NetBSD: util.c,v 1.54 2013/11/26 13:44:41 joerg Exp $");
-#endif
-#endif
-
-#include <sys/param.h>
-
-#include <errno.h>
-#include <stdio.h>
-#include <time.h>
-#include <signal.h>
-
-#include "make.h"
-
-#if !defined(MAKE_NATIVE) && !defined(HAVE_STRERROR)
-extern int errno, sys_nerr;
-extern char *sys_errlist[];
-
-char *
-strerror(int e)
-{
- static char buf[100];
- if (e < 0 || e >= sys_nerr) {
- snprintf(buf, sizeof(buf), "Unknown error %d", e);
- return buf;
- }
- else
- return sys_errlist[e];
-}
-#endif
-
-#if !defined(MAKE_NATIVE) && !defined(HAVE_SETENV)
-extern char **environ;
-
-static char *
-findenv(const char *name, int *offset)
-{
- size_t i, len;
- char *p, *q;
-
- len = strlen(name);
- for (i = 0; (q = environ[i]); i++) {
- p = strchr(q, '=');
- if (p == NULL || p - q != len)
- continue;
- if (strncmp(name, q, len) == 0) {
- *offset = i;
- return q + len + 1;
- }
- }
- *offset = i;
- return NULL;
-}
-
-char *
-getenv(const char *name)
-{
- int offset;
-
- return(findenv(name, &offset));
-}
-
-int
-unsetenv(const char *name)
-{
- char **p;
- int offset;
-
- if (name == NULL || *name == '\0' || strchr(name, '=') != NULL) {
- errno = EINVAL;
- return -1;
- }
-
- while (findenv(name, &offset)) { /* if set multiple times */
- for (p = &environ[offset];; ++p)
- if (!(*p = *(p + 1)))
- break;
- }
- return 0;
-}
-
-int
-setenv(const char *name, const char *value, int rewrite)
-{
- char *c, **newenv;
- const char *cc;
- size_t l_value, size;
- int offset;
-
- if (name == NULL || value == NULL) {
- errno = EINVAL;
- return -1;
- }
-
- if (*value == '=') /* no `=' in value */
- ++value;
- l_value = strlen(value);
-
- /* find if already exists */
- if ((c = findenv(name, &offset))) {
- if (!rewrite)
- return 0;
- if (strlen(c) >= l_value) /* old larger; copy over */
- goto copy;
- } else { /* create new slot */
- size = sizeof(char *) * (offset + 2);
- if (savedEnv == environ) { /* just increase size */
- if ((newenv = realloc(savedEnv, size)) == NULL)
- return -1;
- savedEnv = newenv;
- } else { /* get new space */
- /*
- * We don't free here because we don't know if
- * the first allocation is valid on all OS's
- */
- if ((savedEnv = malloc(size)) == NULL)
- return -1;
- (void)memcpy(savedEnv, environ, size - sizeof(char *));
- }
- environ = savedEnv;
- environ[offset + 1] = NULL;
- }
- for (cc = name; *cc && *cc != '='; ++cc) /* no `=' in name */
- continue;
- size = cc - name;
- /* name + `=' + value */
- if ((environ[offset] = malloc(size + l_value + 2)) == NULL)
- return -1;
- c = environ[offset];
- (void)memcpy(c, name, size);
- c += size;
- *c++ = '=';
-copy:
- (void)memcpy(c, value, l_value + 1);
- return 0;
-}
-
-#ifdef TEST
-int
-main(int argc, char *argv[])
-{
- setenv(argv[1], argv[2], 0);
- printf("%s\n", getenv(argv[1]));
- unsetenv(argv[1]);
- printf("%s\n", getenv(argv[1]));
- return 0;
-}
-#endif
-
-#endif
-
-#if defined(__hpux__) || defined(__hpux)
-/* strrcpy():
- * Like strcpy, going backwards and returning the new pointer
- */
-static char *
-strrcpy(char *ptr, char *str)
-{
- int len = strlen(str);
-
- while (len)
- *--ptr = str[--len];
-
- return (ptr);
-} /* end strrcpy */
-
-char *sys_siglist[] = {
- "Signal 0",
- "Hangup", /* SIGHUP */
- "Interrupt", /* SIGINT */
- "Quit", /* SIGQUIT */
- "Illegal instruction", /* SIGILL */
- "Trace/BPT trap", /* SIGTRAP */
- "IOT trap", /* SIGIOT */
- "EMT trap", /* SIGEMT */
- "Floating point exception", /* SIGFPE */
- "Killed", /* SIGKILL */
- "Bus error", /* SIGBUS */
- "Segmentation fault", /* SIGSEGV */
- "Bad system call", /* SIGSYS */
- "Broken pipe", /* SIGPIPE */
- "Alarm clock", /* SIGALRM */
- "Terminated", /* SIGTERM */
- "User defined signal 1", /* SIGUSR1 */
- "User defined signal 2", /* SIGUSR2 */
- "Child exited", /* SIGCLD */
- "Power-fail restart", /* SIGPWR */
- "Virtual timer expired", /* SIGVTALRM */
- "Profiling timer expired", /* SIGPROF */
- "I/O possible", /* SIGIO */
- "Window size changes", /* SIGWINDOW */
- "Stopped (signal)", /* SIGSTOP */
- "Stopped", /* SIGTSTP */
- "Continued", /* SIGCONT */
- "Stopped (tty input)", /* SIGTTIN */
- "Stopped (tty output)", /* SIGTTOU */
- "Urgent I/O condition", /* SIGURG */
- "Remote lock lost (NFS)", /* SIGLOST */
- "Signal 31", /* reserved */
- "DIL signal" /* SIGDIL */
-};
-#endif /* __hpux__ || __hpux */
-
-#if defined(__hpux__) || defined(__hpux)
-#include <sys/types.h>
-#include <sys/syscall.h>
-#include <sys/signal.h>
-#include <sys/stat.h>
-#include <dirent.h>
-#include <sys/time.h>
-#include <unistd.h>
-
-int
-killpg(int pid, int sig)
-{
- return kill(-pid, sig);
-}
-
-#if !defined(__hpux__) && !defined(__hpux)
-void
-srandom(long seed)
-{
- srand48(seed);
-}
-
-long
-random(void)
-{
- return lrand48();
-}
-#endif
-
-#if !defined(__hpux__) && !defined(__hpux)
-int
-utimes(char *file, struct timeval tvp[2])
-{
- struct utimbuf t;
-
- t.actime = tvp[0].tv_sec;
- t.modtime = tvp[1].tv_sec;
- return(utime(file, &t));
-}
-#endif
-
-#if !defined(BSD) && !defined(d_fileno)
-# define d_fileno d_ino
-#endif
-
-#ifndef DEV_DEV_COMPARE
-# define DEV_DEV_COMPARE(a, b) ((a) == (b))
-#endif
-#define ISDOT(c) ((c)[0] == '.' && (((c)[1] == '\0') || ((c)[1] == '/')))
-#define ISDOTDOT(c) ((c)[0] == '.' && ISDOT(&((c)[1])))
-
-char *
-getwd(char *pathname)
-{
- DIR *dp;
- struct dirent *d;
- extern int errno;
-
- struct stat st_root, st_cur, st_next, st_dotdot;
- char pathbuf[MAXPATHLEN], nextpathbuf[MAXPATHLEN * 2];
- char *pathptr, *nextpathptr, *cur_name_add;
-
- /* find the inode of root */
- if (stat("/", &st_root) == -1) {
- (void)sprintf(pathname,
- "getwd: Cannot stat \"/\" (%s)", strerror(errno));
- return NULL;
- }
- pathbuf[MAXPATHLEN - 1] = '\0';
- pathptr = &pathbuf[MAXPATHLEN - 1];
- nextpathbuf[MAXPATHLEN - 1] = '\0';
- cur_name_add = nextpathptr = &nextpathbuf[MAXPATHLEN - 1];
-
- /* find the inode of the current directory */
- if (lstat(".", &st_cur) == -1) {
- (void)sprintf(pathname,
- "getwd: Cannot stat \".\" (%s)", strerror(errno));
- return NULL;
- }
- nextpathptr = strrcpy(nextpathptr, "../");
-
- /* Descend to root */
- for (;;) {
-
- /* look if we found root yet */
- if (st_cur.st_ino == st_root.st_ino &&
- DEV_DEV_COMPARE(st_cur.st_dev, st_root.st_dev)) {
- (void)strcpy(pathname, *pathptr != '/' ? "/" : pathptr);
- return (pathname);
- }
-
- /* open the parent directory */
- if (stat(nextpathptr, &st_dotdot) == -1) {
- (void)sprintf(pathname,
- "getwd: Cannot stat directory \"%s\" (%s)",
- nextpathptr, strerror(errno));
- return NULL;
- }
- if ((dp = opendir(nextpathptr)) == NULL) {
- (void)sprintf(pathname,
- "getwd: Cannot open directory \"%s\" (%s)",
- nextpathptr, strerror(errno));
- return NULL;
- }
-
- /* look in the parent for the entry with the same inode */
- if (DEV_DEV_COMPARE(st_dotdot.st_dev, st_cur.st_dev)) {
- /* Parent has same device. No need to stat every member */
- for (d = readdir(dp); d != NULL; d = readdir(dp))
- if (d->d_fileno == st_cur.st_ino)
- break;
- }
- else {
- /*
- * Parent has a different device. This is a mount point so we
- * need to stat every member
- */
- for (d = readdir(dp); d != NULL; d = readdir(dp)) {
- if (ISDOT(d->d_name) || ISDOTDOT(d->d_name))
- continue;
- (void)strcpy(cur_name_add, d->d_name);
- if (lstat(nextpathptr, &st_next) == -1) {
- (void)sprintf(pathname,
- "getwd: Cannot stat \"%s\" (%s)",
- d->d_name, strerror(errno));
- (void)closedir(dp);
- return NULL;
- }
- /* check if we found it yet */
- if (st_next.st_ino == st_cur.st_ino &&
- DEV_DEV_COMPARE(st_next.st_dev, st_cur.st_dev))
- break;
- }
- }
- if (d == NULL) {
- (void)sprintf(pathname,
- "getwd: Cannot find \".\" in \"..\"");
- (void)closedir(dp);
- return NULL;
- }
- st_cur = st_dotdot;
- pathptr = strrcpy(pathptr, d->d_name);
- pathptr = strrcpy(pathptr, "/");
- nextpathptr = strrcpy(nextpathptr, "../");
- (void)closedir(dp);
- *cur_name_add = '\0';
- }
-} /* end getwd */
-#endif /* __hpux */
-
-/* force posix signals */
-void (*
-bmake_signal(int s, void (*a)(int)))(int)
-{
- struct sigaction sa, osa;
-
- sa.sa_handler = a;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = SA_RESTART;
-
- if (sigaction(s, &sa, &osa) == -1)
- return SIG_ERR;
- else
- return osa.sa_handler;
-}
-
-#if !defined(MAKE_NATIVE) && !defined(HAVE_VSNPRINTF)
-#include <stdarg.h>
-
-#if !defined(__osf__)
-#ifdef _IOSTRG
-#define STRFLAG (_IOSTRG|_IOWRT) /* no _IOWRT: avoid stdio bug */
-#else
-#if 0
-#define STRFLAG (_IOREAD) /* XXX: Assume svr4 stdio */
-#endif
-#endif /* _IOSTRG */
-#endif /* __osf__ */
-
-int
-vsnprintf(char *s, size_t n, const char *fmt, va_list args)
-{
-#ifdef STRFLAG
- FILE fakebuf;
-
- fakebuf._flag = STRFLAG;
- /*
- * Some os's are char * _ptr, others are unsigned char *_ptr...
- * We cast to void * to make everyone happy.
- */
- fakebuf._ptr = (void *)s;
- fakebuf._cnt = n-1;
- fakebuf._file = -1;
- _doprnt(fmt, args, &fakebuf);
- fakebuf._cnt++;
- putc('\0', &fakebuf);
- if (fakebuf._cnt<0)
- fakebuf._cnt = 0;
- return (n-fakebuf._cnt-1);
-#else
- (void)vsprintf(s, fmt, args);
- return strlen(s);
-#endif
-}
-
-int
-snprintf(char *s, size_t n, const char *fmt, ...)
-{
- va_list ap;
- int rv;
-
- va_start(ap, fmt);
- rv = vsnprintf(s, n, fmt, ap);
- va_end(ap);
- return rv;
-}
-
-#if !defined(MAKE_NATIVE) && !defined(HAVE_STRFTIME)
-size_t
-strftime(char *buf, size_t len, const char *fmt, const struct tm *tm)
-{
- static char months[][4] = {
- "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
- };
-
- size_t s;
- char *b = buf;
-
- while (*fmt) {
- if (len == 0)
- return buf - b;
- if (*fmt != '%') {
- *buf++ = *fmt++;
- len--;
- continue;
- }
- switch (*fmt++) {
- case '%':
- *buf++ = '%';
- len--;
- if (len == 0) return buf - b;
- /*FALLTHROUGH*/
- case '\0':
- *buf = '%';
- s = 1;
- break;
- case 'k':
- s = snprintf(buf, len, "%d", tm->tm_hour);
- break;
- case 'M':
- s = snprintf(buf, len, "%02d", tm->tm_min);
- break;
- case 'S':
- s = snprintf(buf, len, "%02d", tm->tm_sec);
- break;
- case 'b':
- if (tm->tm_mon >= 12)
- return buf - b;
- s = snprintf(buf, len, "%s", months[tm->tm_mon]);
- break;
- case 'd':
- s = snprintf(buf, len, "%02d", tm->tm_mday);
- break;
- case 'Y':
- s = snprintf(buf, len, "%d", 1900 + tm->tm_year);
- break;
- default:
- s = snprintf(buf, len, "Unsupported format %c",
- fmt[-1]);
- break;
- }
- buf += s;
- len -= s;
- }
-}
-#endif
-#endif
diff --git a/usr.bin/make/var.c b/usr.bin/make/var.c
deleted file mode 100644
index 547e7fd..0000000
--- a/usr.bin/make/var.c
+++ /dev/null
@@ -1,4355 +0,0 @@
-/* $NetBSD: var.c,v 1.221 2018/12/21 05:50:19 sjg Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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.
- */
-
-/*
- * Copyright (c) 1989 by Berkeley Softworks
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. 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.
- */
-
-#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: var.c,v 1.221 2018/12/21 05:50:19 sjg Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94";
-#else
-__RCSID("$NetBSD: var.c,v 1.221 2018/12/21 05:50:19 sjg Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-/*-
- * var.c --
- * Variable-handling functions
- *
- * Interface:
- * Var_Set Set the value of a variable in the given
- * context. The variable is created if it doesn't
- * yet exist. The value and variable name need not
- * be preserved.
- *
- * Var_Append Append more characters to an existing variable
- * in the given context. The variable needn't
- * exist already -- it will be created if it doesn't.
- * A space is placed between the old value and the
- * new one.
- *
- * Var_Exists See if a variable exists.
- *
- * Var_Value Return the value of a variable in a context or
- * NULL if the variable is undefined.
- *
- * Var_Subst Substitute named variable, or all variables if
- * NULL in a string using
- * the given context as the top-most one. If the
- * third argument is non-zero, Parse_Error is
- * called if any variables are undefined.
- *
- * Var_Parse Parse a variable expansion from a string and
- * return the result and the number of characters
- * consumed.
- *
- * Var_Delete Delete a variable in a context.
- *
- * Var_Init Initialize this module.
- *
- * Debugging:
- * Var_Dump Print out all variables defined in the given
- * context.
- *
- * XXX: There's a lot of duplication in these functions.
- */
-
-#include <sys/stat.h>
-#ifndef NO_REGEX
-#include <sys/types.h>
-#include <regex.h>
-#endif
-#include <ctype.h>
-#include <inttypes.h>
-#include <stdlib.h>
-#include <limits.h>
-#include <time.h>
-
-#include "make.h"
-#include "buf.h"
-#include "dir.h"
-#include "job.h"
-#include "metachar.h"
-
-extern int makelevel;
-/*
- * This lets us tell if we have replaced the original environ
- * (which we cannot free).
- */
-char **savedEnv = NULL;
-
-/*
- * This is a harmless return value for Var_Parse that can be used by Var_Subst
- * to determine if there was an error in parsing -- easier than returning
- * a flag, as things outside this module don't give a hoot.
- */
-char var_Error[] = "";
-
-/*
- * Similar to var_Error, but returned when the 'VARF_UNDEFERR' flag for
- * Var_Parse is not set. Why not just use a constant? Well, gcc likes
- * to condense identical string instances...
- */
-static char varNoError[] = "";
-
-/*
- * Traditionally we consume $$ during := like any other expansion.
- * Other make's do not.
- * This knob allows controlling the behavior.
- * FALSE for old behavior.
- * TRUE for new compatible.
- */
-#define SAVE_DOLLARS ".MAKE.SAVE_DOLLARS"
-static Boolean save_dollars = TRUE;
-
-/*
- * Internally, variables are contained in four different contexts.
- * 1) the environment. They may not be changed. If an environment
- * variable is appended-to, the result is placed in the global
- * context.
- * 2) the global context. Variables set in the Makefile are located in
- * the global context. It is the penultimate context searched when
- * substituting.
- * 3) the command-line context. All variables set on the command line
- * are placed in this context. They are UNALTERABLE once placed here.
- * 4) the local context. Each target has associated with it a context
- * list. On this list are located the structures describing such
- * local variables as $(@) and $(*)
- * The four contexts are searched in the reverse order from which they are
- * listed.
- */
-GNode *VAR_INTERNAL; /* variables from make itself */
-GNode *VAR_GLOBAL; /* variables from the makefile */
-GNode *VAR_CMD; /* variables defined on the command-line */
-
-#define FIND_CMD 0x1 /* look in VAR_CMD when searching */
-#define FIND_GLOBAL 0x2 /* look in VAR_GLOBAL as well */
-#define FIND_ENV 0x4 /* look in the environment also */
-
-typedef struct Var {
- char *name; /* the variable's name */
- Buffer val; /* its value */
- int flags; /* miscellaneous status flags */
-#define VAR_IN_USE 1 /* Variable's value currently being used.
- * Used to avoid recursion */
-#define VAR_FROM_ENV 2 /* Variable comes from the environment */
-#define VAR_JUNK 4 /* Variable is a junk variable that
- * should be destroyed when done with
- * it. Used by Var_Parse for undefined,
- * modified variables */
-#define VAR_KEEP 8 /* Variable is VAR_JUNK, but we found
- * a use for it in some modifier and
- * the value is therefore valid */
-#define VAR_EXPORTED 16 /* Variable is exported */
-#define VAR_REEXPORT 32 /* Indicate if var needs re-export.
- * This would be true if it contains $'s
- */
-#define VAR_FROM_CMD 64 /* Variable came from command line */
-} Var;
-
-/*
- * Exporting vars is expensive so skip it if we can
- */
-#define VAR_EXPORTED_NONE 0
-#define VAR_EXPORTED_YES 1
-#define VAR_EXPORTED_ALL 2
-static int var_exportedVars = VAR_EXPORTED_NONE;
-/*
- * We pass this to Var_Export when doing the initial export
- * or after updating an exported var.
- */
-#define VAR_EXPORT_PARENT 1
-/*
- * We pass this to Var_Export1 to tell it to leave the value alone.
- */
-#define VAR_EXPORT_LITERAL 2
-
-/* Var*Pattern flags */
-#define VAR_SUB_GLOBAL 0x01 /* Apply substitution globally */
-#define VAR_SUB_ONE 0x02 /* Apply substitution to one word */
-#define VAR_SUB_MATCHED 0x04 /* There was a match */
-#define VAR_MATCH_START 0x08 /* Match at start of word */
-#define VAR_MATCH_END 0x10 /* Match at end of word */
-#define VAR_NOSUBST 0x20 /* don't expand vars in VarGetPattern */
-
-/* Var_Set flags */
-#define VAR_NO_EXPORT 0x01 /* do not export */
-
-typedef struct {
- /*
- * The following fields are set by Var_Parse() when it
- * encounters modifiers that need to keep state for use by
- * subsequent modifiers within the same variable expansion.
- */
- Byte varSpace; /* Word separator in expansions */
- Boolean oneBigWord; /* TRUE if we will treat the variable as a
- * single big word, even if it contains
- * embedded spaces (as opposed to the
- * usual behaviour of treating it as
- * several space-separated words). */
-} Var_Parse_State;
-
-/* struct passed as 'void *' to VarSubstitute() for ":S/lhs/rhs/",
- * to VarSYSVMatch() for ":lhs=rhs". */
-typedef struct {
- const char *lhs; /* String to match */
- int leftLen; /* Length of string */
- const char *rhs; /* Replacement string (w/ &'s removed) */
- int rightLen; /* Length of replacement */
- int flags;
-} VarPattern;
-
-/* struct passed as 'void *' to VarLoopExpand() for ":@tvar@str@" */
-typedef struct {
- GNode *ctxt; /* variable context */
- char *tvar; /* name of temp var */
- int tvarLen;
- char *str; /* string to expand */
- int strLen;
- int errnum; /* errnum for not defined */
-} VarLoop_t;
-
-#ifndef NO_REGEX
-/* struct passed as 'void *' to VarRESubstitute() for ":C///" */
-typedef struct {
- regex_t re;
- int nsub;
- regmatch_t *matches;
- char *replace;
- int flags;
-} VarREPattern;
-#endif
-
-/* struct passed to VarSelectWords() for ":[start..end]" */
-typedef struct {
- int start; /* first word to select */
- int end; /* last word to select */
-} VarSelectWords_t;
-
-static Var *VarFind(const char *, GNode *, int);
-static void VarAdd(const char *, const char *, GNode *);
-static Boolean VarHead(GNode *, Var_Parse_State *,
- char *, Boolean, Buffer *, void *);
-static Boolean VarTail(GNode *, Var_Parse_State *,
- char *, Boolean, Buffer *, void *);
-static Boolean VarSuffix(GNode *, Var_Parse_State *,
- char *, Boolean, Buffer *, void *);
-static Boolean VarRoot(GNode *, Var_Parse_State *,
- char *, Boolean, Buffer *, void *);
-static Boolean VarMatch(GNode *, Var_Parse_State *,
- char *, Boolean, Buffer *, void *);
-#ifdef SYSVVARSUB
-static Boolean VarSYSVMatch(GNode *, Var_Parse_State *,
- char *, Boolean, Buffer *, void *);
-#endif
-static Boolean VarNoMatch(GNode *, Var_Parse_State *,
- char *, Boolean, Buffer *, void *);
-#ifndef NO_REGEX
-static void VarREError(int, regex_t *, const char *);
-static Boolean VarRESubstitute(GNode *, Var_Parse_State *,
- char *, Boolean, Buffer *, void *);
-#endif
-static Boolean VarSubstitute(GNode *, Var_Parse_State *,
- char *, Boolean, Buffer *, void *);
-static Boolean VarLoopExpand(GNode *, Var_Parse_State *,
- char *, Boolean, Buffer *, void *);
-static char *VarGetPattern(GNode *, Var_Parse_State *,
- int, const char **, int, int *, int *,
- VarPattern *);
-static char *VarQuote(char *, Boolean);
-static char *VarHash(char *);
-static char *VarModify(GNode *, Var_Parse_State *,
- const char *,
- Boolean (*)(GNode *, Var_Parse_State *, char *, Boolean, Buffer *, void *),
- void *);
-static char *VarOrder(const char *, const char);
-static char *VarUniq(const char *);
-static int VarWordCompare(const void *, const void *);
-static void VarPrintVar(void *);
-
-#define BROPEN '{'
-#define BRCLOSE '}'
-#define PROPEN '('
-#define PRCLOSE ')'
-
-/*-
- *-----------------------------------------------------------------------
- * VarFind --
- * Find the given variable in the given context and any other contexts
- * indicated.
- *
- * Input:
- * name name to find
- * ctxt context in which to find it
- * flags FIND_GLOBAL set means to look in the
- * VAR_GLOBAL context as well. FIND_CMD set means
- * to look in the VAR_CMD context also. FIND_ENV
- * set means to look in the environment
- *
- * Results:
- * A pointer to the structure describing the desired variable or
- * NULL if the variable does not exist.
- *
- * Side Effects:
- * None
- *-----------------------------------------------------------------------
- */
-static Var *
-VarFind(const char *name, GNode *ctxt, int flags)
-{
- Hash_Entry *var;
- Var *v;
-
- /*
- * If the variable name begins with a '.', it could very well be one of
- * the local ones. We check the name against all the local variables
- * and substitute the short version in for 'name' if it matches one of
- * them.
- */
- if (*name == '.' && isupper((unsigned char) name[1]))
- switch (name[1]) {
- case 'A':
- if (!strcmp(name, ".ALLSRC"))
- name = ALLSRC;
- if (!strcmp(name, ".ARCHIVE"))
- name = ARCHIVE;
- break;
- case 'I':
- if (!strcmp(name, ".IMPSRC"))
- name = IMPSRC;
- break;
- case 'M':
- if (!strcmp(name, ".MEMBER"))
- name = MEMBER;
- break;
- case 'O':
- if (!strcmp(name, ".OODATE"))
- name = OODATE;
- break;
- case 'P':
- if (!strcmp(name, ".PREFIX"))
- name = PREFIX;
- break;
- case 'T':
- if (!strcmp(name, ".TARGET"))
- name = TARGET;
- break;
- }
-#ifdef notyet
- /* for compatibility with gmake */
- if (name[0] == '^' && name[1] == '\0')
- name = ALLSRC;
-#endif
-
- /*
- * First look for the variable in the given context. If it's not there,
- * look for it in VAR_CMD, VAR_GLOBAL and the environment, in that order,
- * depending on the FIND_* flags in 'flags'
- */
- var = Hash_FindEntry(&ctxt->context, name);
-
- if ((var == NULL) && (flags & FIND_CMD) && (ctxt != VAR_CMD)) {
- var = Hash_FindEntry(&VAR_CMD->context, name);
- }
- if (!checkEnvFirst && (var == NULL) && (flags & FIND_GLOBAL) &&
- (ctxt != VAR_GLOBAL))
- {
- var = Hash_FindEntry(&VAR_GLOBAL->context, name);
- if ((var == NULL) && (ctxt != VAR_INTERNAL)) {
- /* VAR_INTERNAL is subordinate to VAR_GLOBAL */
- var = Hash_FindEntry(&VAR_INTERNAL->context, name);
- }
- }
- if ((var == NULL) && (flags & FIND_ENV)) {
- char *env;
-
- if ((env = getenv(name)) != NULL) {
- int len;
-
- v = bmake_malloc(sizeof(Var));
- v->name = bmake_strdup(name);
-
- len = strlen(env);
-
- Buf_Init(&v->val, len + 1);
- Buf_AddBytes(&v->val, len, env);
-
- v->flags = VAR_FROM_ENV;
- return (v);
- } else if (checkEnvFirst && (flags & FIND_GLOBAL) &&
- (ctxt != VAR_GLOBAL))
- {
- var = Hash_FindEntry(&VAR_GLOBAL->context, name);
- if ((var == NULL) && (ctxt != VAR_INTERNAL)) {
- var = Hash_FindEntry(&VAR_INTERNAL->context, name);
- }
- if (var == NULL) {
- return NULL;
- } else {
- return ((Var *)Hash_GetValue(var));
- }
- } else {
- return NULL;
- }
- } else if (var == NULL) {
- return NULL;
- } else {
- return ((Var *)Hash_GetValue(var));
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * VarFreeEnv --
- * If the variable is an environment variable, free it
- *
- * Input:
- * v the variable
- * destroy true if the value buffer should be destroyed.
- *
- * Results:
- * 1 if it is an environment variable 0 ow.
- *
- * Side Effects:
- * The variable is free'ed if it is an environent variable.
- *-----------------------------------------------------------------------
- */
-static Boolean
-VarFreeEnv(Var *v, Boolean destroy)
-{
- if ((v->flags & VAR_FROM_ENV) == 0)
- return FALSE;
- free(v->name);
- Buf_Destroy(&v->val, destroy);
- free(v);
- return TRUE;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * VarAdd --
- * Add a new variable of name name and value val to the given context
- *
- * Input:
- * name name of variable to add
- * val value to set it to
- * ctxt context in which to set it
- *
- * Results:
- * None
- *
- * Side Effects:
- * The new variable is placed at the front of the given context
- * The name and val arguments are duplicated so they may
- * safely be freed.
- *-----------------------------------------------------------------------
- */
-static void
-VarAdd(const char *name, const char *val, GNode *ctxt)
-{
- Var *v;
- int len;
- Hash_Entry *h;
-
- v = bmake_malloc(sizeof(Var));
-
- len = val ? strlen(val) : 0;
- Buf_Init(&v->val, len+1);
- Buf_AddBytes(&v->val, len, val);
-
- v->flags = 0;
-
- h = Hash_CreateEntry(&ctxt->context, name, NULL);
- Hash_SetValue(h, v);
- v->name = h->name;
- if (DEBUG(VAR) && (ctxt->flags & INTERNAL) == 0) {
- fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, val);
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Var_Delete --
- * Remove a variable from a context.
- *
- * Results:
- * None.
- *
- * Side Effects:
- * The Var structure is removed and freed.
- *
- *-----------------------------------------------------------------------
- */
-void
-Var_Delete(const char *name, GNode *ctxt)
-{
- Hash_Entry *ln;
- char *cp;
-
- if (strchr(name, '$')) {
- cp = Var_Subst(NULL, name, VAR_GLOBAL, VARF_WANTRES);
- } else {
- cp = (char *)name;
- }
- ln = Hash_FindEntry(&ctxt->context, cp);
- if (DEBUG(VAR)) {
- fprintf(debug_file, "%s:delete %s%s\n",
- ctxt->name, cp, ln ? "" : " (not found)");
- }
- if (cp != name) {
- free(cp);
- }
- if (ln != NULL) {
- Var *v;
-
- v = (Var *)Hash_GetValue(ln);
- if ((v->flags & VAR_EXPORTED)) {
- unsetenv(v->name);
- }
- if (strcmp(MAKE_EXPORTED, v->name) == 0) {
- var_exportedVars = VAR_EXPORTED_NONE;
- }
- if (v->name != ln->name)
- free(v->name);
- Hash_DeleteEntry(&ctxt->context, ln);
- Buf_Destroy(&v->val, TRUE);
- free(v);
- }
-}
-
-
-/*
- * Export a var.
- * We ignore make internal variables (those which start with '.')
- * Also we jump through some hoops to avoid calling setenv
- * more than necessary since it can leak.
- * We only manipulate flags of vars if 'parent' is set.
- */
-static int
-Var_Export1(const char *name, int flags)
-{
- char tmp[BUFSIZ];
- Var *v;
- char *val = NULL;
- int n;
- int parent = (flags & VAR_EXPORT_PARENT);
-
- if (*name == '.')
- return 0; /* skip internals */
- if (!name[1]) {
- /*
- * A single char.
- * If it is one of the vars that should only appear in
- * local context, skip it, else we can get Var_Subst
- * into a loop.
- */
- switch (name[0]) {
- case '@':
- case '%':
- case '*':
- case '!':
- return 0;
- }
- }
- v = VarFind(name, VAR_GLOBAL, 0);
- if (v == NULL) {
- return 0;
- }
- if (!parent &&
- (v->flags & (VAR_EXPORTED|VAR_REEXPORT)) == VAR_EXPORTED) {
- return 0; /* nothing to do */
- }
- val = Buf_GetAll(&v->val, NULL);
- if ((flags & VAR_EXPORT_LITERAL) == 0 && strchr(val, '$')) {
- if (parent) {
- /*
- * Flag this as something we need to re-export.
- * No point actually exporting it now though,
- * the child can do it at the last minute.
- */
- v->flags |= (VAR_EXPORTED|VAR_REEXPORT);
- return 1;
- }
- if (v->flags & VAR_IN_USE) {
- /*
- * We recursed while exporting in a child.
- * This isn't going to end well, just skip it.
- */
- return 0;
- }
- n = snprintf(tmp, sizeof(tmp), "${%s}", name);
- if (n < (int)sizeof(tmp)) {
- val = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES);
- setenv(name, val, 1);
- free(val);
- }
- } else {
- if (parent) {
- v->flags &= ~VAR_REEXPORT; /* once will do */
- }
- if (parent || !(v->flags & VAR_EXPORTED)) {
- setenv(name, val, 1);
- }
- }
- /*
- * This is so Var_Set knows to call Var_Export again...
- */
- if (parent) {
- v->flags |= VAR_EXPORTED;
- }
- return 1;
-}
-
-/*
- * This gets called from our children.
- */
-void
-Var_ExportVars(void)
-{
- char tmp[BUFSIZ];
- Hash_Entry *var;
- Hash_Search state;
- Var *v;
- char *val;
- int n;
-
- /*
- * Several make's support this sort of mechanism for tracking
- * recursion - but each uses a different name.
- * We allow the makefiles to update MAKELEVEL and ensure
- * children see a correctly incremented value.
- */
- snprintf(tmp, sizeof(tmp), "%d", makelevel + 1);
- setenv(MAKE_LEVEL_ENV, tmp, 1);
-
- if (VAR_EXPORTED_NONE == var_exportedVars)
- return;
-
- if (VAR_EXPORTED_ALL == var_exportedVars) {
- /*
- * Ouch! This is crazy...
- */
- for (var = Hash_EnumFirst(&VAR_GLOBAL->context, &state);
- var != NULL;
- var = Hash_EnumNext(&state)) {
- v = (Var *)Hash_GetValue(var);
- Var_Export1(v->name, 0);
- }
- return;
- }
- /*
- * We have a number of exported vars,
- */
- n = snprintf(tmp, sizeof(tmp), "${" MAKE_EXPORTED ":O:u}");
- if (n < (int)sizeof(tmp)) {
- char **av;
- char *as;
- int ac;
- int i;
-
- val = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES);
- if (*val) {
- av = brk_string(val, &ac, FALSE, &as);
- for (i = 0; i < ac; i++) {
- Var_Export1(av[i], 0);
- }
- free(as);
- free(av);
- }
- free(val);
- }
-}
-
-/*
- * This is called when .export is seen or
- * .MAKE.EXPORTED is modified.
- * It is also called when any exported var is modified.
- */
-void
-Var_Export(char *str, int isExport)
-{
- char *name;
- char *val;
- char **av;
- char *as;
- int flags;
- int ac;
- int i;
-
- if (isExport && (!str || !str[0])) {
- var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */
- return;
- }
-
- flags = 0;
- if (strncmp(str, "-env", 4) == 0) {
- str += 4;
- } else if (strncmp(str, "-literal", 8) == 0) {
- str += 8;
- flags |= VAR_EXPORT_LITERAL;
- } else {
- flags |= VAR_EXPORT_PARENT;
- }
- val = Var_Subst(NULL, str, VAR_GLOBAL, VARF_WANTRES);
- if (*val) {
- av = brk_string(val, &ac, FALSE, &as);
- for (i = 0; i < ac; i++) {
- name = av[i];
- if (!name[1]) {
- /*
- * A single char.
- * If it is one of the vars that should only appear in
- * local context, skip it, else we can get Var_Subst
- * into a loop.
- */
- switch (name[0]) {
- case '@':
- case '%':
- case '*':
- case '!':
- continue;
- }
- }
- if (Var_Export1(name, flags)) {
- if (VAR_EXPORTED_ALL != var_exportedVars)
- var_exportedVars = VAR_EXPORTED_YES;
- if (isExport && (flags & VAR_EXPORT_PARENT)) {
- Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL);
- }
- }
- }
- free(as);
- free(av);
- }
- free(val);
-}
-
-
-/*
- * This is called when .unexport[-env] is seen.
- */
-extern char **environ;
-
-void
-Var_UnExport(char *str)
-{
- char tmp[BUFSIZ];
- char *vlist;
- char *cp;
- Boolean unexport_env;
- int n;
-
- if (!str || !str[0]) {
- return; /* assert? */
- }
-
- vlist = NULL;
-
- str += 8;
- unexport_env = (strncmp(str, "-env", 4) == 0);
- if (unexport_env) {
- char **newenv;
-
- cp = getenv(MAKE_LEVEL_ENV); /* we should preserve this */
- if (environ == savedEnv) {
- /* we have been here before! */
- newenv = bmake_realloc(environ, 2 * sizeof(char *));
- } else {
- if (savedEnv) {
- free(savedEnv);
- savedEnv = NULL;
- }
- newenv = bmake_malloc(2 * sizeof(char *));
- }
- if (!newenv)
- return;
- /* Note: we cannot safely free() the original environ. */
- environ = savedEnv = newenv;
- newenv[0] = NULL;
- newenv[1] = NULL;
- if (cp && *cp)
- setenv(MAKE_LEVEL_ENV, cp, 1);
- } else {
- for (; *str != '\n' && isspace((unsigned char) *str); str++)
- continue;
- if (str[0] && str[0] != '\n') {
- vlist = str;
- }
- }
-
- if (!vlist) {
- /* Using .MAKE.EXPORTED */
- n = snprintf(tmp, sizeof(tmp), "${" MAKE_EXPORTED ":O:u}");
- if (n < (int)sizeof(tmp)) {
- vlist = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES);
- }
- }
- if (vlist) {
- Var *v;
- char **av;
- char *as;
- int ac;
- int i;
-
- av = brk_string(vlist, &ac, FALSE, &as);
- for (i = 0; i < ac; i++) {
- v = VarFind(av[i], VAR_GLOBAL, 0);
- if (!v)
- continue;
- if (!unexport_env &&
- (v->flags & (VAR_EXPORTED|VAR_REEXPORT)) == VAR_EXPORTED) {
- unsetenv(v->name);
- }
- v->flags &= ~(VAR_EXPORTED|VAR_REEXPORT);
- /*
- * If we are unexporting a list,
- * remove each one from .MAKE.EXPORTED.
- * If we are removing them all,
- * just delete .MAKE.EXPORTED below.
- */
- if (vlist == str) {
- n = snprintf(tmp, sizeof(tmp),
- "${" MAKE_EXPORTED ":N%s}", v->name);
- if (n < (int)sizeof(tmp)) {
- cp = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES);
- Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL, 0);
- free(cp);
- }
- }
- }
- free(as);
- free(av);
- if (vlist != str) {
- Var_Delete(MAKE_EXPORTED, VAR_GLOBAL);
- free(vlist);
- }
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Var_Set --
- * Set the variable name to the value val in the given context.
- *
- * Input:
- * name name of variable to set
- * val value to give to the variable
- * ctxt context in which to set it
- *
- * Results:
- * None.
- *
- * Side Effects:
- * If the variable doesn't yet exist, a new record is created for it.
- * Else the old value is freed and the new one stuck in its place
- *
- * Notes:
- * The variable is searched for only in its context before being
- * created in that context. I.e. if the context is VAR_GLOBAL,
- * only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMD, only
- * VAR_CMD->context is searched. This is done to avoid the literally
- * thousands of unnecessary strcmp's that used to be done to
- * set, say, $(@) or $(<).
- * If the context is VAR_GLOBAL though, we check if the variable
- * was set in VAR_CMD from the command line and skip it if so.
- *-----------------------------------------------------------------------
- */
-void
-Var_Set(const char *name, const char *val, GNode *ctxt, int flags)
-{
- Var *v;
- char *expanded_name = NULL;
-
- /*
- * We only look for a variable in the given context since anything set
- * here will override anything in a lower context, so there's not much
- * point in searching them all just to save a bit of memory...
- */
- if (strchr(name, '$') != NULL) {
- expanded_name = Var_Subst(NULL, name, ctxt, VARF_WANTRES);
- if (expanded_name[0] == 0) {
- if (DEBUG(VAR)) {
- fprintf(debug_file, "Var_Set(\"%s\", \"%s\", ...) "
- "name expands to empty string - ignored\n",
- name, val);
- }
- free(expanded_name);
- return;
- }
- name = expanded_name;
- }
- if (ctxt == VAR_GLOBAL) {
- v = VarFind(name, VAR_CMD, 0);
- if (v != NULL) {
- if ((v->flags & VAR_FROM_CMD)) {
- if (DEBUG(VAR)) {
- fprintf(debug_file, "%s:%s = %s ignored!\n", ctxt->name, name, val);
- }
- goto out;
- }
- VarFreeEnv(v, TRUE);
- }
- }
- v = VarFind(name, ctxt, 0);
- if (v == NULL) {
- if (ctxt == VAR_CMD && (flags & VAR_NO_EXPORT) == 0) {
- /*
- * This var would normally prevent the same name being added
- * to VAR_GLOBAL, so delete it from there if needed.
- * Otherwise -V name may show the wrong value.
- */
- Var_Delete(name, VAR_GLOBAL);
- }
- VarAdd(name, val, ctxt);
- } else {
- Buf_Empty(&v->val);
- if (val)
- Buf_AddBytes(&v->val, strlen(val), val);
-
- if (DEBUG(VAR)) {
- fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, val);
- }
- if ((v->flags & VAR_EXPORTED)) {
- Var_Export1(name, VAR_EXPORT_PARENT);
- }
- }
- /*
- * Any variables given on the command line are automatically exported
- * to the environment (as per POSIX standard)
- */
- if (ctxt == VAR_CMD && (flags & VAR_NO_EXPORT) == 0) {
- if (v == NULL) {
- /* we just added it */
- v = VarFind(name, ctxt, 0);
- }
- if (v != NULL)
- v->flags |= VAR_FROM_CMD;
- /*
- * If requested, don't export these in the environment
- * individually. We still put them in MAKEOVERRIDES so
- * that the command-line settings continue to override
- * Makefile settings.
- */
- if (varNoExportEnv != TRUE)
- setenv(name, val ? val : "", 1);
-
- Var_Append(MAKEOVERRIDES, name, VAR_GLOBAL);
- }
- if (*name == '.') {
- if (strcmp(name, SAVE_DOLLARS) == 0)
- save_dollars = s2Boolean(val, save_dollars);
- }
-
- out:
- free(expanded_name);
- if (v != NULL)
- VarFreeEnv(v, TRUE);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Var_Append --
- * The variable of the given name has the given value appended to it in
- * the given context.
- *
- * Input:
- * name name of variable to modify
- * val String to append to it
- * ctxt Context in which this should occur
- *
- * Results:
- * None
- *
- * Side Effects:
- * If the variable doesn't exist, it is created. Else the strings
- * are concatenated (with a space in between).
- *
- * Notes:
- * Only if the variable is being sought in the global context is the
- * environment searched.
- * XXX: Knows its calling circumstances in that if called with ctxt
- * an actual target, it will only search that context since only
- * a local variable could be being appended to. This is actually
- * a big win and must be tolerated.
- *-----------------------------------------------------------------------
- */
-void
-Var_Append(const char *name, const char *val, GNode *ctxt)
-{
- Var *v;
- Hash_Entry *h;
- char *expanded_name = NULL;
-
- if (strchr(name, '$') != NULL) {
- expanded_name = Var_Subst(NULL, name, ctxt, VARF_WANTRES);
- if (expanded_name[0] == 0) {
- if (DEBUG(VAR)) {
- fprintf(debug_file, "Var_Append(\"%s\", \"%s\", ...) "
- "name expands to empty string - ignored\n",
- name, val);
- }
- free(expanded_name);
- return;
- }
- name = expanded_name;
- }
-
- v = VarFind(name, ctxt, (ctxt == VAR_GLOBAL) ? (FIND_CMD|FIND_ENV) : 0);
-
- if (v == NULL) {
- Var_Set(name, val, ctxt, 0);
- } else if (ctxt == VAR_CMD || !(v->flags & VAR_FROM_CMD)) {
- Buf_AddByte(&v->val, ' ');
- Buf_AddBytes(&v->val, strlen(val), val);
-
- if (DEBUG(VAR)) {
- fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name,
- Buf_GetAll(&v->val, NULL));
- }
-
- if (v->flags & VAR_FROM_ENV) {
- /*
- * If the original variable came from the environment, we
- * have to install it in the global context (we could place
- * it in the environment, but then we should provide a way to
- * export other variables...)
- */
- v->flags &= ~VAR_FROM_ENV;
- h = Hash_CreateEntry(&ctxt->context, name, NULL);
- Hash_SetValue(h, v);
- }
- }
- free(expanded_name);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Var_Exists --
- * See if the given variable exists.
- *
- * Input:
- * name Variable to find
- * ctxt Context in which to start search
- *
- * Results:
- * TRUE if it does, FALSE if it doesn't
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-Boolean
-Var_Exists(const char *name, GNode *ctxt)
-{
- Var *v;
- char *cp;
-
- if ((cp = strchr(name, '$')) != NULL) {
- cp = Var_Subst(NULL, name, ctxt, VARF_WANTRES);
- }
- v = VarFind(cp ? cp : name, ctxt, FIND_CMD|FIND_GLOBAL|FIND_ENV);
- free(cp);
- if (v == NULL) {
- return(FALSE);
- } else {
- (void)VarFreeEnv(v, TRUE);
- }
- return(TRUE);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Var_Value --
- * Return the value of the named variable in the given context
- *
- * Input:
- * name name to find
- * ctxt context in which to search for it
- *
- * Results:
- * The value if the variable exists, NULL if it doesn't
- *
- * Side Effects:
- * None
- *-----------------------------------------------------------------------
- */
-char *
-Var_Value(const char *name, GNode *ctxt, char **frp)
-{
- Var *v;
-
- v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
- *frp = NULL;
- if (v != NULL) {
- char *p = (Buf_GetAll(&v->val, NULL));
- if (VarFreeEnv(v, FALSE))
- *frp = p;
- return p;
- } else {
- return NULL;
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * VarHead --
- * Remove the tail of the given word and place the result in the given
- * buffer.
- *
- * Input:
- * word Word to trim
- * addSpace True if need to add a space to the buffer
- * before sticking in the head
- * buf Buffer in which to store it
- *
- * Results:
- * TRUE if characters were added to the buffer (a space needs to be
- * added to the buffer before the next word).
- *
- * Side Effects:
- * The trimmed word is added to the buffer.
- *
- *-----------------------------------------------------------------------
- */
-static Boolean
-VarHead(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
- char *word, Boolean addSpace, Buffer *buf,
- void *dummy MAKE_ATTR_UNUSED)
-{
- char *slash;
-
- slash = strrchr(word, '/');
- if (slash != NULL) {
- if (addSpace && vpstate->varSpace) {
- Buf_AddByte(buf, vpstate->varSpace);
- }
- *slash = '\0';
- Buf_AddBytes(buf, strlen(word), word);
- *slash = '/';
- return (TRUE);
- } else {
- /*
- * If no directory part, give . (q.v. the POSIX standard)
- */
- if (addSpace && vpstate->varSpace)
- Buf_AddByte(buf, vpstate->varSpace);
- Buf_AddByte(buf, '.');
- }
- return TRUE;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * VarTail --
- * Remove the head of the given word and place the result in the given
- * buffer.
- *
- * Input:
- * word Word to trim
- * addSpace True if need to add a space to the buffer
- * before adding the tail
- * buf Buffer in which to store it
- *
- * Results:
- * TRUE if characters were added to the buffer (a space needs to be
- * added to the buffer before the next word).
- *
- * Side Effects:
- * The trimmed word is added to the buffer.
- *
- *-----------------------------------------------------------------------
- */
-static Boolean
-VarTail(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
- char *word, Boolean addSpace, Buffer *buf,
- void *dummy MAKE_ATTR_UNUSED)
-{
- char *slash;
-
- if (addSpace && vpstate->varSpace) {
- Buf_AddByte(buf, vpstate->varSpace);
- }
-
- slash = strrchr(word, '/');
- if (slash != NULL) {
- *slash++ = '\0';
- Buf_AddBytes(buf, strlen(slash), slash);
- slash[-1] = '/';
- } else {
- Buf_AddBytes(buf, strlen(word), word);
- }
- return TRUE;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * VarSuffix --
- * Place the suffix of the given word in the given buffer.
- *
- * Input:
- * word Word to trim
- * addSpace TRUE if need to add a space before placing the
- * suffix in the buffer
- * buf Buffer in which to store it
- *
- * Results:
- * TRUE if characters were added to the buffer (a space needs to be
- * added to the buffer before the next word).
- *
- * Side Effects:
- * The suffix from the word is placed in the buffer.
- *
- *-----------------------------------------------------------------------
- */
-static Boolean
-VarSuffix(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
- char *word, Boolean addSpace, Buffer *buf,
- void *dummy MAKE_ATTR_UNUSED)
-{
- char *dot;
-
- dot = strrchr(word, '.');
- if (dot != NULL) {
- if (addSpace && vpstate->varSpace) {
- Buf_AddByte(buf, vpstate->varSpace);
- }
- *dot++ = '\0';
- Buf_AddBytes(buf, strlen(dot), dot);
- dot[-1] = '.';
- addSpace = TRUE;
- }
- return addSpace;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * VarRoot --
- * Remove the suffix of the given word and place the result in the
- * buffer.
- *
- * Input:
- * word Word to trim
- * addSpace TRUE if need to add a space to the buffer
- * before placing the root in it
- * buf Buffer in which to store it
- *
- * Results:
- * TRUE if characters were added to the buffer (a space needs to be
- * added to the buffer before the next word).
- *
- * Side Effects:
- * The trimmed word is added to the buffer.
- *
- *-----------------------------------------------------------------------
- */
-static Boolean
-VarRoot(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
- char *word, Boolean addSpace, Buffer *buf,
- void *dummy MAKE_ATTR_UNUSED)
-{
- char *dot;
-
- if (addSpace && vpstate->varSpace) {
- Buf_AddByte(buf, vpstate->varSpace);
- }
-
- dot = strrchr(word, '.');
- if (dot != NULL) {
- *dot = '\0';
- Buf_AddBytes(buf, strlen(word), word);
- *dot = '.';
- } else {
- Buf_AddBytes(buf, strlen(word), word);
- }
- return TRUE;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * VarMatch --
- * Place the word in the buffer if it matches the given pattern.
- * Callback function for VarModify to implement the :M modifier.
- *
- * Input:
- * word Word to examine
- * addSpace TRUE if need to add a space to the buffer
- * before adding the word, if it matches
- * buf Buffer in which to store it
- * pattern Pattern the word must match
- *
- * Results:
- * TRUE if a space should be placed in the buffer before the next
- * word.
- *
- * Side Effects:
- * The word may be copied to the buffer.
- *
- *-----------------------------------------------------------------------
- */
-static Boolean
-VarMatch(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
- char *word, Boolean addSpace, Buffer *buf,
- void *pattern)
-{
- if (DEBUG(VAR))
- fprintf(debug_file, "VarMatch [%s] [%s]\n", word, (char *)pattern);
- if (Str_Match(word, (char *)pattern)) {
- if (addSpace && vpstate->varSpace) {
- Buf_AddByte(buf, vpstate->varSpace);
- }
- addSpace = TRUE;
- Buf_AddBytes(buf, strlen(word), word);
- }
- return(addSpace);
-}
-
-#ifdef SYSVVARSUB
-/*-
- *-----------------------------------------------------------------------
- * VarSYSVMatch --
- * Place the word in the buffer if it matches the given pattern.
- * Callback function for VarModify to implement the System V %
- * modifiers.
- *
- * Input:
- * word Word to examine
- * addSpace TRUE if need to add a space to the buffer
- * before adding the word, if it matches
- * buf Buffer in which to store it
- * patp Pattern the word must match
- *
- * Results:
- * TRUE if a space should be placed in the buffer before the next
- * word.
- *
- * Side Effects:
- * The word may be copied to the buffer.
- *
- *-----------------------------------------------------------------------
- */
-static Boolean
-VarSYSVMatch(GNode *ctx, Var_Parse_State *vpstate,
- char *word, Boolean addSpace, Buffer *buf,
- void *patp)
-{
- int len;
- char *ptr;
- VarPattern *pat = (VarPattern *)patp;
- char *varexp;
-
- if (addSpace && vpstate->varSpace)
- Buf_AddByte(buf, vpstate->varSpace);
-
- addSpace = TRUE;
-
- if ((ptr = Str_SYSVMatch(word, pat->lhs, &len)) != NULL) {
- varexp = Var_Subst(NULL, pat->rhs, ctx, VARF_WANTRES);
- Str_SYSVSubst(buf, varexp, ptr, len);
- free(varexp);
- } else {
- Buf_AddBytes(buf, strlen(word), word);
- }
-
- return(addSpace);
-}
-#endif
-
-
-/*-
- *-----------------------------------------------------------------------
- * VarNoMatch --
- * Place the word in the buffer if it doesn't match the given pattern.
- * Callback function for VarModify to implement the :N modifier.
- *
- * Input:
- * word Word to examine
- * addSpace TRUE if need to add a space to the buffer
- * before adding the word, if it matches
- * buf Buffer in which to store it
- * pattern Pattern the word must match
- *
- * Results:
- * TRUE if a space should be placed in the buffer before the next
- * word.
- *
- * Side Effects:
- * The word may be copied to the buffer.
- *
- *-----------------------------------------------------------------------
- */
-static Boolean
-VarNoMatch(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
- char *word, Boolean addSpace, Buffer *buf,
- void *pattern)
-{
- if (!Str_Match(word, (char *)pattern)) {
- if (addSpace && vpstate->varSpace) {
- Buf_AddByte(buf, vpstate->varSpace);
- }
- addSpace = TRUE;
- Buf_AddBytes(buf, strlen(word), word);
- }
- return(addSpace);
-}
-
-
-/*-
- *-----------------------------------------------------------------------
- * VarSubstitute --
- * Perform a string-substitution on the given word, placing the
- * result in the passed buffer.
- *
- * Input:
- * word Word to modify
- * addSpace True if space should be added before
- * other characters
- * buf Buffer for result
- * patternp Pattern for substitution
- *
- * Results:
- * TRUE if a space is needed before more characters are added.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-static Boolean
-VarSubstitute(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
- char *word, Boolean addSpace, Buffer *buf,
- void *patternp)
-{
- int wordLen; /* Length of word */
- char *cp; /* General pointer */
- VarPattern *pattern = (VarPattern *)patternp;
-
- wordLen = strlen(word);
- if ((pattern->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) !=
- (VAR_SUB_ONE|VAR_SUB_MATCHED)) {
- /*
- * Still substituting -- break it down into simple anchored cases
- * and if none of them fits, perform the general substitution case.
- */
- if ((pattern->flags & VAR_MATCH_START) &&
- (strncmp(word, pattern->lhs, pattern->leftLen) == 0)) {
- /*
- * Anchored at start and beginning of word matches pattern
- */
- if ((pattern->flags & VAR_MATCH_END) &&
- (wordLen == pattern->leftLen)) {
- /*
- * Also anchored at end and matches to the end (word
- * is same length as pattern) add space and rhs only
- * if rhs is non-null.
- */
- if (pattern->rightLen != 0) {
- if (addSpace && vpstate->varSpace) {
- Buf_AddByte(buf, vpstate->varSpace);
- }
- addSpace = TRUE;
- Buf_AddBytes(buf, pattern->rightLen, pattern->rhs);
- }
- pattern->flags |= VAR_SUB_MATCHED;
- } else if (pattern->flags & VAR_MATCH_END) {
- /*
- * Doesn't match to end -- copy word wholesale
- */
- goto nosub;
- } else {
- /*
- * Matches at start but need to copy in trailing characters
- */
- if ((pattern->rightLen + wordLen - pattern->leftLen) != 0){
- if (addSpace && vpstate->varSpace) {
- Buf_AddByte(buf, vpstate->varSpace);
- }
- addSpace = TRUE;
- }
- Buf_AddBytes(buf, pattern->rightLen, pattern->rhs);
- Buf_AddBytes(buf, wordLen - pattern->leftLen,
- (word + pattern->leftLen));
- pattern->flags |= VAR_SUB_MATCHED;
- }
- } else if (pattern->flags & VAR_MATCH_START) {
- /*
- * Had to match at start of word and didn't -- copy whole word.
- */
- goto nosub;
- } else if (pattern->flags & VAR_MATCH_END) {
- /*
- * Anchored at end, Find only place match could occur (leftLen
- * characters from the end of the word) and see if it does. Note
- * that because the $ will be left at the end of the lhs, we have
- * to use strncmp.
- */
- cp = word + (wordLen - pattern->leftLen);
- if ((cp >= word) &&
- (strncmp(cp, pattern->lhs, pattern->leftLen) == 0)) {
- /*
- * Match found. If we will place characters in the buffer,
- * add a space before hand as indicated by addSpace, then
- * stuff in the initial, unmatched part of the word followed
- * by the right-hand-side.
- */
- if (((cp - word) + pattern->rightLen) != 0) {
- if (addSpace && vpstate->varSpace) {
- Buf_AddByte(buf, vpstate->varSpace);
- }
- addSpace = TRUE;
- }
- Buf_AddBytes(buf, cp - word, word);
- Buf_AddBytes(buf, pattern->rightLen, pattern->rhs);
- pattern->flags |= VAR_SUB_MATCHED;
- } else {
- /*
- * Had to match at end and didn't. Copy entire word.
- */
- goto nosub;
- }
- } else {
- /*
- * Pattern is unanchored: search for the pattern in the word using
- * String_FindSubstring, copying unmatched portions and the
- * right-hand-side for each match found, handling non-global
- * substitutions correctly, etc. When the loop is done, any
- * remaining part of the word (word and wordLen are adjusted
- * accordingly through the loop) is copied straight into the
- * buffer.
- * addSpace is set FALSE as soon as a space is added to the
- * buffer.
- */
- Boolean done;
- int origSize;
-
- done = FALSE;
- origSize = Buf_Size(buf);
- while (!done) {
- cp = Str_FindSubstring(word, pattern->lhs);
- if (cp != NULL) {
- if (addSpace && (((cp - word) + pattern->rightLen) != 0)){
- Buf_AddByte(buf, vpstate->varSpace);
- addSpace = FALSE;
- }
- Buf_AddBytes(buf, cp-word, word);
- Buf_AddBytes(buf, pattern->rightLen, pattern->rhs);
- wordLen -= (cp - word) + pattern->leftLen;
- word = cp + pattern->leftLen;
- if (wordLen == 0) {
- done = TRUE;
- }
- if ((pattern->flags & VAR_SUB_GLOBAL) == 0) {
- done = TRUE;
- }
- pattern->flags |= VAR_SUB_MATCHED;
- } else {
- done = TRUE;
- }
- }
- if (wordLen != 0) {
- if (addSpace && vpstate->varSpace) {
- Buf_AddByte(buf, vpstate->varSpace);
- }
- Buf_AddBytes(buf, wordLen, word);
- }
- /*
- * If added characters to the buffer, need to add a space
- * before we add any more. If we didn't add any, just return
- * the previous value of addSpace.
- */
- return ((Buf_Size(buf) != origSize) || addSpace);
- }
- return (addSpace);
- }
- nosub:
- if (addSpace && vpstate->varSpace) {
- Buf_AddByte(buf, vpstate->varSpace);
- }
- Buf_AddBytes(buf, wordLen, word);
- return(TRUE);
-}
-
-#ifndef NO_REGEX
-/*-
- *-----------------------------------------------------------------------
- * VarREError --
- * Print the error caused by a regcomp or regexec call.
- *
- * Results:
- * None.
- *
- * Side Effects:
- * An error gets printed.
- *
- *-----------------------------------------------------------------------
- */
-static void
-VarREError(int reerr, regex_t *pat, const char *str)
-{
- char *errbuf;
- int errlen;
-
- errlen = regerror(reerr, pat, 0, 0);
- errbuf = bmake_malloc(errlen);
- regerror(reerr, pat, errbuf, errlen);
- Error("%s: %s", str, errbuf);
- free(errbuf);
-}
-
-
-/*-
- *-----------------------------------------------------------------------
- * VarRESubstitute --
- * Perform a regex substitution on the given word, placing the
- * result in the passed buffer.
- *
- * Results:
- * TRUE if a space is needed before more characters are added.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-static Boolean
-VarRESubstitute(GNode *ctx MAKE_ATTR_UNUSED,
- Var_Parse_State *vpstate MAKE_ATTR_UNUSED,
- char *word, Boolean addSpace, Buffer *buf,
- void *patternp)
-{
- VarREPattern *pat;
- int xrv;
- char *wp;
- char *rp;
- int added;
- int flags = 0;
-
-#define MAYBE_ADD_SPACE() \
- if (addSpace && !added) \
- Buf_AddByte(buf, ' '); \
- added = 1
-
- added = 0;
- wp = word;
- pat = patternp;
-
- if ((pat->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) ==
- (VAR_SUB_ONE|VAR_SUB_MATCHED))
- xrv = REG_NOMATCH;
- else {
- tryagain:
- xrv = regexec(&pat->re, wp, pat->nsub, pat->matches, flags);
- }
-
- switch (xrv) {
- case 0:
- pat->flags |= VAR_SUB_MATCHED;
- if (pat->matches[0].rm_so > 0) {
- MAYBE_ADD_SPACE();
- Buf_AddBytes(buf, pat->matches[0].rm_so, wp);
- }
-
- for (rp = pat->replace; *rp; rp++) {
- if ((*rp == '\\') && ((rp[1] == '&') || (rp[1] == '\\'))) {
- MAYBE_ADD_SPACE();
- Buf_AddByte(buf,rp[1]);
- rp++;
- }
- else if ((*rp == '&') ||
- ((*rp == '\\') && isdigit((unsigned char)rp[1]))) {
- int n;
- const char *subbuf;
- int sublen;
- char errstr[3];
-
- if (*rp == '&') {
- n = 0;
- errstr[0] = '&';
- errstr[1] = '\0';
- } else {
- n = rp[1] - '0';
- errstr[0] = '\\';
- errstr[1] = rp[1];
- errstr[2] = '\0';
- rp++;
- }
-
- if (n > pat->nsub) {
- Error("No subexpression %s", &errstr[0]);
- subbuf = "";
- sublen = 0;
- } else if ((pat->matches[n].rm_so == -1) &&
- (pat->matches[n].rm_eo == -1)) {
- Error("No match for subexpression %s", &errstr[0]);
- subbuf = "";
- sublen = 0;
- } else {
- subbuf = wp + pat->matches[n].rm_so;
- sublen = pat->matches[n].rm_eo - pat->matches[n].rm_so;
- }
-
- if (sublen > 0) {
- MAYBE_ADD_SPACE();
- Buf_AddBytes(buf, sublen, subbuf);
- }
- } else {
- MAYBE_ADD_SPACE();
- Buf_AddByte(buf, *rp);
- }
- }
- wp += pat->matches[0].rm_eo;
- if (pat->flags & VAR_SUB_GLOBAL) {
- flags |= REG_NOTBOL;
- if (pat->matches[0].rm_so == 0 && pat->matches[0].rm_eo == 0) {
- MAYBE_ADD_SPACE();
- Buf_AddByte(buf, *wp);
- wp++;
-
- }
- if (*wp)
- goto tryagain;
- }
- if (*wp) {
- MAYBE_ADD_SPACE();
- Buf_AddBytes(buf, strlen(wp), wp);
- }
- break;
- default:
- VarREError(xrv, &pat->re, "Unexpected regex error");
- /* fall through */
- case REG_NOMATCH:
- if (*wp) {
- MAYBE_ADD_SPACE();
- Buf_AddBytes(buf,strlen(wp),wp);
- }
- break;
- }
- return(addSpace||added);
-}
-#endif
-
-
-
-/*-
- *-----------------------------------------------------------------------
- * VarLoopExpand --
- * Implements the :@<temp>@<string>@ modifier of ODE make.
- * We set the temp variable named in pattern.lhs to word and expand
- * pattern.rhs storing the result in the passed buffer.
- *
- * Input:
- * word Word to modify
- * addSpace True if space should be added before
- * other characters
- * buf Buffer for result
- * pattern Datafor substitution
- *
- * Results:
- * TRUE if a space is needed before more characters are added.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-static Boolean
-VarLoopExpand(GNode *ctx MAKE_ATTR_UNUSED,
- Var_Parse_State *vpstate MAKE_ATTR_UNUSED,
- char *word, Boolean addSpace, Buffer *buf,
- void *loopp)
-{
- VarLoop_t *loop = (VarLoop_t *)loopp;
- char *s;
- int slen;
-
- if (word && *word) {
- Var_Set(loop->tvar, word, loop->ctxt, VAR_NO_EXPORT);
- s = Var_Subst(NULL, loop->str, loop->ctxt, loop->errnum | VARF_WANTRES);
- if (s != NULL && *s != '\0') {
- if (addSpace && *s != '\n')
- Buf_AddByte(buf, ' ');
- Buf_AddBytes(buf, (slen = strlen(s)), s);
- addSpace = (slen > 0 && s[slen - 1] != '\n');
- }
- free(s);
- }
- return addSpace;
-}
-
-
-/*-
- *-----------------------------------------------------------------------
- * VarSelectWords --
- * Implements the :[start..end] modifier.
- * This is a special case of VarModify since we want to be able
- * to scan the list backwards if start > end.
- *
- * Input:
- * str String whose words should be trimmed
- * seldata words to select
- *
- * Results:
- * A string of all the words selected.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-static char *
-VarSelectWords(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
- const char *str, VarSelectWords_t *seldata)
-{
- Buffer buf; /* Buffer for the new string */
- Boolean addSpace; /* TRUE if need to add a space to the
- * buffer before adding the trimmed
- * word */
- char **av; /* word list */
- char *as; /* word list memory */
- int ac, i;
- int start, end, step;
-
- Buf_Init(&buf, 0);
- addSpace = FALSE;
-
- if (vpstate->oneBigWord) {
- /* fake what brk_string() would do if there were only one word */
- ac = 1;
- av = bmake_malloc((ac + 1) * sizeof(char *));
- as = bmake_strdup(str);
- av[0] = as;
- av[1] = NULL;
- } else {
- av = brk_string(str, &ac, FALSE, &as);
- }
-
- /*
- * Now sanitize seldata.
- * If seldata->start or seldata->end are negative, convert them to
- * the positive equivalents (-1 gets converted to argc, -2 gets
- * converted to (argc-1), etc.).
- */
- if (seldata->start < 0)
- seldata->start = ac + seldata->start + 1;
- if (seldata->end < 0)
- seldata->end = ac + seldata->end + 1;
-
- /*
- * We avoid scanning more of the list than we need to.
- */
- if (seldata->start > seldata->end) {
- start = MIN(ac, seldata->start) - 1;
- end = MAX(0, seldata->end - 1);
- step = -1;
- } else {
- start = MAX(0, seldata->start - 1);
- end = MIN(ac, seldata->end);
- step = 1;
- }
-
- for (i = start;
- (step < 0 && i >= end) || (step > 0 && i < end);
- i += step) {
- if (av[i] && *av[i]) {
- if (addSpace && vpstate->varSpace) {
- Buf_AddByte(&buf, vpstate->varSpace);
- }
- Buf_AddBytes(&buf, strlen(av[i]), av[i]);
- addSpace = TRUE;
- }
- }
-
- free(as);
- free(av);
-
- return Buf_Destroy(&buf, FALSE);
-}
-
-
-/*-
- * VarRealpath --
- * Replace each word with the result of realpath()
- * if successful.
- */
-static Boolean
-VarRealpath(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
- char *word, Boolean addSpace, Buffer *buf,
- void *patternp MAKE_ATTR_UNUSED)
-{
- struct stat st;
- char rbuf[MAXPATHLEN];
- char *rp;
-
- if (addSpace && vpstate->varSpace) {
- Buf_AddByte(buf, vpstate->varSpace);
- }
- addSpace = TRUE;
- rp = cached_realpath(word, rbuf);
- if (rp && *rp == '/' && stat(rp, &st) == 0)
- word = rp;
-
- Buf_AddBytes(buf, strlen(word), word);
- return(addSpace);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * VarModify --
- * Modify each of the words of the passed string using the given
- * function. Used to implement all modifiers.
- *
- * Input:
- * str String whose words should be trimmed
- * modProc Function to use to modify them
- * datum Datum to pass it
- *
- * Results:
- * A string of all the words modified appropriately.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-static char *
-VarModify(GNode *ctx, Var_Parse_State *vpstate,
- const char *str,
- Boolean (*modProc)(GNode *, Var_Parse_State *, char *,
- Boolean, Buffer *, void *),
- void *datum)
-{
- Buffer buf; /* Buffer for the new string */
- Boolean addSpace; /* TRUE if need to add a space to the
- * buffer before adding the trimmed
- * word */
- char **av; /* word list */
- char *as; /* word list memory */
- int ac, i;
-
- Buf_Init(&buf, 0);
- addSpace = FALSE;
-
- if (vpstate->oneBigWord) {
- /* fake what brk_string() would do if there were only one word */
- ac = 1;
- av = bmake_malloc((ac + 1) * sizeof(char *));
- as = bmake_strdup(str);
- av[0] = as;
- av[1] = NULL;
- } else {
- av = brk_string(str, &ac, FALSE, &as);
- }
-
- for (i = 0; i < ac; i++) {
- addSpace = (*modProc)(ctx, vpstate, av[i], addSpace, &buf, datum);
- }
-
- free(as);
- free(av);
-
- return Buf_Destroy(&buf, FALSE);
-}
-
-
-static int
-VarWordCompare(const void *a, const void *b)
-{
- int r = strcmp(*(const char * const *)a, *(const char * const *)b);
- return r;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * VarOrder --
- * Order the words in the string.
- *
- * Input:
- * str String whose words should be sorted.
- * otype How to order: s - sort, x - random.
- *
- * Results:
- * A string containing the words ordered.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-static char *
-VarOrder(const char *str, const char otype)
-{
- Buffer buf; /* Buffer for the new string */
- char **av; /* word list [first word does not count] */
- char *as; /* word list memory */
- int ac, i;
-
- Buf_Init(&buf, 0);
-
- av = brk_string(str, &ac, FALSE, &as);
-
- if (ac > 0)
- switch (otype) {
- case 's': /* sort alphabetically */
- qsort(av, ac, sizeof(char *), VarWordCompare);
- break;
- case 'x': /* randomize */
- {
- int rndidx;
- char *t;
-
- /*
- * We will use [ac..2] range for mod factors. This will produce
- * random numbers in [(ac-1)..0] interval, and minimal
- * reasonable value for mod factor is 2 (the mod 1 will produce
- * 0 with probability 1).
- */
- for (i = ac-1; i > 0; i--) {
- rndidx = random() % (i + 1);
- if (i != rndidx) {
- t = av[i];
- av[i] = av[rndidx];
- av[rndidx] = t;
- }
- }
- }
- } /* end of switch */
-
- for (i = 0; i < ac; i++) {
- Buf_AddBytes(&buf, strlen(av[i]), av[i]);
- if (i != ac - 1)
- Buf_AddByte(&buf, ' ');
- }
-
- free(as);
- free(av);
-
- return Buf_Destroy(&buf, FALSE);
-}
-
-
-/*-
- *-----------------------------------------------------------------------
- * VarUniq --
- * Remove adjacent duplicate words.
- *
- * Input:
- * str String whose words should be sorted
- *
- * Results:
- * A string containing the resulting words.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-static char *
-VarUniq(const char *str)
-{
- Buffer buf; /* Buffer for new string */
- char **av; /* List of words to affect */
- char *as; /* Word list memory */
- int ac, i, j;
-
- Buf_Init(&buf, 0);
- av = brk_string(str, &ac, FALSE, &as);
-
- if (ac > 1) {
- for (j = 0, i = 1; i < ac; i++)
- if (strcmp(av[i], av[j]) != 0 && (++j != i))
- av[j] = av[i];
- ac = j + 1;
- }
-
- for (i = 0; i < ac; i++) {
- Buf_AddBytes(&buf, strlen(av[i]), av[i]);
- if (i != ac - 1)
- Buf_AddByte(&buf, ' ');
- }
-
- free(as);
- free(av);
-
- return Buf_Destroy(&buf, FALSE);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * VarRange --
- * Return an integer sequence
- *
- * Input:
- * str String whose words provide default range
- * ac range length, if 0 use str words
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-static char *
-VarRange(const char *str, int ac)
-{
- Buffer buf; /* Buffer for new string */
- char tmp[32]; /* each element */
- char **av; /* List of words to affect */
- char *as; /* Word list memory */
- int i, n;
-
- Buf_Init(&buf, 0);
- if (ac > 0) {
- as = NULL;
- av = NULL;
- } else {
- av = brk_string(str, &ac, FALSE, &as);
- }
- for (i = 0; i < ac; i++) {
- n = snprintf(tmp, sizeof(tmp), "%d", 1 + i);
- if (n >= (int)sizeof(tmp))
- break;
- Buf_AddBytes(&buf, n, tmp);
- if (i != ac - 1)
- Buf_AddByte(&buf, ' ');
- }
-
- free(as);
- free(av);
-
- return Buf_Destroy(&buf, FALSE);
-}
-
-
-/*-
- *-----------------------------------------------------------------------
- * VarGetPattern --
- * Pass through the tstr looking for 1) escaped delimiters,
- * '$'s and backslashes (place the escaped character in
- * uninterpreted) and 2) unescaped $'s that aren't before
- * the delimiter (expand the variable substitution unless flags
- * has VAR_NOSUBST set).
- * Return the expanded string or NULL if the delimiter was missing
- * If pattern is specified, handle escaped ampersands, and replace
- * unescaped ampersands with the lhs of the pattern.
- *
- * Results:
- * A string of all the words modified appropriately.
- * If length is specified, return the string length of the buffer
- * If flags is specified and the last character of the pattern is a
- * $ set the VAR_MATCH_END bit of flags.
- *
- * Side Effects:
- * None.
- *-----------------------------------------------------------------------
- */
-static char *
-VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate MAKE_ATTR_UNUSED,
- int flags, const char **tstr, int delim, int *vflags,
- int *length, VarPattern *pattern)
-{
- const char *cp;
- char *rstr;
- Buffer buf;
- int junk;
- int errnum = flags & VARF_UNDEFERR;
-
- Buf_Init(&buf, 0);
- if (length == NULL)
- length = &junk;
-
-#define IS_A_MATCH(cp, delim) \
- ((cp[0] == '\\') && ((cp[1] == delim) || \
- (cp[1] == '\\') || (cp[1] == '$') || (pattern && (cp[1] == '&'))))
-
- /*
- * Skim through until the matching delimiter is found;
- * pick up variable substitutions on the way. Also allow
- * backslashes to quote the delimiter, $, and \, but don't
- * touch other backslashes.
- */
- for (cp = *tstr; *cp && (*cp != delim); cp++) {
- if (IS_A_MATCH(cp, delim)) {
- Buf_AddByte(&buf, cp[1]);
- cp++;
- } else if (*cp == '$') {
- if (cp[1] == delim) {
- if (vflags == NULL)
- Buf_AddByte(&buf, *cp);
- else
- /*
- * Unescaped $ at end of pattern => anchor
- * pattern at end.
- */
- *vflags |= VAR_MATCH_END;
- } else {
- if (vflags == NULL || (*vflags & VAR_NOSUBST) == 0) {
- char *cp2;
- int len;
- void *freeIt;
-
- /*
- * If unescaped dollar sign not before the
- * delimiter, assume it's a variable
- * substitution and recurse.
- */
- cp2 = Var_Parse(cp, ctxt, errnum | VARF_WANTRES, &len,
- &freeIt);
- Buf_AddBytes(&buf, strlen(cp2), cp2);
- free(freeIt);
- cp += len - 1;
- } else {
- const char *cp2 = &cp[1];
-
- if (*cp2 == PROPEN || *cp2 == BROPEN) {
- /*
- * Find the end of this variable reference
- * and suck it in without further ado.
- * It will be interperated later.
- */
- int have = *cp2;
- int want = (*cp2 == PROPEN) ? PRCLOSE : BRCLOSE;
- int depth = 1;
-
- for (++cp2; *cp2 != '\0' && depth > 0; ++cp2) {
- if (cp2[-1] != '\\') {
- if (*cp2 == have)
- ++depth;
- if (*cp2 == want)
- --depth;
- }
- }
- Buf_AddBytes(&buf, cp2 - cp, cp);
- cp = --cp2;
- } else
- Buf_AddByte(&buf, *cp);
- }
- }
- }
- else if (pattern && *cp == '&')
- Buf_AddBytes(&buf, pattern->leftLen, pattern->lhs);
- else
- Buf_AddByte(&buf, *cp);
- }
-
- if (*cp != delim) {
- *tstr = cp;
- *length = 0;
- return NULL;
- }
-
- *tstr = ++cp;
- *length = Buf_Size(&buf);
- rstr = Buf_Destroy(&buf, FALSE);
- if (DEBUG(VAR))
- fprintf(debug_file, "Modifier pattern: \"%s\"\n", rstr);
- return rstr;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * VarQuote --
- * Quote shell meta-characters and space characters in the string
- * if quoteDollar is set, also quote and double any '$' characters.
- *
- * Results:
- * The quoted string
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-static char *
-VarQuote(char *str, Boolean quoteDollar)
-{
-
- Buffer buf;
- const char *newline;
- size_t nlen;
-
- if ((newline = Shell_GetNewline()) == NULL)
- newline = "\\\n";
- nlen = strlen(newline);
-
- Buf_Init(&buf, 0);
-
- for (; *str != '\0'; str++) {
- if (*str == '\n') {
- Buf_AddBytes(&buf, nlen, newline);
- continue;
- }
- if (isspace((unsigned char)*str) || ismeta((unsigned char)*str))
- Buf_AddByte(&buf, '\\');
- Buf_AddByte(&buf, *str);
- if (quoteDollar && *str == '$')
- Buf_AddBytes(&buf, 2, "\\$");
- }
-
- str = Buf_Destroy(&buf, FALSE);
- if (DEBUG(VAR))
- fprintf(debug_file, "QuoteMeta: [%s]\n", str);
- return str;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * VarHash --
- * Hash the string using the MurmurHash3 algorithm.
- * Output is computed using 32bit Little Endian arithmetic.
- *
- * Input:
- * str String to modify
- *
- * Results:
- * Hash value of str, encoded as 8 hex digits.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-static char *
-VarHash(char *str)
-{
- static const char hexdigits[16] = "0123456789abcdef";
- Buffer buf;
- size_t len, len2;
- unsigned char *ustr = (unsigned char *)str;
- uint32_t h, k, c1, c2;
-
- h = 0x971e137bU;
- c1 = 0x95543787U;
- c2 = 0x2ad7eb25U;
- len2 = strlen(str);
-
- for (len = len2; len; ) {
- k = 0;
- switch (len) {
- default:
- k = (ustr[3] << 24) | (ustr[2] << 16) | (ustr[1] << 8) | ustr[0];
- len -= 4;
- ustr += 4;
- break;
- case 3:
- k |= (ustr[2] << 16);
- case 2:
- k |= (ustr[1] << 8);
- case 1:
- k |= ustr[0];
- len = 0;
- }
- c1 = c1 * 5 + 0x7b7d159cU;
- c2 = c2 * 5 + 0x6bce6396U;
- k *= c1;
- k = (k << 11) ^ (k >> 21);
- k *= c2;
- h = (h << 13) ^ (h >> 19);
- h = h * 5 + 0x52dce729U;
- h ^= k;
- }
- h ^= len2;
- h *= 0x85ebca6b;
- h ^= h >> 13;
- h *= 0xc2b2ae35;
- h ^= h >> 16;
-
- Buf_Init(&buf, 0);
- for (len = 0; len < 8; ++len) {
- Buf_AddByte(&buf, hexdigits[h & 15]);
- h >>= 4;
- }
-
- return Buf_Destroy(&buf, FALSE);
-}
-
-static char *
-VarStrftime(const char *fmt, int zulu, time_t utc)
-{
- char buf[BUFSIZ];
-
- if (!utc)
- time(&utc);
- if (!*fmt)
- fmt = "%c";
- strftime(buf, sizeof(buf), fmt, zulu ? gmtime(&utc) : localtime(&utc));
-
- buf[sizeof(buf) - 1] = '\0';
- return bmake_strdup(buf);
-}
-
-/*
- * Now we need to apply any modifiers the user wants applied.
- * These are:
- * :M<pattern> words which match the given <pattern>.
- * <pattern> is of the standard file
- * wildcarding form.
- * :N<pattern> words which do not match the given <pattern>.
- * :S<d><pat1><d><pat2><d>[1gW]
- * Substitute <pat2> for <pat1> in the value
- * :C<d><pat1><d><pat2><d>[1gW]
- * Substitute <pat2> for regex <pat1> in the value
- * :H Substitute the head of each word
- * :T Substitute the tail of each word
- * :E Substitute the extension (minus '.') of
- * each word
- * :R Substitute the root of each word
- * (pathname minus the suffix).
- * :O ("Order") Alphabeticaly sort words in variable.
- * :Ox ("intermiX") Randomize words in variable.
- * :u ("uniq") Remove adjacent duplicate words.
- * :tu Converts the variable contents to uppercase.
- * :tl Converts the variable contents to lowercase.
- * :ts[c] Sets varSpace - the char used to
- * separate words to 'c'. If 'c' is
- * omitted then no separation is used.
- * :tW Treat the variable contents as a single
- * word, even if it contains spaces.
- * (Mnemonic: one big 'W'ord.)
- * :tw Treat the variable contents as multiple
- * space-separated words.
- * (Mnemonic: many small 'w'ords.)
- * :[index] Select a single word from the value.
- * :[start..end] Select multiple words from the value.
- * :[*] or :[0] Select the entire value, as a single
- * word. Equivalent to :tW.
- * :[@] Select the entire value, as multiple
- * words. Undoes the effect of :[*].
- * Equivalent to :tw.
- * :[#] Returns the number of words in the value.
- *
- * :?<true-value>:<false-value>
- * If the variable evaluates to true, return
- * true value, else return the second value.
- * :lhs=rhs Like :S, but the rhs goes to the end of
- * the invocation.
- * :sh Treat the current value as a command
- * to be run, new value is its output.
- * The following added so we can handle ODE makefiles.
- * :@<tmpvar>@<newval>@
- * Assign a temporary local variable <tmpvar>
- * to the current value of each word in turn
- * and replace each word with the result of
- * evaluating <newval>
- * :D<newval> Use <newval> as value if variable defined
- * :U<newval> Use <newval> as value if variable undefined
- * :L Use the name of the variable as the value.
- * :P Use the path of the node that has the same
- * name as the variable as the value. This
- * basically includes an implied :L so that
- * the common method of refering to the path
- * of your dependent 'x' in a rule is to use
- * the form '${x:P}'.
- * :!<cmd>! Run cmd much the same as :sh run's the
- * current value of the variable.
- * The ::= modifiers, actually assign a value to the variable.
- * Their main purpose is in supporting modifiers of .for loop
- * iterators and other obscure uses. They always expand to
- * nothing. In a target rule that would otherwise expand to an
- * empty line they can be preceded with @: to keep make happy.
- * Eg.
- *
- * foo: .USE
- * .for i in ${.TARGET} ${.TARGET:R}.gz
- * @: ${t::=$i}
- * @echo blah ${t:T}
- * .endfor
- *
- * ::=<str> Assigns <str> as the new value of variable.
- * ::?=<str> Assigns <str> as value of variable if
- * it was not already set.
- * ::+=<str> Appends <str> to variable.
- * ::!=<cmd> Assigns output of <cmd> as the new value of
- * variable.
- */
-
-/* we now have some modifiers with long names */
-#define STRMOD_MATCH(s, want, n) \
- (strncmp(s, want, n) == 0 && (s[n] == endc || s[n] == ':'))
-#define STRMOD_MATCHX(s, want, n) \
- (strncmp(s, want, n) == 0 && (s[n] == endc || s[n] == ':' || s[n] == '='))
-#define CHARMOD_MATCH(c) (c == endc || c == ':')
-
-static char *
-ApplyModifiers(char *nstr, const char *tstr,
- int startc, int endc,
- Var *v, GNode *ctxt, int flags,
- int *lengthPtr, void **freePtr)
-{
- const char *start;
- const char *cp; /* Secondary pointer into str (place marker
- * for tstr) */
- char *newStr; /* New value to return */
- char *ep;
- char termc; /* Character which terminated scan */
- int cnt; /* Used to count brace pairs when variable in
- * in parens or braces */
- char delim;
- int modifier; /* that we are processing */
- Var_Parse_State parsestate; /* Flags passed to helper functions */
- time_t utc; /* for VarStrftime */
-
- delim = '\0';
- parsestate.oneBigWord = FALSE;
- parsestate.varSpace = ' '; /* word separator */
-
- start = cp = tstr;
-
- while (*tstr && *tstr != endc) {
-
- if (*tstr == '$') {
- /*
- * We may have some complex modifiers in a variable.
- */
- void *freeIt;
- char *rval;
- int rlen;
- int c;
-
- rval = Var_Parse(tstr, ctxt, flags, &rlen, &freeIt);
-
- /*
- * If we have not parsed up to endc or ':',
- * we are not interested.
- */
- if (rval != NULL && *rval &&
- (c = tstr[rlen]) != '\0' &&
- c != ':' &&
- c != endc) {
- free(freeIt);
- goto apply_mods;
- }
-
- if (DEBUG(VAR)) {
- fprintf(debug_file, "Got '%s' from '%.*s'%.*s\n",
- rval, rlen, tstr, rlen, tstr + rlen);
- }
-
- tstr += rlen;
-
- if (rval != NULL && *rval) {
- int used;
-
- nstr = ApplyModifiers(nstr, rval,
- 0, 0, v, ctxt, flags, &used, freePtr);
- if (nstr == var_Error
- || (nstr == varNoError && (flags & VARF_UNDEFERR) == 0)
- || strlen(rval) != (size_t) used) {
- free(freeIt);
- goto out; /* error already reported */
- }
- }
- free(freeIt);
- if (*tstr == ':')
- tstr++;
- else if (!*tstr && endc) {
- Error("Unclosed variable specification after complex modifier (expecting '%c') for %s", endc, v->name);
- goto out;
- }
- continue;
- }
- apply_mods:
- if (DEBUG(VAR)) {
- fprintf(debug_file, "Applying[%s] :%c to \"%s\"\n", v->name,
- *tstr, nstr);
- }
- newStr = var_Error;
- switch ((modifier = *tstr)) {
- case ':':
- {
- if (tstr[1] == '=' ||
- (tstr[2] == '=' &&
- (tstr[1] == '!' || tstr[1] == '+' || tstr[1] == '?'))) {
- /*
- * "::=", "::!=", "::+=", or "::?="
- */
- GNode *v_ctxt; /* context where v belongs */
- const char *emsg;
- char *sv_name;
- VarPattern pattern;
- int how;
- int vflags;
-
- if (v->name[0] == 0)
- goto bad_modifier;
-
- v_ctxt = ctxt;
- sv_name = NULL;
- ++tstr;
- if (v->flags & VAR_JUNK) {
- /*
- * We need to bmake_strdup() it incase
- * VarGetPattern() recurses.
- */
- sv_name = v->name;
- v->name = bmake_strdup(v->name);
- } else if (ctxt != VAR_GLOBAL) {
- Var *gv = VarFind(v->name, ctxt, 0);
- if (gv == NULL)
- v_ctxt = VAR_GLOBAL;
- else
- VarFreeEnv(gv, TRUE);
- }
-
- switch ((how = *tstr)) {
- case '+':
- case '?':
- case '!':
- cp = &tstr[2];
- break;
- default:
- cp = ++tstr;
- break;
- }
- delim = startc == PROPEN ? PRCLOSE : BRCLOSE;
- pattern.flags = 0;
-
- vflags = (flags & VARF_WANTRES) ? 0 : VAR_NOSUBST;
- pattern.rhs = VarGetPattern(ctxt, &parsestate, flags,
- &cp, delim, &vflags,
- &pattern.rightLen,
- NULL);
- if (v->flags & VAR_JUNK) {
- /* restore original name */
- free(v->name);
- v->name = sv_name;
- }
- if (pattern.rhs == NULL)
- goto cleanup;
-
- termc = *--cp;
- delim = '\0';
-
- if (flags & VARF_WANTRES) {
- switch (how) {
- case '+':
- Var_Append(v->name, pattern.rhs, v_ctxt);
- break;
- case '!':
- newStr = Cmd_Exec(pattern.rhs, &emsg);
- if (emsg)
- Error(emsg, nstr);
- else
- Var_Set(v->name, newStr, v_ctxt, 0);
- free(newStr);
- break;
- case '?':
- if ((v->flags & VAR_JUNK) == 0)
- break;
- /* FALLTHROUGH */
- default:
- Var_Set(v->name, pattern.rhs, v_ctxt, 0);
- break;
- }
- }
- free(UNCONST(pattern.rhs));
- newStr = varNoError;
- break;
- }
- goto default_case; /* "::<unrecognised>" */
- }
- case '@':
- {
- VarLoop_t loop;
- int vflags = VAR_NOSUBST;
-
- cp = ++tstr;
- delim = '@';
- if ((loop.tvar = VarGetPattern(ctxt, &parsestate, flags,
- &cp, delim,
- &vflags, &loop.tvarLen,
- NULL)) == NULL)
- goto cleanup;
-
- if ((loop.str = VarGetPattern(ctxt, &parsestate, flags,
- &cp, delim,
- &vflags, &loop.strLen,
- NULL)) == NULL)
- goto cleanup;
-
- termc = *cp;
- delim = '\0';
-
- loop.errnum = flags & VARF_UNDEFERR;
- loop.ctxt = ctxt;
- newStr = VarModify(ctxt, &parsestate, nstr, VarLoopExpand,
- &loop);
- Var_Delete(loop.tvar, ctxt);
- free(loop.tvar);
- free(loop.str);
- break;
- }
- case '_': /* remember current value */
- cp = tstr + 1; /* make sure it is set */
- if (STRMOD_MATCHX(tstr, "_", 1)) {
- if (tstr[1] == '=') {
- char *np;
- int n;
-
- cp++;
- n = strcspn(cp, ":)}");
- np = bmake_strndup(cp, n+1);
- np[n] = '\0';
- cp = tstr + 2 + n;
- Var_Set(np, nstr, ctxt, 0);
- free(np);
- } else {
- Var_Set("_", nstr, ctxt, 0);
- }
- newStr = nstr;
- termc = *cp;
- break;
- }
- goto default_case;
- case 'D':
- case 'U':
- {
- Buffer buf; /* Buffer for patterns */
- int nflags;
-
- if (flags & VARF_WANTRES) {
- int wantres;
- if (*tstr == 'U')
- wantres = ((v->flags & VAR_JUNK) != 0);
- else
- wantres = ((v->flags & VAR_JUNK) == 0);
- nflags = flags & ~VARF_WANTRES;
- if (wantres)
- nflags |= VARF_WANTRES;
- } else
- nflags = flags;
- /*
- * Pass through tstr looking for 1) escaped delimiters,
- * '$'s and backslashes (place the escaped character in
- * uninterpreted) and 2) unescaped $'s that aren't before
- * the delimiter (expand the variable substitution).
- * The result is left in the Buffer buf.
- */
- Buf_Init(&buf, 0);
- for (cp = tstr + 1;
- *cp != endc && *cp != ':' && *cp != '\0';
- cp++) {
- if ((*cp == '\\') &&
- ((cp[1] == ':') ||
- (cp[1] == '$') ||
- (cp[1] == endc) ||
- (cp[1] == '\\')))
- {
- Buf_AddByte(&buf, cp[1]);
- cp++;
- } else if (*cp == '$') {
- /*
- * If unescaped dollar sign, assume it's a
- * variable substitution and recurse.
- */
- char *cp2;
- int len;
- void *freeIt;
-
- cp2 = Var_Parse(cp, ctxt, nflags, &len, &freeIt);
- Buf_AddBytes(&buf, strlen(cp2), cp2);
- free(freeIt);
- cp += len - 1;
- } else {
- Buf_AddByte(&buf, *cp);
- }
- }
-
- termc = *cp;
-
- if ((v->flags & VAR_JUNK) != 0)
- v->flags |= VAR_KEEP;
- if (nflags & VARF_WANTRES) {
- newStr = Buf_Destroy(&buf, FALSE);
- } else {
- newStr = nstr;
- Buf_Destroy(&buf, TRUE);
- }
- break;
- }
- case 'L':
- {
- if ((v->flags & VAR_JUNK) != 0)
- v->flags |= VAR_KEEP;
- newStr = bmake_strdup(v->name);
- cp = ++tstr;
- termc = *tstr;
- break;
- }
- case 'P':
- {
- GNode *gn;
-
- if ((v->flags & VAR_JUNK) != 0)
- v->flags |= VAR_KEEP;
- gn = Targ_FindNode(v->name, TARG_NOCREATE);
- if (gn == NULL || gn->type & OP_NOPATH) {
- newStr = NULL;
- } else if (gn->path) {
- newStr = bmake_strdup(gn->path);
- } else {
- newStr = Dir_FindFile(v->name, Suff_FindPath(gn));
- }
- if (!newStr) {
- newStr = bmake_strdup(v->name);
- }
- cp = ++tstr;
- termc = *tstr;
- break;
- }
- case '!':
- {
- const char *emsg;
- VarPattern pattern;
- pattern.flags = 0;
-
- delim = '!';
- emsg = NULL;
- cp = ++tstr;
- if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, flags,
- &cp, delim,
- NULL, &pattern.rightLen,
- NULL)) == NULL)
- goto cleanup;
- if (flags & VARF_WANTRES)
- newStr = Cmd_Exec(pattern.rhs, &emsg);
- else
- newStr = varNoError;
- free(UNCONST(pattern.rhs));
- if (emsg)
- Error(emsg, nstr);
- termc = *cp;
- delim = '\0';
- if (v->flags & VAR_JUNK) {
- v->flags |= VAR_KEEP;
- }
- break;
- }
- case '[':
- {
- /*
- * Look for the closing ']', recursively
- * expanding any embedded variables.
- *
- * estr is a pointer to the expanded result,
- * which we must free().
- */
- char *estr;
-
- cp = tstr+1; /* point to char after '[' */
- delim = ']'; /* look for closing ']' */
- estr = VarGetPattern(ctxt, &parsestate,
- flags, &cp, delim,
- NULL, NULL, NULL);
- if (estr == NULL)
- goto cleanup; /* report missing ']' */
- /* now cp points just after the closing ']' */
- delim = '\0';
- if (cp[0] != ':' && cp[0] != endc) {
- /* Found junk after ']' */
- free(estr);
- goto bad_modifier;
- }
- if (estr[0] == '\0') {
- /* Found empty square brackets in ":[]". */
- free(estr);
- goto bad_modifier;
- } else if (estr[0] == '#' && estr[1] == '\0') {
- /* Found ":[#]" */
-
- /*
- * We will need enough space for the decimal
- * representation of an int. We calculate the
- * space needed for the octal representation,
- * and add enough slop to cope with a '-' sign
- * (which should never be needed) and a '\0'
- * string terminator.
- */
- int newStrSize =
- (sizeof(int) * CHAR_BIT + 2) / 3 + 2;
-
- newStr = bmake_malloc(newStrSize);
- if (parsestate.oneBigWord) {
- strncpy(newStr, "1", newStrSize);
- } else {
- /* XXX: brk_string() is a rather expensive
- * way of counting words. */
- char **av;
- char *as;
- int ac;
-
- av = brk_string(nstr, &ac, FALSE, &as);
- snprintf(newStr, newStrSize, "%d", ac);
- free(as);
- free(av);
- }
- termc = *cp;
- free(estr);
- break;
- } else if (estr[0] == '*' && estr[1] == '\0') {
- /* Found ":[*]" */
- parsestate.oneBigWord = TRUE;
- newStr = nstr;
- termc = *cp;
- free(estr);
- break;
- } else if (estr[0] == '@' && estr[1] == '\0') {
- /* Found ":[@]" */
- parsestate.oneBigWord = FALSE;
- newStr = nstr;
- termc = *cp;
- free(estr);
- break;
- } else {
- /*
- * We expect estr to contain a single
- * integer for :[N], or two integers
- * separated by ".." for :[start..end].
- */
- VarSelectWords_t seldata = { 0, 0 };
-
- seldata.start = strtol(estr, &ep, 0);
- if (ep == estr) {
- /* Found junk instead of a number */
- free(estr);
- goto bad_modifier;
- } else if (ep[0] == '\0') {
- /* Found only one integer in :[N] */
- seldata.end = seldata.start;
- } else if (ep[0] == '.' && ep[1] == '.' &&
- ep[2] != '\0') {
- /* Expecting another integer after ".." */
- ep += 2;
- seldata.end = strtol(ep, &ep, 0);
- if (ep[0] != '\0') {
- /* Found junk after ".." */
- free(estr);
- goto bad_modifier;
- }
- } else {
- /* Found junk instead of ".." */
- free(estr);
- goto bad_modifier;
- }
- /*
- * Now seldata is properly filled in,
- * but we still have to check for 0 as
- * a special case.
- */
- if (seldata.start == 0 && seldata.end == 0) {
- /* ":[0]" or perhaps ":[0..0]" */
- parsestate.oneBigWord = TRUE;
- newStr = nstr;
- termc = *cp;
- free(estr);
- break;
- } else if (seldata.start == 0 ||
- seldata.end == 0) {
- /* ":[0..N]" or ":[N..0]" */
- free(estr);
- goto bad_modifier;
- }
- /*
- * Normal case: select the words
- * described by seldata.
- */
- newStr = VarSelectWords(ctxt, &parsestate,
- nstr, &seldata);
-
- termc = *cp;
- free(estr);
- break;
- }
-
- }
- case 'g':
- cp = tstr + 1; /* make sure it is set */
- if (STRMOD_MATCHX(tstr, "gmtime", 6)) {
- if (tstr[6] == '=') {
- utc = strtoul(&tstr[7], &ep, 10);
- cp = ep;
- } else {
- utc = 0;
- cp = tstr + 6;
- }
- newStr = VarStrftime(nstr, 1, utc);
- termc = *cp;
- } else {
- goto default_case;
- }
- break;
- case 'h':
- cp = tstr + 1; /* make sure it is set */
- if (STRMOD_MATCH(tstr, "hash", 4)) {
- newStr = VarHash(nstr);
- cp = tstr + 4;
- termc = *cp;
- } else {
- goto default_case;
- }
- break;
- case 'l':
- cp = tstr + 1; /* make sure it is set */
- if (STRMOD_MATCHX(tstr, "localtime", 9)) {
- if (tstr[9] == '=') {
- utc = strtoul(&tstr[10], &ep, 10);
- cp = ep;
- } else {
- utc = 0;
- cp = tstr + 9;
- }
- newStr = VarStrftime(nstr, 0, utc);
- termc = *cp;
- } else {
- goto default_case;
- }
- break;
- case 't':
- {
- cp = tstr + 1; /* make sure it is set */
- if (tstr[1] != endc && tstr[1] != ':') {
- if (tstr[1] == 's') {
- /*
- * Use the char (if any) at tstr[2]
- * as the word separator.
- */
- VarPattern pattern;
-
- if (tstr[2] != endc &&
- (tstr[3] == endc || tstr[3] == ':')) {
- /* ":ts<unrecognised><endc>" or
- * ":ts<unrecognised>:" */
- parsestate.varSpace = tstr[2];
- cp = tstr + 3;
- } else if (tstr[2] == endc || tstr[2] == ':') {
- /* ":ts<endc>" or ":ts:" */
- parsestate.varSpace = 0; /* no separator */
- cp = tstr + 2;
- } else if (tstr[2] == '\\') {
- const char *xp = &tstr[3];
- int base = 8; /* assume octal */
-
- switch (tstr[3]) {
- case 'n':
- parsestate.varSpace = '\n';
- cp = tstr + 4;
- break;
- case 't':
- parsestate.varSpace = '\t';
- cp = tstr + 4;
- break;
- case 'x':
- base = 16;
- xp++;
- goto get_numeric;
- case '0':
- base = 0;
- goto get_numeric;
- default:
- if (isdigit((unsigned char)tstr[3])) {
-
- get_numeric:
- parsestate.varSpace =
- strtoul(xp, &ep, base);
- if (*ep != ':' && *ep != endc)
- goto bad_modifier;
- cp = ep;
- } else {
- /*
- * ":ts<backslash><unrecognised>".
- */
- goto bad_modifier;
- }
- break;
- }
- } else {
- /*
- * Found ":ts<unrecognised><unrecognised>".
- */
- goto bad_modifier;
- }
-
- termc = *cp;
-
- /*
- * We cannot be certain that VarModify
- * will be used - even if there is a
- * subsequent modifier, so do a no-op
- * VarSubstitute now to for str to be
- * re-expanded without the spaces.
- */
- pattern.flags = VAR_SUB_ONE;
- pattern.lhs = pattern.rhs = "\032";
- pattern.leftLen = pattern.rightLen = 1;
-
- newStr = VarModify(ctxt, &parsestate, nstr,
- VarSubstitute,
- &pattern);
- } else if (tstr[2] == endc || tstr[2] == ':') {
- /*
- * Check for two-character options:
- * ":tu", ":tl"
- */
- if (tstr[1] == 'A') { /* absolute path */
- newStr = VarModify(ctxt, &parsestate, nstr,
- VarRealpath, NULL);
- cp = tstr + 2;
- termc = *cp;
- } else if (tstr[1] == 'u') {
- char *dp = bmake_strdup(nstr);
- for (newStr = dp; *dp; dp++)
- *dp = toupper((unsigned char)*dp);
- cp = tstr + 2;
- termc = *cp;
- } else if (tstr[1] == 'l') {
- char *dp = bmake_strdup(nstr);
- for (newStr = dp; *dp; dp++)
- *dp = tolower((unsigned char)*dp);
- cp = tstr + 2;
- termc = *cp;
- } else if (tstr[1] == 'W' || tstr[1] == 'w') {
- parsestate.oneBigWord = (tstr[1] == 'W');
- newStr = nstr;
- cp = tstr + 2;
- termc = *cp;
- } else {
- /* Found ":t<unrecognised>:" or
- * ":t<unrecognised><endc>". */
- goto bad_modifier;
- }
- } else {
- /*
- * Found ":t<unrecognised><unrecognised>".
- */
- goto bad_modifier;
- }
- } else {
- /*
- * Found ":t<endc>" or ":t:".
- */
- goto bad_modifier;
- }
- break;
- }
- case 'N':
- case 'M':
- {
- char *pattern;
- const char *endpat; /* points just after end of pattern */
- char *cp2;
- Boolean copy; /* pattern should be, or has been, copied */
- Boolean needSubst;
- int nest;
-
- copy = FALSE;
- needSubst = FALSE;
- nest = 1;
- /*
- * In the loop below, ignore ':' unless we are at
- * (or back to) the original brace level.
- * XXX This will likely not work right if $() and ${}
- * are intermixed.
- */
- for (cp = tstr + 1;
- *cp != '\0' && !(*cp == ':' && nest == 1);
- cp++)
- {
- if (*cp == '\\' &&
- (cp[1] == ':' ||
- cp[1] == endc || cp[1] == startc)) {
- if (!needSubst) {
- copy = TRUE;
- }
- cp++;
- continue;
- }
- if (*cp == '$') {
- needSubst = TRUE;
- }
- if (*cp == '(' || *cp == '{')
- ++nest;
- if (*cp == ')' || *cp == '}') {
- --nest;
- if (nest == 0)
- break;
- }
- }
- termc = *cp;
- endpat = cp;
- if (copy) {
- /*
- * Need to compress the \:'s out of the pattern, so
- * allocate enough room to hold the uncompressed
- * pattern (note that cp started at tstr+1, so
- * cp - tstr takes the null byte into account) and
- * compress the pattern into the space.
- */
- pattern = bmake_malloc(cp - tstr);
- for (cp2 = pattern, cp = tstr + 1;
- cp < endpat;
- cp++, cp2++)
- {
- if ((*cp == '\\') && (cp+1 < endpat) &&
- (cp[1] == ':' || cp[1] == endc)) {
- cp++;
- }
- *cp2 = *cp;
- }
- *cp2 = '\0';
- endpat = cp2;
- } else {
- /*
- * Either Var_Subst or VarModify will need a
- * nul-terminated string soon, so construct one now.
- */
- pattern = bmake_strndup(tstr+1, endpat - (tstr + 1));
- }
- if (needSubst) {
- /*
- * pattern contains embedded '$', so use Var_Subst to
- * expand it.
- */
- cp2 = pattern;
- pattern = Var_Subst(NULL, cp2, ctxt, flags | VARF_WANTRES);
- free(cp2);
- }
- if (DEBUG(VAR))
- fprintf(debug_file, "Pattern[%s] for [%s] is [%s]\n",
- v->name, nstr, pattern);
- if (*tstr == 'M') {
- newStr = VarModify(ctxt, &parsestate, nstr, VarMatch,
- pattern);
- } else {
- newStr = VarModify(ctxt, &parsestate, nstr, VarNoMatch,
- pattern);
- }
- free(pattern);
- break;
- }
- case 'S':
- {
- VarPattern pattern;
- Var_Parse_State tmpparsestate;
-
- pattern.flags = 0;
- tmpparsestate = parsestate;
- delim = tstr[1];
- tstr += 2;
-
- /*
- * If pattern begins with '^', it is anchored to the
- * start of the word -- skip over it and flag pattern.
- */
- if (*tstr == '^') {
- pattern.flags |= VAR_MATCH_START;
- tstr += 1;
- }
-
- cp = tstr;
- if ((pattern.lhs = VarGetPattern(ctxt, &parsestate, flags,
- &cp, delim,
- &pattern.flags,
- &pattern.leftLen,
- NULL)) == NULL)
- goto cleanup;
-
- if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, flags,
- &cp, delim, NULL,
- &pattern.rightLen,
- &pattern)) == NULL)
- goto cleanup;
-
- /*
- * Check for global substitution. If 'g' after the final
- * delimiter, substitution is global and is marked that
- * way.
- */
- for (;; cp++) {
- switch (*cp) {
- case 'g':
- pattern.flags |= VAR_SUB_GLOBAL;
- continue;
- case '1':
- pattern.flags |= VAR_SUB_ONE;
- continue;
- case 'W':
- tmpparsestate.oneBigWord = TRUE;
- continue;
- }
- break;
- }
-
- termc = *cp;
- newStr = VarModify(ctxt, &tmpparsestate, nstr,
- VarSubstitute,
- &pattern);
-
- /*
- * Free the two strings.
- */
- free(UNCONST(pattern.lhs));
- free(UNCONST(pattern.rhs));
- delim = '\0';
- break;
- }
- case '?':
- {
- VarPattern pattern;
- Boolean value;
- int cond_rc;
- int lhs_flags, rhs_flags;
-
- /* find ':', and then substitute accordingly */
- if (flags & VARF_WANTRES) {
- cond_rc = Cond_EvalExpression(NULL, v->name, &value, 0, FALSE);
- if (cond_rc == COND_INVALID) {
- lhs_flags = rhs_flags = VAR_NOSUBST;
- } else if (value) {
- lhs_flags = 0;
- rhs_flags = VAR_NOSUBST;
- } else {
- lhs_flags = VAR_NOSUBST;
- rhs_flags = 0;
- }
- } else {
- /* we are just consuming and discarding */
- cond_rc = value = 0;
- lhs_flags = rhs_flags = VAR_NOSUBST;
- }
- pattern.flags = 0;
-
- cp = ++tstr;
- delim = ':';
- if ((pattern.lhs = VarGetPattern(ctxt, &parsestate, flags,
- &cp, delim, &lhs_flags,
- &pattern.leftLen,
- NULL)) == NULL)
- goto cleanup;
-
- /* BROPEN or PROPEN */
- delim = endc;
- if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, flags,
- &cp, delim, &rhs_flags,
- &pattern.rightLen,
- NULL)) == NULL)
- goto cleanup;
-
- termc = *--cp;
- delim = '\0';
- if (cond_rc == COND_INVALID) {
- Error("Bad conditional expression `%s' in %s?%s:%s",
- v->name, v->name, pattern.lhs, pattern.rhs);
- goto cleanup;
- }
-
- if (value) {
- newStr = UNCONST(pattern.lhs);
- free(UNCONST(pattern.rhs));
- } else {
- newStr = UNCONST(pattern.rhs);
- free(UNCONST(pattern.lhs));
- }
- if (v->flags & VAR_JUNK) {
- v->flags |= VAR_KEEP;
- }
- break;
- }
-#ifndef NO_REGEX
- case 'C':
- {
- VarREPattern pattern;
- char *re;
- int error;
- Var_Parse_State tmpparsestate;
-
- pattern.flags = 0;
- tmpparsestate = parsestate;
- delim = tstr[1];
- tstr += 2;
-
- cp = tstr;
-
- if ((re = VarGetPattern(ctxt, &parsestate, flags, &cp, delim,
- NULL, NULL, NULL)) == NULL)
- goto cleanup;
-
- if ((pattern.replace = VarGetPattern(ctxt, &parsestate,
- flags, &cp, delim, NULL,
- NULL, NULL)) == NULL){
- free(re);
- goto cleanup;
- }
-
- for (;; cp++) {
- switch (*cp) {
- case 'g':
- pattern.flags |= VAR_SUB_GLOBAL;
- continue;
- case '1':
- pattern.flags |= VAR_SUB_ONE;
- continue;
- case 'W':
- tmpparsestate.oneBigWord = TRUE;
- continue;
- }
- break;
- }
-
- termc = *cp;
-
- error = regcomp(&pattern.re, re, REG_EXTENDED);
- free(re);
- if (error) {
- *lengthPtr = cp - start + 1;
- VarREError(error, &pattern.re, "RE substitution error");
- free(pattern.replace);
- goto cleanup;
- }
-
- pattern.nsub = pattern.re.re_nsub + 1;
- if (pattern.nsub < 1)
- pattern.nsub = 1;
- if (pattern.nsub > 10)
- pattern.nsub = 10;
- pattern.matches = bmake_malloc(pattern.nsub *
- sizeof(regmatch_t));
- newStr = VarModify(ctxt, &tmpparsestate, nstr,
- VarRESubstitute,
- &pattern);
- regfree(&pattern.re);
- free(pattern.replace);
- free(pattern.matches);
- delim = '\0';
- break;
- }
-#endif
- case 'q':
- case 'Q':
- if (tstr[1] == endc || tstr[1] == ':') {
- newStr = VarQuote(nstr, modifier == 'q');
- cp = tstr + 1;
- termc = *cp;
- break;
- }
- goto default_case;
- case 'T':
- if (tstr[1] == endc || tstr[1] == ':') {
- newStr = VarModify(ctxt, &parsestate, nstr, VarTail,
- NULL);
- cp = tstr + 1;
- termc = *cp;
- break;
- }
- goto default_case;
- case 'H':
- if (tstr[1] == endc || tstr[1] == ':') {
- newStr = VarModify(ctxt, &parsestate, nstr, VarHead,
- NULL);
- cp = tstr + 1;
- termc = *cp;
- break;
- }
- goto default_case;
- case 'E':
- if (tstr[1] == endc || tstr[1] == ':') {
- newStr = VarModify(ctxt, &parsestate, nstr, VarSuffix,
- NULL);
- cp = tstr + 1;
- termc = *cp;
- break;
- }
- goto default_case;
- case 'R':
- if (tstr[1] == endc || tstr[1] == ':') {
- newStr = VarModify(ctxt, &parsestate, nstr, VarRoot,
- NULL);
- cp = tstr + 1;
- termc = *cp;
- break;
- }
- goto default_case;
- case 'r':
- cp = tstr + 1; /* make sure it is set */
- if (STRMOD_MATCHX(tstr, "range", 5)) {
- int n;
-
- if (tstr[5] == '=') {
- n = strtoul(&tstr[6], &ep, 10);
- cp = ep;
- } else {
- n = 0;
- cp = tstr + 5;
- }
- newStr = VarRange(nstr, n);
- termc = *cp;
- break;
- }
- goto default_case;
- case 'O':
- {
- char otype;
-
- cp = tstr + 1; /* skip to the rest in any case */
- if (tstr[1] == endc || tstr[1] == ':') {
- otype = 's';
- termc = *cp;
- } else if ( (tstr[1] == 'x') &&
- (tstr[2] == endc || tstr[2] == ':') ) {
- otype = tstr[1];
- cp = tstr + 2;
- termc = *cp;
- } else {
- goto bad_modifier;
- }
- newStr = VarOrder(nstr, otype);
- break;
- }
- case 'u':
- if (tstr[1] == endc || tstr[1] == ':') {
- newStr = VarUniq(nstr);
- cp = tstr + 1;
- termc = *cp;
- break;
- }
- goto default_case;
-#ifdef SUNSHCMD
- case 's':
- if (tstr[1] == 'h' && (tstr[2] == endc || tstr[2] == ':')) {
- const char *emsg;
- if (flags & VARF_WANTRES) {
- newStr = Cmd_Exec(nstr, &emsg);
- if (emsg)
- Error(emsg, nstr);
- } else
- newStr = varNoError;
- cp = tstr + 2;
- termc = *cp;
- break;
- }
- goto default_case;
-#endif
- default:
- default_case:
- {
-#ifdef SYSVVARSUB
- /*
- * This can either be a bogus modifier or a System-V
- * substitution command.
- */
- VarPattern pattern;
- Boolean eqFound;
-
- pattern.flags = 0;
- eqFound = FALSE;
- /*
- * First we make a pass through the string trying
- * to verify it is a SYSV-make-style translation:
- * it must be: <string1>=<string2>)
- */
- cp = tstr;
- cnt = 1;
- while (*cp != '\0' && cnt) {
- if (*cp == '=') {
- eqFound = TRUE;
- /* continue looking for endc */
- }
- else if (*cp == endc)
- cnt--;
- else if (*cp == startc)
- cnt++;
- if (cnt)
- cp++;
- }
- if (*cp == endc && eqFound) {
-
- /*
- * Now we break this sucker into the lhs and
- * rhs. We must null terminate them of course.
- */
- delim='=';
- cp = tstr;
- if ((pattern.lhs = VarGetPattern(ctxt, &parsestate,
- flags, &cp, delim, &pattern.flags,
- &pattern.leftLen, NULL)) == NULL)
- goto cleanup;
- delim = endc;
- if ((pattern.rhs = VarGetPattern(ctxt, &parsestate,
- flags, &cp, delim, NULL, &pattern.rightLen,
- &pattern)) == NULL)
- goto cleanup;
-
- /*
- * SYSV modifications happen through the whole
- * string. Note the pattern is anchored at the end.
- */
- termc = *--cp;
- delim = '\0';
- if (pattern.leftLen == 0 && *nstr == '\0') {
- newStr = nstr; /* special case */
- } else {
- newStr = VarModify(ctxt, &parsestate, nstr,
- VarSYSVMatch,
- &pattern);
- }
- free(UNCONST(pattern.lhs));
- free(UNCONST(pattern.rhs));
- } else
-#endif
- {
- Error("Unknown modifier '%c'", *tstr);
- for (cp = tstr+1;
- *cp != ':' && *cp != endc && *cp != '\0';
- cp++)
- continue;
- termc = *cp;
- newStr = var_Error;
- }
- }
- }
- if (DEBUG(VAR)) {
- fprintf(debug_file, "Result[%s] of :%c is \"%s\"\n",
- v->name, modifier, newStr);
- }
-
- if (newStr != nstr) {
- if (*freePtr) {
- free(nstr);
- *freePtr = NULL;
- }
- nstr = newStr;
- if (nstr != var_Error && nstr != varNoError) {
- *freePtr = nstr;
- }
- }
- if (termc == '\0' && endc != '\0') {
- Error("Unclosed variable specification (expecting '%c') for \"%s\" (value \"%s\") modifier %c", endc, v->name, nstr, modifier);
- } else if (termc == ':') {
- cp++;
- }
- tstr = cp;
- }
- out:
- *lengthPtr = tstr - start;
- return (nstr);
-
- bad_modifier:
- /* "{(" */
- Error("Bad modifier `:%.*s' for %s", (int)strcspn(tstr, ":)}"), tstr,
- v->name);
-
- cleanup:
- *lengthPtr = cp - start;
- if (delim != '\0')
- Error("Unclosed substitution for %s (%c missing)",
- v->name, delim);
- free(*freePtr);
- *freePtr = NULL;
- return (var_Error);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Var_Parse --
- * Given the start of a variable invocation, extract the variable
- * name and find its value, then modify it according to the
- * specification.
- *
- * Input:
- * str The string to parse
- * ctxt The context for the variable
- * flags VARF_UNDEFERR if undefineds are an error
- * VARF_WANTRES if we actually want the result
- * VARF_ASSIGN if we are in a := assignment
- * lengthPtr OUT: The length of the specification
- * freePtr OUT: Non-NULL if caller should free *freePtr
- *
- * Results:
- * The (possibly-modified) value of the variable or var_Error if the
- * specification is invalid. The length of the specification is
- * placed in *lengthPtr (for invalid specifications, this is just
- * 2...?).
- * If *freePtr is non-NULL then it's a pointer that the caller
- * should pass to free() to free memory used by the result.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-/* coverity[+alloc : arg-*4] */
-char *
-Var_Parse(const char *str, GNode *ctxt, int flags,
- int *lengthPtr, void **freePtr)
-{
- const char *tstr; /* Pointer into str */
- Var *v; /* Variable in invocation */
- Boolean haveModifier;/* TRUE if have modifiers for the variable */
- char endc; /* Ending character when variable in parens
- * or braces */
- char startc; /* Starting character when variable in parens
- * or braces */
- int vlen; /* Length of variable name */
- const char *start; /* Points to original start of str */
- char *nstr; /* New string, used during expansion */
- Boolean dynamic; /* TRUE if the variable is local and we're
- * expanding it in a non-local context. This
- * is done to support dynamic sources. The
- * result is just the invocation, unaltered */
- const char *extramodifiers; /* extra modifiers to apply first */
- char name[2];
-
- *freePtr = NULL;
- extramodifiers = NULL;
- dynamic = FALSE;
- start = str;
-
- startc = str[1];
- if (startc != PROPEN && startc != BROPEN) {
- /*
- * If it's not bounded by braces of some sort, life is much simpler.
- * We just need to check for the first character and return the
- * value if it exists.
- */
-
- /* Error out some really stupid names */
- if (startc == '\0' || strchr(")}:$", startc)) {
- *lengthPtr = 1;
- return var_Error;
- }
- name[0] = startc;
- name[1] = '\0';
-
- v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
- if (v == NULL) {
- *lengthPtr = 2;
-
- if ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)) {
- /*
- * If substituting a local variable in a non-local context,
- * assume it's for dynamic source stuff. We have to handle
- * this specially and return the longhand for the variable
- * with the dollar sign escaped so it makes it back to the
- * caller. Only four of the local variables are treated
- * specially as they are the only four that will be set
- * when dynamic sources are expanded.
- */
- switch (str[1]) {
- case '@':
- return UNCONST("$(.TARGET)");
- case '%':
- return UNCONST("$(.MEMBER)");
- case '*':
- return UNCONST("$(.PREFIX)");
- case '!':
- return UNCONST("$(.ARCHIVE)");
- }
- }
- /*
- * Error
- */
- return (flags & VARF_UNDEFERR) ? var_Error : varNoError;
- } else {
- haveModifier = FALSE;
- tstr = &str[1];
- endc = str[1];
- }
- } else {
- Buffer buf; /* Holds the variable name */
- int depth = 1;
-
- endc = startc == PROPEN ? PRCLOSE : BRCLOSE;
- Buf_Init(&buf, 0);
-
- /*
- * Skip to the end character or a colon, whichever comes first.
- */
- for (tstr = str + 2; *tstr != '\0'; tstr++)
- {
- /*
- * Track depth so we can spot parse errors.
- */
- if (*tstr == startc) {
- depth++;
- }
- if (*tstr == endc) {
- if (--depth == 0)
- break;
- }
- if (depth == 1 && *tstr == ':') {
- break;
- }
- /*
- * A variable inside a variable, expand
- */
- if (*tstr == '$') {
- int rlen;
- void *freeIt;
- char *rval = Var_Parse(tstr, ctxt, flags, &rlen, &freeIt);
- if (rval != NULL) {
- Buf_AddBytes(&buf, strlen(rval), rval);
- }
- free(freeIt);
- tstr += rlen - 1;
- }
- else
- Buf_AddByte(&buf, *tstr);
- }
- if (*tstr == ':') {
- haveModifier = TRUE;
- } else if (*tstr == endc) {
- haveModifier = FALSE;
- } else {
- /*
- * If we never did find the end character, return NULL
- * right now, setting the length to be the distance to
- * the end of the string, since that's what make does.
- */
- *lengthPtr = tstr - str;
- Buf_Destroy(&buf, TRUE);
- return (var_Error);
- }
- str = Buf_GetAll(&buf, &vlen);
-
- /*
- * At this point, str points into newly allocated memory from
- * buf, containing only the name of the variable.
- *
- * start and tstr point into the const string that was pointed
- * to by the original value of the str parameter. start points
- * to the '$' at the beginning of the string, while tstr points
- * to the char just after the end of the variable name -- this
- * will be '\0', ':', PRCLOSE, or BRCLOSE.
- */
-
- v = VarFind(str, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
- /*
- * Check also for bogus D and F forms of local variables since we're
- * in a local context and the name is the right length.
- */
- if ((v == NULL) && (ctxt != VAR_CMD) && (ctxt != VAR_GLOBAL) &&
- (vlen == 2) && (str[1] == 'F' || str[1] == 'D') &&
- strchr("@%?*!<>", str[0]) != NULL) {
- /*
- * Well, it's local -- go look for it.
- */
- name[0] = *str;
- name[1] = '\0';
- v = VarFind(name, ctxt, 0);
-
- if (v != NULL) {
- if (str[1] == 'D') {
- extramodifiers = "H:";
- }
- else { /* F */
- extramodifiers = "T:";
- }
- }
- }
-
- if (v == NULL) {
- if (((vlen == 1) ||
- (((vlen == 2) && (str[1] == 'F' || str[1] == 'D')))) &&
- ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)))
- {
- /*
- * If substituting a local variable in a non-local context,
- * assume it's for dynamic source stuff. We have to handle
- * this specially and return the longhand for the variable
- * with the dollar sign escaped so it makes it back to the
- * caller. Only four of the local variables are treated
- * specially as they are the only four that will be set
- * when dynamic sources are expanded.
- */
- switch (*str) {
- case '@':
- case '%':
- case '*':
- case '!':
- dynamic = TRUE;
- break;
- }
- } else if ((vlen > 2) && (*str == '.') &&
- isupper((unsigned char) str[1]) &&
- ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)))
- {
- int len;
-
- len = vlen - 1;
- if ((strncmp(str, ".TARGET", len) == 0) ||
- (strncmp(str, ".ARCHIVE", len) == 0) ||
- (strncmp(str, ".PREFIX", len) == 0) ||
- (strncmp(str, ".MEMBER", len) == 0))
- {
- dynamic = TRUE;
- }
- }
-
- if (!haveModifier) {
- /*
- * No modifiers -- have specification length so we can return
- * now.
- */
- *lengthPtr = tstr - start + 1;
- if (dynamic) {
- char *pstr = bmake_strndup(start, *lengthPtr);
- *freePtr = pstr;
- Buf_Destroy(&buf, TRUE);
- return(pstr);
- } else {
- Buf_Destroy(&buf, TRUE);
- return (flags & VARF_UNDEFERR) ? var_Error : varNoError;
- }
- } else {
- /*
- * Still need to get to the end of the variable specification,
- * so kludge up a Var structure for the modifications
- */
- v = bmake_malloc(sizeof(Var));
- v->name = UNCONST(str);
- Buf_Init(&v->val, 1);
- v->flags = VAR_JUNK;
- Buf_Destroy(&buf, FALSE);
- }
- } else
- Buf_Destroy(&buf, TRUE);
- }
-
- if (v->flags & VAR_IN_USE) {
- Fatal("Variable %s is recursive.", v->name);
- /*NOTREACHED*/
- } else {
- v->flags |= VAR_IN_USE;
- }
- /*
- * Before doing any modification, we have to make sure the value
- * has been fully expanded. If it looks like recursion might be
- * necessary (there's a dollar sign somewhere in the variable's value)
- * we just call Var_Subst to do any other substitutions that are
- * necessary. Note that the value returned by Var_Subst will have
- * been dynamically-allocated, so it will need freeing when we
- * return.
- */
- nstr = Buf_GetAll(&v->val, NULL);
- if (strchr(nstr, '$') != NULL) {
- nstr = Var_Subst(NULL, nstr, ctxt, flags);
- *freePtr = nstr;
- }
-
- v->flags &= ~VAR_IN_USE;
-
- if ((nstr != NULL) && (haveModifier || extramodifiers != NULL)) {
- void *extraFree;
- int used;
-
- extraFree = NULL;
- if (extramodifiers != NULL) {
- nstr = ApplyModifiers(nstr, extramodifiers, '(', ')',
- v, ctxt, flags, &used, &extraFree);
- }
-
- if (haveModifier) {
- /* Skip initial colon. */
- tstr++;
-
- nstr = ApplyModifiers(nstr, tstr, startc, endc,
- v, ctxt, flags, &used, freePtr);
- tstr += used;
- free(extraFree);
- } else {
- *freePtr = extraFree;
- }
- }
- if (*tstr) {
- *lengthPtr = tstr - start + 1;
- } else {
- *lengthPtr = tstr - start;
- }
-
- if (v->flags & VAR_FROM_ENV) {
- Boolean destroy = FALSE;
-
- if (nstr != Buf_GetAll(&v->val, NULL)) {
- destroy = TRUE;
- } else {
- /*
- * Returning the value unmodified, so tell the caller to free
- * the thing.
- */
- *freePtr = nstr;
- }
- VarFreeEnv(v, destroy);
- } else if (v->flags & VAR_JUNK) {
- /*
- * Perform any free'ing needed and set *freePtr to NULL so the caller
- * doesn't try to free a static pointer.
- * If VAR_KEEP is also set then we want to keep str as is.
- */
- if (!(v->flags & VAR_KEEP)) {
- if (*freePtr) {
- free(nstr);
- *freePtr = NULL;
- }
- if (dynamic) {
- nstr = bmake_strndup(start, *lengthPtr);
- *freePtr = nstr;
- } else {
- nstr = (flags & VARF_UNDEFERR) ? var_Error : varNoError;
- }
- }
- if (nstr != Buf_GetAll(&v->val, NULL))
- Buf_Destroy(&v->val, TRUE);
- free(v->name);
- free(v);
- }
- return (nstr);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Var_Subst --
- * Substitute for all variables in the given string in the given context
- * If flags & VARF_UNDEFERR, Parse_Error will be called when an undefined
- * variable is encountered.
- *
- * Input:
- * var Named variable || NULL for all
- * str the string which to substitute
- * ctxt the context wherein to find variables
- * flags VARF_UNDEFERR if undefineds are an error
- * VARF_WANTRES if we actually want the result
- * VARF_ASSIGN if we are in a := assignment
- *
- * Results:
- * The resulting string.
- *
- * Side Effects:
- * None. The old string must be freed by the caller
- *-----------------------------------------------------------------------
- */
-char *
-Var_Subst(const char *var, const char *str, GNode *ctxt, int flags)
-{
- Buffer buf; /* Buffer for forming things */
- char *val; /* Value to substitute for a variable */
- int length; /* Length of the variable invocation */
- Boolean trailingBslash; /* variable ends in \ */
- void *freeIt = NULL; /* Set if it should be freed */
- static Boolean errorReported; /* Set true if an error has already
- * been reported to prevent a plethora
- * of messages when recursing */
-
- Buf_Init(&buf, 0);
- errorReported = FALSE;
- trailingBslash = FALSE;
-
- while (*str) {
- if (*str == '\n' && trailingBslash)
- Buf_AddByte(&buf, ' ');
- if (var == NULL && (*str == '$') && (str[1] == '$')) {
- /*
- * A dollar sign may be escaped either with another dollar sign.
- * In such a case, we skip over the escape character and store the
- * dollar sign into the buffer directly.
- */
- if (save_dollars && (flags & VARF_ASSIGN))
- Buf_AddByte(&buf, *str);
- str++;
- Buf_AddByte(&buf, *str);
- str++;
- } else if (*str != '$') {
- /*
- * Skip as many characters as possible -- either to the end of
- * the string or to the next dollar sign (variable invocation).
- */
- const char *cp;
-
- for (cp = str++; *str != '$' && *str != '\0'; str++)
- continue;
- Buf_AddBytes(&buf, str - cp, cp);
- } else {
- if (var != NULL) {
- int expand;
- for (;;) {
- if (str[1] == '\0') {
- /* A trailing $ is kind of a special case */
- Buf_AddByte(&buf, str[0]);
- str++;
- expand = FALSE;
- } else if (str[1] != PROPEN && str[1] != BROPEN) {
- if (str[1] != *var || strlen(var) > 1) {
- Buf_AddBytes(&buf, 2, str);
- str += 2;
- expand = FALSE;
- }
- else
- expand = TRUE;
- break;
- }
- else {
- const char *p;
-
- /*
- * Scan up to the end of the variable name.
- */
- for (p = &str[2]; *p &&
- *p != ':' && *p != PRCLOSE && *p != BRCLOSE; p++)
- if (*p == '$')
- break;
- /*
- * A variable inside the variable. We cannot expand
- * the external variable yet, so we try again with
- * the nested one
- */
- if (*p == '$') {
- Buf_AddBytes(&buf, p - str, str);
- str = p;
- continue;
- }
-
- if (strncmp(var, str + 2, p - str - 2) != 0 ||
- var[p - str - 2] != '\0') {
- /*
- * Not the variable we want to expand, scan
- * until the next variable
- */
- for (;*p != '$' && *p != '\0'; p++)
- continue;
- Buf_AddBytes(&buf, p - str, str);
- str = p;
- expand = FALSE;
- }
- else
- expand = TRUE;
- break;
- }
- }
- if (!expand)
- continue;
- }
-
- val = Var_Parse(str, ctxt, flags, &length, &freeIt);
-
- /*
- * When we come down here, val should either point to the
- * value of this variable, suitably modified, or be NULL.
- * Length should be the total length of the potential
- * variable invocation (from $ to end character...)
- */
- if (val == var_Error || val == varNoError) {
- /*
- * If performing old-time variable substitution, skip over
- * the variable and continue with the substitution. Otherwise,
- * store the dollar sign and advance str so we continue with
- * the string...
- */
- if (oldVars) {
- str += length;
- } else if ((flags & VARF_UNDEFERR) || val == var_Error) {
- /*
- * If variable is undefined, complain and skip the
- * variable. The complaint will stop us from doing anything
- * when the file is parsed.
- */
- if (!errorReported) {
- Parse_Error(PARSE_FATAL,
- "Undefined variable \"%.*s\"",length,str);
- }
- str += length;
- errorReported = TRUE;
- } else {
- Buf_AddByte(&buf, *str);
- str += 1;
- }
- } else {
- /*
- * We've now got a variable structure to store in. But first,
- * advance the string pointer.
- */
- str += length;
-
- /*
- * Copy all the characters from the variable value straight
- * into the new string.
- */
- length = strlen(val);
- Buf_AddBytes(&buf, length, val);
- trailingBslash = length > 0 && val[length - 1] == '\\';
- }
- free(freeIt);
- freeIt = NULL;
- }
- }
-
- return Buf_DestroyCompact(&buf);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Var_GetTail --
- * Return the tail from each of a list of words. Used to set the
- * System V local variables.
- *
- * Input:
- * file Filename to modify
- *
- * Results:
- * The resulting string.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-#if 0
-char *
-Var_GetTail(char *file)
-{
- return(VarModify(file, VarTail, NULL));
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Var_GetHead --
- * Find the leading components of a (list of) filename(s).
- * XXX: VarHead does not replace foo by ., as (sun) System V make
- * does.
- *
- * Input:
- * file Filename to manipulate
- *
- * Results:
- * The leading components.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-char *
-Var_GetHead(char *file)
-{
- return(VarModify(file, VarHead, NULL));
-}
-#endif
-
-/*-
- *-----------------------------------------------------------------------
- * Var_Init --
- * Initialize the module
- *
- * Results:
- * None
- *
- * Side Effects:
- * The VAR_CMD and VAR_GLOBAL contexts are created
- *-----------------------------------------------------------------------
- */
-void
-Var_Init(void)
-{
- VAR_INTERNAL = Targ_NewGN("Internal");
- VAR_GLOBAL = Targ_NewGN("Global");
- VAR_CMD = Targ_NewGN("Command");
-
-}
-
-
-void
-Var_End(void)
-{
-}
-
-
-/****************** PRINT DEBUGGING INFO *****************/
-static void
-VarPrintVar(void *vp)
-{
- Var *v = (Var *)vp;
- fprintf(debug_file, "%-16s = %s\n", v->name, Buf_GetAll(&v->val, NULL));
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Var_Dump --
- * print all variables in a context
- *-----------------------------------------------------------------------
- */
-void
-Var_Dump(GNode *ctxt)
-{
- Hash_Search search;
- Hash_Entry *h;
-
- for (h = Hash_EnumFirst(&ctxt->context, &search);
- h != NULL;
- h = Hash_EnumNext(&search)) {
- VarPrintVar(Hash_GetValue(h));
- }
-}