diff options
Diffstat (limited to 'usr.bin/make')
61 files changed, 0 insertions, 27495 deletions
diff --git a/usr.bin/make/Makefile b/usr.bin/make/Makefile deleted file mode 100644 index b6ae9fc126918..0000000000000 --- a/usr.bin/make/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -# from: @(#)Makefile 5.2 (Berkeley) 12/28/90 -# $Id: Makefile,v 1.6 1994/06/30 05:33:39 cgd Exp $ - -PROG= make -CFLAGS+= -I${.CURDIR} -DPOSIX -SRCS= arch.c buf.c compat.c cond.c dir.c for.c hash.c job.c main.c \ - make.c parse.c str.c suff.c targ.c var.c -SRCS+= lstAppend.c lstAtEnd.c lstAtFront.c lstClose.c lstConcat.c \ - lstDatum.c lstDeQueue.c lstDestroy.c lstDupl.c lstEnQueue.c \ - lstFind.c lstFindFrom.c lstFirst.c lstForEach.c lstForEachFrom.c \ - lstInit.c lstInsert.c lstIsAtEnd.c lstIsEmpty.c lstLast.c \ - lstMember.c lstNext.c lstOpen.c lstRemove.c lstReplace.c lstSucc.c -.PATH: ${.CURDIR}/lst.lib - -.if make(install) -SUBDIR+= PSD.doc -.endif - -.include <bsd.prog.mk> diff --git a/usr.bin/make/Makefile.boot b/usr.bin/make/Makefile.boot deleted file mode 100644 index b8e8001096bfe..0000000000000 --- a/usr.bin/make/Makefile.boot +++ /dev/null @@ -1,36 +0,0 @@ -# $NetBSD: Makefile.boot,v 1.7 1996/08/30 17:59:37 thorpej 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 -# -MACHINE=sun -MACHINE_ARCH=sparc -CFLAGS= -I. -DMACHINE=\"${MACHINE}\" -DMACHINE_ARCH=\"${MACHINE_ARCH}\" \ - -DMAKE_BOOTSTRAP -LIBS= - -OBJ=arch.o buf.o compat.o cond.o dir.o for.o hash.o job.o main.o make.o \ - parse.o str.o suff.o targ.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 - -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 acac84f3edc61..0000000000000 --- a/usr.bin/make/PSD.doc/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# @(#)Makefile 8.1 (Berkeley) 8/14/93 - -DIR= psd/12.make -SRCS= tutorial.ms -MACROS= -ms - -.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 3cd869d052897..0000000000000 --- a/usr.bin/make/PSD.doc/tutorial.ms +++ /dev/null @@ -1,3732 +0,0 @@ -.\" Copyright (c) 1988, 1989 by Adam de Boor -.\" Copyright (c) 1989 by Berkeley Softworks -.\" 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. 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.4 (Berkeley) 4/28/95 -.\" -.EH 'PSD:12-%''PMake \*- A Tutorial' -.OH 'PMake \*- A Tutorial''PSD:12-%' -.\" 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. -.\" -.\" $Id: tutorial.ms,v 1.4 89/01/08 20:20:22 adam Exp Locker: adam $ -.\" -.\" @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 -.po -0.5i -.br -.mk -.nr g3 \\n(.f -.nr g4 \\n(.s -.sp -1 -.\" .st cf -\D's -1u'\D't 5u' -.sp -1 -\h'50u'\D'l 71u 0u'\D'l 50u 50u'\D'l 0u 71u'\D'l -50u 50u'\D'l -71u 0u'\D'l -50u -50u'\D'l 0u -71u'\D'l 50u -50u' -.sp -1 -\D't 3u' -.sp -1 -.sp 7u -\h'53u'\D'p 14 68u 0u 46u 46u 0u 68u -46u 46u -68u 0u -47u -46u 0u -68u 47u -46u' -.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'\D's -1u' -.br -.po -.rt -.ft \\n(g3 -.ps \\n(g4 -.. -.de Bp -.ie !\\n(.$ .IP \(bu 2 -.el .IP "\&" 2 -.. -.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 preceeding 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\-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 happpening. 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, prceeded 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 soley 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 (to find out what that -directory is, give PMake the -.B \-h -flag). -.Ix 0 ref flags -h -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 occurences 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 preceeds 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 preceeding 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 libararies 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 havok 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 occurences 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 64071dc6c535f..0000000000000 --- a/usr.bin/make/arch.c +++ /dev/null @@ -1,1091 +0,0 @@ -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * 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 lint -static char sccsid[] = "@(#)arch.c 8.3 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * 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 <ctype.h> -#include <ar.h> -#include <ranlib.h> -#include <stdio.h> -#include <stdlib.h> -#include "make.h" -#include "hash.h" -#include "dir.h" -#include "config.h" - -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 */ -} Arch; - -static int ArchFindArchive __P((ClientData, ClientData)); -static void ArchFree __P((ClientData)); -static struct ar_hdr *ArchStatMember __P((char *, char *, Boolean)); -static FILE *ArchFindMember __P((char *, char *, struct ar_hdr *, char *)); - -/*- - *----------------------------------------------------------------------- - * ArchFree -- - * Free memory used by an archive - * - * Results: - * None. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ -static void -ArchFree(ap) - ClientData ap; -{ - Arch *a = (Arch *) ap; - Hash_Search search; - Hash_Entry *entry; - - /* Free memory from hash entries */ - for (entry = Hash_EnumFirst(&a->members, &search); - entry != (Hash_Entry *)NULL; - entry = Hash_EnumNext(&search)) - free((Address) Hash_GetValue (entry)); - - free(a->name); - Hash_DeleteTable(&a->members); - free((Address) a); -} - - - -/*- - *----------------------------------------------------------------------- - * 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. - * - * 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 (linePtr, nodeLst, ctxt) - char **linePtr; /* Pointer to start of specification */ - Lst nodeLst; /* Lst on which to place the nodes */ - GNode *ctxt; /* Context in which to expand variables */ -{ - register char *cp; /* Pointer into line */ - GNode *gn; /* New node */ - char *libName; /* Library-part of specification */ - char *memName; /* Member-part of specification */ - char nameBuf[MAKE_BSIZE]; /* 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; - Boolean freeIt; - char *result; - - result=Var_Parse(cp, ctxt, TRUE, &length, &freeIt); - if (result == var_Error) { - return(FAILURE); - } else { - subLibName = TRUE; - } - - if (freeIt) { - free(result); - } - cp += length-1; - } - } - - *cp++ = '\0'; - if (subLibName) { - libName = Var_Subst(NULL, libName, ctxt, TRUE); - } - - - 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 (*cp)) { - cp++; - } - memName = cp; - while (*cp != '\0' && *cp != ')' && !isspace (*cp)) { - if (*cp == '$') { - /* - * Variable spec, so call the Var module to parse the puppy - * so we can safely advance beyond it... - */ - int length; - Boolean freeIt; - char *result; - - result=Var_Parse(cp, ctxt, TRUE, &length, &freeIt); - if (result == var_Error) { - return(FAILURE); - } else { - doSubst = TRUE; - } - - if (freeIt) { - free(result); - } - 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; - - memName = Var_Subst(NULL, memName, ctxt, TRUE); - - /* - * 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. - */ - buf = sacrifice = emalloc(strlen(memName)+strlen(libName)+3); - - sprintf(buf, "%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 == NILGNODE) { - free(buf); - return(FAILURE); - } else { - gn->type |= OP_ARCHV; - (void)Lst_AtEnd(nodeLst, (ClientData)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; - - Dir_Expand(memName, dirSearchPath, members); - while (!Lst_IsEmpty(members)) { - member = (char *)Lst_DeQueue(members); - - sprintf(nameBuf, "%s(%s)", libName, member); - free(member); - gn = Targ_FindNode (nameBuf, TARG_CREATE); - if (gn == NILGNODE) { - 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, (ClientData)gn); - } - } - Lst_Destroy(members, NOFREE); - } else { - sprintf(nameBuf, "%s(%s)", libName, memName); - gn = Targ_FindNode (nameBuf, TARG_CREATE); - if (gn == NILGNODE) { - 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, (ClientData)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 (*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. - * - * Results: - * 0 if it is, non-zero if it isn't. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ -static int -ArchFindArchive (ar, archName) - ClientData ar; /* Current list element */ - ClientData archName; /* Name we want */ -{ - return (strcmp ((char *) archName, ((Arch *) ar)->name)); -} - -/*- - *----------------------------------------------------------------------- - * ArchStatMember -- - * Locate a member of an archive, given the path of the archive and - * the path of the desired member. - * - * 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 (archive, member, hash) - char *archive; /* Path to the archive */ - char *member; /* Name of member. If it is a path, only the - * last component is used. */ - Boolean hash; /* TRUE if archive should be hashed if not - * already so. */ -{ -#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 != (char *) NULL) { - member = cp + 1; - } - - ln = Lst_Find (archives, (ClientData) archive, ArchFindArchive); - if (ln != NILLNODE) { - ar = (Arch *) Lst_Datum (ln); - - he = Hash_FindEntry (&ar->members, member); - - if (he != (Hash_Entry *) NULL) { - return ((struct ar_hdr *) Hash_GetValue (he)); - } else { - /* Try truncated name */ - char copy[AR_MAX_NAME_LEN+1]; - int 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)) - return ((struct ar_hdr *) Hash_GetValue (he)); - return ((struct ar_hdr *) 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 == (FILE *)NULL) { - return ((struct ar_hdr *)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 == (FILE *) NULL) { - return ((struct ar_hdr *) 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 ((struct ar_hdr *) NULL); - } - - ar = (Arch *)emalloc (sizeof (Arch)); - ar->name = strdup (archive); - 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... - */ - fclose (arch); - Hash_DeleteTable (&ar->members); - free ((Address)ar); - return ((struct ar_hdr *) NULL); - } else { - (void) strncpy (memName, arh.ar_name, sizeof(arh.ar_name)); - for (cp = &memName[AR_MAX_NAME_LEN]; *cp == ' '; cp--) { - continue; - } - cp[1] = '\0'; - -#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(memName[sizeof(AR_EFMT1) - 1])) { - - unsigned int elen = atoi(&memName[sizeof(AR_EFMT1)-1]); - - if (elen > MAXPATHLEN) { - fclose (arch); - Hash_DeleteTable (&ar->members); - free ((Address)ar); - return ((struct ar_hdr *) NULL); - } - if (fread (memName, elen, 1, arch) != 1) { - fclose (arch); - Hash_DeleteTable (&ar->members); - free ((Address)ar); - return ((struct ar_hdr *) NULL); - } - memName[elen] = '\0'; - fseek (arch, -elen, 1); - if (DEBUG(ARCH) || DEBUG(MAKE)) { - printf("ArchStat: Extended format entry for %s\n", memName); - } - } -#endif - - he = Hash_CreateEntry (&ar->members, memName, (Boolean *)NULL); - Hash_SetValue (he, (ClientData)emalloc (sizeof (struct ar_hdr))); - memcpy ((Address)Hash_GetValue (he), (Address)&arh, - sizeof (struct ar_hdr)); - } - /* - * 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); - fseek (arch, (size + 1) & ~1, 1); - } - - fclose (arch); - - (void) Lst_AtEnd (archives, (ClientData) 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 != (Hash_Entry *) NULL) { - return ((struct ar_hdr *) Hash_GetValue (he)); - } else { - return ((struct ar_hdr *) NULL); - } -} - -/*- - *----------------------------------------------------------------------- - * 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". - * - * 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 (archive, member, arhPtr, mode) - char *archive; /* Path to the archive */ - char *member; /* Name of member. If it is a path, only the - * last component is used. */ - struct ar_hdr *arhPtr; /* Pointer to header structure to be filled in */ - char *mode; /* The mode for opening the stream */ -{ - FILE * arch; /* Stream to archive */ - int size; /* Size of archive member */ - char *cp; /* Useful character pointer */ - char magic[SARMAG]; - int len, tlen; - - arch = fopen (archive, mode); - if (arch == (FILE *) NULL) { - return ((FILE *) 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 ((FILE *) 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 != (char *) 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 ((FILE *) 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... - */ - fseek (arch, -sizeof(struct ar_hdr), 1); - 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(arhPtr->ar_name[sizeof(AR_EFMT1) - 1])) { - - unsigned int elen = atoi(&arhPtr->ar_name[sizeof(AR_EFMT1)-1]); - char ename[MAXPATHLEN]; - - 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)) { - printf("ArchFind: Extended format entry for %s\n", ename); - } - if (strncmp(ename, member, len) == 0) { - /* Found as extended name */ - fseek (arch, -sizeof(struct ar_hdr) - elen, 1); - return (arch); - } - fseek (arch, -elen, 1); - 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); - fseek (arch, (size + 1) & ~1, 1); - } - } - - /* - * We've looked everywhere, but the member is not to be found. Close the - * archive and return NULL -- an error. - */ - fclose (arch); - return ((FILE *) NULL); -} - -/*- - *----------------------------------------------------------------------- - * Arch_Touch -- - * Touch a member of an archive. - * - * 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 (gn) - GNode *gn; /* Node of member to touch */ -{ - 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 (TARGET, gn, &p2), - &arh, "r+"); - if (p1) - free(p1); - if (p2) - free(p2); - sprintf(arh.ar_date, "%-12ld", (long) now); - - if (arch != (FILE *) 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. - * - * Results: - * None. - * - * Side Effects: - * Both the modification time of the library and of the RANLIBMAG - * member are set to 'now'. - * - *----------------------------------------------------------------------- - */ -void -Arch_TouchLib (gn) - GNode *gn; /* The node of the library to touch */ -{ - FILE * arch; /* Stream open to archive */ - struct ar_hdr arh; /* Header describing table of contents */ - struct timeval times[2]; /* Times for utimes() call */ - - arch = ArchFindMember (gn->path, RANLIBMAG, &arh, "r+"); - sprintf(arh.ar_date, "%-12ld", (long) now); - - if (arch != (FILE *) NULL) { - (void)fwrite ((char *)&arh, sizeof (struct ar_hdr), 1, arch); - fclose (arch); - - times[0].tv_sec = times[1].tv_sec = now; - times[0].tv_usec = times[1].tv_usec = 0; - utimes(gn->path, times); - } -} - -/*- - *----------------------------------------------------------------------- - * Arch_MTime -- - * Return the modification time of a member of an archive. - * - * Results: - * The modification time (seconds). - * - * Side Effects: - * The mtime field of the given node is filled in with the value - * returned by the function. - * - *----------------------------------------------------------------------- - */ -int -Arch_MTime (gn) - GNode *gn; /* Node describing archive member */ -{ - struct ar_hdr *arhPtr; /* Header of desired member */ - int modTime; /* Modification time as an integer */ - char *p1, *p2; - - arhPtr = ArchStatMember (Var_Value (ARCHIVE, gn, &p1), - Var_Value (TARGET, gn, &p2), - TRUE); - if (p1) - free(p1); - if (p2) - free(p2); - - if (arhPtr != (struct ar_hdr *) NULL) { - modTime = (int) 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. - * - *----------------------------------------------------------------------- - */ -int -Arch_MemMTime (gn) - 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)) != NILLNODE) { - 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->make && - strncmp(nameStart, gn->name, nameEnd - nameStart) == 0) { - gn->mtime = Arch_MTime(pgn); - } - } else if (pgn->make) { - /* - * 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. - * - * 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 (gn, path) - GNode *gn; /* Node of library to find */ - Lst path; /* Search path */ -{ - char *libName; /* file name for archive */ - - libName = (char *)emalloc (strlen (gn->name) + 6 - 2); - sprintf(libName, "lib%s.a", &gn->name[2]); - - gn->path = Dir_FindFile (libName, path); - - free (libName); - -#ifdef LIBRARIES - Var_Set (TARGET, gn->name, gn); -#else - Var_Set (TARGET, gn->path == (char *) NULL ? gn->name : gn->path, gn); -#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->cmtime). - * 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. - * - * 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 (gn) - GNode *gn; /* The library's graph node */ -{ - Boolean oodate; - - if (OP_NOP(gn->type) && Lst_IsEmpty(gn->children)) { - oodate = FALSE; - } else if ((gn->mtime > now) || (gn->mtime < gn->cmtime)) { - oodate = TRUE; - } else { - struct ar_hdr *arhPtr; /* Header for __.SYMDEF */ - int modTimeTOC; /* The table-of-contents's mod time */ - - arhPtr = ArchStatMember (gn->path, RANLIBMAG, FALSE); - - if (arhPtr != (struct ar_hdr *)NULL) { - modTimeTOC = (int) strtol(arhPtr->ar_date, NULL, 10); - - if (DEBUG(ARCH) || DEBUG(MAKE)) { - printf("%s modified %s...", RANLIBMAG, Targ_FmtTime(modTimeTOC)); - } - oodate = (gn->cmtime > modTimeTOC); - } else { - /* - * A library w/o a table of contents is out-of-date - */ - if (DEBUG(ARCH) || DEBUG(MAKE)) { - printf("No t.o.c...."); - } - oodate = TRUE; - } - } - return (oodate); -} - -/*- - *----------------------------------------------------------------------- - * Arch_Init -- - * Initialize things for this module. - * - * Results: - * None. - * - * Side Effects: - * The 'archives' list is initialized. - * - *----------------------------------------------------------------------- - */ -void -Arch_Init () -{ - archives = Lst_Init (FALSE); -} - - - -/*- - *----------------------------------------------------------------------- - * Arch_End -- - * Cleanup things for this module. - * - * Results: - * None. - * - * Side Effects: - * The 'archives' list is freed - * - *----------------------------------------------------------------------- - */ -void -Arch_End () -{ - Lst_Destroy(archives, ArchFree); -} diff --git a/usr.bin/make/bit.h b/usr.bin/make/bit.h deleted file mode 100644 index 53b3745a2515c..0000000000000 --- a/usr.bin/make/bit.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * 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. - * - * @(#)bit.h 8.2 (Berkeley) 4/28/95 - */ - -/* - * bit.h -- - * - * Definition of macros for setting and clearing bits in an array - * of integers. - * - * It is assumed that "int" is 32 bits wide. - */ - -#ifndef _BIT -#define _BIT - -#include "sprite.h" - -#define BIT_NUM_BITS_PER_INT 32 -#define BIT_NUM_BITS_PER_BYTE 8 - -#define Bit_NumInts(numBits) \ - (((numBits)+BIT_NUM_BITS_PER_INT -1)/BIT_NUM_BITS_PER_INT) - -#define Bit_NumBytes(numBits) \ - (Bit_NumInts(numBits) * sizeof(int)) - -#define Bit_Alloc(numBits, bitArrayPtr) \ - bitArrayPtr = (int *)malloc((unsigned)Bit_NumBytes(numBits)); \ - Bit_Zero((numBits), (bitArrayPtr)) - -#define Bit_Free(bitArrayPtr) \ - free((char *)bitArrayPtr) - -#define Bit_Set(numBits, bitArrayPtr) \ - ((bitArrayPtr)[(numBits)/BIT_NUM_BITS_PER_INT] |= \ - (1 << ((numBits) % BIT_NUM_BITS_PER_INT))) - -#define Bit_IsSet(numBits, bitArrayPtr) \ - ((bitArrayPtr)[(numBits)/BIT_NUM_BITS_PER_INT] & \ - (1 << ((numBits) % BIT_NUM_BITS_PER_INT))) - -#define Bit_Clear(numBits, bitArrayPtr) \ - ((bitArrayPtr)[(numBits)/BIT_NUM_BITS_PER_INT] &= \ - ~(1 << ((numBits) % BIT_NUM_BITS_PER_INT))) - -#define Bit_IsClear(numBits, bitArrayPtr) \ - (!(Bit_IsSet((numBits), (bitArrayPtr)))) - -#define Bit_Copy(numBits, srcArrayPtr, destArrayPtr) \ - bcopy((char *)(srcArrayPtr), (char *)(destArrayPtr), \ - Bit_NumBytes(numBits)) - -#define Bit_Zero(numBits, bitArrayPtr) \ - bzero((char *)(bitArrayPtr), Bit_NumBytes(numBits)) - -extern int Bit_FindFirstSet(); -extern int Bit_FindFirstClear(); -extern Boolean Bit_Intersect(); -extern Boolean Bit_Union(); -extern Boolean Bit_AnySet(); -extern int *Bit_Expand(); - -#endif /* _BIT */ diff --git a/usr.bin/make/buf.c b/usr.bin/make/buf.c deleted file mode 100644 index 68a534db14bcc..0000000000000 --- a/usr.bin/make/buf.c +++ /dev/null @@ -1,436 +0,0 @@ -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * 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 lint -static char sccsid[] = "@(#)buf.c 8.2 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * buf.c -- - * Functions for automatically-expanded buffers. - */ - -#include "sprite.h" -#include "make.h" -#include "buf.h" - -#ifndef max -#define max(a,b) ((a) > (b) ? (a) : (b)) -#endif - -/* - * BufExpand -- - * Expand the given buffer to hold the given number of additional - * bytes. - * Makes sure there's room for an extra NULL byte at the end of the - * buffer in case it holds a string. - */ -#define BufExpand(bp,nb) \ - if (bp->left < (nb)+1) {\ - int newSize = (bp)->size + max((nb)+1,BUF_ADD_INC); \ - Byte *newBuf = (Byte *) realloc((bp)->buffer, newSize); \ - \ - (bp)->inPtr = newBuf + ((bp)->inPtr - (bp)->buffer); \ - (bp)->outPtr = newBuf + ((bp)->outPtr - (bp)->buffer);\ - (bp)->buffer = newBuf;\ - (bp)->size = newSize;\ - (bp)->left = newSize - ((bp)->inPtr - (bp)->buffer);\ - } - -#define BUF_DEF_SIZE 256 /* Default buffer size */ -#define BUF_ADD_INC 256 /* Expansion increment when Adding */ -#define BUF_UNGET_INC 16 /* Expansion increment when Ungetting */ - -/*- - *----------------------------------------------------------------------- - * Buf_OvAddByte -- - * Add a single byte to the buffer. left is zero or negative. - * - * Results: - * None. - * - * Side Effects: - * The buffer may be expanded. - * - *----------------------------------------------------------------------- - */ -void -Buf_OvAddByte (bp, byte) - register Buffer bp; - int byte; -{ - int nbytes = 1; - bp->left = 0; - BufExpand (bp, nbytes); - - *bp->inPtr++ = byte; - bp->left--; - - /* - * Null-terminate - */ - *bp->inPtr = 0; -} - -/*- - *----------------------------------------------------------------------- - * Buf_AddBytes -- - * Add a number of bytes to the buffer. - * - * Results: - * None. - * - * Side Effects: - * Guess what? - * - *----------------------------------------------------------------------- - */ -void -Buf_AddBytes (bp, numBytes, bytesPtr) - register Buffer bp; - int numBytes; - Byte *bytesPtr; -{ - - BufExpand (bp, numBytes); - - memcpy (bp->inPtr, bytesPtr, numBytes); - bp->inPtr += numBytes; - bp->left -= numBytes; - - /* - * Null-terminate - */ - *bp->inPtr = 0; -} - -/*- - *----------------------------------------------------------------------- - * Buf_UngetByte -- - * Place the byte back at the beginning of the buffer. - * - * Results: - * SUCCESS if the byte was added ok. FAILURE if not. - * - * Side Effects: - * The byte is stuffed in the buffer and outPtr is decremented. - * - *----------------------------------------------------------------------- - */ -void -Buf_UngetByte (bp, byte) - register Buffer bp; - int byte; -{ - - if (bp->outPtr != bp->buffer) { - bp->outPtr--; - *bp->outPtr = byte; - } else if (bp->outPtr == bp->inPtr) { - *bp->inPtr = byte; - bp->inPtr++; - bp->left--; - *bp->inPtr = 0; - } else { - /* - * Yech. have to expand the buffer to stuff this thing in. - * We use a different expansion constant because people don't - * usually push back many bytes when they're doing it a byte at - * a time... - */ - int numBytes = bp->inPtr - bp->outPtr; - Byte *newBuf; - - newBuf = (Byte *)emalloc(bp->size + BUF_UNGET_INC); - memcpy ((char *)(newBuf+BUF_UNGET_INC), (char *)bp->outPtr, numBytes+1); - bp->outPtr = newBuf + BUF_UNGET_INC; - bp->inPtr = bp->outPtr + numBytes; - free ((char *)bp->buffer); - bp->buffer = newBuf; - bp->size += BUF_UNGET_INC; - bp->left = bp->size - (bp->inPtr - bp->buffer); - bp->outPtr -= 1; - *bp->outPtr = byte; - } -} - -/*- - *----------------------------------------------------------------------- - * Buf_UngetBytes -- - * Push back a series of bytes at the beginning of the buffer. - * - * Results: - * None. - * - * Side Effects: - * outPtr is decremented and the bytes copied into the buffer. - * - *----------------------------------------------------------------------- - */ -void -Buf_UngetBytes (bp, numBytes, bytesPtr) - register Buffer bp; - int numBytes; - Byte *bytesPtr; -{ - - if (bp->outPtr - bp->buffer >= numBytes) { - bp->outPtr -= numBytes; - memcpy (bp->outPtr, bytesPtr, numBytes); - } else if (bp->outPtr == bp->inPtr) { - Buf_AddBytes (bp, numBytes, bytesPtr); - } else { - int curNumBytes = bp->inPtr - bp->outPtr; - Byte *newBuf; - int newBytes = max(numBytes,BUF_UNGET_INC); - - newBuf = (Byte *)emalloc (bp->size + newBytes); - memcpy((char *)(newBuf+newBytes), (char *)bp->outPtr, curNumBytes+1); - bp->outPtr = newBuf + newBytes; - bp->inPtr = bp->outPtr + curNumBytes; - free ((char *)bp->buffer); - bp->buffer = newBuf; - bp->size += newBytes; - bp->left = bp->size - (bp->inPtr - bp->buffer); - bp->outPtr -= numBytes; - memcpy ((char *)bp->outPtr, (char *)bytesPtr, numBytes); - } -} - -/*- - *----------------------------------------------------------------------- - * Buf_GetByte -- - * Return the next byte from the buffer. Actually returns an integer. - * - * Results: - * Returns BUF_ERROR if there's no byte in the buffer, or the byte - * itself if there is one. - * - * Side Effects: - * outPtr is incremented and both outPtr and inPtr will be reset if - * the buffer is emptied. - * - *----------------------------------------------------------------------- - */ -int -Buf_GetByte (bp) - register Buffer bp; -{ - int res; - - if (bp->inPtr == bp->outPtr) { - return (BUF_ERROR); - } else { - res = (int) *bp->outPtr; - bp->outPtr += 1; - if (bp->outPtr == bp->inPtr) { - bp->outPtr = bp->inPtr = bp->buffer; - bp->left = bp->size; - *bp->inPtr = 0; - } - return (res); - } -} - -/*- - *----------------------------------------------------------------------- - * Buf_GetBytes -- - * Extract a number of bytes from the buffer. - * - * Results: - * The number of bytes gotten. - * - * Side Effects: - * The passed array is overwritten. - * - *----------------------------------------------------------------------- - */ -int -Buf_GetBytes (bp, numBytes, bytesPtr) - register Buffer bp; - int numBytes; - Byte *bytesPtr; -{ - - if (bp->inPtr - bp->outPtr < numBytes) { - numBytes = bp->inPtr - bp->outPtr; - } - memcpy (bytesPtr, bp->outPtr, numBytes); - bp->outPtr += numBytes; - - if (bp->outPtr == bp->inPtr) { - bp->outPtr = bp->inPtr = bp->buffer; - bp->left = bp->size; - *bp->inPtr = 0; - } - return (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 (bp, numBytesPtr) - register Buffer bp; - int *numBytesPtr; -{ - - if (numBytesPtr != (int *)NULL) { - *numBytesPtr = bp->inPtr - bp->outPtr; - } - - return (bp->outPtr); -} - -/*- - *----------------------------------------------------------------------- - * Buf_Discard -- - * Throw away bytes in a buffer. - * - * Results: - * None. - * - * Side Effects: - * The bytes are discarded. - * - *----------------------------------------------------------------------- - */ -void -Buf_Discard (bp, numBytes) - register Buffer bp; - int numBytes; -{ - - if (bp->inPtr - bp->outPtr <= numBytes) { - bp->inPtr = bp->outPtr = bp->buffer; - bp->left = bp->size; - *bp->inPtr = 0; - } else { - bp->outPtr += numBytes; - } -} - -/*- - *----------------------------------------------------------------------- - * Buf_Size -- - * Returns the number of bytes in the given buffer. Doesn't include - * the null-terminating byte. - * - * Results: - * The number of bytes. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ -int -Buf_Size (buf) - Buffer buf; -{ - return (buf->inPtr - buf->outPtr); -} - -/*- - *----------------------------------------------------------------------- - * Buf_Init -- - * Initialize a buffer. If no initial size is given, a reasonable - * default is used. - * - * Results: - * A buffer to be given to other functions in this library. - * - * Side Effects: - * The buffer is created, the space allocated and pointers - * initialized. - * - *----------------------------------------------------------------------- - */ -Buffer -Buf_Init (size) - int size; /* Initial size for the buffer */ -{ - Buffer bp; /* New Buffer */ - - bp = (Buffer)emalloc(sizeof(*bp)); - - if (size <= 0) { - size = BUF_DEF_SIZE; - } - bp->left = bp->size = size; - bp->buffer = (Byte *)emalloc(size); - bp->inPtr = bp->outPtr = bp->buffer; - *bp->inPtr = 0; - - return (bp); -} - -/*- - *----------------------------------------------------------------------- - * Buf_Destroy -- - * Nuke a buffer and all its resources. - * - * Results: - * None. - * - * Side Effects: - * The buffer is freed. - * - *----------------------------------------------------------------------- - */ -void -Buf_Destroy (buf, freeData) - Buffer buf; /* Buffer to destroy */ - Boolean freeData; /* TRUE if the data should be destroyed as well */ -{ - - if (freeData) { - free ((char *)buf->buffer); - } - free ((char *)buf); -} diff --git a/usr.bin/make/buf.h b/usr.bin/make/buf.h deleted file mode 100644 index 33313b8ff0ea9..0000000000000 --- a/usr.bin/make/buf.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * 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. - * - * @(#)buf.h 8.2 (Berkeley) 4/28/95 - */ - -/*- - * buf.h -- - * Header for users of the buf library. - */ - -#ifndef _BUF_H -#define _BUF_H - -#include "sprite.h" - -typedef char Byte; - -typedef struct Buffer { - int size; /* Current size of the buffer */ - int left; /* Space left (== size - (inPtr - buffer)) */ - Byte *buffer; /* The buffer itself */ - Byte *inPtr; /* Place to write to */ - Byte *outPtr; /* Place to read from */ -} *Buffer; - -/* Buf_AddByte adds a single byte to a buffer. */ -#define Buf_AddByte(bp, byte) \ - (void) (--(bp)->left <= 0 ? Buf_OvAddByte(bp, byte), 1 : \ - (*(bp)->inPtr++ = (byte), *(bp)->inPtr = 0), 1) - -#define BUF_ERROR 256 - -void Buf_OvAddByte __P((Buffer, int)); -void Buf_AddBytes __P((Buffer, int, Byte *)); -void Buf_UngetByte __P((Buffer, int)); -void Buf_UngetBytes __P((Buffer, int, Byte *)); -int Buf_GetByte __P((Buffer)); -int Buf_GetBytes __P((Buffer, int, Byte *)); -Byte *Buf_GetAll __P((Buffer, int *)); -void Buf_Discard __P((Buffer, int)); -int Buf_Size __P((Buffer)); -Buffer Buf_Init __P((int)); -void Buf_Destroy __P((Buffer, Boolean)); - -#endif /* _BUF_H */ diff --git a/usr.bin/make/compat.c b/usr.bin/make/compat.c deleted file mode 100644 index 9cab63c073454..0000000000000 --- a/usr.bin/make/compat.c +++ /dev/null @@ -1,650 +0,0 @@ -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * 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 lint -static char sccsid[] = "@(#)compat.c 8.3 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * 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 <stdio.h> -#include <sys/types.h> -#include <sys/signal.h> -#include <sys/wait.h> -#include <sys/errno.h> -#include <sys/stat.h> -#include <ctype.h> -#include "make.h" -#include "hash.h" -#include "dir.h" -#include "job.h" -extern int errno; - -/* - * 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. - */ - -static char meta[256]; - -static GNode *curTarg = NILGNODE; -static GNode *ENDNode; -static void CompatInterrupt __P((int)); -static int CompatRunCommand __P((ClientData, ClientData)); -static int CompatMake __P((ClientData, ClientData)); - -/*- - *----------------------------------------------------------------------- - * 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.. - * - *----------------------------------------------------------------------- - */ -static void -CompatInterrupt (signo) - int signo; -{ - GNode *gn; - - if ((curTarg != NILGNODE) && !Targ_Precious (curTarg)) { - char *p1; - char *file = Var_Value (TARGET, curTarg, &p1); - struct stat st; - - if (!noExecute && lstat(file, &st) != -1 && !S_ISDIR(st.st_mode) && - unlink(file) != -1) { - printf ("*** %s removed\n", file); - } - if (p1) - free(p1); - - /* - * Run .INTERRUPT only if hit with interrupt signal - */ - if (signo == SIGINT) { - gn = Targ_FindNode(".INTERRUPT", TARG_NOCREATE); - if (gn != NILGNODE) { - Lst_ForEach(gn->commands, CompatRunCommand, (ClientData)gn); - } - } - - } - exit (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. - * - * Results: - * 0 if the command succeeded, 1 if an error occurred. - * - * Side Effects: - * The node's 'made' field may be set to ERROR. - * - *----------------------------------------------------------------------- - */ -static int -CompatRunCommand (cmdp, gnp) - ClientData cmdp; /* Command to execute */ - ClientData gnp; /* Node from which the command came */ -{ - char *cmdStart; /* Start of expanded command */ - register char *cp; - Boolean silent, /* Don't print command */ - errCheck; /* Check errors */ - union wait reason; /* Reason for child's death */ - int status; /* Description of child's death */ - int cpid; /* Child actually found */ - ReturnStatus stat; /* Status of fork */ - LstNode cmdNode; /* Node where current command is located */ - char **av; /* Argument vector for thing to exec */ - int argc; /* Number of arguments in av or 0 if not - * dynamically allocated */ - Boolean local; /* TRUE if command should be executed - * locally */ - char *cmd = (char *) cmdp; - GNode *gn = (GNode *) gnp; - - /* - * Avoid clobbered variable warnings by forcing the compiler - * to ``unregister'' variables - */ -#if __GNUC__ - (void) &av; - (void) &errCheck; -#endif - silent = gn->type & OP_SILENT; - errCheck = !(gn->type & OP_IGNORE); - - cmdNode = Lst_Member (gn->commands, (ClientData)cmd); - cmdStart = Var_Subst (NULL, cmd, gn, FALSE); - - /* - * brk_string will return an argv with a NULL in av[1], 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); - Error("%s expands to empty string", cmd); - return(0); - } else { - cmd = cmdStart; - } - Lst_Replace (cmdNode, (ClientData)cmdStart); - - if ((gn->type & OP_SAVE_CMDS) && (gn != ENDNode)) { - (void)Lst_AtEnd(ENDNode->commands, (ClientData)cmdStart); - return(0); - } else if (strcmp(cmdStart, "...") == 0) { - gn->type |= OP_SAVE_CMDS; - return(0); - } - - while ((*cmd == '@') || (*cmd == '-')) { - if (*cmd == '@') { - silent = TRUE; - } else { - errCheck = FALSE; - } - cmd++; - } - - while (isspace((unsigned char)*cmd)) - cmd++; - - /* - * 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. - */ - for (cp = cmd; !meta[(unsigned char)*cp]; cp++) { - continue; - } - - /* - * 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) { - printf ("%s\n", cmd); - fflush(stdout); - } - - /* - * If we're not supposed to execute any commands, this is as far as - * we go... - */ - if (noExecute) { - return (0); - } - - if (*cp != '\0') { - /* - * If *cp isn't the null character, we hit a "meta" character and - * need to pass the command off to the shell. We give the shell the - * -e flag as well as -c if it's supposed to exit when it hits an - * error. - */ - static char *shargv[4] = { "/bin/sh" }; - - shargv[1] = (errCheck ? "-ec" : "-c"); - shargv[2] = cmd; - shargv[3] = (char *)NULL; - av = shargv; - argc = 0; - } else { - /* - * No meta-characters, so no need to exec a shell. Break the command - * into words to form an argument vector we can execute. - * brk_string sticks our name in av[0], so we have to - * skip over it... - */ - av = brk_string(cmd, &argc, TRUE); - av += 1; - } - - local = TRUE; - - /* - * Fork and execute the single command. If the fork fails, we abort. - */ - cpid = vfork(); - if (cpid < 0) { - Fatal("Could not fork"); - } - if (cpid == 0) { - if (local) { - execvp(av[0], av); - (void) write (2, av[0], strlen (av[0])); - (void) write (2, ": not found\n", sizeof(": not found")); - } else { - (void)execv(av[0], av); - } - exit(1); - } - free(cmdStart); - Lst_Replace (cmdNode, (ClientData) NULL); - - /* - * The child is off and running. Now all we can do is wait... - */ - while (1) { - - while ((stat = wait((int *)&reason)) != cpid) { - if (stat == -1 && errno != EINTR) { - break; - } - } - - if (stat > -1) { - if (WIFSTOPPED(reason)) { - status = reason.w_stopval; /* stopped */ - } else if (WIFEXITED(reason)) { - status = reason.w_retcode; /* exited */ - if (status != 0) { - printf ("*** Error code %d", status); - } - } else { - status = reason.w_termsig; /* signaled */ - printf ("*** Signal %d", status); - } - - - if (!WIFEXITED(reason) || (status != 0)) { - if (errCheck) { - gn->made = ERROR; - if (keepgoing) { - /* - * Abort the current target, but let others - * continue. - */ - printf (" (continuing)\n"); - } - } 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", stat); - /*NOTREACHED*/ - } - } - - return (status); -} - -/*- - *----------------------------------------------------------------------- - * CompatMake -- - * Make a target. - * - * Results: - * 0 - * - * Side Effects: - * If an error is detected and not being ignored, the process exits. - * - *----------------------------------------------------------------------- - */ -static int -CompatMake (gnp, pgnp) - ClientData gnp; /* The node to make */ - ClientData pgnp; /* Parent to abort if necessary */ -{ - GNode *gn = (GNode *) gnp; - GNode *pgn = (GNode *) pgnp; - if (gn->type & OP_USE) { - Make_HandleUse(gn, pgn); - } else if (gn->made == UNMADE) { - /* - * 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->make = TRUE; - gn->made = BEINGMADE; - Suff_FindDeps (gn); - Lst_ForEach (gn->children, CompatMake, (ClientData)gn); - if (!gn->make) { - gn->made = ABORTED; - pgn->make = FALSE; - return (0); - } - - if (Lst_Member (gn->iParents, pgn) != NILLNODE) { - char *p1; - Var_Set (IMPSRC, Var_Value(TARGET, gn, &p1), pgn); - if (p1) - free(p1); - } - - /* - * All the children were made ok. Now cmtime 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)) { - printf("Examining %s...", gn->name); - } - if (! Make_OODate(gn)) { - gn->made = UPTODATE; - if (DEBUG(MAKE)) { - printf("up-to-date.\n"); - } - return (0); - } else if (DEBUG(MAKE)) { - printf("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) { - curTarg = gn; - Lst_ForEach (gn->commands, CompatRunCommand, (ClientData)gn); - curTarg = NILGNODE; - } else { - Job_Touch (gn, gn->type & OP_SILENT); - } - } else { - gn->made = ERROR; - } - - 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; -#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 (and the speed of this program), there are times - * when the modification time of a file created on a remote - * machine will not be modified before the 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 - */ - if (noExecute || Dir_MTime(gn) == 0) { - gn->mtime = now; - } - if (gn->cmtime > gn->mtime) - gn->mtime = gn->cmtime; - if (DEBUG(MAKE)) { - printf("update time: %s\n", Targ_FmtTime(gn->mtime)); - } -#endif - if (!(gn->type & OP_EXEC)) { - pgn->childMade = TRUE; - Make_TimeStamp(pgn, gn); - } - } else if (keepgoing) { - pgn->make = FALSE; - } else { - printf ("\n\nStop.\n"); - exit (1); - } - } else if (gn->made == ERROR) { - /* - * Already had an error when making this beastie. Tell the parent - * to abort. - */ - pgn->make = FALSE; - } else { - if (Lst_Member (gn->iParents, pgn) != NILLNODE) { - char *p1; - Var_Set (IMPSRC, Var_Value(TARGET, gn, &p1), pgn); - if (p1) - free(p1); - } - switch(gn->made) { - case BEINGMADE: - Error("Graph cycles through %s\n", gn->name); - gn->made = ERROR; - pgn->make = FALSE; - break; - case MADE: - if ((gn->type & OP_EXEC) == 0) { - pgn->childMade = TRUE; - Make_TimeStamp(pgn, gn); - } - break; - case UPTODATE: - if ((gn->type & OP_EXEC) == 0) { - Make_TimeStamp(pgn, gn); - } - break; - default: - break; - } - } - - return (0); -} - -/*- - *----------------------------------------------------------------------- - * Compat_Run -- - * Initialize this mode and start making. - * - * Results: - * None. - * - * Side Effects: - * Guess what? - * - *----------------------------------------------------------------------- - */ -void -Compat_Run(targs) - Lst targs; /* List of target nodes to re-create */ -{ - char *cp; /* Pointer to string of shell meta-characters */ - GNode *gn = NULL;/* Current root target */ - int errors; /* Number of targets not remade due to errors */ - - if (signal(SIGINT, SIG_IGN) != SIG_IGN) { - signal(SIGINT, CompatInterrupt); - } - if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { - signal(SIGTERM, CompatInterrupt); - } - if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { - signal(SIGHUP, CompatInterrupt); - } - if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) { - signal(SIGQUIT, CompatInterrupt); - } - - for (cp = "#=|^(){};&<>*?[]:$`\\\n"; *cp != '\0'; cp++) { - meta[(unsigned char) *cp] = 1; - } - /* - * The null character serves as a sentinel in the string. - */ - meta[0] = 1; - - ENDNode = Targ_FindNode(".END", TARG_CREATE); - /* - * If the user has defined a .BEGIN target, execute the commands attached - * to it. - */ - if (!queryFlag) { - gn = Targ_FindNode(".BEGIN", TARG_NOCREATE); - if (gn != NILGNODE) { - Lst_ForEach(gn->commands, CompatRunCommand, (ClientData)gn); - } - } - - /* - * For each entry in the list of targets to create, call CompatMake on - * it to create the thing. CompatMake 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); - CompatMake (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) { - Lst_ForEach(ENDNode->commands, CompatRunCommand, (ClientData)gn); - } -} diff --git a/usr.bin/make/cond.c b/usr.bin/make/cond.c deleted file mode 100644 index 6ea0d6a3d4765..0000000000000 --- a/usr.bin/make/cond.c +++ /dev/null @@ -1,1252 +0,0 @@ -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * 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 lint -static char sccsid[] = "@(#)cond.c 8.3 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * cond.c -- - * Functions to handle conditionals in a makefile. - * - * Interface: - * Cond_Eval Evaluate the conditional in the passed line. - * - */ - -#include <ctype.h> -#include <math.h> -#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 -> symbol - * T -> $(varspec) op value - * T -> $(varspec) == "string" - * T -> $(varspec) != "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 And for '&' and '&&', Or for '|' and '||', Not for '!', - * LParen for '(', 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 True or False. - * - * All Non-Terminal functions (CondE, CondF and CondT) return Err on error. - */ -typedef enum { - And, Or, Not, True, False, LParen, RParen, EndOfFile, None, Err -} Token; - -/*- - * Structures to handle elegantly the different forms of #if's. The - * last two fields are stored in condInvert and condDefProc, respectively. - */ -static int CondGetArg __P((char **, char **, char *, Boolean)); -static Boolean CondDoDefined __P((int, char *)); -static int CondStrMatch __P((ClientData, ClientData)); -static Boolean CondDoMake __P((int, char *)); -static Boolean CondDoExists __P((int, char *)); -static Boolean CondDoTarget __P((int, char *)); -static Boolean CondCvtArg __P((char *, double *)); -static Token CondToken __P((Boolean)); -static Token CondT __P((Boolean)); -static Token CondF __P((Boolean)); -static Token CondE __P((Boolean)); - -static struct If { - char *form; /* Form of if */ - int formlen; /* Length of form */ - Boolean doNot; /* TRUE if default function should be negated */ - Boolean (*defProc)(); /* Default function to apply */ -} ifs[] = { - { "ifdef", 5, FALSE, CondDoDefined }, - { "ifndef", 6, TRUE, CondDoDefined }, - { "ifmake", 6, FALSE, CondDoMake }, - { "ifnmake", 7, TRUE, CondDoMake }, - { "if", 2, FALSE, CondDoDefined }, - { (char *)0, 0, FALSE, (Boolean (*)())0 } -}; - -static Boolean condInvert; /* Invert the default function */ -static Boolean (*condDefProc)(); /* Default function to apply */ -static char *condExpr; /* The expression to parse */ -static Token condPushBack=None; /* Single push-back token used in - * parsing */ - -#define MAXIF 30 /* greatest depth of #if'ing */ - -static Boolean condStack[MAXIF]; /* Stack of conditionals's values */ -static int condTop = MAXIF; /* Top-most conditional */ -static int skipIfLevel=0; /* Depth of skipped conditionals */ -static Boolean skipLine = FALSE; /* Whether the parse module is skipping - * lines */ - -/*- - *----------------------------------------------------------------------- - * CondPushBack -- - * Push back the most recent token read. We only need one level of - * this, so the thing is just stored in 'condPushback'. - * - * Results: - * None. - * - * Side Effects: - * condPushback is overwritten. - * - *----------------------------------------------------------------------- - */ -static void -CondPushBack (t) - Token t; /* Token to push back into the "stream" */ -{ - condPushBack = t; -} - -/*- - *----------------------------------------------------------------------- - * CondGetArg -- - * Find the argument of a built-in function. - * - * 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 (linePtr, argPtr, func, parens) - char **linePtr; - char **argPtr; - char *func; - Boolean parens; /* TRUE if arg should be bounded by parens */ -{ - register char *cp; - int argLen; - register Buffer buf; - - cp = *linePtr; - if (parens) { - while (*cp != '(' && *cp != '\0') { - cp++; - } - if (*cp == '(') { - 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 = cp; - 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 = Buf_Init(16); - - while ((strchr(" \t)&|", *cp) == (char *)NULL) && (*cp != '\0')) { - 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; - Boolean doFree; - - cp2 = Var_Parse(cp, VAR_CMD, TRUE, &len, &doFree); - - Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2); - if (doFree) { - free(cp2); - } - cp += len; - } else { - Buf_AddByte(buf, (Byte)*cp); - cp++; - } - } - - Buf_AddByte(buf, (Byte)'\0'); - *argPtr = (char *)Buf_GetAll(buf, &argLen); - Buf_Destroy(buf, FALSE); - - while (*cp == ' ' || *cp == '\t') { - cp++; - } - if (parens && *cp != ')') { - Parse_Error (PARSE_WARNING, "Missing closing parenthesis for %s()", - func); - return (0); - } else if (parens) { - /* - * Advance pointer past close parenthesis. - */ - cp++; - } - - *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 (argLen, arg) - int argLen; - char *arg; -{ - char savec = arg[argLen]; - char *p1; - Boolean result; - - arg[argLen] = '\0'; - if (Var_Value (arg, VAR_CMD, &p1) != (char *)NULL) { - result = TRUE; - } else { - result = FALSE; - } - if (p1) - free(p1); - arg[argLen] = savec; - 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(string, pattern) - ClientData string; - ClientData pattern; -{ - return(!Str_Match((char *) string,(char *) pattern)); -} - -/*- - *----------------------------------------------------------------------- - * CondDoMake -- - * Handle the 'make' function for conditionals. - * - * Results: - * TRUE if the given target is being made. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ -static Boolean -CondDoMake (argLen, arg) - int argLen; - char *arg; -{ - char savec = arg[argLen]; - Boolean result; - - arg[argLen] = '\0'; - if (Lst_Find (create, (ClientData)arg, CondStrMatch) == NILLNODE) { - result = FALSE; - } else { - result = TRUE; - } - arg[argLen] = savec; - return (result); -} - -/*- - *----------------------------------------------------------------------- - * 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 (argLen, arg) - int argLen; - char *arg; -{ - char savec = arg[argLen]; - Boolean result; - char *path; - - arg[argLen] = '\0'; - path = Dir_FindFile(arg, dirSearchPath); - if (path != (char *)NULL) { - result = TRUE; - free(path); - } else { - result = FALSE; - } - arg[argLen] = savec; - 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 (argLen, arg) - int argLen; - char *arg; -{ - char savec = arg[argLen]; - Boolean result; - GNode *gn; - - arg[argLen] = '\0'; - gn = Targ_FindNode(arg, TARG_NOCREATE); - if ((gn != NILGNODE) && !OP_NOP(gn->type)) { - result = TRUE; - } else { - result = FALSE; - } - arg[argLen] = savec; - return (result); -} - - -/*- - *----------------------------------------------------------------------- - * CondCvtArg -- - * Convert the given number into a double. If the number begins - * with 0x, it is interpreted as a hexadecimal integer - * and converted to a double from there. All other strings just have - * strtod called on them. - * - * Results: - * Sets 'value' to double value of string. - * Returns true if the string was a valid number, false o.w. - * - * Side Effects: - * Can change 'value' even if string is not a valid number. - * - * - *----------------------------------------------------------------------- - */ -static Boolean -CondCvtArg(str, value) - register char *str; - double *value; -{ - if ((*str == '0') && (str[1] == 'x')) { - register long i; - - for (str += 2, i = 0; *str; str++) { - int x; - if (isdigit((unsigned char) *str)) - x = *str - '0'; - else if (isxdigit((unsigned char) *str)) - x = 10 + *str - isupper((unsigned char) *str) ? 'A' : 'a'; - else - return FALSE; - i = (i << 4) + x; - } - *value = (double) i; - return TRUE; - } - else { - char *eptr; - *value = strtod(str, &eptr); - return *eptr == '\0'; - } -} - -/*- - *----------------------------------------------------------------------- - * 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 None if it is used. - * - *----------------------------------------------------------------------- - */ -static Token -CondToken(doEval) - Boolean doEval; -{ - Token t; - - if (condPushBack == None) { - while (*condExpr == ' ' || *condExpr == '\t') { - condExpr++; - } - switch (*condExpr) { - case '(': - t = LParen; - condExpr++; - break; - case ')': - t = RParen; - condExpr++; - break; - case '|': - if (condExpr[1] == '|') { - condExpr++; - } - condExpr++; - t = Or; - break; - case '&': - if (condExpr[1] == '&') { - condExpr++; - } - condExpr++; - t = And; - break; - case '!': - t = Not; - condExpr++; - break; - case '\n': - case '\0': - t = EndOfFile; - break; - case '$': { - char *lhs; - char *rhs; - char *op; - int varSpecLen; - Boolean doFree; - - /* - * Parse the variable spec and skip over it, saving its - * value in lhs. - */ - t = Err; - lhs = Var_Parse(condExpr, VAR_CMD, doEval,&varSpecLen,&doFree); - if (lhs == var_Error) { - /* - * Even if !doEval, we still report syntax errors, which - * is what getting var_Error back with !doEval means. - */ - return(Err); - } - condExpr += varSpecLen; - - if (!isspace((unsigned char) *condExpr) && - strchr("!=><", *condExpr) == NULL) { - Buffer buf; - char *cp; - - buf = Buf_Init(0); - - for (cp = lhs; *cp; cp++) - Buf_AddByte(buf, (Byte)*cp); - - if (doFree) - free(lhs); - - for (;*condExpr && !isspace((unsigned char) *condExpr); - condExpr++) - Buf_AddByte(buf, (Byte)*condExpr); - - Buf_AddByte(buf, (Byte)'\0'); - lhs = (char *)Buf_GetAll(buf, &varSpecLen); - Buf_Destroy(buf, FALSE); - - doFree = TRUE; - } - - /* - * 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: - op = "!="; - rhs = "0"; - - goto do_compare; - } - while (isspace((unsigned char) *condExpr)) { - condExpr++; - } - if (*condExpr == '\0') { - Parse_Error(PARSE_WARNING, - "Missing right-hand-side of operator"); - goto error; - } - rhs = condExpr; -do_compare: - if (*rhs == '"') { - /* - * Doing a string comparison. Only allow == and != for - * operators. - */ - char *string; - char *cp, *cp2; - int qt; - Buffer buf; - -do_string_compare: - if (((*op != '!') && (*op != '=')) || (op[1] != '=')) { - Parse_Error(PARSE_WARNING, - "String comparison operator should be either == or !="); - goto error; - } - - buf = Buf_Init(0); - qt = *rhs == '"' ? 1 : 0; - - for (cp = &rhs[qt]; - ((qt && (*cp != '"')) || - (!qt && strchr(" \t)", *cp) == NULL)) && - (*cp != '\0'); cp++) { - if ((*cp == '\\') && (cp[1] != '\0')) { - /* - * Backslash escapes things -- skip over next - * character, if it exists. - */ - cp++; - Buf_AddByte(buf, (Byte)*cp); - } else if (*cp == '$') { - int len; - Boolean freeIt; - - cp2 = Var_Parse(cp, VAR_CMD, doEval,&len, &freeIt); - if (cp2 != var_Error) { - Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2); - if (freeIt) { - free(cp2); - } - cp += len - 1; - } else { - Buf_AddByte(buf, (Byte)*cp); - } - } else { - Buf_AddByte(buf, (Byte)*cp); - } - } - - Buf_AddByte(buf, (Byte)0); - - string = (char *)Buf_GetAll(buf, (int *)0); - Buf_Destroy(buf, FALSE); - - if (DEBUG(COND)) { - printf("lhs = \"%s\", rhs = \"%s\", op = %.2s\n", - lhs, string, op); - } - /* - * Null-terminate rhs and perform the comparison. - * t is set to the result. - */ - if (*op == '=') { - t = strcmp(lhs, string) ? False : True; - } else { - t = strcmp(lhs, string) ? True : False; - } - free(string); - if (rhs == condExpr) { - if (!qt && *cp == ')') - condExpr = cp; - else - condExpr = cp + 1; - } - } else { - /* - * rhs is either a float or an integer. Convert both the - * lhs and the rhs to a double and compare the two. - */ - double left, right; - char *string; - - if (!CondCvtArg(lhs, &left)) - goto do_string_compare; - if (*rhs == '$') { - int len; - Boolean freeIt; - - string = Var_Parse(rhs, VAR_CMD, doEval,&len,&freeIt); - if (string == var_Error) { - right = 0.0; - } else { - if (!CondCvtArg(string, &right)) { - if (freeIt) - free(string); - goto do_string_compare; - } - if (freeIt) - free(string); - if (rhs == condExpr) - condExpr += len; - } - } else { - if (!CondCvtArg(rhs, &right)) - goto do_string_compare; - if (rhs == condExpr) { - /* - * Skip over the right-hand side - */ - while(!isspace((unsigned char) *condExpr) && - (*condExpr != '\0')) { - condExpr++; - } - } - } - - if (DEBUG(COND)) { - printf("left = %f, right = %f, op = %.2s\n", left, - right, op); - } - switch(op[0]) { - case '!': - if (op[1] != '=') { - Parse_Error(PARSE_WARNING, - "Unknown operator"); - goto error; - } - t = (left != right ? True : False); - break; - case '=': - if (op[1] != '=') { - Parse_Error(PARSE_WARNING, - "Unknown operator"); - goto error; - } - t = (left == right ? True : False); - break; - case '<': - if (op[1] == '=') { - t = (left <= right ? True : False); - } else { - t = (left < right ? True : False); - } - break; - case '>': - if (op[1] == '=') { - t = (left >= right ? True : False); - } else { - t = (left > right ? True : False); - } - break; - } - } -error: - if (doFree) - free(lhs); - break; - } - default: { - Boolean (*evalProc)(); - Boolean invert = FALSE; - char *arg; - int arglen; - - if (strncmp (condExpr, "defined", 7) == 0) { - /* - * Use CondDoDefined to evaluate the argument and - * CondGetArg to extract the argument from the 'function - * call'. - */ - evalProc = CondDoDefined; - condExpr += 7; - arglen = CondGetArg (&condExpr, &arg, "defined", TRUE); - if (arglen == 0) { - condExpr -= 7; - goto use_default; - } - } else if (strncmp (condExpr, "make", 4) == 0) { - /* - * Use CondDoMake to evaluate the argument and - * CondGetArg to extract the argument from the 'function - * call'. - */ - evalProc = CondDoMake; - condExpr += 4; - arglen = CondGetArg (&condExpr, &arg, "make", TRUE); - if (arglen == 0) { - condExpr -= 4; - goto use_default; - } - } else if (strncmp (condExpr, "exists", 6) == 0) { - /* - * Use CondDoExists to evaluate the argument and - * CondGetArg to extract the argument from the - * 'function call'. - */ - evalProc = CondDoExists; - condExpr += 6; - arglen = CondGetArg(&condExpr, &arg, "exists", TRUE); - if (arglen == 0) { - condExpr -= 6; - goto use_default; - } - } else if (strncmp(condExpr, "empty", 5) == 0) { - /* - * Use Var_Parse to parse the spec in parens and return - * True if the resulting string is empty. - */ - int length; - Boolean doFree; - char *val; - - condExpr += 5; - - for (arglen = 0; - condExpr[arglen] != '(' && condExpr[arglen] != '\0'; - arglen += 1) - continue; - - if (condExpr[arglen] != '\0') { - val = Var_Parse(&condExpr[arglen - 1], VAR_CMD, - doEval, &length, &doFree); - if (val == var_Error) { - t = Err; - } else { - /* - * A variable is empty when it just contains - * spaces... 4/15/92, christos - */ - char *p; - for (p = val; *p && isspace((unsigned char)*p); p++) - continue; - t = (*p == '\0') ? True : False; - } - if (doFree) { - free(val); - } - /* - * Advance condExpr to beyond the closing ). Note that - * we subtract one from arglen + length b/c length - * is calculated from condExpr[arglen - 1]. - */ - condExpr += arglen + length - 1; - } else { - condExpr -= 5; - goto use_default; - } - break; - } else if (strncmp (condExpr, "target", 6) == 0) { - /* - * Use CondDoTarget to evaluate the argument and - * CondGetArg to extract the argument from the - * 'function call'. - */ - evalProc = CondDoTarget; - condExpr += 6; - arglen = CondGetArg(&condExpr, &arg, "target", TRUE); - if (arglen == 0) { - condExpr -= 6; - goto use_default; - } - } else { - /* - * The symbol is itself the argument to the default - * function. We advance condExpr to the end of the symbol - * by hand (the next whitespace, closing paren or - * binary operator) and set to invert the evaluation - * function if condInvert is TRUE. - */ - use_default: - invert = condInvert; - evalProc = condDefProc; - arglen = CondGetArg(&condExpr, &arg, "", FALSE); - } - - /* - * Evaluate the argument using the set function. If invert - * is TRUE, we invert the sense of the function. - */ - t = (!doEval || (* evalProc) (arglen, arg) ? - (invert ? False : True) : - (invert ? True : False)); - free(arg); - break; - } - } - } else { - t = condPushBack; - condPushBack = None; - } - return (t); -} - -/*- - *----------------------------------------------------------------------- - * CondT -- - * Parse a single term in the expression. This consists of a terminal - * symbol or Not and a terminal symbol (not including the binary - * operators): - * T -> defined(variable) | make(target) | exists(file) | symbol - * T -> ! T | ( E ) - * - * Results: - * True, False or Err. - * - * Side Effects: - * Tokens are consumed. - * - *----------------------------------------------------------------------- - */ -static Token -CondT(doEval) - Boolean doEval; -{ - Token t; - - t = CondToken(doEval); - - if (t == EndOfFile) { - /* - * If we reached the end of the expression, the expression - * is malformed... - */ - t = Err; - } else if (t == LParen) { - /* - * T -> ( E ) - */ - t = CondE(doEval); - if (t != Err) { - if (CondToken(doEval) != RParen) { - t = Err; - } - } - } else if (t == Not) { - t = CondT(doEval); - if (t == True) { - t = False; - } else if (t == False) { - t = True; - } - } - return (t); -} - -/*- - *----------------------------------------------------------------------- - * CondF -- - * Parse a conjunctive factor (nice name, wot?) - * F -> T && F | T - * - * Results: - * True, False or Err - * - * Side Effects: - * Tokens are consumed. - * - *----------------------------------------------------------------------- - */ -static Token -CondF(doEval) - Boolean doEval; -{ - Token l, o; - - l = CondT(doEval); - if (l != Err) { - o = CondToken(doEval); - - if (o == And) { - /* - * F -> T && F - * - * If T is False, the whole thing will be False, but we have to - * parse the r.h.s. anyway (to throw it away). - * If T is True, the result is the r.h.s., be it an Err or no. - */ - if (l == True) { - l = CondF(doEval); - } else { - (void) CondF(FALSE); - } - } else { - /* - * F -> T - */ - CondPushBack (o); - } - } - return (l); -} - -/*- - *----------------------------------------------------------------------- - * CondE -- - * Main expression production. - * E -> F || E | F - * - * Results: - * True, False or Err. - * - * Side Effects: - * Tokens are, of course, consumed. - * - *----------------------------------------------------------------------- - */ -static Token -CondE(doEval) - Boolean doEval; -{ - Token l, o; - - l = CondF(doEval); - if (l != Err) { - o = CondToken(doEval); - - if (o == Or) { - /* - * E -> F || E - * - * A similar thing occurs for ||, except that here we make sure - * the l.h.s. is False before we bother to evaluate the r.h.s. - * Once again, if l is False, the result is the r.h.s. and once - * again if l is True, we parse the r.h.s. to throw it away. - */ - if (l == False) { - l = CondE(doEval); - } else { - (void) CondE(FALSE); - } - } else { - /* - * E -> F - */ - CondPushBack (o); - } - } - return (l); -} - -/*- - *----------------------------------------------------------------------- - * 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. - * - * 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. - * - *----------------------------------------------------------------------- - */ -int -Cond_Eval (line) - char *line; /* Line to parse */ -{ - struct If *ifp; - Boolean isElse; - Boolean value = FALSE; - int level; /* Level at which to report errors. */ - - level = PARSE_FATAL; - - for (line++; *line == ' ' || *line == '\t'; line++) { - continue; - } - - /* - * Find what type of if we're dealing with. The result is left - * in ifp and isElse is set TRUE if it's an elif line. - */ - if (line[0] == 'e' && line[1] == 'l') { - line += 2; - isElse = TRUE; - } else if (strncmp (line, "endif", 5) == 0) { - /* - * End of a conditional section. If skipIfLevel is non-zero, that - * conditional was skipped, so lines following it should also be - * skipped. Hence, we return COND_SKIP. Otherwise, the conditional - * was read so succeeding lines should be parsed (think about it...) - * so we return COND_PARSE, unless this endif isn't paired with - * a decent if. - */ - if (skipIfLevel != 0) { - skipIfLevel -= 1; - return (COND_SKIP); - } else { - if (condTop == MAXIF) { - Parse_Error (level, "if-less endif"); - return (COND_INVALID); - } else { - skipLine = FALSE; - condTop += 1; - return (COND_PARSE); - } - } - } else { - isElse = FALSE; - } - - /* - * Figure out what sort of conditional it is -- what its default - * function is, etc. -- by looking in the table of valid "ifs" - */ - for (ifp = ifs; ifp->form != (char *)0; ifp++) { - if (strncmp (ifp->form, line, ifp->formlen) == 0) { - break; - } - } - - if (ifp->form == (char *) 0) { - /* - * Nothing fit. If the first word on the line is actually - * "else", it's a valid conditional whose value is the inverse - * of the previous if we parsed. - */ - if (isElse && (line[0] == 's') && (line[1] == 'e')) { - if (condTop == MAXIF) { - Parse_Error (level, "if-less else"); - return (COND_INVALID); - } else if (skipIfLevel == 0) { - value = !condStack[condTop]; - } else { - return (COND_SKIP); - } - } else { - /* - * Not a valid conditional type. No error... - */ - return (COND_INVALID); - } - } else { - if (isElse) { - if (condTop == MAXIF) { - Parse_Error (level, "if-less elif"); - return (COND_INVALID); - } else if (skipIfLevel != 0) { - /* - * If skipping this conditional, just ignore the whole thing. - * If we don't, the user might be employing a variable that's - * undefined, for which there's an enclosing ifdef that - * we're skipping... - */ - return(COND_SKIP); - } - } else if (skipLine) { - /* - * Don't even try to evaluate a conditional that's not an else if - * we're skipping things... - */ - skipIfLevel += 1; - return(COND_SKIP); - } - - /* - * Initialize file-global variables for parsing - */ - condDefProc = ifp->defProc; - condInvert = ifp->doNot; - - line += ifp->formlen; - - while (*line == ' ' || *line == '\t') { - line++; - } - - condExpr = line; - condPushBack = None; - - switch (CondE(TRUE)) { - case True: - if (CondToken(TRUE) == EndOfFile) { - value = TRUE; - break; - } - goto err; - /*FALLTHRU*/ - case False: - if (CondToken(TRUE) == EndOfFile) { - value = FALSE; - break; - } - /*FALLTHRU*/ - case Err: - err: - Parse_Error (level, "Malformed conditional (%s)", - line); - return (COND_INVALID); - default: - break; - } - } - if (!isElse) { - condTop -= 1; - } else if ((skipIfLevel != 0) || condStack[condTop]) { - /* - * If this is an else-type conditional, it should only take effect - * if its corresponding if was evaluated and FALSE. If its if was - * TRUE or skipped, we return COND_SKIP (and start skipping in case - * we weren't already), leaving the stack unmolested so later elif's - * don't screw up... - */ - skipLine = TRUE; - return (COND_SKIP); - } - - if (condTop < 0) { - /* - * This is the one case where we can definitely proclaim a fatal - * error. If we don't, we're hosed. - */ - Parse_Error (PARSE_FATAL, "Too many nested if's. %d max.", MAXIF); - return (COND_INVALID); - } else { - condStack[condTop] = value; - skipLine = !value; - return (value ? COND_PARSE : COND_SKIP); - } -} - -/*- - *----------------------------------------------------------------------- - * 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_End() -{ - if (condTop != MAXIF) { - Parse_Error(PARSE_FATAL, "%d open conditional%s", MAXIF-condTop, - MAXIF-condTop == 1 ? "" : "s"); - } - condTop = MAXIF; -} diff --git a/usr.bin/make/config.h b/usr.bin/make/config.h deleted file mode 100644 index 1f70f3768aa34..0000000000000 --- a/usr.bin/make/config.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * 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. - * - * @(#)config.h 8.2 (Berkeley) 4/28/95 - */ - -#define DEFSHELL 1 /* Bourne shell */ - -/* - * 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. - * - * POSIX - * If the POSIX standard for Make is to be followed. There are - * several areas that I dislike, hence this constant. - */ -#define LIBSUFF ".a" -#define RECHECK - -#ifndef RANLIBMAG -#define RANLIBMAG "__.SYMDEF" -#endif -/*#define POSIX*/ diff --git a/usr.bin/make/dir.c b/usr.bin/make/dir.c deleted file mode 100644 index e515fbb731e10..0000000000000 --- a/usr.bin/make/dir.c +++ /dev/null @@ -1,1274 +0,0 @@ -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * 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 lint -static char sccsid[] = "@(#)dir.c 8.3 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * 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_End Cleanup the module. - * - * 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_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 <stdio.h> -#include <sys/types.h> -#include <dirent.h> -#include <sys/stat.h> -#include "make.h" -#include "hash.h" -#include "dir.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 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 int DirFindName __P((ClientData, ClientData)); -static int DirMatchFiles __P((char *, Path *, Lst)); -static void DirExpandCurly __P((char *, char *, Lst, Lst)); -static void DirExpandInt __P((char *, Lst, Lst)); -static int DirPrintWord __P((ClientData, ClientData)); -static int DirPrintDir __P((ClientData, ClientData)); - -/*- - *----------------------------------------------------------------------- - * Dir_Init -- - * initialize things for this module - * - * Results: - * none - * - * Side Effects: - * some directories may be opened. - *----------------------------------------------------------------------- - */ -void -Dir_Init () -{ - dirSearchPath = Lst_Init (FALSE); - openDirectories = Lst_Init (FALSE); - Hash_InitTable(&mtimes, 0); - - /* - * Since the Path structure is placed on both openDirectories and - * the path we give Dir_AddDir (which in this case is openDirectories), - * we need to remove "." from openDirectories and what better time to - * do it than when we have to fetch the thing anyway? - */ - Dir_AddDir (openDirectories, "."); - dot = (Path *) Lst_DeQueue (openDirectories); - - /* - * We always need to have dot around, so we increment its reference count - * to make sure it's not destroyed. - */ - dot->refCount += 1; -} - -/*- - *----------------------------------------------------------------------- - * Dir_End -- - * cleanup things for this module - * - * Results: - * none - * - * Side Effects: - * none - *----------------------------------------------------------------------- - */ -void -Dir_End() -{ - dot->refCount -= 1; - Dir_Destroy((ClientData) dot); - Dir_ClearPath(dirSearchPath); - Lst_Destroy(dirSearchPath, NOFREE); - Dir_ClearPath(openDirectories); - Lst_Destroy(openDirectories, NOFREE); - Hash_DeleteTable(&mtimes); -} - -/*- - *----------------------------------------------------------------------- - * 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. - * - * Results: - * 0 if it is the same. Non-zero otherwise - * - * Side Effects: - * None - *----------------------------------------------------------------------- - */ -static int -DirFindName (p, dname) - ClientData p; /* Current name */ - ClientData dname; /* Desired name */ -{ - return (strcmp (((Path *)p)->name, (char *) dname)); -} - -/*- - *----------------------------------------------------------------------- - * Dir_HasWildcards -- - * see if the given name has any wildcard characters in it - * - * Results: - * returns TRUE if the word should be expanded, FALSE otherwise - * - * Side Effects: - * none - *----------------------------------------------------------------------- - */ -Boolean -Dir_HasWildcards (name) - char *name; /* name to check */ -{ - register char *cp; - - for (cp = name; *cp; cp++) { - switch(*cp) { - case '{': - case '[': - case '?': - case '*': - return (TRUE); - } - } - return (FALSE); -} - -/*- - *----------------------------------------------------------------------- - * 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. - * - * 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 (pattern, p, expansions) - char *pattern; /* Pattern to look for */ - Path *p; /* Directory to search */ - Lst expansions; /* Place to store the results */ -{ - 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 != (Hash_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 ? 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. - * - * Results: - * None. - * - * Side Effects: - * The given list is filled with the expansions... - * - *----------------------------------------------------------------------- - */ -static void -DirExpandCurly(word, brace, path, expansions) - char *word; /* Entire word to expand */ - char *brace; /* First curly brace in it */ - Lst path; /* Search path to use */ - Lst expansions; /* Place to store the expansions */ -{ - char *end; /* Character after the closing brace */ - char *cp; /* Current position in brace clause */ - 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 = emalloc(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... - * - * Results: - * None. - * - * Side Effects: - * Things are added to the expansions list. - * - *----------------------------------------------------------------------- - */ -static void -DirExpandInt(word, path, expansions) - char *word; /* Word to expand */ - Lst path; /* Path on which to look */ - Lst expansions; /* Place to store the result */ -{ - LstNode ln; /* Current node */ - Path *p; /* Directory in the node */ - - if (Lst_Open(path) == SUCCESS) { - while ((ln = Lst_Next(path)) != NILLNODE) { - 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(word, dummy) - ClientData word; - ClientData dummy; -{ - printf("%s ", (char *) word); - - return(dummy ? 0 : 0); -} - -/*- - *----------------------------------------------------------------------- - * Dir_Expand -- - * Expand the given word into a list of words by globbing it looking - * in the directories on the given search path. - * - * 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 (word, path, expansions) - char *word; /* the word to expand */ - Lst path; /* the list of directories in which to find - * the resulting files */ - Lst expansions; /* the list on which to place the results */ -{ - char *cp; - - if (DEBUG(DIR)) { - printf("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]; - cp[1] = '\0'; - dirpath = Dir_FindFile(word, path); - 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 != (char *)NULL) { - char *dp = &dirpath[strlen(dirpath) - 1]; - if (*dp == '/') - *dp = '\0'; - path = Lst_Init(FALSE); - Dir_AddDir(path, dirpath); - DirExpandInt(cp+1, path, expansions); - Lst_Destroy(path, NOFREE); - } - } 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, (ClientData) 0); - fputc('\n', stdout); - } -} - -/*- - *----------------------------------------------------------------------- - * Dir_FindFile -- - * Find the file with the given name along the given search 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 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 (name, path) - char *name; /* the file to find */ - Lst path; /* the Lst of directories to search */ -{ - register char *p1; /* pointer into p->name */ - register char *p2; /* pointer into name */ - LstNode ln; /* a list element */ - register char *file; /* the current filename to check */ - register Path *p; /* current path member */ - register char *cp; /* index of first slash, if any */ - Boolean hasSlash; /* true if 'name' contains a / */ - struct stat stb; /* Buffer for stat, if necessary */ - Hash_Entry *entry; /* Entry for mtimes table */ - - /* - * 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)) { - printf("Searching for %s...", name); - } - /* - * No matter what, we always look for the file in the current directory - * before anywhere else 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 ((!hasSlash || (cp - name == 2 && *name == '.')) && - (Hash_FindEntry (&dot->files, cp) != (Hash_Entry *)NULL)) { - if (DEBUG(DIR)) { - printf("in '.'\n"); - } - hits += 1; - dot->hits += 1; - return (strdup (name)); - } - - if (Lst_Open (path) == FAILURE) { - if (DEBUG(DIR)) { - printf("couldn't open path, file not found\n"); - } - misses += 1; - return ((char *) NULL); - } - - /* - * We look through all the directories on the path seeking one which - * contains the final component of the given name and whose final - * component(s) match the name's initial component(s). 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... - */ - while ((ln = Lst_Next (path)) != NILLNODE) { - p = (Path *) Lst_Datum (ln); - if (DEBUG(DIR)) { - printf("%s...", p->name); - } - if (Hash_FindEntry (&p->files, cp) != (Hash_Entry *)NULL) { - if (DEBUG(DIR)) { - printf("here..."); - } - if (hasSlash) { - /* - * If the name had a slash, its initial components and p's - * final components must match. This is false if a mismatch - * is encountered before all of the initial components - * have been checked (p2 > name at the end of the loop), or - * we matched only part of one of the components of p - * along with all the rest of them (*p1 != '/'). - */ - p1 = p->name + strlen (p->name) - 1; - p2 = cp - 2; - while (p2 >= name && p1 >= p->name && *p1 == *p2) { - p1 -= 1; p2 -= 1; - } - if (p2 >= name || (p1 >= p->name && *p1 != '/')) { - if (DEBUG(DIR)) { - printf("component mismatch -- continuing..."); - } - continue; - } - } - file = str_concat (p->name, cp, STR_ADDSLASH); - if (DEBUG(DIR)) { - printf("returning %s\n", file); - } - Lst_Close (path); - p->hits += 1; - hits += 1; - return (file); - } else if (hasSlash) { - /* - * If the file has a leading path component and that component - * exactly matches the entire name of the current search - * directory, we assume the file doesn't exist and return NULL. - */ - for (p1 = p->name, p2 = name; *p1 && *p1 == *p2; p1++, p2++) { - continue; - } - if (*p1 == '\0' && p2 == cp - 1) { - if (DEBUG(DIR)) { - printf("must be here but isn't -- returing NULL\n"); - } - Lst_Close (path); - return ((char *) NULL); - } - } - } - - /* - * We didn't find the file on any existing members of the directory. - * 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) 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)) { - printf("failed.\n"); - } - misses += 1; - return ((char *) NULL); - } - - if (*name != '/') { - Boolean checkedDot = FALSE; - - if (DEBUG(DIR)) { - printf("failed. Trying subdirectories..."); - } - (void) Lst_Open (path); - while ((ln = Lst_Next (path)) != NILLNODE) { - p = (Path *) Lst_Datum (ln); - if (p != dot) { - file = str_concat (p->name, name, STR_ADDSLASH); - } else { - /* - * Checking in dot -- DON'T put a leading ./ on the thing. - */ - file = strdup(name); - checkedDot = TRUE; - } - if (DEBUG(DIR)) { - printf("checking %s...", file); - } - - - if (stat (file, &stb) == 0) { - if (DEBUG(DIR)) { - printf("got it.\n"); - } - - Lst_Close (path); - - /* - * We've found another directory to search. We know there's - * a slash in 'file' because we put one there. We nuke it after - * finding it and call Dir_AddDir to add this new directory - * onto the existing search path. Once that's done, we restore - * the slash and triumphantly return the file name, knowing - * that should a file in this directory every be referenced - * again in such a manner, we will find it without having to do - * numerous numbers of access calls. Hurrah! - */ - cp = strrchr (file, '/'); - *cp = '\0'; - Dir_AddDir (path, file); - *cp = '/'; - - /* - * Save the modification time so if it's needed, we don't have - * to fetch it again. - */ - if (DEBUG(DIR)) { - printf("Caching %s for %s\n", Targ_FmtTime(stb.st_mtime), - file); - } - entry = Hash_CreateEntry(&mtimes, (char *) file, - (Boolean *)NULL); - Hash_SetValue(entry, (long)stb.st_mtime); - nearmisses += 1; - return (file); - } else { - free (file); - } - } - - if (DEBUG(DIR)) { - printf("failed. "); - } - Lst_Close (path); - - if (checkedDot) { - /* - * Already checked by the given name, since . was in the path, - * so no point in proceeding... - */ - if (DEBUG(DIR)) { - printf("Checked . already, returning NULL\n"); - } - return(NULL); - } - } - - /* - * 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 - cp[-1] = '\0'; - Dir_AddDir (path, name); - cp[-1] = '/'; - - bigmisses += 1; - ln = Lst_Last (path); - if (ln == NILLNODE) { - return ((char *) NULL); - } else { - p = (Path *) Lst_Datum (ln); - } - - if (Hash_FindEntry (&p->files, cp) != (Hash_Entry *)NULL) { - return (strdup (name)); - } else { - return ((char *) NULL); - } -#else /* !notdef */ - if (DEBUG(DIR)) { - printf("Looking for \"%s\"...", name); - } - - bigmisses += 1; - entry = Hash_FindEntry(&mtimes, name); - if (entry != (Hash_Entry *)NULL) { - if (DEBUG(DIR)) { - printf("got it (in mtime cache)\n"); - } - return(strdup(name)); - } else if (stat (name, &stb) == 0) { - entry = Hash_CreateEntry(&mtimes, name, (Boolean *)NULL); - if (DEBUG(DIR)) { - printf("Caching %s for %s\n", Targ_FmtTime(stb.st_mtime), - name); - } - Hash_SetValue(entry, (long)stb.st_mtime); - return (strdup (name)); - } else { - if (DEBUG(DIR)) { - printf("failed. Returning NULL\n"); - } - return ((char *)NULL); - } -#endif /* notdef */ -} - -/*- - *----------------------------------------------------------------------- - * Dir_MTime -- - * Find the modification time of the file described by gn along the - * search path dirSearchPath. - * - * 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 (gn) - GNode *gn; /* the file whose modification time is - * desired */ -{ - char *fullName; /* the full pathname of name */ - struct stat stb; /* buffer for finding the mod time */ - Hash_Entry *entry; - - if (gn->type & OP_ARCHV) { - return Arch_MTime (gn); - } else if (gn->path == (char *)NULL) { - fullName = Dir_FindFile (gn->name, dirSearchPath); - } else { - fullName = gn->path; - } - - if (fullName == (char *)NULL) { - fullName = strdup(gn->name); - } - - entry = Hash_FindEntry(&mtimes, fullName); - if (entry != (Hash_Entry *)NULL) { - /* - * Only do this once -- the second time folks are checking to - * see if the file was actually updated, so we need to actually go - * to the file system. - */ - if (DEBUG(DIR)) { - printf("Using cached time %s for %s\n", - Targ_FmtTime((time_t)(long)Hash_GetValue(entry)), fullName); - } - stb.st_mtime = (time_t)(long)Hash_GetValue(entry); - Hash_DeleteEntry(&mtimes, entry); - } else if (stat (fullName, &stb) < 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 == (char *)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... - * - * Results: - * none - * - * Side Effects: - * A structure is added to the list and the directory is - * read and hashed. - *----------------------------------------------------------------------- - */ -void -Dir_AddDir (path, name) - Lst path; /* the path to which the directory should be - * added */ - char *name; /* the name of the directory to add */ -{ - LstNode ln; /* node in case Path structure is found */ - register Path *p; /* pointer to new Path structure */ - DIR *d; /* for reading directory */ - register struct dirent *dp; /* entry in directory */ - - ln = Lst_Find (openDirectories, (ClientData)name, DirFindName); - if (ln != NILLNODE) { - p = (Path *)Lst_Datum (ln); - if (Lst_Member(path, (ClientData)p) == NILLNODE) { - p->refCount += 1; - (void)Lst_AtEnd (path, (ClientData)p); - } - } else { - if (DEBUG(DIR)) { - printf("Caching %s...", name); - fflush(stdout); - } - - if ((d = opendir (name)) != (DIR *) NULL) { - p = (Path *) emalloc (sizeof (Path)); - p->name = strdup (name); - p->hits = 0; - p->refCount = 1; - Hash_InitTable (&p->files, -1); - - /* - * Skip the first two entries -- these will *always* be . and .. - */ - (void)readdir(d); - (void)readdir(d); - - while ((dp = readdir (d)) != (struct dirent *) NULL) { -#ifdef sun - /* - * 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 */ - (void)Hash_CreateEntry(&p->files, dp->d_name, (Boolean *)NULL); - } - (void) closedir (d); - (void)Lst_AtEnd (openDirectories, (ClientData)p); - (void)Lst_AtEnd (path, (ClientData)p); - } - if (DEBUG(DIR)) { - printf("done\n"); - } - } -} - -/*- - *----------------------------------------------------------------------- - * 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. - * - *----------------------------------------------------------------------- - */ -ClientData -Dir_CopyDir(p) - ClientData p; -{ - ((Path *) p)->refCount += 1; - - return ((ClientData)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. - * - * 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 (flag, path) - char *flag; /* flag which should precede each directory */ - Lst path; /* list of directories */ -{ - char *str; /* the string which will be returned */ - char *tstr; /* the current directory preceded by 'flag' */ - LstNode ln; /* the node of the current directory */ - Path *p; /* the structure describing the current directory */ - - str = strdup (""); - - if (Lst_Open (path) == SUCCESS) { - while ((ln = Lst_Next (path)) != NILLNODE) { - p = (Path *) Lst_Datum (ln); - tstr = str_concat (flag, p->name, 0); - str = str_concat (str, tstr, STR_ADDSPACE | STR_DOFREE); - } - Lst_Close (path); - } - - return (str); -} - -/*- - *----------------------------------------------------------------------- - * Dir_Destroy -- - * Nuke a directory descriptor, if possible. Callback procedure - * for the suffixes module when destroying a search path. - * - * Results: - * None. - * - * Side Effects: - * If no other path references this directory (refCount == 0), - * the Path and all its data are freed. - * - *----------------------------------------------------------------------- - */ -void -Dir_Destroy (pp) - ClientData pp; /* The directory descriptor to nuke */ -{ - Path *p = (Path *) pp; - p->refCount -= 1; - - if (p->refCount == 0) { - LstNode ln; - - ln = Lst_Member (openDirectories, (ClientData)p); - (void) Lst_Remove (openDirectories, ln); - - Hash_DeleteTable (&p->files); - free((Address)p->name); - free((Address)p); - } -} - -/*- - *----------------------------------------------------------------------- - * Dir_ClearPath -- - * Clear out all elements of the given search path. This is different - * from destroying the list, notice. - * - * Results: - * None. - * - * Side Effects: - * The path is set to the empty list. - * - *----------------------------------------------------------------------- - */ -void -Dir_ClearPath(path) - Lst path; /* Path to clear */ -{ - Path *p; - while (!Lst_IsEmpty(path)) { - p = (Path *)Lst_DeQueue(path); - Dir_Destroy((ClientData) p); - } -} - - -/*- - *----------------------------------------------------------------------- - * Dir_Concat -- - * Concatenate two paths, adding the second to the end of the first. - * Makes sure to avoid duplicates. - * - * Results: - * None - * - * Side Effects: - * Reference counts for added dirs are upped. - * - *----------------------------------------------------------------------- - */ -void -Dir_Concat(path1, path2) - Lst path1; /* Dest */ - Lst path2; /* Source */ -{ - LstNode ln; - Path *p; - - for (ln = Lst_First(path2); ln != NILLNODE; ln = Lst_Succ(ln)) { - p = (Path *)Lst_Datum(ln); - if (Lst_Member(path1, (ClientData)p) == NILLNODE) { - p->refCount += 1; - (void)Lst_AtEnd(path1, (ClientData)p); - } - } -} - -/********** DEBUG INFO **********/ -void -Dir_PrintDirectories() -{ - LstNode ln; - Path *p; - - printf ("#*** Directory Cache:\n"); - printf ("# 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)); - printf ("# %-20s referenced\thits\n", "directory"); - if (Lst_Open (openDirectories) == SUCCESS) { - while ((ln = Lst_Next (openDirectories)) != NILLNODE) { - p = (Path *) Lst_Datum (ln); - printf ("# %-20s %10d\t%4d\n", p->name, p->refCount, p->hits); - } - Lst_Close (openDirectories); - } -} - -static int DirPrintDir (p, dummy) - ClientData p; - ClientData dummy; -{ - printf ("%s ", ((Path *) p)->name); - return (dummy ? 0 : 0); -} - -void -Dir_PrintPath (path) - Lst path; -{ - Lst_ForEach (path, DirPrintDir, (ClientData)0); -} diff --git a/usr.bin/make/dir.h b/usr.bin/make/dir.h deleted file mode 100644 index 81d76d11504dc..0000000000000 --- a/usr.bin/make/dir.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * 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. - * - * @(#)dir.h 8.2 (Berkeley) 4/28/95 - */ - -/* dir.h -- - */ - -#ifndef _DIR -#define _DIR - -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 __P((void)); -void Dir_End __P((void)); -Boolean Dir_HasWildcards __P((char *)); -void Dir_Expand __P((char *, Lst, Lst)); -char *Dir_FindFile __P((char *, Lst)); -int Dir_MTime __P((GNode *)); -void Dir_AddDir __P((Lst, char *)); -char *Dir_MakeFlags __P((char *, Lst)); -void Dir_ClearPath __P((Lst)); -void Dir_Concat __P((Lst, Lst)); -void Dir_PrintDirectories __P((void)); -void Dir_PrintPath __P((Lst)); -void Dir_Destroy __P((ClientData)); -ClientData Dir_CopyDir __P((ClientData)); - -#endif /* _DIR */ diff --git a/usr.bin/make/for.c b/usr.bin/make/for.c deleted file mode 100644 index 3ab3cba33dce4..0000000000000 --- a/usr.bin/make/for.c +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley 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. - * 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 lint -static char sccsid[] = "@(#)for.c 8.2 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * 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 <ctype.h> -#include "make.h" -#include "hash.h" -#include "dir.h" -#include "buf.h" - -/* - * 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. - */ - -static int forLevel = 0; /* Nesting level */ -static char *forVar; /* Iteration variable */ -static Buffer forBuf; /* Commands in loop */ -static Lst forLst; /* List of items */ - -/* - * State of a for loop. - */ -typedef struct _For { - Buffer buf; /* Unexpanded buffer */ - char* var; /* Index name */ - Lst lst; /* List of variables */ -} For; - -static int ForExec __P((ClientData, ClientData)); - - - - -/*- - *----------------------------------------------------------------------- - * For_Eval -- - * Evaluate the for loop in the passed line. The line - * looks like this: - * .for <variable> in <varlist> - * - * Results: - * TRUE: We found a for loop, or we are inside a for loop - * FALSE: We did not find a for loop, or we found the end of the for - * for loop. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ -int -For_Eval (line) - char *line; /* Line to parse */ -{ - char *ptr = line, *sub, *wrd; - int level; /* Level at which to report errors. */ - - level = PARSE_FATAL; - - - if (forLevel == 0) { - Buffer buf; - int varlen; - - 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])) - return FALSE; - ptr += 3; - - /* - * we found a for loop, and now we are going to parse it. - */ - while (*ptr && isspace((unsigned char) *ptr)) - ptr++; - - /* - * Grab the variable - */ - buf = Buf_Init(0); - for (wrd = ptr; *ptr && !isspace((unsigned char) *ptr); ptr++) - continue; - Buf_AddBytes(buf, ptr - wrd, (Byte *) wrd); - - forVar = (char *) Buf_GetAll(buf, &varlen); - if (varlen == 0) { - Parse_Error (level, "missing variable in for"); - return 0; - } - Buf_Destroy(buf, FALSE); - - while (*ptr && isspace((unsigned char) *ptr)) - ptr++; - - /* - * Grab the `in' - */ - if (ptr[0] != 'i' || ptr[1] != 'n' || - !isspace((unsigned char) ptr[2])) { - Parse_Error (level, "missing `in' in for"); - printf("%s\n", ptr); - return 0; - } - ptr += 3; - - while (*ptr && isspace((unsigned char) *ptr)) - ptr++; - - /* - * Make a list with the remaining words - */ - forLst = Lst_Init(FALSE); - buf = Buf_Init(0); - sub = Var_Subst(NULL, ptr, VAR_GLOBAL, FALSE); - -#define ADDWORD() \ - Buf_AddBytes(buf, ptr - wrd, (Byte *) wrd), \ - Buf_AddByte(buf, (Byte) '\0'), \ - Lst_AtEnd(forLst, (ClientData) Buf_GetAll(buf, &varlen)), \ - Buf_Destroy(buf, FALSE) - - for (ptr = sub; *ptr && isspace((unsigned char) *ptr); ptr++) - continue; - - for (wrd = ptr; *ptr; ptr++) - if (isspace((unsigned char) *ptr)) { - ADDWORD(); - buf = Buf_Init(0); - while (*ptr && isspace((unsigned char) *ptr)) - ptr++; - wrd = ptr--; - } - if (DEBUG(FOR)) - (void) fprintf(stderr, "For: Iterator %s List %s\n", forVar, sub); - if (ptr - wrd > 0) - ADDWORD(); - else - Buf_Destroy(buf, TRUE); - free((Address) sub); - - forBuf = Buf_Init(0); - forLevel++; - return 1; - } - else 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(stderr, "For: end for %d\n", forLevel); - if (--forLevel < 0) { - Parse_Error (level, "for-less endfor"); - return 0; - } - } - else if (strncmp(ptr, "for", 3) == 0 && - isspace((unsigned char) ptr[3])) { - forLevel++; - if (DEBUG(FOR)) - (void) fprintf(stderr, "For: new loop %d\n", forLevel); - } - } - - if (forLevel != 0) { - Buf_AddBytes(forBuf, strlen(line), (Byte *) line); - Buf_AddByte(forBuf, (Byte) '\n'); - return 1; - } - else { - return 0; - } -} - -/*- - *----------------------------------------------------------------------- - * ForExec -- - * Expand the for loop for this index and push it in the Makefile - * - * Results: - * None. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ -static int -ForExec(namep, argp) - ClientData namep; - ClientData argp; -{ - char *name = (char *) namep; - For *arg = (For *) argp; - int len; - Var_Set(arg->var, name, VAR_GLOBAL); - if (DEBUG(FOR)) - (void) fprintf(stderr, "--- %s = %s\n", arg->var, name); - Parse_FromString(Var_Subst(arg->var, (char *) Buf_GetAll(arg->buf, &len), - VAR_GLOBAL, FALSE)); - Var_Delete(arg->var, VAR_GLOBAL); - - return 0; -} - - -/*- - *----------------------------------------------------------------------- - * For_Run -- - * Run the for loop, immitating the actions of an include file - * - * Results: - * None. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ -void -For_Run() -{ - For arg; - - if (forVar == NULL || forBuf == NULL || forLst == NULL) - return; - arg.var = forVar; - arg.buf = forBuf; - arg.lst = forLst; - forVar = NULL; - forBuf = NULL; - forLst = NULL; - - Lst_ForEach(arg.lst, ForExec, (ClientData) &arg); - - free((Address)arg.var); - Lst_Destroy(arg.lst, (void (*) __P((ClientData))) free); - Buf_Destroy(arg.buf, TRUE); -} diff --git a/usr.bin/make/hash.c b/usr.bin/make/hash.c deleted file mode 100644 index 37e839862b562..0000000000000 --- a/usr.bin/make/hash.c +++ /dev/null @@ -1,418 +0,0 @@ -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * 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 lint -static char sccsid[] = "@(#)hash.c 8.2 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/* 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 __P((Hash_Table *)); - -/* - * The following defines the ratio of # entries to # buckets - * at which we rebuild the table to make it larger. - */ - -#define rebuildLimit 8 - -/* - *--------------------------------------------------------- - * - * Hash_InitTable -- - * - * This routine just sets up the hash table. - * - * Results: - * None. - * - * Side Effects: - * Memory is allocated for the initial bucket area. - * - *--------------------------------------------------------- - */ - -void -Hash_InitTable(t, numBuckets) - register Hash_Table *t; /* Structure to use to hold table. */ - int 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. */ -{ - register int i; - register 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 = (struct Hash_Entry **)emalloc(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(t) - Hash_Table *t; -{ - register struct Hash_Entry **hp, *h, *nexth = NULL; - register int i; - - for (hp = t->bucketPtr, i = t->size; --i >= 0;) { - for (h = *hp++; h != NULL; h = nexth) { - nexth = h->next; - free((char *)h); - } - } - free((char *)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. - * - * 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(t, key) - Hash_Table *t; /* Hash table to search. */ - char *key; /* A hash key. */ -{ - register Hash_Entry *e; - register unsigned h; - register char *p; - - 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. - * - * 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(t, key, newPtr) - register Hash_Table *t; /* Hash table to search. */ - char *key; /* A hash key. */ - Boolean *newPtr; /* Filled in with TRUE if new entry created, - * FALSE otherwise. */ -{ - register Hash_Entry *e; - register unsigned h; - register 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 = (Hash_Entry *) emalloc(sizeof(*e) + keylen); - hp = &t->bucketPtr[h & t->mask]; - e->next = *hp; - *hp = e; - e->clientData = 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(t, e) - Hash_Table *t; - Hash_Entry *e; -{ - register 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((char *)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. - * - * 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(t, searchPtr) - Hash_Table *t; /* Table to be searched. */ - register Hash_Search *searchPtr;/* Area in which to keep state - * about search.*/ -{ - searchPtr->tablePtr = t; - searchPtr->nextIndex = 0; - searchPtr->hashEntryPtr = NULL; - return Hash_EnumNext(searchPtr); -} - -/* - *--------------------------------------------------------- - * - * Hash_EnumNext -- - * This procedure returns successive entries in the hash table. - * - * 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(searchPtr) - register Hash_Search *searchPtr; /* Area used to keep state about - search. */ -{ - register 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(t) - register Hash_Table *t; -{ - register Hash_Entry *e, *next = NULL, **hp, **xp; - register int i, mask; - register 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 = (struct Hash_Entry **) emalloc(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((char *)oldhp); -} diff --git a/usr.bin/make/hash.h b/usr.bin/make/hash.h deleted file mode 100644 index 63e8783726cea..0000000000000 --- a/usr.bin/make/hash.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * 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. - * - * @(#)hash.h 8.2 (Berkeley) 4/28/95 - */ - -/* hash.h -- - * - * This file contains definitions used by the hash module, - * which maintains hash tables. - */ - -#ifndef _HASH -#define _HASH - -/* - * 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. */ - ClientData clientData; /* Arbitrary piece of data associated - * with key. */ - 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. - */ - -/* - * ClientData Hash_GetValue(h) - * Hash_Entry *h; - */ - -#define Hash_GetValue(h) ((h)->clientData) - -/* - * Hash_SetValue(h, val); - * Hash_Entry *h; - * char *val; - */ - -#define Hash_SetValue(h, val) ((h)->clientData = (ClientData) (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 __P((Hash_Table *, int)); -void Hash_DeleteTable __P((Hash_Table *)); -Hash_Entry *Hash_FindEntry __P((Hash_Table *, char *)); -Hash_Entry *Hash_CreateEntry __P((Hash_Table *, char *, Boolean *)); -void Hash_DeleteEntry __P((Hash_Table *, Hash_Entry *)); -Hash_Entry *Hash_EnumFirst __P((Hash_Table *, Hash_Search *)); -Hash_Entry *Hash_EnumNext __P((Hash_Search *)); - -#endif /* _HASH */ diff --git a/usr.bin/make/job.c b/usr.bin/make/job.c deleted file mode 100644 index 166fd974797aa..0000000000000 --- a/usr.bin/make/job.c +++ /dev/null @@ -1,2668 +0,0 @@ -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * 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 lint -static char sccsid[] = "@(#)job.c 8.3 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * 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. - * Its single argument is TRUE if the function - * should block waiting for a child to terminate. - * - * 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 intialize 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_Full Return TRUE if the job table is filled. - * - * Job_Empty Return TRUE if the job table is completely - * empty. - * - * Job_ParseShell Given the line following a .SHELL target, parse - * the line as a shell specification. Returns - * FAILURE if the spec was incorrect. - * - * Job_End 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/signal.h> -#include <sys/stat.h> -#include <sys/file.h> -#include <sys/time.h> -#include <sys/wait.h> -#include <fcntl.h> -#include <errno.h> -#include <stdio.h> -#include <string.h> -#include <signal.h> -#include "make.h" -#include "hash.h" -#include "dir.h" -#include "job.h" -#include "pathnames.h" - -extern int errno; - -/* - * 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 */ - - -/* - * 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; /* 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 */ -#define JOB_STOPPED 3 /* The job is stopped */ - -/* - * tfile is the name of a file into which all shell commands are put. It is - * used over by removing it before the child shell is executed. The XXXXX in - * the string are replaced by the pid of the make process in a 5-character - * field with leading zeroes. - */ -static char tfile[] = TMPPAT; - - -/* - * Descriptions for various shells. - */ -static Shell shells[] = { - /* - * 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\"", - "v", "e", -}, - /* - * SH description. Echo control is also possible and, under - * sun UNIX anyway, one can even control error checking. - */ -{ - "sh", - TRUE, "set -", "set -v", "set -", 5, - FALSE, "echo \"%s\"\n", "sh -c '%s || exit 0'\n", - "v", "e", -}, - /* - * UNKNOWN. - */ -{ - (char *)0, - FALSE, (char *)0, (char *)0, (char *)0, 0, - FALSE, (char *)0, (char *)0, - (char *)0, (char *)0, -} -}; -static Shell *commandShell = &shells[DEFSHELL];/* this is the shell to - * which we pass all - * commands in the Makefile. - * It is set by the - * Job_ParseShell function */ -static char *shellPath = (char *) NULL, /* full pathname of - * executable image */ - *shellName; /* last component of shell */ - - -static int maxJobs; /* The most children we can run at once */ -static int maxLocal; /* The most local ones we can have */ -int nJobs; /* The number of children currently running */ -int nLocal; /* The number of local children */ -Lst jobs; /* The structures that describe them */ -Boolean jobFull; /* Flag to tell when the job table is full. It - * is set TRUE when (1) the total number of - * running jobs equals the maximum allowed or - * (2) a job can only be run locally, but - * nLocal equals maxLocal */ -#ifndef RMT_WILL_WATCH -static fd_set outputs; /* Set of descriptors of pipes connected to - * the output channels of children */ -#endif - -GNode *lastNode; /* The node for which output was most recently - * produced. */ -char *targFmt; /* Format string to use to head output from a - * job when it's not the most-recent job heard - * from */ -#define TARG_FMT "--- %s ---\n" /* Default format */ - -/* - * When JobStart attempts to run a job remotely but can't, and isn't allowed - * to run the job locally, or when Job_CatchChildren detects a job that has - * been migrated home, the job is placed on the stoppedJobs queue to be run - * when the next job finishes. - */ -Lst stoppedJobs; /* Lst of Job structures describing - * jobs that were stopped due to concurrency - * limits or migration home */ - - -#if defined(USE_PGRP) && defined(SYSV) -#define KILL(pid,sig) killpg (-(pid),(sig)) -#else -# if defined(USE_PGRP) -#define KILL(pid,sig) killpg ((pid),(sig)) -# else -#define KILL(pid,sig) kill ((pid),(sig)) -# endif -#endif - -static int JobCondPassSig __P((ClientData, ClientData)); -static void JobPassSig __P((int)); -static int JobCmpPid __P((ClientData, ClientData)); -static int JobPrintCommand __P((ClientData, ClientData)); -static int JobSaveCommand __P((ClientData, ClientData)); -static void JobFinish __P((Job *, union wait)); -static void JobExec __P((Job *, char **)); -static void JobMakeArgv __P((Job *, char **)); -static void JobRestart __P((Job *)); -static int JobStart __P((GNode *, int, Job *)); -static void JobDoOutput __P((Job *, Boolean)); -static Shell *JobMatchShell __P((char *)); -static void JobInterrupt __P((int)); - -/*- - *----------------------------------------------------------------------- - * JobCondPassSig -- - * Pass a signal to a job if the job is remote or if USE_PGRP - * is defined. - * - * Results: - * === 0 - * - * Side Effects: - * None, except the job may bite it. - * - *----------------------------------------------------------------------- - */ -static int -JobCondPassSig(jobp, signop) - ClientData jobp; /* Job to biff */ - ClientData signop; /* Signal to send it */ -{ - Job *job = (Job *) jobp; - int signo = *(int *) signop; -#ifdef RMT_WANTS_SIGNALS - if (job->flags & JOB_REMOTE) { - (void)Rmt_Signal(job, signo); - } else { - KILL(job->pid, signo); - } -#else - /* - * Assume that sending the signal to job->pid will signal any remote - * job as well. - */ - KILL(job->pid, signo); -#endif - return(0); -} - -/*- - *----------------------------------------------------------------------- - * JobPassSig -- - * Pass a signal on to all remote jobs and to all local jobs if - * USE_PGRP is defined, then die ourselves. - * - * Results: - * None. - * - * Side Effects: - * We die by the same signal. - * - *----------------------------------------------------------------------- - */ -static void -JobPassSig(signo) - int signo; /* The signal number we've received */ -{ - int mask; - - Lst_ForEach(jobs, JobCondPassSig, (ClientData)(long)signo); - - /* - * Deal with proper cleanup based on the signal received. We only run - * the .INTERRUPT target if the signal was in fact an interrupt. The other - * three termination signals are more of a "get out *now*" command. - */ - if (signo == SIGINT) { - JobInterrupt(TRUE); - } else if ((signo == SIGHUP) || (signo == SIGTERM) || (signo == SIGQUIT)) { - JobInterrupt(FALSE); - } - - /* - * Leave gracefully if SIGQUIT, rather than core dumping. - */ - if (signo == SIGQUIT) { - Finish(0); - } - - /* - * 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. - */ - mask = sigblock(0); - (void) sigsetmask(~0 & ~(1 << (signo-1))); - signal(signo, SIG_DFL); - - kill(getpid(), signo); - - signo = SIGCONT; - Lst_ForEach(jobs, JobCondPassSig, (ClientData) &signo); - - sigsetmask(mask); - signal(signo, JobPassSig); - -} - -/*- - *----------------------------------------------------------------------- - * JobCmpPid -- - * Compare the pid of the job with the given pid and return 0 if they - * are equal. This function is called from Job_CatchChildren via - * Lst_Find to find the job descriptor of the finished job. - * - * Results: - * 0 if the pid's match - * - * Side Effects: - * None - *----------------------------------------------------------------------- - */ -static int -JobCmpPid (job, pid) - ClientData job; /* job to examine */ - ClientData pid; /* process id desired */ -{ - return ( *(int *) pid - ((Job *) job)->pid); -} - -/*- - *----------------------------------------------------------------------- - * 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. - * - * 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 (cmdp, jobp) - ClientData cmdp; /* command string to print */ - ClientData jobp; /* job for which to print it */ -{ - 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 */ - char *cmdTemplate; /* Template to use when printing the - * command */ - char *cmdStart; /* Start of expanded command */ - LstNode cmdNode; /* Node for replacing the command */ - char *cmd = (char *) cmdp; - Job *job = (Job *) jobp; - - noSpecials = (noExecute && ! (job->node->type & OP_MAKE)); - - 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, - (ClientData)cmd)); - return (1); - } - return (0); - } - -#define DBPRINTF(fmt, arg) if (DEBUG(JOB)) printf (fmt, arg); fprintf (job->cmdFILE, fmt, arg) - - numCommands += 1; - - /* - * For debugging, we replace each command with the result of expanding - * the variables in the command. - */ - cmdNode = Lst_Member (job->node->commands, (ClientData)cmd); - cmdStart = cmd = Var_Subst (NULL, cmd, job->node, FALSE); - Lst_Replace (cmdNode, (ClientData)cmdStart); - - cmdTemplate = "%s\n"; - - /* - * Check for leading @' and -'s to control echoing and error checking. - */ - while (*cmd == '@' || *cmd == '-') { - if (*cmd == '@') { - shutUp = TRUE; - } else { - errOff = TRUE; - } - cmd++; - } - - while (isspace((unsigned char) *cmd)) - cmd++; - - if (shutUp) { - if (! (job->flags & JOB_SILENT) && !noSpecials && - commandShell->hasEchoCtl) { - DBPRINTF ("%s\n", commandShell->echoOff); - } else { - shutUp = FALSE; - } - } - - if (errOff) { - if ( ! (job->flags & JOB_IGNERR) && !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. - */ - if (! (job->flags & JOB_SILENT) && !shutUp && - commandShell->hasEchoCtl) { - DBPRINTF ("%s\n", commandShell->echoOff); - DBPRINTF (commandShell->errCheck, cmd); - shutUp = TRUE; - } - 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; - } - } - - DBPRINTF (cmdTemplate, cmd); - - 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) { - 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 (cmd, gn) - ClientData cmd; - ClientData gn; -{ - cmd = (ClientData) Var_Subst (NULL, (char *) cmd, (GNode *) gn, FALSE); - (void)Lst_AtEnd (postCommands->commands, cmd); - return (0); -} - -/*- - *----------------------------------------------------------------------- - * 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. - * - * Results: - * None - * - * Side Effects: - * Some nodes may be put on the toBeMade queue. - * 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, status) - Job *job; /* job to finish */ - union wait status; /* sub-why job went away */ -{ - Boolean done; - - if ((WIFEXITED(status) && - (((status.w_retcode != 0) && !(job->flags & JOB_IGNERR)))) || - (WIFSIGNALED(status) && (status.w_termsig != SIGCONT))) - { - /* - * 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... - */ - if (usePipes) { -#ifdef RMT_WILL_WATCH - Rmt_Ignore(job->inPipe); -#else - FD_CLR(job->inPipe, &outputs); -#endif /* RMT_WILL_WATCH */ - if (job->outPipe != job->inPipe) { - (void)close (job->outPipe); - } - JobDoOutput (job, TRUE); - (void)close (job->inPipe); - } else { - (void)close (job->outFd); - JobDoOutput (job, TRUE); - } - - if (job->cmdFILE != NULL && job->cmdFILE != stdout) { - fclose(job->cmdFILE); - } - done = TRUE; - } else if (WIFEXITED(status) && status.w_retcode != 0) { - /* - * 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. Note we don't - * want to close down any of the streams until we know we're at the - * end. - */ - done = TRUE; - } else { - /* - * No need to close things down or anything. - */ - done = FALSE; - } - - if (done || - WIFSTOPPED(status) || - (WIFSIGNALED(status) && (status.w_termsig == SIGCONT)) || - DEBUG(JOB)) - { - FILE *out; - - if (!usePipes && (job->flags & JOB_IGNERR)) { - /* - * If output is going to a file and this job is ignoring - * errors, arrange to have the exit status sent to the - * output file as well. - */ - out = fdopen (job->outFd, "w"); - } else { - out = stdout; - } - - if (WIFEXITED(status)) { - if (status.w_retcode != 0) { - if (usePipes && job->node != lastNode) { - fprintf (out, targFmt, job->node->name); - lastNode = job->node; - } - fprintf (out, "*** Error code %d%s\n", status.w_retcode, - (job->flags & JOB_IGNERR) ? " (ignored)" : ""); - - if (job->flags & JOB_IGNERR) { - status.w_status = 0; - } - } else if (DEBUG(JOB)) { - if (usePipes && job->node != lastNode) { - fprintf (out, targFmt, job->node->name); - lastNode = job->node; - } - fprintf (out, "*** Completed successfully\n"); - } - } else if (WIFSTOPPED(status)) { - if (usePipes && job->node != lastNode) { - fprintf (out, targFmt, job->node->name); - lastNode = job->node; - } - if (! (job->flags & JOB_REMIGRATE)) { - fprintf (out, "*** Stopped -- signal %d\n", status.w_stopsig); - } - job->flags |= JOB_RESUME; - (void)Lst_AtEnd(stoppedJobs, (ClientData)job); - fflush(out); - return; - } else if (status.w_termsig == SIGCONT) { - /* - * If the beastie has continued, shift the Job from the stopped - * list to the running one (or re-stop it if concurrency is - * exceeded) and go and get another child. - */ - if (job->flags & (JOB_RESUME|JOB_REMIGRATE|JOB_RESTART)) { - if (usePipes && job->node != lastNode) { - fprintf (out, targFmt, job->node->name); - lastNode = job->node; - } - fprintf (out, "*** Continued\n"); - } - if (! (job->flags & JOB_CONTINUING)) { - JobRestart(job); - } else { - Lst_AtEnd(jobs, (ClientData)job); - nJobs += 1; - if (! (job->flags & JOB_REMOTE)) { - nLocal += 1; - } - if (nJobs == maxJobs) { - jobFull = TRUE; - if (DEBUG(JOB)) { - printf("Job queue is full.\n"); - } - } - } - fflush(out); - return; - } else { - if (usePipes && job->node != lastNode) { - fprintf (out, targFmt, job->node->name); - lastNode = job->node; - } - fprintf (out, "*** Signal %d\n", status.w_termsig); - } - - fflush (out); - } - - /* - * Now handle the -B-mode stuff. If the beast still isn't finished, - * try and restart the job on the next command. If JobStart says it's - * ok, it's ok. If there's an error, this puppy is done. - */ - if ((status.w_status == 0) && - !Lst_IsAtEnd (job->node->commands)) - { - switch (JobStart (job->node, - job->flags & JOB_IGNDOTS, - job)) - { - case JOB_RUNNING: - done = FALSE; - break; - case JOB_ERROR: - done = TRUE; - status.w_retcode = 1; - break; - case JOB_FINISHED: - /* - * If we got back a JOB_FINISHED code, JobStart has already - * called Make_Update and freed the job descriptor. We set - * done to false here to avoid fake cycles and double frees. - * JobStart needs to do the update so we can proceed up the - * graph when given the -n flag.. - */ - done = FALSE; - break; - } - } else { - done = TRUE; - } - - - if (done && - (aborting != ABORT_ERROR) && - (aborting != ABORT_INTERRUPT) && - (status.w_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 != NILLNODE) { - Lst_ForEachFrom (job->node->commands, job->tailCmds, - JobSaveCommand, - (ClientData)job->node); - } - job->node->made = MADE; - Make_Update (job->node); - free((Address)job); - } else if (status.w_status) { - errors += 1; - free((Address)job); - } - - while (!errors && !jobFull && !Lst_IsEmpty(stoppedJobs)) { - JobRestart((Job *)Lst_DeQueue(stoppedJobs)); - } - - /* - * 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 ((aborting == ABORT_ERROR) && Job_Empty()) { - /* - * If we are aborting and the job table is now empty, we finish. - */ - (void) unlink (tfile); - Finish (errors); - } -} - -/*- - *----------------------------------------------------------------------- - * Job_Touch -- - * Touch the given target. Called by JobStart when the -t flag was - * given - * - * 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 (gn, silent) - GNode *gn; /* the node of the file to touch */ - Boolean silent; /* TRUE if should not print messages */ -{ - int streamID; /* ID of stream opened to do the touch */ - struct timeval times[2]; /* Times for utimes() call */ - - if (gn->type & (OP_JOIN|OP_USE|OP_EXEC|OP_OPTIONAL)) { - /* - * .JOIN, .USE, .ZEROTIME and .OPTIONAL targets are "virtual" targets - * and, as such, shouldn't really be created. - */ - return; - } - - if (!silent) { - printf ("touch %s\n", gn->name); - } - - if (noExecute) { - 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[0].tv_sec = times[1].tv_sec = now; - times[0].tv_usec = times[1].tv_usec = 0; - if (utimes(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) { - lseek(streamID, 0L, L_SET); - write(streamID, &c, 1); - } - - (void)close (streamID); - } else - printf("*** couldn't touch %s: %s", file, strerror(errno)); - } - } -} - -/*- - *----------------------------------------------------------------------- - * Job_CheckCommands -- - * Make sure the given node has all the commands it needs. - * - * 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 (gn, abortProc) - GNode *gn; /* The target whose commands need - * verifying */ - void (*abortProc) __P((char *, ...)); - /* Function to abort with message */ -{ - if (OP_NOP(gn->type) && Lst_IsEmpty (gn->commands) && - (gn->type & OP_LIB) == 0) { - /* - * No commands. Look for .DEFAULT rule from which we might infer - * commands - */ - if ((DEFAULT != NILGNODE) && !Lst_IsEmpty(DEFAULT->commands)) { - 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); - if (p1) - free(p1); - } else if (Dir_MTime (gn) == 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. - */ - if (gn->type & OP_OPTIONAL) { - printf ("make: don't know how to make %s (ignored)\n", - gn->name); - } else if (keepgoing) { - printf ("make: don't know how to make %s (continuing)\n", - gn->name); - return (FALSE); - } else { - (*abortProc) ("make: don't know how to make %s. Stop", - gn->name); - return(FALSE); - } - } - } - return (TRUE); -} -#ifdef RMT_WILL_WATCH -/*- - *----------------------------------------------------------------------- - * JobLocalInput -- - * Handle a pipe becoming readable. Callback function for Rmt_Watch - * - * Results: - * None - * - * Side Effects: - * JobDoOutput is called. - * - *----------------------------------------------------------------------- - */ -/*ARGSUSED*/ -static void -JobLocalInput(stream, job) - int stream; /* Stream that's ready (ignored) */ - Job *job; /* Job to which the stream belongs */ -{ - JobDoOutput(job, FALSE); -} -#endif /* RMT_WILL_WATCH */ - -/*- - *----------------------------------------------------------------------- - * JobExec -- - * Execute the shell for the given job. Called from JobStart and - * JobRestart. - * - * Results: - * None. - * - * Side Effects: - * A shell is executed, outputs is altered and the Job structure added - * to the job table. - * - *----------------------------------------------------------------------- - */ -static void -JobExec(job, argv) - Job *job; /* Job to execute */ - char **argv; -{ - int cpid; /* ID of new child */ - - if (DEBUG(JOB)) { - int i; - - printf("Running %s %sly\n", job->node->name, - job->flags&JOB_REMOTE?"remote":"local"); - printf("\tCommand: "); - for (i = 0; argv[i] != (char *)NULL; i++) { - printf("%s ", argv[i]); - } - printf("\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_FIRST) && - !(job->flags & JOB_SILENT)) - { - printf(targFmt, job->node->name); - lastNode = job->node; - } - -#ifdef RMT_NO_EXEC - if (job->flags & JOB_REMOTE) { - goto jobExecFinish; - } -#endif /* RMT_NO_EXEC */ - - if ((cpid = vfork()) == -1) { - Punt ("Cannot fork"); - } else if (cpid == 0) { - - /* - * 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. - */ - (void) dup2(fileno(job->cmdFILE), 0); - fcntl(0, F_SETFD, 0); - lseek(0, 0, L_SET); - - if (usePipes) { - /* - * Set up the child's output to be routed through the pipe - * we've created for it. - */ - (void) dup2 (job->outPipe, 1); - } else { - /* - * We're capturing output in a file, so we duplicate the - * descriptor to the temporary file into the standard - * output. - */ - (void) dup2 (job->outFd, 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. - */ - fcntl(1, F_SETFD, 0); - (void) dup2 (1, 2); - -#ifdef USE_PGRP - /* - * 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. - */ - - (void) setpgrp(0, getpid()); -#endif USE_PGRP - - (void) execv (shellPath, argv); - (void) write (2, "Could not execute shell\n", - sizeof ("Could not execute shell")); - _exit (1); - } else { - job->pid = cpid; - - if (usePipes && (job->flags & JOB_FIRST) ) { - /* - * The first time a job is run for a node, we set the current - * position in the buffer to the beginning and mark another - * stream to watch in the outputs mask - */ - job->curPos = 0; - -#ifdef RMT_WILL_WATCH - Rmt_Watch(job->inPipe, JobLocalInput, job); -#else - FD_SET(job->inPipe, &outputs); -#endif /* RMT_WILL_WATCH */ - } - - if (job->flags & JOB_REMOTE) { - job->rmtID = 0; - } else { - nLocal += 1; - /* - * XXX: Used to not happen if CUSTOMS. Why? - */ - if (job->cmdFILE != stdout) { - fclose(job->cmdFILE); - job->cmdFILE = NULL; - } - } - } - -#ifdef RMT_NO_EXEC -jobExecFinish: -#endif - /* - * Now the job is actually running, add it to the table. - */ - nJobs += 1; - (void)Lst_AtEnd (jobs, (ClientData)job); - if (nJobs == maxJobs) { - jobFull = TRUE; - } -} - -/*- - *----------------------------------------------------------------------- - * JobMakeArgv -- - * Create the argv needed to execute the shell for a given job. - * - * - * Results: - * - * Side Effects: - * - *----------------------------------------------------------------------- - */ -static void -JobMakeArgv(job, argv) - Job *job; - char **argv; -{ - int argc; - static char args[10]; /* For merged arguments */ - - argv[0] = 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)sprintf(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] = commandShell->exit; - argc++; - } - if (!(job->flags & JOB_SILENT) && commandShell->echo) { - argv[argc] = commandShell->echo; - argc++; - } - } - argv[argc] = (char *)NULL; -} - -/*- - *----------------------------------------------------------------------- - * JobRestart -- - * Restart a job that stopped for some reason. - * - * Results: - * None. - * - * Side Effects: - * jobFull will be set if the job couldn't be run. - * - *----------------------------------------------------------------------- - */ -static void -JobRestart(job) - Job *job; /* Job to restart */ -{ - if (job->flags & JOB_REMIGRATE) { - if (DEBUG(JOB)) { - printf("Remigrating %x\n", job->pid); - } - if (nLocal != maxLocal) { - /* - * Job cannot be remigrated, but there's room on the local - * machine, so resume the job and note that another - * local job has started. - */ - if (DEBUG(JOB)) { - printf("resuming on local machine\n"); - } - KILL(job->pid, SIGCONT); - nLocal +=1; - job->flags &= ~(JOB_REMIGRATE|JOB_RESUME); - } else { - /* - * Job cannot be restarted. Mark the table as full and - * place the job back on the list of stopped jobs. - */ - if (DEBUG(JOB)) { - printf("holding\n"); - } - (void)Lst_AtFront(stoppedJobs, (ClientData)job); - jobFull = TRUE; - if (DEBUG(JOB)) { - printf("Job queue is full.\n"); - } - return; - } - - (void)Lst_AtEnd(jobs, (ClientData)job); - nJobs += 1; - if (nJobs == maxJobs) { - jobFull = TRUE; - if (DEBUG(JOB)) { - printf("Job queue is full.\n"); - } - } - } else if (job->flags & JOB_RESTART) { - /* - * Set up the control arguments to the shell. This is based on the - * flags set earlier for this job. If the JOB_IGNERR flag is clear, - * the 'exit' flag of the commandShell is used to cause it to exit - * upon receiving an error. If the JOB_SILENT flag is clear, the - * 'echo' flag of the commandShell is used to get it to start echoing - * as soon as it starts processing commands. - */ - char *argv[4]; - - JobMakeArgv(job, argv); - - if (DEBUG(JOB)) { - printf("Restarting %s...", job->node->name); - } - if (((nLocal >= maxLocal) && ! (job->flags & JOB_SPECIAL))) { - /* - * Can't be exported and not allowed to run locally -- put it - * back on the hold queue and mark the table full - */ - if (DEBUG(JOB)) { - printf("holding\n"); - } - (void)Lst_AtFront(stoppedJobs, (ClientData)job); - jobFull = TRUE; - if (DEBUG(JOB)) { - printf("Job queue is full.\n"); - } - return; - } else { - /* - * Job may be run locally. - */ - if (DEBUG(JOB)) { - printf("running locally\n"); - } - job->flags &= ~JOB_REMOTE; - } - JobExec(job, argv); - } else { - /* - * The job has stopped and needs to be restarted. Why it stopped, - * we don't know... - */ - if (DEBUG(JOB)) { - printf("Resuming %s...", job->node->name); - } - if (((job->flags & JOB_REMOTE) || - (nLocal < maxLocal) || - (((job->flags & JOB_SPECIAL)) && - (maxLocal == 0))) && - (nJobs != maxJobs)) - { - /* - * If the job is remote, it's ok to resume it as long as the - * maximum concurrency won't be exceeded. If it's local and - * we haven't reached the local concurrency limit already (or the - * job must be run locally and maxLocal is 0), it's also ok to - * resume it. - */ - Boolean error; - extern int errno; - union wait status; - -#ifdef RMT_WANTS_SIGNALS - if (job->flags & JOB_REMOTE) { - error = !Rmt_Signal(job, SIGCONT); - } else -#endif /* RMT_WANTS_SIGNALS */ - error = (KILL(job->pid, SIGCONT) != 0); - - if (!error) { - /* - * Make sure the user knows we've continued the beast and - * actually put the thing in the job table. - */ - job->flags |= JOB_CONTINUING; - status.w_termsig = SIGCONT; - JobFinish(job, status); - - job->flags &= ~(JOB_RESUME|JOB_CONTINUING); - if (DEBUG(JOB)) { - printf("done\n"); - } - } else { - Error("couldn't resume %s: %s", - job->node->name, strerror(errno)); - status.w_status = 0; - status.w_retcode = 1; - JobFinish(job, status); - } - } else { - /* - * Job cannot be restarted. Mark the table as full and - * place the job back on the list of stopped jobs. - */ - if (DEBUG(JOB)) { - printf("table full\n"); - } - (void)Lst_AtFront(stoppedJobs, (ClientData)job); - jobFull = TRUE; - if (DEBUG(JOB)) { - printf("Job queue is full.\n"); - } - } - } -} - -/*- - *----------------------------------------------------------------------- - * JobStart -- - * Start a target-creation process going for the target described - * by the graph node gn. - * - * 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. - *----------------------------------------------------------------------- - */ -static int -JobStart (gn, flags, previous) - GNode *gn; /* target to create */ - int flags; /* flags for the job to override normal ones. - * e.g. JOB_SPECIAL or JOB_IGNDOTS */ - Job *previous; /* The previous Job structure for this node, - * if any. */ -{ - register Job *job; /* new job descriptor */ - char *argv[4]; /* Argument vector to shell */ - static int jobno = 0; /* job number of catching output in a file */ - Boolean cmdsOK; /* true if the nodes commands were all right */ - Boolean local; /* Set true if the job was run locally */ - Boolean noExec; /* Set true if we decide not to run the job */ - - if (previous != (Job *)NULL) { - previous->flags &= ~ (JOB_FIRST|JOB_IGNERR|JOB_SILENT|JOB_REMOTE); - job = previous; - } else { - job = (Job *) emalloc (sizeof (Job)); - if (job == (Job *)NULL) { - Punt("JobStart out of memory"); - } - flags |= JOB_FIRST; - } - - job->node = gn; - job->tailCmds = NILLNODE; - - /* - * 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 - */ - if (job->flags & JOB_FIRST) { - cmdsOK = Job_CheckCommands(gn, Error); - } else { - cmdsOK = TRUE; - } - - /* - * 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) || (!noExecute && !touchFlag)) { - /* - * We're serious here, but if the commands were bogus, we're - * also dead... - */ - if (!cmdsOK) { - DieHorribly(); - } - - job->cmdFILE = fopen (tfile, "w+"); - if (job->cmdFILE == (FILE *) NULL) { - Punt ("Could not open %s", tfile); - } - fcntl(fileno(job->cmdFILE), F_SETFD, 1); - /* - * Send the commands to the command file, flush all its buffers then - * rewind and remove the thing. - */ - noExec = FALSE; - - /* - * used to be backwards; replace when start doing multiple commands - * per shell. - */ - if (compatMake) { - /* - * Be compatible: If this is the first time for this node, - * verify its commands are ok and open the commands list for - * sequential access by later invocations of JobStart. - * Once that is done, we take the next command off the list - * and print it to the command file. If the command was an - * ellipsis, note that there's nothing more to execute. - */ - if ((job->flags&JOB_FIRST) && (Lst_Open(gn->commands) != SUCCESS)){ - cmdsOK = FALSE; - } else { - LstNode ln = Lst_Next (gn->commands); - - if ((ln == NILLNODE) || - JobPrintCommand ((char *)Lst_Datum (ln), job)) - { - noExec = TRUE; - Lst_Close (gn->commands); - } - if (noExec && !(job->flags & JOB_FIRST)) { - /* - * If we're not going to execute anything, the job - * is done and we need to close down the various - * file descriptors we've opened for output, then - * call JobDoOutput to catch the final characters or - * send the file to the screen... Note that the i/o streams - * are only open if this isn't the first job. - * Note also that this could not be done in - * Job_CatchChildren b/c it wasn't clear if there were - * more commands to execute or not... - */ - if (usePipes) { -#ifdef RMT_WILL_WATCH - Rmt_Ignore(job->inPipe); -#else - FD_CLR(job->inPipe, &outputs); -#endif - if (job->outPipe != job->inPipe) { - (void)close (job->outPipe); - } - JobDoOutput (job, TRUE); - (void)close (job->inPipe); - } else { - (void)close (job->outFd); - JobDoOutput (job, TRUE); - } - } - } - } else { - /* - * We can do all the commands at once. hooray for sanity - */ - numCommands = 0; - Lst_ForEach (gn->commands, JobPrintCommand, (ClientData)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; - } - } - } else if (noExecute) { - /* - * 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) { - printf (targFmt, gn->name); - 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, (ClientData)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; - } - - /* - * If we're not supposed to execute a shell, don't. - */ - if (noExec) { - /* - * Unlink and close the command file if we opened one - */ - if (job->cmdFILE != stdout) { - (void) unlink (tfile); - fclose(job->cmdFILE); - } else { - fflush (stdout); - } - - /* - * 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) { - if (aborting == 0) { - if (job->tailCmds != NILLNODE) { - Lst_ForEachFrom(job->node->commands, job->tailCmds, - JobSaveCommand, - (ClientData)job->node); - } - Make_Update(job->node); - } - free((Address)job); - return(JOB_FINISHED); - } else { - free((Address)job); - return(JOB_ERROR); - } - } else { - fflush (job->cmdFILE); - (void) unlink (tfile); - } - - /* - * Set up the control arguments to the shell. This is based on the flags - * set earlier for this job. - */ - JobMakeArgv(job, argv); - - /* - * If we're using pipes to catch output, create the pipe by which we'll - * get the shell's output. If we're using files, print out that we're - * starting a job and then set up its temporary-file name. This is just - * tfile with two extra digits tacked on -- jobno. - */ - if (job->flags & JOB_FIRST) { - if (usePipes) { - int fd[2]; - (void) pipe(fd); - job->inPipe = fd[0]; - job->outPipe = fd[1]; - (void)fcntl (job->inPipe, F_SETFD, 1); - (void)fcntl (job->outPipe, F_SETFD, 1); - } else { - printf ("Remaking `%s'\n", gn->name); - fflush (stdout); - sprintf (job->outFile, "%s%02d", tfile, jobno); - jobno = (jobno + 1) % 100; - job->outFd = open(job->outFile,O_WRONLY|O_CREAT|O_APPEND,0600); - (void)fcntl (job->outFd, F_SETFD, 1); - } - } - - local = TRUE; - - if (local && (((nLocal >= maxLocal) && - !(job->flags & JOB_SPECIAL) && - (maxLocal != 0)))) - { - /* - * The job can only be run locally, but we've hit the limit of - * local concurrency, so put the job on hold until some other job - * finishes. Note that the special jobs (.BEGIN, .INTERRUPT and .END) - * may be run locally even when the local limit has been reached - * (e.g. when maxLocal == 0), though they will be exported if at - * all possible. - */ - jobFull = TRUE; - - if (DEBUG(JOB)) { - printf("Can only run job locally.\n"); - } - job->flags |= JOB_RESTART; - (void)Lst_AtEnd(stoppedJobs, (ClientData)job); - } else { - if ((nLocal >= maxLocal) && local) { - /* - * If we're running this job locally as a special case (see above), - * at least say the table is full. - */ - jobFull = TRUE; - if (DEBUG(JOB)) { - printf("Local job queue is full.\n"); - } - } - JobExec(job, argv); - } - return(JOB_RUNNING); -} - -/*- - *----------------------------------------------------------------------- - * 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. - * - * Results: - * None - * - * Side Effects: - * curPos may be shifted as may the contents of outBuf. - *----------------------------------------------------------------------- - */ -static void -JobDoOutput (job, finish) - register Job *job; /* the job whose output needs printing */ - Boolean finish; /* TRUE if this is the last time we'll be - * called for this job */ -{ - Boolean gotNL = FALSE; /* true if got a newline */ - register int nr; /* number of bytes read */ - register int i; /* auxiliary index into outBuf */ - register int max; /* limit for i (end of current data) */ - int nRead; /* (Temporary) number of bytes read */ - - FILE *oFILE; /* Stream pointer to shell's output file */ - char inLine[132]; - - - if (usePipes) { - /* - * Read as many bytes as will fit in the buffer. - */ -end_loop: - - nRead = read (job->inPipe, &job->outBuf[job->curPos], - JOB_BUFSIZE - job->curPos); - if (nRead < 0) { - 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. - */ - gotNL = TRUE; - i = job->curPos; - } - } - if (gotNL) { - /* - * 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, preceeded - * 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) { - register char *cp, *ecp; - - cp = job->outBuf; - if (commandShell->noPrint) { - ecp = Str_FindSubstring(job->outBuf, - commandShell->noPrint); - while (ecp != (char *)NULL) { - if (cp != ecp) { - *ecp = '\0'; - if (job->node != lastNode) { - printf (targFmt, job->node->name); - 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. - */ - printf ("%s", cp); - } - cp = ecp + commandShell->noPLen; - if (cp != &job->outBuf[i]) { - /* - * 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 { - break; - } - } - } - - /* - * 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 (job->node != lastNode) { - printf (targFmt, job->node->name); - lastNode = job->node; - } - printf ("%s\n", cp); - } - - fflush (stdout); - } - if (i < max - 1) { - /* shift the remaining characters down */ - memcpy ( job->outBuf, &job->outBuf[i + 1], max - (i + 1)); - job->curPos = max - (i + 1); - - } else { - /* - * We have written everything out, so we just start over - * from the start of the buffer. No copying. No nothing. - */ - 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; - } - } else { - /* - * We've been called to retrieve the output of the job from the - * temporary file where it's been squirreled away. This consists of - * opening the file, reading the output line by line, being sure not - * to print the noPrint line for the shell we used, then close and - * remove the temporary file. Very simple. - * - * Change to read in blocks and do FindSubString type things as for - * pipes? That would allow for "@echo -n..." - */ - oFILE = fopen (job->outFile, "r"); - if (oFILE != (FILE *) NULL) { - printf ("Results of making %s:\n", job->node->name); - while (fgets (inLine, sizeof(inLine), oFILE) != NULL) { - register char *cp, *ecp, *endp; - - cp = inLine; - endp = inLine + strlen(inLine); - if (endp[-1] == '\n') { - *--endp = '\0'; - } - if (commandShell->noPrint) { - ecp = Str_FindSubstring(cp, commandShell->noPrint); - while (ecp != (char *)NULL) { - if (cp != ecp) { - *ecp = '\0'; - /* - * 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. - */ - printf ("%s", cp); - } - 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 { - break; - } - } - } - - /* - * 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') { - printf ("%s\n", cp); - } - } - fclose (oFILE); - (void) unlink (job->outFile); - } - } - fflush(stdout); -} - -/*- - *----------------------------------------------------------------------- - * Job_CatchChildren -- - * Handle the exit of a child. Called from Make_Make. - * - * 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. This will take care of - * putting jobs on the stoppedJobs queue. - * - *----------------------------------------------------------------------- - */ -void -Job_CatchChildren (block) - Boolean block; /* TRUE if should block on the wait. */ -{ - int pid; /* pid of dead child */ - register Job *job; /* job descriptor for dead child */ - LstNode jnode; /* list element for finding job */ - union wait status; /* Exit/termination status */ - - /* - * Don't even bother if we know there's no one around. - */ - if (nLocal == 0) { - return; - } - - while ((pid = wait3((int *)&status, (block?0:WNOHANG)|WUNTRACED, - (struct rusage *)0)) > 0) - { - if (DEBUG(JOB)) - printf("Process %d exited or stopped.\n", pid); - - - jnode = Lst_Find (jobs, (ClientData)&pid, JobCmpPid); - - if (jnode == NILLNODE) { - if (WIFSIGNALED(status) && (status.w_termsig == SIGCONT)) { - jnode = Lst_Find(stoppedJobs, (ClientData) &pid, JobCmpPid); - if (jnode == NILLNODE) { - Error("Resumed child (%d) not in table", pid); - continue; - } - job = (Job *)Lst_Datum(jnode); - (void)Lst_Remove(stoppedJobs, jnode); - } else { - Error ("Child (%d) not in table?", pid); - continue; - } - } else { - job = (Job *) Lst_Datum (jnode); - (void)Lst_Remove (jobs, jnode); - nJobs -= 1; - if (jobFull && DEBUG(JOB)) { - printf("Job queue is no longer full.\n"); - } - jobFull = FALSE; - nLocal -= 1; - } - - 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 () -{ - int nfds; - struct timeval timeout; - fd_set readfds; - register LstNode ln; - register Job *job; -#ifdef RMT_WILL_WATCH - int pnJobs; /* Previous nJobs */ -#endif - - fflush(stdout); -#ifdef RMT_WILL_WATCH - pnJobs = nJobs; - - /* - * It is possible for us to be called with nJobs equal to 0. This happens - * if all the jobs finish and a job that is stopped cannot be run - * locally (eg if maxLocal is 0) and cannot be exported. The job will - * be placed back on the stoppedJobs queue, Job_Empty() will return false, - * Make_Run will call us again when there's nothing for which to wait. - * nJobs never changes, so we loop forever. Hence the check. It could - * be argued that we should sleep for a bit so as not to swamp the - * exportation system with requests. Perhaps we should. - * - * NOTE: IT IS THE RESPONSIBILITY OF Rmt_Wait TO CALL Job_CatchChildren - * IN A TIMELY FASHION TO CATCH ANY LOCALLY RUNNING JOBS THAT EXIT. - * It may use the variable nLocal to determine if it needs to call - * Job_CatchChildren (if nLocal is 0, there's nothing for which to - * wait...) - */ - while (nJobs != 0 && pnJobs == nJobs) { - Rmt_Wait(); - } -#else - if (usePipes) { - readfds = outputs; - timeout.tv_sec = SEL_SEC; - timeout.tv_usec = SEL_USEC; - - if ((nfds = select (FD_SETSIZE, &readfds, (fd_set *) 0, (fd_set *) 0, &timeout)) < 0) - { - return; - } else { - if (Lst_Open (jobs) == FAILURE) { - Punt ("Cannot open job table"); - } - while (nfds && (ln = Lst_Next (jobs)) != NILLNODE) { - job = (Job *) Lst_Datum (ln); - if (FD_ISSET(job->inPipe, &readfds)) { - JobDoOutput (job, FALSE); - nfds -= 1; - } - } - Lst_Close (jobs); - } - } -#endif /* RMT_WILL_WATCH */ -} - -/*- - *----------------------------------------------------------------------- - * 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 (gn) - GNode *gn; -{ - (void)JobStart (gn, 0, (Job *)NULL); -} - -/*- - *----------------------------------------------------------------------- - * Job_Init -- - * Initialize the process module - * - * Results: - * none - * - * Side Effects: - * lists and counters are initialized - *----------------------------------------------------------------------- - */ -void -Job_Init (maxproc, maxlocal) - int maxproc; /* the greatest number of jobs which may be - * running at one time */ - int maxlocal; /* the greatest number of local jobs which may - * be running at once. */ -{ - GNode *begin; /* node for commands to do at the very start */ - - sprintf (tfile, "/tmp/make%05d", getpid()); - - jobs = Lst_Init (FALSE); - stoppedJobs = Lst_Init(FALSE); - maxJobs = maxproc; - maxLocal = maxlocal; - nJobs = 0; - nLocal = 0; - jobFull = FALSE; - - aborting = 0; - errors = 0; - - lastNode = NILGNODE; - - if (maxJobs == 1) { - /* - * If only one job can run at a time, there's no need for a banner, - * no is there? - */ - targFmt = ""; - } else { - targFmt = TARG_FMT; - } - - if (shellPath == (char *) NULL) { - /* - * The user didn't specify a shell to use, so we are using the - * default one... Both the absolute path and the last component - * must be set. The last component is taken from the 'name' field - * of the default shell description pointed-to by commandShell. - * All default shells are located in _PATH_DEFSHELLDIR. - */ - shellName = commandShell->name; - shellPath = str_concat (_PATH_DEFSHELLDIR, shellName, STR_ADDSLASH); - } - - if (commandShell->exit == (char *)NULL) { - commandShell->exit = ""; - } - if (commandShell->echo == (char *)NULL) { - commandShell->echo = ""; - } - - /* - * Catch the four signals that POSIX specifies if they aren't ignored. - * JobPassSig will take care of calling JobInterrupt if appropriate. - */ - if (signal (SIGINT, SIG_IGN) != SIG_IGN) { - signal (SIGINT, JobPassSig); - } - if (signal (SIGHUP, SIG_IGN) != SIG_IGN) { - signal (SIGHUP, JobPassSig); - } - if (signal (SIGQUIT, SIG_IGN) != SIG_IGN) { - signal (SIGQUIT, JobPassSig); - } - if (signal (SIGTERM, SIG_IGN) != SIG_IGN) { - signal (SIGTERM, JobPassSig); - } - /* - * 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) - */ -#if defined(RMT_WANTS_SIGNALS) || defined(USE_PGRP) - if (signal (SIGTSTP, SIG_IGN) != SIG_IGN) { - signal (SIGTSTP, JobPassSig); - } - if (signal (SIGTTOU, SIG_IGN) != SIG_IGN) { - signal (SIGTTOU, JobPassSig); - } - if (signal (SIGTTIN, SIG_IGN) != SIG_IGN) { - signal (SIGTTIN, JobPassSig); - } - if (signal (SIGWINCH, SIG_IGN) != SIG_IGN) { - signal (SIGWINCH, JobPassSig); - } -#endif - - begin = Targ_FindNode (".BEGIN", TARG_NOCREATE); - - if (begin != NILGNODE) { - JobStart (begin, JOB_SPECIAL, (Job *)0); - while (nJobs) { - Job_CatchOutput(); -#ifndef RMT_WILL_WATCH - Job_CatchChildren (!usePipes); -#endif /* RMT_WILL_WATCH */ - } - } - postCommands = Targ_FindNode (".END", TARG_CREATE); -} - -/*- - *----------------------------------------------------------------------- - * Job_Full -- - * See if the job table is full. It is considered full if it is OR - * if we are in the process of aborting OR if we have - * reached/exceeded our local quota. This prevents any more jobs - * from starting up. - * - * Results: - * TRUE if the job table is full, FALSE otherwise - * Side Effects: - * None. - *----------------------------------------------------------------------- - */ -Boolean -Job_Full () -{ - return (aborting || jobFull); -} - -/*- - *----------------------------------------------------------------------- - * Job_Empty -- - * See if the job table is empty. Because the local concurrency may - * be set to 0, it is possible for the job table to become empty, - * while the list of stoppedJobs remains non-empty. In such a case, - * we want to restart as many jobs as we can. - * - * Results: - * TRUE if it is. FALSE if it ain't. - * - * Side Effects: - * None. - * - * ----------------------------------------------------------------------- - */ -Boolean -Job_Empty () -{ - if (nJobs == 0) { - if (!Lst_IsEmpty(stoppedJobs) && !aborting) { - /* - * The job table is obviously not full if it has no jobs in - * it...Try and restart the stopped jobs. - */ - jobFull = FALSE; - while (!jobFull && !Lst_IsEmpty(stoppedJobs)) { - JobRestart((Job *)Lst_DeQueue(stoppedJobs)); - } - return(FALSE); - } else { - return(TRUE); - } - } else { - return(FALSE); - } -} - -/*- - *----------------------------------------------------------------------- - * JobMatchShell -- - * Find a matching shell in 'shells' given its final component. - * - * Results: - * A pointer to the Shell structure. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ -static Shell * -JobMatchShell (name) - char *name; /* Final component of shell path */ -{ - register Shell *sh; /* Pointer into shells table */ - Shell *match; /* Longest-matching shell */ - register char *cp1, - *cp2; - char *eoname; - - eoname = name + strlen (name); - - match = (Shell *) NULL; - - for (sh = shells; sh->name != NULL; sh++) { - for (cp1 = eoname - strlen (sh->name), cp2 = sh->name; - *cp1 != '\0' && *cp1 == *cp2; - cp1++, cp2++) { - continue; - } - if (*cp1 != *cp2) { - continue; - } else if (match == (Shell *) NULL || - strlen (match->name) < strlen (sh->name)) { - match = sh; - } - } - return (match == (Shell *) NULL ? sh : match); -} - -/*- - *----------------------------------------------------------------------- - * Job_ParseShell -- - * Parse a shell specification and set up commandShell, shellPath - * and shellName appropriately. - * - * 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. Overrides "name" if given - * 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 - * 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 (line) - char *line; /* The shell spec */ -{ - char **words; - int wordCount; - register char **argv; - register int argc; - char *path; - Shell newShell; - Boolean fullSpec = FALSE; - - while (isspace (*line)) { - line++; - } - words = brk_string (line, &wordCount, TRUE); - - memset ((Address)&newShell, 0, sizeof(newShell)); - - /* - * Parse the specification by keyword - */ - for (path = (char *)NULL, argc = wordCount - 1, argv = words + 1; - 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, "check=", 6) == 0) { - newShell.errCheck = &argv[0][6]; - } else if (strncmp (*argv, "ignore=", 7) == 0) { - newShell.ignErr = &argv[0][7]; - } else { - Parse_Error (PARSE_FATAL, "Unknown keyword \"%s\"", - *argv); - return (FAILURE); - } - fullSpec = TRUE; - } - } - - if (path == (char *)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 - * Job_Init. - */ - if (newShell.name == (char *)NULL) { - Parse_Error (PARSE_FATAL, "Neither path nor name specified"); - return (FAILURE); - } else { - commandShell = JobMatchShell (newShell.name); - shellName = newShell.name; - } - } 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 == (char *)NULL) { - path = shellPath; - } else { - path += 1; - } - if (newShell.name != (char *)NULL) { - shellName = newShell.name; - } else { - shellName = path; - } - if (!fullSpec) { - commandShell = JobMatchShell (shellName); - } else { - commandShell = (Shell *) emalloc(sizeof(Shell)); - *commandShell = newShell; - } - } - - if (commandShell->echoOn && commandShell->echoOff) { - commandShell->hasEchoCtl = TRUE; - } - - if (!commandShell->hasErrCtl) { - if (commandShell->errCheck == (char *)NULL) { - commandShell->errCheck = ""; - } - if (commandShell->ignErr == (char *)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. - * - * Results: - * None - * - * Side Effects: - * All children are killed. Another job will be started if the - * .INTERRUPT target was given. - *----------------------------------------------------------------------- - */ -static void -JobInterrupt (runINTERRUPT) - int runINTERRUPT; /* Non-zero if commands for the .INTERRUPT - * target should be executed */ -{ - LstNode ln; /* element in job table */ - Job *job; /* job descriptor in that element */ - GNode *interrupt; /* the node describing the .INTERRUPT target */ - - aborting = ABORT_INTERRUPT; - - (void)Lst_Open (jobs); - while ((ln = Lst_Next (jobs)) != NILLNODE) { - job = (Job *) Lst_Datum (ln); - - if (!Targ_Precious (job->node)) { - char *file = (job->node->path == (char *)NULL ? - job->node->name : - job->node->path); - struct stat st; - if (!noExecute && lstat(file, &st) != -1 && !S_ISDIR(st.st_mode) && - unlink(file) != -1) { - Error ("*** %s removed", file); - } - } -#ifdef RMT_WANTS_SIGNALS - if (job->flags & JOB_REMOTE) { - /* - * If job is remote, let the Rmt module do the killing. - */ - if (!Rmt_Signal(job, SIGINT)) { - /* - * If couldn't kill the thing, finish it out now with an - * error code, since no exit report will come in likely. - */ - union wait status; - - status.w_status = 0; - status.w_retcode = 1; - JobFinish(job, status); - } - } else if (job->pid) { - KILL(job->pid, SIGINT); - } -#else - if (job->pid) { - KILL(job->pid, SIGINT); - } -#endif /* RMT_WANTS_SIGNALS */ - } - Lst_Close (jobs); - - if (runINTERRUPT && !touchFlag) { - interrupt = Targ_FindNode (".INTERRUPT", TARG_NOCREATE); - if (interrupt != NILGNODE) { - ignoreErrors = FALSE; - - JobStart (interrupt, JOB_IGNDOTS, (Job *)0); - while (nJobs) { - Job_CatchOutput(); -#ifndef RMT_WILL_WATCH - Job_CatchChildren (!usePipes); -#endif /* RMT_WILL_WATCH */ - } - } - } - (void) unlink (tfile); - exit (0); -} - -/* - *----------------------------------------------------------------------- - * Job_End -- - * Do final processing such as the running of the commands - * attached to the .END target. - * - * Results: - * Number of errors reported. - * - * Side Effects: - * The process' temporary file (tfile) is removed if it still - * existed. - *----------------------------------------------------------------------- - */ -int -Job_End () -{ - if (postCommands != NILGNODE && !Lst_IsEmpty (postCommands->commands)) { - if (errors) { - Error ("Errors reported so .END ignored"); - } else { - JobStart (postCommands, JOB_SPECIAL | JOB_IGNDOTS, - (Job *)0); - - while (nJobs) { - Job_CatchOutput(); -#ifndef RMT_WILL_WATCH - Job_CatchChildren (!usePipes); -#endif /* RMT_WILL_WATCH */ - } - } - } - (void) unlink (tfile); - return(errors); -} - -/*- - *----------------------------------------------------------------------- - * 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() -{ - aborting = ABORT_WAIT; - while (nJobs != 0) { - Job_CatchOutput(); -#ifndef RMT_WILL_WATCH - Job_CatchChildren(!usePipes); -#endif /* RMT_WILL_WATCH */ - } - 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 () -{ - LstNode ln; /* element in job table */ - Job *job; /* the job descriptor in that element */ - int foo; - - aborting = ABORT_ERROR; - - if (nJobs) { - - (void)Lst_Open (jobs); - while ((ln = Lst_Next (jobs)) != NILLNODE) { - job = (Job *) Lst_Datum (ln); - - /* - * kill the child process with increasingly drastic signals to make - * darn sure it's dead. - */ -#ifdef RMT_WANTS_SIGNALS - if (job->flags & JOB_REMOTE) { - Rmt_Signal(job, SIGINT); - Rmt_Signal(job, SIGKILL); - } else { - KILL(job->pid, SIGINT); - KILL(job->pid, SIGKILL); - } -#else - KILL(job->pid, SIGINT); - KILL(job->pid, SIGKILL); -#endif /* RMT_WANTS_SIGNALS */ - } - } - - /* - * Catch as many children as want to report in at first, then give up - */ - while (wait3(&foo, WNOHANG, (struct rusage *)0) > 0) - continue; - (void) unlink (tfile); -} diff --git a/usr.bin/make/job.h b/usr.bin/make/job.h deleted file mode 100644 index 5feb43fb6e435..0000000000000 --- a/usr.bin/make/job.h +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * 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. - * - * @(#)job.h 8.2 (Berkeley) 4/28/95 - */ - -/*- - * job.h -- - * Definitions pertaining to the running of jobs in parallel mode. - * Exported from job.c for the use of remote-execution modules. - */ -#ifndef _JOB_H_ -#define _JOB_H_ - -#define TMPPAT "/tmp/makeXXXXX" - -/* - * The SEL_ constants determine the maximum amount of time spent in select - * before coming out to see if a child has finished. SEL_SEC is the number of - * seconds and SEL_USEC is the number of micro-seconds - */ -#define SEL_SEC 0 -#define SEL_USEC 500000 - - -/*- - * 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 NILLNODE 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) A union of things used for handling the shell's output. Different - * parts of the union are used based on the value of the usePipes - * flag. If it is true, 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. If, on the other hand, usePipes is false, - * the output is routed to a temporary file and all that is kept - * is the name of the file and the descriptor open to the file. - * 6) An identifier provided by and for the exclusive use of the - * Rmt module. - * 7) A word of flags which determine how the module handles errors, - * echoing, etc. for the job - * - * The job "table" is kept as a linked Lst in 'jobs', with the number of - * active jobs maintained in the 'nJobs' variable. At no time will this - * exceed the value of 'maxJobs', initialized by the Job_Init function. - * - * 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. - */ -#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 rmtID; /* ID returned from Rmt module */ - 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_REMOTE 0x010 /* Job is running remotely */ -#define JOB_FIRST 0x020 /* Job is first job for the node */ -#define JOB_REMIGRATE 0x040 /* Job needs to be remigrated */ -#define JOB_RESTART 0x080 /* Job needs to be completely restarted */ -#define JOB_RESUME 0x100 /* Job needs to be resumed b/c it stopped, - * for some reason */ -#define JOB_CONTINUING 0x200 /* We are in the process of resuming this job. - * Used to avoid infinite recursion between - * JobFinish and JobRestart */ - union { - struct { - int op_inPipe; /* Input side of pipe associated - * with job's output channel */ - int op_outPipe; /* Output side of pipe associated with - * job's output channel */ - char op_outBuf[JOB_BUFSIZE + 1]; - /* Buffer for storing the output of the - * job, line by line */ - int op_curPos; /* Current position in op_outBuf */ - } o_pipe; /* data used when catching the output via - * a pipe */ - struct { - char of_outFile[sizeof(TMPPAT)+2]; - /* Name of file to which shell output - * was rerouted */ - int of_outFd; /* Stream open to the output - * file. Used to funnel all - * from a single job to one file - * while still allowing - * multiple shell invocations */ - } o_file; /* Data used when catching the output in - * a temporary file */ - } output; /* Data for tracking a shell's output */ -} Job; - -#define outPipe output.o_pipe.op_outPipe -#define inPipe output.o_pipe.op_inPipe -#define outBuf output.o_pipe.op_outBuf -#define curPos output.o_pipe.op_curPos -#define outFile output.o_file.of_outFile -#define outFd output.o_file.of_outFd - - -/*- - * 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. If either of these - * strings is empty when hasErrCtl is FALSE, the command will be executed - * anyway as is and if it causes an error, so be it. - */ -typedef struct Shell { - 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 */ - char *echoOff; /* command to turn off echo */ - char *echoOn; /* command to turn it back on again */ - 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 */ - char *errCheck; /* string to turn error checking on */ - char *ignErr; /* string to turn off error checking */ - /* - * command-line flags - */ - char *echo; /* echo commands */ - char *exit; /* exit on error */ -} Shell; - - -extern char *targFmt; /* Format string for banner that separates - * output from multiple jobs. Contains a - * single %s where the name of the node being - * made should be put. */ -extern GNode *lastNode; /* Last node for which a banner was printed. - * If Rmt module finds it necessary to print - * a banner, it should set this to the node - * for which the banner was printed */ -extern int nJobs; /* Number of jobs running (local and remote) */ -extern int nLocal; /* Number of jobs running locally */ -extern Lst jobs; /* List of active job descriptors */ -extern Lst stoppedJobs; /* List of jobs that are stopped or didn't - * quite get started */ -extern Boolean jobFull; /* Non-zero if no more jobs should/will start*/ - - -void Job_Touch __P((GNode *, Boolean)); -Boolean Job_CheckCommands __P((GNode *, void (*abortProc )(char *, ...))); -void Job_CatchChildren __P((Boolean)); -void Job_CatchOutput __P((void)); -void Job_Make __P((GNode *)); -void Job_Init __P((int, int)); -Boolean Job_Full __P((void)); -Boolean Job_Empty __P((void)); -ReturnStatus Job_ParseShell __P((char *)); -int Job_End __P((void)); -void Job_Wait __P((void)); -void Job_AbortAll __P((void)); -void JobFlagForMigration __P((int)); - -#endif /* _JOB_H_ */ diff --git a/usr.bin/make/list.h b/usr.bin/make/list.h deleted file mode 100644 index 41b9a19302938..0000000000000 --- a/usr.bin/make/list.h +++ /dev/null @@ -1,298 +0,0 @@ -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * 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. - * - * @(#)list.h 8.2 (Berkeley) 4/28/95 - */ - -/* - * list.h -- - * - * Structures, macros, and routines exported by the List module. - */ - -#ifndef _LIST -#define _LIST - -#ifndef _SPRITE -#include "sprite.h" -#endif _SPRITE - -/* - * This module defines the list abstraction, which enables one to link - * together arbitrary data structures. Lists are doubly-linked and - * circular. A list contains a header followed by its real members, if - * any. (An empty list therefore consists of a single element, the - * header, whose nextPtr and prevPtr fields point to itself). To refer - * to a list as a whole, the user keeps a pointer to the header; that - * header is initialized by a call to List_Init(), which creates an empty - * list given a pointer to a List_Links structure (described below). - * - * The links are contained in a two-element structure called List_Links. - * A list joins List_Links records (that is, each List_Links structure - * points to other List_Links structures), but if the List_Links is the - * first field within a larger structure, then the larger structures are - * effectively linked together as follows: - * - * header - * (List_Links) first elt. second elt. - * ----------------- ----------------- ----------------- - * ..-> | nextPtr | ----> | List_Links | ----> | List_Links |----.. - * | - - - - - - - | | | | | - * ..-- | prevPtr | <---- | | <---- | |<---.. - * ----------------- - --- --- --- - - --- --- --- - - * | rest of | | rest of | - * | structure | | structure | - * | | | | - * | ... | | ... | - * ----------------- ----------------- - * - * It is possible to link structures through List_Links fields that are - * not at the beginning of the larger structure, but it is then necessary - * to perform pointer arithmetic to find the beginning of the larger - * structure, given a pointer to some point within it. - * - * A typical structure might be something like: - * - * typedef struct { - * List_Links links; - * char ch; - * integer flags; - * } EditChar; - * - * Before an element is inserted in a list for the first time, it must - * be initialized by calling the macro List_InitElement(). - */ - - -/* - * data structure for lists - */ - -typedef struct List_Links { - struct List_Links *prevPtr; - struct List_Links *nextPtr; -} List_Links; - -/* - * procedures - */ - -void List_Init(); /* initialize a header to a list */ -void List_Insert(); /* insert an element into a list */ -void List_Remove(); /* remove an element from a list */ -void List_Move(); /* move an element elsewhere in a list */ - -/* - * ---------------------------------------------------------------------------- - * - * List_InitElement -- - * - * Initialize a list element. Must be called before an element is first - * inserted into a list. - * - * ---------------------------------------------------------------------------- - */ -#define List_InitElement(elementPtr) \ - (elementPtr)->prevPtr = (List_Links *) NIL; \ - (elementPtr)->nextPtr = (List_Links *) NIL; - -/* - * Macros for stepping through or selecting parts of lists - */ - -/* - * ---------------------------------------------------------------------------- - * - * LIST_FORALL -- - * - * Macro to loop through a list and perform an operation on each member. - * - * Usage: LIST_FORALL(headerPtr, itemPtr) { - * / * - * * operation on itemPtr, which points to successive members - * * of the list - * * - * * It may be appropriate to first assign - * * foobarPtr = (Foobar *) itemPtr; - * * to refer to the entire Foobar structure. - * * / - * } - * - * Note: itemPtr must be a List_Links pointer variable, and headerPtr - * must evaluate to a pointer to a List_Links structure. - * - * ---------------------------------------------------------------------------- - */ - -#define LIST_FORALL(headerPtr, itemPtr) \ - for (itemPtr = List_First(headerPtr); \ - !List_IsAtEnd((headerPtr),itemPtr); \ - itemPtr = List_Next(itemPtr)) - -/* - * ---------------------------------------------------------------------------- - * - * List_IsEmpty -- - * - * Macro: Boolean value, TRUE if the given list does not contain any - * members. - * - * Usage: if (List_IsEmpty(headerPtr)) ... - * - * ---------------------------------------------------------------------------- - */ - -#define List_IsEmpty(headerPtr) \ - ((headerPtr) == (headerPtr)->nextPtr) - -/* - * ---------------------------------------------------------------------------- - * - * List_IsAtEnd -- - * - * Macro: Boolean value, TRUE if itemPtr is after the end of headerPtr - * (i.e., itemPtr is the header of the list). - * - * Usage: if (List_IsAtEnd(headerPtr, itemPtr)) ... - * - * ---------------------------------------------------------------------------- - */ - - -#define List_IsAtEnd(headerPtr, itemPtr) \ - ((itemPtr) == (headerPtr)) - - -/* - * ---------------------------------------------------------------------------- - * - * List_First -- - * - * Macro to return the first member in a list, which is the header if - * the list is empty. - * - * Usage: firstPtr = List_First(headerPtr); - * - * ---------------------------------------------------------------------------- - */ - -#define List_First(headerPtr) ((headerPtr)->nextPtr) - -/* - * ---------------------------------------------------------------------------- - * - * List_Last -- - * - * Macro to return the last member in a list, which is the header if - * the list is empty. - * - * Usage: lastPtr = List_Last(headerPtr); - * - * ---------------------------------------------------------------------------- - */ - -#define List_Last(headerPtr) ((headerPtr)->prevPtr) - -/* - * ---------------------------------------------------------------------------- - * - * List_Prev -- - * - * Macro to return the member preceding the given member in its list. - * If the given list member is the first element in the list, List_Prev - * returns the list header. - * - * Usage: prevPtr = List_Prev(itemPtr); - * - * ---------------------------------------------------------------------------- - */ - -#define List_Prev(itemPtr) ((itemPtr)->prevPtr) - -/* - * ---------------------------------------------------------------------------- - * - * List_Next -- - * - * Macro to return the member following the given member in its list. - * If the given list member is the last element in the list, List_Next - * returns the list header. - * - * Usage: nextPtr = List_Next(itemPtr); - * - * ---------------------------------------------------------------------------- - */ - -#define List_Next(itemPtr) ((itemPtr)->nextPtr) - - -/* - * ---------------------------------------------------------------------------- - * The List_Insert procedure takes two arguments. The first argument - * is a pointer to the structure to be inserted into a list, and - * the second argument is a pointer to the list member after which - * the new element is to be inserted. Macros are used to determine - * which existing member will precede the new one. - * - * The List_Move procedure takes a destination argument with the same - * semantics as List_Insert. - * - * The following macros define where to insert the new element - * in the list: - * - * LIST_AFTER(itemPtr) -- insert after itemPtr - * LIST_BEFORE(itemPtr) -- insert before itemPtr - * LIST_ATFRONT(headerPtr) -- insert at front of list - * LIST_ATREAR(headerPtr) -- insert at end of list - * - * For example, - * - * List_Insert(itemPtr, LIST_AFTER(otherPtr)); - * - * will insert itemPtr following otherPtr in the list containing otherPtr. - * ---------------------------------------------------------------------------- - */ - -#define LIST_AFTER(itemPtr) ((List_Links *) itemPtr) - -#define LIST_BEFORE(itemPtr) (((List_Links *) itemPtr)->prevPtr) - -#define LIST_ATFRONT(headerPtr) ((List_Links *) headerPtr) - -#define LIST_ATREAR(headerPtr) (((List_Links *) headerPtr)->prevPtr) - -#endif /* _LIST */ diff --git a/usr.bin/make/lst.h b/usr.bin/make/lst.h deleted file mode 100644 index 8d8abe04c814e..0000000000000 --- a/usr.bin/make/lst.h +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * 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. - * - * @(#)lst.h 8.2 (Berkeley) 4/28/95 - */ - -/*- - * lst.h -- - * Header for using the list library - */ -#ifndef _LST_H_ -#define _LST_H_ - -#include <sprite.h> -#if __STDC__ -#include <stdlib.h> -#endif - -/* - * basic typedef. This is what the Lst_ functions handle - */ - -typedef struct Lst *Lst; -typedef struct LstNode *LstNode; - -#define NILLST ((Lst) NIL) -#define NILLNODE ((LstNode) NIL) - -/* - * NOFREE can be used as the freeProc to Lst_Destroy when the elements are - * not to be freed. - * NOCOPY performs similarly when given as the copyProc to Lst_Duplicate. - */ -#define NOFREE ((void (*) __P((ClientData))) 0) -#define NOCOPY ((ClientData (*) __P((ClientData))) 0) - -#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 __P((Boolean)); -/* Duplicate an existing list */ -Lst Lst_Duplicate __P((Lst, ClientData (*)(ClientData))); -/* Destroy an old one */ -void Lst_Destroy __P((Lst, void (*)(ClientData))); -/* True if list is empty */ -Boolean Lst_IsEmpty __P((Lst)); - -/* - * Functions to modify a list - */ -/* Insert an element before another */ -ReturnStatus Lst_Insert __P((Lst, LstNode, ClientData)); -/* Insert an element after another */ -ReturnStatus Lst_Append __P((Lst, LstNode, ClientData)); -/* Place an element at the front of a lst. */ -ReturnStatus Lst_AtFront __P((Lst, ClientData)); -/* Place an element at the end of a lst. */ -ReturnStatus Lst_AtEnd __P((Lst, ClientData)); -/* Remove an element */ -ReturnStatus Lst_Remove __P((Lst, LstNode)); -/* Replace a node with a new value */ -ReturnStatus Lst_Replace __P((LstNode, ClientData)); -/* Concatenate two lists */ -ReturnStatus Lst_Concat __P((Lst, Lst, int)); - -/* - * Node-specific functions - */ -/* Return first element in list */ -LstNode Lst_First __P((Lst)); -/* Return last element in list */ -LstNode Lst_Last __P((Lst)); -/* Return successor to given element */ -LstNode Lst_Succ __P((LstNode)); -/* Get datum from LstNode */ -ClientData Lst_Datum __P((LstNode)); - -/* - * Functions for entire lists - */ -/* Find an element in a list */ -LstNode Lst_Find __P((Lst, ClientData, - int (*)(ClientData, ClientData))); -/* Find an element starting from somewhere */ -LstNode Lst_FindFrom __P((Lst, LstNode, ClientData, - int (*cProc)(ClientData, ClientData))); -/* - * See if the given datum is on the list. Returns the LstNode containing - * the datum - */ -LstNode Lst_Member __P((Lst, ClientData)); -/* Apply a function to all elements of a lst */ -void Lst_ForEach __P((Lst, int (*)(ClientData, ClientData), - ClientData)); -/* - * 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. - */ -void Lst_ForEachFrom __P((Lst, LstNode, - int (*)(ClientData, ClientData), - ClientData)); -/* - * 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 __P((Lst)); -/* Next element please */ -LstNode Lst_Next __P((Lst)); -/* Done yet? */ -Boolean Lst_IsAtEnd __P((Lst)); -/* Finish table access */ -void Lst_Close __P((Lst)); - -/* - * for using the list as a queue - */ -/* Place an element at tail of queue */ -ReturnStatus Lst_EnQueue __P((Lst, ClientData)); -/* Remove an element from head of queue */ -ClientData Lst_DeQueue __P((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 1e73eca40479f..0000000000000 --- a/usr.bin/make/lst.lib/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# $NetBSD: Makefile,v 1.3 1995/06/14 15:20:42 christos 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 - -CFLAGS=-I.. -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 93800db01a0bd..0000000000000 --- a/usr.bin/make/lst.lib/lstAppend.c +++ /dev/null @@ -1,113 +0,0 @@ -/* - * 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. 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 lint -static char sccsid[] = "@(#)lstAppend.c 8.2 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * LstAppend.c -- - * Add a new node with a new datum after an existing node - */ - -#include "lstInt.h" - -/*- - *----------------------------------------------------------------------- - * Lst_Append -- - * Create a new node and add it to the given list after the given node. - * - * 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 NILLNODE. - * - *----------------------------------------------------------------------- - */ -ReturnStatus -Lst_Append (l, ln, d) - Lst l; /* affected list */ - LstNode ln; /* node after which to append the datum */ - ClientData d; /* said datum */ -{ - register List list; - register ListNode lNode; - register ListNode nLNode; - - if (LstValid (l) && (ln == NILLNODE && LstIsEmpty (l))) { - goto ok; - } - - if (!LstValid (l) || LstIsEmpty (l) || ! LstNodeValid (ln, l)) { - return (FAILURE); - } - ok: - - list = (List)l; - lNode = (ListNode)ln; - - PAlloc (nLNode, ListNode); - nLNode->datum = d; - nLNode->useCount = nLNode->flags = 0; - - if (lNode == NilListNode) { - if (list->isCirc) { - nLNode->nextPtr = nLNode->prevPtr = nLNode; - } else { - nLNode->nextPtr = nLNode->prevPtr = NilListNode; - } - list->firstPtr = list->lastPtr = nLNode; - } else { - nLNode->prevPtr = lNode; - nLNode->nextPtr = lNode->nextPtr; - - lNode->nextPtr = nLNode; - if (nLNode->nextPtr != NilListNode) { - 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 e61a28c0673fc..0000000000000 --- a/usr.bin/make/lst.lib/lstAtEnd.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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. 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 lint -static char sccsid[] = "@(#)lstAtEnd.c 8.2 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * 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 - * - * Results: - * SUCCESS if life is good. - * - * Side Effects: - * A new ListNode is created and added to the list. - * - *----------------------------------------------------------------------- - */ -ReturnStatus -Lst_AtEnd (l, d) - Lst l; /* List to which to add the datum */ - ClientData d; /* Datum to add */ -{ - register LstNode end; - - end = Lst_Last (l); - return (Lst_Append (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 5e8b7f1ab4c28..0000000000000 --- a/usr.bin/make/lst.lib/lstAtFront.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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. 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 lint -static char sccsid[] = "@(#)lstAtFront.c 8.2 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * 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 (l, d) - Lst l; - ClientData d; -{ - register LstNode front; - - front = Lst_First (l); - return (Lst_Insert (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 6f9174f3db8ab..0000000000000 --- a/usr.bin/make/lst.lib/lstClose.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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. 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 lint -static char sccsid[] = "@(#)lstClose.c 8.2 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * 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. - * - * Results: - * None. - * - * Side Effects: - * The list is closed. - * - *----------------------------------------------------------------------- - */ -void -Lst_Close (l) - Lst l; /* The list to close */ -{ - register List 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 e7726a862b60e..0000000000000 --- a/usr.bin/make/lst.lib/lstConcat.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * 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. 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 lint -static char sccsid[] = "@(#)lstConcat.c 8.2 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * 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. - * - * Results: - * SUCCESS if all went well. FAILURE otherwise. - * - * Side Effects: - * New elements are created and appended the the first list. - *----------------------------------------------------------------------- - */ -ReturnStatus -Lst_Concat (l1, l2, flags) - Lst l1; /* The list to which l2 is to be appended */ - Lst l2; /* The list to append to l1 */ - int flags; /* LST_CONCNEW if LstNode's should be duplicated - * LST_CONCLINK if should just be relinked */ -{ - register ListNode ln; /* original LstNode */ - register ListNode nln; /* new LstNode */ - register ListNode last; /* the last element in the list. Keeps - * bookkeeping until the end */ - register List list1 = (List)l1; - register List list2 = (List)l2; - - if (!LstValid (l1) || !LstValid (l2)) { - return (FAILURE); - } - - if (flags == LST_CONCLINK) { - if (list2->firstPtr != NilListNode) { - /* - * 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 = NilListNode; - /* - * 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 != NilListNode) { - list1->lastPtr->nextPtr = list2->firstPtr; - } else { - list1->firstPtr = list2->firstPtr; - } - list1->lastPtr = list2->lastPtr; - } - if (list1->isCirc && list1->firstPtr != NilListNode) { - /* - * 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 ((Address)l2); - } else if (list2->firstPtr != NilListNode) { - /* - * 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 = NilListNode; - for (last = list1->lastPtr, ln = list2->firstPtr; - ln != NilListNode; - ln = ln->nextPtr) - { - PAlloc (nln, ListNode); - nln->datum = ln->datum; - if (last != NilListNode) { - 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 = NilListNode; - } - - 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 6b0988e0fa2bc..0000000000000 --- a/usr.bin/make/lst.lib/lstDatum.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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. 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 lint -static char sccsid[] = "@(#)lstDatum.c 8.2 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * 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 (ick!) NIL if the node is invalid. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ -ClientData -Lst_Datum (ln) - LstNode ln; -{ - if (ln != NILLNODE) { - return (((ListNode)ln)->datum); - } else { - return ((ClientData) NIL); - } -} - diff --git a/usr.bin/make/lst.lib/lstDeQueue.c b/usr.bin/make/lst.lib/lstDeQueue.c deleted file mode 100644 index 4b901257b0018..0000000000000 --- a/usr.bin/make/lst.lib/lstDeQueue.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * 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. 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 lint -static char sccsid[] = "@(#)lstDeQueue.c 8.2 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * 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 (ick) NIL if the list - * is empty. - * - * Side Effects: - * The head node is removed from the list. - * - *----------------------------------------------------------------------- - */ -ClientData -Lst_DeQueue (l) - Lst l; -{ - ClientData rd; - register ListNode tln; - - tln = (ListNode) Lst_First (l); - if (tln == NilListNode) { - return ((ClientData) NIL); - } - - rd = tln->datum; - if (Lst_Remove (l, (LstNode)tln) == FAILURE) { - return ((ClientData) NIL); - } 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 56ea5c528fe6c..0000000000000 --- a/usr.bin/make/lst.lib/lstDestroy.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - * 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. 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 lint -static char sccsid[] = "@(#)lstDestroy.c 8.2 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * 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 (l, freeProc) - Lst l; - register void (*freeProc) __P((ClientData)); -{ - register ListNode ln; - register ListNode tln = NilListNode; - register List list = (List)l; - - if (l == NILLST || ! l) { - /* - * Note the check for l == (Lst)0 to catch uninitialized static Lst's. - * Gross, but useful. - */ - return; - } - - /* To ease scanning */ - if (list->lastPtr != NilListNode) - list->lastPtr->nextPtr = NilListNode; - else { - free ((Address)l); - return; - } - - if (freeProc) { - for (ln = list->firstPtr; ln != NilListNode; ln = tln) { - tln = ln->nextPtr; - (*freeProc) (ln->datum); - free ((Address)ln); - } - } else { - for (ln = list->firstPtr; ln != NilListNode; ln = tln) { - tln = ln->nextPtr; - free ((Address)ln); - } - } - - free ((Address)l); -} diff --git a/usr.bin/make/lst.lib/lstDupl.c b/usr.bin/make/lst.lib/lstDupl.c deleted file mode 100644 index 184b386228d39..0000000000000 --- a/usr.bin/make/lst.lib/lstDupl.c +++ /dev/null @@ -1,99 +0,0 @@ -/* - * 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. 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 lint -static char sccsid[] = "@(#)lstDupl.c 8.2 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * 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 ClientData is - * given, the individual client elements will be duplicated as well. - * - * Results: - * The new Lst structure or NILLST if failure. - * - * Side Effects: - * A new list is created. - *----------------------------------------------------------------------- - */ -Lst -Lst_Duplicate (l, copyProc) - Lst l; /* the list to duplicate */ - /* A function to duplicate each ClientData */ - ClientData (*copyProc) __P((ClientData)); -{ - register Lst nl; - register ListNode ln; - register List list = (List)l; - - if (!LstValid (l)) { - return (NILLST); - } - - nl = Lst_Init (list->isCirc); - if (nl == NILLST) { - return (NILLST); - } - - ln = list->firstPtr; - while (ln != NilListNode) { - if (copyProc != NOCOPY) { - if (Lst_AtEnd (nl, (*copyProc) (ln->datum)) == FAILURE) { - return (NILLST); - } - } else if (Lst_AtEnd (nl, ln->datum) == FAILURE) { - return (NILLST); - } - - if (list->isCirc && ln == list->lastPtr) { - ln = NilListNode; - } 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 1016c88d28344..0000000000000 --- a/usr.bin/make/lst.lib/lstEnQueue.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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. 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 lint -static char sccsid[] = "@(#)lstEnQueue.c 8.2 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * 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_Append. - * - * 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 (l, d) - Lst l; - ClientData d; -{ - if (LstValid (l) == FALSE) { - return (FAILURE); - } - - return (Lst_Append (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 bab85ccd173ce..0000000000000 --- a/usr.bin/make/lst.lib/lstFind.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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. 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 lint -static char sccsid[] = "@(#)lstFind.c 8.2 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * 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 NILLNODE if none matches. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ -LstNode -Lst_Find (l, d, cProc) - Lst l; - ClientData d; - int (*cProc) __P((ClientData, ClientData)); -{ - 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 08de990afe5c7..0000000000000 --- a/usr.bin/make/lst.lib/lstFindFrom.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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. 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 lint -static char sccsid[] = "@(#)lstFindFrom.c 8.2 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * 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 NILLNODE - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ -LstNode -Lst_FindFrom (l, ln, d, cProc) - Lst l; - register LstNode ln; - register ClientData d; - register int (*cProc) __P((ClientData, ClientData)); -{ - register ListNode tln; - Boolean found = FALSE; - - if (!LstValid (l) || LstIsEmpty (l) || !LstNodeValid (ln, l)) { - return (NILLNODE); - } - - tln = (ListNode)ln; - - do { - if ((*cProc) (tln->datum, d) == 0) { - found = TRUE; - break; - } else { - tln = tln->nextPtr; - } - } while (tln != (ListNode)ln && tln != NilListNode); - - if (found) { - return ((LstNode)tln); - } else { - return (NILLNODE); - } -} - diff --git a/usr.bin/make/lst.lib/lstFirst.c b/usr.bin/make/lst.lib/lstFirst.c deleted file mode 100644 index 9a95018777abc..0000000000000 --- a/usr.bin/make/lst.lib/lstFirst.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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. 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 lint -static char sccsid[] = "@(#)lstFirst.c 8.2 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * 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 NILLNODE if the list is empty. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ -LstNode -Lst_First (l) - Lst l; -{ - if (!LstValid (l) || LstIsEmpty (l)) { - return (NILLNODE); - } else { - return ((LstNode)((List)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 1d6ba9396dc6f..0000000000000 --- a/usr.bin/make/lst.lib/lstForEach.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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. 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 lint -static char sccsid[] = "@(#)lstForEach.c 8.2 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * 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*/ -void -Lst_ForEach (l, proc, d) - Lst l; - register int (*proc) __P((ClientData, ClientData)); - register ClientData d; -{ - 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 7c9e51e749f08..0000000000000 --- a/usr.bin/make/lst.lib/lstForEachFrom.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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. 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 lint -static char sccsid[] = "@(#)lstForEachFrom.c 8.2 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * 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*/ -void -Lst_ForEachFrom (l, ln, proc, d) - Lst l; - LstNode ln; - register int (*proc)(); - register ClientData d; -{ - register ListNode tln = (ListNode)ln; - register List list = (List)l; - register ListNode next; - Boolean done; - int result; - - if (!LstValid (list) || LstIsEmpty (list)) { - return; - } - - do { - /* - * Take care of having the current element deleted out from under - * us. - */ - - next = tln->nextPtr; - - (void) tln->useCount++; - result = (*proc) (tln->datum, d); - (void) tln->useCount--; - - /* - * We're done with the traversal if - * - nothing's been added after the current node and - * - the next node to examine is the first in the queue or - * doesn't exist. - */ - done = (next == tln->nextPtr && - (next == NilListNode || next == list->firstPtr)); - - next = tln->nextPtr; - - if (tln->flags & LN_DELETED) { - free((char *)tln); - } - tln = next; - } while (!result && !LstIsEmpty(list) && !done); - -} diff --git a/usr.bin/make/lst.lib/lstInit.c b/usr.bin/make/lst.lib/lstInit.c deleted file mode 100644 index 17276be6f1e71..0000000000000 --- a/usr.bin/make/lst.lib/lstInit.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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. 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 lint -static char sccsid[] = "@(#)lstInit.c 8.2 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * init.c -- - * Initialize a new linked list. - */ - -#include "lstInt.h" - -/*- - *----------------------------------------------------------------------- - * Lst_Init -- - * Create and initialize a new list. - * - * Results: - * The created list. - * - * Side Effects: - * A list is created, what else? - * - *----------------------------------------------------------------------- - */ -Lst -Lst_Init(circ) - Boolean circ; /* TRUE if the list should be made circular */ -{ - register List nList; - - PAlloc (nList, List); - - nList->firstPtr = NilListNode; - nList->lastPtr = NilListNode; - nList->isOpen = FALSE; - nList->isCirc = circ; - nList->atEnd = Unknown; - - return ((Lst)nList); -} diff --git a/usr.bin/make/lst.lib/lstInsert.c b/usr.bin/make/lst.lib/lstInsert.c deleted file mode 100644 index 724924adf071f..0000000000000 --- a/usr.bin/make/lst.lib/lstInsert.c +++ /dev/null @@ -1,113 +0,0 @@ -/* - * 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. 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 lint -static char sccsid[] = "@(#)lstInsert.c 8.2 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * LstInsert.c -- - * Insert a new datum before an old one - */ - -#include "lstInt.h" - -/*- - *----------------------------------------------------------------------- - * Lst_Insert -- - * Insert a new node with the given piece of data before the given - * node in the given list. - * - * Results: - * SUCCESS or FAILURE. - * - * Side Effects: - * the firstPtr field will be changed if ln is the first node in the - * list. - * - *----------------------------------------------------------------------- - */ -ReturnStatus -Lst_Insert (l, ln, d) - Lst l; /* list to manipulate */ - LstNode ln; /* node before which to insert d */ - ClientData d; /* datum to be inserted */ -{ - register ListNode nLNode; /* new lnode for d */ - register ListNode lNode = (ListNode)ln; - register List list = (List)l; - - - /* - * check validity of arguments - */ - if (LstValid (l) && (LstIsEmpty (l) && ln == NILLNODE)) - 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 == NILLNODE) { - if (list->isCirc) { - nLNode->prevPtr = nLNode->nextPtr = nLNode; - } else { - nLNode->prevPtr = nLNode->nextPtr = NilListNode; - } - list->firstPtr = list->lastPtr = nLNode; - } else { - nLNode->prevPtr = lNode->prevPtr; - nLNode->nextPtr = lNode; - - if (nLNode->prevPtr != NilListNode) { - 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 1253660f8e81f..0000000000000 --- a/usr.bin/make/lst.lib/lstInt.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * 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. 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. - * - * @(#)lstInt.h 8.2 (Berkeley) 4/28/95 - */ - -/*- - * lstInt.h -- - * Internals for the list library - */ -#ifndef _LSTINT_H_ -#define _LSTINT_H_ - -#include "lst.h" - -typedef struct ListNode { - struct ListNode *prevPtr; /* previous element in list */ - struct ListNode *nextPtr; /* next in list */ - short useCount:8, /* Count of functions using the node. - * node may not be deleted until count - * goes to 0 */ - flags:8; /* Node status flags */ - ClientData datum; /* datum associated with this element */ -} *ListNode; -/* - * Flags required for synchronization - */ -#define LN_DELETED 0x0001 /* List node should be removed when done */ - -#define NilListNode ((ListNode)-1) - -typedef enum { - Head, Middle, Tail, Unknown -} Where; - -typedef struct { - 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. NilListNode if - * *just* opened */ - ListNode prevPtr; /* Previous node, if open. Used by - * Lst_Remove */ -} *List; - -#define NilList ((List)-1) - -/* - * PAlloc (var, ptype) -- - * Allocate a pointer-typedef structure 'ptype' into the variable 'var' - */ -#define PAlloc(var,ptype) var = (ptype) malloc (sizeof (*var)) - -/* - * LstValid (l) -- - * Return TRUE if the list l is valid - */ -#define LstValid(l) (((Lst)l == NILLST) ? FALSE : TRUE) - -/* - * LstNodeValid (ln, l) -- - * Return TRUE if the LstNode ln is valid with respect to l - */ -#define LstNodeValid(ln, l) ((((LstNode)ln) == NILLNODE) ? FALSE : TRUE) - -/* - * LstIsEmpty (l) -- - * TRUE if the list l is empty. - */ -#define LstIsEmpty(l) (((List)l)->firstPtr == NilListNode) - -#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 7fdf68dca49c3..0000000000000 --- a/usr.bin/make/lst.lib/lstIsAtEnd.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * 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. 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 lint -static char sccsid[] = "@(#)lstIsAtEnd.c 8.2 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * 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 (l) - Lst l; -{ - register List 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 da475611bfa86..0000000000000 --- a/usr.bin/make/lst.lib/lstIsEmpty.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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. 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 lint -static char sccsid[] = "@(#)lstIsEmpty.c 8.2 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * 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 == NilListNode (or if - * the list itself is NILLIST). - *----------------------------------------------------------------------- - */ -Boolean -Lst_IsEmpty (l) - 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 a87c50c0f8370..0000000000000 --- a/usr.bin/make/lst.lib/lstLast.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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. 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 lint -static char sccsid[] = "@(#)lstLast.c 8.2 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * 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 NILLNODE if the list is empty. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ -LstNode -Lst_Last (l) - Lst l; -{ - if (!LstValid(l) || LstIsEmpty (l)) { - return (NILLNODE); - } else { - return ((LstNode)((List)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 a6145ee64fd31..0000000000000 --- a/usr.bin/make/lst.lib/lstMember.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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. 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 lint -static char sccsid[] = "@(#)lstMember.c 8.2 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * lstMember.c -- - * See if a given datum is on a given list. - */ - -#include "lstInt.h" - -LstNode -Lst_Member (l, d) - Lst l; - ClientData d; -{ - List list = (List) l; - register ListNode lNode; - - lNode = list->firstPtr; - if (lNode == NilListNode) { - return NILLNODE; - } - - do { - if (lNode->datum == d) { - return (LstNode)lNode; - } - lNode = lNode->nextPtr; - } while (lNode != NilListNode && lNode != list->firstPtr); - - return NILLNODE; -} diff --git a/usr.bin/make/lst.lib/lstNext.c b/usr.bin/make/lst.lib/lstNext.c deleted file mode 100644 index b6986d866d59c..0000000000000 --- a/usr.bin/make/lst.lib/lstNext.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * 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. 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 lint -static char sccsid[] = "@(#)lstNext.c 8.2 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * 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 NILLNODE if the list has yet to be opened. Also - * if the list is non-circular and the end has been reached, NILLNODE - * is returned. - * - * Side Effects: - * the curPtr field is updated. - * - *----------------------------------------------------------------------- - */ -LstNode -Lst_Next (l) - Lst l; -{ - register ListNode tln; - register List list = (List)l; - - if ((LstValid (l) == FALSE) || - (list->isOpen == FALSE)) { - return (NILLNODE); - } - - list->prevPtr = list->curPtr; - - if (list->curPtr == NilListNode) { - 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 = NilListNode; - list->atEnd = Tail; - } - } else { - tln = list->curPtr->nextPtr; - list->curPtr = tln; - - if (tln == list->firstPtr || tln == NilListNode) { - /* - * 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 ((LstNode)tln); -} - diff --git a/usr.bin/make/lst.lib/lstOpen.c b/usr.bin/make/lst.lib/lstOpen.c deleted file mode 100644 index 9da8cfab57698..0000000000000 --- a/usr.bin/make/lst.lib/lstOpen.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * 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. 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 lint -static char sccsid[] = "@(#)lstOpen.c 8.2 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * 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 NilListNode so the - * other sequential functions no it was just opened and can choose - * the first element accessed based on this. - * - *----------------------------------------------------------------------- - */ -ReturnStatus -Lst_Open (l) - register Lst l; -{ - if (LstValid (l) == FALSE) { - return (FAILURE); - } - ((List) l)->isOpen = TRUE; - ((List) l)->atEnd = LstIsEmpty (l) ? Head : Unknown; - ((List) l)->curPtr = NilListNode; - - return (SUCCESS); -} - diff --git a/usr.bin/make/lst.lib/lstRemove.c b/usr.bin/make/lst.lib/lstRemove.c deleted file mode 100644 index 98eb3ce53493b..0000000000000 --- a/usr.bin/make/lst.lib/lstRemove.c +++ /dev/null @@ -1,131 +0,0 @@ -/* - * 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. 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 lint -static char sccsid[] = "@(#)lstRemove.c 8.2 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * 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 NilListNode 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 (l, ln) - Lst l; - LstNode ln; -{ - register List list = (List) l; - register ListNode lNode = (ListNode) ln; - - if (!LstValid (l) || - !LstNodeValid (ln, l)) { - return (FAILURE); - } - - /* - * unlink it from the list - */ - if (lNode->nextPtr != NilListNode) { - lNode->nextPtr->prevPtr = lNode->prevPtr; - } - if (lNode->prevPtr != NilListNode) { - 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 == NilListNode), we set the - * end to be Unknown, since it is. - */ - if (list->isOpen && (list->curPtr == lNode)) { - list->curPtr = list->prevPtr; - if (list->curPtr == NilListNode) { - 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 = NilListNode; - } - - /* - * note that the datum is unmolested. The caller must free it as - * necessary and as expected. - */ - if (lNode->useCount == 0) { - free ((Address)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 8adb6895aec17..0000000000000 --- a/usr.bin/make/lst.lib/lstReplace.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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. 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 lint -static char sccsid[] = "@(#)lstReplace.c 8.2 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * 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 (ln, d) - register LstNode ln; - ClientData d; -{ - if (ln == NILLNODE) { - return (FAILURE); - } else { - ((ListNode) 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 a5875f6868742..0000000000000 --- a/usr.bin/make/lst.lib/lstSucc.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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. 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 lint -static char sccsid[] = "@(#)lstSucc.c 8.2 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * LstSucc.c -- - * return the successor to a given node - */ - -#include "lstInt.h" - -/*- - *----------------------------------------------------------------------- - * Lst_Succ -- - * Return the sucessor 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 (ln) - LstNode ln; -{ - if (ln == NILLNODE) { - return (NILLNODE); - } else { - return ((LstNode) ((ListNode) ln)->nextPtr); - } -} - diff --git a/usr.bin/make/main.c b/usr.bin/make/main.c deleted file mode 100644 index 8607fbb08bb6b..0000000000000 --- a/usr.bin/make/main.c +++ /dev/null @@ -1,954 +0,0 @@ -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * 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 lint -static char copyright[] = -"@(#) Copyright (c) 1988, 1989, 1990, 1993\n\ - The Regents of the University of California. All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -static char sccsid[] = "@(#)main.c 8.4 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * 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 two optional - * arguments for it. - * - * Fatal Print an error message and exit. Also takes - * a format string and two arguments. - * - * Punt Aborts all jobs and exits with a message. Also - * takes a format string and two arguments. - * - * Finish Finish things up by printing the number of - * errors which occured, as passed to it, and - * exiting. - */ - -#include <sys/types.h> -#include <sys/time.h> -#include <sys/param.h> -#include <sys/resource.h> -#include <sys/signal.h> -#include <sys/stat.h> -#include <sys/utsname.h> -#include <errno.h> -#include <fcntl.h> -#include <stdio.h> -#if __STDC__ -#include <stdarg.h> -#else -#include <varargs.h> -#endif -#include "make.h" -#include "hash.h" -#include "dir.h" -#include "job.h" -#include "pathnames.h" - -#ifndef DEFMAXLOCAL -#define DEFMAXLOCAL DEFMAXJOBS -#endif DEFMAXLOCAL - -#define MAKEFLAGS ".MAKEFLAGS" - -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 */ - -static Boolean noBuiltins; /* -r flag */ -static Lst makefiles; /* ordered list of makefiles to read */ -int maxJobs; /* -J argument */ -static int maxLocal; /* -L argument */ -Boolean compatMake; /* -B argument */ -Boolean debug; /* -d flag */ -Boolean noExecute; /* -n flag */ -Boolean keepgoing; /* -k flag */ -Boolean queryFlag; /* -q flag */ -Boolean touchFlag; /* -t flag */ -Boolean usePipes; /* !-P flag */ -Boolean ignoreErrors; /* -i flag */ -Boolean beSilent; /* -s flag */ -Boolean oldVars; /* variable substitution style */ -Boolean checkEnvFirst; /* -e flag */ -static Boolean jobsRunning; /* TRUE if the jobs might be running */ - -static Boolean ReadMakefile(); -static void usage(); - -static char *curdir; /* startup directory */ -static char *objdir; /* where we chdir'ed to */ - -/*- - * 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(argc, argv) - int argc; - char **argv; -{ - extern int optind; - extern char *optarg; - int c; - - optind = 1; /* since we're called more than once */ -#ifdef notyet -# define OPTFLAGS "BD:I:L:PSd:ef:ij:knqrst" -#else -# define OPTFLAGS "D:I:d:ef:ij:knqrst" -#endif -rearg: while((c = getopt(argc, argv, OPTFLAGS)) != EOF) { - switch(c) { - case 'D': - Var_Set(optarg, "1", VAR_GLOBAL); - Var_Append(MAKEFLAGS, "-D", VAR_GLOBAL); - Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); - break; - case 'I': - Parse_AddIncludeDir(optarg); - Var_Append(MAKEFLAGS, "-I", VAR_GLOBAL); - Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); - break; -#ifdef notyet - case 'B': - compatMake = TRUE; - break; - case 'L': - maxLocal = atoi(optarg); - Var_Append(MAKEFLAGS, "-L", VAR_GLOBAL); - Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); - break; - case 'P': - usePipes = FALSE; - Var_Append(MAKEFLAGS, "-P", VAR_GLOBAL); - break; - case 'S': - keepgoing = FALSE; - Var_Append(MAKEFLAGS, "-S", VAR_GLOBAL); - break; -#endif - case 'd': { - char *modules = optarg; - - for (; *modules; ++modules) - switch (*modules) { - case 'A': - debug = ~0; - break; - case 'a': - debug |= DEBUG_ARCH; - break; - case 'c': - debug |= DEBUG_COND; - break; - case 'd': - debug |= DEBUG_DIR; - 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; - } - break; - case 'j': - debug |= DEBUG_JOB; - break; - case 'm': - debug |= DEBUG_MAKE; - break; - case 's': - debug |= DEBUG_SUFF; - break; - case 't': - debug |= DEBUG_TARG; - break; - case 'v': - debug |= DEBUG_VAR; - break; - default: - (void)fprintf(stderr, - "make: illegal argument to d option -- %c\n", - *modules); - usage(); - } - Var_Append(MAKEFLAGS, "-d", VAR_GLOBAL); - Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); - break; - } - case 'e': - checkEnvFirst = TRUE; - Var_Append(MAKEFLAGS, "-e", VAR_GLOBAL); - break; - case 'f': - (void)Lst_AtEnd(makefiles, (ClientData)optarg); - break; - case 'i': - ignoreErrors = TRUE; - Var_Append(MAKEFLAGS, "-i", VAR_GLOBAL); - break; - case 'j': - maxJobs = atoi(optarg); - Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL); - Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); - break; - case 'k': - keepgoing = TRUE; - Var_Append(MAKEFLAGS, "-k", 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; - default: - case '?': - usage(); - } - } - - 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 (argv += optind, argc -= optind; *argv; ++argv, --argc) - if (Parse_IsVar(*argv)) - Parse_DoVar(*argv, VAR_CMD); - else { - if (!**argv) - Punt("illegal (null) argument."); - if (**argv == '-') { - if ((*argv)[1]) - optind = 0; /* -flag... */ - else - optind = 1; /* - */ - goto rearg; - } - (void)Lst_AtEnd(create, (ClientData)strdup(*argv)); - } -} - -/*- - * 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. - * - * Results: - * None - * - * Side Effects: - * Only those that come from the various arguments. - */ -void -Main_ParseArgLine(line) - char *line; /* Line to fracture */ -{ - char **argv; /* Manufactured argument vector */ - int argc; /* Number of arguments in argv */ - - if (line == NULL) - return; - for (; *line == ' '; ++line) - continue; - if (!*line) - return; - - argv = brk_string(line, &argc, TRUE); - MainParseArgs(argc, argv); -} - -/*- - * 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(argc, argv) - int argc; - char **argv; -{ - Lst targs; /* target nodes to create -- passed to Make_Init */ - Boolean outOfDate = TRUE; /* FALSE if all targets up to date */ - struct stat sb, sa; - char *p, *p1, *path, *pwd, *getenv(), *getwd(); - char mdpath[MAXPATHLEN + 1]; - char obpath[MAXPATHLEN + 1]; - char cdpath[MAXPATHLEN + 1]; - struct utsname utsname; - char *machine = getenv("MACHINE"); - - /* - * Find where we are and take care of PWD for the automounter... - * All this code is so that we know where we are when we start up - * on a different machine with pmake. - */ - curdir = cdpath; - if (getcwd(curdir, MAXPATHLEN) == NULL) { - (void)fprintf(stderr, "make: %s.\n", strerror(errno)); - exit(2); - } - - if (stat(curdir, &sa) == -1) { - (void)fprintf(stderr, "make: %s: %s.\n", - curdir, strerror(errno)); - exit(2); - } - - if ((pwd = getenv("PWD")) != NULL) { - if (stat(pwd, &sb) == 0 && sa.st_ino == sb.st_ino && - sa.st_dev == sb.st_dev) - (void) strcpy(curdir, pwd); - } - - /* - * 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 while MACHINE is decided at run-time, - * MACHINE_ARCH is always known at compile time. - */ - if (!machine) { - if (uname(&utsname)) { - perror("make: uname"); - exit(2); - } - machine = utsname.machine; - } - - /* - * if the MAKEOBJDIR (or by default, the _PATH_OBJDIR) directory - * exists, change into it and build there. Once things are - * initted, have to add the original directory to the search path, - * and modify the paths for the Makefiles apropriately. The - * current directory is also placed as a variable for make scripts. - */ - if (!(path = getenv("MAKEOBJDIR"))) { - path = _PATH_OBJDIR; - (void) sprintf(mdpath, "%s.%s", path, machine); - } - else - (void) strncpy(mdpath, path, MAXPATHLEN + 1); - - if (stat(mdpath, &sb) == 0 && S_ISDIR(sb.st_mode)) { - - if (chdir(mdpath)) { - (void)fprintf(stderr, "make warning: %s: %s.\n", - mdpath, strerror(errno)); - objdir = curdir; - } - else { - if (mdpath[0] != '/') { - (void) sprintf(obpath, "%s/%s", curdir, mdpath); - objdir = obpath; - } - else - objdir = mdpath; - } - } - else { - if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) { - - if (chdir(path)) { - (void)fprintf(stderr, "make warning: %s: %s.\n", - path, strerror(errno)); - objdir = curdir; - } - else { - if (path[0] != '/') { - (void) sprintf(obpath, "%s/%s", curdir, - path); - objdir = obpath; - } - else - objdir = obpath; - } - } - else - objdir = curdir; - } - - setenv("PWD", objdir, 1); - - create = Lst_Init(FALSE); - makefiles = Lst_Init(FALSE); - beSilent = FALSE; /* Print commands as executed */ - ignoreErrors = FALSE; /* Pay attention to non-zero returns */ - noExecute = FALSE; /* Execute all commands */ - keepgoing = FALSE; /* Stop on error */ - allPrecious = FALSE; /* Remove targets when interrupted */ - queryFlag = FALSE; /* This is not just a check-run */ - noBuiltins = FALSE; /* Read the built-in rules */ - touchFlag = FALSE; /* Actually update targets */ - usePipes = TRUE; /* Catch child output in pipes */ - debug = 0; /* No debug verbosity, please. */ - jobsRunning = FALSE; - - maxJobs = DEFMAXJOBS; /* Set default max concurrency */ - maxLocal = DEFMAXLOCAL; /* Set default local max concurrency */ -#ifdef notyet - compatMake = FALSE; /* No compat mode */ -#else - compatMake = TRUE; /* No compat mode */ -#endif - - - /* - * Initialize the parsing, directory and variable modules to prepare - * for the reading of inclusion paths and variable settings on the - * command line - */ - Dir_Init(); /* Initialize directory structures so -I flags - * can be processed correctly */ - Parse_Init(); /* Need to initialize the paths of #include - * directories */ - Var_Init(); /* As well as the lists of variables for - * parsing arguments */ - str_init(); - if (objdir != curdir) - Dir_AddDir(dirSearchPath, curdir); - Var_Set(".CURDIR", curdir, VAR_GLOBAL); - Var_Set(".OBJDIR", objdir, VAR_GLOBAL); - - /* - * 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. - */ - Var_Set("MAKE", argv[0], VAR_GLOBAL); - Var_Set(MAKEFLAGS, "", VAR_GLOBAL); - Var_Set("MFLAGS", "", VAR_GLOBAL); - Var_Set("MACHINE", machine, VAR_GLOBAL); -#ifdef MACHINE_ARCH - Var_Set("MACHINE_ARCH", MACHINE_ARCH, VAR_GLOBAL); -#endif - - /* - * 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 - Main_ParseArgLine(getenv("MAKEFLAGS")); -#else - Main_ParseArgLine(getenv("MAKE")); -#endif - - MainParseArgs(argc, argv); - - /* - * Initialize archive, target and suffix modules in preparation for - * parsing the makefile(s) - */ - Arch_Init(); - Targ_Init(); - Suff_Init(); - - DEFAULT = NILGNODE; - (void)time(&now); - - /* - * 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 != NILLNODE; - ln = Lst_Succ(ln)) { - char *name = (char *)Lst_Datum(ln); - - Var_Append(".TARGETS", name, VAR_GLOBAL); - } - } else - Var_Set(".TARGETS", "", VAR_GLOBAL); - - /* - * Read in the built-in rules first, followed by the specified makefile, - * if it was (makefile != (char *) NULL), or the default Makefile and - * makefile, in that order, if it wasn't. - */ - if (!noBuiltins && !ReadMakefile(_PATH_DEFSYSMK)) - Fatal("make: no system rules (%s).", _PATH_DEFSYSMK); - - if (!Lst_IsEmpty(makefiles)) { - LstNode ln; - - ln = Lst_Find(makefiles, (ClientData)NULL, ReadMakefile); - if (ln != NILLNODE) - Fatal("make: cannot open %s.", (char *)Lst_Datum(ln)); - } else if (!ReadMakefile("makefile")) - (void)ReadMakefile("Makefile"); - - (void)ReadMakefile(".depend"); - - Var_Append("MFLAGS", Var_Value(MAKEFLAGS, VAR_GLOBAL, &p1), VAR_GLOBAL); - if (p1) - free(p1); - - /* Install all the flags into the MAKE envariable. */ - if (((p = Var_Value(MAKEFLAGS, VAR_GLOBAL, &p1)) != NULL) && *p) -#ifdef POSIX - setenv("MAKEFLAGS", p, 1); -#else - setenv("MAKE", p, 1); -#endif - if (p1) - free(p1); - - /* - * 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, *path, *cp, 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, FALSE); - 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 */ - Dir_AddDir(dirSearchPath, path); - *cp = savec; - path = cp + 1; - } while (savec == ':'); - (void)free((Address)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(); - - /* print the initial graph, if the user requested it */ - if (DEBUG(GRAPH1)) - Targ_PrintGraph(1); - - /* - * 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); - -/* - * this was original amMake -- want to allow parallelism, so put this - * back in, eventually. - */ - 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) { - if (maxLocal == -1) - maxLocal = maxJobs; - Job_Init(maxJobs, maxLocal); - 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); - - Lst_Destroy(targs, NOFREE); - Lst_Destroy(makefiles, NOFREE); - Lst_Destroy(create, (void (*) __P((ClientData))) free); - - /* print the graph now it's been processed if the user requested it */ - if (DEBUG(GRAPH2)) - Targ_PrintGraph(2); - - Suff_End(); - Targ_End(); - Arch_End(); - str_end(); - Var_End(); - Parse_End(); - Dir_End(); - - if (queryFlag && outOfDate) - return(1); - else - return(0); -} - -/*- - * ReadMakefile -- - * Open and parse the given makefile. - * - * Results: - * TRUE if ok. FALSE if couldn't open file. - * - * Side Effects: - * lots - */ -static Boolean -ReadMakefile(fname) - char *fname; /* makefile to read */ -{ - extern Lst parseIncPath, sysIncPath; - FILE *stream; - char *name, path[MAXPATHLEN + 1]; - - if (!strcmp(fname, "-")) { - Parse_File("(stdin)", stdin); - Var_Set("MAKEFILE", "", VAR_GLOBAL); - } else { - if ((stream = fopen(fname, "r")) != NULL) - goto found; - /* if we've chdir'd, rebuild the path name */ - if (curdir != objdir && *fname != '/') { - (void)sprintf(path, "%s/%s", curdir, fname); - if ((stream = fopen(path, "r")) != NULL) { - fname = path; - goto found; - } - } - /* look in -I and system include directories. */ - name = Dir_FindFile(fname, parseIncPath); - if (!name) - name = Dir_FindFile(fname, sysIncPath); - if (!name || !(stream = fopen(name, "r"))) - return(FALSE); - 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: Var_Set("MAKEFILE", fname, VAR_GLOBAL); - Parse_File(fname, stream); - (void)fclose(stream); - } - return(TRUE); -} - -/*- - * Error -- - * Print an error message given its format. - * - * Results: - * None. - * - * Side Effects: - * The message is printed. - */ -/* VARARGS */ -void -#if __STDC__ -Error(char *fmt, ...) -#else -Error(va_alist) - va_dcl -#endif -{ - va_list ap; -#if __STDC__ - va_start(ap, fmt); -#else - char *fmt; - - va_start(ap); - fmt = va_arg(ap, char *); -#endif - (void)vfprintf(stderr, fmt, ap); - va_end(ap); - (void)fprintf(stderr, "\n"); - (void)fflush(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 -#if __STDC__ -Fatal(char *fmt, ...) -#else -Fatal(va_alist) - va_dcl -#endif -{ - va_list ap; -#if __STDC__ - va_start(ap, fmt); -#else - char *fmt; - - va_start(ap); - fmt = va_arg(ap, char *); -#endif - if (jobsRunning) - Job_Wait(); - - (void)vfprintf(stderr, fmt, ap); - va_end(ap); - (void)fprintf(stderr, "\n"); - (void)fflush(stderr); - - if (DEBUG(GRAPH2)) - Targ_PrintGraph(2); - 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 -#if __STDC__ -Punt(char *fmt, ...) -#else -Punt(va_alist) - va_dcl -#endif -{ - va_list ap; -#if __STDC__ - va_start(ap, fmt); -#else - char *fmt; - - va_start(ap); - fmt = va_arg(ap, char *); -#endif - - (void)fprintf(stderr, "make: "); - (void)vfprintf(stderr, fmt, ap); - va_end(ap); - (void)fprintf(stderr, "\n"); - (void)fflush(stderr); - - DieHorribly(); -} - -/*- - * DieHorribly -- - * Exit without giving a message. - * - * Results: - * None - * - * Side Effects: - * A big one... - */ -void -DieHorribly() -{ - if (jobsRunning) - Job_AbortAll(); - if (DEBUG(GRAPH2)) - Targ_PrintGraph(2); - 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(errors) - int errors; /* number of errors encountered in Make_Make */ -{ - Fatal("%d error%s", errors, errors == 1 ? "" : "s"); -} - -/* - * emalloc -- - * malloc, but die on error. - */ -char * -emalloc(len) - size_t len; -{ - char *p; - - if ((p = (char *) malloc(len)) == NULL) - enomem(); - return(p); -} - -/* - * enomem -- - * die when out of memory. - */ -void -enomem() -{ - (void)fprintf(stderr, "make: %s.\n", strerror(errno)); - exit(2); -} - -/* - * usage -- - * exit with usage message - */ -static void -usage() -{ - (void)fprintf(stderr, -"usage: make [-eiknqrst] [-D variable] [-d flags] [-f makefile ]\n\ - [-I directory] [-j max_jobs] [variable=value]\n"); - exit(2); -} - - -int -PrintAddr(a, b) - ClientData a; - ClientData b; -{ - printf("%lx ", (unsigned long) a); - return b ? 0 : 0; -} diff --git a/usr.bin/make/make.1 b/usr.bin/make/make.1 deleted file mode 100644 index b1392cc6e944e..0000000000000 --- a/usr.bin/make/make.1 +++ /dev/null @@ -1,890 +0,0 @@ -.\" 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. 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. -.\" -.\" @(#)make.1 8.8 (Berkeley) 6/13/95 -.\" -.Dd June 13, 1995 -.Dt MAKE 1 -.Os -.Sh NAME -.Nm make -.Nd maintain program dependencies -.Sh SYNOPSIS -.Nm make -.Op Fl eiknqrstv -.Op Fl D Ar variable -.Op Fl d Ar flags -.Op Fl f Ar makefile -.Op Fl I Ar directory -.Bk -words -.Op Fl j Ar max_jobs -.Ek -.Op Ar variable=value -.Op Ar target ... -.Sh DESCRIPTION -.Nm Make -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 the file -.Ql Pa makefile -exists, it is read for this list of specifications. -If it does not exist, the file -.Ql Pa Makefile -is read. -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 make -and makefiles, please refer to -.%T "Make \- A Tutorial" . -.Pp -The options are as follows: -.Bl -tag -width Ds -.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 make -are to print debugging information. -.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 conditional evaluation. -.It Ar d -Print debugging information about directory searching and caching. -.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 j -Print debugging information about running multiple shells. -.It Ar m -Print debugging information about making targets, including modification -dates. -.It Ar s -Print debugging information about suffix-transformation rules. -.It Ar t -Print debugging information about target list maintenance. -.It Ar v -Print debugging information about variable assignment. -.El -.It Fl e -Specify that environmental variables override macro assignments within -makefiles. -.It Fl f Ar makefile -Specify a makefile to read instead of the default -.Ql Pa makefile -and -.Ql Pa Makefile . -If -.Ar makefile -is -.Ql Fl , -standard input is read. -Multiple makefile's 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 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 max_jobs -Specify the maximum number of jobs that -.Nm make -may have running at any one time. -.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 n -Display the commands that would have been executed, but do not actually -execute them. -.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 -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 Ar variable=value -Set the value of the variable -.Ar variable -to -.Ar value . -.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 ``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 make -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 make -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 make -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 a series of shell commands, normally -used to create the target. -Each of the commands in this script -.Em must -be preceded by a tab. -While any target may appear on a dependency line, only one of these -dependencies may be followed by a creation script, unless the -.Ql Ic :: -operator is used. -.Pp -If the first or first two characters of the command line are -.Ql Ic @ -and/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 any non-zero exit status of the command line to be ignored. -.Sh VARIABLE ASSIGNMENTS -Variables in make are much like variables in the shell, and, by tradition, -consist of all upper-case letters. -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. -.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 -Variable substitution occurs at two distinct times, depending on where -the variable is being used. -Variables in dependency lines are expanded as the line is read. -Variables in shell commands are expanded when the shell command is -executed. -.Pp -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 make 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. -The seven local variables are as follows: -.Bl -tag -width ".ARCHIVE" -.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. -.It Va .IMPSRC -The name/path of the source from which the target is to be transformed -(the ``implied'' source); also known as -.Ql Va \&< . -.It Va .MEMBER -The name of the archive member. -.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 file, containing only the file portion, no suffix -or preceding directory components; also known as -.Ql Va * . -.It Va .TARGET -The name of the target; also known as -.Ql Va @ . -.El -.Pp -The shorter forms -.Ql Va @ , -.Ql Va ? , -.Ql Va \&> -and -.Ql Va * -are permitted for backward -compatibility with historical makefiles and are not recommended. -The six variables -.Ql Va "@F" , -.Ql Va "@D" , -.Ql Va "<F" , -.Ql Va "<D" , -.Ql Va "*F" -and -.Ql Va "*D" -are -permitted for compatibility with -.At V -makefiles and 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 . -.Pp -In addition, -.Nm make -sets or knows about the following variables: -.Bl -tag -width MAKEFLAGS -.It Va \&$ -A single dollar sign -.Ql \&$ , -i.e. -.Ql \&$$ -expands to a single dollar -sign. -.It Va .MAKE -The name that -.Nm make -was executed with -.Pq Va argv Op 0 -.It Va .CURDIR -A path to the directory where -.Nm make -was executed. -.It Va .OBJDIR -A path to the directory where the targets are built. -.It Ev MAKEFLAGS -The environment variable -.Ql Ev MAKEFLAGS -may contain anything that -may be specified on -.Nm make Ns 's -command line. -Anything specified on -.Nm make Ns 's -command line is appended to the -.Ql Ev MAKEFLAGS -variable which is then -entered into the environment for all programs which -.Nm make -executes. -.El -.Pp -Variable expansion may be modified to select or modify each word of the -variable (where a ``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 and one of the following -special characters. -The colon may be escaped with a backslash -.Pq Ql \e . -.Bl -tag -width Cm E\& -.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 the rest of the modifier. -The standard shell wildcard characters -.Pf ( Ql * , -.Ql ? , -and -.Ql Op ) -may -be used. -The wildcard characters may be escaped with a backslash -.Pq Ql \e . -.It Cm N Ns Ar pattern -This is identical to -.Ql Cm M , -but selects all words which do not match -the rest of the modifier. -.It Cm R -Replaces each word in the variable with everything but its suffix. -.Sm off -.It Cm S No \&/ Ar old_pattern Xo -.No \&/ Ar new_pattern -.No \&/ Op Cm g -.Xc -.Sm on -Modify the first occurrence of -.Ar old_pattern -in each word to be replaced with -.Ar new_pattern . -If a -.Ql g -is appended to the last slash of the pattern, all occurrences -in each word are replaced. -If -.Ar old_pattern -begins with a carat -.Pq Ql ^ , -.Ar old_pattern -is anchored at the beginning of each word. -If -.Ar old_pattern -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_pattern . -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. -.It Cm T -Replaces each word in the variable with its last component. -.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 -.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 make . -All such structures are identified by a line beginning with a single -dot -.Pq Ql \&. -character. -Files are included with either -.Ql .include <file> -or -.Ql .include \*qfile\*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. -.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 .undef Ar variable -Un-define the specified global variable. -Only global variables may be un-defined. -.It Xo -.Ic \&.if -.Oo \&! Oc Ns Ar expression -.Op Ar operator expression ... -.Xc -Test the value of an expression. -.It Xo -.Ic .ifdef -.Oo \&! Oc Ns Ar variable -.Op Ar operator variable ... -.Xc -Test the value of a variable. -.It Xo -.Ic .ifndef -.Oo \&! Oc Ns Ar variable -.Op Ar operator variable ... -.Xc -Test the value of a variable. -.It Xo -.Ic .ifmake -.Oo \&! Oc Ns Ar target -.Op Ar operator target ... -.Xc -Test the target being built. -.It Xo -.Ic .ifnmake -.Oo \&! Oc Ar target -.Op Ar operator target ... -.Xc -Test the target being built. -.It Ic .else -Reverse the sense of the last conditional. -.It Xo -.Ic .elif -.Oo \&! Oc Ar expression -.Op Ar operator expression ... -.Xc -A combination of -.Ql Ic .else -followed by -.Ql Ic .if . -.It Xo -.Ic .elifdef -.Oo \&! Oc Ns Ar variable -.Op Ar operator variable ... -.Xc -A combination of -.Ql Ic .else -followed by -.Ql Ic .ifdef . -.It Xo -.Ic .elifndef -.Oo \&! Oc Ns Ar variable -.Op Ar operator variable ... -.Xc -A combination of -.Ql Ic .else -followed by -.Ql Ic .ifndef . -.It Xo -.Ic .elifmake -.Oo \&! Oc Ns Ar target -.Op Ar operator target ... -.Xc -A combination of -.Ql Ic .else -followed by -.Ql Ic .ifmake . -.It Xo -.Ic .elifnmake -.Oo \&! Oc Ns Ar target -.Op Ar operator target ... -.Xc -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 make -will only evaluate a conditional as far as is necessary to determine -its value. -Parenthesis 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 Ic 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 make 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. -.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. -.Pp -When -.Nm make -is evaluating one of these conditional expression, and it encounters -a word it doesn't recognize, either the ``make'' or ``defined'' -expression is applied to it, depending on the form of the conditional. -If the form is -.Ql Ic .ifdef -or -.Ql Ic .ifndef , -the ``defined'' expression -is applied. -Similarly, if the form is -.Ql Ic .ifmake -or -.Ql Ic .ifnmake , the ``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: -.Bl -tag -width Ds -.It Xo -.Ic \&.for -.Ar variable -.Ic in -.Ar expression -.Xc -.It Xo -<make-rules> -.Xc -.It Xo -.Ic \&.endfor -.Xc -.El -After the for -.Ic expression -is evaluated, it is split into words. The -iteration -.Ic variable -is successively set to each word, and substituted in the -.Ic make-rules -inside the body of the for loop. -.Sh COMMENTS -Comments begin with a hash -.Pq Ql \&# -character, anywhere but in a shell -command line, and continue to the end of the line. -.Sh SPECIAL SOURCES -.Bl -tag -width Ic .IGNORE -.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 .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 make Ns 's . -.It Ic .NOTMAIN -Normally -.Nm make -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 make -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 -If this special target is present in a Makefile, all sources for the -target will considered to be `phony' targets. I.e. they don't refer -to real files, and they will always be considered out-of-date. This -is useful in case one wants to create a target called `install', in -a directory where a file `install' already exists. -.It Ic .PRECIOUS -When -.Nm make -is interrupted, it removes any partially made targets. -This source prevents the target from being removed. -.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 make 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. -.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 Ic .BEGIN -.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 make -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 .END -Any command lines attached to this target are executed after everything -else is done. -.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 make -is interrupted, the commands for this target will be executed. -.It Ic .MAIN -If no target is specified when -.Nm make -is invoked, this target will be built. -.It Ic .MAKEFLAGS -This target provides a way to specify flags for -.Nm make -when the makefile is used. -The flags are as if typed to the shell, though the -.Fl f -option will have -no effect. -.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. -.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 .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 .SUFFIXES -Each source specifies a suffix to -.Nm make . -If no sources are specified, any previous specified suffices are deleted. -.Sh ENVIRONMENT -.Nm Make -utilizes the following environment variables, if they exist: -.Ev MAKE , -.Ev MAKEFLAGS -and -.Ev MAKEOBJDIR . -.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 SEE ALSO -.Xr mkdep 1 -.Sh HISTORY -A -.Nm Make -command appeared in -.At v7 . diff --git a/usr.bin/make/make.c b/usr.bin/make/make.c deleted file mode 100644 index 6d17b2ed87f35..0000000000000 --- a/usr.bin/make/make.c +++ /dev/null @@ -1,908 +0,0 @@ -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * 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 lint -static char sccsid[] = "@(#)make.c 8.3 (Berkeley) 6/13/95"; -#endif /* not lint */ - -/*- - * 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 cmtime 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 cmtime 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. - */ - -#include "make.h" -#include "hash.h" -#include "dir.h" -#include "job.h" - -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 numNodes; /* Number of nodes to be processed. If this - * is non-zero when Job_Empty() returns - * TRUE, there's a cycle in the graph */ - -static int MakeAddChild __P((ClientData, ClientData)); -static int MakeAddAllSrc __P((ClientData, ClientData)); -static int MakeTimeStamp __P((ClientData, ClientData)); -static int MakeHandleUse __P((ClientData, ClientData)); -static Boolean MakeStartJobs __P((void)); -static int MakePrintStatus __P((ClientData, ClientData)); -/*- - *----------------------------------------------------------------------- - * Make_TimeStamp -- - * Set the cmtime field of a parent node based on the mtime stamp in its - * child. Called from MakeOODate via Lst_ForEach. - * - * Results: - * Always returns 0. - * - * Side Effects: - * The cmtime of the parent node will be changed if the mtime - * field of the child is greater than it. - *----------------------------------------------------------------------- - */ -int -Make_TimeStamp (pgn, cgn) - GNode *pgn; /* the current parent */ - GNode *cgn; /* the child we've just examined */ -{ - if (cgn->mtime > pgn->cmtime) { - pgn->cmtime = cgn->mtime; - } - return (0); -} - -static int -MakeTimeStamp (pgn, cgn) - ClientData pgn; /* the current parent */ - ClientData cgn; /* the child we've just examined */ -{ - 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. - * - * Results: - * TRUE if the node is out of date. FALSE otherwise. - * - * Side Effects: - * The mtime field of the node and the cmtime field of its parents - * will/may be changed. - *----------------------------------------------------------------------- - */ -Boolean -Make_OODate (gn) - register GNode *gn; /* the node to check */ -{ - 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_EXEC|OP_PHONY)) == 0) { - (void) Dir_MTime (gn); - if (DEBUG(MAKE)) { - if (gn->mtime != 0) { - printf ("modified %s...", Targ_FmtTime(gn->mtime)); - } else { - printf ("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-Compatability and - * the strange people who wrote 'Make'. - */ - if (gn->type & OP_PHONY) { - /* - * A PHONY node is always out of date - */ - if (DEBUG(MAKE)) - printf("phony..."); - return TRUE; - } else if (gn->type & OP_USE) { - /* - * If the node is a USE node it is *never* out of date - * no matter *what*. - */ - if (DEBUG(MAKE)) { - printf(".USE node..."); - } - oodate = FALSE; - } else if (gn->type & OP_LIB) { - if (DEBUG(MAKE)) { - printf("library..."); - } - - /* - * always out of date if no children and :: target - */ - - oodate = Arch_LibOODate (gn) || - ((gn->cmtime == 0) && (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)) { - printf(".JOIN node..."); - } - oodate = gn->childMade; - } else if (gn->type & (OP_FORCE|OP_EXEC)) { - /* - * 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) { - printf("! operator..."); - } else { - printf(".EXEC node..."); - } - } - oodate = TRUE; - } else if ((gn->mtime < gn->cmtime) || - ((gn->cmtime == 0) && - ((gn->mtime==0) || (gn->type & OP_DOUBLEDEP)))) - { - /* - * A node whose modification time is less than that of its - * youngest child or that has no children (cmtime == 0) and - * either doesn't exist (mtime == 0) 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->mtime < gn->cmtime) { - printf("modified before source..."); - } else if (gn->mtime == 0) { - printf("non-existent and no sources..."); - } else { - printf(":: operator and no sources..."); - } - } - oodate = TRUE; - } else { -#if 0 - /* WHY? */ - if (DEBUG(MAKE)) { - printf("source %smade...", gn->childMade ? "" : "not "); - } - oodate = gn->childMade; -#else - oodate = FALSE; -#endif /* 0 */ - } - - /* - * 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, (ClientData)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. - * - * Results: - * Always returns 0 - * - * Side Effects: - * The given list is extended - *----------------------------------------------------------------------- - */ -static int -MakeAddChild (gnp, lp) - ClientData gnp; /* the node to add */ - ClientData lp; /* the list to which to add it */ -{ - GNode *gn = (GNode *) gnp; - Lst l = (Lst) lp; - if (!gn->make && !(gn->type & OP_USE)) { - (void)Lst_EnQueue (l, (ClientData)gn); - } - return (0); -} - -/*- - *----------------------------------------------------------------------- - * Make_HandleUse -- - * Function called by Make_Run and SuffApplyTransform on the downward - * pass to handle .USE and transformation nodes. A callback function - * for Lst_ForEach, it implements the .USE and transformation - * functionality by copying the node's commands, type flags - * and children to the parent node. Should be called before the - * children are enqueued to be looked at by MakeAddChild. - * - * 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. - * - * Results: - * returns 0. - * - * Side Effects: - * Children and commands may be added to the parent and the parent's - * type may be changed. - * - *----------------------------------------------------------------------- - */ -int -Make_HandleUse (cgn, pgn) - register GNode *cgn; /* The .USE node */ - register GNode *pgn; /* The target of the .USE node */ -{ - register GNode *gn; /* A child of the .USE node */ - register LstNode ln; /* An element in the children list */ - - if (cgn->type & (OP_USE|OP_TRANSFORM)) { - if ((cgn->type & OP_USE) || Lst_IsEmpty(pgn->commands)) { - /* - * .USE or transformation and 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)) != NILLNODE) { - gn = (GNode *)Lst_Datum (ln); - - if (Lst_Member (pgn->children, gn) == NILLNODE) { - (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_TRANSFORM); - - /* - * 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 (cgn->type & OP_USE) { - pgn->unmade -= 1; - } - } - return (0); -} -static int -MakeHandleUse (pgn, cgn) - ClientData pgn; /* the current parent */ - ClientData cgn; /* the child we've just examined */ -{ - return Make_HandleUse((GNode *) pgn, (GNode *) cgn); -} - -/*- - *----------------------------------------------------------------------- - * 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. - * - * 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 childMade field will be set true - * and its cmtime set to now. - * - * If the child wasn't made, the cmtime 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 (cgn) - register GNode *cgn; /* the child node */ -{ - register GNode *pgn; /* the parent node */ - register char *cname; /* the child's name */ - register LstNode ln; /* Element in parents and iParents lists */ - char *p1; - - cname = Var_Value (TARGET, cgn, &p1); - if (p1) - free(p1); - - /* - * 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) { -#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 cgn->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(cgn->commands) || Lst_IsEmpty(cgn->children)) { - cgn->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 || (cgn->type & OP_SAVE_CMDS) || Dir_MTime(cgn) == 0) { - cgn->mtime = now; - } - if (DEBUG(MAKE)) { - printf("update time: %s\n", Targ_FmtTime(cgn->mtime)); - } -#endif - } - - if (Lst_Open (cgn->parents) == SUCCESS) { - while ((ln = Lst_Next (cgn->parents)) != NILLNODE) { - pgn = (GNode *)Lst_Datum (ln); - if (pgn->make) { - pgn->unmade -= 1; - - if ( ! (cgn->type & (OP_EXEC|OP_USE))) { - if (cgn->made == MADE) { - pgn->childMade = TRUE; - if (pgn->cmtime < cgn->mtime) { - pgn->cmtime = cgn->mtime; - } - } else { - (void)Make_TimeStamp (pgn, cgn); - } - } - if (pgn->unmade == 0) { - /* - * Queue the node up -- any unmade predecessors will - * be dealt with in MakeStartJobs. - */ - (void)Lst_EnQueue (toBeMade, (ClientData)pgn); - } else if (pgn->unmade < 0) { - Error ("Graph cycles through %s", pgn->name); - } - } - } - Lst_Close (cgn->parents); - } - /* - * Deal with successor nodes. If any is marked for making and has an unmade - * count of 0, has not been made and isn't in the examination queue, - * it means we need to place it in the queue as it restrained itself - * before. - */ - for (ln = Lst_First(cgn->successors); ln != NILLNODE; ln = Lst_Succ(ln)) { - GNode *succ = (GNode *)Lst_Datum(ln); - - if (succ->make && succ->unmade == 0 && succ->made == UNMADE && - Lst_Member(toBeMade, (ClientData)succ) == NILLNODE) - { - (void)Lst_EnQueue(toBeMade, (ClientData)succ); - } - } - - /* - * Set the .PREFIX and .IMPSRC variables for all the implied parents - * of this node. - */ - if (Lst_Open (cgn->iParents) == SUCCESS) { - char *p1; - char *cpref = Var_Value(PREFIX, cgn, &p1); - - while ((ln = Lst_Next (cgn->iParents)) != NILLNODE) { - pgn = (GNode *)Lst_Datum (ln); - if (pgn->make) { - Var_Set (IMPSRC, cname, pgn); - Var_Set (PREFIX, cpref, pgn); - } - } - if (p1) - 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... - * 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 -MakeAddAllSrc (cgnp, pgnp) - ClientData cgnp; /* The child to add */ - ClientData pgnp; /* The parent to whose ALLSRC variable it should be */ - /* added */ -{ - GNode *cgn = (GNode *) cgnp; - GNode *pgn = (GNode *) pgnp; - if ((cgn->type & (OP_EXEC|OP_USE|OP_INVISIBLE)) == 0) { - char *child; - char *p1; - - child = Var_Value(TARGET, cgn, &p1); - Var_Append (ALLSRC, child, pgn); - 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); - } - if (p1) - 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 (gn) - GNode *gn; -{ - Lst_ForEach (gn->children, MakeAddAllSrc, (ClientData) gn); - - if (!Var_Exists (OODATE, gn)) { - Var_Set (OODATE, "", gn); - } - if (!Var_Exists (ALLSRC, gn)) { - Var_Set (ALLSRC, "", gn); - } - - if (gn->type & OP_JOIN) { - char *p1; - Var_Set (TARGET, Var_Value (ALLSRC, gn, &p1), gn); - if (p1) - free(p1); - } -} - -/*- - *----------------------------------------------------------------------- - * 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 Boolean -MakeStartJobs () -{ - register GNode *gn; - - while (!Job_Full() && !Lst_IsEmpty (toBeMade)) { - gn = (GNode *) Lst_DeQueue (toBeMade); - if (DEBUG(MAKE)) { - printf ("Examining %s...", gn->name); - } - /* - * Make sure any and all predecessors that are going to be made, - * have been. - */ - if (!Lst_IsEmpty(gn->preds)) { - LstNode ln; - - for (ln = Lst_First(gn->preds); ln != NILLNODE; ln = Lst_Succ(ln)){ - GNode *pgn = (GNode *)Lst_Datum(ln); - - if (pgn->make && pgn->made == UNMADE) { - if (DEBUG(MAKE)) { - printf("predecessor %s not made yet.\n", pgn->name); - } - break; - } - } - /* - * If ln isn't nil, there's a predecessor as yet unmade, so we - * just drop this node on the floor. When the node in question - * has been made, it will notice this node as being ready to - * make but as yet unmade and will place the node on the queue. - */ - if (ln != NILLNODE) { - continue; - } - } - - numNodes--; - if (Make_OODate (gn)) { - if (DEBUG(MAKE)) { - printf ("out-of-date\n"); - } - if (queryFlag) { - return (TRUE); - } - Make_DoAllVar (gn); - Job_Make (gn); - } else { - if (DEBUG(MAKE)) { - printf ("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); - } - } - 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. - * - * Results: - * Always returns 0. - * - * Side Effects: - * A message may be printed. - * - *----------------------------------------------------------------------- - */ -static int -MakePrintStatus(gnp, cyclep) - ClientData gnp; /* Node to examine */ - ClientData cyclep; /* True if gn->unmade being non-zero implies - * a cycle in the graph, not an error in an - * inferior */ -{ - GNode *gn = (GNode *) gnp; - Boolean cycle = *(Boolean *) cyclep; - if (gn->made == UPTODATE) { - printf ("`%s' is up to date.\n", gn->name); - } else if (gn->unmade != 0) { - if (cycle) { - Boolean t = TRUE; - /* - * If printing cycles and came to one that has unmade children, - * print out the cycle by recursing on its children. Note a - * cycle like: - * a : b - * b : c - * c : b - * will cause this to erroneously complain about a being in - * the cycle, but this is a good approximation. - */ - if (gn->made == CYCLE) { - Error("Graph cycles through `%s'", gn->name); - gn->made = ENDCYCLE; - Lst_ForEach(gn->children, MakePrintStatus, (ClientData) &t); - gn->made = UNMADE; - } else if (gn->made != ENDCYCLE) { - gn->made = CYCLE; - Lst_ForEach(gn->children, MakePrintStatus, (ClientData) &t); - } - } else { - printf ("`%s' not remade because of errors.\n", gn->name); - } - } - return (0); -} - -/*- - *----------------------------------------------------------------------- - * 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. - * - * 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 (targs) - Lst targs; /* the initial list of targets */ -{ - register GNode *gn; /* a temporary pointer */ - register Lst examine; /* List of targets to examine */ - int errors; /* Number of errors the Job module reports */ - - toBeMade = Lst_Init (FALSE); - - examine = Lst_Duplicate(targs, NOCOPY); - numNodes = 0; - - /* - * 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->make) { - gn->make = TRUE; - numNodes++; - - /* - * Apply any .USE rules before looking for implicit dependencies - * to make sure everything has commands that should... - */ - Lst_ForEach (gn->children, MakeHandleUse, (ClientData)gn); - Suff_FindDeps (gn); - - if (gn->unmade != 0) { - Lst_ForEach (gn->children, MakeAddChild, (ClientData)examine); - } else { - (void)Lst_EnQueue (toBeMade, (ClientData)gn); - } - } - } - - Lst_Destroy (examine, NOFREE); - - 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()); - } else { - /* - * 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 (!Job_Empty ()) { - Job_CatchOutput (); - Job_CatchChildren (!usePipes); - (void)MakeStartJobs(); - } - - errors = Job_End(); - - /* - * Print the final status of each target. E.g. if it wasn't made - * because some inferior reported an error. - */ - errors = ((errors == 0) && (numNodes != 0)); - Lst_ForEach(targs, MakePrintStatus, (ClientData) &errors); - - return (TRUE); -} diff --git a/usr.bin/make/make.h b/usr.bin/make/make.h deleted file mode 100644 index 3af67f7e4157a..0000000000000 --- a/usr.bin/make/make.h +++ /dev/null @@ -1,366 +0,0 @@ -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * 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. - * - * @(#)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 <stdio.h> -#include <string.h> -#include <ctype.h> -#ifndef MAKE_BOOTSTRAP -#include <sys/cdefs.h> -#else -#if defined(__STDC__) || defined(__cplusplus) -#define __P(protos) protos /* full-blown ANSI C */ -#else -#define __P(protos) () /* traditional C preprocessor */ -#endif -#endif -#if __STDC__ -#include <stdlib.h> -#include <unistd.h> -#endif -#include "sprite.h" -#include "lst.h" -#include "config.h" -#include "buf.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 - * 11) a list of nodes on which this depends - * 12) a list of nodes that depend on this, as gleaned from the - * transformation rules. - * 13) a list of nodes of the same name created by the :: operator - * 14) a list of nodes that must be made (if they're made) before - * this node can be, but that do no enter into the datedness of - * this node. - * 15) 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. - * 16) a Lst of ``local'' variables that are specific to this target - * and this target only (qv. var.c [$@ $< $?, etc.]) - * 17) 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 *path; /* The full pathname of the file */ - int type; /* Its type (see the OP flags, below) */ - - Boolean make; /* TRUE if this target needs to be remade */ - enum { - UNMADE, BEINGMADE, MADE, UPTODATE, ERROR, ABORTED, - CYCLE, ENDCYCLE, - } made; /* Set to reflect the state of processing - * on this node: - * UNMADE - Not examined yet - * BEINGMADE - Target is already being made. - * Indicates a cycle in the graph. (compat - * mode only) - * MADE - Was out-of-date and has been made - * UPTODATE - Was already up-to-date - * ERROR - An error occured while it was being - * made (used only in compat mode) - * ABORTED - The target was aborted due to - * an error making an inferior (compat). - * CYCLE - Marked as potentially being part of - * a graph cycle. If we come back to a - * node marked this way, it is printed - * and 'made' is changed to ENDCYCLE. - * ENDCYCLE - the cycle has been completely - * printed. Go back and unmark all its - * members. - */ - Boolean childMade; /* TRUE if one of this target's children was - * made */ - int unmade; /* The number of unmade children */ - - int mtime; /* Its modification time */ - int cmtime; /* The modification time of its 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 successors; /* Nodes that must be made after this one */ - Lst preds; /* Nodes that must be made before this one */ - - Lst 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) */ -} GNode; - -/* - * Manifest constants - */ -#define NILGNODE ((GNode *) NIL) - -/* - * 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 recurrsive 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_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 */ -/* 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 */ - -/* - * 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) - -/* - * 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 NIL pointer will be returned. - */ -#define TARG_CREATE 0x01 /* create node if not found */ -#define TARG_NOCREATE 0x00 /* don't create it */ - -/* - * There are several places where expandable buffers are used (parse.c and - * var.c). This constant is merely the starting point for those buffers. If - * lines tend to be much shorter than this, it would be best to reduce BSIZE. - * If longer, it should be increased. Reducing it will cause more copying to - * be done for longer lines, but will save space for shorter ones. In any - * case, it ought to be a power of two simply because most storage allocation - * schemes allocate in powers of two. - */ -#define MAKE_BSIZE 256 /* starting size for expandable buffers */ - -/* - * 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_DOFREE 0x02 /* free source strings after concatenation */ -#define STR_ADDSLASH 0x04 /* 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_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 allPrecious; /* True if every target is precious */ -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 usePipes; /* TRUE if should capture the output of - * subshells by means of pipes. Otherwise it - * is routed to temporary files from which it - * is retrieved when the shell exits */ -extern Boolean queryFlag; /* TRUE if we aren't supposed to really make - * anything, just see if the targets are out- - * of-date */ - -extern Boolean checkEnvFirst; /* TRUE if environment should be searched for - * variables before the global context */ - -extern GNode *DEFAULT; /* .DEFAULT rule */ - -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 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 */ - -/* - * debug control: - * There is one bit per module. It is up to the module what debug - * information to print. - */ -extern int debug; -#define DEBUG_ARCH 0x0001 -#define DEBUG_COND 0x0002 -#define DEBUG_DIR 0x0004 -#define DEBUG_GRAPH1 0x0008 -#define DEBUG_GRAPH2 0x0010 -#define DEBUG_JOB 0x0020 -#define DEBUG_MAKE 0x0040 -#define DEBUG_SUFF 0x0080 -#define DEBUG_TARG 0x0100 -#define DEBUG_VAR 0x0200 -#define DEBUG_FOR 0x0400 - -#ifdef __STDC__ -#define CONCAT(a,b) a##b -#else -#define I(a) a -#define CONCAT(a,b) I(a)b -#endif /* __STDC__ */ - -#define DEBUG(module) (debug & CONCAT(DEBUG_,module)) - -/* - * Since there are so many, all functions that return non-integer values are - * extracted by means of a sed script or two and stuck in the file "nonints.h" - */ -#include "nonints.h" - -int Make_TimeStamp __P((GNode *, GNode *)); -Boolean Make_OODate __P((GNode *)); -int Make_HandleUse __P((GNode *, GNode *)); -void Make_Update __P((GNode *)); -void Make_DoAllVar __P((GNode *)); -Boolean Make_Run __P((Lst)); - -#endif /* _MAKE_H_ */ diff --git a/usr.bin/make/nonints.h b/usr.bin/make/nonints.h deleted file mode 100644 index 039d4b967ed2d..0000000000000 --- a/usr.bin/make/nonints.h +++ /dev/null @@ -1,140 +0,0 @@ -/*- - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * 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. - * - * @(#)nonints.h 8.4 (Berkeley) 4/28/95 - */ - -/* arch.c */ -ReturnStatus Arch_ParseArchive __P((char **, Lst, GNode *)); -void Arch_Touch __P((GNode *)); -void Arch_TouchLib __P((GNode *)); -int Arch_MTime __P((GNode *)); -int Arch_MemMTime __P((GNode *)); -void Arch_FindLib __P((GNode *, Lst)); -Boolean Arch_LibOODate __P((GNode *)); -void Arch_Init __P((void)); -void Arch_End __P((void)); - -/* compat.c */ -void Compat_Run __P((Lst)); - -/* cond.c */ -int Cond_Eval __P((char *)); -void Cond_End __P((void)); - -/* for.c */ -int For_Eval __P((char *)); -void For_Run __P((void)); - -/* main.c */ -void Main_ParseArgLine __P((char *)); -int main __P((int, char **)); -void Error __P((char *, ...)); -void Fatal __P((char *, ...)); -void Punt __P((char *, ...)); -void DieHorribly __P((void)); -int PrintAddr __P((ClientData, ClientData)); -void Finish __P((int)); -char *emalloc __P((size_t)); -void enomem __P((void)); - -/* parse.c */ -void Parse_Error __P((int, char *, ...)); -Boolean Parse_AnyExport __P((void)); -Boolean Parse_IsVar __P((char *)); -void Parse_DoVar __P((char *, GNode *)); -void Parse_AddIncludeDir __P((char *)); -void Parse_File __P((char *, FILE *)); -void Parse_Init __P((void)); -void Parse_End __P((void)); -void Parse_FromString __P((char *)); -Lst Parse_MainName __P((void)); - -/* str.c */ -void str_init __P((void)); -void str_end __P((void)); -char *str_concat __P((char *, char *, int)); -char **brk_string __P((char *, int *, Boolean)); -char *Str_FindSubstring __P((char *, char *)); -int Str_Match __P((char *, char *)); -char *Str_SYSVMatch __P((char *, char *, int *len)); -void Str_SYSVSubst __P((Buffer, char *, char *, int)); - -/* suff.c */ -void Suff_ClearSuffixes __P((void)); -Boolean Suff_IsTransform __P((char *)); -GNode *Suff_AddTransform __P((char *)); -int Suff_EndTransform __P((ClientData, ClientData)); -void Suff_AddSuffix __P((char *)); -Lst Suff_GetPath __P((char *)); -void Suff_DoPaths __P((void)); -void Suff_AddInclude __P((char *)); -void Suff_AddLib __P((char *)); -void Suff_FindDeps __P((GNode *)); -void Suff_SetNull __P((char *)); -void Suff_Init __P((void)); -void Suff_End __P((void)); -void Suff_PrintAll __P((void)); - -/* targ.c */ -void Targ_Init __P((void)); -void Targ_End __P((void)); -GNode *Targ_NewGN __P((char *)); -GNode *Targ_FindNode __P((char *, int)); -Lst Targ_FindList __P((Lst, int)); -Boolean Targ_Ignore __P((GNode *)); -Boolean Targ_Silent __P((GNode *)); -Boolean Targ_Precious __P((GNode *)); -void Targ_SetMain __P((GNode *)); -int Targ_PrintCmd __P((ClientData, ClientData)); -char *Targ_FmtTime __P((time_t)); -void Targ_PrintType __P((int)); -void Targ_PrintGraph __P((int)); - -/* var.c */ -void Var_Delete __P((char *, GNode *)); -void Var_Set __P((char *, char *, GNode *)); -void Var_Append __P((char *, char *, GNode *)); -Boolean Var_Exists __P((char *, GNode *)); -char *Var_Value __P((char *, GNode *, char **)); -char *Var_Parse __P((char *, GNode *, Boolean, int *, Boolean *)); -char *Var_Subst __P((char *, char *, GNode *, Boolean)); -char *Var_GetTail __P((char *)); -char *Var_GetHead __P((char *)); -void Var_Init __P((void)); -void Var_End __P((void)); -void Var_Dump __P((GNode *)); diff --git a/usr.bin/make/parse.c b/usr.bin/make/parse.c deleted file mode 100644 index e4d8446279bdc..0000000000000 --- a/usr.bin/make/parse.c +++ /dev/null @@ -1,2661 +0,0 @@ -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * 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 lint -static char sccsid[] = "@(#)parse.c 8.6 (Berkeley) 6/13/95"; -#endif /* not lint */ - -/*- - * 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. - */ - -#if __STDC__ -#include <stdarg.h> -#else -#include <varargs.h> -#endif -#include <stdio.h> -#include <ctype.h> -#include <errno.h> -#include <sys/wait.h> -#include "make.h" -#include "hash.h" -#include "dir.h" -#include "job.h" -#include "buf.h" -#include "pathnames.h" - -/* - * 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 -static Lst targets; /* targets we're working on */ -static Lst targCmds; /* command lines for targets */ -static Boolean inLine; /* true if currently in a dependency - * line or its commands */ -typedef struct { - char *str; - char *ptr; -} PTR; - -static char *fname; /* name of current file (for errors) */ -static int lineno; /* line number in current file */ -static FILE *curFILE = NULL; /* current makefile */ - -static PTR *curPTR = NULL; /* current makefile */ - -static int fatals = 0; - -static GNode *mainNode; /* The main target to create. This is the - * first target on the first dependency - * line in the first makefile */ -/* - * Definitions for handling #include specifications - */ -typedef struct IFile { - char *fname; /* name of previous file */ - int lineno; /* saved line number */ - FILE * F; /* the open stream */ - PTR * p; /* the char pointer */ -} IFile; - -static Lst includes; /* stack of IFiles generated by - * #includes */ -Lst parseIncPath; /* list of directories for "..." includes */ -Lst sysIncPath; /* list of directories for <...> includes */ - -/*- - * 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 - */ -typedef enum { - Begin, /* .BEGIN */ - Default, /* .DEFAULT */ - End, /* .END */ - Ignore, /* .IGNORE */ - Includes, /* .INCLUDES */ - Interrupt, /* .INTERRUPT */ - Libs, /* .LIBS */ - MFlags, /* .MFLAGS or .MAKEFLAGS */ - Main, /* .MAIN and we don't have anything user-specified to - * make */ - NoExport, /* .NOEXPORT */ - Not, /* Not special */ - NotParallel, /* .NOTPARALELL */ - Null, /* .NULL */ - Order, /* .ORDER */ - ExPath, /* .PATH */ - Precious, /* .PRECIOUS */ - Reserved, /* .RESERVED or .[A-Z]* */ - ExShell, /* .SHELL */ - Silent, /* .SILENT */ - SingleShell, /* .SINGLESHELL */ - Suffixes, /* .SUFFIXES */ - Attribute /* Generic attribute */ -} ParseSpecial; - -static ParseSpecial specType; - -/* - * Predecessor node for handling .ORDER. Initialized to NILGNODE when .ORDER - * seen, then set to each successive source on the line. - */ -static GNode *predecessor; - -/* - * 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 struct { - char *name; /* Name of keyword */ - ParseSpecial spec; /* Type when used as a target */ - int op; /* Operator when used as a source */ -} parseKeywords[] = { -#define DOT_BEGIN 0 -{ ".BEGIN", Begin, 0 }, -#define DOT_DEFAULT 1 -{ ".DEFAULT", Default, 0 }, -#define DOT_END 2 -{ ".END", End, 0 }, -#define DOT_EXEC 3 -{ ".EXEC", Attribute, OP_EXEC }, -#define DOT_IGNORE 4 -{ ".IGNORE", Ignore, OP_IGNORE }, -#define DOT_INCLUDES 5 -{ ".INCLUDES", Includes, 0 }, -#define DOT_INTERRUPT 6 -{ ".INTERRUPT", Interrupt, 0 }, -#define DOT_INVISIBLE 7 -{ ".INVISIBLE", Attribute, OP_INVISIBLE }, -#define DOT_JOIN 8 -{ ".JOIN", Attribute, OP_JOIN }, -#define DOT_LIBS 9 -{ ".LIBS", Libs, 0 }, -#define DOT_MAIN 10 -{ ".MAIN", Main, 0 }, -#define DOT_MAKE 11 -{ ".MAKE", Attribute, OP_MAKE }, -#define DOT_MAKEFLAGS 12 -{ ".MAKEFLAGS", MFlags, 0 }, -#define DOT_MFLAGS 13 -{ ".MFLAGS", MFlags, 0 }, -#define DOT_NOTMAIN 14 -{ ".NOTMAIN", Attribute, OP_NOTMAIN }, -#define DOT_NOTPARALLEL 15 -{ ".NOTPARALLEL", NotParallel, 0 }, -#define DOT_NULL 16 -{ ".NULL", Null, 0 }, -#define DOT_OPTIONAL 17 -{ ".OPTIONAL", Attribute, OP_OPTIONAL }, -#define DOT_ORDER 18 -{ ".ORDER", Order, 0 }, -#define DOT_PATH 19 -{ ".PATH", ExPath, 0 }, -#define DOT_PHONY 20 -{ ".PHONY", Attribute, OP_PHONY }, -#define DOT_PRECIOUS 21 -{ ".PRECIOUS", Precious, OP_PRECIOUS }, -#define DOT_RECURSIVE 22 -{ ".RECURSIVE", Attribute, OP_MAKE }, -#define DOT_RESERVED 23 -{ ".RESERVED", Reserved, 0 }, -#define DOT_SHELL 24 -{ ".SHELL", ExShell, 0 }, -#define DOT_SILENT 25 -{ ".SILENT", Silent, OP_SILENT }, -#define DOT_SINGLESHELL 26 -{ ".SINGLESHELL", SingleShell, 0 }, -#define DOT_SUFFIXES 27 -{ ".SUFFIXES", Suffixes, 0 }, -#define DOT_USE 28 -{ ".USE", Attribute, OP_USE }, -}; - -static int ParseFindKeyword __P((char *)); -static int ParseLinkSrc __P((ClientData, ClientData)); -static int ParseDoOp __P((ClientData, ClientData)); -static void ParseDoSrc __P((int, char *)); -static int ParseFindMain __P((ClientData, ClientData)); -static int ParseAddDir __P((ClientData, ClientData)); -static int ParseClearPath __P((ClientData, ClientData)); -static void ParseDoDependency __P((char *)); -static int ParseAddCmd __P((ClientData, ClientData)); -static int ParseReadc __P((void)); -static void ParseUnreadc __P((int)); -static void ParseHasCommands __P((ClientData)); -static void ParseDoInclude __P((char *)); -#ifdef SYSVINCLUDE -static void ParseTraditionalInclude __P((char *)); -#endif -static int ParseEOF __P((int)); -static char *ParseReadLine __P((void)); -static char *ParseSkipLine __P((int)); -static void ParseFinishLine __P((void)); - -/*- - *---------------------------------------------------------------------- - * ParseFindKeyword -- - * Look in the table of keywords for one matching the given string. - * - * Results: - * The index of the keyword, or -1 if it isn't there. - * - * Side Effects: - * None - *---------------------------------------------------------------------- - */ -static int -ParseFindKeyword (str) - char *str; /* String to find */ -{ - register int start, - end, - cur; - register 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); - - cur = 0; - for (++str; *str; str++) - if (!isupper((unsigned char) *str)) - break; - return *str ? -1 : DOT_RESERVED; -} - -/*- - * Parse_Error -- - * 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 */ -void -#if __STDC__ -Parse_Error(int type, char *fmt, ...) -#else -Parse_Error(va_alist) - va_dcl -#endif -{ - va_list ap; -#if __STDC__ - va_start(ap, fmt); -#else - int type; /* Error type (PARSE_WARNING, PARSE_FATAL) */ - char *fmt; - - va_start(ap); - type = va_arg(ap, int); - fmt = va_arg(ap, char *); -#endif - - (void)fprintf(stderr, "\"%s\", line %d: ", fname, lineno); - if (type == PARSE_WARNING) - (void)fprintf(stderr, "warning: "); - (void)vfprintf(stderr, fmt, ap); - va_end(ap); - (void)fprintf(stderr, "\n"); - (void)fflush(stderr); - if (type == PARSE_FATAL) - fatals += 1; -} - -/*- - *--------------------------------------------------------------------- - * 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. - * - * 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 (pgnp, cgnp) - ClientData pgnp; /* The parent node */ - ClientData cgnp; /* The child node */ -{ - GNode *pgn = (GNode *) pgnp; - GNode *cgn = (GNode *) cgnp; - if (Lst_Member (pgn->children, (ClientData)cgn) == NILLNODE) { - (void)Lst_AtEnd (pgn->children, (ClientData)cgn); - if (specType == Not) { - (void)Lst_AtEnd (cgn->parents, (ClientData)pgn); - } - pgn->unmade += 1; - } - 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. - * - * Results: - * Always 0 - * - * Side Effects: - * The type field of the node is altered to reflect any new bits in - * the op. - *--------------------------------------------------------------------- - */ -static int -ParseDoOp (gnp, opp) - ClientData gnp; /* The node to which the operator is to be - * applied */ - ClientData opp; /* The operator to apply */ -{ - 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. - */ - register GNode *cohort; - LstNode ln; - - cohort = Targ_NewGN(gn->name); - /* - * Duplicate links to parents so graph traversal is simple. Perhaps - * some type bits should be duplicated? - * - * 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. - */ - Lst_ForEach(gn->parents, ParseLinkSrc, (ClientData)cohort); - cohort->type = OP_DOUBLEDEP|OP_INVISIBLE; - (void)Lst_AtEnd(gn->cohorts, (ClientData)cohort); - - /* - * Replace the node in the targets list with the new copy - */ - ln = Lst_Member(targets, (ClientData)gn); - Lst_Replace(ln, (ClientData)cohort); - gn = cohort; - } - /* - * 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' - * - * 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 (tOp, src) - int tOp; /* operator (if any) from special targets */ - char *src; /* name of the source to handle */ -{ - int op; /* operator (if any) from special source */ - GNode *gn; - - op = 0; - if (*src == '.' && isupper (src[1])) { - int keywd = ParseFindKeyword(src); - if (keywd != -1) { - op = parseKeywords[keywd].op; - } - } - if (op != 0) { - Lst_ForEach (targets, ParseDoOp, (ClientData)&op); - } else if (specType == 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, (ClientData)strdup(src)); - /* - * Add the name to the .TARGETS variable as well, so the user cna - * employ that, if desired. - */ - Var_Append(".TARGETS", src, VAR_GLOBAL); - } else if (specType == Order) { - /* - * Create proper predecessor/successor links between the previous - * source and the current one. - */ - gn = Targ_FindNode(src, TARG_CREATE); - if (predecessor != NILGNODE) { - (void)Lst_AtEnd(predecessor->successors, (ClientData)gn); - (void)Lst_AtEnd(gn->preds, (ClientData)predecessor); - } - /* - * The current source now becomes the predecessor for the next one. - */ - predecessor = gn; - } else { - /* - * 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. - */ - gn = Targ_FindNode (src, TARG_CREATE); - if (tOp) { - gn->type |= tOp; - } else { - Lst_ForEach (targets, ParseLinkSrc, (ClientData)gn); - } - if ((gn->type & OP_OPMASK) == OP_DOUBLEDEP) { - register GNode *cohort; - register LstNode ln; - - for (ln=Lst_First(gn->cohorts); ln != NILLNODE; ln = Lst_Succ(ln)){ - cohort = (GNode *)Lst_Datum(ln); - if (tOp) { - cohort->type |= tOp; - } else { - Lst_ForEach(targets, ParseLinkSrc, (ClientData)cohort); - } - } - } - } -} - -/*- - *----------------------------------------------------------------------- - * 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. - * - * Results: - * 0 if main not found yet, 1 if it is. - * - * Side Effects: - * mainNode is changed and Targ_SetMain is called. - * - *----------------------------------------------------------------------- - */ -static int -ParseFindMain(gnp, dummy) - ClientData gnp; /* Node to examine */ - ClientData dummy; -{ - GNode *gn = (GNode *) gnp; - if ((gn->type & (OP_NOTMAIN|OP_USE|OP_EXEC|OP_TRANSFORM)) == 0) { - mainNode = gn; - Targ_SetMain(gn); - return (dummy ? 1 : 1); - } else { - return (dummy ? 0 : 0); - } -} - -/*- - *----------------------------------------------------------------------- - * ParseAddDir -- - * Front-end for Dir_AddDir to make sure Lst_ForEach keeps going - * - * Results: - * === 0 - * - * Side Effects: - * See Dir_AddDir. - * - *----------------------------------------------------------------------- - */ -static int -ParseAddDir(path, name) - ClientData path; - ClientData name; -{ - 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(path, dummy) - ClientData path; - ClientData dummy; -{ - Dir_ClearPath((Lst) path); - return(dummy ? 0 : 0); -} - -/*- - *--------------------------------------------------------------------- - * ParseDoDependency -- - * Parse the dependency line in line. - * - * 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 (line) - char *line; /* the line to parse */ -{ - char *cp; /* our current position */ - GNode *gn; /* 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 source names after expansion */ - Lst curTargs; /* list of target names to be found and added - * to the targets list */ - - tOp = 0; - - specType = Not; - paths = (Lst)NULL; - - curTargs = Lst_Init(FALSE); - - do { - for (cp = line; - *cp && !isspace (*cp) && - (*cp != '!') && (*cp != ':') && (*cp != '('); - 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; - Boolean freeIt; - char *result; - - result=Var_Parse(cp, VAR_CMD, TRUE, &length, &freeIt); - - if (freeIt) { - free(result); - } - cp += length-1; - } - continue; - } - if (*cp == '(') { - /* - * 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); - return; - } else { - continue; - } - } - savec = *cp; - - if (!*cp) { - /* - * Ending a dependency line without an operator is a Bozo - * no-no - */ - Parse_Error (PARSE_FATAL, "Need an operator"); - return; - } - *cp = '\0'; - /* - * Have a word in line. See if it's a special target and set - * specType to match it. - */ - if (*line == '.' && isupper (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"); - return; - } - - 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. - * .BEGIN - * .END - * .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 NIL - */ - switch (specType) { - case ExPath: - if (paths == NULL) { - paths = Lst_Init(FALSE); - } - (void)Lst_AtEnd(paths, (ClientData)dirSearchPath); - break; - case Main: - if (!Lst_IsEmpty(create)) { - specType = Not; - } - break; - case Begin: - case End: - case Interrupt: - gn = Targ_FindNode(line, TARG_CREATE); - gn->type |= OP_NOTMAIN; - (void)Lst_AtEnd(targets, (ClientData)gn); - break; - case Default: - gn = Targ_NewGN(".DEFAULT"); - gn->type |= (OP_NOTMAIN|OP_TRANSFORM); - (void)Lst_AtEnd(targets, (ClientData)gn); - DEFAULT = gn; - break; - case NotParallel: - { - extern int maxJobs; - - maxJobs = 1; - break; - } - case SingleShell: - compatMake = 1; - break; - case Order: - predecessor = NILGNODE; - break; - case Reserved: - /* - * A posix reserved target that we don't know - * how to deal with. - */ - return; - 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 == NILLST) { - Parse_Error (PARSE_FATAL, - "Suffix '%s' not defined (yet)", - &line[5]); - return; - } else { - if (paths == (Lst)NULL) { - paths = Lst_Init(FALSE); - } - (void)Lst_AtEnd(paths, (ClientData)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, (ClientData)line); - } - - 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); - } - - (void)Lst_AtEnd (targets, (ClientData)gn); - } - } else if (specType == ExPath && *line != '.' && *line != '\0') { - Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", line); - } - - *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 warn = FALSE; - - while ((*cp != '!') && (*cp != ':') && *cp) { - if (*cp != ' ' && *cp != '\t') { - warn = TRUE; - } - cp++; - } - if (warn) { - Parse_Error(PARSE_WARNING, "Extra target ignored"); - } - } else { - while (*cp && isspace (*cp)) { - cp++; - } - } - line = cp; - } while ((*line != '!') && (*line != ':') && *line); - - /* - * Don't need the list of target names anymore... - */ - Lst_Destroy(curTargs, NOFREE); - - 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 Begin: - case End: - 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, "Missing dependency operator"); - return; - } - - cp++; /* Advance beyond operator */ - - Lst_ForEach (targets, ParseDoOp, (ClientData)&op); - - /* - * Get to the first source - */ - while (*cp && isspace (*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, (ClientData)NULL); - break; - 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"); - return; - } - *line = '\0'; - } else if ((specType == NotParallel) || (specType == SingleShell)) { - *line = '\0'; - } - - /* - * NOW GO FOR THE SOURCES - */ - if ((specType == Suffixes) || (specType == ExPath) || - (specType == Includes) || (specType == Libs) || - (specType == Null)) - { - 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. - */ - char savec; - while (*cp && !isspace (*cp)) { - cp++; - } - savec = *cp; - *cp = '\0'; - switch (specType) { - case Suffixes: - Suff_AddSuffix (line); - break; - case ExPath: - Lst_ForEach(paths, ParseAddDir, (ClientData)line); - break; - case Includes: - Suff_AddInclude (line); - break; - case Libs: - Suff_AddLib (line); - break; - case Null: - Suff_SetNull (line); - break; - default: - break; - } - *cp = savec; - if (savec != '\0') { - cp++; - } - while (*cp && isspace (*cp)) { - cp++; - } - line = cp; - } - if (paths) { - Lst_Destroy(paths, NOFREE); - } - } else { - 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. - */ - while (*cp && !isspace (*cp)) { - if ((*cp == '(') && (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; - } else { - cp++; - } - } - - if (*cp == '(') { - GNode *gn; - - sources = Lst_Init (FALSE); - if (Arch_ParseArchive (&line, sources, VAR_CMD) != SUCCESS) { - Parse_Error (PARSE_FATAL, - "Error in source archive spec \"%s\"", line); - return; - } - - while (!Lst_IsEmpty (sources)) { - gn = (GNode *) Lst_DeQueue (sources); - ParseDoSrc (tOp, gn->name); - } - Lst_Destroy (sources, NOFREE); - cp = line; - } else { - if (*cp) { - *cp = '\0'; - cp += 1; - } - - ParseDoSrc (tOp, line); - } - while (*cp && isspace (*cp)) { - cp++; - } - line = cp; - } - } - - if (mainNode == NILGNODE) { - /* - * 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, (ClientData)0); - } - -} - -/*- - *--------------------------------------------------------------------- - * 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. - * - * Results: - * TRUE if it is. FALSE if it ain't - * - * Side Effects: - * none - *--------------------------------------------------------------------- - */ -Boolean -Parse_IsVar (line) - register char *line; /* the line to check */ -{ - register Boolean wasSpace = FALSE; /* set TRUE if found a space */ - register Boolean haveName = FALSE; /* Set TRUE if have a variable name */ - - /* - * Skip to variable name - */ - while ((*line == ' ') || (*line == '\t')) { - line++; - } - - while (*line != '=') { - if (*line == '\0') { - /* - * end-of-line -- can't be a variable assignment. - */ - return (FALSE); - } else if ((*line == ' ') || (*line == '\t')) { - /* - * there can be as much white space as desired so long as there is - * only one word before the operator - */ - wasSpace = TRUE; - } else if (wasSpace && haveName) { - /* - * Stop when an = operator is found. - */ - if ((*line == '+') || (*line == ':') || (*line == '?') || - (*line == '!')) { - break; - } - - /* - * This is the start of another word, so not assignment. - */ - return (FALSE); - } else { - haveName = TRUE; - wasSpace = FALSE; - } - line++; - } - - /* - * A final check: if we stopped on a +, ?, ! or :, the next character must - * be an = or it ain't a valid assignment - */ - if (((*line == '+') || - (*line == '?') || - (*line == ':') || - (*line == '!')) && - (line[1] != '=')) - { - return (FALSE); - } else { - return (haveName); - } -} - -/*- - *--------------------------------------------------------------------- - * 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++ =". - * - * Results: - * none - * - * Side Effects: - * the variable structure of the given variable name is altered in the - * global context. - *--------------------------------------------------------------------- - */ -void -Parse_DoVar (line, ctxt) - char *line; /* a line guaranteed to be a variable - * assignment. This reduces error checks */ - GNode *ctxt; /* Context in which to do the assignment */ -{ - 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 */ - /* - * Avoid clobbered variable warnings by forcing the compiler - * to ``unregister'' variables - */ -#if __GNUC__ - (void) &cp; - (void) &line; -#endif - - /* - * Skip to variable name - */ - while ((*line == ' ') || (*line == '\t')) { - line++; - } - - /* - * Skip to operator character, nulling out whitespace as we go - */ - for (cp = line + 1; *cp != '='; cp++) { - if (isspace (*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: - type = VAR_NORMAL; - break; - } - - while (isspace (*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; - cp = Var_Subst(NULL, cp, ctxt, FALSE); - oldVars = oldOldVars; - - Var_Set(line, cp, ctxt); - free(cp); - } else if (type == VAR_SHELL) { - char *args[4]; /* Args for invoking the shell */ - int fds[2]; /* Pipe streams */ - int cpid; /* Child PID */ - int pid; /* PID from wait() */ - Boolean freeCmd; /* TRUE if the command needs to be freed, i.e. - * if any variable expansion was performed */ - - /* - * Avoid clobbered variable warnings by forcing the compiler - * to ``unregister'' variables - */ -#if __GNUC__ - (void) &freeCmd; -#endif - - /* - * Set up arguments for shell - */ - args[0] = "sh"; - args[1] = "-c"; - if (strchr(cp, '$') != (char *)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. - */ - args[2] = Var_Subst(NULL, cp, VAR_CMD, TRUE); - freeCmd = TRUE; - } else { - args[2] = cp; - freeCmd = FALSE; - } - args[3] = (char *)NULL; - - /* - * Open a pipe for fetching its output - */ - pipe(fds); - - /* - * Fork - */ - cpid = vfork(); - if (cpid == 0) { - /* - * Close input side of pipe - */ - 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? - */ - dup2(fds[1], 1); - close(fds[1]); - - execv("/bin/sh", args); - _exit(1); - } else if (cpid < 0) { - /* - * Couldn't fork -- tell the user and make the variable null - */ - Parse_Error(PARSE_WARNING, "Couldn't exec \"%s\"", cp); - Var_Set(line, "", ctxt); - } else { - int status; - int cc; - Buffer buf; - char *res; - - /* - * No need for the writing half - */ - close(fds[1]); - - buf = Buf_Init (MAKE_BSIZE); - - do { - char result[BUFSIZ]; - cc = read(fds[0], result, sizeof(result)); - if (cc > 0) - Buf_AddBytes(buf, cc, (Byte *) result); - } - while (cc > 0 || (cc == -1 && errno == EINTR)); - - /* - * Close the input side of the pipe. - */ - close(fds[0]); - - /* - * Wait for the process to exit. - */ - while(((pid = wait(&status)) != cpid) && (pid >= 0)) - continue; - - res = (char *)Buf_GetAll (buf, &cc); - Buf_Destroy (buf, FALSE); - - if (cc == 0) { - /* - * Couldn't read the child's output -- tell the user and - * set the variable to null - */ - Parse_Error(PARSE_WARNING, "Couldn't read shell's output"); - } - - if (status) { - /* - * Child returned an error -- tell the user but still use - * the result. - */ - Parse_Error(PARSE_WARNING, "\"%s\" returned non-zero", cp); - } - - /* - * Null-terminate the result, convert newlines to spaces and - * install it in the variable. - */ - res[cc] = '\0'; - cp = &res[cc] - 1; - - if (*cp == '\n') { - /* - * A final newline is just stripped - */ - *cp-- = '\0'; - } - while (cp >= res) { - if (*cp == '\n') { - *cp = ' '; - } - cp--; - } - Var_Set(line, res, ctxt); - free(res); - - } - if (freeCmd) { - free(args[2]); - } - } else { - /* - * Normal assignment -- just do it. - */ - Var_Set (line, cp, ctxt); - } -} - -/*- - * ParseAddCmd -- - * Lst_ForEach function to add a command line to all targets - * - * Results: - * Always 0 - * - * Side Effects: - * A new element is added to the commands list of the node. - */ -static int -ParseAddCmd(gnp, cmd) - ClientData gnp; /* the node to which the command is to be added */ - ClientData cmd; /* the command to add */ -{ - GNode *gn = (GNode *) gnp; - /* if target already supplied, ignore commands */ - if (!(gn->type & OP_HAS_COMMANDS)) - (void)Lst_AtEnd(gn->commands, cmd); - 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. - * - * Results: - * None - * - * Side Effects: - * OP_HAS_COMMANDS may be set for the target. - * - *----------------------------------------------------------------------- - */ -static void -ParseHasCommands(gnp) - ClientData gnp; /* Node to examine */ -{ - 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 - * - * Results: - * None. - * - * Side Effects: - * The directory is appended to the list. - * - *----------------------------------------------------------------------- - */ -void -Parse_AddIncludeDir (dir) - char *dir; /* The name of the directory to add */ -{ - Dir_AddDir (parseIncPath, dir); -} - -/*- - *--------------------------------------------------------------------- - * ParseDoInclude -- - * Push to another file. - * - * The input is the line minus the #include. 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 -ParseDoInclude (file) - char *file; /* file specification */ -{ - char *fullname; /* full pathname of file */ - IFile *oldFile; /* state associated with current file */ - char endc; /* the character which ends the file spec */ - char *cp; /* current position in file spec */ - Boolean isSystem; /* TRUE if makefile is a system makefile */ - - /* - * 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 == '<') { - isSystem = TRUE; - endc = '>'; - } else { - isSystem = FALSE; - 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, FALSE); - - /* - * 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. - */ - if (!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. - */ - char *prefEnd; - - prefEnd = strrchr (fname, '/'); - if (prefEnd != (char *)NULL) { - char *newName; - - *prefEnd = '\0'; - if (file[0] == '/') - newName = strdup(file); - else - newName = str_concat (fname, file, STR_ADDSLASH); - fullname = Dir_FindFile (newName, parseIncPath); - if (fullname == (char *)NULL) { - fullname = Dir_FindFile(newName, dirSearchPath); - } - free (newName); - *prefEnd = '/'; - } else { - fullname = (char *)NULL; - } - } else { - fullname = (char *)NULL; - } - - if (fullname == (char *)NULL) { - /* - * System makefile or 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. - * XXX: Suffix specific? - */ - fullname = Dir_FindFile (file, parseIncPath); - if (fullname == (char *)NULL) { - fullname = Dir_FindFile(file, dirSearchPath); - } - } - - if (fullname == (char *)NULL) { - /* - * Still haven't found the makefile. Look for it on the system - * path as a last resort. - */ - fullname = Dir_FindFile(file, sysIncPath); - } - - if (fullname == (char *) NULL) { - *cp = endc; - Parse_Error (PARSE_FATAL, "Could not find %s", file); - return; - } - - free(file); - - /* - * Once we find the absolute path to the file, we get to save all the - * state from the current file before we can start reading this - * include file. The state is stored in an IFile structure which - * is placed on a list with other IFile structures. The list makes - * a very nice stack to track how we got here... - */ - oldFile = (IFile *) emalloc (sizeof (IFile)); - oldFile->fname = fname; - - oldFile->F = curFILE; - oldFile->p = curPTR; - oldFile->lineno = lineno; - - (void) Lst_AtFront (includes, (ClientData)oldFile); - - /* - * 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. Naturally enough, we start reading at line number 0. - */ - fname = fullname; - lineno = 0; - - curFILE = fopen (fullname, "r"); - curPTR = NULL; - if (curFILE == (FILE * ) NULL) { - Parse_Error (PARSE_FATAL, "Cannot open %s", fullname); - /* - * Pop to previous file - */ - (void) ParseEOF(0); - } -} - - -/*- - *--------------------------------------------------------------------- - * Parse_FromString -- - * Start Parsing from the given string - * - * 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_FromString(str) - char *str; -{ - IFile *oldFile; /* state associated with this file */ - - if (DEBUG(FOR)) - (void) fprintf(stderr, "%s\n----\n", str); - - oldFile = (IFile *) emalloc (sizeof (IFile)); - oldFile->lineno = lineno; - oldFile->fname = fname; - oldFile->F = curFILE; - oldFile->p = curPTR; - - (void) Lst_AtFront (includes, (ClientData)oldFile); - - curFILE = NULL; - curPTR = (PTR *) emalloc (sizeof (PTR)); - curPTR->str = curPTR->ptr = str; - lineno = 0; - fname = strdup(fname); -} - - -#ifdef SYSVINCLUDE -/*- - *--------------------------------------------------------------------- - * ParseTraditionalInclude -- - * Push to another file. - * - * The input is the line minus the "include". The file name is - * the string 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 (file) - char *file; /* file specification */ -{ - char *fullname; /* full pathname of file */ - IFile *oldFile; /* state associated with current file */ - char *cp; /* current position in file spec */ - char *prefEnd; - - /* - * Skip over whitespace - */ - while ((*file == ' ') || (*file == '\t')) { - file++; - } - - if (*file == '\0') { - Parse_Error (PARSE_FATAL, - "Filename missing from \"include\""); - return; - } - - /* - * Skip to end of line or next whitespace - */ - for (cp = file; *cp && *cp != '\n' && *cp != '\t' && *cp != ' '; cp++) { - continue; - } - - *cp = '\0'; - - /* - * Substitute for any variables in the file name before trying to - * find the thing. - */ - file = Var_Subst (NULL, file, VAR_CMD, FALSE); - - /* - * Now we know the file's name, we attempt to find the durn thing. - * A return of NULL indicates the file don't exist. - * - * Include files 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. - * XXX - this *does* search in the current directory, right? - */ - - prefEnd = strrchr (fname, '/'); - if (prefEnd != (char *)NULL) { - char *newName; - - *prefEnd = '\0'; - newName = str_concat (fname, file, STR_ADDSLASH); - fullname = Dir_FindFile (newName, parseIncPath); - if (fullname == (char *)NULL) { - fullname = Dir_FindFile(newName, dirSearchPath); - } - free (newName); - *prefEnd = '/'; - } else { - fullname = (char *)NULL; - } - - if (fullname == (char *)NULL) { - /* - * System makefile or 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. - * XXX: Suffix specific? - */ - fullname = Dir_FindFile (file, parseIncPath); - if (fullname == (char *)NULL) { - fullname = Dir_FindFile(file, dirSearchPath); - } - } - - if (fullname == (char *)NULL) { - /* - * Still haven't found the makefile. Look for it on the system - * path as a last resort. - */ - fullname = Dir_FindFile(file, sysIncPath); - } - - if (fullname == (char *) NULL) { - Parse_Error (PARSE_FATAL, "Could not find %s", file); - return; - } - - /* - * Once we find the absolute path to the file, we get to save all the - * state from the current file before we can start reading this - * include file. The state is stored in an IFile structure which - * is placed on a list with other IFile structures. The list makes - * a very nice stack to track how we got here... - */ - oldFile = (IFile *) emalloc (sizeof (IFile)); - oldFile->fname = fname; - - oldFile->F = curFILE; - oldFile->p = curPTR; - oldFile->lineno = lineno; - - (void) Lst_AtFront (includes, (ClientData)oldFile); - - /* - * 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. Naturally enough, we start reading at line number 0. - */ - fname = fullname; - lineno = 0; - - curFILE = fopen (fullname, "r"); - curPTR = NULL; - if (curFILE == (FILE * ) NULL) { - Parse_Error (PARSE_FATAL, "Cannot open %s", fullname); - /* - * Pop to previous file - */ - (void) ParseEOF(1); - } -} -#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 (opened) - int opened; -{ - IFile *ifile; /* the state on the top of the includes stack */ - - if (Lst_IsEmpty (includes)) { - return (DONE); - } - - ifile = (IFile *) Lst_DeQueue (includes); - free ((Address) fname); - fname = ifile->fname; - lineno = ifile->lineno; - if (opened && curFILE) - (void) fclose (curFILE); - if (curPTR) { - free((Address) curPTR->str); - free((Address) curPTR); - } - curFILE = ifile->F; - curPTR = ifile->p; - free ((Address)ifile); - return (CONTINUE); -} - -/*- - *--------------------------------------------------------------------- - * ParseReadc -- - * Read a character from the current file - * - * Results: - * The character that was read - * - * Side Effects: - *--------------------------------------------------------------------- - */ -static int -ParseReadc() -{ - if (curFILE) - return fgetc(curFILE); - - if (curPTR && *curPTR->ptr) - return *curPTR->ptr++; - return EOF; -} - - -/*- - *--------------------------------------------------------------------- - * ParseUnreadc -- - * Put back a character to the current file - * - * Results: - * None. - * - * Side Effects: - *--------------------------------------------------------------------- - */ -static void -ParseUnreadc(c) - int c; -{ - if (curFILE) { - ungetc(c, curFILE); - return; - } - if (curPTR) { - *--(curPTR->ptr) = c; - return; - } -} - - -/* ParseSkipLine(): - * Grab the next line - */ -static char * -ParseSkipLine(skip) - int skip; /* Skip lines that don't start with . */ -{ - char *line; - int c, lastc = '\0', lineLength; - Buffer buf; - - c = ParseReadc(); - - if (skip) { - /* - * Skip lines until get to one that begins with a - * special char. - */ - while ((c != '.') && (c != EOF)) { - while (((c != '\n') || (lastc == '\\')) && (c != EOF)) - { - /* - * Advance to next unescaped newline - */ - if ((lastc = c) == '\n') { - lineno++; - } - c = ParseReadc(); - } - lineno++; - - lastc = c; - c = ParseReadc (); - } - } - - if (c == EOF) { - Parse_Error (PARSE_FATAL, "Unclosed conditional/for loop"); - return ((char *)NULL); - } - - /* - * Read the entire line into buf - */ - buf = Buf_Init (MAKE_BSIZE); - if (c != '\n') { - do { - Buf_AddByte (buf, (Byte)c); - c = ParseReadc(); - } while ((c != '\n') && (c != EOF)); - } - lineno++; - - Buf_AddByte (buf, (Byte)'\0'); - line = (char *)Buf_GetAll (buf, &lineLength); - Buf_Destroy (buf, FALSE); - return line; -} - - -/*- - *--------------------------------------------------------------------- - * ParseReadLine -- - * Read an entire line from the input file. Called only by Parse_File. - * To facilitate escaped newlines and what have you, a character is - * buffered in 'lastc', which is '\0' when no characters have been - * read. When we break out of the loop, c holds the terminating - * character and lastc holds a character that should be added to - * the line (unless we don't read anything but a terminator). - * - * Results: - * A line w/o its newline - * - * Side Effects: - * Only those associated with reading a character - *--------------------------------------------------------------------- - */ -static char * -ParseReadLine () -{ - Buffer buf; /* Buffer for current line */ - register int c; /* the current character */ - register int lastc; /* The most-recent character */ - Boolean semiNL; /* treat semi-colons as newlines */ - Boolean ignDepOp; /* TRUE if should ignore dependency operators - * for the purposes of setting semiNL */ - Boolean ignComment; /* TRUE if should ignore comments (in a - * shell command */ - char *line; /* Result */ - char *ep; /* to strip trailing blanks */ - int lineLength; /* Length of result */ - - semiNL = FALSE; - ignDepOp = FALSE; - ignComment = FALSE; - - /* - * Handle special-characters at the beginning of the line. Either a - * leading tab (shell command) or pound-sign (possible conditional) - * forces us to ignore comments and dependency operators and treat - * semi-colons as semi-colons (by leaving semiNL FALSE). This also - * discards completely blank lines. - */ - for (;;) { - c = ParseReadc(); - - if (c == '\t') { - ignComment = ignDepOp = TRUE; - break; - } else if (c == '\n') { - lineno++; - } else if (c == '#') { - ParseUnreadc(c); - break; - } else { - /* - * Anything else breaks out without doing anything - */ - break; - } - } - - if (c != EOF) { - lastc = c; - buf = Buf_Init(MAKE_BSIZE); - - while (((c = ParseReadc ()) != '\n' || (lastc == '\\')) && - (c != EOF)) - { -test_char: - switch(c) { - case '\n': - /* - * Escaped newline: read characters until a non-space or an - * unescaped newline and replace them all by a single space. - * This is done by storing the space over the backslash and - * dropping through with the next nonspace. If it is a - * semi-colon and semiNL is TRUE, it will be recognized as a - * newline in the code below this... - */ - lineno++; - lastc = ' '; - while ((c = ParseReadc ()) == ' ' || c == '\t') { - continue; - } - if (c == EOF || c == '\n') { - goto line_read; - } else { - /* - * Check for comments, semiNL's, etc. -- easier than - * ParseUnreadc(c); continue; - */ - goto test_char; - } - /*NOTREACHED*/ - break; - - case ';': - /* - * Semi-colon: Need to see if it should be interpreted as a - * newline - */ - if (semiNL) { - /* - * To make sure the command that may be following this - * semi-colon begins with a tab, we push one back into the - * input stream. This will overwrite the semi-colon in the - * buffer. If there is no command following, this does no - * harm, since the newline remains in the buffer and the - * whole line is ignored. - */ - ParseUnreadc('\t'); - goto line_read; - } - break; - case '=': - if (!semiNL) { - /* - * Haven't seen a dependency operator before this, so this - * must be a variable assignment -- don't pay attention to - * dependency operators after this. - */ - ignDepOp = TRUE; - } else if (lastc == ':' || lastc == '!') { - /* - * Well, we've seen a dependency operator already, but it - * was the previous character, so this is really just an - * expanded variable assignment. Revert semi-colons to - * being just semi-colons again and ignore any more - * dependency operators. - * - * XXX: Note that a line like "foo : a:=b" will blow up, - * but who'd write a line like that anyway? - */ - ignDepOp = TRUE; semiNL = FALSE; - } - break; - case '#': - if (!ignComment) { - if (compatMake && (lastc != '\\')) { - /* - * If the character is a hash mark and it isn't escaped - * (or we're being compatible), the thing is a comment. - * Skip to the end of the line. - */ - do { - c = ParseReadc(); - } while ((c != '\n') && (c != EOF)); - goto line_read; - } else { - /* - * Don't add the backslash. Just let the # get copied - * over. - */ - lastc = c; - continue; - } - } - break; - case ':': - case '!': - if (!ignDepOp && (c == ':' || c == '!')) { - /* - * A semi-colon is recognized as a newline only on - * dependency lines. Dependency lines are lines with a - * colon or an exclamation point. Ergo... - */ - semiNL = TRUE; - } - break; - } - /* - * Copy in the previous character and save this one in lastc. - */ - Buf_AddByte (buf, (Byte)lastc); - lastc = c; - - } - line_read: - lineno++; - - if (lastc != '\0') { - Buf_AddByte (buf, (Byte)lastc); - } - Buf_AddByte (buf, (Byte)'\0'); - line = (char *)Buf_GetAll (buf, &lineLength); - Buf_Destroy (buf, FALSE); - - /* - * Strip trailing blanks and tabs from the line. - * Do not strip a blank or tab that is preceeded by - * a '\' - */ - ep = line; - while (*ep) - ++ep; - while (ep > line && (ep[-1] == ' ' || ep[-1] == '\t')) { - if (ep > line + 1 && ep[-2] == '\\') - break; - --ep; - } - *ep = 0; - - if (line[0] == '.') { - /* - * 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 { - free (line); - line = ParseSkipLine(1); - } while (line && Cond_Eval(line) != COND_PARSE); - if (line == NULL) - break; - /*FALLTHRU*/ - case COND_PARSE: - free ((Address) line); - line = ParseReadLine(); - break; - case COND_INVALID: - if (For_Eval(line)) { - int ok; - free(line); - do { - /* - * Skip after the matching end - */ - line = ParseSkipLine(0); - if (line == NULL) { - Parse_Error (PARSE_FATAL, - "Unexpected end of file in for loop.\n"); - break; - } - ok = For_Eval(line); - free(line); - } - while (ok); - if (line != NULL) - For_Run(); - line = ParseReadLine(); - } - break; - } - } - return (line); - - } else { - /* - * Hit end-of-file, so return a NULL line to indicate this. - */ - return((char *)NULL); - } -} - -/*- - *----------------------------------------------------------------------- - * ParseFinishLine -- - * Handle the end of a dependency group. - * - * Results: - * Nothing. - * - * Side Effects: - * inLine set FALSE. 'targets' list destroyed. - * - *----------------------------------------------------------------------- - */ -static void -ParseFinishLine() -{ - if (inLine) { - Lst_ForEach(targets, Suff_EndTransform, (ClientData)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 - * - * Results: - * None - * - * Side Effects: - * 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(name, stream) - char *name; /* the name of the file being read */ - FILE * stream; /* Stream open to makefile to parse */ -{ - register char *cp, /* pointer into the line */ - *line; /* the line we're working on */ - - inLine = FALSE; - fname = name; - curFILE = stream; - lineno = 0; - fatals = 0; - - do { - while ((line = ParseReadLine ()) != NULL) { - if (*line == '.') { - /* - * Lines that begin with the special character are either - * include or undef directives. - */ - for (cp = line + 1; isspace (*cp); cp++) { - continue; - } - if (strncmp (cp, "include", 7) == 0) { - ParseDoInclude (cp + 7); - goto nextLine; - } else 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); - goto nextLine; - } - } - if (*line == '#' || *line == '\0') { - /* If we're this far, the line must be a comment. - (Empty lines are ignored as well) */ - goto nextLine; - } - - if (*line == '\t') { - /* - * If a line starts with a tab, it can only hope to be - * a creation command. - */ -#ifndef POSIX - shellCommand: -#endif - for (cp = line + 1; isspace (*cp); cp++) { - continue; - } - if (*cp) { - if (inLine) { - /* - * 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 - */ - Lst_ForEach (targets, ParseAddCmd, cp); - Lst_AtEnd(targCmds, (ClientData) line); - continue; - } else { - Parse_Error (PARSE_FATAL, - "Unassociated shell command \"%.20s\"", - cp); - } - } -#ifdef SYSVINCLUDE - } else if (strncmp (line, "include", 7) == 0 && - strchr(line, ':') == NULL) { - /* - * It's an S3/S5-style "include". - */ - ParseTraditionalInclude (line + 7); - goto nextLine; -#endif - } else if (Parse_IsVar (line)) { - ParseFinishLine(); - Parse_DoVar (line, VAR_GLOBAL); - } else { - /* - * 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... - * 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. - */ -#ifndef POSIX - Boolean nonSpace = FALSE; -#endif - - cp = line; - if (isspace((unsigned char) line[0])) { - while ((*cp != '\0') && isspace((unsigned char) *cp)) { - cp++; - } - if (*cp == '\0') { - goto nextLine; - } -#ifndef POSIX - while ((*cp != ':') && (*cp != '!') && (*cp != '\0')) { - nonSpace = TRUE; - cp++; - } -#endif - } - -#ifndef POSIX - if (*cp == '\0') { - if (inLine) { - Parse_Error (PARSE_WARNING, - "Shell command needs a leading tab"); - goto shellCommand; - } else if (nonSpace) { - Parse_Error (PARSE_FATAL, "Missing operator"); - } - } else { -#endif - ParseFinishLine(); - - cp = Var_Subst (NULL, line, VAR_CMD, TRUE); - free (line); - line = cp; - - /* - * Need a non-circular list for the target nodes - */ - if (targets) - Lst_Destroy(targets, NOFREE); - - targets = Lst_Init (FALSE); - inLine = TRUE; - - ParseDoDependency (line); -#ifndef POSIX - } -#endif - } - - nextLine: - - free (line); - } - /* - * Reached EOF, but it may be just EOF of an include file... - */ - } while (ParseEOF(1) == CONTINUE); - - /* - * Make sure conditionals are clean - */ - Cond_End(); - - if (fatals) { - fprintf (stderr, "Fatal errors encountered -- cannot continue\n"); - exit (1); - } -} - -/*- - *--------------------------------------------------------------------- - * Parse_Init -- - * initialize the parsing module - * - * Results: - * none - * - * Side Effects: - * the parseIncPath list is initialized... - *--------------------------------------------------------------------- - */ -void -Parse_Init () -{ - char *cp = NULL, *start; - /* avoid faults on read-only strings */ - static char syspath[] = _PATH_DEFSYSPATH; - - mainNode = NILGNODE; - parseIncPath = Lst_Init (FALSE); - sysIncPath = Lst_Init (FALSE); - includes = Lst_Init (FALSE); - targCmds = Lst_Init (FALSE); - - /* - * Add the directories from the DEFSYSPATH (more than one may be given - * as dir1:...:dirn) to the system include path. - */ - for (start = syspath; *start != '\0'; start = cp) { - for (cp = start; *cp != '\0' && *cp != ':'; cp++) - continue; - if (*cp == '\0') { - Dir_AddDir(sysIncPath, start); - } else { - *cp++ = '\0'; - Dir_AddDir(sysIncPath, start); - } - } -} - -void -Parse_End() -{ - Lst_Destroy(targCmds, (void (*) __P((ClientData))) free); - if (targets) - Lst_Destroy(targets, NOFREE); - Lst_Destroy(sysIncPath, Dir_Destroy); - Lst_Destroy(parseIncPath, Dir_Destroy); - Lst_Destroy(includes, NOFREE); /* Should be empty now */ -} - - -/*- - *----------------------------------------------------------------------- - * 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() -{ - Lst main; /* result list */ - - main = Lst_Init (FALSE); - - if (mainNode == NILGNODE) { - Punt ("make: no target to make.\n"); - /*NOTREACHED*/ - } else if (mainNode->type & OP_DOUBLEDEP) { - (void) Lst_AtEnd (main, (ClientData)mainNode); - Lst_Concat(main, mainNode->cohorts, LST_CONCNEW); - } - else - (void) Lst_AtEnd (main, (ClientData)mainNode); - return (main); -} diff --git a/usr.bin/make/pathnames.h b/usr.bin/make/pathnames.h deleted file mode 100644 index 8cb0661483933..0000000000000 --- a/usr.bin/make/pathnames.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. 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. - * - * @(#)pathnames.h 8.2 (Berkeley) 4/28/95 - */ - -#define _PATH_OBJDIR "obj" -#define _PATH_DEFSHELLDIR "/bin" -#define _PATH_DEFSYSMK "sys.mk" -#define _PATH_DEFSYSPATH "/usr/share/mk" diff --git a/usr.bin/make/sprite.h b/usr.bin/make/sprite.h deleted file mode 100644 index 0da22f180d052..0000000000000 --- a/usr.bin/make/sprite.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * 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. - * - * @(#)sprite.h 8.2 (Berkeley) 4/28/95 - */ - -/* - * sprite.h -- - * - * Common constants and type declarations for Sprite. - */ - -#ifndef _SPRITE -#define _SPRITE - - -/* - * 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 - - -/* - * A nil pointer must be something that will cause an exception if - * referenced. There are two nils: the kernels nil and the nil used - * by user processes. - */ - -#define NIL ~0 -#define USER_NIL 0 -#ifndef NULL -#define NULL 0 -#endif NULL - -/* - * An address is just a pointer in C. It is defined as a character pointer - * so that address arithmetic will work properly, a byte at a time. - */ - -typedef char *Address; - -/* - * ClientData is an uninterpreted word. It is defined as an int so that - * kdbx will not interpret client data as a string. Unlike an "Address", - * client data will generally not be used in arithmetic. - * But we don't have kdbx anymore so we define it as void (christos) - */ - -typedef void *ClientData; - -#endif /* _SPRITE */ diff --git a/usr.bin/make/str.c b/usr.bin/make/str.c deleted file mode 100644 index 7df8e8d2f113f..0000000000000 --- a/usr.bin/make/str.c +++ /dev/null @@ -1,491 +0,0 @@ -/*- - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * 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 lint -static char sccsid[] = "@(#)str.c 8.6 (Berkeley) 4/28/95"; -#endif /* not lint */ - -#include "make.h" - -static char **argv, *buffer; -static int argmax, curlen; - -/* - * str_init -- - * Initialize the strings package - * - */ -void -str_init() -{ - char *p1; - argv = (char **)emalloc((argmax = 50) * sizeof(char *)); - argv[0] = Var_Value(".MAKE", VAR_GLOBAL, &p1); -} - - -/* - * str_end -- - * Cleanup the strings package - * - */ -void -str_end() -{ - if (argv[0]) { - free(argv[0]); - free((Address) argv); - } - if (buffer) - free(buffer); -} - - -/*- - * 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(s1, s2, flags) - char *s1, *s2; - int flags; -{ - register int len1, len2; - register char *result; - - /* get the length of both strings */ - len1 = strlen(s1); - len2 = strlen(s2); - - /* allocate length plus separator plus EOS */ - result = emalloc((u_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); - - /* free original strings */ - if (flags & STR_DOFREE) { - (void)free(s1); - (void)free(s2); - } - 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. - * - * returns -- - * Pointer to the array of pointers to the words. To make life easier, - * the first word is always the value of the .MAKE variable. - */ -char ** -brk_string(str, store_argc, expand) - register char *str; - int *store_argc; - Boolean expand; -{ - register int argc, ch; - register char inquote, *p, *start, *t; - int len; - - /* skip leading space chars. */ - for (; *str == ' ' || *str == '\t'; ++str) - continue; - - /* allocate room for a copy of the string */ - if ((len = strlen(str) + 1) > curlen) { - if (buffer) - free(buffer); - buffer = emalloc(curlen = len); - } - - /* - * copy the string; at the same time, parse backslashes, - * quotes and build the argument list. - */ - argc = 1; - 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) { - start = t + 1; - 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 */ - if (!(argv = (char **)realloc(argv, - argmax * sizeof(char *)))) - enomem(); - } - argv[argc++] = start; - start = (char *)NULL; - if (ch == '\n' || ch == '\0') - goto done; - continue; - case '\\': - if (!expand) { - if (!start) - start = t; - *t++ = '\\'; - 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] = (char *)NULL; - *store_argc = argc; - return(argv); -} - -/* - * Str_FindSubstring -- See if a string contains a particular substring. - * - * 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(string, substring) - register char *string; /* String to search. */ - char *substring; /* Substring to find in string */ -{ - register 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(string); - if (*a++ != *b++) - break; - } - b = substring; - } - return((char *) 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). - * - * Side effects: None. - */ -int -Str_Match(string, pattern) - register char *string; /* String */ - register char *pattern; /* 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 == '[') { - ++pattern; - for (;;) { - if ((*pattern == ']') || (*pattern == 0)) - return(0); - if (*pattern == *string) - break; - if (pattern[1] == '-') { - c2 = pattern[2]; - if (c2 == 0) - return(0); - if ((*pattern <= *string) && - (c2 >= *string)) - break; - if ((*pattern >= *string) && - (c2 <= *string)) - break; - pattern += 2; - } - ++pattern; - } - 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), - * - * 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(word, pattern, len) - char *word; /* Word to examine */ - char *pattern; /* Pattern to examine against */ - int *len; /* Number of characters to substitute */ -{ - char *p = pattern; - char *w = word; - char *m; - - if (*p == '\0') { - /* Null pattern is the whole string */ - *len = strlen(w); - return 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 w; - } - } - - m = w; - - /* Find a matching tail */ - do - if (strcmp(p, w) == 0) { - *len = w - m; - return 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(buf, pat, src, len) - Buffer buf; - char *pat; - char *src; - int len; -{ - char *m; - - if ((m = strchr(pat, '%')) != NULL) { - /* Copy the prefix */ - Buf_AddBytes(buf, m - pat, (Byte *) pat); - /* skip the % */ - pat = m + 1; - } - - /* Copy the pattern */ - Buf_AddBytes(buf, len, (Byte *) src); - - /* append the rest */ - Buf_AddBytes(buf, strlen(pat), (Byte *) pat); -} diff --git a/usr.bin/make/suff.c b/usr.bin/make/suff.c deleted file mode 100644 index 1b344d4994906..0000000000000 --- a/usr.bin/make/suff.c +++ /dev/null @@ -1,2435 +0,0 @@ -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * 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 lint -static char sccsid[] = "@(#)suff.c 8.5 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * 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 NILGNODE - * if the target had no implicit sources. - */ - -#include <stdio.h> -#include "make.h" -#include "hash.h" -#include "dir.h" -#include "bit.h" - -static Lst sufflist; /* Lst of suffixes */ -static Lst suffClean; /* Lst of suffixes to be cleaned */ -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; - -/* - * 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; - -static Suff *suffNull; /* The NULL suffix for this run */ -static Suff *emptySuff; /* The empty suffix required for POSIX - * single-suffix transformation rules */ - - -static char *SuffStrIsPrefix __P((char *, char *)); -static char *SuffSuffIsSuffix __P((Suff *, char *)); -static int SuffSuffIsSuffixP __P((ClientData, ClientData)); -static int SuffSuffHasNameP __P((ClientData, ClientData)); -static int SuffSuffIsPrefix __P((ClientData, ClientData)); -static int SuffGNHasNameP __P((ClientData, ClientData)); -static void SuffFree __P((ClientData)); -static void SuffInsert __P((Lst, Suff *)); -static void SuffRemove __P((Lst, Suff *)); -static Boolean SuffParseTransform __P((char *, Suff **, Suff **)); -static int SuffRebuildGraph __P((ClientData, ClientData)); -static int SuffAddSrc __P((ClientData, ClientData)); -static int SuffRemoveSrc __P((Lst)); -static void SuffAddLevel __P((Lst, Src *)); -static Src *SuffFindThem __P((Lst, Lst)); -static Src *SuffFindCmds __P((Src *, Lst)); -static int SuffExpandChildren __P((ClientData, ClientData)); -static Boolean SuffApplyTransform __P((GNode *, GNode *, Suff *, Suff *)); -static void SuffFindDeps __P((GNode *, Lst)); -static void SuffFindArchiveDeps __P((GNode *, Lst)); -static void SuffFindNormalDeps __P((GNode *, Lst)); -static int SuffPrintName __P((ClientData, ClientData)); -static int SuffPrintSuff __P((ClientData, ClientData)); -static int SuffPrintTrans __P((ClientData, ClientData)); - - /*************** Lst Predicates ****************/ -/*- - *----------------------------------------------------------------------- - * SuffStrIsPrefix -- - * See if pref is a prefix of str. - * - * Results: - * NULL if it ain't, pointer to character in str after prefix if so - * - * Side Effects: - * None - *----------------------------------------------------------------------- - */ -static char * -SuffStrIsPrefix (pref, str) - register char *pref; /* possible prefix */ - register char *str; /* string to check */ -{ - while (*str && *pref == *str) { - pref++; - str++; - } - - return (*pref ? NULL : str); -} - -/*- - *----------------------------------------------------------------------- - * SuffSuffIsSuffix -- - * See if suff is a suffix of str. Str should point to THE END of the - * string to check. (THE END == the null byte) - * - * Results: - * NULL if it ain't, pointer to character in str before suffix if - * it is. - * - * Side Effects: - * None - *----------------------------------------------------------------------- - */ -static char * -SuffSuffIsSuffix (s, str) - register Suff *s; /* possible suffix */ - char *str; /* string to examine */ -{ - register char *p1; /* Pointer into suffix name */ - register char *p2; /* Pointer into string being examined */ - - p1 = s->name + s->nameLen; - p2 = str; - - 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(s, str) - ClientData s; - ClientData str; -{ - return(!SuffSuffIsSuffix((Suff *) s, (char *) str)); -} - -/*- - *----------------------------------------------------------------------- - * SuffSuffHasNameP -- - * Callback procedure for finding a suffix based on its name. Used by - * Suff_GetPath. - * - * Results: - * 0 if the suffix is of the given name. non-zero otherwise. - * - * Side Effects: - * None - *----------------------------------------------------------------------- - */ -static int -SuffSuffHasNameP (s, sname) - ClientData s; /* Suffix to check */ - ClientData sname; /* Desired name */ -{ - return (strcmp ((char *) sname, ((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... - * - * Results: - * 0 if s is a prefix of str. non-zero otherwise - * - * Side Effects: - * None - *----------------------------------------------------------------------- - */ -static int -SuffSuffIsPrefix (s, str) - ClientData s; /* suffix to compare */ - ClientData str; /* string to examine */ -{ - return (SuffStrIsPrefix (((Suff *) s)->name, (char *) str) == NULL ? 1 : 0); -} - -/*- - *----------------------------------------------------------------------- - * SuffGNHasNameP -- - * See if the graph node has the desired name - * - * Results: - * 0 if it does. non-zero if it doesn't - * - * Side Effects: - * None - *----------------------------------------------------------------------- - */ -static int -SuffGNHasNameP (gn, name) - ClientData gn; /* current node we're looking at */ - ClientData name; /* name we're looking for */ -{ - return (strcmp ((char *) name, ((GNode *) gn)->name)); -} - - /*********** Maintenance Functions ************/ - -static void -SuffUnRef(lp, sp) - ClientData lp; - ClientData sp; -{ - Lst l = (Lst) lp; - - LstNode ln = Lst_Member(l, sp); - if (ln != NILLNODE) { - 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 (sp) - ClientData sp; -{ - Suff *s = (Suff *) sp; - - if (s == suffNull) - suffNull = NULL; - - if (s == emptySuff) - emptySuff = NULL; - - Lst_Destroy (s->ref, NOFREE); - Lst_Destroy (s->children, NOFREE); - Lst_Destroy (s->parents, NOFREE); - Lst_Destroy (s->searchPath, Dir_Destroy); - - free ((Address)s->name); - free ((Address)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(l, s) - Lst l; - Suff *s; -{ - SuffUnRef((ClientData) l, (ClientData) s); - if (s->refCount == 0) - SuffFree((ClientData) s); -} - -/*- - *----------------------------------------------------------------------- - * SuffInsert -- - * Insert the suffix into the list keeping the list ordered by suffix - * numbers. - * - * Results: - * None - * - * Side Effects: - * The reference count of the suffix is incremented - *----------------------------------------------------------------------- - */ -static void -SuffInsert (l, s) - Lst l; /* the list where in s should be inserted */ - Suff *s; /* the suffix to insert */ -{ - 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)) != NILLNODE) { - s2 = (Suff *) Lst_Datum (ln); - if (s2->sNum >= s->sNum) { - break; - } - } - - Lst_Close (l); - if (DEBUG(SUFF)) { - printf("inserting %s(%d)...", s->name, s->sNum); - } - if (ln == NILLNODE) { - if (DEBUG(SUFF)) { - printf("at end of list\n"); - } - (void)Lst_AtEnd (l, (ClientData)s); - s->refCount++; - (void)Lst_AtEnd(s->ref, (ClientData) l); - } else if (s2->sNum != s->sNum) { - if (DEBUG(SUFF)) { - printf("before %s(%d)\n", s2->name, s2->sNum); - } - (void)Lst_Insert (l, ln, (ClientData)s); - s->refCount++; - (void)Lst_AtEnd(s->ref, (ClientData) l); - } else if (DEBUG(SUFF)) { - printf("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 () -{ - Lst_Concat (suffClean, sufflist, LST_CONCLINK); - sufflist = Lst_Init(FALSE); - sNum = 0; - suffNull = emptySuff; -} - -/*- - *----------------------------------------------------------------------- - * SuffParseTransform -- - * Parse a transformation string to find its two component suffixes. - * - * Results: - * TRUE if the string is a valid transformation and FALSE otherwise. - * - * Side Effects: - * The passed pointers are overwritten. - * - *----------------------------------------------------------------------- - */ -static Boolean -SuffParseTransform(str, srcPtr, targPtr) - char *str; /* String being parsed */ - Suff **srcPtr; /* Place to store source of trans. */ - Suff **targPtr; /* Place to store target of trans. */ -{ - register LstNode srcLn; /* element in suffix list of trans source*/ - register Suff *src; /* Source of transformation */ - register LstNode targLn; /* element in suffix list of trans target*/ - register 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 = NILLNODE; - singleLn = NILLNODE; - - /* - * 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 == NILLNODE) { - srcLn = Lst_Find(sufflist, (ClientData)str, SuffSuffIsPrefix); - } else { - srcLn = Lst_FindFrom (sufflist, Lst_Succ(srcLn), (ClientData)str, - SuffSuffIsPrefix); - } - if (srcLn == NILLNODE) { - /* - * Ran out of source suffixes -- no such rule - */ - if (singleLn != NILLNODE) { - /* - * 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, (ClientData)str2, SuffSuffHasNameP); - if (targLn != NILLNODE) { - *srcPtr = src; - *targPtr = (Suff *)Lst_Datum(targLn); - return (TRUE); - } - } - } -} - -/*- - *----------------------------------------------------------------------- - * Suff_IsTransform -- - * Return TRUE if the given string is a transformation rule - * - * - * Results: - * TRUE if the string is a concatenation of two known suffixes. - * FALSE otherwise - * - * Side Effects: - * None - *----------------------------------------------------------------------- - */ -Boolean -Suff_IsTransform (str) - char *str; /* string to check */ -{ - 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 - * - * 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 (line) - char *line; /* name of transformation to add */ -{ - GNode *gn; /* GNode of transformation rule */ - Suff *s, /* source suffix */ - *t; /* target suffix */ - LstNode ln; /* Node for existing transformation */ - - ln = Lst_Find (transforms, (ClientData)line, SuffGNHasNameP); - if (ln == NILLNODE) { - /* - * 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, (ClientData)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, NOFREE); - Lst_Destroy (gn->children, NOFREE); - 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)) { - printf("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 - * - * Results: - * === 0 - * - * Side Effects: - * If the node has no commands or children, the children and parents - * lists of the affected suffices are altered. - * - *----------------------------------------------------------------------- - */ -int -Suff_EndTransform(gnp, dummy) - ClientData gnp; /* Node for transformation */ - ClientData dummy; /* Node for transformation */ -{ - GNode *gn = (GNode *) gnp; - - if ((gn->type & OP_TRANSFORM) && Lst_IsEmpty(gn->commands) && - Lst_IsEmpty(gn->children)) - { - Suff *s, *t; - - (void)SuffParseTransform(gn->name, &s, &t); - - if (DEBUG(SUFF)) { - printf("deleting transformation from %s to %s\n", - s->name, t->name); - } - - /* - * 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(s->parents, t); - } else if ((gn->type & OP_TRANSFORM) && DEBUG(SUFF)) { - printf("transformation %s complete\n", gn->name); - } - - return(dummy ? 0 : 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. - * - * 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(transformp, sp) - ClientData transformp; /* Transformation to test */ - ClientData sp; /* Suffix to rebuild */ -{ - GNode *transform = (GNode *) transformp; - Suff *s = (Suff *) sp; - char *cp; - LstNode ln; - Suff *s2; - - /* - * First see if it is a transformation from this suffix. - */ - cp = SuffStrIsPrefix(s->name, transform->name); - if (cp != (char *)NULL) { - ln = Lst_Find(sufflist, (ClientData)cp, SuffSuffHasNameP); - if (ln != NILLNODE) { - /* - * 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? - */ - cp = SuffSuffIsSuffix(s, transform->name + strlen(transform->name)); - if (cp != (char *)NULL) { - /* - * Null-terminate the source suffix in order to find it. - */ - cp[1] = '\0'; - ln = Lst_Find(sufflist, (ClientData)transform->name, SuffSuffHasNameP); - /* - * Replace the start of the target suffix - */ - cp[1] = s->name[0]; - if (ln != NILLNODE) { - /* - * Found it -- establish the proper relationship - */ - s2 = (Suff *)Lst_Datum(ln); - SuffInsert(s->children, s2); - SuffInsert(s2->parents, s); - } - } - 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... - * - * 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. - *----------------------------------------------------------------------- - */ -void -Suff_AddSuffix (str) - char *str; /* the name of the suffix to add */ -{ - Suff *s; /* new suffix descriptor */ - LstNode ln; - - ln = Lst_Find (sufflist, (ClientData)str, SuffSuffHasNameP); - if (ln == NILLNODE) { - s = (Suff *) emalloc (sizeof (Suff)); - - s->name = 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 = 0; - - (void)Lst_AtEnd (sufflist, (ClientData)s); - /* - * Look for any existing transformations from or to this suffix. - * XXX: Only do this after a Suff_ClearSuffixes? - */ - Lst_ForEach (transforms, SuffRebuildGraph, (ClientData)s); - } -} - -/*- - *----------------------------------------------------------------------- - * Suff_GetPath -- - * Return the search path for the given suffix, if it's defined. - * - * Results: - * The searchPath for the desired suffix or NILLST if the suffix isn't - * defined. - * - * Side Effects: - * None - *----------------------------------------------------------------------- - */ -Lst -Suff_GetPath (sname) - char *sname; -{ - LstNode ln; - Suff *s; - - ln = Lst_Find (sufflist, (ClientData)sname, SuffSuffHasNameP); - if (ln == NILLNODE) { - return (NILLST); - } 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 preceeded 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() -{ - register Suff *s; - register 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)) != NILLNODE) { - 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); - free(ptr); - Var_Set(".LIBS", ptr = Dir_MakeFlags("-L", inLibs), VAR_GLOBAL); - 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. - * - * Results: - * None. - * - * Side Effects: - * The SUFF_INCLUDE bit is set in the suffix's flags field - * - *----------------------------------------------------------------------- - */ -void -Suff_AddInclude (sname) - char *sname; /* Name of suffix to mark */ -{ - LstNode ln; - Suff *s; - - ln = Lst_Find (sufflist, (ClientData)sname, SuffSuffHasNameP); - if (ln != NILLNODE) { - 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. - * - * Results: - * None. - * - * Side Effects: - * The SUFF_LIBRARY bit is set in the suffix's flags field - * - *----------------------------------------------------------------------- - */ -void -Suff_AddLib (sname) - char *sname; /* Name of suffix to mark */ -{ - LstNode ln; - Suff *s; - - ln = Lst_Find (sufflist, (ClientData)sname, SuffSuffHasNameP); - if (ln != NILLNODE) { - 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. - * - * Results: - * always returns 0 - * - * Side Effects: - * A Src structure is created and tacked onto the end of the list - *----------------------------------------------------------------------- - */ -static int -SuffAddSrc (sp, lsp) - ClientData sp; /* suffix for which to create a Src structure */ - ClientData lsp; /* list and parent for the new Src */ -{ - 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 = (Src *) emalloc (sizeof (Src)); - s2->file = strdup(targ->pref); - s2->pref = targ->pref; - s2->parent = targ; - s2->node = NILGNODE; - s2->suff = s; - s->refCount++; - s2->children = 0; - targ->children += 1; - (void)Lst_AtEnd (ls->l, (ClientData)s2); -#ifdef DEBUG_SRC - s2->cp = Lst_Init(FALSE); - Lst_AtEnd(targ->cp, (ClientData) s2); - printf("1 add %x %x to %x:", targ, s2, ls->l); - Lst_ForEach(ls->l, PrintAddr, (ClientData) 0); - printf("\n"); -#endif - } - s2 = (Src *) emalloc (sizeof (Src)); - s2->file = str_concat (targ->pref, s->name, 0); - s2->pref = targ->pref; - s2->parent = targ; - s2->node = NILGNODE; - s2->suff = s; - s->refCount++; - s2->children = 0; - targ->children += 1; - (void)Lst_AtEnd (ls->l, (ClientData)s2); -#ifdef DEBUG_SRC - s2->cp = Lst_Init(FALSE); - Lst_AtEnd(targ->cp, (ClientData) s2); - printf("2 add %x %x to %x:", targ, s2, ls->l); - Lst_ForEach(ls->l, PrintAddr, (ClientData) 0); - printf("\n"); -#endif - - return(0); -} - -/*- - *----------------------------------------------------------------------- - * SuffAddLevel -- - * Add all the children of targ as Src structures to the given list - * - * Results: - * None - * - * Side Effects: - * Lots of structures are created and added to the list - *----------------------------------------------------------------------- - */ -static void -SuffAddLevel (l, targ) - Lst l; /* list to which to add the new level */ - Src *targ; /* Src structure to use as the parent */ -{ - LstSrc ls; - - ls.s = targ; - ls.l = l; - - Lst_ForEach (targ->suff->children, SuffAddSrc, (ClientData)&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 (l) - Lst l; -{ - LstNode ln; - Src *s; - int t = 0; - - if (Lst_Open (l) == FAILURE) { - return 0; - } -#ifdef DEBUG_SRC - printf("cleaning %lx: ", (unsigned long) l); - Lst_ForEach(l, PrintAddr, (ClientData) 0); - printf("\n"); -#endif - - - while ((ln = Lst_Next (l)) != NILLNODE) { - s = (Src *) Lst_Datum (ln); - if (s->children == 0) { - free ((Address)s->file); - if (!s->parent) - free((Address)s->pref); - else { -#ifdef DEBUG_SRC - LstNode ln = Lst_Member(s->parent->cp, (ClientData)s); - if (ln != NILLNODE) - Lst_Remove(s->parent->cp, ln); -#endif - --s->parent->children; - } -#ifdef DEBUG_SRC - printf("free: [l=%x] p=%x %d\n", l, s, s->children); - Lst_Destroy(s->cp, NOFREE); -#endif - Lst_Remove(l, ln); - free ((Address)s); - t |= 1; - Lst_Close(l); - return TRUE; - } -#ifdef DEBUG_SRC - else { - printf("keep: [l=%x] p=%x %d: ", l, s, s->children); - Lst_ForEach(s->cp, PrintAddr, (ClientData) 0); - printf("\n"); - } -#endif - } - - Lst_Close(l); - - return t; -} - -/*- - *----------------------------------------------------------------------- - * SuffFindThem -- - * Find the first existing file/target in the list srcs - * - * Results: - * The lowest structure in the chain of transformations - * - * Side Effects: - * None - *----------------------------------------------------------------------- - */ -static Src * -SuffFindThem (srcs, slst) - Lst srcs; /* list of Src structures to search through */ - Lst slst; -{ - Src *s; /* current Src */ - Src *rs; /* returned Src */ - char *ptr; - - rs = (Src *) NULL; - - while (!Lst_IsEmpty (srcs)) { - s = (Src *) Lst_DeQueue (srcs); - - if (DEBUG(SUFF)) { - printf ("\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) != NILGNODE) { -#ifdef DEBUG_SRC - printf("remove %x from %x\n", s, srcs); -#endif - rs = s; - break; - } - - if ((ptr = Dir_FindFile (s->file, s->suff->searchPath)) != NULL) { - rs = s; -#ifdef DEBUG_SRC - printf("remove %x from %x\n", s, srcs); -#endif - free(ptr); - break; - } - - if (DEBUG(SUFF)) { - printf ("not there\n"); - } - - SuffAddLevel (srcs, s); - Lst_AtEnd(slst, (ClientData) s); - } - - if (DEBUG(SUFF) && rs) { - printf ("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. - * - * Results: - * The Src structure of the "winning" child, or NIL if no such beast. - * - * Side Effects: - * A Src structure may be allocated. - * - *----------------------------------------------------------------------- - */ -static Src * -SuffFindCmds (targ, slst) - Src *targ; /* Src structure to play with */ - Lst slst; -{ - LstNode ln; /* General-purpose list node */ - register 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); - - while ((ln = Lst_Next (t->children)) != NILLNODE) { - s = (GNode *)Lst_Datum (ln); - - cp = strrchr (s->name, '/'); - if (cp == (char *)NULL) { - cp = s->name; - } else { - cp++; - } - if (strncmp (cp, targ->pref, prefLen) == 0) { - /* - * The node matches the prefix ok, see if it has a known - * suffix. - */ - ln = Lst_Find (sufflist, (ClientData)&cp[prefLen], - SuffSuffHasNameP); - if (ln != NILLNODE) { - /* - * 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, - (ClientData)targ->suff) != NILLNODE) - { - /* - * 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 = (Src *)emalloc (sizeof (Src)); - ret->file = 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); - printf("3 add %x %x\n", targ, ret); - Lst_AtEnd(targ->cp, (ClientData) ret); -#endif - Lst_AtEnd(slst, (ClientData) ret); - if (DEBUG(SUFF)) { - printf ("\tusing existing source %s\n", s->name); - } - return (ret); - } - } - } - } - Lst_Close (t->children); - return ((Src *)NULL); -} - -/*- - *----------------------------------------------------------------------- - * SuffExpandChildren -- - * Expand the names of any children of a given node that contain - * variable invocations or file wildcards into actual targets. - * - * 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 int -SuffExpandChildren(cgnp, pgnp) - ClientData cgnp; /* Child to examine */ - ClientData pgnp; /* Parent node being processed */ -{ - GNode *cgn = (GNode *) cgnp; - GNode *pgn = (GNode *) pgnp; - GNode *gn; /* New source 8) */ - LstNode prevLN; /* Node after which new source should be put */ - LstNode ln; /* List element for old source */ - char *cp; /* Expanded value */ - - /* - * New nodes effectively take the place of the child, so place them - * after the child - */ - prevLN = Lst_Member(pgn->children, (ClientData)cgn); - - /* - * 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, '$') != (char *)NULL) { - if (DEBUG(SUFF)) { - printf("Expanding \"%s\"...", cgn->name); - } - cp = Var_Subst(NULL, cgn->name, pgn, TRUE); - - if (cp != (char *)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, (ClientData)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; - Boolean doFree; - - junk = Var_Parse(cp, pgn, TRUE, &len, &doFree); - if (junk != var_Error) { - cp += len - 1; - } - - if (doFree) { - free(junk); - } - } else if (*cp == '\\' && *cp != '\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, (ClientData)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)) { - printf("%s...", gn->name); - } - if (Lst_Member(pgn->children, (ClientData)gn) == NILLNODE) { - (void)Lst_Append(pgn->children, prevLN, (ClientData)gn); - prevLN = Lst_Succ(prevLN); - (void)Lst_AtEnd(gn->parents, (ClientData)pgn); - pgn->unmade++; - } - } - Lst_Destroy(members, NOFREE); - /* - * Free the result - */ - free((char *)cp); - } - /* - * Now the source is expanded, remove it from the list of children to - * keep it from being processed. - */ - ln = Lst_Member(pgn->children, (ClientData)cgn); - pgn->unmade--; - Lst_Remove(pgn->children, ln); - if (DEBUG(SUFF)) { - printf("\n"); - } - } else if (Dir_HasWildcards(cgn->name)) { - Lst exp; /* List of expansions */ - Lst path; /* Search path along which to expand */ - - /* - * Find a path along which to expand the word. - * - * If the word has a known suffix, use that path. - * If it has no known suffix and we're allowed to use the null - * suffix, use its path. - * Else use the default system search path. - */ - cp = cgn->name + strlen(cgn->name); - ln = Lst_Find(sufflist, (ClientData)cp, SuffSuffIsSuffixP); - - if (DEBUG(SUFF)) { - printf("Wildcard expanding \"%s\"...", cgn->name); - } - - if (ln != NILLNODE) { - Suff *s = (Suff *)Lst_Datum(ln); - - if (DEBUG(SUFF)) { - printf("suffix is \"%s\"...", s->name); - } - path = s->searchPath; - } else { - /* - * Use default search path - */ - path = dirSearchPath; - } - - /* - * Expand the word along the chosen path - */ - exp = Lst_Init(FALSE); - Dir_Expand(cgn->name, path, exp); - - while (!Lst_IsEmpty(exp)) { - /* - * Fetch next expansion off the list and find its GNode - */ - cp = (char *)Lst_DeQueue(exp); - - if (DEBUG(SUFF)) { - printf("%s...", cp); - } - gn = Targ_FindNode(cp, TARG_CREATE); - - /* - * If gn isn't already a child of the parent, make it so and - * up the parent's count of unmade children. - */ - if (Lst_Member(pgn->children, (ClientData)gn) == NILLNODE) { - (void)Lst_Append(pgn->children, prevLN, (ClientData)gn); - prevLN = Lst_Succ(prevLN); - (void)Lst_AtEnd(gn->parents, (ClientData)pgn); - pgn->unmade++; - } - } - - /* - * Nuke what's left of the list - */ - Lst_Destroy(exp, NOFREE); - - /* - * Now the source is expanded, remove it from the list of children to - * keep it from being processed. - */ - ln = Lst_Member(pgn->children, (ClientData)cgn); - pgn->unmade--; - Lst_Remove(pgn->children, ln); - if (DEBUG(SUFF)) { - printf("\n"); - } - } - - return(0); -} - -/*- - *----------------------------------------------------------------------- - * SuffApplyTransform -- - * Apply a transformation rule, given the source and target nodes - * and suffixes. - * - * 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(tGn, sGn, t, s) - GNode *tGn; /* Target node */ - GNode *sGn; /* Source node */ - Suff *t; /* Target suffix */ - Suff *s; /* Source suffix */ -{ - LstNode ln; /* General node */ - char *tname; /* Name of transformation rule */ - GNode *gn; /* Node for same */ - - if (Lst_Member(tGn->children, (ClientData)sGn) == NILLNODE) { - /* - * Not already linked, so form the proper links between the - * target and source. - */ - (void)Lst_AtEnd(tGn->children, (ClientData)sGn); - (void)Lst_AtEnd(sGn->parents, (ClientData)tGn); - tGn->unmade += 1; - } - - if ((sGn->type & OP_OPMASK) == OP_DOUBLEDEP) { - /* - * When a :: node is used as the implied source of a node, we have - * to link all its cohorts in as sources as well. Only the initial - * sGn gets the target in its iParents list, however, as that - * will be sufficient to get the .IMPSRC variable set for tGn - */ - for (ln=Lst_First(sGn->cohorts); ln != NILLNODE; ln=Lst_Succ(ln)) { - gn = (GNode *)Lst_Datum(ln); - - if (Lst_Member(tGn->children, (ClientData)gn) == NILLNODE) { - /* - * Not already linked, so form the proper links between the - * target and source. - */ - (void)Lst_AtEnd(tGn->children, (ClientData)gn); - (void)Lst_AtEnd(gn->parents, (ClientData)tGn); - tGn->unmade += 1; - } - } - } - /* - * Locate the transformation rule itself - */ - tname = str_concat(s->name, t->name, 0); - ln = Lst_Find(transforms, (ClientData)tname, SuffGNHasNameP); - free(tname); - - if (ln == NILLNODE) { - /* - * 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)) { - printf("\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 - */ - ln = Lst_Succ(ln); - if (ln != NILLNODE) { - Lst_ForEachFrom(tGn->children, ln, - SuffExpandChildren, (ClientData)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, (ClientData)tGn); - - return(TRUE); -} - - -/*- - *----------------------------------------------------------------------- - * SuffFindArchiveDeps -- - * Locate dependencies for an OP_ARCHV node. - * - * Results: - * None - * - * Side Effects: - * Same as Suff_FindDeps - * - *----------------------------------------------------------------------- - */ -static void -SuffFindArchiveDeps(gn, slst) - GNode *gn; /* Node for which to locate dependencies */ - Lst slst; -{ - char *eoarch; /* End of archive portion */ - char *eoname; /* End of member portion */ - GNode *mem; /* Node for member */ - static char *copy[] = { /* Variables to be copied from the member node */ - TARGET, /* Must be first */ - PREFIX, /* Must be second */ - }; - 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, ')'); - - *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 - */ - if (Lst_Member(gn->children, (ClientData)mem) == NILLNODE) { - (void)Lst_AtEnd(gn->children, (ClientData)mem); - (void)Lst_AtEnd(mem->parents, (ClientData)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); - if (p1) - 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)) { - printf("using null suffix\n"); - } - ms = suffNull; - } - - - /* - * Set the other two local variables required for this target. - */ - Var_Set (MEMBER, name, gn); - Var_Set (ARCHIVE, gn->name, 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... - */ - LstNode ln; - - /* - * Use first matching suffix... - */ - ln = Lst_Find(ms->parents, eoarch, SuffSuffIsSuffixP); - - if (ln != NILLNODE) { - /* - * Got one -- apply it - */ - if (!SuffApplyTransform(gn, mem, (Suff *)Lst_Datum(ln), ms) && - DEBUG(SUFF)) - { - printf("\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. - */ - mem->type |= OP_MEMBER; -} - -/*- - *----------------------------------------------------------------------- - * SuffFindNormalDeps -- - * Locate implicit dependencies for regular targets. - * - * Results: - * None. - * - * Side Effects: - * Same as Suff_FindDeps... - * - *----------------------------------------------------------------------- - */ -static void -SuffFindNormalDeps(gn, slst) - GNode *gn; /* Node for which to find sources */ - Lst slst; -{ - char *eoname; /* End of name */ - char *sopref; /* Start of prefix */ - LstNode ln; /* 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 */ - - - eoname = gn->name + strlen(gn->name); - - 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. - */ - while(ln != NILLNODE) { - /* - * Look for next possible suffix... - */ - ln = Lst_FindFrom(sufflist, ln, eoname, SuffSuffIsSuffixP); - - if (ln != NILLNODE) { - int prefLen; /* Length of the prefix */ - Src *targ; - - /* - * Allocate a Src structure to which things can be transformed - */ - targ = (Src *)emalloc(sizeof (Src)); - targ->file = strdup(gn->name); - targ->suff = (Suff *)Lst_Datum(ln); - targ->suff->refCount++; - targ->node = gn; - targ->parent = (Src *)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 = emalloc(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, (ClientData)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)) { - printf("\tNo known suffix on %s. Using .NULL suffix: ", gn->name); - } - - targ = (Src *)emalloc(sizeof (Src)); - targ->file = strdup(gn->name); - targ->suff = suffNull; - targ->suff->refCount++; - targ->node = gn; - targ->parent = (Src *)NULL; - targ->children = 0; - targ->pref = strdup(sopref); -#ifdef DEBUG_SRC - targ->cp = Lst_Init(FALSE); -#endif - - /* - * Only use the default suffix rules if we don't have commands - * or dependencies defined for this gnode - */ - if (Lst_IsEmpty(gn->commands) && Lst_IsEmpty(gn->children)) - SuffAddLevel(srcs, targ); - else { - if (DEBUG(SUFF)) - printf("not "); - } - - if (DEBUG(SUFF)) - printf("adding suffix rules\n"); - - (void)Lst_AtEnd(targs, (ClientData)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 == (Src *)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 = (Src *)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; - } - - /* - * The .TARGET variable we always set to be the name at this point, - * since it's only set to the path if the thing is only a source and - * if it's only a source, it doesn't matter what we put here as far - * as expanding sources is concerned, since it has none... - */ - Var_Set(TARGET, gn->name, gn); - - pref = (targ != NULL) ? targ->pref : gn->name; - Var_Set(PREFIX, pref, gn); - - /* - * Now we've got the important local variables set, expand any sources - * that still contain variables or wildcards in their names. - */ - Lst_ForEach(gn->children, SuffExpandChildren, (ClientData)gn); - - if (targ == NULL) { - if (DEBUG(SUFF)) { - printf("\tNo valid suffix on %s\n", gn->name); - } - -sfnd_abort: - /* - * Deal with finding the thing on the default search path if the - * node is only a source (not on the lhs of a dependency operator - * or [XXX] it has neither children or commands). - */ - if (OP_NOP(gn->type) || - (Lst_IsEmpty(gn->children) && Lst_IsEmpty(gn->commands))) - { - gn->path = Dir_FindFile(gn->name, - (targ == NULL ? dirSearchPath : - targ->suff->searchPath)); - if (gn->path != NULL) { - Var_Set(TARGET, gn->path, gn); - - if (targ != NULL) { - /* - * Suffix known for the thing -- trim the suffix off - * the path to form the proper .PREFIX variable. - */ - int len = strlen(gn->path); - char savec; - - if (gn->suffix) - gn->suffix->refCount--; - gn->suffix = targ->suff; - gn->suffix->refCount++; - - savec = gn->path[len-targ->suff->nameLen]; - gn->path[len-targ->suff->nameLen] = '\0'; - - Var_Set(PREFIX, gn->path, gn); - - gn->path[len-targ->suff->nameLen] = savec; - } else { - /* - * The .PREFIX gets the full path if the target has - * no known suffix. - */ - if (gn->suffix) - gn->suffix->refCount--; - gn->suffix = NULL; - - Var_Set(PREFIX, gn->path, gn); - } - } - } else { - /* - * Not appropriate to search for the thing -- set the - * path to be the name so Dir_MTime won't go grovelling for - * it. - */ - if (gn->suffix) - gn->suffix->refCount--; - gn->suffix = (targ == NULL) ? NULL : targ->suff; - if (gn->suffix) - gn->suffix->refCount++; - if (gn->path != NULL) - free(gn->path); - gn->path = strdup(gn->name); - } - - 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 != (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, (ClientData) bottom) == NILLNODE) { - Lst_AtEnd(slst, (ClientData) 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 == NILGNODE) { - bottom->node = Targ_FindNode(bottom->file, TARG_CREATE); - } - - for (src = bottom; src->parent != (Src *)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 == NILGNODE) { - 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); - - Var_Set(TARGET, targ->node->name, targ->node); - } - } - - if (gn->suffix) - gn->suffix->refCount--; - gn->suffix = src->suff; - gn->suffix->refCount++; - - /* - * So Dir_MTime doesn't go questing for it... - */ - if (gn->path) - free(gn->path); - gn->path = strdup(gn->name); - - /* - * Nuke the transformation path and the Src structures left over in the - * two lists. - */ -sfnd_return: - if (bottom) - if (Lst_Member(slst, (ClientData) bottom) == NILLNODE) - Lst_AtEnd(slst, (ClientData) 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(gn) - GNode *gn; -{ - - SuffFindDeps(gn, srclist); - while (SuffRemoveSrc(srclist)) - continue; -} - - -static void -SuffFindDeps (gn, slst) - GNode *gn; /* node we're dealing with */ - 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; - } - - if (DEBUG(SUFF)) { - printf ("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, (ClientData)LIBSUFF, SuffSuffHasNameP); - if (gn->suffix) - gn->suffix->refCount--; - if (ln != NILLNODE) { - 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); - } - /* - * 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); - } else { - SuffFindNormalDeps(gn, slst); - } -} - -/*- - *----------------------------------------------------------------------- - * Suff_SetNull -- - * Define which suffix is the 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(name) - char *name; /* Name of null suffix */ -{ - Suff *s; - LstNode ln; - - ln = Lst_Find(sufflist, (ClientData)name, SuffSuffHasNameP); - if (ln != NILLNODE) { - s = (Suff *)Lst_Datum(ln); - if (suffNull != (Suff *)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 () -{ - sufflist = Lst_Init (FALSE); - suffClean = Lst_Init(FALSE); - srclist = Lst_Init (FALSE); - transforms = Lst_Init (FALSE); - - sNum = 0; - /* - * 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. - */ - emptySuff = suffNull = (Suff *) emalloc (sizeof (Suff)); - - suffNull->name = 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; - -} - - -/*- - *---------------------------------------------------------------------- - * Suff_End -- - * Cleanup the this module - * - * Results: - * None - * - * Side Effects: - * The memory is free'd. - *---------------------------------------------------------------------- - */ - -void -Suff_End() -{ - Lst_Destroy(sufflist, SuffFree); - Lst_Destroy(suffClean, SuffFree); - if (suffNull) - SuffFree(suffNull); - Lst_Destroy(srclist, NOFREE); - Lst_Destroy(transforms, NOFREE); -} - - -/********************* DEBUGGING FUNCTIONS **********************/ - -static int SuffPrintName(s, dummy) - ClientData s; - ClientData dummy; -{ - printf ("%s ", ((Suff *) s)->name); - return (dummy ? 0 : 0); -} - -static int -SuffPrintSuff (sp, dummy) - ClientData sp; - ClientData dummy; -{ - Suff *s = (Suff *) sp; - int flags; - int flag; - - printf ("# `%s' [%d] ", s->name, s->refCount); - - flags = s->flags; - if (flags) { - fputs (" (", stdout); - while (flags) { - flag = 1 << (ffs(flags) - 1); - flags &= ~flag; - switch (flag) { - case SUFF_NULL: - printf ("NULL"); - break; - case SUFF_INCLUDE: - printf ("INCLUDE"); - break; - case SUFF_LIBRARY: - printf ("LIBRARY"); - break; - } - fputc(flags ? '|' : ')', stdout); - } - } - fputc ('\n', stdout); - printf ("#\tTo: "); - Lst_ForEach (s->parents, SuffPrintName, (ClientData)0); - fputc ('\n', stdout); - printf ("#\tFrom: "); - Lst_ForEach (s->children, SuffPrintName, (ClientData)0); - fputc ('\n', stdout); - printf ("#\tSearch Path: "); - Dir_PrintPath (s->searchPath); - fputc ('\n', stdout); - return (dummy ? 0 : 0); -} - -static int -SuffPrintTrans (tp, dummy) - ClientData tp; - ClientData dummy; -{ - GNode *t = (GNode *) tp; - - printf ("%-16s: ", t->name); - Targ_PrintType (t->type); - fputc ('\n', stdout); - Lst_ForEach (t->commands, Targ_PrintCmd, (ClientData)0); - fputc ('\n', stdout); - return(dummy ? 0 : 0); -} - -void -Suff_PrintAll() -{ - printf ("#*** Suffixes:\n"); - Lst_ForEach (sufflist, SuffPrintSuff, (ClientData)0); - - printf ("#*** Transformations:\n"); - Lst_ForEach (transforms, SuffPrintTrans, (ClientData)0); -} diff --git a/usr.bin/make/targ.c b/usr.bin/make/targ.c deleted file mode 100644 index 49aedbd5d2186..0000000000000 --- a/usr.bin/make/targ.c +++ /dev/null @@ -1,657 +0,0 @@ -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * 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 lint -static char sccsid[] = "@(#)targ.c 8.3 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * 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_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. - * - * 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 */ -static Lst allGNs; /* List of all the GNodes */ -static Hash_Table targets; /* a hash table of same */ - -#define HTSIZE 191 /* initial size of hash table */ - -static int TargPrintOnlySrc __P((ClientData, ClientData)); -static int TargPrintName __P((ClientData, ClientData)); -static int TargPrintNode __P((ClientData, ClientData)); -static void TargFreeGN __P((ClientData)); - -/*- - *----------------------------------------------------------------------- - * Targ_Init -- - * Initialize this module - * - * Results: - * None - * - * Side Effects: - * The allTargets list and the targets hash table are initialized - *----------------------------------------------------------------------- - */ -void -Targ_Init () -{ - 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 () -{ - Lst_Destroy(allTargets, NOFREE); - if (allGNs) - Lst_Destroy(allGNs, TargFreeGN); - Hash_DeleteTable(&targets); -} - -/*- - *----------------------------------------------------------------------- - * Targ_NewGN -- - * Create and initialize a new graph 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 (name) - char *name; /* the name to stick in the new node */ -{ - register GNode *gn; - - gn = (GNode *) emalloc (sizeof (GNode)); - gn->name = strdup (name); - gn->path = (char *) 0; - if (name[0] == '-' && name[1] == 'l') { - gn->type = OP_LIB; - } else { - gn->type = 0; - } - gn->unmade = 0; - gn->make = FALSE; - gn->made = UNMADE; - gn->childMade = FALSE; - gn->mtime = gn->cmtime = 0; - gn->iParents = Lst_Init (FALSE); - gn->cohorts = Lst_Init (FALSE); - gn->parents = Lst_Init (FALSE); - gn->children = Lst_Init (FALSE); - gn->successors = Lst_Init (FALSE); - gn->preds = Lst_Init (FALSE); - gn->context = Lst_Init (FALSE); - gn->commands = Lst_Init (FALSE); - gn->suffix = NULL; - - if (allGNs == NULL) - allGNs = Lst_Init(FALSE); - Lst_AtEnd(allGNs, (ClientData) gn); - - return (gn); -} - -/*- - *----------------------------------------------------------------------- - * TargFreeGN -- - * Destroy a GNode - * - * Results: - * None. - * - * Side Effects: - * None. - *----------------------------------------------------------------------- - */ -static void -TargFreeGN (gnp) - ClientData gnp; -{ - GNode *gn = (GNode *) gnp; - - - free(gn->name); - if (gn->path) - free(gn->path); - - Lst_Destroy(gn->iParents, NOFREE); - Lst_Destroy(gn->cohorts, NOFREE); - Lst_Destroy(gn->parents, NOFREE); - Lst_Destroy(gn->children, NOFREE); - Lst_Destroy(gn->successors, NOFREE); - Lst_Destroy(gn->preds, NOFREE); - Lst_Destroy(gn->context, NOFREE); - Lst_Destroy(gn->commands, NOFREE); - free((Address)gn); -} - - -/*- - *----------------------------------------------------------------------- - * Targ_FindNode -- - * Find a node in the list using the given name for matching - * - * Results: - * The node in the list if it was. If it wasn't, return NILGNODE 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 (name, flags) - char *name; /* the name to find */ - int flags; /* flags governing events when target not - * found */ -{ - GNode *gn; /* node in that element */ - Hash_Entry *he; /* 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) { - he = Hash_CreateEntry (&targets, name, &isNew); - if (isNew) { - gn = Targ_NewGN (name); - Hash_SetValue (he, gn); - (void) Lst_AtEnd (allTargets, (ClientData)gn); - } - } else { - he = Hash_FindEntry (&targets, name); - } - - if (he == (Hash_Entry *) NULL) { - return (NILGNODE); - } else { - return ((GNode *) Hash_GetValue (he)); - } -} - -/*- - *----------------------------------------------------------------------- - * Targ_FindList -- - * Make a complete list of GNodes from the given list of names - * - * 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 (names, flags) - Lst names; /* list of names to find */ - int flags; /* flags used if no node is found for a given - * name */ -{ - Lst nodes; /* result list */ - register LstNode ln; /* name list element */ - register GNode *gn; /* node in tLn */ - char *name; - - nodes = Lst_Init (FALSE); - - if (Lst_Open (names) == FAILURE) { - return (nodes); - } - while ((ln = Lst_Next (names)) != NILLNODE) { - name = (char *)Lst_Datum(ln); - gn = Targ_FindNode (name, flags); - if (gn != NILGNODE) { - /* - * 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, (ClientData)gn); - if (gn->type & OP_DOUBLEDEP) { - (void)Lst_Concat (nodes, gn->cohorts, LST_CONCNEW); - } - } 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 - * - * Results: - * TRUE if should ignore errors - * - * Side Effects: - * None - *----------------------------------------------------------------------- - */ -Boolean -Targ_Ignore (gn) - GNode *gn; /* node to check for */ -{ - if (ignoreErrors || gn->type & OP_IGNORE) { - return (TRUE); - } else { - return (FALSE); - } -} - -/*- - *----------------------------------------------------------------------- - * Targ_Silent -- - * Return true if be silent when creating gn - * - * Results: - * TRUE if should be silent - * - * Side Effects: - * None - *----------------------------------------------------------------------- - */ -Boolean -Targ_Silent (gn) - GNode *gn; /* node to check for */ -{ - if (beSilent || gn->type & OP_SILENT) { - return (TRUE); - } else { - return (FALSE); - } -} - -/*- - *----------------------------------------------------------------------- - * Targ_Precious -- - * See if the given target is precious - * - * Results: - * TRUE if it is precious. FALSE otherwise - * - * Side Effects: - * None - *----------------------------------------------------------------------- - */ -Boolean -Targ_Precious (gn) - GNode *gn; /* the node to check */ -{ - 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. - * - * Results: - * None. - * - * Side Effects: - * "mainTarg" is set to the main target's node. - *----------------------------------------------------------------------- - */ -void -Targ_SetMain (gn) - GNode *gn; /* The main target we'll create */ -{ - mainTarg = gn; -} - -static int -TargPrintName (gnp, ppath) - ClientData gnp; - ClientData ppath; -{ - GNode *gn = (GNode *) gnp; - printf ("%s ", gn->name); -#ifdef notdef - if (ppath) { - if (gn->path) { - printf ("[%s] ", gn->path); - } - if (gn == mainTarg) { - printf ("(MAIN NAME) "); - } - } -#endif /* notdef */ - return (ppath ? 0 : 0); -} - - -int -Targ_PrintCmd (cmd, dummy) - ClientData cmd; - ClientData dummy; -{ - printf ("\t%s\n", (char *) cmd); - return (dummy ? 0 : 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) - time_t time; -{ - struct tm *parts; - static char buf[40]; - static char *months[] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" - }; - - parts = localtime(&time); - - sprintf (buf, "%d:%02d:%02d %s %d, 19%d", - parts->tm_hour, parts->tm_min, parts->tm_sec, - months[parts->tm_mon], parts->tm_mday, parts->tm_year); - return(buf); -} - -/*- - *----------------------------------------------------------------------- - * Targ_PrintType -- - * Print out a type field giving only those attributes the user can - * set. - * - * Results: - * - * Side Effects: - * - *----------------------------------------------------------------------- - */ -void -Targ_PrintType (type) - register int type; -{ - register int tbit; - -#ifdef __STDC__ -#define PRINTBIT(attr) case CONCAT(OP_,attr): printf("." #attr " "); break -#define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf("." #attr " "); break -#else -#define PRINTBIT(attr) case CONCAT(OP_,attr): printf(".attr "); break -#define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf(".attr "); break -#endif /* __STDC__ */ - - 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)) printf(".MEMBER "); break; - PRINTDBIT(ARCHV); - } - } -} - -/*- - *----------------------------------------------------------------------- - * TargPrintNode -- - * print the contents of a node - *----------------------------------------------------------------------- - */ -static int -TargPrintNode (gnp, passp) - ClientData gnp; - ClientData passp; -{ - GNode *gn = (GNode *) gnp; - int pass = *(int *) passp; - if (!OP_NOP(gn->type)) { - printf("#\n"); - if (gn == mainTarg) { - printf("# *** MAIN TARGET ***\n"); - } - if (pass == 2) { - if (gn->unmade) { - printf("# %d unmade children\n", gn->unmade); - } else { - printf("# No unmade children\n"); - } - if (! (gn->type & (OP_JOIN|OP_USE|OP_EXEC))) { - if (gn->mtime != 0) { - printf("# last modified %s: %s\n", - Targ_FmtTime(gn->mtime), - (gn->made == UNMADE ? "unmade" : - (gn->made == MADE ? "made" : - (gn->made == UPTODATE ? "up-to-date" : - "error when made")))); - } else if (gn->made != UNMADE) { - printf("# non-existent (maybe): %s\n", - (gn->made == MADE ? "made" : - (gn->made == UPTODATE ? "up-to-date" : - (gn->made == ERROR ? "error when made" : - "aborted")))); - } else { - printf("# unmade\n"); - } - } - if (!Lst_IsEmpty (gn->iParents)) { - printf("# implicit parents: "); - Lst_ForEach (gn->iParents, TargPrintName, (ClientData)0); - fputc ('\n', stdout); - } - } - if (!Lst_IsEmpty (gn->parents)) { - printf("# parents: "); - Lst_ForEach (gn->parents, TargPrintName, (ClientData)0); - fputc ('\n', stdout); - } - - printf("%-16s", gn->name); - switch (gn->type & OP_OPMASK) { - case OP_DEPENDS: - printf(": "); break; - case OP_FORCE: - printf("! "); break; - case OP_DOUBLEDEP: - printf(":: "); break; - } - Targ_PrintType (gn->type); - Lst_ForEach (gn->children, TargPrintName, (ClientData)0); - fputc ('\n', stdout); - Lst_ForEach (gn->commands, Targ_PrintCmd, (ClientData)0); - printf("\n\n"); - if (gn->type & OP_DOUBLEDEP) { - Lst_ForEach (gn->cohorts, TargPrintNode, (ClientData)&pass); - } - } - return (0); -} - -/*- - *----------------------------------------------------------------------- - * TargPrintOnlySrc -- - * Print only those targets that are just a source. - * - * Results: - * 0. - * - * Side Effects: - * The name of each file is printed preceeded by #\t - * - *----------------------------------------------------------------------- - */ -static int -TargPrintOnlySrc(gnp, dummy) - ClientData gnp; - ClientData dummy; -{ - GNode *gn = (GNode *) gnp; - if (OP_NOP(gn->type)) - printf("#\t%s [%s]\n", gn->name, gn->path ? gn->path : gn->name); - - return (dummy ? 0 : 0); -} - -/*- - *----------------------------------------------------------------------- - * Targ_PrintGraph -- - * print the entire graph. heh heh - * - * Results: - * none - * - * Side Effects: - * lots o' output - *----------------------------------------------------------------------- - */ -void -Targ_PrintGraph (pass) - int pass; /* Which pass this is. 1 => no processing - * 2 => processing done */ -{ - printf("#*** Input graph:\n"); - Lst_ForEach (allTargets, TargPrintNode, (ClientData)&pass); - printf("\n\n"); - printf("#\n# Files that are only sources:\n"); - Lst_ForEach (allTargets, TargPrintOnlySrc, (ClientData) 0); - printf("#*** Global Variables:\n"); - Var_Dump (VAR_GLOBAL); - printf("#*** Command-line Variables:\n"); - Var_Dump (VAR_CMD); - printf("\n"); - Dir_PrintDirectories(); - printf("\n"); - Suff_PrintAll(); -} diff --git a/usr.bin/make/util.c b/usr.bin/make/util.c deleted file mode 100644 index 07eb6a47e55db..0000000000000 --- a/usr.bin/make/util.c +++ /dev/null @@ -1,351 +0,0 @@ -/* $NetBSD: util.c,v 1.7 1996/08/30 17:59:44 thorpej Exp $ */ - -/* - * Missing stuff from OS's - */ - -#ifndef lint -static char rcsid[] = "$NetBSD: util.c,v 1.7 1996/08/30 17:59:44 thorpej Exp $"; -#endif - -#include <stdio.h> -#include "make.h" - -#if !__STDC__ -# ifndef const -# define const -# endif -#endif - -#ifdef sun - - - -extern int errno, sys_nerr; -extern char *sys_errlist[]; - -char * -strerror(e) - int e; -{ - static char buf[100]; - if (e < 0 || e >= sys_nerr) { - sprintf(buf, "Unknown error %d", e); - return buf; - } - else - return sys_errlist[e]; -} -#endif - -#ifdef ultrix -#include <string.h> - -/* strdup - * - * Make a duplicate of a string. - * For systems which lack this function. - */ -char * -strdup(str) - const char *str; -{ - size_t len; - - if (str == NULL) - return NULL; - len = strlen(str) + 1; - if ((p = malloc(len)) == NULL) - return NULL; - - return memcpy(p, str, len); -} - -#endif - -#if defined(sun) || defined(__hpux) || defined(__sgi) - -int -setenv(name, value, dum) - const char *name; - const char *value; - int dum; -{ - register char *p; - int len = strlen(name) + strlen(value) + 2; /* = \0 */ - char *ptr = (char*) malloc(len); - - (void) dum; - - if (ptr == NULL) - return -1; - - p = ptr; - - while (*name) - *p++ = *name++; - - *p++ = '='; - - while (*value) - *p++ = *value++; - - *p = '\0'; - - len = putenv(ptr); -/* free(ptr); */ - return len; -} -#endif - -#ifdef __hpux -#include <sys/types.h> -#include <sys/param.h> -#include <sys/syscall.h> -#include <sys/signal.h> -#include <sys/stat.h> -#include <stdio.h> -#include <dirent.h> -#include <sys/time.h> -#include <time.h> -#include <unistd.h> - - -int -killpg(pid, sig) - int pid, sig; -{ - return kill(-pid, sig); -} - -void -srandom(seed) - long seed; -{ - srand48(seed); -} - -long -random() -{ - return lrand48(); -} - -/* turn into bsd signals */ -void (* -signal(s, a)) () - int s; - void (*a)(); -{ - struct sigvec osv, sv; - - (void) sigvector(s, (struct sigvec *) 0, &osv); - sv = osv; - sv.sv_handler = a; -#ifdef SV_BSDSIG - sv.sv_flags = SV_BSDSIG; -#endif - - if (sigvector(s, &sv, (struct sigvec *) 0) == -1) - return (BADSIG); - return (osv.sv_handler); -} - -#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]))) - - -/* strrcpy(): - * Like strcpy, going backwards and returning the new pointer - */ -static char * -strrcpy(ptr, str) - register char *ptr, *str; -{ - register int len = strlen(str); - - while (len) - *--ptr = str[--len]; - - return (ptr); -} /* end strrcpy */ - - -char * -getwd(pathname) - 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 */ - - -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 */ -}; - -int -utimes(file, tvp) - 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 /* __hpux */ - -#if defined(sun) && defined(__svr4__) -#include <signal.h> - -/* turn into bsd signals */ -void (* -signal(s, a)) () - int s; - void (*a)(); -{ - 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; -} - -#endif diff --git a/usr.bin/make/var.c b/usr.bin/make/var.c deleted file mode 100644 index 4d7b2e956878e..0000000000000 --- a/usr.bin/make/var.c +++ /dev/null @@ -1,2033 +0,0 @@ -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * 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 lint -static char sccsid[] = "@(#)var.c 8.4 (Berkeley) 4/28/95"; -#endif /* not lint */ - -/*- - * 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 <ctype.h> -#include "make.h" -#include "buf.h" - -/* - * 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 'err' flag for Var_Parse is - * set false. Why not just use a constant? Well, gcc likes to condense - * identical string instances... - */ -static char varNoError[] = ""; - -/* - * 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_GLOBAL; /* variables from the makefile */ -GNode *VAR_CMD; /* variables defined on the command-line */ - -static Lst allVars; /* List of all variables */ - -#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 */ -} Var; - -typedef struct { - char *lhs; /* String to match */ - int leftLen; /* Length of string */ - char *rhs; /* Replacement string (w/ &'s removed) */ - int rightLen; /* Length of replacement */ - int flags; -#define VAR_SUB_GLOBAL 1 /* Apply substitution globally */ -#define VAR_MATCH_START 2 /* Match at start of word */ -#define VAR_MATCH_END 4 /* Match at end of word */ -#define VAR_NO_SUB 8 /* Substitution is non-global and already done */ -} VarPattern; - -static int VarCmp __P((ClientData, ClientData)); -static Var *VarFind __P((char *, GNode *, int)); -static void VarAdd __P((char *, char *, GNode *)); -static void VarDelete __P((ClientData)); -static Boolean VarHead __P((char *, Boolean, Buffer, ClientData)); -static Boolean VarTail __P((char *, Boolean, Buffer, ClientData)); -static Boolean VarSuffix __P((char *, Boolean, Buffer, ClientData)); -static Boolean VarRoot __P((char *, Boolean, Buffer, ClientData)); -static Boolean VarMatch __P((char *, Boolean, Buffer, ClientData)); -static Boolean VarSYSVMatch __P((char *, Boolean, Buffer, ClientData)); -static Boolean VarNoMatch __P((char *, Boolean, Buffer, ClientData)); -static Boolean VarSubstitute __P((char *, Boolean, Buffer, ClientData)); -static char *VarModify __P((char *, Boolean (*)(char *, Boolean, Buffer, - ClientData), - ClientData)); -static int VarPrintVar __P((ClientData, ClientData)); - -/*- - *----------------------------------------------------------------------- - * VarCmp -- - * See if the given variable matches the named one. Called from - * Lst_Find when searching for a variable of a given name. - * - * Results: - * 0 if they match. non-zero otherwise. - * - * Side Effects: - * none - *----------------------------------------------------------------------- - */ -static int -VarCmp (v, name) - ClientData v; /* VAR structure to compare */ - ClientData name; /* name to look for */ -{ - return (strcmp ((char *) name, ((Var *) v)->name)); -} - -/*- - *----------------------------------------------------------------------- - * VarFind -- - * Find the given variable in the given context and any other contexts - * indicated. - * - * Results: - * A pointer to the structure describing the desired variable or - * NIL if the variable does not exist. - * - * Side Effects: - * None - *----------------------------------------------------------------------- - */ -static Var * -VarFind (name, ctxt, flags) - char *name; /* name to find */ - GNode *ctxt; /* context in which to find it */ - int 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 */ -{ - LstNode 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; - } - /* - * 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 = Lst_Find (ctxt->context, (ClientData)name, VarCmp); - - if ((var == NILLNODE) && (flags & FIND_CMD) && (ctxt != VAR_CMD)) { - var = Lst_Find (VAR_CMD->context, (ClientData)name, VarCmp); - } - if (!checkEnvFirst && (var == NILLNODE) && (flags & FIND_GLOBAL) && - (ctxt != VAR_GLOBAL)) - { - var = Lst_Find (VAR_GLOBAL->context, (ClientData)name, VarCmp); - } - if ((var == NILLNODE) && (flags & FIND_ENV)) { - char *env; - - if ((env = getenv (name)) != NULL) { - int len; - - v = (Var *) emalloc(sizeof(Var)); - v->name = strdup(name); - - len = strlen(env); - - v->val = Buf_Init(len); - Buf_AddBytes(v->val, len, (Byte *)env); - - v->flags = VAR_FROM_ENV; - return (v); - } else if (checkEnvFirst && (flags & FIND_GLOBAL) && - (ctxt != VAR_GLOBAL)) - { - var = Lst_Find (VAR_GLOBAL->context, (ClientData)name, VarCmp); - if (var == NILLNODE) { - return ((Var *) NIL); - } else { - return ((Var *)Lst_Datum(var)); - } - } else { - return((Var *)NIL); - } - } else if (var == NILLNODE) { - return ((Var *) NIL); - } else { - return ((Var *) Lst_Datum (var)); - } -} - -/*- - *----------------------------------------------------------------------- - * VarAdd -- - * Add a new variable of name name and value val to the given context - * - * 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 (name, val, ctxt) - char *name; /* name of variable to add */ - char *val; /* value to set it to */ - GNode *ctxt; /* context in which to set it */ -{ - register Var *v; - int len; - - v = (Var *) emalloc (sizeof (Var)); - - v->name = strdup (name); - - len = val ? strlen(val) : 0; - v->val = Buf_Init(len+1); - Buf_AddBytes(v->val, len, (Byte *)val); - - v->flags = 0; - - (void) Lst_AtFront (ctxt->context, (ClientData)v); - (void) Lst_AtEnd (allVars, (ClientData) v); - if (DEBUG(VAR)) { - printf("%s:%s = %s\n", ctxt->name, name, val); - } -} - - -/*- - *----------------------------------------------------------------------- - * VarDelete -- - * Delete a variable and all the space associated with it. - * - * Results: - * None - * - * Side Effects: - * None - *----------------------------------------------------------------------- - */ -static void -VarDelete(vp) - ClientData vp; -{ - Var *v = (Var *) vp; - free(v->name); - Buf_Destroy(v->val, TRUE); - free((Address) v); -} - - - -/*- - *----------------------------------------------------------------------- - * Var_Delete -- - * Remove a variable from a context. - * - * Results: - * None. - * - * Side Effects: - * The Var structure is removed and freed. - * - *----------------------------------------------------------------------- - */ -void -Var_Delete(name, ctxt) - char *name; - GNode *ctxt; -{ - LstNode ln; - - if (DEBUG(VAR)) { - printf("%s:delete %s\n", ctxt->name, name); - } - ln = Lst_Find(ctxt->context, (ClientData)name, VarCmp); - if (ln != NILLNODE) { - register Var *v; - - v = (Var *)Lst_Datum(ln); - Lst_Remove(ctxt->context, ln); - ln = Lst_Member(allVars, v); - Lst_Remove(allVars, ln); - VarDelete((ClientData) v); - } -} - -/*- - *----------------------------------------------------------------------- - * Var_Set -- - * Set the variable name to the value val in the given context. - * - * 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 $(<). - *----------------------------------------------------------------------- - */ -void -Var_Set (name, val, ctxt) - char *name; /* name of variable to set */ - char *val; /* value to give to the variable */ - GNode *ctxt; /* context in which to set it */ -{ - register Var *v; - - /* - * 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... - */ - v = VarFind (name, ctxt, 0); - if (v == (Var *) NIL) { - VarAdd (name, val, ctxt); - } else { - Buf_Discard(v->val, Buf_Size(v->val)); - Buf_AddBytes(v->val, strlen(val), (Byte *)val); - - if (DEBUG(VAR)) { - printf("%s:%s = %s\n", ctxt->name, name, val); - } - } - /* - * Any variables given on the command line are automatically exported - * to the environment (as per POSIX standard) - */ - if (ctxt == VAR_CMD) { - setenv(name, val, 1); - } -} - -/*- - *----------------------------------------------------------------------- - * Var_Append -- - * The variable of the given name has the given value appended to it in - * the given context. - * - * 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 (name, val, ctxt) - char *name; /* Name of variable to modify */ - char *val; /* String to append to it */ - GNode *ctxt; /* Context in which this should occur */ -{ - register Var *v; - - v = VarFind (name, ctxt, (ctxt == VAR_GLOBAL) ? FIND_ENV : 0); - - if (v == (Var *) NIL) { - VarAdd (name, val, ctxt); - } else { - Buf_AddByte(v->val, (Byte)' '); - Buf_AddBytes(v->val, strlen(val), (Byte *)val); - - if (DEBUG(VAR)) { - printf("%s:%s = %s\n", ctxt->name, name, - (char *) Buf_GetAll(v->val, (int *)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; - Lst_AtFront(ctxt->context, (ClientData)v); - } - } -} - -/*- - *----------------------------------------------------------------------- - * Var_Exists -- - * See if the given variable exists. - * - * Results: - * TRUE if it does, FALSE if it doesn't - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ -Boolean -Var_Exists(name, ctxt) - char *name; /* Variable to find */ - GNode *ctxt; /* Context in which to start search */ -{ - Var *v; - - v = VarFind(name, ctxt, FIND_CMD|FIND_GLOBAL|FIND_ENV); - - if (v == (Var *)NIL) { - return(FALSE); - } else if (v->flags & VAR_FROM_ENV) { - free(v->name); - Buf_Destroy(v->val, TRUE); - free((char *)v); - } - return(TRUE); -} - -/*- - *----------------------------------------------------------------------- - * Var_Value -- - * Return the value of the named variable in the given context - * - * Results: - * The value if the variable exists, NULL if it doesn't - * - * Side Effects: - * None - *----------------------------------------------------------------------- - */ -char * -Var_Value (name, ctxt, frp) - char *name; /* name to find */ - GNode *ctxt; /* context in which to search for it */ - char **frp; -{ - Var *v; - - v = VarFind (name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); - *frp = NULL; - if (v != (Var *) NIL) { - char *p = ((char *)Buf_GetAll(v->val, (int *)NULL)); - if (v->flags & VAR_FROM_ENV) { - Buf_Destroy(v->val, FALSE); - free((Address) v); - *frp = p; - } - return p; - } else { - return ((char *) NULL); - } -} - -/*- - *----------------------------------------------------------------------- - * VarHead -- - * Remove the tail of the given word and place the result in the given - * buffer. - * - * 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 (word, addSpace, buf, dummy) - char *word; /* Word to trim */ - Boolean addSpace; /* True if need to add a space to the buffer - * before sticking in the head */ - Buffer buf; /* Buffer in which to store it */ - ClientData dummy; -{ - register char *slash; - - slash = strrchr (word, '/'); - if (slash != (char *)NULL) { - if (addSpace) { - Buf_AddByte (buf, (Byte)' '); - } - *slash = '\0'; - Buf_AddBytes (buf, strlen (word), (Byte *)word); - *slash = '/'; - return (TRUE); - } else { - /* - * If no directory part, give . (q.v. the POSIX standard) - */ - if (addSpace) { - Buf_AddBytes(buf, 2, (Byte *)" ."); - } else { - Buf_AddByte(buf, (Byte)'.'); - } - } - return(dummy ? TRUE : TRUE); -} - -/*- - *----------------------------------------------------------------------- - * VarTail -- - * Remove the head of the given word and place the result in the given - * buffer. - * - * 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 (word, addSpace, buf, dummy) - char *word; /* Word to trim */ - Boolean addSpace; /* TRUE if need to stick a space in the - * buffer before adding the tail */ - Buffer buf; /* Buffer in which to store it */ - ClientData dummy; -{ - register char *slash; - - if (addSpace) { - Buf_AddByte (buf, (Byte)' '); - } - - slash = strrchr (word, '/'); - if (slash != (char *)NULL) { - *slash++ = '\0'; - Buf_AddBytes (buf, strlen(slash), (Byte *)slash); - slash[-1] = '/'; - } else { - Buf_AddBytes (buf, strlen(word), (Byte *)word); - } - return (dummy ? TRUE : TRUE); -} - -/*- - *----------------------------------------------------------------------- - * VarSuffix -- - * Place the suffix of the given word in the given buffer. - * - * 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 (word, addSpace, buf, dummy) - char *word; /* Word to trim */ - Boolean addSpace; /* TRUE if need to add a space before placing - * the suffix in the buffer */ - Buffer buf; /* Buffer in which to store it */ - ClientData dummy; -{ - register char *dot; - - dot = strrchr (word, '.'); - if (dot != (char *)NULL) { - if (addSpace) { - Buf_AddByte (buf, (Byte)' '); - } - *dot++ = '\0'; - Buf_AddBytes (buf, strlen (dot), (Byte *)dot); - dot[-1] = '.'; - addSpace = TRUE; - } - return (dummy ? addSpace : addSpace); -} - -/*- - *----------------------------------------------------------------------- - * VarRoot -- - * Remove the suffix of the given word and place the result in the - * buffer. - * - * 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 (word, addSpace, buf, dummy) - char *word; /* Word to trim */ - Boolean addSpace; /* TRUE if need to add a space to the buffer - * before placing the root in it */ - Buffer buf; /* Buffer in which to store it */ - ClientData dummy; -{ - register char *dot; - - if (addSpace) { - Buf_AddByte (buf, (Byte)' '); - } - - dot = strrchr (word, '.'); - if (dot != (char *)NULL) { - *dot = '\0'; - Buf_AddBytes (buf, strlen (word), (Byte *)word); - *dot = '.'; - } else { - Buf_AddBytes (buf, strlen(word), (Byte *)word); - } - return (dummy ? TRUE : TRUE); -} - -/*- - *----------------------------------------------------------------------- - * VarMatch -- - * Place the word in the buffer if it matches the given pattern. - * Callback function for VarModify to implement the :M modifier. - * - * 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 (word, addSpace, buf, pattern) - char *word; /* Word to examine */ - Boolean addSpace; /* TRUE if need to add a space to the - * buffer before adding the word, if it - * matches */ - Buffer buf; /* Buffer in which to store it */ - ClientData pattern; /* Pattern the word must match */ -{ - if (Str_Match(word, (char *) pattern)) { - if (addSpace) { - Buf_AddByte(buf, (Byte)' '); - } - addSpace = TRUE; - Buf_AddBytes(buf, strlen(word), (Byte *)word); - } - return(addSpace); -} - - - -/*- - *----------------------------------------------------------------------- - * VarSYSVMatch -- - * Place the word in the buffer if it matches the given pattern. - * Callback function for VarModify to implement the System V % - * modifiers. - * - * 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 (word, addSpace, buf, patp) - char *word; /* Word to examine */ - Boolean addSpace; /* TRUE if need to add a space to the - * buffer before adding the word, if it - * matches */ - Buffer buf; /* Buffer in which to store it */ - ClientData patp; /* Pattern the word must match */ -{ - int len; - char *ptr; - VarPattern *pat = (VarPattern *) patp; - - if (addSpace) - Buf_AddByte(buf, (Byte)' '); - - addSpace = TRUE; - - if ((ptr = Str_SYSVMatch(word, pat->lhs, &len)) != NULL) - Str_SYSVSubst(buf, pat->rhs, ptr, len); - else - Buf_AddBytes(buf, strlen(word), (Byte *) word); - - return(addSpace); -} - - -/*- - *----------------------------------------------------------------------- - * VarNoMatch -- - * Place the word in the buffer if it doesn't match the given pattern. - * Callback function for VarModify to implement the :N modifier. - * - * 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 (word, addSpace, buf, pattern) - char *word; /* Word to examine */ - Boolean addSpace; /* TRUE if need to add a space to the - * buffer before adding the word, if it - * matches */ - Buffer buf; /* Buffer in which to store it */ - ClientData pattern; /* Pattern the word must match */ -{ - if (!Str_Match(word, (char *) pattern)) { - if (addSpace) { - Buf_AddByte(buf, (Byte)' '); - } - addSpace = TRUE; - Buf_AddBytes(buf, strlen(word), (Byte *)word); - } - return(addSpace); -} - - -/*- - *----------------------------------------------------------------------- - * VarSubstitute -- - * Perform a string-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 -VarSubstitute (word, addSpace, buf, patternp) - char *word; /* Word to modify */ - Boolean addSpace; /* True if space should be added before - * other characters */ - Buffer buf; /* Buffer for result */ - ClientData patternp; /* Pattern for substitution */ -{ - register int wordLen; /* Length of word */ - register char *cp; /* General pointer */ - VarPattern *pattern = (VarPattern *) patternp; - - wordLen = strlen(word); - if ((pattern->flags & VAR_NO_SUB) == 0) { - /* - * 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) { - Buf_AddByte(buf, (Byte)' '); - } - addSpace = TRUE; - Buf_AddBytes(buf, pattern->rightLen, - (Byte *)pattern->rhs); - } - } 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) { - Buf_AddByte(buf, (Byte)' '); - } - addSpace = TRUE; - } - Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs); - Buf_AddBytes(buf, wordLen - pattern->leftLen, - (Byte *)(word + pattern->leftLen)); - } - } 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) { - Buf_AddByte(buf, (Byte)' '); - } - addSpace = TRUE; - } - Buf_AddBytes(buf, cp - word, (Byte *)word); - Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs); - } 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 - * subsititutions 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. - */ - register Boolean done; - int origSize; - - done = FALSE; - origSize = Buf_Size(buf); - while (!done) { - cp = Str_FindSubstring(word, pattern->lhs); - if (cp != (char *)NULL) { - if (addSpace && (((cp - word) + pattern->rightLen) != 0)){ - Buf_AddByte(buf, (Byte)' '); - addSpace = FALSE; - } - Buf_AddBytes(buf, cp-word, (Byte *)word); - Buf_AddBytes(buf, pattern->rightLen, (Byte *)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_NO_SUB; - } - } else { - done = TRUE; - } - } - if (wordLen != 0) { - if (addSpace) { - Buf_AddByte(buf, (Byte)' '); - } - Buf_AddBytes(buf, wordLen, (Byte *)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); - } - /* - * Common code for anchored substitutions: if performed a substitution - * and it's not supposed to be global, mark the pattern as requiring - * no more substitutions. addSpace was set TRUE if characters were - * added to the buffer. - */ - if ((pattern->flags & VAR_SUB_GLOBAL) == 0) { - pattern->flags |= VAR_NO_SUB; - } - return (addSpace); - } - nosub: - if (addSpace) { - Buf_AddByte(buf, (Byte)' '); - } - Buf_AddBytes(buf, wordLen, (Byte *)word); - return(TRUE); -} - -/*- - *----------------------------------------------------------------------- - * VarModify -- - * Modify each of the words of the passed string using the given - * function. Used to implement all modifiers. - * - * Results: - * A string of all the words modified appropriately. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ -static char * -VarModify (str, modProc, datum) - char *str; /* String whose words should be trimmed */ - /* Function to use to modify them */ - Boolean (*modProc) __P((char *, Boolean, Buffer, ClientData)); - ClientData datum; /* Datum to pass it */ -{ - 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 [first word does not count] */ - int ac, i; - - buf = Buf_Init (0); - addSpace = FALSE; - - av = brk_string(str, &ac, FALSE); - - for (i = 1; i < ac; i++) - addSpace = (*modProc)(av[i], addSpace, buf, datum); - - Buf_AddByte (buf, '\0'); - str = (char *)Buf_GetAll (buf, (int *)NULL); - Buf_Destroy (buf, FALSE); - return (str); -} - -/*- - *----------------------------------------------------------------------- - * Var_Parse -- - * Given the start of a variable invocation, extract the variable - * name and find its value, then modify it according to the - * specification. - * - * 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...?). - * A Boolean in *freePtr telling whether the returned string should - * be freed by the caller. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ -char * -Var_Parse (str, ctxt, err, lengthPtr, freePtr) - char *str; /* The string to parse */ - GNode *ctxt; /* The context for the variable */ - Boolean err; /* TRUE if undefined variables are an error */ - int *lengthPtr; /* OUT: The length of the specification */ - Boolean *freePtr; /* OUT: TRUE if caller should free result */ -{ - register char *tstr; /* Pointer into str */ - Var *v; /* Variable in invocation */ - register char *cp; /* Secondary pointer into str (place marker - * for tstr) */ - Boolean haveModifier;/* TRUE if have modifiers for the variable */ - register char endc; /* Ending character when variable in parens - * or braces */ - register char startc; /* Starting character when variable in parens - * or braces */ - int cnt; /* Used to count brace pairs when variable in - * in parens or braces */ - char *start; - 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 */ - - *freePtr = FALSE; - dynamic = FALSE; - start = str; - - if (str[1] != '(' && str[1] != '{') { - /* - * 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. - */ - char name[2]; - - name[0] = str[1]; - name[1] = '\0'; - - v = VarFind (name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); - if (v == (Var *)NIL) { - *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("$(.TARGET)"); - case '%': - return("$(.ARCHIVE)"); - case '*': - return("$(.PREFIX)"); - case '!': - return("$(.MEMBER)"); - } - } - /* - * Error - */ - return (err ? var_Error : varNoError); - } else { - haveModifier = FALSE; - tstr = &str[1]; - endc = str[1]; - } - } else { - startc = str[1]; - endc = startc == '(' ? ')' : '}'; - - /* - * Skip to the end character or a colon, whichever comes first. - */ - for (tstr = str + 2; - *tstr != '\0' && *tstr != endc && *tstr != ':'; - tstr++) - { - continue; - } - if (*tstr == ':') { - haveModifier = TRUE; - } else if (*tstr != '\0') { - 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; - return (var_Error); - } - *tstr = '\0'; - - v = VarFind (str + 2, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); - if ((v == (Var *)NIL) && (ctxt != VAR_CMD) && (ctxt != VAR_GLOBAL) && - ((tstr-str) == 4) && (str[3] == 'F' || str[3] == 'D')) - { - /* - * Check for bogus D and F forms of local variables since we're - * in a local context and the name is the right length. - */ - switch(str[2]) { - case '@': - case '%': - case '*': - case '!': - case '>': - case '<': - { - char vname[2]; - char *val; - - /* - * Well, it's local -- go look for it. - */ - vname[0] = str[2]; - vname[1] = '\0'; - v = VarFind(vname, ctxt, 0); - - if (v != (Var *)NIL) { - /* - * No need for nested expansion or anything, as we're - * the only one who sets these things and we sure don't - * but nested invocations in them... - */ - val = (char *)Buf_GetAll(v->val, (int *)NULL); - - if (str[3] == 'D') { - val = VarModify(val, VarHead, (ClientData)0); - } else { - val = VarModify(val, VarTail, (ClientData)0); - } - /* - * Resulting string is dynamically allocated, so - * tell caller to free it. - */ - *freePtr = TRUE; - *lengthPtr = tstr-start+1; - *tstr = endc; - return(val); - } - break; - } - } - } - - if (v == (Var *)NIL) { - if ((((tstr-str) == 3) || - ((((tstr-str) == 4) && (str[3] == 'F' || - str[3] == '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[2]) { - case '@': - case '%': - case '*': - case '!': - dynamic = TRUE; - break; - } - } else if (((tstr-str) > 4) && (str[2] == '.') && - isupper((unsigned char) str[3]) && - ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL))) - { - int len; - - len = (tstr-str) - 3; - if ((strncmp(str+2, ".TARGET", len) == 0) || - (strncmp(str+2, ".ARCHIVE", len) == 0) || - (strncmp(str+2, ".PREFIX", len) == 0) || - (strncmp(str+2, ".MEMBER", len) == 0)) - { - dynamic = TRUE; - } - } - - if (!haveModifier) { - /* - * No modifiers -- have specification length so we can return - * now. - */ - *lengthPtr = tstr - start + 1; - *tstr = endc; - if (dynamic) { - str = emalloc(*lengthPtr + 1); - strncpy(str, start, *lengthPtr); - str[*lengthPtr] = '\0'; - *freePtr = TRUE; - return(str); - } else { - return (err ? 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 = (Var *) emalloc(sizeof(Var)); - v->name = &str[1]; - v->val = Buf_Init(1); - v->flags = VAR_JUNK; - } - } - } - - 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. - */ - str = (char *)Buf_GetAll(v->val, (int *)NULL); - if (strchr (str, '$') != (char *)NULL) { - str = Var_Subst(NULL, str, ctxt, err); - *freePtr = TRUE; - } - - v->flags &= ~VAR_IN_USE; - - /* - * 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. - * :S<d><pat1><d><pat2><d>[g] - * Substitute <pat2> for <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). - * :lhs=rhs Like :S, but the rhs goes to the end of - * the invocation. - */ - if ((str != (char *)NULL) && haveModifier) { - /* - * Skip initial colon while putting it back. - */ - *tstr++ = ':'; - while (*tstr != endc) { - char *newStr; /* New value to return */ - char termc; /* Character which terminated scan */ - - if (DEBUG(VAR)) { - printf("Applying :%c to \"%s\"\n", *tstr, str); - } - switch (*tstr) { - case 'N': - case 'M': - { - char *pattern; - char *cp2; - Boolean copy; - - copy = FALSE; - for (cp = tstr + 1; - *cp != '\0' && *cp != ':' && *cp != endc; - cp++) - { - if (*cp == '\\' && (cp[1] == ':' || cp[1] == endc)){ - copy = TRUE; - cp++; - } - } - termc = *cp; - *cp = '\0'; - 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 = emalloc(cp - tstr); - for (cp2 = pattern, cp = tstr + 1; - *cp != '\0'; - cp++, cp2++) - { - if ((*cp == '\\') && - (cp[1] == ':' || cp[1] == endc)) { - cp++; - } - *cp2 = *cp; - } - *cp2 = '\0'; - } else { - pattern = &tstr[1]; - } - if (*tstr == 'M' || *tstr == 'm') { - newStr = VarModify(str, VarMatch, (ClientData)pattern); - } else { - newStr = VarModify(str, VarNoMatch, - (ClientData)pattern); - } - if (copy) { - free(pattern); - } - break; - } - case 'S': - { - VarPattern pattern; - register char delim; - Buffer buf; /* Buffer for patterns */ - - pattern.flags = 0; - 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; - } - - buf = Buf_Init(0); - - /* - * Pass through the lhs 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. - */ - for (cp = tstr; *cp != '\0' && *cp != delim; cp++) { - if ((*cp == '\\') && - ((cp[1] == delim) || - (cp[1] == '$') || - (cp[1] == '\\'))) - { - Buf_AddByte(buf, (Byte)cp[1]); - cp++; - } else if (*cp == '$') { - if (cp[1] != delim) { - /* - * If unescaped dollar sign not before the - * delimiter, assume it's a variable - * substitution and recurse. - */ - char *cp2; - int len; - Boolean freeIt; - - cp2 = Var_Parse(cp, ctxt, err, &len, &freeIt); - Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2); - if (freeIt) { - free(cp2); - } - cp += len - 1; - } else { - /* - * Unescaped $ at end of pattern => anchor - * pattern at end. - */ - pattern.flags |= VAR_MATCH_END; - } - } else { - Buf_AddByte(buf, (Byte)*cp); - } - } - - Buf_AddByte(buf, (Byte)'\0'); - - /* - * If lhs didn't end with the delimiter, complain and - * return NULL - */ - if (*cp != delim) { - *lengthPtr = cp - start + 1; - if (*freePtr) { - free(str); - } - Buf_Destroy(buf, TRUE); - Error("Unclosed substitution for %s (%c missing)", - v->name, delim); - return (var_Error); - } - - /* - * Fetch pattern and destroy buffer, but preserve the data - * in it, since that's our lhs. Note that Buf_GetAll - * will return the actual number of bytes, which includes - * the null byte, so we have to decrement the length by - * one. - */ - pattern.lhs = (char *)Buf_GetAll(buf, &pattern.leftLen); - pattern.leftLen--; - Buf_Destroy(buf, FALSE); - - /* - * Now comes the replacement string. Three things need to - * be done here: 1) need to compress escaped delimiters and - * ampersands and 2) need to replace unescaped ampersands - * with the l.h.s. (since this isn't regexp, we can do - * it right here) and 3) expand any variable substitutions. - */ - buf = Buf_Init(0); - - tstr = cp + 1; - for (cp = tstr; *cp != '\0' && *cp != delim; cp++) { - if ((*cp == '\\') && - ((cp[1] == delim) || - (cp[1] == '&') || - (cp[1] == '\\') || - (cp[1] == '$'))) - { - Buf_AddByte(buf, (Byte)cp[1]); - cp++; - } else if ((*cp == '$') && (cp[1] != delim)) { - char *cp2; - int len; - Boolean freeIt; - - cp2 = Var_Parse(cp, ctxt, err, &len, &freeIt); - Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2); - cp += len - 1; - if (freeIt) { - free(cp2); - } - } else if (*cp == '&') { - Buf_AddBytes(buf, pattern.leftLen, - (Byte *)pattern.lhs); - } else { - Buf_AddByte(buf, (Byte)*cp); - } - } - - Buf_AddByte(buf, (Byte)'\0'); - - /* - * If didn't end in delimiter character, complain - */ - if (*cp != delim) { - *lengthPtr = cp - start + 1; - if (*freePtr) { - free(str); - } - Buf_Destroy(buf, TRUE); - Error("Unclosed substitution for %s (%c missing)", - v->name, delim); - return (var_Error); - } - - pattern.rhs = (char *)Buf_GetAll(buf, &pattern.rightLen); - pattern.rightLen--; - Buf_Destroy(buf, FALSE); - - /* - * Check for global substitution. If 'g' after the final - * delimiter, substitution is global and is marked that - * way. - */ - cp++; - if (*cp == 'g') { - pattern.flags |= VAR_SUB_GLOBAL; - cp++; - } - - termc = *cp; - newStr = VarModify(str, VarSubstitute, - (ClientData)&pattern); - /* - * Free the two strings. - */ - free(pattern.lhs); - free(pattern.rhs); - break; - } - case 'T': - if (tstr[1] == endc || tstr[1] == ':') { - newStr = VarModify (str, VarTail, (ClientData)0); - cp = tstr + 1; - termc = *cp; - break; - } - /*FALLTHRU*/ - case 'H': - if (tstr[1] == endc || tstr[1] == ':') { - newStr = VarModify (str, VarHead, (ClientData)0); - cp = tstr + 1; - termc = *cp; - break; - } - /*FALLTHRU*/ - case 'E': - if (tstr[1] == endc || tstr[1] == ':') { - newStr = VarModify (str, VarSuffix, (ClientData)0); - cp = tstr + 1; - termc = *cp; - break; - } - /*FALLTHRU*/ - case 'R': - if (tstr[1] == endc || tstr[1] == ':') { - newStr = VarModify (str, VarRoot, (ClientData)0); - cp = tstr + 1; - termc = *cp; - break; - } - /*FALLTHRU*/ - default: { - /* - * 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. - */ - for (cp = tstr; *cp != '='; cp++) - continue; - pattern.lhs = tstr; - pattern.leftLen = cp - tstr; - *cp++ = '\0'; - - pattern.rhs = cp; - cnt = 1; - while (cnt) { - if (*cp == endc) - cnt--; - else if (*cp == startc) - cnt++; - if (cnt) - cp++; - } - pattern.rightLen = cp - pattern.rhs; - *cp = '\0'; - - /* - * SYSV modifications happen through the whole - * string. Note the pattern is anchored at the end. - */ - newStr = VarModify(str, VarSYSVMatch, - (ClientData)&pattern); - - /* - * Restore the nulled characters - */ - pattern.lhs[pattern.leftLen] = '='; - pattern.rhs[pattern.rightLen] = endc; - termc = endc; - } else { - Error ("Unknown modifier '%c'\n", *tstr); - for (cp = tstr+1; - *cp != ':' && *cp != endc && *cp != '\0'; - cp++) - continue; - termc = *cp; - newStr = var_Error; - } - } - } - if (DEBUG(VAR)) { - printf("Result is \"%s\"\n", newStr); - } - - if (*freePtr) { - free (str); - } - str = newStr; - if (str != var_Error) { - *freePtr = TRUE; - } else { - *freePtr = FALSE; - } - if (termc == '\0') { - Error("Unclosed variable specification for %s", v->name); - } else if (termc == ':') { - *cp++ = termc; - } else { - *cp = termc; - } - tstr = cp; - } - *lengthPtr = tstr - start + 1; - } else { - *lengthPtr = tstr - start + 1; - *tstr = endc; - } - - if (v->flags & VAR_FROM_ENV) { - Boolean destroy = FALSE; - - if (str != (char *)Buf_GetAll(v->val, (int *)NULL)) { - destroy = TRUE; - } else { - /* - * Returning the value unmodified, so tell the caller to free - * the thing. - */ - *freePtr = TRUE; - } - Buf_Destroy(v->val, destroy); - free((Address)v); - } else if (v->flags & VAR_JUNK) { - /* - * Perform any free'ing needed and set *freePtr to FALSE so the caller - * doesn't try to free a static pointer. - */ - if (*freePtr) { - free(str); - } - *freePtr = FALSE; - Buf_Destroy(v->val, TRUE); - free((Address)v); - if (dynamic) { - str = emalloc(*lengthPtr + 1); - strncpy(str, start, *lengthPtr); - str[*lengthPtr] = '\0'; - *freePtr = TRUE; - } else { - str = var_Error; - } - } - return (str); -} - -/*- - *----------------------------------------------------------------------- - * Var_Subst -- - * Substitute for all variables in the given string in the given context - * If undefErr is TRUE, Parse_Error will be called when an undefined - * variable is encountered. - * - * Results: - * The resulting string. - * - * Side Effects: - * None. The old string must be freed by the caller - *----------------------------------------------------------------------- - */ -char * -Var_Subst (var, str, ctxt, undefErr) - char *var; /* Named variable || NULL for all */ - char *str; /* the string in which to substitute */ - GNode *ctxt; /* the context wherein to find variables */ - Boolean undefErr; /* TRUE if undefineds are an error */ -{ - Buffer buf; /* Buffer for forming things */ - char *val; /* Value to substitute for a variable */ - int length; /* Length of the variable invocation */ - Boolean doFree; /* Set true if val should be freed */ - static Boolean errorReported; /* Set true if an error has already - * been reported to prevent a plethora - * of messages when recursing */ - - buf = Buf_Init (MAKE_BSIZE); - errorReported = FALSE; - - while (*str) { - 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. - */ - str++; - Buf_AddByte(buf, (Byte)*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). - */ - char *cp; - - for (cp = str++; *str != '$' && *str != '\0'; str++) - continue; - Buf_AddBytes(buf, str - cp, (Byte *)cp); - } else { - if (var != NULL) { - int expand; - for (;;) { - if (str[1] != '(' && str[1] != '{') { - if (str[1] != *var) { - Buf_AddBytes(buf, 2, (Byte *) str); - str += 2; - expand = FALSE; - } - else - expand = TRUE; - break; - } - else { - char *p; - - /* - * Scan up to the end of the variable name. - */ - for (p = &str[2]; *p && - *p != ':' && *p != ')' && *p != '}'; 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, (Byte *) 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, (Byte *) str); - str = p; - expand = FALSE; - } - else - expand = TRUE; - break; - } - } - if (!expand) - continue; - } - - val = Var_Parse (str, ctxt, undefErr, &length, &doFree); - - /* - * 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 (undefErr) { - /* - * 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, (Byte)*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. - */ - Buf_AddBytes (buf, strlen (val), (Byte *)val); - if (doFree) { - free ((Address)val); - } - } - } - } - - Buf_AddByte (buf, '\0'); - str = (char *)Buf_GetAll (buf, (int *)NULL); - Buf_Destroy (buf, FALSE); - return (str); -} - -/*- - *----------------------------------------------------------------------- - * Var_GetTail -- - * Return the tail from each of a list of words. Used to set the - * System V local variables. - * - * Results: - * The resulting string. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ -char * -Var_GetTail(file) - char *file; /* Filename to modify */ -{ - return(VarModify(file, VarTail, (ClientData)0)); -} - -/*- - *----------------------------------------------------------------------- - * 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. - * - * Results: - * The leading components. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ -char * -Var_GetHead(file) - char *file; /* Filename to manipulate */ -{ - return(VarModify(file, VarHead, (ClientData)0)); -} - -/*- - *----------------------------------------------------------------------- - * Var_Init -- - * Initialize the module - * - * Results: - * None - * - * Side Effects: - * The VAR_CMD and VAR_GLOBAL contexts are created - *----------------------------------------------------------------------- - */ -void -Var_Init () -{ - VAR_GLOBAL = Targ_NewGN ("Global"); - VAR_CMD = Targ_NewGN ("Command"); - allVars = Lst_Init(FALSE); - -} - - -void -Var_End () -{ - Lst_Destroy(allVars, VarDelete); -} - - -/****************** PRINT DEBUGGING INFO *****************/ -static int -VarPrintVar (vp, dummy) - ClientData vp; - ClientData dummy; -{ - Var *v = (Var *) vp; - printf ("%-16s = %s\n", v->name, (char *) Buf_GetAll(v->val, (int *)NULL)); - return (dummy ? 0 : 0); -} - -/*- - *----------------------------------------------------------------------- - * Var_Dump -- - * print all variables in a context - *----------------------------------------------------------------------- - */ -void -Var_Dump (ctxt) - GNode *ctxt; -{ - Lst_ForEach (ctxt->context, VarPrintVar, (ClientData) 0); -} |
