Import NetBSD csh(1)
Jobctl warning commented out. Largely untested. Change-Id: I4dffe23a2855a374628c820703b51591633aed64
This commit is contained in:
parent
29346ab043
commit
d1e4d7ce7d
41 changed files with 23896 additions and 2 deletions
|
@ -1,7 +1,7 @@
|
|||
# $NetBSD: Makefile,v 1.22 2007/12/31 15:31:24 ad Exp $
|
||||
# @(#)Makefile 8.1 (Berkeley) 5/31/93
|
||||
|
||||
SUBDIR= cat chmod cp date dd df domainname echo ed expr hostname \
|
||||
SUBDIR= cat chmod cp csh date dd df domainname echo ed expr hostname \
|
||||
kill ksh ln ls mkdir mv pax pwd rcp rcmd rm rmdir sh \
|
||||
sleep stty sync test
|
||||
|
||||
|
|
76
bin/csh/Makefile
Normal file
76
bin/csh/Makefile
Normal file
|
@ -0,0 +1,76 @@
|
|||
# $NetBSD: Makefile,v 1.39 2013/07/16 17:47:43 christos Exp $
|
||||
# @(#)Makefile 8.1 (Berkeley) 5/31/93
|
||||
#
|
||||
# C Shell with process control; VM/UNIX VAX Makefile
|
||||
# Bill Joy UC Berkeley; Jim Kulp IIASA, Austria
|
||||
#
|
||||
# To profile, put -DPROF in DFLAGS and -pg in COPTS, and recompile.
|
||||
|
||||
.include <bsd.own.mk>
|
||||
WARNS=6
|
||||
|
||||
PROG= csh
|
||||
DFLAGS=-DBUILTIN -DFILEC -DNLS -DSHORT_STRINGS
|
||||
# - Editor history not always aligned with shell history,
|
||||
# should implement internally
|
||||
# - Does not handle escaped prompts.
|
||||
# - Does not do completion
|
||||
.ifndef SMALLPROG
|
||||
DFLAGS+=-DEDIT
|
||||
.endif
|
||||
CPPFLAGS+=-I${.CURDIR} -I. ${DFLAGS}
|
||||
SRCS= alloc.c char.c const.c csh.c dir.c dol.c err.c exec.c exp.c file.c \
|
||||
func.c glob.c hist.c init.c lex.c misc.c parse.c printf.c proc.c \
|
||||
sem.c set.c str.c time.c
|
||||
.PATH: ${NETBSDSRCDIR}/usr.bin/printf
|
||||
|
||||
MLINKS= csh.1 limit.1 csh.1 alias.1 csh.1 bg.1 csh.1 dirs.1 csh.1 fg.1 \
|
||||
csh.1 foreach.1 csh.1 history.1 csh.1 jobs.1 csh.1 popd.1 \
|
||||
csh.1 pushd.1 csh.1 rehash.1 csh.1 repeat.1 csh.1 suspend.1 \
|
||||
csh.1 stop.1 csh.1 source.1
|
||||
|
||||
DPSRCS+= errnum.h const.h
|
||||
CLEANFILES+= errnum.h const.h
|
||||
|
||||
errnum.h: err.c
|
||||
${_MKTARGET_CREATE}
|
||||
rm -f ${.TARGET}
|
||||
(\
|
||||
echo '/* Do not edit this file, make creates it. */' ;\
|
||||
echo '#ifndef _h_sh_errnum' ;\
|
||||
echo '#define _h_sh_errnum' ;\
|
||||
egrep 'ERR_' ${.ALLSRC} | egrep '^#define' ;\
|
||||
echo '#endif /* _h_sh_errnum */' ;\
|
||||
) > ${.TARGET}
|
||||
|
||||
const.c: errnum.h
|
||||
const.h: const.c
|
||||
${_MKTARGET_CREATE}
|
||||
rm -f ${.TARGET}
|
||||
echo '/* Do not edit this file, make creates it. */' > ${.TARGET}
|
||||
${CC} -E ${CPPFLAGS} ${.ALLSRC} | egrep 'Char STR' | \
|
||||
${TOOL_SED} -e 's/Char \([a-zA-Z0-9_]*\)\(.*\)/extern Char \1[];/' | \
|
||||
sort >> ${.TARGET}
|
||||
|
||||
.if make(install)
|
||||
SUBDIR+=USD.doc
|
||||
.endif
|
||||
|
||||
# XXX Only GCC 4.1 problem
|
||||
.if defined(HAVE_GCC) && ${HAVE_GCC} == 4 && ${MACHINE_ARCH} == "vax"
|
||||
COPTS.parse.c+= -O0
|
||||
.endif
|
||||
COPTS.err.c = -Wno-format-nonliteral
|
||||
COPTS.printf.c = -Wno-format-nonliteral
|
||||
COPTS.proc.c = -Wno-format-nonliteral
|
||||
|
||||
.if !empty(DFLAGS:M*EDIT)
|
||||
LDADD+=-ledit -lterminfo -lutil
|
||||
DPADD+=${LIBEDIT} ${LIBUTIL}
|
||||
.else
|
||||
LDADD+=-lutil
|
||||
DPADD+=${LIBUTIL}
|
||||
.endif
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
.include <bsd.subdir.mk>
|
12
bin/csh/USD.doc/Makefile
Normal file
12
bin/csh/USD.doc/Makefile
Normal file
|
@ -0,0 +1,12 @@
|
|||
# $NetBSD: Makefile,v 1.7 2007/10/18 18:26:31 tls Exp $
|
||||
# @(#)Makefile 8.1 (Berkeley) 8/14/93
|
||||
|
||||
DIR= usd/04.csh
|
||||
SRCS= tabs csh.1 csh.2 csh.3 csh.4 csh.ap csh.g
|
||||
MACROS= -ms
|
||||
|
||||
paper.ps: ${SRCS}
|
||||
${TOOL_SOELIM} -I${.CURDIR} ${.ALLSRC} | \
|
||||
${TOOL_ROFF_PS} ${MACROS} > ${.TARGET}
|
||||
|
||||
.include <bsd.doc.mk>
|
1010
bin/csh/USD.doc/csh.1
Normal file
1010
bin/csh/USD.doc/csh.1
Normal file
File diff suppressed because it is too large
Load diff
1303
bin/csh/USD.doc/csh.2
Normal file
1303
bin/csh/USD.doc/csh.2
Normal file
File diff suppressed because it is too large
Load diff
648
bin/csh/USD.doc/csh.3
Normal file
648
bin/csh/USD.doc/csh.3
Normal file
|
@ -0,0 +1,648 @@
|
|||
.\" $NetBSD: csh.3,v 1.5 2003/08/07 09:05:08 agc Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1980, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. Neither the name of the University nor the names of its contributors
|
||||
.\" may be used to endorse or promote products derived from this software
|
||||
.\" without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)csh.3 8.1 (Berkeley) 6/8/93
|
||||
.\"
|
||||
.nr H1 2
|
||||
.NH
|
||||
Shell control structures and command scripts
|
||||
.NH 2
|
||||
Introduction
|
||||
.PP
|
||||
It is possible to place commands in files and to cause shells to be
|
||||
invoked to read and execute commands from these files,
|
||||
which are called
|
||||
.I "shell scripts."
|
||||
We here detail those features of the shell useful to the writers of such
|
||||
scripts.
|
||||
.NH 2
|
||||
Make
|
||||
.PP
|
||||
It is important to first note what shell scripts are
|
||||
.I not
|
||||
useful for.
|
||||
There is a program called
|
||||
.I make
|
||||
which is very useful for maintaining a group of related files
|
||||
or performing sets of operations on related files.
|
||||
For instance a large program consisting of one or more files
|
||||
can have its dependencies described in a
|
||||
.I makefile
|
||||
which contains definitions of the commands used to create these
|
||||
different files when changes occur.
|
||||
Definitions of the means for printing listings, cleaning up the directory
|
||||
in which the files reside, and installing the resultant programs
|
||||
are easily, and most appropriately placed in this
|
||||
.I makefile.
|
||||
This format is superior and preferable to maintaining a group of shell
|
||||
procedures to maintain these files.
|
||||
.PP
|
||||
Similarly when working on a document a
|
||||
.I makefile
|
||||
may be created which defines how different versions of the document
|
||||
are to be created and which options of
|
||||
.I nroff
|
||||
or
|
||||
.I troff
|
||||
are appropriate.
|
||||
.NH 2
|
||||
Invocation and the argv variable
|
||||
.PP
|
||||
A
|
||||
.I csh
|
||||
command script may be interpreted by saying
|
||||
.DS
|
||||
% csh script ...
|
||||
.DE
|
||||
where
|
||||
.I script
|
||||
is the name of the file containing a group of
|
||||
.I csh
|
||||
commands and
|
||||
`\&...' is replaced by a sequence of arguments.
|
||||
The shell places these arguments in the variable
|
||||
.I argv
|
||||
and then begins to read commands from the script.
|
||||
These parameters are then available through the same mechanisms
|
||||
which are used to reference any other shell variables.
|
||||
.PP
|
||||
If you make the file
|
||||
`script'
|
||||
executable by doing
|
||||
.DS
|
||||
chmod 755 script
|
||||
.DE
|
||||
and place a shell comment at the beginning of the shell script
|
||||
(i.e. begin the file with a `#' character)
|
||||
then a `/bin/csh' will automatically be invoked to execute `script' when
|
||||
you type
|
||||
.DS
|
||||
script
|
||||
.DE
|
||||
If the file does not begin with a `#' then the standard shell
|
||||
`/bin/sh' will be used to execute it.
|
||||
This allows you to convert your older shell scripts to use
|
||||
.I csh
|
||||
at your convenience.
|
||||
.NH 2
|
||||
Variable substitution
|
||||
.PP
|
||||
After each input line is broken into words and history substitutions
|
||||
are done on it, the input line is parsed into distinct commands.
|
||||
Before each command is executed a mechanism know as
|
||||
.I "variable substitution"
|
||||
is done on these words.
|
||||
Keyed by the character `$' this substitution replaces the names
|
||||
of variables by their values.
|
||||
Thus
|
||||
.DS
|
||||
echo $argv
|
||||
.DE
|
||||
when placed in a command script would cause the current value of the
|
||||
variable
|
||||
.I argv
|
||||
to be echoed to the output of the shell script.
|
||||
It is an error for
|
||||
.I argv
|
||||
to be unset at this point.
|
||||
.PP
|
||||
A number of notations are provided for accessing components and attributes
|
||||
of variables.
|
||||
The notation
|
||||
.DS
|
||||
$?name
|
||||
.DE
|
||||
expands to `1' if name is
|
||||
.I set
|
||||
or to `0'
|
||||
if name is not
|
||||
.I set.
|
||||
It is the fundamental mechanism used for checking whether particular
|
||||
variables have been assigned values.
|
||||
All other forms of reference to undefined variables cause errors.
|
||||
.PP
|
||||
The notation
|
||||
.DS
|
||||
$#name
|
||||
.DE
|
||||
expands to the number of elements in the variable
|
||||
.I name.
|
||||
Thus
|
||||
.DS
|
||||
% set argv=(a b c)
|
||||
% echo $?argv
|
||||
1
|
||||
% echo $#argv
|
||||
3
|
||||
% unset argv
|
||||
% echo $?argv
|
||||
0
|
||||
% echo $argv
|
||||
Undefined variable: argv.
|
||||
%
|
||||
.DE
|
||||
.PP
|
||||
It is also possible to access the components of a variable
|
||||
which has several values.
|
||||
Thus
|
||||
.DS
|
||||
$argv[1]
|
||||
.DE
|
||||
gives the first component of
|
||||
.I argv
|
||||
or in the example above `a'.
|
||||
Similarly
|
||||
.DS
|
||||
$argv[$#argv]
|
||||
.DE
|
||||
would give `c',
|
||||
and
|
||||
.DS
|
||||
$argv[1\-2]
|
||||
.DE
|
||||
would give `a b'. Other notations useful in shell scripts are
|
||||
.DS
|
||||
$\fIn\fR
|
||||
.DE
|
||||
where
|
||||
.I n
|
||||
is an integer as a shorthand for
|
||||
.DS
|
||||
$argv[\fIn\fR\|]
|
||||
.DE
|
||||
the
|
||||
.I n\|th
|
||||
parameter and
|
||||
.DS
|
||||
$*
|
||||
.DE
|
||||
which is a shorthand for
|
||||
.DS
|
||||
$argv
|
||||
.DE
|
||||
The form
|
||||
.DS
|
||||
$$
|
||||
.DE
|
||||
expands to the process number of the current shell.
|
||||
Since this process number is unique in the system it can
|
||||
be used in generation of unique temporary file names.
|
||||
The form
|
||||
.DS
|
||||
$<
|
||||
.DE
|
||||
is quite special and is replaced by the next line of input read from
|
||||
the shell's standard input (not the script it is reading). This is
|
||||
useful for writing shell scripts that are interactive, reading
|
||||
commands from the terminal, or even writing a shell script that
|
||||
acts as a filter, reading lines from its input file. Thus the sequence
|
||||
.DS
|
||||
echo 'yes or no?\ec'
|
||||
set a=($<)
|
||||
.DE
|
||||
would write out the prompt `yes or no?' without a newline and then
|
||||
read the answer into the variable `a'. In this case `$#a' would be
|
||||
`0' if either a blank line or end-of-file (^D) was typed.
|
||||
.PP
|
||||
One minor difference between `$\fIn\fR\|' and `$argv[\fIn\fR\|]'
|
||||
should be noted here.
|
||||
The form
|
||||
`$argv[\fIn\fR\|]'
|
||||
will yield an error if
|
||||
.I n
|
||||
is not in the range
|
||||
`1\-$#argv'
|
||||
while `$n'
|
||||
will never yield an out of range subscript error.
|
||||
This is for compatibility with the way older shells handled parameters.
|
||||
.PP
|
||||
Another important point is that it is never an error to give a subrange
|
||||
of the form `n\-'; if there are less than
|
||||
.I n
|
||||
components of the given variable then no words are substituted.
|
||||
A range of the form `m\-n' likewise returns an empty vector without giving
|
||||
an error when \fIm\fR exceeds the number of elements of the given variable,
|
||||
provided the subscript \fIn\fR is in range.
|
||||
.NH 2
|
||||
Expressions
|
||||
.PP
|
||||
In order for interesting shell scripts to be constructed it
|
||||
must be possible to evaluate expressions in the shell based on the
|
||||
values of variables.
|
||||
In fact, all the arithmetic operations of the language C are available
|
||||
in the shell
|
||||
with the same precedence that they have in C.
|
||||
In particular, the operations `==' and `!=' compare strings
|
||||
and the operators `&&' and `|\|\||' implement the boolean and/or operations.
|
||||
The special operators `=~' and `!~' are similar to `==' and `!=' except
|
||||
that the string on the right side can have pattern matching characters
|
||||
(like *, ? or []) and the test is whether the string on the left matches
|
||||
the pattern on the right.
|
||||
.PP
|
||||
The shell also allows file enquiries of the form
|
||||
.DS
|
||||
\-? filename
|
||||
.DE
|
||||
where `?' is replace by a number of single characters.
|
||||
For instance the expression primitive
|
||||
.DS
|
||||
\-e filename
|
||||
.DE
|
||||
tell whether the file
|
||||
`filename'
|
||||
exists.
|
||||
Other primitives test for read, write and execute access to the file,
|
||||
whether it is a directory, or has non-zero length.
|
||||
.PP
|
||||
It is possible to test whether a command terminates normally,
|
||||
by a primitive of the
|
||||
form `{ command }' which returns true, i.e. `1' if the command
|
||||
succeeds exiting normally with exit status 0, or `0' if the command
|
||||
terminates abnormally or with exit status non-zero.
|
||||
If more detailed information about the execution status of a command
|
||||
is required, it can be executed and the variable `$status' examined
|
||||
in the next command.
|
||||
Since `$status' is set by every command, it is very transient.
|
||||
It can be saved if it is inconvenient to use it only in the single
|
||||
immediately following command.
|
||||
.PP
|
||||
For a full list of expression components available see the manual
|
||||
section for the shell.
|
||||
.NH 2
|
||||
Sample shell script
|
||||
.PP
|
||||
A sample shell script which makes use of the expression mechanism
|
||||
of the shell and some of its control structure follows:
|
||||
.DS
|
||||
% cat copyc
|
||||
#
|
||||
# Copyc copies those C programs in the specified list
|
||||
# to the directory ~/backup if they differ from the files
|
||||
# already in ~/backup
|
||||
#
|
||||
set noglob
|
||||
foreach i ($argv)
|
||||
|
||||
if ($i !~ *.c) continue # not a .c file so do nothing
|
||||
|
||||
if (! \-r ~/backup/$i:t) then
|
||||
echo $i:t not in backup... not cp\e\'ed
|
||||
continue
|
||||
endif
|
||||
|
||||
cmp \-s $i ~/backup/$i:t # to set $status
|
||||
|
||||
if ($status != 0) then
|
||||
echo new backup of $i
|
||||
cp $i ~/backup/$i:t
|
||||
endif
|
||||
end
|
||||
.DE
|
||||
.PP
|
||||
This script makes use of the
|
||||
.I foreach
|
||||
command, which causes the shell to execute the commands between the
|
||||
.I foreach
|
||||
and the matching
|
||||
.I end
|
||||
for each of the values given between `(' and `)' with the named
|
||||
variable, in this case `i' set to successive values in the list.
|
||||
Within this loop we may use the command
|
||||
.I break
|
||||
to stop executing the loop
|
||||
and
|
||||
.I continue
|
||||
to prematurely terminate one iteration
|
||||
and begin the next.
|
||||
After the
|
||||
.I foreach
|
||||
loop the iteration variable
|
||||
(\fIi\fR in this case)
|
||||
has the value at the last iteration.
|
||||
.PP
|
||||
We set the variable
|
||||
.I noglob
|
||||
here to prevent filename expansion of the members of
|
||||
.I argv.
|
||||
This is a good idea, in general, if the arguments to a shell script
|
||||
are filenames which have already been expanded or if the arguments
|
||||
may contain filename expansion metacharacters.
|
||||
It is also possible to quote each use of a `$' variable expansion,
|
||||
but this is harder and less reliable.
|
||||
.PP
|
||||
The other control construct used here is a statement of the form
|
||||
.DS
|
||||
\fBif\fR ( expression ) \fBthen\fR
|
||||
command
|
||||
...
|
||||
\fBendif\fR
|
||||
.DE
|
||||
The placement of the keywords here is
|
||||
.B not
|
||||
flexible due to the current implementation of the shell.\(dg
|
||||
.FS
|
||||
\(dgThe following two formats are not currently acceptable to the shell:
|
||||
.sp
|
||||
.in +5
|
||||
.nf
|
||||
\fBif\fR ( expression ) # \fBWon't work!\fR
|
||||
\fBthen\fR
|
||||
command
|
||||
...
|
||||
\fBendif\fR
|
||||
.fi
|
||||
.in -5
|
||||
.sp
|
||||
and
|
||||
.sp
|
||||
.in +5
|
||||
.nf
|
||||
\fBif\fR ( expression ) \fBthen\fR command \fBendif\fR # \fBWon't work\fR
|
||||
.in -5
|
||||
.fi
|
||||
.FE
|
||||
.PP
|
||||
The shell does have another form of the if statement of the form
|
||||
.DS
|
||||
\fBif\fR ( expression ) \fBcommand\fR
|
||||
.DE
|
||||
which can be written
|
||||
.DS
|
||||
\fBif\fR ( expression ) \e
|
||||
command
|
||||
.DE
|
||||
Here we have escaped the newline for the sake of appearance.
|
||||
The command must not involve `\||\|', `&' or `;'
|
||||
and must not be another control command.
|
||||
The second form requires the final `\e' to
|
||||
.B immediately
|
||||
precede the end-of-line.
|
||||
.PP
|
||||
The more general
|
||||
.I if
|
||||
statements above also admit a sequence of
|
||||
.I else\-if
|
||||
pairs followed by a single
|
||||
.I else
|
||||
and an
|
||||
.I endif,
|
||||
e.g.:
|
||||
.DS
|
||||
\fBif\fR ( expression ) \fBthen\fR
|
||||
commands
|
||||
\fBelse\fR \fBif\fR (expression ) \fBthen\fR
|
||||
commands
|
||||
\&...
|
||||
|
||||
\fBelse\fR
|
||||
commands
|
||||
\fBendif\fR
|
||||
.DE
|
||||
.PP
|
||||
Another important mechanism used in shell scripts is the `:' modifier.
|
||||
We can use the modifier `:r' here to extract a root of a filename or
|
||||
`:e' to extract the
|
||||
.I extension.
|
||||
Thus if the variable
|
||||
.I i
|
||||
has the value
|
||||
`/mnt/foo.bar'
|
||||
then
|
||||
.sp
|
||||
.in +5
|
||||
.nf
|
||||
% echo $i $i:r $i:e
|
||||
/mnt/foo.bar /mnt/foo bar
|
||||
%
|
||||
.sp
|
||||
.in -5
|
||||
.fi
|
||||
shows how the `:r' modifier strips off the trailing `.bar' and the
|
||||
the `:e' modifier leaves only the `bar'.
|
||||
Other modifiers will take off the last component of a pathname leaving
|
||||
the head `:h' or all but the last component of a pathname leaving the
|
||||
tail `:t'.
|
||||
These modifiers are fully described in the
|
||||
.I csh
|
||||
manual pages in the User's Reference Manual.
|
||||
It is also possible to use the
|
||||
.I "command substitution"
|
||||
mechanism described in the next major section to perform modifications
|
||||
on strings to then reenter the shell's environment.
|
||||
Since each usage of this mechanism involves the creation of a new process,
|
||||
it is much more expensive to use than the `:' modification mechanism.\(dd
|
||||
.FS
|
||||
\(dd It is also important to note that
|
||||
the current implementation of the shell limits the number of `:' modifiers
|
||||
on a `$' substitution to 1.
|
||||
Thus
|
||||
.sp
|
||||
.nf
|
||||
.in +5
|
||||
% echo $i $i:h:t
|
||||
/a/b/c /a/b:t
|
||||
%
|
||||
.in -5
|
||||
.fi
|
||||
.sp
|
||||
does not do what one would expect.
|
||||
.FE
|
||||
Finally, we note that the character `#' lexically introduces a shell
|
||||
comment in shell scripts (but not from the terminal).
|
||||
All subsequent characters on the input line after a `#' are discarded
|
||||
by the shell.
|
||||
This character can be quoted using `\'' or `\e' to place it in
|
||||
an argument word.
|
||||
.NH 2
|
||||
Other control structures
|
||||
.PP
|
||||
The shell also has control structures
|
||||
.I while
|
||||
and
|
||||
.I switch
|
||||
similar to those of C.
|
||||
These take the forms
|
||||
.DS
|
||||
\fBwhile\fR ( expression )
|
||||
commands
|
||||
\fBend\fR
|
||||
.DE
|
||||
and
|
||||
.DS
|
||||
\fBswitch\fR ( word )
|
||||
|
||||
\fBcase\fR str1:
|
||||
commands
|
||||
\fBbreaksw\fR
|
||||
|
||||
\& ...
|
||||
|
||||
\fBcase\fR strn:
|
||||
commands
|
||||
\fBbreaksw\fR
|
||||
|
||||
\fBdefault:\fR
|
||||
commands
|
||||
\fBbreaksw\fR
|
||||
|
||||
\fBendsw\fR
|
||||
.DE
|
||||
For details see the manual section for
|
||||
.I csh.
|
||||
C programmers should note that we use
|
||||
.I breaksw
|
||||
to exit from a
|
||||
.I switch
|
||||
while
|
||||
.I break
|
||||
exits a
|
||||
.I while
|
||||
or
|
||||
.I foreach
|
||||
loop.
|
||||
A common mistake to make in
|
||||
.I csh
|
||||
scripts is to use
|
||||
.I break
|
||||
rather than
|
||||
.I breaksw
|
||||
in switches.
|
||||
.PP
|
||||
Finally,
|
||||
.I csh
|
||||
allows a
|
||||
.I goto
|
||||
statement, with labels looking like they do in C, i.e.:
|
||||
.DS
|
||||
loop:
|
||||
commands
|
||||
\fBgoto\fR loop
|
||||
.DE
|
||||
.NH 2
|
||||
Supplying input to commands
|
||||
.PP
|
||||
Commands run from shell scripts receive by default the standard
|
||||
input of the shell which is running the script.
|
||||
This is different from previous shells running
|
||||
under \s-2UNIX\s0. It allows shell scripts to fully participate
|
||||
in pipelines, but mandates extra notation for commands which are to take
|
||||
inline data.
|
||||
.PP
|
||||
Thus we need a metanotation for supplying inline data to commands in
|
||||
shell scripts.
|
||||
As an example, consider this script which runs the editor to
|
||||
delete leading blanks from the lines in each argument file:
|
||||
.DS
|
||||
% cat deblank
|
||||
# deblank \-\- remove leading blanks
|
||||
foreach i ($argv)
|
||||
ed \- $i << \'EOF\'
|
||||
1,$s/^[ ]*//
|
||||
w
|
||||
q
|
||||
\&\'EOF\'
|
||||
end
|
||||
%
|
||||
.DE
|
||||
The notation `<< \'EOF\''
|
||||
means that the standard input for the
|
||||
.I ed
|
||||
command is to come from the text in the shell script file
|
||||
up to the next line consisting of exactly `\'EOF\''.
|
||||
The fact that the `EOF' is enclosed in `\'' characters, i.e. quoted,
|
||||
causes the shell to not perform variable substitution on the
|
||||
intervening lines.
|
||||
In general, if any part of the word following the `<<' which the
|
||||
shell uses to terminate the text to be given to the command is quoted
|
||||
then these substitutions will not be performed.
|
||||
In this case since we used the form `1,$' in our editor script
|
||||
we needed to insure that this `$' was not variable substituted.
|
||||
We could also have insured this by preceding the `$' here with a `\e',
|
||||
i.e.:
|
||||
.DS
|
||||
1,\e$s/^[ ]*//
|
||||
.DE
|
||||
but quoting the `EOF' terminator is a more reliable way of achieving the
|
||||
same thing.
|
||||
.NH 2
|
||||
Catching interrupts
|
||||
.PP
|
||||
If our shell script creates temporary files, we may wish to catch
|
||||
interruptions of the shell script so that we can clean up
|
||||
these files.
|
||||
We can then do
|
||||
.DS
|
||||
onintr label
|
||||
.DE
|
||||
where
|
||||
.I label
|
||||
is a label in our program.
|
||||
If an interrupt is received the shell will do a
|
||||
`goto label'
|
||||
and we can remove the temporary files and then do an
|
||||
.I exit
|
||||
command (which is built in to the shell)
|
||||
to exit from the shell script.
|
||||
If we wish to exit with a non-zero status we can do
|
||||
.DS
|
||||
exit(1)
|
||||
.DE
|
||||
e.g. to exit with status `1'.
|
||||
.NH 2
|
||||
What else?
|
||||
.PP
|
||||
There are other features of the shell useful to writers of shell
|
||||
procedures.
|
||||
The
|
||||
.I verbose
|
||||
and
|
||||
.I echo
|
||||
options and the related
|
||||
.I \-v
|
||||
and
|
||||
.I \-x
|
||||
command line options can be used to help trace the actions of the shell.
|
||||
The
|
||||
.I \-n
|
||||
option causes the shell only to read commands and not to execute
|
||||
them and may sometimes be of use.
|
||||
.PP
|
||||
One other thing to note is that
|
||||
.I csh
|
||||
will not execute shell scripts which do not begin with the
|
||||
character `#', that is shell scripts that do not begin with a comment.
|
||||
Similarly, the `/bin/sh' on your system may well defer to `csh'
|
||||
to interpret shell scripts which begin with `#'.
|
||||
This allows shell scripts for both shells to live in harmony.
|
||||
.PP
|
||||
There is also another quotation mechanism using `"' which allows
|
||||
only some of the expansion mechanisms we have so far discussed to occur
|
||||
on the quoted string and serves to make this string into a single word
|
||||
as `\'' does.
|
||||
.bp
|
176
bin/csh/USD.doc/csh.4
Normal file
176
bin/csh/USD.doc/csh.4
Normal file
|
@ -0,0 +1,176 @@
|
|||
.\" $NetBSD: csh.4,v 1.4 2003/08/07 09:05:08 agc Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1980, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. Neither the name of the University nor the names of its contributors
|
||||
.\" may be used to endorse or promote products derived from this software
|
||||
.\" without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)csh.4 8.1 (Berkeley) 6/8/93
|
||||
.\"
|
||||
.nr H1 3
|
||||
.NH
|
||||
Other, less commonly used, shell features
|
||||
.NH 2
|
||||
Loops at the terminal; variables as vectors
|
||||
.PP
|
||||
It is occasionally useful to use the
|
||||
.I foreach
|
||||
control structure at the terminal to aid in performing a number
|
||||
of similar commands.
|
||||
For instance, there were at one point three shells in use on the Cory \s-2UNIX\s0
|
||||
system at Cory Hall,
|
||||
`/bin/sh',
|
||||
`/bin/nsh',
|
||||
and
|
||||
`/bin/csh'.
|
||||
To count the number of persons using each shell one could have issued
|
||||
the commands
|
||||
.DS
|
||||
% grep \-c csh$ /etc/passwd
|
||||
27
|
||||
% grep \-c nsh$ /etc/passwd
|
||||
128
|
||||
% grep \-c \-v sh$ /etc/passwd
|
||||
430
|
||||
%
|
||||
.DE
|
||||
Since these commands are very similar we can use
|
||||
.I foreach
|
||||
to do this more easily.
|
||||
.DS
|
||||
% foreach i (\'sh$\' \'csh$\' \'\-v sh$\')
|
||||
? grep \-c $i /etc/passwd
|
||||
? end
|
||||
27
|
||||
128
|
||||
430
|
||||
%
|
||||
.DE
|
||||
Note here that the shell prompts for
|
||||
input with `? ' when reading the body of the loop.
|
||||
.PP
|
||||
Very useful with loops are variables which contain lists of filenames
|
||||
or other words.
|
||||
You can, for example, do
|
||||
.DS
|
||||
% set a=(\`ls\`)
|
||||
% echo $a
|
||||
csh.n csh.rm
|
||||
% ls
|
||||
csh.n
|
||||
csh.rm
|
||||
% echo $#a
|
||||
2
|
||||
%
|
||||
.DE
|
||||
The
|
||||
.I set
|
||||
command here gave the variable
|
||||
.I a
|
||||
a list of all the filenames in the current directory as value.
|
||||
We can then iterate over these names to perform any chosen function.
|
||||
.PP
|
||||
The output of a command within `\`' characters is converted by
|
||||
the shell to a list of words.
|
||||
You can also place the `\`' quoted string within `"' characters
|
||||
to take each (non-empty) line as a component of the variable;
|
||||
preventing the lines from being split into words at blanks and tabs.
|
||||
A modifier `:x' exists which can be used later to expand each component
|
||||
of the variable into another variable splitting it into separate words
|
||||
at embedded blanks and tabs.
|
||||
.NH 2
|
||||
Braces { ... } in argument expansion
|
||||
.PP
|
||||
Another form of filename expansion, alluded
|
||||
to before involves the characters `{' and `}'.
|
||||
These characters specify that the contained strings, separated by `,'
|
||||
are to be consecutively substituted into the containing characters
|
||||
and the results expanded left to right.
|
||||
Thus
|
||||
.DS
|
||||
A{str1,str2,...strn}B
|
||||
.DE
|
||||
expands to
|
||||
.DS
|
||||
Astr1B Astr2B ... AstrnB
|
||||
.DE
|
||||
This expansion occurs before the other filename expansions, and may
|
||||
be applied recursively (i.e. nested).
|
||||
The results of each expanded string are sorted separately, left
|
||||
to right order being preserved.
|
||||
The resulting filenames are not required to exist if no other expansion
|
||||
mechanisms are used.
|
||||
This means that this mechanism can be used to generate arguments which are
|
||||
not filenames, but which have common parts.
|
||||
.PP
|
||||
A typical use of this would be
|
||||
.DS
|
||||
mkdir ~/{hdrs,retrofit,csh}
|
||||
.DE
|
||||
to make subdirectories `hdrs', `retrofit' and `csh'
|
||||
in your home directory.
|
||||
This mechanism is most useful when the common prefix is longer
|
||||
than in this example, i.e.
|
||||
.DS
|
||||
chown root /usr/{ucb/{ex,edit},lib/{ex?.?*,how_ex}}
|
||||
.DE
|
||||
.NH 2
|
||||
Command substitution
|
||||
.PP
|
||||
A command enclosed in `\`' characters is replaced, just before
|
||||
filenames are expanded, by the output from that command.
|
||||
Thus it is possible to do
|
||||
.DS
|
||||
set pwd=\`pwd\`
|
||||
.DE
|
||||
to save the current directory in the variable
|
||||
.I pwd
|
||||
or to do
|
||||
.DS
|
||||
ex \`grep \-l TRACE *.c\`
|
||||
.DE
|
||||
to run the editor
|
||||
.I ex
|
||||
supplying as arguments those files whose names end in `.c'
|
||||
which have the string `TRACE' in them.*
|
||||
.FS
|
||||
*Command expansion also occurs in input redirected with `<<'
|
||||
and within `"' quotations.
|
||||
Refer to the shell manual section for full details.
|
||||
.FE
|
||||
.NH 2
|
||||
Other details not covered here
|
||||
.PP
|
||||
In particular circumstances it may be necessary to know the exact
|
||||
nature and order of different substitutions performed by the shell.
|
||||
The exact meaning of certain combinations of quotations is also
|
||||
occasionally important.
|
||||
These are detailed fully in its manual section.
|
||||
.PP
|
||||
The shell has a number of command line option flags mostly of use
|
||||
in writing \s-2UNIX\s0 programs,
|
||||
and debugging shell scripts.
|
||||
See the csh(1) manual section for a list of these options.
|
||||
.bp
|
93
bin/csh/USD.doc/csh.ap
Normal file
93
bin/csh/USD.doc/csh.ap
Normal file
|
@ -0,0 +1,93 @@
|
|||
.\" $NetBSD: csh.ap,v 1.1 2007/10/18 18:26:31 tls Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1980, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. Neither the name of the University nor the names of its contributors
|
||||
.\" may be used to endorse or promote products derived from this software
|
||||
.\" without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)csh.a 8.1 (Berkeley) 6/8/93
|
||||
.\"
|
||||
.SH
|
||||
Appendix \- Special characters
|
||||
.LP
|
||||
The following table lists the special characters of
|
||||
.I csh
|
||||
and the \s-2UNIX\s0 system, giving for each the section(s) in which it
|
||||
is discussed.
|
||||
A number of these characters also have special meaning in expressions.
|
||||
See the
|
||||
.I csh
|
||||
manual section
|
||||
for a complete list.
|
||||
.ta .75i 1.5i 2.25i
|
||||
.LP
|
||||
Syntactic metacharacters
|
||||
.DS
|
||||
; 2.4 separates commands to be executed sequentially
|
||||
| 1.5 separates commands in a pipeline
|
||||
( ) 2.2,3.6 brackets expressions and variable values
|
||||
& 2.5 follows commands to be executed without waiting for completion
|
||||
.DE
|
||||
.LP
|
||||
Filename metacharacters
|
||||
.DS
|
||||
/ 1.6 separates components of a file's pathname
|
||||
\&. 1.6 separates root parts of a file name from extensions
|
||||
? 1.6 expansion character matching any single character
|
||||
* 1.6 expansion character matching any sequence of characters
|
||||
[ ] 1.6 expansion sequence matching any single character from a set
|
||||
~ 1.6 used at the beginning of a filename to indicate home directories
|
||||
{ } 4.2 used to specify groups of arguments with common parts
|
||||
.DE
|
||||
.LP
|
||||
Quotation metacharacters
|
||||
.DS
|
||||
\e 1.7 prevents meta-meaning of following single character
|
||||
\' 1.7 prevents meta-meaning of a group of characters
|
||||
" 4.3 like \', but allows variable and command expansion
|
||||
.DE
|
||||
.LP
|
||||
Input/output metacharacters
|
||||
.DS
|
||||
< 1.5 indicates redirected input
|
||||
> 1.3 indicates redirected output
|
||||
.DE
|
||||
.LP
|
||||
Expansion/substitution metacharacters
|
||||
.DS
|
||||
$ 3.4 indicates variable substitution
|
||||
! 2.3 indicates history substitution
|
||||
: 3.6 precedes substitution modifiers
|
||||
^ 2.3 used in special forms of history substitution
|
||||
\` 4.3 indicates command substitution
|
||||
.DE
|
||||
.LP
|
||||
Other metacharacters
|
||||
.DS
|
||||
# 1.3,3.6 begins scratch file names; indicates shell comments
|
||||
\- 1.2 prefixes option (flag) arguments to commands
|
||||
% 2.6 prefixes job name specifications
|
||||
.DE
|
||||
.bp
|
1719
bin/csh/USD.doc/csh.g
Normal file
1719
bin/csh/USD.doc/csh.g
Normal file
File diff suppressed because it is too large
Load diff
32
bin/csh/USD.doc/tabs
Normal file
32
bin/csh/USD.doc/tabs
Normal file
|
@ -0,0 +1,32 @@
|
|||
.\" $NetBSD: tabs,v 1.4 2003/08/07 09:05:09 agc Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1980, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. Neither the name of the University nor the names of its contributors
|
||||
.\" may be used to endorse or promote products derived from this software
|
||||
.\" without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)tabs 8.1 (Berkeley) 6/8/93
|
||||
.\"
|
||||
.ta 5n 10n 15n 20n 25n 30n 35n 40n 45n 50n 55n 60n 65n 70n 75n 80n
|
91
bin/csh/alloc.c
Normal file
91
bin/csh/alloc.c
Normal file
|
@ -0,0 +1,91 @@
|
|||
/* $NetBSD: alloc.c,v 1.13 2013/01/22 19:28:00 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1983, 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)alloc.c 8.1 (Berkeley) 5/31/93";
|
||||
#else
|
||||
__RCSID("$NetBSD: alloc.c,v 1.13 2013/01/22 19:28:00 christos Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "csh.h"
|
||||
#include "extern.h"
|
||||
|
||||
ptr_t
|
||||
Malloc(size_t n)
|
||||
{
|
||||
ptr_t ptr;
|
||||
|
||||
if ((ptr = malloc(n)) == (ptr_t) 0) {
|
||||
child++;
|
||||
stderror(ERR_NOMEM);
|
||||
}
|
||||
return (ptr);
|
||||
}
|
||||
|
||||
ptr_t
|
||||
Realloc(ptr_t p, size_t n)
|
||||
{
|
||||
ptr_t ptr;
|
||||
|
||||
if ((ptr = realloc(p, n)) == (ptr_t) 0) {
|
||||
child++;
|
||||
stderror(ERR_NOMEM);
|
||||
}
|
||||
return (ptr);
|
||||
}
|
||||
|
||||
ptr_t
|
||||
Calloc(size_t s, size_t n)
|
||||
{
|
||||
ptr_t ptr;
|
||||
|
||||
if ((ptr = calloc(s, n)) == (ptr_t) 0) {
|
||||
child++;
|
||||
stderror(ERR_NOMEM);
|
||||
}
|
||||
return (ptr);
|
||||
}
|
||||
|
||||
void
|
||||
Free(ptr_t p)
|
||||
{
|
||||
if (p)
|
||||
free(p);
|
||||
}
|
315
bin/csh/char.c
Normal file
315
bin/csh/char.c
Normal file
|
@ -0,0 +1,315 @@
|
|||
/* $NetBSD: char.c,v 1.10 2012/01/19 02:42:53 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1980, 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)char.c 8.1 (Berkeley) 5/31/93";
|
||||
#else
|
||||
__RCSID("$NetBSD: char.c,v 1.10 2012/01/19 02:42:53 christos Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include "char.h"
|
||||
|
||||
/* on default same as original map */
|
||||
unsigned short _cmap[256] = {
|
||||
/* 0 nul 1 soh 2 stx 3 etx */
|
||||
_CTR, _CTR, _CTR, _CTR,
|
||||
|
||||
/* 4 eot 5 enq 6 ack 7 bel */
|
||||
_CTR, _CTR, _CTR, _CTR,
|
||||
|
||||
/* 8 bs 9 ht 10 nl 11 vt */
|
||||
_CTR, _CTR|_SP|_META, _CTR|_NL|_META, _CTR,
|
||||
|
||||
/* 12 np 13 cr 14 so 15 si */
|
||||
_CTR, _CTR, _CTR, _CTR,
|
||||
|
||||
/* 16 dle 17 dc1 18 dc2 19 dc3 */
|
||||
_CTR, _CTR, _CTR, _CTR,
|
||||
|
||||
/* 20 dc4 21 nak 22 syn 23 etb */
|
||||
_CTR, _CTR, _CTR, _CTR,
|
||||
|
||||
/* 24 can 25 em 26 sub 27 esc */
|
||||
_CTR, _CTR, _CTR, _CTR,
|
||||
|
||||
/* 28 fs 29 gs 30 rs 31 us */
|
||||
_CTR, _CTR, _CTR, _CTR,
|
||||
|
||||
/* 32 sp 33 ! 34 " 35 # */
|
||||
_SP|_META, _PUN, _QF|_PUN, _META|_PUN,
|
||||
|
||||
/* 36 $ 37 % 38 & 39 ' */
|
||||
_DOL|_PUN, _PUN, _META|_CMD|_PUN,_QF|_PUN,
|
||||
|
||||
/* 40 ( 41 ) 42 * 43 + */
|
||||
_META|_CMD|_PUN,_META|_PUN, _GLOB|_PUN, _PUN,
|
||||
|
||||
/* 44 , 45 - 46 . 47 / */
|
||||
_PUN, _PUN, _PUN, _PUN,
|
||||
|
||||
/* 48 0 49 1 50 2 51 3 */
|
||||
_DIG|_XD, _DIG|_XD, _DIG|_XD, _DIG|_XD,
|
||||
|
||||
/* 52 4 53 5 54 6 55 7 */
|
||||
_DIG|_XD, _DIG|_XD, _DIG|_XD, _DIG|_XD,
|
||||
|
||||
/* 56 8 57 9 58 : 59 ; */
|
||||
_DIG|_XD, _DIG|_XD, _PUN, _META|_CMD|_PUN,
|
||||
|
||||
/* 60 < 61 = 62 > 63 ? */
|
||||
_META|_PUN, _PUN, _META|_PUN, _GLOB|_PUN,
|
||||
|
||||
/* 64 @ 65 A 66 B 67 C */
|
||||
_PUN, _LET|_UP|_XD, _LET|_UP|_XD, _LET|_UP|_XD,
|
||||
|
||||
/* 68 D 69 E 70 F 71 G */
|
||||
_LET|_UP|_XD, _LET|_UP|_XD, _LET|_UP|_XD, _LET|_UP,
|
||||
|
||||
/* 72 H 73 I 74 J 75 K */
|
||||
_LET|_UP, _LET|_UP, _LET|_UP, _LET|_UP,
|
||||
|
||||
/* 76 L 77 M 78 N 79 O */
|
||||
_LET|_UP, _LET|_UP, _LET|_UP, _LET|_UP,
|
||||
|
||||
/* 80 P 81 Q 82 R 83 S */
|
||||
_LET|_UP, _LET|_UP, _LET|_UP, _LET|_UP,
|
||||
|
||||
/* 84 T 85 U 86 V 87 W */
|
||||
_LET|_UP, _LET|_UP, _LET|_UP, _LET|_UP,
|
||||
|
||||
/* 88 X 89 Y 90 Z 91 [ */
|
||||
_LET|_UP, _LET|_UP, _LET|_UP, _GLOB|_PUN,
|
||||
|
||||
/* 92 \ 93 ] 94 ^ 95 _ */
|
||||
_ESC|_PUN, _PUN, _PUN, _PUN,
|
||||
|
||||
/* 96 ` 97 a 98 b 99 c */
|
||||
_QB|_GLOB|_META|_PUN, _LET|_LOW|_XD, _LET|_LOW|_XD, _LET|_LOW|_XD,
|
||||
|
||||
/* 100 d 101 e 102 f 103 g */
|
||||
_LET|_LOW|_XD, _LET|_LOW|_XD, _LET|_LOW|_XD, _LET|_LOW,
|
||||
|
||||
/* 104 h 105 i 106 j 107 k */
|
||||
_LET|_LOW, _LET|_LOW, _LET|_LOW, _LET|_LOW,
|
||||
|
||||
/* 108 l 109 m 110 n 111 o */
|
||||
_LET|_LOW, _LET|_LOW, _LET|_LOW, _LET|_LOW,
|
||||
|
||||
/* 112 p 113 q 114 r 115 s */
|
||||
_LET|_LOW, _LET|_LOW, _LET|_LOW, _LET|_LOW,
|
||||
|
||||
/* 116 t 117 u 118 v 119 w */
|
||||
_LET|_LOW, _LET|_LOW, _LET|_LOW, _LET|_LOW,
|
||||
|
||||
/* 120 x 121 y 122 z 123 { */
|
||||
_LET|_LOW, _LET|_LOW, _LET|_LOW, _GLOB|_PUN,
|
||||
|
||||
/* 124 | 125 } 126 ~ 127 del */
|
||||
_META|_CMD|_PUN,_PUN, _PUN, _CTR,
|
||||
|
||||
#ifdef SHORT_STRINGS
|
||||
/****************************************************************/
|
||||
/* 128 - 255 The below is supposedly ISO 8859/1 */
|
||||
/****************************************************************/
|
||||
/* 128 (undef) 129 (undef) 130 (undef) 131 (undef) */
|
||||
_CTR, _CTR, _CTR, _CTR,
|
||||
|
||||
/* 132 (undef) 133 (undef) 134 (undef) 135 (undef) */
|
||||
_CTR, _CTR, _CTR, _CTR,
|
||||
|
||||
/* 136 (undef) 137 (undef) 138 (undef) 139 (undef) */
|
||||
_CTR, _CTR, _CTR, _CTR,
|
||||
|
||||
/* 140 (undef) 141 (undef) 142 (undef) 143 (undef) */
|
||||
_CTR, _CTR, _CTR, _CTR,
|
||||
|
||||
/* 144 (undef) 145 (undef) 146 (undef) 147 (undef) */
|
||||
_CTR, _CTR, _CTR, _CTR,
|
||||
|
||||
/* 148 (undef) 149 (undef) 150 (undef) 151 (undef) */
|
||||
_CTR, _CTR, _CTR, _CTR,
|
||||
|
||||
/* 152 (undef) 153 (undef) 154 (undef) 155 (undef) */
|
||||
_CTR, _CTR, _CTR, _CTR,
|
||||
|
||||
/* 156 (undef) 157 (undef) 158 (undef) 159 (undef) */
|
||||
_CTR, _CTR, _CTR, _CTR,
|
||||
|
||||
/* 160 nobreakspace 161 exclamdown 162 cent 163 sterling */
|
||||
_PUN, /* XXX */ _PUN, _PUN, _PUN,
|
||||
|
||||
/* 164 currency 165 yen 166 brokenbar 167 section */
|
||||
_PUN, _PUN, _PUN, _PUN,
|
||||
|
||||
/* 168 diaeresis 169 copyright 170 ordfeminine 171 guillemotleft*/
|
||||
_PUN, _PUN, _PUN, _PUN,
|
||||
|
||||
/* 172 notsign 173 hyphen 174 registered 175 macron */
|
||||
_PUN, _PUN, _PUN, _PUN,
|
||||
|
||||
/* 176 degree 177 plusminus 178 twosuperior 179 threesuperior*/
|
||||
_PUN, _PUN, _PUN, _PUN,
|
||||
|
||||
/* 180 acute 181 mu 182 paragraph 183 periodcentered*/
|
||||
_PUN, _PUN, /*XXX*/ _PUN, _PUN,
|
||||
|
||||
/* 184 cedilla 185 onesuperior 186 masculine 187 guillemotright*/
|
||||
_PUN, _PUN, _PUN, _PUN,
|
||||
|
||||
/* 188 onequarter 189 onehalf 190 threequarters 191 questiondown*/
|
||||
_PUN, _PUN, _PUN, _PUN,
|
||||
|
||||
/* 192 Agrave 193 Aacute 194 Acircumflex 195 Atilde */
|
||||
_LET|_UP, _LET|_UP, _LET|_UP, _LET|_UP,
|
||||
|
||||
/* 196 Adiaeresis 197 Aring 198 AE 199 Ccedilla */
|
||||
_LET|_UP, _LET|_UP, _LET|_UP, _LET|_UP,
|
||||
|
||||
/* 200 Egrave 201 Eacute 202 Ecircumflex 203 Ediaeresis */
|
||||
_LET|_UP, _LET|_UP, _LET|_UP, _LET|_UP,
|
||||
|
||||
/* 204 Igrave 205 Iacute 206 Icircumflex 207 Idiaeresis */
|
||||
_LET|_UP, _LET|_UP, _LET|_UP, _LET|_UP,
|
||||
|
||||
/* 208 ETH 209 Ntilde 210 Ograve 211 Oacute */
|
||||
_LET|_UP, _LET|_UP, _LET|_UP, _LET|_UP,
|
||||
|
||||
/* 212 Ocircumflex 213 Otilde 214 Odiaeresis 215 multiply */
|
||||
_LET|_UP, _LET|_UP, _LET|_UP, _PUN,
|
||||
|
||||
/* 216 Ooblique 217 Ugrave 218 Uacute 219 Ucircumflex */
|
||||
_LET|_UP, _LET|_UP, _LET|_UP, _LET|_UP,
|
||||
|
||||
/* 220 Udiaeresis 221 Yacute 222 THORN 223 ssharp */
|
||||
_LET|_UP, _LET|_UP, _LET|_UP, _LET|_LOW,
|
||||
|
||||
/* 224 agrave 225 aacute 226 acircumflex 227 atilde */
|
||||
_LET|_LOW, _LET|_LOW, _LET|_LOW, _LET|_LOW,
|
||||
|
||||
/* 228 adiaeresis 229 aring 230 ae 231 ccedilla */
|
||||
_LET|_LOW, _LET|_LOW, _LET|_LOW, _LET|_LOW,
|
||||
|
||||
/* 232 egrave 233 eacute 234 ecircumflex 235 ediaeresis */
|
||||
_LET|_LOW, _LET|_LOW, _LET|_LOW, _LET|_LOW,
|
||||
|
||||
/* 236 igrave 237 iacute 238 icircumflex 239 idiaeresis */
|
||||
_LET|_LOW, _LET|_LOW, _LET|_LOW, _LET|_LOW,
|
||||
|
||||
/* 240 eth 241 ntilde 242 ograve 243 oacute */
|
||||
_LET|_LOW, _LET|_LOW, _LET|_LOW, _LET|_LOW,
|
||||
|
||||
/* 244 ocircumflex 245 otilde 246 odiaeresis 247 division */
|
||||
_LET|_LOW, _LET|_LOW, _LET|_LOW, _PUN,
|
||||
|
||||
/* 248 oslash 249 ugrave 250 uacute 251 ucircumflex */
|
||||
_LET|_LOW, _LET|_LOW, _LET|_LOW, _LET|_LOW,
|
||||
|
||||
/* 252 udiaeresis 253 yacute 254 thorn 255 ydiaeresis */
|
||||
_LET|_LOW, _LET|_LOW, _LET|_LOW, _LET|_LOW,
|
||||
#endif /* SHORT_STRINGS */
|
||||
};
|
||||
|
||||
#ifndef NLS
|
||||
/* _cmap_lower, _cmap_upper for ISO 8859/1 */
|
||||
|
||||
unsigned char _cmap_lower[256] = {
|
||||
0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007,
|
||||
0010, 0011, 0012, 0013, 0014, 0015, 0016, 0017,
|
||||
0020, 0021, 0022, 0023, 0024, 0025, 0026, 0027,
|
||||
0030, 0031, 0032, 0033, 0034, 0035, 0036, 0037,
|
||||
0040, 0041, 0042, 0043, 0044, 0045, 0046, 0047,
|
||||
0050, 0051, 0052, 0053, 0054, 0055, 0056, 0057,
|
||||
0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
|
||||
0070, 0071, 0072, 0073, 0074, 0075, 0076, 0077,
|
||||
0100, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
|
||||
0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157,
|
||||
0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167,
|
||||
0170, 0171, 0172, 0133, 0134, 0135, 0136, 0137,
|
||||
0140, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
|
||||
0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157,
|
||||
0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167,
|
||||
0170, 0171, 0172, 0173, 0174, 0175, 0176, 0177,
|
||||
0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
|
||||
0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217,
|
||||
0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227,
|
||||
0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237,
|
||||
0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
|
||||
0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
|
||||
0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
|
||||
0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
|
||||
0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
|
||||
0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
|
||||
0360, 0361, 0362, 0363, 0364, 0365, 0366, 0327,
|
||||
0370, 0371, 0372, 0373, 0374, 0375, 0376, 0337,
|
||||
0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
|
||||
0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
|
||||
0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
|
||||
0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377,
|
||||
};
|
||||
|
||||
unsigned char _cmap_upper[256] = {
|
||||
0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007,
|
||||
0010, 0011, 0012, 0013, 0014, 0015, 0016, 0017,
|
||||
0020, 0021, 0022, 0023, 0024, 0025, 0026, 0027,
|
||||
0030, 0031, 0032, 0033, 0034, 0035, 0036, 0037,
|
||||
0040, 0041, 0042, 0043, 0044, 0045, 0046, 0047,
|
||||
0050, 0051, 0052, 0053, 0054, 0055, 0056, 0057,
|
||||
0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
|
||||
0070, 0071, 0072, 0073, 0074, 0075, 0076, 0077,
|
||||
0100, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
|
||||
0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117,
|
||||
0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
|
||||
0130, 0131, 0132, 0133, 0134, 0135, 0136, 0137,
|
||||
0140, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
|
||||
0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117,
|
||||
0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
|
||||
0130, 0131, 0132, 0173, 0174, 0175, 0176, 0177,
|
||||
0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
|
||||
0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217,
|
||||
0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227,
|
||||
0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237,
|
||||
0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
|
||||
0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
|
||||
0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
|
||||
0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
|
||||
0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
|
||||
0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317,
|
||||
0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327,
|
||||
0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
|
||||
0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
|
||||
0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317,
|
||||
0320, 0321, 0322, 0323, 0324, 0325, 0326, 0367,
|
||||
0330, 0331, 0332, 0333, 0334, 0335, 0336, 0377,
|
||||
};
|
||||
#endif /* NLS */
|
100
bin/csh/char.h
Normal file
100
bin/csh/char.h
Normal file
|
@ -0,0 +1,100 @@
|
|||
/* $NetBSD: char.h,v 1.9 2012/01/19 02:42:53 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1980, 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)char.h 8.1 (Berkeley) 5/31/93
|
||||
*/
|
||||
|
||||
#ifndef _CHAR_H_
|
||||
#define _CHAR_H_
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
extern unsigned short _cmap[];
|
||||
|
||||
#ifndef NLS
|
||||
extern unsigned char _cmap_lower[], _cmap_upper[];
|
||||
|
||||
#endif
|
||||
|
||||
#define _QF 0x0001 /* '" (Forward quotes) */
|
||||
#define _QB 0x0002 /* ` (Backquote) */
|
||||
#define _SP 0x0004 /* space and tab */
|
||||
#define _NL 0x0008 /* \n */
|
||||
#define _META 0x0010 /* lex meta characters, sp #'`";&<>()|\t\n */
|
||||
#define _GLOB 0x0020 /* glob characters, *?{[` */
|
||||
#define _ESC 0x0040 /* \ */
|
||||
#define _DOL 0x0080 /* $ */
|
||||
#define _DIG 0x0100 /* 0-9 */
|
||||
#define _LET 0x0200 /* a-z, A-Z, _ */
|
||||
#define _UP 0x0400 /* A-Z */
|
||||
#define _LOW 0x0800 /* a-z */
|
||||
#define _XD 0x1000 /* 0-9, a-f, A-F */
|
||||
#define _CMD 0x2000 /* lex end of command chars, ;&(|` */
|
||||
#define _CTR 0x4000 /* control */
|
||||
#define _PUN 0x8000 /* punctuation */
|
||||
|
||||
#define cmap(c, bits) \
|
||||
(((c) & QUOTE) ? 0 : (_cmap[(unsigned char)(c)] & (bits)))
|
||||
|
||||
#define isglob(c) cmap(c, _GLOB)
|
||||
#define isspc(c) cmap(c, _SP)
|
||||
#define ismeta(c) cmap(c, _META)
|
||||
#define iscmdmeta(c) cmap(c, _CMD)
|
||||
#define letter(c) (((c) & QUOTE) ? 0 : \
|
||||
(isalpha((unsigned char) (c)) || (c) == '_'))
|
||||
#define alnum(c) (((c) & QUOTE) ? 0 : \
|
||||
(isalnum((unsigned char) (c)) || (c) == '_'))
|
||||
#ifdef NLS
|
||||
#define Isspace(c) (((c) & QUOTE) ? 0 : isspace((unsigned char) (c)))
|
||||
#define Isdigit(c) (((c) & QUOTE) ? 0 : isdigit((unsigned char) (c)))
|
||||
#define Isalpha(c) (((c) & QUOTE) ? 0 : isalpha((unsigned char) (c)))
|
||||
#define Islower(c) (((c) & QUOTE) ? 0 : islower((unsigned char) (c)))
|
||||
#define Isupper(c) (((c) & QUOTE) ? 0 : isupper((unsigned char) (c)))
|
||||
#define Tolower(c) (((c) & QUOTE) ? 0 : tolower((unsigned char) (c)))
|
||||
#define Toupper(c) (((c) & QUOTE) ? 0 : toupper((unsigned char) (c)))
|
||||
#define Isxdigit(c) (((c) & QUOTE) ? 0 : isxdigit((unsigned char) (c)))
|
||||
#define Isalnum(c) (((c) & QUOTE) ? 0 : isalnum((unsigned char) (c)))
|
||||
#define Iscntrl(c) (((c) & QUOTE) ? 0 : iscntrl((unsigned char) (c)))
|
||||
#define Isprint(c) (((c) & QUOTE) ? 0 : isprint((unsigned char) (c)))
|
||||
#else
|
||||
#define Isspace(c) cmap(c, _SP|_NL)
|
||||
#define Isdigit(c) cmap(c, _DIG)
|
||||
#define Isalpha(c) (cmap(c,_LET) && !(((c) & META) && AsciiOnly))
|
||||
#define Islower(c) (cmap(c,_LOW) && !(((c) & META) && AsciiOnly))
|
||||
#define Isupper(c) (cmap(c, _UP) && !(((c) & META) && AsciiOnly))
|
||||
#define Tolower(c) (_cmap_lower[(unsigned char)(c)])
|
||||
#define Toupper(c) (_cmap_upper[(unsigned char)(c)])
|
||||
#define Isxdigit(c) cmap(c, _XD)
|
||||
#define Isalnum(c) (cmap(c, _DIG|_LET) && !(((c) & META) && AsciiOnly))
|
||||
#define Iscntrl(c) (cmap(c,_CTR) && !(((c) & META) && AsciiOnly))
|
||||
#define Isprint(c) (!cmap(c,_CTR) && !(((c) & META) && AsciiOnly))
|
||||
#endif
|
||||
|
||||
#endif /* !_CHAR_H_ */
|
164
bin/csh/const.c
Normal file
164
bin/csh/const.c
Normal file
|
@ -0,0 +1,164 @@
|
|||
/* $NetBSD: const.c,v 1.10 2013/01/22 20:35:29 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)const.c 8.1 (Berkeley) 5/31/93";
|
||||
#else
|
||||
__RCSID("$NetBSD: const.c,v 1.10 2013/01/22 20:35:29 christos Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* tc.const.c: String constants for csh.
|
||||
*/
|
||||
|
||||
#include "csh.h"
|
||||
|
||||
Char STR0[] = { '0', '\0' };
|
||||
Char STR1[] = { '1', '\0' };
|
||||
Char STRHOME[] = { 'H', 'O', 'M', 'E', '\0' };
|
||||
Char STRLANG[] = { 'L', 'A', 'N', 'G', '\0' };
|
||||
Char STRLC_CTYPE[] = { 'L', 'C', '_', 'C', 'T', 'Y', 'P', 'E' ,'\0' };
|
||||
Char STRLOGNAME[] = { 'L', 'O', 'G', 'N', 'A', 'M', 'E', '\0' };
|
||||
Char STRLbrace[] = { '{', '\0' };
|
||||
Char STRLparen[] = { '(', '\0' };
|
||||
Char STRLparensp[] = { '(', ' ', '\0' };
|
||||
Char STRNULL[] = { '\0' };
|
||||
Char STRPATH[] = { 'P', 'A', 'T', 'H', '\0' };
|
||||
Char STRPWD[] = { 'P', 'W', 'D', '\0' };
|
||||
Char STRQNULL[] = { '\0' | QUOTE, '\0' };
|
||||
Char STRRbrace[] = { '}', '\0' };
|
||||
Char STRspRparen[] = { ' ', ')', '\0' };
|
||||
Char STRTERM[] = { 'T', 'E', 'R', 'M', '\0' };
|
||||
Char STRUSER[] = { 'U', 'S', 'E', 'R', '\0' };
|
||||
Char STRalias[] = { 'a', 'l', 'i', 'a', 's', '\0' };
|
||||
Char STRand[] = { '&', '\0' };
|
||||
Char STRand2[] = { '&', '&', '\0' };
|
||||
Char STRaout[] = { 'a', '.', 'o', 'u', 't', '\0' };
|
||||
Char STRargv[] = { 'a', 'r', 'g', 'v', '\0' };
|
||||
Char STRbang[] = { '!', '\0' };
|
||||
Char STRcaret[] = { '^', '\0' };
|
||||
Char STRcdpath[] = { 'c', 'd', 'p', 'a', 't', 'h', '\0' };
|
||||
Char STRcent2[] = { '%', '%', '\0' };
|
||||
Char STRcenthash[] = { '%', '#', '\0' };
|
||||
Char STRcentplus[] = { '%', '+', '\0' };
|
||||
Char STRcentminus[] = { '%', '-', '\0' };
|
||||
Char STRchase_symlinks[] = { 'c', 'h', 'a', 's', 'e', '_', 's', 'y', 'm', 'l',
|
||||
'i', 'n', 'k', 's', '\0' };
|
||||
Char STRchild[] = { 'c', 'h', 'i', 'l', 'd', '\0' };
|
||||
Char STRcolon[] = { ':', '\0' };
|
||||
Char STRcwd[] = { 'c', 'w', 'd', '\0' };
|
||||
Char STRdefault[] = { 'd', 'e', 'f', 'a', 'u', 'l', 't', '\0' };
|
||||
Char STRdot[] = { '.', '\0' };
|
||||
Char STRdotdotsl[] = { '.', '.', '/', '\0' };
|
||||
Char STRdotsl[] = { '.', '/', '\0' };
|
||||
Char STRecho[] = { 'e', 'c', 'h', 'o', '\0' };
|
||||
Char STRedit[] = { 'e', 'd', 'i', 't', '\0' };
|
||||
Char STRequal[] = { '=', '\0' };
|
||||
Char STRfakecom[] = { '{', ' ', '.', '.', '.', ' ', '}', '\0' };
|
||||
Char STRfakecom1[] = { '`', ' ', '.', '.', '.', ' ', '`', '\0' };
|
||||
Char STRfignore[] = { 'f', 'i', 'g', 'n', 'o', 'r', 'e', '\0' };
|
||||
#ifdef FILEC
|
||||
Char STRfilec[] = { 'f', 'i', 'l', 'e', 'c', '\0' };
|
||||
#endif /* FILEC */
|
||||
Char STRhistchars[] = { 'h', 'i', 's', 't', 'c', 'h', 'a', 'r', 's', '\0' };
|
||||
Char STRtildothist[] = { '~', '/', '.', 'h', 'i', 's', 't', 'o', 'r',
|
||||
'y', '\0' };
|
||||
Char STRhistfile[] = { 'h', 'i', 's', 't', 'f', 'i', 'l', 'e', '\0' };
|
||||
Char STRhistory[] = { 'h', 'i', 's', 't', 'o', 'r', 'y', '\0' };
|
||||
Char STRhome[] = { 'h', 'o', 'm', 'e', '\0' };
|
||||
Char STRignore_symlinks[] = { 'i', 'g', 'n', 'o', 'r', 'e', '_', 's', 'y', 'm',
|
||||
'l', 'i', 'n', 'k', 's', '\0' };
|
||||
Char STRignoreeof[] = { 'i', 'g', 'n', 'o', 'r', 'e', 'e', 'o', 'f', '\0' };
|
||||
Char STRjobs[] = { 'j', 'o', 'b', 's', '\0' };
|
||||
Char STRlistjobs[] = { 'l', 'i', 's', 't', 'j', 'o', 'b', 's', '\0' };
|
||||
Char STRlogout[] = { 'l', 'o', 'g', 'o', 'u', 't', '\0' };
|
||||
Char STRlong[] = { 'l', 'o', 'n', 'g', '\0' };
|
||||
Char STRmail[] = { 'm', 'a', 'i', 'l', '\0' };
|
||||
Char STRmh[] = { '-', 'h', '\0' };
|
||||
Char STRminus[] = { '-', '\0' };
|
||||
Char STRml[] = { '-', 'l', '\0' };
|
||||
Char STRmn[] = { '-', 'n', '\0' };
|
||||
Char STRmquestion[] = { '?' | QUOTE, ' ', '\0' };
|
||||
Char STRnice[] = { 'n', 'i', 'c', 'e', '\0' };
|
||||
Char STRnoambiguous[] = { 'n', 'o', 'a', 'm', 'b', 'i', 'g', 'u', 'o', 'u',
|
||||
's', '\0' };
|
||||
Char STRnobeep[] = { 'n', 'o', 'b', 'e', 'e', 'p', '\0' };
|
||||
Char STRnoclobber[] = { 'n', 'o', 'c', 'l', 'o', 'b', 'b', 'e', 'r', '\0' };
|
||||
Char STRnoglob[] = { 'n', 'o', 'g', 'l', 'o', 'b', '\0' };
|
||||
Char STRnohup[] = { 'n', 'o', 'h', 'u', 'p', '\0' };
|
||||
Char STRnonomatch[] = { 'n', 'o', 'n', 'o', 'm', 'a', 't', 'c', 'h', '\0' };
|
||||
Char STRnormal[] = { 'n', 'o', 'r', 'm', 'a', 'l', '\0' };
|
||||
Char STRnotify[] = { 'n', 'o', 't', 'i', 'f', 'y', '\0' };
|
||||
Char STRor[] = { '|', '\0' };
|
||||
Char STRor2[] = { '|', '|', '\0' };
|
||||
Char STRpath[] = { 'p', 'a', 't', 'h', '\0' };
|
||||
Char STRprintexitvalue[] = { 'p', 'r', 'i', 'n', 't', 'e', 'x', 'i', 't', 'v',
|
||||
'a', 'l', 'u', 'e', '\0' };
|
||||
Char STRprompt[] = { 'p', 'r', 'o', 'm', 'p', 't', '\0' };
|
||||
Char STRprompt2[] = { 'p', 'r', 'o', 'm', 'p', 't', '2', '\0' };
|
||||
Char STRpushdsilent[] = { 'p', 'u', 's', 'h', 'd', 's', 'i', 'l', 'e', 'n',
|
||||
't', '\0' };
|
||||
Char STRret[] = { '\n', '\0' };
|
||||
Char STRsavehist[] = { 's', 'a', 'v', 'e', 'h', 'i', 's', 't', '\0' };
|
||||
Char STRsemisp[] = { ';', ' ', '\0' };
|
||||
Char STRshell[] = { 's', 'h', 'e', 'l', 'l', '\0' };
|
||||
Char STRslash[] = { '/', '\0' };
|
||||
Char STRsldotcshrc[] = { '/', '.', 'c', 's', 'h', 'r', 'c', '\0' };
|
||||
Char STRsldotlogin[] = { '/', '.', 'l', 'o', 'g', 'i', 'n', '\0' };
|
||||
Char STRsldthist[] = { '/', '.', 'h', 'i', 's', 't', 'o', 'r', 'y', '\0' };
|
||||
Char STRsldtlogout[] = { '/', '.', 'l', 'o', 'g', 'o', 'u', 't', '\0' };
|
||||
Char STRsource[] = { 's', 'o', 'u', 'r', 'c', 'e', '\0' };
|
||||
Char STRsp3dots[] = { ' ', '.', '.', '.', '\0' };
|
||||
Char STRspLarrow2sp[] = { ' ', '<', '<', ' ', '\0' };
|
||||
Char STRspLarrowsp[] = { ' ', '<', ' ', '\0' };
|
||||
Char STRspRarrow[] = { ' ', '>', '\0' };
|
||||
Char STRspRarrow2[] = { ' ', '>', '>', '\0' };
|
||||
Char STRRparen[] = { ')', '\0' };
|
||||
Char STRspace[] = { ' ', '\0' };
|
||||
Char STRspand2sp[] = { ' ', '&', '&', ' ', '\0' };
|
||||
Char STRspor2sp[] = { ' ', '|', '|', ' ', '\0' };
|
||||
Char STRsporsp[] = { ' ', '|', ' ', '\0' };
|
||||
Char STRstar[] = { '*', '\0' };
|
||||
Char STRstatus[] = { 's', 't', 'a', 't', 'u', 's', '\0' };
|
||||
Char STRsymcent[] = { '%', ' ', '\0' };
|
||||
Char STRsymhash[] = { '#', ' ', '\0' };
|
||||
Char STRterm[] = { 't', 'e', 'r', 'm', '\0' };
|
||||
Char STRthen[] = { 't', 'h', 'e', 'n', '\0' };
|
||||
Char STRtilde[] = { '~', '\0' };
|
||||
Char STRtime[] = { 't', 'i', 'm', 'e', '\0' };
|
||||
Char STRtmpsh[] = { '/', 't', 'm', 'p', '/', 's', 'h', '\0' };
|
||||
Char STRunalias[] = { 'u', 'n', 'a', 'l', 'i', 'a', 's', '\0' };
|
||||
Char STRuser[] = { 'u', 's', 'e', 'r', '\0' };
|
||||
Char STRverbose[] = { 'v', 'e', 'r', 'b', 'o', 's', 'e', '\0' };
|
||||
Char STRwordchars[] = { 'w', 'o', 'r', 'd', 'c', 'h', 'a', 'r', 's', '\0' };
|
2293
bin/csh/csh.1
Normal file
2293
bin/csh/csh.1
Normal file
File diff suppressed because it is too large
Load diff
1401
bin/csh/csh.c
Normal file
1401
bin/csh/csh.c
Normal file
File diff suppressed because it is too large
Load diff
559
bin/csh/csh.h
Normal file
559
bin/csh/csh.h
Normal file
|
@ -0,0 +1,559 @@
|
|||
/* $NetBSD: csh.h,v 1.26 2013/07/16 17:47:43 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1980, 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)csh.h 8.1 (Berkeley) 5/31/93
|
||||
*/
|
||||
|
||||
#ifndef _CSH_H_
|
||||
#define _CSH_H_
|
||||
|
||||
/*
|
||||
* Fundamental definitions which may vary from system to system.
|
||||
*
|
||||
* BUFSIZE The i/o buffering size; also limits word size
|
||||
* MAILINTVL How often to mailcheck; more often is more expensive
|
||||
*/
|
||||
#ifndef BUFSIZE
|
||||
#define BUFSIZE 4096 /* default buffer size */
|
||||
#endif /* BUFSIZE */
|
||||
|
||||
#define FORKSLEEP 10 /* delay loop on non-interactive fork failure */
|
||||
#define MAILINTVL 600 /* 10 minutes */
|
||||
|
||||
/*
|
||||
* The shell moves std in/out/diag and the old std input away from units
|
||||
* 0, 1, and 2 so that it is easy to set up these standards for invoked
|
||||
* commands.
|
||||
*/
|
||||
#define FSHTTY 15 /* /dev/tty when manip pgrps */
|
||||
#define FSHIN 16 /* Preferred desc for shell input */
|
||||
#define FSHOUT 17 /* ... shell output */
|
||||
#define FSHERR 18 /* ... shell diagnostics */
|
||||
#define FOLDSTD 19 /* ... old std input */
|
||||
|
||||
#ifdef PROF
|
||||
#define xexit(n) done(n)
|
||||
#endif
|
||||
|
||||
#ifdef SHORT_STRINGS
|
||||
typedef short Char;
|
||||
|
||||
#define SAVE(a) (Strsave(str2short(a)))
|
||||
#else
|
||||
typedef char Char;
|
||||
|
||||
#define SAVE(a) (strsave(a))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Make sure a variable is not stored in a register by taking its address
|
||||
* This is used where variables might be clobbered by longjmp.
|
||||
*/
|
||||
#define UNREGISTER(a) (void) &a
|
||||
|
||||
typedef void *ioctl_t; /* Third arg of ioctl */
|
||||
|
||||
typedef void *ptr_t;
|
||||
|
||||
#include "const.h"
|
||||
#include "char.h"
|
||||
#include "errnum.h"
|
||||
|
||||
#define xmalloc(i) Malloc(i)
|
||||
#define xrealloc(p, i) Realloc(p, i)
|
||||
#define xcalloc(n, s) Calloc(n, s)
|
||||
#define xfree(p) Free(p)
|
||||
|
||||
#include <stdio.h>
|
||||
FILE *cshin, *cshout, *csherr;
|
||||
|
||||
#define isdir(d) (S_ISDIR(d.st_mode))
|
||||
|
||||
#define eq(a, b) (Strcmp(a, b) == 0)
|
||||
|
||||
/* globone() flags */
|
||||
#define G_ERROR 0 /* default action: error if multiple words */
|
||||
#define G_IGNORE 1 /* ignore the rest of the words */
|
||||
#define G_APPEND 2 /* make a sentence by cat'ing the words */
|
||||
|
||||
/*
|
||||
* Global flags
|
||||
*/
|
||||
int child; /* Child shell ... errors cause exit */
|
||||
int chkstop; /* Warned of stopped jobs... allow exit */
|
||||
int didfds; /* Have setup i/o fd's for child */
|
||||
int doneinp; /* EOF indicator after reset from readc */
|
||||
int exiterr; /* Exit if error or non-zero exit status */
|
||||
int haderr; /* Reset was because of an error */
|
||||
int havhash; /* path hashing is available */
|
||||
int intact; /* We are interactive... therefore prompt */
|
||||
int intty; /* Input is a tty */
|
||||
int justpr; /* Just print because of :p hist mod */
|
||||
int loginsh; /* We are a loginsh -> .login/.logout */
|
||||
int neednote; /* Need to pnotify() */
|
||||
int noexec; /* Don't execute, just syntax check */
|
||||
int pjobs; /* want to print jobs if interrupted */
|
||||
int setintr; /* Set interrupts on/off -> Wait intr... */
|
||||
int timflg; /* Time the next waited for command */
|
||||
|
||||
#ifdef FILEC
|
||||
extern int filec; /* doing filename expansion */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Global i/o info
|
||||
*/
|
||||
Char *arginp; /* Argument input for sh -c and internal `xx` */
|
||||
Char *ffile; /* Name of shell file for $0 */
|
||||
int onelflg; /* 2 -> need line for -t, 1 -> exit on read */
|
||||
|
||||
extern char *seterr; /* Error message from scanner/parser */
|
||||
Char *shtemp; /* Temp name for << shell files in /tmp */
|
||||
|
||||
#include <sys/resource.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
struct timespec time0; /* Time at which the shell started */
|
||||
struct rusage ru0;
|
||||
|
||||
/*
|
||||
* Miscellany
|
||||
*/
|
||||
time_t chktim; /* Time mail last checked */
|
||||
Char *doldol; /* Character pid for $$ */
|
||||
pid_t backpid; /* Pid of the last background process */
|
||||
gid_t egid, gid; /* Invokers gid */
|
||||
uid_t euid, uid; /* Invokers uid */
|
||||
int shpgrp; /* Pgrp of shell */
|
||||
int tpgrp; /* Terminal process group */
|
||||
|
||||
/* If tpgrp is -1, leave tty alone! */
|
||||
int opgrp; /* Initial pgrp and tty pgrp */
|
||||
|
||||
|
||||
/*
|
||||
* To be able to redirect i/o for builtins easily, the shell moves the i/o
|
||||
* descriptors it uses away from 0,1,2.
|
||||
* Ideally these should be in units which are closed across exec's
|
||||
* (this saves work) but for version 6, this is not usually possible.
|
||||
* The desired initial values for these descriptors are F{SHIN,...}.
|
||||
*/
|
||||
int SHIN; /* Current shell input (script) */
|
||||
int SHOUT; /* Shell output */
|
||||
int SHERR; /* Diagnostic output... shell errs go here */
|
||||
int OLDSTD; /* Old standard input (def for cmds) */
|
||||
|
||||
/*
|
||||
* Error control
|
||||
*
|
||||
* Errors in scanning and parsing set up an error message to be printed
|
||||
* at the end and complete. Other errors always cause a reset.
|
||||
* Because of source commands and .cshrc we need nested error catches.
|
||||
*/
|
||||
|
||||
#include <setjmp.h>
|
||||
jmp_buf reslab;
|
||||
|
||||
#define setexit() (setjmp(reslab))
|
||||
#define reset() longjmp(reslab, 1)
|
||||
/* Should use structure assignment here */
|
||||
#define getexit(a) (void)memcpy((a), reslab, sizeof reslab)
|
||||
#define resexit(a) (void)memcpy(reslab, (a), sizeof reslab)
|
||||
|
||||
Char *gointr; /* Label for an onintr transfer */
|
||||
|
||||
#include <signal.h>
|
||||
sig_t parintr; /* Parents interrupt catch */
|
||||
sig_t parterm; /* Parents terminate catch */
|
||||
|
||||
/*
|
||||
* Lexical definitions.
|
||||
*
|
||||
* All lexical space is allocated dynamically.
|
||||
* The eighth/sixteenth bit of characters is used to prevent recognition,
|
||||
* and eventually stripped.
|
||||
*/
|
||||
#define META 0x80
|
||||
#define ASCII 0x7f
|
||||
#ifdef SHORT_STRINGS
|
||||
#define CHAR ((Char)0xff)
|
||||
#define QUOTE ((Char)0x8000) /* 16nth char bit used for 'ing */
|
||||
#define TRIM ((Char)0x7fff) /* Mask to strip quote bit */
|
||||
#else
|
||||
#define CHAR ((Char)0x7f)
|
||||
#define QUOTE ((Char)0x80) /* Eighth char bit used for 'ing */
|
||||
#define TRIM ((Char)0x7f) /* Mask to strip quote bit */
|
||||
#endif
|
||||
|
||||
int AsciiOnly; /* If set only 7 bits is expected in characters */
|
||||
|
||||
/*
|
||||
* Each level of input has a buffered input structure.
|
||||
* There are one or more blocks of buffered input for each level,
|
||||
* exactly one if the input is seekable and tell is available.
|
||||
* In other cases, the shell buffers enough blocks to keep all loops
|
||||
* in the buffer.
|
||||
*/
|
||||
struct Bin {
|
||||
off_t Bfseekp; /* Seek pointer */
|
||||
off_t Bfbobp; /* Seekp of beginning of buffers */
|
||||
off_t Bfeobp; /* Seekp of end of buffers */
|
||||
int Bfblocks; /* Number of buffer blocks */
|
||||
Char **Bfbuf; /* The array of buffer blocks */
|
||||
} B;
|
||||
|
||||
/*
|
||||
* This structure allows us to seek inside aliases
|
||||
*/
|
||||
struct Ain {
|
||||
int type;
|
||||
#define I_SEEK -1 /* Invalid seek */
|
||||
#define A_SEEK 0 /* Alias seek */
|
||||
#define F_SEEK 1 /* File seek */
|
||||
#define E_SEEK 2 /* Eval seek */
|
||||
union {
|
||||
off_t _f_seek;
|
||||
Char* _c_seek;
|
||||
} fc;
|
||||
#define f_seek fc._f_seek
|
||||
#define c_seek fc._c_seek
|
||||
Char **a_seek;
|
||||
} ;
|
||||
extern int aret; /* What was the last character returned */
|
||||
#define SEEKEQ(a, b) ((a)->type == (b)->type && \
|
||||
(a)->f_seek == (b)->f_seek && \
|
||||
(a)->a_seek == (b)->a_seek)
|
||||
|
||||
#define fseekp B.Bfseekp
|
||||
#define fbobp B.Bfbobp
|
||||
#define feobp B.Bfeobp
|
||||
#define fblocks B.Bfblocks
|
||||
#define fbuf B.Bfbuf
|
||||
|
||||
/*
|
||||
* The shell finds commands in loops by reseeking the input
|
||||
* For whiles, in particular, it reseeks to the beginning of the
|
||||
* line the while was on; hence the while placement restrictions.
|
||||
*/
|
||||
struct Ain lineloc;
|
||||
|
||||
int cantell; /* Is current source tellable ? */
|
||||
|
||||
/*
|
||||
* Input lines are parsed into doubly linked circular
|
||||
* lists of words of the following form.
|
||||
*/
|
||||
struct wordent {
|
||||
Char *word;
|
||||
struct wordent *prev;
|
||||
struct wordent *next;
|
||||
};
|
||||
|
||||
/*
|
||||
* During word building, both in the initial lexical phase and
|
||||
* when expanding $ variable substitutions, expansion by `!' and `$'
|
||||
* must be inhibited when reading ahead in routines which are themselves
|
||||
* processing `!' and `$' expansion or after characters such as `\' or in
|
||||
* quotations. The following flags are passed to the getC routines
|
||||
* telling them which of these substitutions are appropriate for the
|
||||
* next character to be returned.
|
||||
*/
|
||||
#define DODOL 1
|
||||
#define DOEXCL 2
|
||||
#define DOALL DODOL|DOEXCL
|
||||
|
||||
/*
|
||||
* Labuf implements a general buffer for lookahead during lexical operations.
|
||||
* Text which is to be placed in the input stream can be stuck here.
|
||||
* We stick parsed ahead $ constructs during initial input,
|
||||
* process id's from `$$', and modified variable values (from qualifiers
|
||||
* during expansion in sh.dol.c) here.
|
||||
*/
|
||||
Char *lap;
|
||||
|
||||
/*
|
||||
* Parser structure
|
||||
*
|
||||
* Each command is parsed to a tree of command structures and
|
||||
* flags are set bottom up during this process, to be propagated down
|
||||
* as needed during the semantics/execution pass (sh.sem.c).
|
||||
*/
|
||||
struct command {
|
||||
int t_dtyp; /* Type of node */
|
||||
#define NODE_COMMAND 1 /* t_dcom <t_dlef >t_drit */
|
||||
#define NODE_PAREN 2 /* ( t_dspr ) <t_dlef >t_drit */
|
||||
#define NODE_PIPE 3 /* t_dlef | t_drit */
|
||||
#define NODE_LIST 4 /* t_dlef ; t_drit */
|
||||
#define NODE_OR 5 /* t_dlef || t_drit */
|
||||
#define NODE_AND 6 /* t_dlef && t_drit */
|
||||
int t_dflg; /* Flags, e.g. F_AMPERSAND|... */
|
||||
#define F_SAVE (F_NICE|F_TIME|F_NOHUP) /* save these when re-doing */
|
||||
|
||||
#define F_AMPERSAND (1<<0) /* executes in background */
|
||||
#define F_APPEND (1<<1) /* output is redirected >> */
|
||||
#define F_PIPEIN (1<<2) /* input is a pipe */
|
||||
#define F_PIPEOUT (1<<3) /* output is a pipe */
|
||||
#define F_NOFORK (1<<4) /* don't fork, last ()ized cmd */
|
||||
#define F_NOINTERRUPT (1<<5) /* should be immune from intr's */
|
||||
/* spare */
|
||||
#define F_STDERR (1<<7) /* redirect unit 2 with unit 1 */
|
||||
#define F_OVERWRITE (1<<8) /* output was ! */
|
||||
#define F_READ (1<<9) /* input redirection is << */
|
||||
#define F_REPEAT (1<<10) /* reexec aft if, repeat,... */
|
||||
#define F_NICE (1<<11) /* t_nice is meaningful */
|
||||
#define F_NOHUP (1<<12) /* nohup this command */
|
||||
#define F_TIME (1<<13) /* time this command */
|
||||
union {
|
||||
Char *T_dlef; /* Input redirect word */
|
||||
struct command *T_dcar; /* Left part of list/pipe */
|
||||
} L;
|
||||
union {
|
||||
Char *T_drit; /* Output redirect word */
|
||||
struct command *T_dcdr; /* Right part of list/pipe */
|
||||
} R;
|
||||
#define t_dlef L.T_dlef
|
||||
#define t_dcar L.T_dcar
|
||||
#define t_drit R.T_drit
|
||||
#define t_dcdr R.T_dcdr
|
||||
Char **t_dcom; /* Command/argument vector */
|
||||
struct command *t_dspr; /* Pointer to ()'d subtree */
|
||||
int t_nice;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* These are declared here because they want to be
|
||||
* initialized in sh.init.c (to allow them to be made readonly)
|
||||
*/
|
||||
|
||||
extern struct biltins {
|
||||
const char *bname;
|
||||
void (*bfunct)(Char **, struct command *);
|
||||
short minargs, maxargs;
|
||||
} bfunc[];
|
||||
|
||||
extern int nbfunc;
|
||||
extern int nsrchn;
|
||||
|
||||
extern struct srch {
|
||||
const char *s_name;
|
||||
short s_value;
|
||||
} srchn[];
|
||||
|
||||
/*
|
||||
* The keywords for the parser
|
||||
*/
|
||||
#define T_BREAK 0
|
||||
#define T_BRKSW 1
|
||||
#define T_CASE 2
|
||||
#define T_DEFAULT 3
|
||||
#define T_ELSE 4
|
||||
#define T_END 5
|
||||
#define T_ENDIF 6
|
||||
#define T_ENDSW 7
|
||||
#define T_EXIT 8
|
||||
#define T_FOREACH 9
|
||||
#define T_GOTO 10
|
||||
#define T_IF 11
|
||||
#define T_LABEL 12
|
||||
#define T_LET 13
|
||||
#define T_SET 14
|
||||
#define T_SWITCH 15
|
||||
#define T_TEST 16
|
||||
#define T_THEN 17
|
||||
#define T_WHILE 18
|
||||
|
||||
/*
|
||||
* Structure defining the existing while/foreach loops at this
|
||||
* source level. Loops are implemented by seeking back in the
|
||||
* input. For foreach (fe), the word list is attached here.
|
||||
*/
|
||||
struct whyle {
|
||||
struct Ain w_start; /* Point to restart loop */
|
||||
struct Ain w_end; /* End of loop (0 if unknown) */
|
||||
Char **w_fe, **w_fe0; /* Current/initial wordlist for fe */
|
||||
Char *w_fename; /* Name for fe */
|
||||
struct whyle *w_next; /* Next (more outer) loop */
|
||||
} *whyles;
|
||||
|
||||
/*
|
||||
* Variable structure
|
||||
*
|
||||
* Aliases and variables are stored in AVL balanced binary trees.
|
||||
*/
|
||||
struct varent {
|
||||
Char **vec; /* Array of words which is the value */
|
||||
Char *v_name; /* Name of variable/alias */
|
||||
struct varent *v_link[3]; /* The links, see below */
|
||||
int v_bal; /* Balance factor */
|
||||
} shvhed, aliases;
|
||||
|
||||
#define v_left v_link[0]
|
||||
#define v_right v_link[1]
|
||||
#define v_parent v_link[2]
|
||||
|
||||
#define adrof(v) adrof1(v, &shvhed)
|
||||
#define value(v) value1(v, &shvhed)
|
||||
|
||||
/*
|
||||
* The following are for interfacing redo substitution in
|
||||
* aliases to the lexical routines.
|
||||
*/
|
||||
struct wordent *alhistp; /* Argument list (first) */
|
||||
struct wordent *alhistt; /* Node after last in arg list */
|
||||
extern Char **alvec, *alvecp; /* The (remnants of) alias vector */
|
||||
|
||||
/*
|
||||
* Filename/command name expansion variables
|
||||
*/
|
||||
int gflag; /* After tglob -> is globbing needed? */
|
||||
|
||||
#define MAXVARLEN 30 /* Maximum number of char in a variable name */
|
||||
|
||||
/*
|
||||
* Variables for filename expansion
|
||||
*/
|
||||
extern long gargc; /* Number args in gargv */
|
||||
extern Char **gargv; /* Pointer to the (stack) arglist */
|
||||
|
||||
/*
|
||||
* Variables for command expansion.
|
||||
*/
|
||||
extern Char **pargv; /* Pointer to the argv list space */
|
||||
extern long pargc; /* Count of arguments in pargv */
|
||||
long pnleft; /* Number of chars left in pargs */
|
||||
Char *pargs; /* Pointer to start current word */
|
||||
Char *pargcp; /* Current index into pargs */
|
||||
|
||||
/*
|
||||
* History list
|
||||
*
|
||||
* Each history list entry contains an embedded wordlist
|
||||
* from the scanner, a number for the event, and a reference count
|
||||
* to aid in discarding old entries.
|
||||
*
|
||||
* Essentially "invisible" entries are put on the history list
|
||||
* when history substitution includes modifiers, and thrown away
|
||||
* at the next discarding since their event numbers are very negative.
|
||||
*/
|
||||
struct Hist {
|
||||
struct wordent Hlex;
|
||||
int Hnum;
|
||||
int Href;
|
||||
struct Hist *Hnext;
|
||||
} Histlist;
|
||||
|
||||
struct wordent paraml; /* Current lexical word list */
|
||||
int eventno; /* Next events number */
|
||||
int lastev; /* Last event reference (default) */
|
||||
|
||||
Char HIST; /* history invocation character */
|
||||
Char HISTSUB; /* auto-substitute character */
|
||||
|
||||
/*
|
||||
* strings.h:
|
||||
*/
|
||||
#ifndef SHORT_STRINGS
|
||||
#define Strchr(a, b) strchr(a, b)
|
||||
#define Strrchr(a, b) strrchr(a, b)
|
||||
#define Strcat(a, b) strcat(a, b)
|
||||
#define Strncat(a, b, c) strncat(a, b, c)
|
||||
#define Strcpy(a, b) strcpy(a, b)
|
||||
#define Strncpy(a, b, c) strncpy(a, b, c)
|
||||
#define Strlen(a) strlen(a)
|
||||
#define Strcmp(a, b) strcmp(a, b)
|
||||
#define Strncmp(a, b, c) strncmp(a, b, c)
|
||||
|
||||
#define Strspl(a, b) strspl(a, b)
|
||||
#define Strsave(a) strsave(a)
|
||||
#define Strend(a) strend(a)
|
||||
#define Strstr(a, b) strstr(a, b)
|
||||
|
||||
#define str2short(a) (a)
|
||||
#define blk2short(a) saveblk(a)
|
||||
#define short2blk(a) saveblk(a)
|
||||
#define short2str(a) strip(a)
|
||||
#else
|
||||
#define Strchr(a, b) s_strchr(a, b)
|
||||
#define Strrchr(a, b) s_strrchr(a, b)
|
||||
#define Strcat(a, b) s_strcat(a, b)
|
||||
#define Strncat(a, b, c) s_strncat(a, b, c)
|
||||
#define Strcpy(a, b) s_strcpy(a, b)
|
||||
#define Strncpy(a, b, c) s_strncpy(a, b, c)
|
||||
#define Strlen(a) s_strlen(a)
|
||||
#define Strcmp(a, b) s_strcmp(a, b)
|
||||
#define Strncmp(a, b, c) s_strncmp(a, b, c)
|
||||
|
||||
#define Strspl(a, b) s_strspl(a, b)
|
||||
#define Strsave(a) s_strsave(a)
|
||||
#define Strend(a) s_strend(a)
|
||||
#define Strstr(a, b) s_strstr(a, b)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* setname is a macro to save space (see sh.err.c)
|
||||
*/
|
||||
const char *bname;
|
||||
|
||||
#define setname(a) (bname = (a))
|
||||
|
||||
Char *Vsav;
|
||||
Char *Vdp;
|
||||
Char *Vexpath;
|
||||
char **Vt;
|
||||
|
||||
Char **evalvec;
|
||||
Char *evalp;
|
||||
|
||||
/* word_chars is set by default to WORD_CHARS but can be overridden by
|
||||
the worchars variable--if unset, reverts to WORD_CHARS */
|
||||
|
||||
Char *word_chars;
|
||||
|
||||
#define WORD_CHARS "*?_-.[]~=" /* default chars besides alnums in words */
|
||||
|
||||
Char *STR_SHELLPATH;
|
||||
|
||||
#include <paths.h>
|
||||
#ifdef _PATH_BSHELL
|
||||
Char *STR_BSHELL;
|
||||
#endif
|
||||
Char *STR_WORD_CHARS;
|
||||
Char **STR_environ;
|
||||
|
||||
#ifdef EDIT
|
||||
#include <histedit.h>
|
||||
EditLine *el;
|
||||
History *hi;
|
||||
#endif
|
||||
int editing;
|
||||
|
||||
#endif /* !_CSH_H_ */
|
901
bin/csh/dir.c
Normal file
901
bin/csh/dir.c
Normal file
|
@ -0,0 +1,901 @@
|
|||
/* $NetBSD: dir.c,v 1.30 2013/07/16 17:47:43 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1980, 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)dir.c 8.1 (Berkeley) 5/31/93";
|
||||
#else
|
||||
__RCSID("$NetBSD: dir.c,v 1.30 2013/07/16 17:47:43 christos Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "csh.h"
|
||||
#include "dir.h"
|
||||
#include "extern.h"
|
||||
|
||||
/* Directory management. */
|
||||
|
||||
static struct directory *dfind(Char *);
|
||||
static Char *dfollow(Char *);
|
||||
static void printdirs(void);
|
||||
static Char *dgoto(Char *);
|
||||
static void skipargs(Char ***, const char *);
|
||||
static void dnewcwd(struct directory *);
|
||||
static void dset(Char *);
|
||||
|
||||
struct directory dhead; /* "head" of loop */
|
||||
int printd; /* force name to be printed */
|
||||
|
||||
static int dirflag = 0;
|
||||
|
||||
/*
|
||||
* dinit - initialize current working directory
|
||||
*/
|
||||
void
|
||||
dinit(Char *hp)
|
||||
{
|
||||
static const char emsg[] = "csh: Trying to start from \"%s\"\n";
|
||||
char path[MAXPATHLEN];
|
||||
struct directory *dp;
|
||||
const char *ecp;
|
||||
Char *cp;
|
||||
|
||||
/* Don't believe the login shell home, because it may be a symlink */
|
||||
ecp = getcwd(path, MAXPATHLEN);
|
||||
if (ecp == NULL || *ecp == '\0') {
|
||||
(void)fprintf(csherr, "csh: %s\n", strerror(errno));
|
||||
if (hp && *hp) {
|
||||
ecp = short2str(hp);
|
||||
if (chdir(ecp) == -1)
|
||||
cp = NULL;
|
||||
else
|
||||
cp = Strsave(hp);
|
||||
(void)fprintf(csherr, emsg, vis_str(hp));
|
||||
}
|
||||
else
|
||||
cp = NULL;
|
||||
if (cp == NULL) {
|
||||
(void)fprintf(csherr, emsg, "/");
|
||||
if (chdir("/") == -1) {
|
||||
/* I am not even try to print an error message! */
|
||||
xexit(1);
|
||||
}
|
||||
cp = SAVE("/");
|
||||
}
|
||||
}
|
||||
else {
|
||||
struct stat swd, shp;
|
||||
|
||||
/*
|
||||
* See if $HOME is the working directory we got and use that
|
||||
*/
|
||||
if (hp && *hp &&
|
||||
stat(ecp, &swd) != -1 && stat(short2str(hp), &shp) != -1 &&
|
||||
swd.st_dev == shp.st_dev && swd.st_ino == shp.st_ino)
|
||||
cp = Strsave(hp);
|
||||
else {
|
||||
const char *cwd;
|
||||
|
||||
/*
|
||||
* use PWD if we have it (for subshells)
|
||||
*/
|
||||
if ((cwd = getenv("PWD")) != NULL) {
|
||||
if (stat(cwd, &shp) != -1 && swd.st_dev == shp.st_dev &&
|
||||
swd.st_ino == shp.st_ino)
|
||||
ecp = cwd;
|
||||
}
|
||||
cp = dcanon(SAVE(ecp), STRNULL);
|
||||
}
|
||||
}
|
||||
|
||||
dp = (struct directory *)xcalloc(1, sizeof(struct directory));
|
||||
dp->di_name = cp;
|
||||
dp->di_count = 0;
|
||||
dhead.di_next = dhead.di_prev = dp;
|
||||
dp->di_next = dp->di_prev = &dhead;
|
||||
printd = 0;
|
||||
dnewcwd(dp);
|
||||
}
|
||||
|
||||
static void
|
||||
dset(Char *dp)
|
||||
{
|
||||
Char **vec;
|
||||
|
||||
/*
|
||||
* Don't call set() directly cause if the directory contains ` or
|
||||
* other junk characters glob will fail.
|
||||
*/
|
||||
|
||||
vec = xmalloc((size_t)(2 * sizeof(Char **)));
|
||||
vec[0] = Strsave(dp);
|
||||
vec[1] = 0;
|
||||
setq(STRcwd, vec, &shvhed);
|
||||
Setenv(STRPWD, dp);
|
||||
}
|
||||
|
||||
#define DIR_LONG 1
|
||||
#define DIR_VERT 2
|
||||
#define DIR_LINE 4
|
||||
|
||||
static void
|
||||
skipargs(Char ***v, const char *str)
|
||||
{
|
||||
Char **n, *s;
|
||||
|
||||
n = *v;
|
||||
dirflag = 0;
|
||||
for (n++; *n != NULL && (*n)[0] == '-'; n++)
|
||||
for (s = &((*n)[1]); *s; s++)
|
||||
switch (*s) {
|
||||
case 'l':
|
||||
dirflag |= DIR_LONG;
|
||||
break;
|
||||
case 'n':
|
||||
dirflag |= DIR_LINE;
|
||||
break;
|
||||
case 'v':
|
||||
dirflag |= DIR_VERT;
|
||||
break;
|
||||
default:
|
||||
stderror(ERR_DIRUS, vis_str(**v), str);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
*v = n;
|
||||
}
|
||||
|
||||
/*
|
||||
* dodirs - list all directories in directory loop
|
||||
*/
|
||||
void
|
||||
/*ARGSUSED*/
|
||||
dodirs(Char **v, struct command *t)
|
||||
{
|
||||
skipargs(&v, "");
|
||||
|
||||
if (*v != NULL)
|
||||
stderror(ERR_DIRUS, "dirs", "");
|
||||
printdirs();
|
||||
}
|
||||
|
||||
static void
|
||||
printdirs(void)
|
||||
{
|
||||
struct directory *dp;
|
||||
Char *hp, *s;
|
||||
size_t cur, idx, len;
|
||||
|
||||
hp = value(STRhome);
|
||||
if (*hp == '\0')
|
||||
hp = NULL;
|
||||
dp = dcwd;
|
||||
idx = 0;
|
||||
cur = 0;
|
||||
do {
|
||||
if (dp == &dhead)
|
||||
continue;
|
||||
if (dirflag & DIR_VERT) {
|
||||
(void)fprintf(cshout, "%zu\t", idx++);
|
||||
cur = 0;
|
||||
}
|
||||
if (!(dirflag & DIR_LONG) && hp != NULL && !eq(hp, STRslash) &&
|
||||
(len = Strlen(hp), Strncmp(hp, dp->di_name, len) == 0) &&
|
||||
(dp->di_name[len] == '\0' || dp->di_name[len] == '/'))
|
||||
len = Strlen(s = (dp->di_name + len)) + 2;
|
||||
else
|
||||
len = Strlen(s = dp->di_name) + 1;
|
||||
|
||||
cur += len;
|
||||
if ((dirflag & DIR_LINE) && cur >= 80 - 1 && len < 80) {
|
||||
(void)fprintf(cshout, "\n");
|
||||
cur = len;
|
||||
}
|
||||
(void) fprintf(cshout, "%s%s%c", (s != dp->di_name)? "~" : "",
|
||||
vis_str(s), (dirflag & DIR_VERT) ? '\n' : ' ');
|
||||
} while ((dp = dp->di_prev) != dcwd);
|
||||
if (!(dirflag & DIR_VERT))
|
||||
(void)fprintf(cshout, "\n");
|
||||
}
|
||||
|
||||
void
|
||||
dtildepr(Char *home, Char *dir)
|
||||
{
|
||||
if (!eq(home, STRslash) && prefix(home, dir))
|
||||
(void)fprintf(cshout, "~%s", vis_str(dir + Strlen(home)));
|
||||
else
|
||||
(void)fprintf(cshout, "%s", vis_str(dir));
|
||||
}
|
||||
|
||||
void
|
||||
dtilde(void)
|
||||
{
|
||||
struct directory *d;
|
||||
|
||||
d = dcwd;
|
||||
do {
|
||||
if (d == &dhead)
|
||||
continue;
|
||||
d->di_name = dcanon(d->di_name, STRNULL);
|
||||
} while ((d = d->di_prev) != dcwd);
|
||||
|
||||
dset(dcwd->di_name);
|
||||
}
|
||||
|
||||
|
||||
/* dnormalize():
|
||||
* If the name starts with . or .. then we might need to normalize
|
||||
* it depending on the symbolic link flags
|
||||
*/
|
||||
Char *
|
||||
dnormalize(Char *cp)
|
||||
{
|
||||
#define UC (unsigned char)
|
||||
#define ISDOT(c) (UC(c)[0] == '.' && ((UC(c)[1] == '\0') || (UC(c)[1] == '/')))
|
||||
#define ISDOTDOT(c) (UC(c)[0] == '.' && ISDOT(&((c)[1])))
|
||||
if ((unsigned char) cp[0] == '/')
|
||||
return (Strsave(cp));
|
||||
|
||||
if (adrof(STRignore_symlinks)) {
|
||||
size_t dotdot = 0;
|
||||
Char *dp, *cwd;
|
||||
|
||||
cwd = xmalloc((size_t)((Strlen(dcwd->di_name) + 3) *
|
||||
sizeof(Char)));
|
||||
(void)Strcpy(cwd, dcwd->di_name);
|
||||
|
||||
/*
|
||||
* Ignore . and count ..'s
|
||||
*/
|
||||
while (*cp) {
|
||||
if (ISDOT(cp)) {
|
||||
if (*++cp)
|
||||
cp++;
|
||||
}
|
||||
else if (ISDOTDOT(cp)) {
|
||||
dotdot++;
|
||||
cp += 2;
|
||||
if (*cp)
|
||||
cp++;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
while (dotdot > 0) {
|
||||
dp = Strrchr(cwd, '/');
|
||||
if (dp) {
|
||||
*dp = '\0';
|
||||
dotdot--;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (*cp) {
|
||||
cwd[dotdot = Strlen(cwd)] = '/';
|
||||
cwd[dotdot + 1] = '\0';
|
||||
dp = Strspl(cwd, cp);
|
||||
xfree((ptr_t) cwd);
|
||||
return dp;
|
||||
}
|
||||
else {
|
||||
if (!*cwd) {
|
||||
cwd[0] = '/';
|
||||
cwd[1] = '\0';
|
||||
}
|
||||
return cwd;
|
||||
}
|
||||
}
|
||||
return Strsave(cp);
|
||||
}
|
||||
|
||||
/*
|
||||
* dochngd - implement chdir command.
|
||||
*/
|
||||
void
|
||||
/*ARGSUSED*/
|
||||
dochngd(Char **v, struct command *t)
|
||||
{
|
||||
struct directory *dp;
|
||||
Char *cp;
|
||||
|
||||
skipargs(&v, " [<dir>]");
|
||||
printd = 0;
|
||||
if (*v == NULL) {
|
||||
if ((cp = value(STRhome)) == NULL || *cp == 0)
|
||||
stderror(ERR_NAME | ERR_NOHOMEDIR);
|
||||
if (chdir(short2str(cp)) < 0)
|
||||
stderror(ERR_NAME | ERR_CANTCHANGE);
|
||||
cp = Strsave(cp);
|
||||
}
|
||||
else if (v[1] != NULL)
|
||||
stderror(ERR_NAME | ERR_TOOMANY);
|
||||
else if ((dp = dfind(*v)) != 0) {
|
||||
char *tmp;
|
||||
|
||||
printd = 1;
|
||||
if (chdir(tmp = short2str(dp->di_name)) < 0)
|
||||
stderror(ERR_SYSTEM, tmp, strerror(errno));
|
||||
dcwd->di_prev->di_next = dcwd->di_next;
|
||||
dcwd->di_next->di_prev = dcwd->di_prev;
|
||||
dfree(dcwd);
|
||||
dnewcwd(dp);
|
||||
return;
|
||||
}
|
||||
else
|
||||
cp = dfollow(*v);
|
||||
dp = (struct directory *)xcalloc(1, sizeof(struct directory));
|
||||
dp->di_name = cp;
|
||||
dp->di_count = 0;
|
||||
dp->di_next = dcwd->di_next;
|
||||
dp->di_prev = dcwd->di_prev;
|
||||
dp->di_prev->di_next = dp;
|
||||
dp->di_next->di_prev = dp;
|
||||
dfree(dcwd);
|
||||
dnewcwd(dp);
|
||||
}
|
||||
|
||||
static Char *
|
||||
dgoto(Char *cp)
|
||||
{
|
||||
Char *dp;
|
||||
|
||||
if (*cp != '/') {
|
||||
Char *p, *q;
|
||||
size_t cwdlen;
|
||||
|
||||
for (p = dcwd->di_name; *p++;)
|
||||
continue;
|
||||
if ((cwdlen = (size_t)(p - dcwd->di_name - 1)) == 1) /* root */
|
||||
cwdlen = 0;
|
||||
for (p = cp; *p++;)
|
||||
continue;
|
||||
dp = xmalloc((size_t)(cwdlen + (size_t)(p - cp) + 1) * sizeof(Char));
|
||||
for (p = dp, q = dcwd->di_name; (*p++ = *q++) != '\0';)
|
||||
continue;
|
||||
if (cwdlen)
|
||||
p[-1] = '/';
|
||||
else
|
||||
p--; /* don't add a / after root */
|
||||
for (q = cp; (*p++ = *q++) != '\0';)
|
||||
continue;
|
||||
xfree((ptr_t) cp);
|
||||
cp = dp;
|
||||
dp += cwdlen;
|
||||
}
|
||||
else
|
||||
dp = cp;
|
||||
|
||||
cp = dcanon(cp, dp);
|
||||
return cp;
|
||||
}
|
||||
|
||||
/*
|
||||
* dfollow - change to arg directory; fall back on cdpath if not valid
|
||||
*/
|
||||
static Char *
|
||||
dfollow(Char *cp)
|
||||
{
|
||||
char ebuf[MAXPATHLEN];
|
||||
struct varent *c;
|
||||
Char *dp;
|
||||
int serrno;
|
||||
|
||||
cp = globone(cp, G_ERROR);
|
||||
/*
|
||||
* if we are ignoring symlinks, try to fix relatives now.
|
||||
*/
|
||||
dp = dnormalize(cp);
|
||||
if (chdir(short2str(dp)) >= 0) {
|
||||
xfree((ptr_t) cp);
|
||||
return dgoto(dp);
|
||||
}
|
||||
else {
|
||||
xfree((ptr_t) dp);
|
||||
if (chdir(short2str(cp)) >= 0)
|
||||
return dgoto(cp);
|
||||
serrno = errno;
|
||||
}
|
||||
|
||||
if (cp[0] != '/' && !prefix(STRdotsl, cp) && !prefix(STRdotdotsl, cp)
|
||||
&& (c = adrof(STRcdpath))) {
|
||||
Char **cdp;
|
||||
Char *p;
|
||||
Char buf[MAXPATHLEN];
|
||||
|
||||
for (cdp = c->vec; *cdp; cdp++) {
|
||||
for (dp = buf, p = *cdp; (*dp++ = *p++) != '\0';)
|
||||
continue;
|
||||
dp[-1] = '/';
|
||||
for (p = cp; (*dp++ = *p++) != '\0';)
|
||||
continue;
|
||||
if (chdir(short2str(buf)) >= 0) {
|
||||
printd = 1;
|
||||
xfree((ptr_t) cp);
|
||||
cp = Strsave(buf);
|
||||
return dgoto(cp);
|
||||
}
|
||||
}
|
||||
}
|
||||
dp = value(cp);
|
||||
if ((dp[0] == '/' || dp[0] == '.') && chdir(short2str(dp)) >= 0) {
|
||||
xfree((ptr_t) cp);
|
||||
cp = Strsave(dp);
|
||||
printd = 1;
|
||||
return dgoto(cp);
|
||||
}
|
||||
(void)strcpy(ebuf, short2str(cp));
|
||||
xfree((ptr_t) cp);
|
||||
stderror(ERR_SYSTEM, ebuf, strerror(serrno));
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/*
|
||||
* dopushd - push new directory onto directory stack.
|
||||
* with no arguments exchange top and second.
|
||||
* with numeric argument (+n) bring it to top.
|
||||
*/
|
||||
void
|
||||
/*ARGSUSED*/
|
||||
dopushd(Char **v, struct command *t)
|
||||
{
|
||||
struct directory *dp;
|
||||
|
||||
skipargs(&v, " [<dir>|+<n>]");
|
||||
printd = 1;
|
||||
if (*v == NULL) {
|
||||
char *tmp;
|
||||
|
||||
if ((dp = dcwd->di_prev) == &dhead)
|
||||
dp = dhead.di_prev;
|
||||
if (dp == dcwd)
|
||||
stderror(ERR_NAME | ERR_NODIR);
|
||||
if (chdir(tmp = short2str(dp->di_name)) < 0)
|
||||
stderror(ERR_SYSTEM, tmp, strerror(errno));
|
||||
dp->di_prev->di_next = dp->di_next;
|
||||
dp->di_next->di_prev = dp->di_prev;
|
||||
dp->di_next = dcwd->di_next;
|
||||
dp->di_prev = dcwd;
|
||||
dcwd->di_next->di_prev = dp;
|
||||
dcwd->di_next = dp;
|
||||
}
|
||||
else if (v[1] != NULL)
|
||||
stderror(ERR_NAME | ERR_TOOMANY);
|
||||
else if ((dp = dfind(*v)) != NULL) {
|
||||
char *tmp;
|
||||
|
||||
if (chdir(tmp = short2str(dp->di_name)) < 0)
|
||||
stderror(ERR_SYSTEM, tmp, strerror(errno));
|
||||
}
|
||||
else {
|
||||
Char *ccp;
|
||||
|
||||
ccp = dfollow(*v);
|
||||
dp = (struct directory *)xcalloc(1, sizeof(struct directory));
|
||||
dp->di_name = ccp;
|
||||
dp->di_count = 0;
|
||||
dp->di_prev = dcwd;
|
||||
dp->di_next = dcwd->di_next;
|
||||
dcwd->di_next = dp;
|
||||
dp->di_next->di_prev = dp;
|
||||
}
|
||||
dnewcwd(dp);
|
||||
}
|
||||
|
||||
/*
|
||||
* dfind - find a directory if specified by numeric (+n) argument
|
||||
*/
|
||||
static struct directory *
|
||||
dfind(Char *cp)
|
||||
{
|
||||
struct directory *dp;
|
||||
Char *ep;
|
||||
int i;
|
||||
|
||||
if (*cp++ != '+')
|
||||
return (0);
|
||||
for (ep = cp; Isdigit(*ep); ep++)
|
||||
continue;
|
||||
if (*ep)
|
||||
return (0);
|
||||
i = getn(cp);
|
||||
if (i <= 0)
|
||||
return (0);
|
||||
for (dp = dcwd; i != 0; i--) {
|
||||
if ((dp = dp->di_prev) == &dhead)
|
||||
dp = dp->di_prev;
|
||||
if (dp == dcwd)
|
||||
stderror(ERR_NAME | ERR_DEEP);
|
||||
}
|
||||
return (dp);
|
||||
}
|
||||
|
||||
/*
|
||||
* dopopd - pop a directory out of the directory stack
|
||||
* with a numeric argument just discard it.
|
||||
*/
|
||||
void
|
||||
/*ARGSUSED*/
|
||||
dopopd(Char **v, struct command *t)
|
||||
{
|
||||
struct directory *dp, *p = NULL;
|
||||
|
||||
skipargs(&v, " [+<n>]");
|
||||
printd = 1;
|
||||
if (*v == NULL)
|
||||
dp = dcwd;
|
||||
else if (v[1] != NULL)
|
||||
stderror(ERR_NAME | ERR_TOOMANY);
|
||||
else if ((dp = dfind(*v)) == 0)
|
||||
stderror(ERR_NAME | ERR_BADDIR);
|
||||
if (dp->di_prev == &dhead && dp->di_next == &dhead)
|
||||
stderror(ERR_NAME | ERR_EMPTY);
|
||||
if (dp == dcwd) {
|
||||
char *tmp;
|
||||
|
||||
if ((p = dp->di_prev) == &dhead)
|
||||
p = dhead.di_prev;
|
||||
if (chdir(tmp = short2str(p->di_name)) < 0)
|
||||
stderror(ERR_SYSTEM, tmp, strerror(errno));
|
||||
}
|
||||
dp->di_prev->di_next = dp->di_next;
|
||||
dp->di_next->di_prev = dp->di_prev;
|
||||
if (dp == dcwd)
|
||||
dnewcwd(p);
|
||||
else {
|
||||
printdirs();
|
||||
}
|
||||
dfree(dp);
|
||||
}
|
||||
|
||||
/*
|
||||
* dfree - free the directory (or keep it if it still has ref count)
|
||||
*/
|
||||
void
|
||||
dfree(struct directory *dp)
|
||||
{
|
||||
|
||||
if (dp->di_count != 0) {
|
||||
dp->di_next = dp->di_prev = 0;
|
||||
}
|
||||
else {
|
||||
xfree((char *) dp->di_name);
|
||||
xfree((ptr_t) dp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* dcanon - canonicalize the pathname, removing excess ./ and ../ etc.
|
||||
* we are of course assuming that the file system is standardly
|
||||
* constructed (always have ..'s, directories have links)
|
||||
*/
|
||||
Char *
|
||||
dcanon(Char *cp, Char *p)
|
||||
{
|
||||
Char slink[MAXPATHLEN];
|
||||
char tlink[MAXPATHLEN];
|
||||
Char *newcp, *sp;
|
||||
Char *p1, *p2; /* general purpose */
|
||||
ssize_t cc;
|
||||
size_t len;
|
||||
int slash;
|
||||
|
||||
/*
|
||||
* christos: if the path given does not start with a slash prepend cwd. If
|
||||
* cwd does not start with a path or the result would be too long abort().
|
||||
*/
|
||||
if (*cp != '/') {
|
||||
Char tmpdir[MAXPATHLEN];
|
||||
|
||||
p1 = value(STRcwd);
|
||||
if (p1 == NULL || *p1 != '/')
|
||||
abort();
|
||||
if (Strlen(p1) + Strlen(cp) + 1 >= MAXPATHLEN)
|
||||
abort();
|
||||
(void)Strcpy(tmpdir, p1);
|
||||
(void)Strcat(tmpdir, STRslash);
|
||||
(void)Strcat(tmpdir, cp);
|
||||
xfree((ptr_t) cp);
|
||||
cp = p = Strsave(tmpdir);
|
||||
}
|
||||
|
||||
while (*p) { /* for each component */
|
||||
sp = p; /* save slash address */
|
||||
while (*++p == '/') /* flush extra slashes */
|
||||
continue;
|
||||
if (p != ++sp)
|
||||
for (p1 = sp, p2 = p; (*p1++ = *p2++) != '\0';)
|
||||
continue;
|
||||
p = sp; /* save start of component */
|
||||
slash = 0;
|
||||
while (*++p) /* find next slash or end of path */
|
||||
if (*p == '/') {
|
||||
slash = 1;
|
||||
*p = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (*sp == '\0') { /* if component is null */
|
||||
if (--sp == cp) /* if path is one char (i.e. /) */
|
||||
break;
|
||||
else
|
||||
*sp = '\0';
|
||||
} else if (sp[0] == '.' && sp[1] == 0) {
|
||||
if (slash) {
|
||||
for (p1 = sp, p2 = p + 1; (*p1++ = *p2++) != '\0';)
|
||||
continue;
|
||||
p = --sp;
|
||||
}
|
||||
else if (--sp != cp)
|
||||
*sp = '\0';
|
||||
}
|
||||
else if (sp[0] == '.' && sp[1] == '.' && sp[2] == 0) {
|
||||
/*
|
||||
* We have something like "yyy/xxx/..", where "yyy" can be null or
|
||||
* a path starting at /, and "xxx" is a single component. Before
|
||||
* compressing "xxx/..", we want to expand "yyy/xxx", if it is a
|
||||
* symbolic link.
|
||||
*/
|
||||
*--sp = 0; /* form the pathname for readlink */
|
||||
if (sp != cp && !adrof(STRignore_symlinks) &&
|
||||
(cc = readlink(short2str(cp), tlink,
|
||||
sizeof(tlink) - 1)) >= 0) {
|
||||
tlink[cc] = '\0';
|
||||
(void)Strcpy(slink, str2short(tlink));
|
||||
|
||||
if (slash)
|
||||
*p = '/';
|
||||
/*
|
||||
* Point p to the '/' in "/..", and restore the '/'.
|
||||
*/
|
||||
*(p = sp) = '/';
|
||||
/*
|
||||
* find length of p
|
||||
*/
|
||||
for (p1 = p; *p1++;)
|
||||
continue;
|
||||
if (*slink != '/') {
|
||||
/*
|
||||
* Relative path, expand it between the "yyy/" and the
|
||||
* "/..". First, back sp up to the character past "yyy/".
|
||||
*/
|
||||
while (*--sp != '/')
|
||||
continue;
|
||||
sp++;
|
||||
*sp = 0;
|
||||
/*
|
||||
* New length is "yyy/" + slink + "/.." and rest
|
||||
*/
|
||||
p1 = newcp = xmalloc(
|
||||
(size_t)((sp - cp) + cc + (p1 - p)) * sizeof(Char));
|
||||
/*
|
||||
* Copy new path into newcp
|
||||
*/
|
||||
for (p2 = cp; (*p1++ = *p2++) != '\0';)
|
||||
continue;
|
||||
for (p1--, p2 = slink; (*p1++ = *p2++) != '\0';)
|
||||
continue;
|
||||
for (p1--, p2 = p; (*p1++ = *p2++) != '\0';)
|
||||
continue;
|
||||
/*
|
||||
* Restart canonicalization at expanded "/xxx".
|
||||
*/
|
||||
p = sp - cp - 1 + newcp;
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* New length is slink + "/.." and rest
|
||||
*/
|
||||
p1 = newcp = xmalloc(
|
||||
(size_t)(cc + (p1 - p)) * sizeof(Char));
|
||||
/*
|
||||
* Copy new path into newcp
|
||||
*/
|
||||
for (p2 = slink; (*p1++ = *p2++) != '\0';)
|
||||
continue;
|
||||
for (p1--, p2 = p; (*p1++ = *p2++) != '\0';)
|
||||
continue;
|
||||
/*
|
||||
* Restart canonicalization at beginning
|
||||
*/
|
||||
p = newcp;
|
||||
}
|
||||
xfree((ptr_t) cp);
|
||||
cp = newcp;
|
||||
continue; /* canonicalize the link */
|
||||
}
|
||||
*sp = '/';
|
||||
if (sp != cp)
|
||||
while (*--sp != '/')
|
||||
continue;
|
||||
if (slash) {
|
||||
for (p1 = sp + 1, p2 = p + 1; (*p1++ = *p2++) != '\0';)
|
||||
continue;
|
||||
p = sp;
|
||||
}
|
||||
else if (cp == sp)
|
||||
*++sp = '\0';
|
||||
else
|
||||
*sp = '\0';
|
||||
}
|
||||
else { /* normal dir name (not . or .. or nothing) */
|
||||
|
||||
if (sp != cp && adrof(STRchase_symlinks) &&
|
||||
!adrof(STRignore_symlinks) &&
|
||||
(cc = readlink(short2str(cp), tlink, sizeof(tlink)-1)) >= 0) {
|
||||
tlink[cc] = '\0';
|
||||
(void)Strcpy(slink, str2short(tlink));
|
||||
|
||||
/*
|
||||
* restore the '/'.
|
||||
*/
|
||||
if (slash)
|
||||
*p = '/';
|
||||
|
||||
/*
|
||||
* point sp to p (rather than backing up).
|
||||
*/
|
||||
sp = p;
|
||||
|
||||
/*
|
||||
* find length of p
|
||||
*/
|
||||
for (p1 = p; *p1++;)
|
||||
continue;
|
||||
if (*slink != '/') {
|
||||
/*
|
||||
* Relative path, expand it between the "yyy/" and the
|
||||
* remainder. First, back sp up to the character past
|
||||
* "yyy/".
|
||||
*/
|
||||
while (*--sp != '/')
|
||||
continue;
|
||||
sp++;
|
||||
*sp = 0;
|
||||
/*
|
||||
* New length is "yyy/" + slink + "/.." and rest
|
||||
*/
|
||||
p1 = newcp = xmalloc(
|
||||
(size_t)((sp - cp) + cc + (p1 - p)) * sizeof(Char));
|
||||
/*
|
||||
* Copy new path into newcp
|
||||
*/
|
||||
for (p2 = cp; (*p1++ = *p2++) != '\0';)
|
||||
continue;
|
||||
for (p1--, p2 = slink; (*p1++ = *p2++) != '\0';)
|
||||
continue;
|
||||
for (p1--, p2 = p; (*p1++ = *p2++) != '\0';)
|
||||
continue;
|
||||
/*
|
||||
* Restart canonicalization at expanded "/xxx".
|
||||
*/
|
||||
p = sp - cp - 1 + newcp;
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* New length is slink + the rest
|
||||
*/
|
||||
p1 = newcp = xmalloc(
|
||||
(size_t)(cc + (p1 - p)) * sizeof(Char));
|
||||
/*
|
||||
* Copy new path into newcp
|
||||
*/
|
||||
for (p2 = slink; (*p1++ = *p2++) != '\0';)
|
||||
continue;
|
||||
for (p1--, p2 = p; (*p1++ = *p2++) != '\0';)
|
||||
continue;
|
||||
/*
|
||||
* Restart canonicalization at beginning
|
||||
*/
|
||||
p = newcp;
|
||||
}
|
||||
xfree((ptr_t) cp);
|
||||
cp = newcp;
|
||||
continue; /* canonicalize the link */
|
||||
}
|
||||
if (slash)
|
||||
*p = '/';
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* fix home...
|
||||
*/
|
||||
p1 = value(STRhome);
|
||||
len = Strlen(p1);
|
||||
/*
|
||||
* See if we're not in a subdir of STRhome
|
||||
*/
|
||||
if (p1 && *p1 == '/' &&
|
||||
(Strncmp(p1, cp, len) != 0 || (cp[len] != '/' && cp[len] != '\0'))) {
|
||||
static ino_t home_ino;
|
||||
static dev_t home_dev = NODEV;
|
||||
static Char *home_ptr = NULL;
|
||||
struct stat statbuf;
|
||||
|
||||
/*
|
||||
* Get dev and ino of STRhome
|
||||
*/
|
||||
if (home_ptr != p1 &&
|
||||
stat(short2str(p1), &statbuf) != -1) {
|
||||
home_dev = statbuf.st_dev;
|
||||
home_ino = statbuf.st_ino;
|
||||
home_ptr = p1;
|
||||
}
|
||||
/*
|
||||
* Start comparing dev & ino backwards
|
||||
*/
|
||||
p2 = Strcpy(slink, cp);
|
||||
for (sp = NULL; *p2 && stat(short2str(p2), &statbuf) != -1;) {
|
||||
if (statbuf.st_dev == home_dev &&
|
||||
statbuf.st_ino == home_ino) {
|
||||
sp = (Char *) - 1;
|
||||
break;
|
||||
}
|
||||
if ((sp = Strrchr(p2, '/')) != NULL)
|
||||
*sp = '\0';
|
||||
}
|
||||
/*
|
||||
* See if we found it
|
||||
*/
|
||||
if (*p2 && sp == (Char *) -1) {
|
||||
/*
|
||||
* Use STRhome to make '~' work
|
||||
*/
|
||||
newcp = Strspl(p1, cp + Strlen(p2));
|
||||
xfree((ptr_t) cp);
|
||||
cp = newcp;
|
||||
}
|
||||
}
|
||||
return cp;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* dnewcwd - make a new directory in the loop the current one
|
||||
*/
|
||||
static void
|
||||
dnewcwd(struct directory *dp)
|
||||
{
|
||||
dcwd = dp;
|
||||
dset(dcwd->di_name);
|
||||
if (printd && !(adrof(STRpushdsilent)))
|
||||
printdirs();
|
||||
}
|
48
bin/csh/dir.h
Normal file
48
bin/csh/dir.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/* $NetBSD: dir.h,v 1.8 2003/08/07 09:05:04 agc Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1980, 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)dir.h 8.1 (Berkeley) 5/31/93
|
||||
*/
|
||||
|
||||
#ifndef _DIR_H_
|
||||
#define _DIR_H_
|
||||
|
||||
/*
|
||||
* Structure for entries in directory stack.
|
||||
*/
|
||||
struct directory {
|
||||
struct directory *di_next; /* next in loop */
|
||||
struct directory *di_prev; /* prev in loop */
|
||||
unsigned short *di_count; /* refcount of processes */
|
||||
Char *di_name; /* actual name */
|
||||
};
|
||||
struct directory *dcwd; /* the one we are in now */
|
||||
|
||||
#endif /* !_DIR_H_ */
|
968
bin/csh/dol.c
Normal file
968
bin/csh/dol.c
Normal file
|
@ -0,0 +1,968 @@
|
|||
/* $NetBSD: dol.c,v 1.29 2013/07/16 17:47:43 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1980, 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)dol.c 8.1 (Berkeley) 5/31/93";
|
||||
#else
|
||||
__RCSID("$NetBSD: dol.c,v 1.29 2013/07/16 17:47:43 christos Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "csh.h"
|
||||
#include "extern.h"
|
||||
|
||||
/*
|
||||
* These routines perform variable substitution and quoting via ' and ".
|
||||
* To this point these constructs have been preserved in the divided
|
||||
* input words. Here we expand variables and turn quoting via ' and " into
|
||||
* QUOTE bits on characters (which prevent further interpretation).
|
||||
* If the `:q' modifier was applied during history expansion, then
|
||||
* some QUOTEing may have occurred already, so we dont "trim()" here.
|
||||
*/
|
||||
|
||||
static int Dpeekc, Dpeekrd; /* Peeks for DgetC and Dreadc */
|
||||
static Char *Dcp, **Dvp; /* Input vector for Dreadc */
|
||||
|
||||
#define DEOF -1
|
||||
#define unDgetC(c) Dpeekc = c
|
||||
#define QUOTES (_QF|_QB|_ESC) /* \ ' " ` */
|
||||
|
||||
/*
|
||||
* The following variables give the information about the current
|
||||
* $ expansion, recording the current word position, the remaining
|
||||
* words within this expansion, the count of remaining words, and the
|
||||
* information about any : modifier which is being applied.
|
||||
*/
|
||||
#define MAXWLEN (BUFSIZE - 4)
|
||||
#define MAXMOD MAXWLEN /* This cannot overflow */
|
||||
static Char dolmod[MAXMOD]; /* : modifier character */
|
||||
static Char *dolp; /* Remaining chars from this word */
|
||||
static Char **dolnxt; /* Further words */
|
||||
static int dolcnt; /* Count of further words */
|
||||
static int dolnmod; /* Number of modifiers */
|
||||
static int dolmcnt; /* :gx -> 10000, else 1 */
|
||||
static int dolwcnt; /* :wx -> 10000, else 1 */
|
||||
|
||||
static void Dfix2(Char **);
|
||||
static Char *Dpack(Char *, Char *);
|
||||
static int Dword(void);
|
||||
__dead static void dolerror(Char *);
|
||||
static int DgetC(int);
|
||||
static void Dgetdol(void);
|
||||
static void fixDolMod(void);
|
||||
static void setDolp(Char *);
|
||||
static void unDredc(int);
|
||||
static int Dredc(void);
|
||||
static void Dtestq(int);
|
||||
|
||||
|
||||
/*
|
||||
* Fix up the $ expansions and quotations in the
|
||||
* argument list to command t.
|
||||
*/
|
||||
void
|
||||
Dfix(struct command *t)
|
||||
{
|
||||
Char *p, **pp;
|
||||
|
||||
if (noexec)
|
||||
return;
|
||||
/* Note that t_dcom isn't trimmed thus !...:q's aren't lost */
|
||||
for (pp = t->t_dcom; (p = *pp++) != NULL;)
|
||||
for (; *p; p++) {
|
||||
if (cmap(*p, _DOL | QUOTES)) { /* $, \, ', ", ` */
|
||||
Dfix2(t->t_dcom); /* found one */
|
||||
blkfree(t->t_dcom);
|
||||
t->t_dcom = gargv;
|
||||
gargv = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* $ substitute one word, for i/o redirection
|
||||
*/
|
||||
Char *
|
||||
Dfix1(Char *cp)
|
||||
{
|
||||
Char *Dv[2];
|
||||
|
||||
if (noexec)
|
||||
return (0);
|
||||
Dv[0] = cp;
|
||||
Dv[1] = NULL;
|
||||
Dfix2(Dv);
|
||||
if (gargc != 1) {
|
||||
setname(vis_str(cp));
|
||||
stderror(ERR_NAME | ERR_AMBIG);
|
||||
}
|
||||
cp = Strsave(gargv[0]);
|
||||
blkfree(gargv), gargv = 0;
|
||||
return (cp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Subroutine to do actual fixing after state initialization.
|
||||
*/
|
||||
static void
|
||||
Dfix2(Char **v)
|
||||
{
|
||||
ginit(); /* Initialize glob's area pointers */
|
||||
Dvp = v;
|
||||
Dcp = STRNULL; /* Setup input vector for Dreadc */
|
||||
unDgetC(0);
|
||||
unDredc(0); /* Clear out any old peeks (at error) */
|
||||
dolp = 0;
|
||||
dolcnt = 0; /* Clear out residual $ expands (...) */
|
||||
while (Dword())
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Pack up more characters in this word
|
||||
*/
|
||||
static Char *
|
||||
Dpack(Char *wbuf, Char *wp)
|
||||
{
|
||||
int c;
|
||||
ptrdiff_t i;
|
||||
|
||||
i = MAXWLEN - (wp - wbuf);
|
||||
for (;;) {
|
||||
c = DgetC(DODOL);
|
||||
if (c == '\\') {
|
||||
c = DgetC(0);
|
||||
if (c == DEOF) {
|
||||
unDredc(c);
|
||||
*wp = 0;
|
||||
Gcat(STRNULL, wbuf);
|
||||
return (NULL);
|
||||
}
|
||||
if (c == '\n')
|
||||
c = ' ';
|
||||
else
|
||||
c |= QUOTE;
|
||||
}
|
||||
if (c == DEOF) {
|
||||
unDredc(c);
|
||||
*wp = 0;
|
||||
Gcat(STRNULL, wbuf);
|
||||
return (NULL);
|
||||
}
|
||||
if (cmap(c, _SP | _NL | _QF | _QB)) { /* sp \t\n'"` */
|
||||
unDgetC(c);
|
||||
if (cmap(c, QUOTES))
|
||||
return (wp);
|
||||
*wp++ = 0;
|
||||
Gcat(STRNULL, wbuf);
|
||||
return (NULL);
|
||||
}
|
||||
if (--i <= 0)
|
||||
stderror(ERR_WTOOLONG);
|
||||
*wp++ = (Char)c;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a word. This routine is analogous to the routine
|
||||
* word() in sh.lex.c for the main lexical input. One difference
|
||||
* here is that we don't get a newline to terminate our expansion.
|
||||
* Rather, DgetC will return a DEOF when we hit the end-of-input.
|
||||
*/
|
||||
static int
|
||||
Dword(void)
|
||||
{
|
||||
Char wbuf[BUFSIZE], *wp;
|
||||
int c, c1;
|
||||
ptrdiff_t i;
|
||||
int dolflg, done, sofar;
|
||||
|
||||
done = 0;
|
||||
i = MAXWLEN;
|
||||
sofar = 0;
|
||||
wp = wbuf;
|
||||
|
||||
while (!done) {
|
||||
done = 1;
|
||||
c = DgetC(DODOL);
|
||||
switch (c) {
|
||||
case DEOF:
|
||||
if (sofar == 0)
|
||||
return (0);
|
||||
/* finish this word and catch the code above the next time */
|
||||
unDredc(c);
|
||||
/* FALLTHROUGH */
|
||||
case '\n':
|
||||
*wp = 0;
|
||||
Gcat(STRNULL, wbuf);
|
||||
return (1);
|
||||
case ' ':
|
||||
case '\t':
|
||||
done = 0;
|
||||
break;
|
||||
case '`':
|
||||
/* We preserve ` quotations which are done yet later */
|
||||
*wp++ = (Char)c, --i;
|
||||
/* FALLTHROUGH */
|
||||
case '\'':
|
||||
case '"':
|
||||
/*
|
||||
* Note that DgetC never returns a QUOTES character from an
|
||||
* expansion, so only true input quotes will get us here or out.
|
||||
*/
|
||||
c1 = c;
|
||||
dolflg = c1 == '"' ? DODOL : 0;
|
||||
for (;;) {
|
||||
c = DgetC(dolflg);
|
||||
if (c == c1)
|
||||
break;
|
||||
if (c == '\n' || c == DEOF)
|
||||
stderror(ERR_UNMATCHED, c1);
|
||||
if ((c & (QUOTE | TRIM)) == ('\n' | QUOTE))
|
||||
--wp, ++i;
|
||||
if (--i <= 0)
|
||||
stderror(ERR_WTOOLONG);
|
||||
switch (c1) {
|
||||
case '"':
|
||||
/*
|
||||
* Leave any `s alone for later. Other chars are all
|
||||
* quoted, thus `...` can tell it was within "...".
|
||||
*/
|
||||
*wp++ = (Char)(c == '`' ? '`' : (c | QUOTE));
|
||||
break;
|
||||
case '\'':
|
||||
/* Prevent all further interpretation */
|
||||
*wp++ = (Char)(c | QUOTE);
|
||||
break;
|
||||
case '`':
|
||||
/* Leave all text alone for later */
|
||||
*wp++ = (Char)c;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (c1 == '`')
|
||||
*wp++ = '`' /* i--; eliminated */;
|
||||
sofar = 1;
|
||||
if ((wp = Dpack(wbuf, wp)) == NULL)
|
||||
return (1);
|
||||
else {
|
||||
i = MAXWLEN - (wp - wbuf);
|
||||
done = 0;
|
||||
}
|
||||
break;
|
||||
case '\\':
|
||||
c = DgetC(0); /* No $ subst! */
|
||||
if (c == '\n' || c == DEOF) {
|
||||
done = 0;
|
||||
break;
|
||||
}
|
||||
c |= QUOTE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (done) {
|
||||
unDgetC(c);
|
||||
sofar = 1;
|
||||
if ((wp = Dpack(wbuf, wp)) == NULL)
|
||||
return (1);
|
||||
else {
|
||||
i = MAXWLEN - (wp - wbuf);
|
||||
done = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Really NOTREACHED */
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get a character, performing $ substitution unless flag is 0.
|
||||
* Any QUOTES character which is returned from a $ expansion is
|
||||
* QUOTEd so that it will not be recognized above.
|
||||
*/
|
||||
static int
|
||||
DgetC(int flag)
|
||||
{
|
||||
int c;
|
||||
top:
|
||||
if ((c = Dpeekc) != '\0') {
|
||||
Dpeekc = 0;
|
||||
return (c);
|
||||
}
|
||||
if (lap) {
|
||||
c = *lap++ & (QUOTE | TRIM);
|
||||
if (c == 0) {
|
||||
lap = 0;
|
||||
goto top;
|
||||
}
|
||||
quotspec:
|
||||
if (cmap(c, QUOTES))
|
||||
return (c | QUOTE);
|
||||
return (c);
|
||||
}
|
||||
if (dolp) {
|
||||
if ((c = *dolp++ & (QUOTE | TRIM)) != '\0')
|
||||
goto quotspec;
|
||||
if (dolcnt > 0) {
|
||||
setDolp(*dolnxt++);
|
||||
--dolcnt;
|
||||
return (' ');
|
||||
}
|
||||
dolp = 0;
|
||||
}
|
||||
if (dolcnt > 0) {
|
||||
setDolp(*dolnxt++);
|
||||
--dolcnt;
|
||||
goto top;
|
||||
}
|
||||
c = Dredc();
|
||||
if (c == '$' && flag) {
|
||||
Dgetdol();
|
||||
goto top;
|
||||
}
|
||||
return (c);
|
||||
}
|
||||
|
||||
static Char *nulvec[] = {0};
|
||||
static struct varent nulargv = {nulvec, STRargv, { NULL, NULL, NULL }, 0};
|
||||
|
||||
static void
|
||||
dolerror(Char *s)
|
||||
{
|
||||
setname(vis_str(s));
|
||||
stderror(ERR_NAME | ERR_RANGE);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle the multitudinous $ expansion forms.
|
||||
* Ugh.
|
||||
*/
|
||||
static void
|
||||
Dgetdol(void)
|
||||
{
|
||||
static Char *dolbang = NULL;
|
||||
Char name[4*MAXVARLEN+1];
|
||||
Char wbuf[BUFSIZE];
|
||||
struct varent *vp;
|
||||
Char *np;
|
||||
int c, lwb, sc, subscr, upb;
|
||||
int dimen, bitset;
|
||||
char tnp;
|
||||
|
||||
bitset = 0;
|
||||
dimen = 0;
|
||||
lwb = 1;
|
||||
upb = 0;
|
||||
subscr = 0;
|
||||
vp = NULL;
|
||||
|
||||
dolnmod = dolmcnt = dolwcnt = 0;
|
||||
c = sc = DgetC(0);
|
||||
if (c == '{')
|
||||
c = DgetC(0); /* sc is { to take } later */
|
||||
if ((c & TRIM) == '#')
|
||||
dimen++, c = DgetC(0); /* $# takes dimension */
|
||||
else if (c == '?')
|
||||
bitset++, c = DgetC(0); /* $? tests existence */
|
||||
switch (c) {
|
||||
case '!':
|
||||
if (dimen || bitset)
|
||||
stderror(ERR_SYNTAX);
|
||||
if (backpid != 0) {
|
||||
if (dolbang)
|
||||
xfree((ptr_t)dolbang);
|
||||
setDolp(dolbang = putn(backpid));
|
||||
}
|
||||
goto eatbrac;
|
||||
case '$':
|
||||
if (dimen || bitset)
|
||||
stderror(ERR_SYNTAX);
|
||||
setDolp(doldol);
|
||||
goto eatbrac;
|
||||
case '<' | QUOTE:
|
||||
if (bitset)
|
||||
stderror(ERR_NOTALLOWED, "$?<");
|
||||
if (dimen)
|
||||
stderror(ERR_NOTALLOWED, "$?#");
|
||||
for (np = wbuf; read(OLDSTD, &tnp, 1) == 1; np++) {
|
||||
*np = (unsigned char)tnp;
|
||||
if (np >= &wbuf[BUFSIZE - 1])
|
||||
stderror(ERR_LTOOLONG);
|
||||
if (tnp == '\n')
|
||||
break;
|
||||
}
|
||||
*np = 0;
|
||||
/*
|
||||
* KLUDGE: dolmod is set here because it will cause setDolp to call
|
||||
* domod and thus to copy wbuf. Otherwise setDolp would use it
|
||||
* directly. If we saved it ourselves, no one would know when to free
|
||||
* it. The actual function of the 'q' causes filename expansion not to
|
||||
* be done on the interpolated value.
|
||||
*/
|
||||
dolmod[dolnmod++] = 'q';
|
||||
dolmcnt = 10000;
|
||||
setDolp(wbuf);
|
||||
goto eatbrac;
|
||||
case DEOF:
|
||||
case '\n':
|
||||
stderror(ERR_SYNTAX);
|
||||
/* NOTREACHED */
|
||||
case '*':
|
||||
(void) Strcpy(name, STRargv);
|
||||
vp = adrof(STRargv);
|
||||
subscr = -1; /* Prevent eating [...] */
|
||||
break;
|
||||
default:
|
||||
np = name;
|
||||
if (Isdigit(c)) {
|
||||
if (dimen)
|
||||
stderror(ERR_NOTALLOWED, "$#<num>");
|
||||
subscr = 0;
|
||||
do {
|
||||
subscr = subscr * 10 + c - '0';
|
||||
c = DgetC(0);
|
||||
} while (Isdigit(c));
|
||||
unDredc(c);
|
||||
if (subscr < 0)
|
||||
stderror(ERR_RANGE);
|
||||
if (subscr == 0) {
|
||||
if (bitset) {
|
||||
dolp = ffile ? STR1 : STR0;
|
||||
goto eatbrac;
|
||||
}
|
||||
if (ffile == 0)
|
||||
stderror(ERR_DOLZERO);
|
||||
fixDolMod();
|
||||
setDolp(ffile);
|
||||
goto eatbrac;
|
||||
}
|
||||
if (bitset)
|
||||
stderror(ERR_DOLQUEST);
|
||||
vp = adrof(STRargv);
|
||||
if (vp == 0) {
|
||||
vp = &nulargv;
|
||||
goto eatmod;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!alnum(c))
|
||||
stderror(ERR_VARALNUM);
|
||||
for (;;) {
|
||||
*np++ = (Char)c;
|
||||
c = DgetC(0);
|
||||
if (!alnum(c))
|
||||
break;
|
||||
if (np >= &name[MAXVARLEN])
|
||||
stderror(ERR_VARTOOLONG);
|
||||
}
|
||||
*np++ = 0;
|
||||
unDredc(c);
|
||||
vp = adrof(name);
|
||||
}
|
||||
if (bitset) {
|
||||
dolp = (vp || getenv(short2str(name))) ? STR1 : STR0;
|
||||
goto eatbrac;
|
||||
}
|
||||
if (vp == 0) {
|
||||
np = str2short(getenv(short2str(name)));
|
||||
if (np) {
|
||||
fixDolMod();
|
||||
setDolp(np);
|
||||
goto eatbrac;
|
||||
}
|
||||
udvar(name);
|
||||
}
|
||||
c = DgetC(0);
|
||||
upb = blklen(vp->vec);
|
||||
if (dimen == 0 && subscr == 0 && c == '[') {
|
||||
np = name;
|
||||
for (;;) {
|
||||
c = DgetC(DODOL); /* Allow $ expand within [ ] */
|
||||
if (c == ']')
|
||||
break;
|
||||
if (c == '\n' || c == DEOF)
|
||||
stderror(ERR_INCBR);
|
||||
if (np >= &name[sizeof(name) / sizeof(Char) - 2])
|
||||
stderror(ERR_VARTOOLONG);
|
||||
*np++ = (Char)c;
|
||||
}
|
||||
*np = 0, np = name;
|
||||
if (dolp || dolcnt) /* $ exp must end before ] */
|
||||
stderror(ERR_EXPORD);
|
||||
if (!*np)
|
||||
stderror(ERR_SYNTAX);
|
||||
if (Isdigit(*np)) {
|
||||
int i;
|
||||
|
||||
for (i = 0; Isdigit(*np); i = i * 10 + *np++ - '0')
|
||||
continue;
|
||||
if ((i < 0 || i > upb) && !any("-*", *np)) {
|
||||
dolerror(vp->v_name);
|
||||
return;
|
||||
}
|
||||
lwb = i;
|
||||
if (!*np)
|
||||
upb = lwb, np = STRstar;
|
||||
}
|
||||
if (*np == '*')
|
||||
np++;
|
||||
else if (*np != '-')
|
||||
stderror(ERR_MISSING, '-');
|
||||
else {
|
||||
int i = upb;
|
||||
|
||||
np++;
|
||||
if (Isdigit(*np)) {
|
||||
i = 0;
|
||||
while (Isdigit(*np))
|
||||
i = i * 10 + *np++ - '0';
|
||||
if (i < 0 || i > upb) {
|
||||
dolerror(vp->v_name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (i < lwb)
|
||||
upb = lwb - 1;
|
||||
else
|
||||
upb = i;
|
||||
}
|
||||
if (lwb == 0) {
|
||||
if (upb != 0) {
|
||||
dolerror(vp->v_name);
|
||||
return;
|
||||
}
|
||||
upb = -1;
|
||||
}
|
||||
if (*np)
|
||||
stderror(ERR_SYNTAX);
|
||||
}
|
||||
else {
|
||||
if (subscr > 0) {
|
||||
if (subscr > upb)
|
||||
lwb = 1, upb = 0;
|
||||
else
|
||||
lwb = upb = subscr;
|
||||
}
|
||||
unDredc(c);
|
||||
}
|
||||
if (dimen) {
|
||||
Char *cp = putn(upb - lwb + 1);
|
||||
|
||||
addla(cp);
|
||||
xfree((ptr_t) cp);
|
||||
}
|
||||
else {
|
||||
eatmod:
|
||||
fixDolMod();
|
||||
dolnxt = &vp->vec[lwb - 1];
|
||||
dolcnt = upb - lwb + 1;
|
||||
}
|
||||
eatbrac:
|
||||
if (sc == '{') {
|
||||
c = Dredc();
|
||||
if (c != '}')
|
||||
stderror(ERR_MISSING, '}');
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fixDolMod(void)
|
||||
{
|
||||
int c;
|
||||
|
||||
c = DgetC(0);
|
||||
if (c == ':') {
|
||||
do {
|
||||
c = DgetC(0), dolmcnt = 1, dolwcnt = 1;
|
||||
if (c == 'g' || c == 'a') {
|
||||
if (c == 'g')
|
||||
dolmcnt = 10000;
|
||||
else
|
||||
dolwcnt = 10000;
|
||||
c = DgetC(0);
|
||||
}
|
||||
if ((c == 'g' && dolmcnt != 10000) ||
|
||||
(c == 'a' && dolwcnt != 10000)) {
|
||||
if (c == 'g')
|
||||
dolmcnt = 10000;
|
||||
else
|
||||
dolwcnt = 10000;
|
||||
c = DgetC(0);
|
||||
}
|
||||
|
||||
if (c == 's') { /* [eichin:19910926.0755EST] */
|
||||
int delimcnt = 2;
|
||||
int delim = DgetC(0);
|
||||
dolmod[dolnmod++] = (Char)c;
|
||||
dolmod[dolnmod++] = (Char)delim;
|
||||
|
||||
if (!delim || letter(delim)
|
||||
|| Isdigit(delim) || any(" \t\n", delim)) {
|
||||
seterror(ERR_BADSUBST);
|
||||
break;
|
||||
}
|
||||
while ((c = DgetC(0)) != (-1)) {
|
||||
dolmod[dolnmod++] = (Char)c;
|
||||
if(c == delim) delimcnt--;
|
||||
if(!delimcnt) break;
|
||||
}
|
||||
if(delimcnt) {
|
||||
seterror(ERR_BADSUBST);
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!any("htrqxes", c))
|
||||
stderror(ERR_BADMOD, c);
|
||||
dolmod[dolnmod++] = (Char)c;
|
||||
if (c == 'q')
|
||||
dolmcnt = 10000;
|
||||
}
|
||||
while ((c = DgetC(0)) == ':');
|
||||
unDredc(c);
|
||||
}
|
||||
else
|
||||
unDredc(c);
|
||||
}
|
||||
|
||||
static void
|
||||
setDolp(Char *cp)
|
||||
{
|
||||
Char *dp;
|
||||
int i;
|
||||
|
||||
if (dolnmod == 0 || dolmcnt == 0) {
|
||||
dolp = cp;
|
||||
return;
|
||||
}
|
||||
dp = cp = Strsave(cp);
|
||||
for (i = 0; i < dolnmod; i++) {
|
||||
/* handle s// [eichin:19910926.0510EST] */
|
||||
if(dolmod[i] == 's') {
|
||||
int delim;
|
||||
Char *lhsub, *rhsub, *np;
|
||||
size_t lhlen = 0, rhlen = 0;
|
||||
int didmod = 0;
|
||||
|
||||
delim = dolmod[++i];
|
||||
if (!delim || letter(delim)
|
||||
|| Isdigit(delim) || any(" \t\n", delim)) {
|
||||
seterror(ERR_BADSUBST);
|
||||
break;
|
||||
}
|
||||
lhsub = &dolmod[++i];
|
||||
while(dolmod[i] != delim && dolmod[++i]) {
|
||||
lhlen++;
|
||||
}
|
||||
dolmod[i] = 0;
|
||||
rhsub = &dolmod[++i];
|
||||
while(dolmod[i] != delim && dolmod[++i]) {
|
||||
rhlen++;
|
||||
}
|
||||
dolmod[i] = 0;
|
||||
|
||||
do {
|
||||
dp = Strstr(cp, lhsub);
|
||||
if (dp) {
|
||||
np = xmalloc(
|
||||
(size_t)((Strlen(cp) + 1 - lhlen + rhlen) *
|
||||
sizeof(*np)));
|
||||
(void)Strncpy(np, cp, (size_t)(dp - cp));
|
||||
(void)Strcpy(np + (dp - cp), rhsub);
|
||||
(void)Strcpy(np + (dp - cp) + rhlen, dp + lhlen);
|
||||
|
||||
xfree((ptr_t) cp);
|
||||
dp = cp = np;
|
||||
didmod = 1;
|
||||
} else {
|
||||
/* should this do a seterror? */
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (dolwcnt == 10000);
|
||||
/*
|
||||
* restore dolmod for additional words
|
||||
*/
|
||||
dolmod[i] = rhsub[-1] = (Char)delim;
|
||||
if (didmod)
|
||||
dolmcnt--;
|
||||
else
|
||||
break;
|
||||
} else {
|
||||
int didmod = 0;
|
||||
|
||||
do {
|
||||
if ((dp = domod(cp, dolmod[i]))) {
|
||||
didmod = 1;
|
||||
if (Strcmp(cp, dp) == 0) {
|
||||
xfree((ptr_t) cp);
|
||||
cp = dp;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
xfree((ptr_t) cp);
|
||||
cp = dp;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
while (dolwcnt == 10000);
|
||||
dp = cp;
|
||||
if (didmod)
|
||||
dolmcnt--;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (dp) {
|
||||
addla(dp);
|
||||
xfree((ptr_t) dp);
|
||||
}
|
||||
else {
|
||||
addla(cp);
|
||||
xfree((ptr_t) cp);
|
||||
}
|
||||
|
||||
dolp = STRNULL;
|
||||
if (seterr)
|
||||
stderror(ERR_OLD);
|
||||
}
|
||||
|
||||
static void
|
||||
unDredc(int c)
|
||||
{
|
||||
Dpeekrd = c;
|
||||
}
|
||||
|
||||
static int
|
||||
Dredc(void)
|
||||
{
|
||||
int c;
|
||||
|
||||
if ((c = Dpeekrd) != '\0') {
|
||||
Dpeekrd = 0;
|
||||
return (c);
|
||||
}
|
||||
if (Dcp && (c = *Dcp++))
|
||||
return (c & (QUOTE | TRIM));
|
||||
if (*Dvp == 0) {
|
||||
Dcp = 0;
|
||||
return (DEOF);
|
||||
}
|
||||
Dcp = *Dvp++;
|
||||
return (' ');
|
||||
}
|
||||
|
||||
static void
|
||||
Dtestq(int c)
|
||||
{
|
||||
if (cmap(c, QUOTES))
|
||||
gflag = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Form a shell temporary file (in unit 0) from the words
|
||||
* of the shell input up to EOF or a line the same as "term".
|
||||
* Unit 0 should have been closed before this call.
|
||||
*/
|
||||
void
|
||||
/*ARGSUSED*/
|
||||
heredoc(Char *term)
|
||||
{
|
||||
Char obuf[BUFSIZE], lbuf[BUFSIZE], mbuf[BUFSIZE];
|
||||
struct timespec tv;
|
||||
Char *Dv[2], *lbp, *obp, *mbp, **vp;
|
||||
char *tmp;
|
||||
int c, ocnt, lcnt, mcnt;
|
||||
int quoted;
|
||||
|
||||
again:
|
||||
tmp = short2str(shtemp);
|
||||
if (open(tmp, O_RDWR | O_CREAT | O_TRUNC | O_EXCL, 0600) < 0) {
|
||||
if (errno == EEXIST) {
|
||||
if (unlink(tmp) == -1) {
|
||||
(void)clock_gettime(CLOCK_MONOTONIC, &tv);
|
||||
mbp = putn((((int)tv.tv_sec) ^
|
||||
((int)tv.tv_nsec) ^ ((int)getpid())) & 0x00ffffff);
|
||||
shtemp = Strspl(STRtmpsh, mbp);
|
||||
xfree((ptr_t)mbp);
|
||||
}
|
||||
goto again;
|
||||
}
|
||||
stderror(ERR_SYSTEM, tmp, strerror(errno));
|
||||
}
|
||||
(void)unlink(tmp); /* 0 0 inode! */
|
||||
Dv[0] = term;
|
||||
Dv[1] = NULL;
|
||||
gflag = 0;
|
||||
trim(Dv);
|
||||
rscan(Dv, Dtestq);
|
||||
quoted = gflag;
|
||||
ocnt = BUFSIZE;
|
||||
obp = obuf;
|
||||
for (;;) {
|
||||
/*
|
||||
* Read up a line
|
||||
*/
|
||||
lbp = lbuf;
|
||||
lcnt = BUFSIZE - 4;
|
||||
for (;;) {
|
||||
c = readc(1); /* 1 -> Want EOF returns */
|
||||
if (c < 0 || c == '\n')
|
||||
break;
|
||||
if ((c &= TRIM) != '\0') {
|
||||
*lbp++ = (Char)c;
|
||||
if (--lcnt < 0) {
|
||||
setname("<<");
|
||||
stderror(ERR_NAME | ERR_OVERFLOW);
|
||||
}
|
||||
}
|
||||
}
|
||||
*lbp = 0;
|
||||
|
||||
/*
|
||||
* Check for EOF or compare to terminator -- before expansion
|
||||
*/
|
||||
if (c < 0 || eq(lbuf, term)) {
|
||||
(void)write(0, short2str(obuf), (size_t)(BUFSIZE - ocnt));
|
||||
(void)lseek(0, (off_t)0, SEEK_SET);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If term was quoted or -n just pass it on
|
||||
*/
|
||||
if (quoted || noexec) {
|
||||
*lbp++ = '\n';
|
||||
*lbp = 0;
|
||||
for (lbp = lbuf; (c = *lbp++) != '\0';) {
|
||||
*obp++ = (Char)c;
|
||||
if (--ocnt == 0) {
|
||||
(void) write(0, short2str(obuf), BUFSIZE);
|
||||
obp = obuf;
|
||||
ocnt = BUFSIZE;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Term wasn't quoted so variable and then command expand the input
|
||||
* line
|
||||
*/
|
||||
Dcp = lbuf;
|
||||
Dvp = Dv + 1;
|
||||
mbp = mbuf;
|
||||
mcnt = BUFSIZE - 4;
|
||||
for (;;) {
|
||||
c = DgetC(DODOL);
|
||||
if (c == DEOF)
|
||||
break;
|
||||
if ((c &= TRIM) == 0)
|
||||
continue;
|
||||
/* \ quotes \ $ ` here */
|
||||
if (c == '\\') {
|
||||
c = DgetC(0);
|
||||
if (!any("$\\`", c))
|
||||
unDgetC(c | QUOTE), c = '\\';
|
||||
else
|
||||
c |= QUOTE;
|
||||
}
|
||||
*mbp++ = (Char)c;
|
||||
if (--mcnt == 0) {
|
||||
setname("<<");
|
||||
stderror(ERR_NAME | ERR_OVERFLOW);
|
||||
}
|
||||
}
|
||||
*mbp++ = 0;
|
||||
|
||||
/*
|
||||
* If any ` in line do command substitution
|
||||
*/
|
||||
mbp = mbuf;
|
||||
if (any(short2str(mbp), '`')) {
|
||||
/*
|
||||
* 1 arg to dobackp causes substitution to be literal. Words are
|
||||
* broken only at newlines so that all blanks and tabs are
|
||||
* preserved. Blank lines (null words) are not discarded.
|
||||
*/
|
||||
vp = dobackp(mbuf, 1);
|
||||
}
|
||||
else
|
||||
/* Setup trivial vector similar to return of dobackp */
|
||||
Dv[0] = mbp, Dv[1] = NULL, vp = Dv;
|
||||
|
||||
/*
|
||||
* Resurrect the words from the command substitution each separated by
|
||||
* a newline. Note that the last newline of a command substitution
|
||||
* will have been discarded, but we put a newline after the last word
|
||||
* because this represents the newline after the last input line!
|
||||
*/
|
||||
for (; *vp; vp++) {
|
||||
for (mbp = *vp; *mbp; mbp++) {
|
||||
*obp++ = *mbp & TRIM;
|
||||
if (--ocnt == 0) {
|
||||
(void)write(0, short2str(obuf), BUFSIZE);
|
||||
obp = obuf;
|
||||
ocnt = BUFSIZE;
|
||||
}
|
||||
}
|
||||
*obp++ = '\n';
|
||||
if (--ocnt == 0) {
|
||||
(void)write(0, short2str(obuf), BUFSIZE);
|
||||
obp = obuf;
|
||||
ocnt = BUFSIZE;
|
||||
}
|
||||
}
|
||||
if (pargv)
|
||||
blkfree(pargv), pargv = 0;
|
||||
}
|
||||
}
|
388
bin/csh/err.c
Normal file
388
bin/csh/err.c
Normal file
|
@ -0,0 +1,388 @@
|
|||
/* $NetBSD: err.c,v 1.21 2013/07/16 17:47:43 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1980, 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)err.c 8.1 (Berkeley) 5/31/93";
|
||||
#else
|
||||
__RCSID("$NetBSD: err.c,v 1.21 2013/07/16 17:47:43 christos Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "csh.h"
|
||||
#include "extern.h"
|
||||
|
||||
char *seterr = NULL; /* Holds last error if there was one */
|
||||
|
||||
#define ERR_FLAGS ((int)0xf0000000)
|
||||
#define ERR_NAME 0x10000000
|
||||
#define ERR_SILENT 0x20000000
|
||||
#define ERR_OLD 0x40000000
|
||||
|
||||
static const char *errorlist[] =
|
||||
{
|
||||
#define ERR_SYNTAX 0
|
||||
"Syntax Error",
|
||||
#define ERR_NOTALLOWED 1
|
||||
"%s is not allowed",
|
||||
#define ERR_WTOOLONG 2
|
||||
"Word too long",
|
||||
#define ERR_LTOOLONG 3
|
||||
"$< line too long",
|
||||
#define ERR_DOLZERO 4
|
||||
"No file for $0",
|
||||
#define ERR_DOLQUEST 5
|
||||
"$? not allowed here",
|
||||
#define ERR_INCBR 6
|
||||
"Incomplete [] modifier",
|
||||
#define ERR_EXPORD 7
|
||||
"$ expansion must end before ]",
|
||||
#define ERR_BADMOD 8
|
||||
"Bad : modifier in $ (%c)",
|
||||
#define ERR_SUBSCRIPT 9
|
||||
"Subscript error",
|
||||
#define ERR_BADNUM 10
|
||||
"Badly formed number",
|
||||
#define ERR_NOMORE 11
|
||||
"No more words",
|
||||
#define ERR_FILENAME 12
|
||||
"Missing file name",
|
||||
#define ERR_GLOB 13
|
||||
"Internal glob error",
|
||||
#define ERR_COMMAND 14
|
||||
"Command not found",
|
||||
#define ERR_TOOFEW 15
|
||||
"Too few arguments",
|
||||
#define ERR_TOOMANY 16
|
||||
"Too many arguments",
|
||||
#define ERR_DANGER 17
|
||||
"Too dangerous to alias that",
|
||||
#define ERR_EMPTYIF 18
|
||||
"Empty if",
|
||||
#define ERR_IMPRTHEN 19
|
||||
"Improper then",
|
||||
#define ERR_NOPAREN 20
|
||||
"Words not parenthesized",
|
||||
#define ERR_NOTFOUND 21
|
||||
"%s not found",
|
||||
#define ERR_MASK 22
|
||||
"Improper mask",
|
||||
#define ERR_LIMIT 23
|
||||
"No such limit",
|
||||
#define ERR_TOOLARGE 24
|
||||
"Argument too large",
|
||||
#define ERR_SCALEF 25
|
||||
"Improper or unknown scale factor",
|
||||
#define ERR_UNDVAR 26
|
||||
"Undefined variable",
|
||||
#define ERR_DEEP 27
|
||||
"Directory stack not that deep",
|
||||
#define ERR_BADSIG 28
|
||||
"Bad signal number",
|
||||
#define ERR_UNKSIG 29
|
||||
"Unknown signal; kill -l lists signals",
|
||||
#define ERR_VARBEGIN 30
|
||||
"Variable name must begin with a letter",
|
||||
#define ERR_VARTOOLONG 31
|
||||
"Variable name too long",
|
||||
#define ERR_VARALNUM 32
|
||||
"Variable name must contain alphanumeric characters",
|
||||
#define ERR_JOBCONTROL 33
|
||||
"No job control in this shell",
|
||||
#define ERR_EXPRESSION 34
|
||||
"Expression Syntax",
|
||||
#define ERR_NOHOMEDIR 35
|
||||
"No home directory",
|
||||
#define ERR_CANTCHANGE 36
|
||||
"Can't change to home directory",
|
||||
#define ERR_NULLCOM 37
|
||||
"Invalid null command",
|
||||
#define ERR_ASSIGN 38
|
||||
"Assignment missing expression",
|
||||
#define ERR_UNKNOWNOP 39
|
||||
"Unknown operator",
|
||||
#define ERR_AMBIG 40
|
||||
"Ambiguous",
|
||||
#define ERR_EXISTS 41
|
||||
"%s: File exists",
|
||||
#define ERR_INTR 42
|
||||
"Interrupted",
|
||||
#define ERR_RANGE 43
|
||||
"Subscript out of range",
|
||||
#define ERR_OVERFLOW 44
|
||||
"Line overflow",
|
||||
#define ERR_VARMOD 45
|
||||
"Unknown variable modifier",
|
||||
#define ERR_NOSUCHJOB 46
|
||||
"No such job",
|
||||
#define ERR_TERMINAL 47
|
||||
"Can't from terminal",
|
||||
#define ERR_NOTWHILE 48
|
||||
"Not in while/foreach",
|
||||
#define ERR_NOPROC 49
|
||||
"No more processes",
|
||||
#define ERR_NOMATCH 50
|
||||
"No match",
|
||||
#define ERR_MISSING 51
|
||||
"Missing %c",
|
||||
#define ERR_UNMATCHED 52
|
||||
"Unmatched %c",
|
||||
#define ERR_NOMEM 53
|
||||
"Out of memory",
|
||||
#define ERR_PIPE 54
|
||||
"Can't make pipe",
|
||||
#define ERR_SYSTEM 55
|
||||
"%s: %s",
|
||||
#define ERR_STRING 56
|
||||
"%s",
|
||||
#define ERR_JOBS 57
|
||||
"usage: jobs [ -l ]",
|
||||
#define ERR_JOBARGS 58
|
||||
"Arguments should be jobs or process id's",
|
||||
#define ERR_JOBCUR 59
|
||||
"No current job",
|
||||
#define ERR_JOBPREV 60
|
||||
"No previous job",
|
||||
#define ERR_JOBPAT 61
|
||||
"No job matches pattern",
|
||||
#define ERR_NESTING 62
|
||||
"Fork nesting > %d; maybe `...` loop",
|
||||
#define ERR_JOBCTRLSUB 63
|
||||
"No job control in subshells",
|
||||
#define ERR_BADPLPS 64
|
||||
"Badly placed ()'s",
|
||||
#define ERR_STOPPED 65
|
||||
"%sThere are suspended jobs",
|
||||
#define ERR_NODIR 66
|
||||
"No other directory",
|
||||
#define ERR_EMPTY 67
|
||||
"Directory stack empty",
|
||||
#define ERR_BADDIR 68
|
||||
"Bad directory",
|
||||
#define ERR_DIRUS 69
|
||||
"usage: %s [-lvn]%s",
|
||||
#define ERR_HFLAG 70
|
||||
"No operand for -h flag",
|
||||
#define ERR_NOTLOGIN 71
|
||||
"Not a login shell",
|
||||
#define ERR_DIV0 72
|
||||
"Division by 0",
|
||||
#define ERR_MOD0 73
|
||||
"Mod by 0",
|
||||
#define ERR_BADSCALE 74
|
||||
"Bad scaling; did you mean \"%s\"?",
|
||||
#define ERR_SUSPLOG 75
|
||||
"Can't suspend a login shell (yet)",
|
||||
#define ERR_UNKUSER 76
|
||||
"Unknown user: %s",
|
||||
#define ERR_NOHOME 77
|
||||
"No $home variable set",
|
||||
#define ERR_HISTUS 78
|
||||
"usage: history [-rh] [# number of events]",
|
||||
#define ERR_SPDOLLT 79
|
||||
"$, ! or < not allowed with $# or $?",
|
||||
#define ERR_NEWLINE 80
|
||||
"Newline in variable name",
|
||||
#define ERR_SPSTAR 81
|
||||
"* not allowed with $# or $?",
|
||||
#define ERR_DIGIT 82
|
||||
"$?<digit> or $#<digit> not allowed",
|
||||
#define ERR_VARILL 83
|
||||
"Illegal variable name",
|
||||
#define ERR_NLINDEX 84
|
||||
"Newline in variable index",
|
||||
#define ERR_EXPOVFL 85
|
||||
"Expansion buffer overflow",
|
||||
#define ERR_VARSYN 86
|
||||
"Variable syntax",
|
||||
#define ERR_BADBANG 87
|
||||
"Bad ! form",
|
||||
#define ERR_NOSUBST 88
|
||||
"No previous substitute",
|
||||
#define ERR_BADSUBST 89
|
||||
"Bad substitute",
|
||||
#define ERR_LHS 90
|
||||
"No previous left hand side",
|
||||
#define ERR_RHSLONG 91
|
||||
"Right hand side too long",
|
||||
#define ERR_BADBANGMOD 92
|
||||
"Bad ! modifier: %c",
|
||||
#define ERR_MODFAIL 93
|
||||
"Modifier failed",
|
||||
#define ERR_SUBOVFL 94
|
||||
"Substitution buffer overflow",
|
||||
#define ERR_BADBANGARG 95
|
||||
"Bad ! arg selector",
|
||||
#define ERR_NOSEARCH 96
|
||||
"No prev search",
|
||||
#define ERR_NOEVENT 97
|
||||
"%s: Event not found",
|
||||
#define ERR_TOOMANYRP 98
|
||||
"Too many )'s",
|
||||
#define ERR_TOOMANYLP 99
|
||||
"Too many ('s",
|
||||
#define ERR_BADPLP 100
|
||||
"Badly placed (",
|
||||
#define ERR_MISRED 101
|
||||
"Missing name for redirect",
|
||||
#define ERR_OUTRED 102
|
||||
"Ambiguous output redirect",
|
||||
#define ERR_REDPAR 103
|
||||
"Can't << within ()'s",
|
||||
#define ERR_INRED 104
|
||||
"Ambiguous input redirect",
|
||||
#define ERR_ALIASLOOP 105
|
||||
"Alias loop",
|
||||
#define ERR_HISTLOOP 106
|
||||
"!# History loop",
|
||||
#define ERR_ARCH 107
|
||||
"%s: %s. Wrong Architecture",
|
||||
#define ERR_FILEINQ 108
|
||||
"Malformed file inquiry",
|
||||
#define ERR_SELOVFL 109
|
||||
"Selector overflow",
|
||||
#define ERR_INVALID 110
|
||||
"Invalid Error"
|
||||
};
|
||||
|
||||
/*
|
||||
* The parser and scanner set up errors for later by calling seterr,
|
||||
* which sets the variable err as a side effect; later to be tested,
|
||||
* e.g. in process.
|
||||
*/
|
||||
void
|
||||
seterror(int id, ...)
|
||||
{
|
||||
if (seterr == 0) {
|
||||
char berr[BUFSIZE];
|
||||
va_list va;
|
||||
|
||||
va_start(va, id);
|
||||
if (id < 0 || id >= (int)(sizeof(errorlist) / sizeof(errorlist[0])) - 1)
|
||||
id = ERR_INVALID;
|
||||
(void)vsnprintf(berr, sizeof(berr), errorlist[id], va);
|
||||
va_end(va);
|
||||
|
||||
seterr = strsave(berr);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Print the error with the given id.
|
||||
*
|
||||
* Special ids:
|
||||
* ERR_SILENT: Print nothing.
|
||||
* ERR_OLD: Print the previously set error if one was there.
|
||||
* otherwise return.
|
||||
* ERR_NAME: If this bit is set, print the name of the function
|
||||
* in bname
|
||||
*
|
||||
* This routine always resets or exits. The flag haderr
|
||||
* is set so the routine who catches the unwind can propogate
|
||||
* it if they want.
|
||||
*
|
||||
* Note that any open files at the point of error will eventually
|
||||
* be closed in the routine process in sh.c which is the only
|
||||
* place error unwinds are ever caught.
|
||||
*/
|
||||
void
|
||||
stderror(int id, ...)
|
||||
{
|
||||
va_list va;
|
||||
Char **v;
|
||||
int flags;
|
||||
|
||||
flags = id & ERR_FLAGS;
|
||||
id &= ~ERR_FLAGS;
|
||||
|
||||
if ((flags & ERR_OLD) && seterr == NULL)
|
||||
abort();
|
||||
|
||||
if (id < 0 || id > (int)(sizeof(errorlist) / sizeof(errorlist[0])))
|
||||
id = ERR_INVALID;
|
||||
|
||||
(void)fflush(cshout);
|
||||
(void)fflush(csherr);
|
||||
haderr = 1; /* Now to diagnostic output */
|
||||
timflg = 0; /* This isn't otherwise reset */
|
||||
|
||||
|
||||
if (!(flags & ERR_SILENT)) {
|
||||
if (flags & ERR_NAME)
|
||||
(void)fprintf(csherr, "%s: ", bname);
|
||||
if ((flags & ERR_OLD))
|
||||
/* Old error. */
|
||||
(void)fprintf(csherr, "%s.\n", seterr);
|
||||
else {
|
||||
va_start(va, id);
|
||||
(void)vfprintf(csherr, errorlist[id], va);
|
||||
va_end(va);
|
||||
(void)fprintf(csherr, ".\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (seterr) {
|
||||
xfree((ptr_t) seterr);
|
||||
seterr = NULL;
|
||||
}
|
||||
|
||||
if ((v = pargv) != NULL)
|
||||
pargv = 0, blkfree(v);
|
||||
if ((v = gargv) != NULL)
|
||||
gargv = 0, blkfree(v);
|
||||
|
||||
(void)fflush(cshout);
|
||||
(void)fflush(csherr);
|
||||
didfds = 0; /* Forget about 0,1,2 */
|
||||
/*
|
||||
* Go away if -e or we are a child shell
|
||||
*/
|
||||
if (exiterr || child)
|
||||
xexit(1);
|
||||
|
||||
/*
|
||||
* Reset the state of the input. This buffered seek to end of file will
|
||||
* also clear the while/foreach stack.
|
||||
*/
|
||||
btoeof();
|
||||
|
||||
set(STRstatus, Strsave(STR1));
|
||||
if (tpgrp > 0)
|
||||
(void)tcsetpgrp(FSHTTY, tpgrp);
|
||||
reset(); /* Unwind */
|
||||
}
|
746
bin/csh/exec.c
Normal file
746
bin/csh/exec.c
Normal file
|
@ -0,0 +1,746 @@
|
|||
/* $NetBSD: exec.c,v 1.29 2013/07/16 17:47:43 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1980, 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)exec.c 8.3 (Berkeley) 5/23/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: exec.c,v 1.29 2013/07/16 17:47:43 christos Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "csh.h"
|
||||
#include "extern.h"
|
||||
|
||||
/*
|
||||
* System level search and execute of a command. We look in each directory
|
||||
* for the specified command name. If the name contains a '/' then we
|
||||
* execute only the full path name. If there is no search path then we
|
||||
* execute only full path names.
|
||||
*/
|
||||
extern char **environ;
|
||||
|
||||
/*
|
||||
* As we search for the command we note the first non-trivial error
|
||||
* message for presentation to the user. This allows us often
|
||||
* to show that a file has the wrong mode/no access when the file
|
||||
* is not in the last component of the search path, so we must
|
||||
* go on after first detecting the error.
|
||||
*/
|
||||
static const char *exerr; /* Execution error message */
|
||||
static Char *expath; /* Path for exerr */
|
||||
|
||||
/*
|
||||
* Xhash is an array of HSHSIZ bits (HSHSIZ / 8 chars), which are used
|
||||
* to hash execs. If it is allocated (havhash true), then to tell
|
||||
* whether ``name'' is (possibly) present in the i'th component
|
||||
* of the variable path, you look at the bit in xhash indexed by
|
||||
* hash(hashname("name"), i). This is setup automatically
|
||||
* after .login is executed, and recomputed whenever ``path'' is
|
||||
* changed.
|
||||
* The two part hash function is designed to let texec() call the
|
||||
* more expensive hashname() only once and the simple hash() several
|
||||
* times (once for each path component checked).
|
||||
* Byte size is assumed to be 8.
|
||||
*/
|
||||
#define HSHSIZ 8192 /* 1k bytes */
|
||||
#define HSHMASK (HSHSIZ - 1)
|
||||
#define HSHMUL 243
|
||||
static unsigned char xhash[HSHSIZ / 8];
|
||||
|
||||
#define hash(a, b) (((a) * HSHMUL + (b)) & HSHMASK)
|
||||
#define bit(h, b) ((h)[(b) >> 3] & 1 << ((b) & 7)) /* bit test */
|
||||
#define bis(h, b) ((h)[(b) >> 3] |= (unsigned char)(1 << ((b) & 7))) /* bit set */
|
||||
static int hits, misses;
|
||||
|
||||
/* Dummy search path for just absolute search when no path */
|
||||
static Char *justabs[] = {STRNULL, 0};
|
||||
|
||||
static void pexerr(void) __dead;
|
||||
static void texec(Char *, Char **);
|
||||
static int hashname(Char *);
|
||||
static int tellmewhat(struct wordent *, Char *);
|
||||
static int executable(Char *, Char *, int);
|
||||
static int iscommand(Char *);
|
||||
|
||||
void
|
||||
/*ARGSUSED*/
|
||||
doexec(Char **v, struct command *t)
|
||||
{
|
||||
struct varent *pathv;
|
||||
Char *blk[2], **av, *dp, **pv, *sav;
|
||||
int i, hashval, hashval1;
|
||||
sigset_t nsigset;
|
||||
int slash;
|
||||
|
||||
hashval = 0;
|
||||
/*
|
||||
* Glob the command name. We will search $path even if this does something,
|
||||
* as in sh but not in csh. One special case: if there is no PATH, then we
|
||||
* execute only commands which start with '/'.
|
||||
*/
|
||||
blk[0] = t->t_dcom[0];
|
||||
blk[1] = 0;
|
||||
gflag = 0, tglob(blk);
|
||||
if (gflag) {
|
||||
pv = globall(blk);
|
||||
if (pv == 0) {
|
||||
setname(vis_str(blk[0]));
|
||||
stderror(ERR_NAME | ERR_NOMATCH);
|
||||
}
|
||||
gargv = 0;
|
||||
}
|
||||
else
|
||||
pv = saveblk(blk);
|
||||
|
||||
trim(pv);
|
||||
|
||||
exerr = 0;
|
||||
expath = Strsave(pv[0]);
|
||||
Vexpath = expath;
|
||||
|
||||
pathv = adrof(STRpath);
|
||||
if (pathv == 0 && expath[0] != '/') {
|
||||
blkfree(pv);
|
||||
pexerr();
|
||||
}
|
||||
slash = any(short2str(expath), '/');
|
||||
|
||||
/*
|
||||
* Glob the argument list, if necessary. Otherwise trim off the quote bits.
|
||||
*/
|
||||
gflag = 0;
|
||||
av = &t->t_dcom[1];
|
||||
tglob(av);
|
||||
if (gflag) {
|
||||
av = globall(av);
|
||||
if (av == 0) {
|
||||
blkfree(pv);
|
||||
setname(vis_str(expath));
|
||||
stderror(ERR_NAME | ERR_NOMATCH);
|
||||
}
|
||||
gargv = 0;
|
||||
}
|
||||
else
|
||||
av = saveblk(av);
|
||||
|
||||
blkfree(t->t_dcom);
|
||||
t->t_dcom = blkspl(pv, av);
|
||||
xfree((ptr_t) pv);
|
||||
xfree((ptr_t) av);
|
||||
av = t->t_dcom;
|
||||
trim(av);
|
||||
|
||||
if (*av == NULL || **av == '\0')
|
||||
pexerr();
|
||||
|
||||
xechoit(av); /* Echo command if -x */
|
||||
/*
|
||||
* Since all internal file descriptors are set to close on exec, we don't
|
||||
* need to close them explicitly here. Just reorient ourselves for error
|
||||
* messages.
|
||||
*/
|
||||
SHIN = 0;
|
||||
SHOUT = 1;
|
||||
SHERR = 2;
|
||||
OLDSTD = 0;
|
||||
/*
|
||||
* We must do this AFTER any possible forking (like `foo` in glob) so that
|
||||
* this shell can still do subprocesses.
|
||||
*/
|
||||
sigemptyset(&nsigset);
|
||||
(void)sigprocmask(SIG_SETMASK, &nsigset, NULL);
|
||||
/*
|
||||
* If no path, no words in path, or a / in the filename then restrict the
|
||||
* command search.
|
||||
*/
|
||||
if (pathv == 0 || pathv->vec[0] == 0 || slash)
|
||||
pv = justabs;
|
||||
else
|
||||
pv = pathv->vec;
|
||||
sav = Strspl(STRslash, *av); /* / command name for postpending */
|
||||
Vsav = sav;
|
||||
if (havhash)
|
||||
hashval = hashname(*av);
|
||||
i = 0;
|
||||
hits++;
|
||||
do {
|
||||
/*
|
||||
* Try to save time by looking at the hash table for where this command
|
||||
* could be. If we are doing delayed hashing, then we put the names in
|
||||
* one at a time, as the user enters them. This is kinda like Korn
|
||||
* Shell's "tracked aliases".
|
||||
*/
|
||||
if (!slash && pv[0][0] == '/' && havhash) {
|
||||
hashval1 = hash(hashval, i);
|
||||
if (!bit(xhash, hashval1))
|
||||
goto cont;
|
||||
}
|
||||
if (pv[0][0] == 0 || eq(pv[0], STRdot)) /* don't make ./xxx */
|
||||
texec(*av, av);
|
||||
else {
|
||||
dp = Strspl(*pv, sav);
|
||||
Vdp = dp;
|
||||
texec(dp, av);
|
||||
Vdp = 0;
|
||||
xfree((ptr_t)dp);
|
||||
}
|
||||
misses++;
|
||||
cont:
|
||||
pv++;
|
||||
i++;
|
||||
} while (*pv);
|
||||
hits--;
|
||||
Vsav = 0;
|
||||
xfree((ptr_t)sav);
|
||||
pexerr();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
static void
|
||||
pexerr(void)
|
||||
{
|
||||
/* Couldn't find the damn thing */
|
||||
if (expath) {
|
||||
setname(vis_str(expath));
|
||||
Vexpath = 0;
|
||||
xfree((ptr_t)expath);
|
||||
expath = 0;
|
||||
}
|
||||
else
|
||||
setname("");
|
||||
if (exerr)
|
||||
stderror(ERR_NAME | ERR_STRING, exerr);
|
||||
else
|
||||
stderror(ERR_NAME | ERR_COMMAND);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute command f, arg list t.
|
||||
* Record error message if not found.
|
||||
* Also do shell scripts here.
|
||||
*/
|
||||
static void
|
||||
texec(Char *sf, Char **st)
|
||||
{
|
||||
struct varent *v;
|
||||
Char *lastsh[2], **vp, *st0, **ost;
|
||||
char *f, **t;
|
||||
int fd;
|
||||
unsigned char c = '\0';
|
||||
|
||||
/* The order for the conversions is significant */
|
||||
t = short2blk(st);
|
||||
f = short2str(sf);
|
||||
Vt = t;
|
||||
errno = 0; /* don't use a previous error */
|
||||
(void)execve(f, t, environ);
|
||||
Vt = 0;
|
||||
blkfree((Char **)t);
|
||||
switch (errno) {
|
||||
|
||||
case ENOEXEC:
|
||||
/*
|
||||
* From: casper@fwi.uva.nl (Casper H.S. Dik) If we could not execute
|
||||
* it, don't feed it to the shell if it looks like a binary!
|
||||
*/
|
||||
if ((fd = open(f, O_RDONLY)) != -1) {
|
||||
if (read(fd, (char *)&c, 1) == 1) {
|
||||
if (!Isprint(c) && (c != '\n' && c != '\t')) {
|
||||
(void)close(fd);
|
||||
/*
|
||||
* We *know* what ENOEXEC means.
|
||||
*/
|
||||
stderror(ERR_ARCH, f, strerror(errno));
|
||||
}
|
||||
}
|
||||
#ifdef _PATH_BSHELL
|
||||
else
|
||||
c = '#';
|
||||
#endif
|
||||
(void)close(fd);
|
||||
}
|
||||
/*
|
||||
* If there is an alias for shell, then put the words of the alias in
|
||||
* front of the argument list replacing the command name. Note no
|
||||
* interpretation of the words at this point.
|
||||
*/
|
||||
v = adrof1(STRshell, &aliases);
|
||||
if (v == 0) {
|
||||
vp = lastsh;
|
||||
vp[0] = adrof(STRshell) ? value(STRshell) : STR_SHELLPATH;
|
||||
vp[1] = NULL;
|
||||
#ifdef _PATH_BSHELL
|
||||
if (fd != -1 && c != '#')
|
||||
vp[0] = STR_BSHELL;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
vp = v->vec;
|
||||
st0 = st[0];
|
||||
st[0] = sf;
|
||||
ost = st;
|
||||
st = blkspl(vp, st); /* Splice up the new arglst */
|
||||
ost[0] = st0;
|
||||
sf = *st;
|
||||
/* The order for the conversions is significant */
|
||||
t = short2blk(st);
|
||||
f = short2str(sf);
|
||||
xfree((ptr_t) st);
|
||||
Vt = t;
|
||||
(void)execve(f, t, environ);
|
||||
Vt = 0;
|
||||
blkfree((Char **) t);
|
||||
/* FALLTHROUGH */
|
||||
|
||||
case ENOMEM:
|
||||
stderror(ERR_SYSTEM, f, strerror(errno));
|
||||
/* NOTREACHED */
|
||||
|
||||
case ENOENT:
|
||||
break;
|
||||
|
||||
default:
|
||||
if (exerr == 0) {
|
||||
exerr = strerror(errno);
|
||||
if (expath)
|
||||
xfree((ptr_t) expath);
|
||||
expath = Strsave(sf);
|
||||
Vexpath = expath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
void
|
||||
execash(Char **t, struct command *kp)
|
||||
{
|
||||
jmp_buf osetexit;
|
||||
sig_t osigint, osigquit, osigterm;
|
||||
int my_reenter, odidfds, oOLDSTD, oSHERR, oSHIN, oSHOUT;
|
||||
int saveDIAG, saveIN, saveOUT, saveSTD;
|
||||
|
||||
if (chkstop == 0 && setintr)
|
||||
panystop(0);
|
||||
/*
|
||||
* Hmm, we don't really want to do that now because we might
|
||||
* fail, but what is the choice
|
||||
*/
|
||||
rechist();
|
||||
|
||||
osigint = signal(SIGINT, parintr);
|
||||
osigquit = signal(SIGQUIT, parintr);
|
||||
osigterm = signal(SIGTERM, parterm);
|
||||
|
||||
odidfds = didfds;
|
||||
oSHIN = SHIN;
|
||||
oSHOUT = SHOUT;
|
||||
oSHERR = SHERR;
|
||||
oOLDSTD = OLDSTD;
|
||||
|
||||
saveIN = dcopy(SHIN, -1);
|
||||
saveOUT = dcopy(SHOUT, -1);
|
||||
saveDIAG = dcopy(SHERR, -1);
|
||||
saveSTD = dcopy(OLDSTD, -1);
|
||||
|
||||
lshift(kp->t_dcom, 1);
|
||||
|
||||
getexit(osetexit);
|
||||
|
||||
if ((my_reenter = setexit()) == 0) {
|
||||
SHIN = dcopy(0, -1);
|
||||
SHOUT = dcopy(1, -1);
|
||||
SHERR = dcopy(2, -1);
|
||||
didfds = 0;
|
||||
doexec(t, kp);
|
||||
}
|
||||
|
||||
(void)signal(SIGINT, osigint);
|
||||
(void)signal(SIGQUIT, osigquit);
|
||||
(void)signal(SIGTERM, osigterm);
|
||||
|
||||
doneinp = 0;
|
||||
didfds = odidfds;
|
||||
(void)close(SHIN);
|
||||
(void)close(SHOUT);
|
||||
(void)close(SHERR);
|
||||
(void)close(OLDSTD);
|
||||
SHIN = dmove(saveIN, oSHIN);
|
||||
SHOUT = dmove(saveOUT, oSHOUT);
|
||||
SHERR = dmove(saveDIAG, oSHERR);
|
||||
OLDSTD = dmove(saveSTD, oOLDSTD);
|
||||
|
||||
resexit(osetexit);
|
||||
if (my_reenter)
|
||||
stderror(ERR_SILENT);
|
||||
}
|
||||
|
||||
void
|
||||
xechoit(Char **t)
|
||||
{
|
||||
if (adrof(STRecho)) {
|
||||
int odidfds = didfds;
|
||||
(void)fflush(csherr);
|
||||
odidfds = didfds;
|
||||
didfds = 0;
|
||||
blkpr(csherr, t);
|
||||
(void)fputc('\n', csherr);
|
||||
(void)fflush(csherr);
|
||||
didfds = odidfds;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
/*ARGSUSED*/
|
||||
dohash(Char **v, struct command *t)
|
||||
{
|
||||
struct dirent *dp;
|
||||
struct varent *pathv;
|
||||
DIR *dirp;
|
||||
Char **pv;
|
||||
size_t cnt;
|
||||
int hashval, i;
|
||||
|
||||
i = 0;
|
||||
havhash = 1;
|
||||
pathv = adrof(STRpath);
|
||||
|
||||
for (cnt = 0; cnt < sizeof xhash; cnt++)
|
||||
xhash[cnt] = 0;
|
||||
if (pathv == 0)
|
||||
return;
|
||||
for (pv = pathv->vec; *pv; pv++, i++) {
|
||||
if (pv[0][0] != '/')
|
||||
continue;
|
||||
dirp = opendir(short2str(*pv));
|
||||
if (dirp == NULL)
|
||||
continue;
|
||||
while ((dp = readdir(dirp)) != NULL) {
|
||||
if (dp->d_ino == 0)
|
||||
continue;
|
||||
if (dp->d_name[0] == '.' &&
|
||||
(dp->d_name[1] == '\0' ||
|
||||
(dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
|
||||
continue;
|
||||
hashval = hash(hashname(str2short(dp->d_name)), i);
|
||||
bis(xhash, hashval);
|
||||
/* tw_add_comm_name (dp->d_name); */
|
||||
}
|
||||
(void) closedir(dirp);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
/*ARGSUSED*/
|
||||
dounhash(Char **v, struct command *t)
|
||||
{
|
||||
havhash = 0;
|
||||
}
|
||||
|
||||
void
|
||||
/*ARGSUSED*/
|
||||
hashstat(Char **v, struct command *t)
|
||||
{
|
||||
if (hits + misses)
|
||||
(void)fprintf(cshout, "%d hits, %d misses, %d%%\n",
|
||||
hits, misses, 100 * hits / (hits + misses));
|
||||
}
|
||||
|
||||
/*
|
||||
* Hash a command name.
|
||||
*/
|
||||
static int
|
||||
hashname(Char *cp)
|
||||
{
|
||||
long h = 0;
|
||||
|
||||
while (*cp)
|
||||
h = hash(h, *cp++);
|
||||
return ((int) h);
|
||||
}
|
||||
|
||||
static int
|
||||
iscommand(Char *name)
|
||||
{
|
||||
struct varent *v;
|
||||
Char **pv, *sav;
|
||||
int hashval, hashval1, i;
|
||||
int slash;
|
||||
|
||||
hashval = 0;
|
||||
slash = any(short2str(name), '/');
|
||||
v = adrof(STRpath);
|
||||
|
||||
if (v == 0 || v->vec[0] == 0 || slash)
|
||||
pv = justabs;
|
||||
else
|
||||
pv = v->vec;
|
||||
sav = Strspl(STRslash, name); /* / command name for postpending */
|
||||
if (havhash)
|
||||
hashval = hashname(name);
|
||||
i = 0;
|
||||
do {
|
||||
if (!slash && pv[0][0] == '/' && havhash) {
|
||||
hashval1 = hash(hashval, i);
|
||||
if (!bit(xhash, hashval1))
|
||||
goto cont;
|
||||
}
|
||||
if (pv[0][0] == 0 || eq(pv[0], STRdot)) { /* don't make ./xxx */
|
||||
if (executable(NULL, name, 0)) {
|
||||
xfree((ptr_t) sav);
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (executable(*pv, sav, 0)) {
|
||||
xfree((ptr_t) sav);
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
cont:
|
||||
pv++;
|
||||
i++;
|
||||
} while (*pv);
|
||||
xfree((ptr_t) sav);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Also by:
|
||||
* Andreas Luik <luik@isaak.isa.de>
|
||||
* I S A GmbH - Informationssysteme fuer computerintegrierte Automatisierung
|
||||
* Azenberstr. 35
|
||||
* D-7000 Stuttgart 1
|
||||
* West-Germany
|
||||
* is the executable() routine below and changes to iscommand().
|
||||
* Thanks again!!
|
||||
*/
|
||||
|
||||
/*
|
||||
* executable() examines the pathname obtained by concatenating dir and name
|
||||
* (dir may be NULL), and returns 1 either if it is executable by us, or
|
||||
* if dir_ok is set and the pathname refers to a directory.
|
||||
* This is a bit kludgy, but in the name of optimization...
|
||||
*/
|
||||
static int
|
||||
executable(Char *dir, Char *name, int dir_ok)
|
||||
{
|
||||
struct stat stbuf;
|
||||
Char path[MAXPATHLEN + 1], *dp, *sp;
|
||||
char *strname;
|
||||
|
||||
if (dir && *dir) {
|
||||
for (dp = path, sp = dir; *sp; *dp++ = *sp++)
|
||||
if (dp == &path[MAXPATHLEN + 1]) {
|
||||
*--dp = '\0';
|
||||
break;
|
||||
}
|
||||
for (sp = name; *sp; *dp++ = *sp++)
|
||||
if (dp == &path[MAXPATHLEN + 1]) {
|
||||
*--dp = '\0';
|
||||
break;
|
||||
}
|
||||
*dp = '\0';
|
||||
strname = short2str(path);
|
||||
}
|
||||
else
|
||||
strname = short2str(name);
|
||||
return (stat(strname, &stbuf) != -1 && ((S_ISREG(stbuf.st_mode) &&
|
||||
/* save time by not calling access() in the hopeless case */
|
||||
(stbuf.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)) &&
|
||||
access(strname, X_OK) == 0) || (dir_ok && S_ISDIR(stbuf.st_mode))));
|
||||
}
|
||||
|
||||
/* The dowhich() is by:
|
||||
* Andreas Luik <luik@isaak.isa.de>
|
||||
* I S A GmbH - Informationssysteme fuer computerintegrierte Automatisierung
|
||||
* Azenberstr. 35
|
||||
* D-7000 Stuttgart 1
|
||||
* West-Germany
|
||||
* Thanks!!
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
void
|
||||
dowhich(Char **v, struct command *c)
|
||||
{
|
||||
struct wordent lexw[3];
|
||||
struct varent *vp;
|
||||
|
||||
lexw[0].next = &lexw[1];
|
||||
lexw[1].next = &lexw[2];
|
||||
lexw[2].next = &lexw[0];
|
||||
|
||||
lexw[0].prev = &lexw[2];
|
||||
lexw[1].prev = &lexw[0];
|
||||
lexw[2].prev = &lexw[1];
|
||||
|
||||
lexw[0].word = STRNULL;
|
||||
lexw[2].word = STRret;
|
||||
|
||||
while (*++v) {
|
||||
if ((vp = adrof1(*v, &aliases)) != NULL) {
|
||||
(void)fprintf(cshout, "%s: \t aliased to ", vis_str(*v));
|
||||
blkpr(cshout, vp->vec);
|
||||
(void)fputc('\n', cshout);
|
||||
set(STRstatus, Strsave(STR0));
|
||||
}
|
||||
else {
|
||||
lexw[1].word = *v;
|
||||
set(STRstatus, Strsave(tellmewhat(lexw, NULL) ? STR0 : STR1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
tellmewhat(struct wordent *lexp, Char *str)
|
||||
{
|
||||
struct biltins *bptr;
|
||||
struct wordent *sp;
|
||||
Char *cmd, *s0, *s1, *s2;
|
||||
int i;
|
||||
int aliased, found;
|
||||
Char qc;
|
||||
|
||||
aliased = 0;
|
||||
sp = lexp->next;
|
||||
|
||||
if (adrof1(sp->word, &aliases)) {
|
||||
alias(lexp);
|
||||
sp = lexp->next;
|
||||
aliased = 1;
|
||||
}
|
||||
|
||||
s0 = sp->word; /* to get the memory freeing right... */
|
||||
|
||||
/* handle quoted alias hack */
|
||||
if ((*(sp->word) & (QUOTE | TRIM)) == QUOTE)
|
||||
(sp->word)++;
|
||||
|
||||
/* do quoting, if it hasn't been done */
|
||||
s1 = s2 = sp->word;
|
||||
while (*s2)
|
||||
switch (*s2) {
|
||||
case '\'':
|
||||
case '"':
|
||||
qc = *s2++;
|
||||
while (*s2 && *s2 != qc)
|
||||
*s1++ = (Char)(*s2++ | QUOTE);
|
||||
if (*s2)
|
||||
s2++;
|
||||
break;
|
||||
case '\\':
|
||||
if (*++s2)
|
||||
*s1++ = (Char)(*s2++ | QUOTE);
|
||||
break;
|
||||
default:
|
||||
*s1++ = *s2++;
|
||||
}
|
||||
*s1 = '\0';
|
||||
|
||||
for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) {
|
||||
if (eq(sp->word, str2short(bptr->bname))) {
|
||||
if (str == NULL) {
|
||||
if (aliased)
|
||||
prlex(cshout, lexp);
|
||||
(void)fprintf(cshout, "%s: shell built-in command.\n",
|
||||
vis_str(sp->word));
|
||||
}
|
||||
else
|
||||
(void)Strcpy(str, sp->word);
|
||||
sp->word = s0; /* we save and then restore this */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
sp->word = cmd = globone(sp->word, G_IGNORE);
|
||||
|
||||
if ((i = iscommand(sp->word)) != 0) {
|
||||
Char **pv;
|
||||
struct varent *v;
|
||||
int slash = any(short2str(sp->word), '/');
|
||||
|
||||
v = adrof(STRpath);
|
||||
if (v == 0 || v->vec[0] == 0 || slash)
|
||||
pv = justabs;
|
||||
else
|
||||
pv = v->vec;
|
||||
|
||||
while (--i)
|
||||
pv++;
|
||||
if (pv[0][0] == 0 || eq(pv[0], STRdot)) {
|
||||
if (!slash) {
|
||||
sp->word = Strspl(STRdotsl, sp->word);
|
||||
prlex(cshout, lexp);
|
||||
xfree((ptr_t) sp->word);
|
||||
}
|
||||
else
|
||||
prlex(cshout, lexp);
|
||||
}
|
||||
else {
|
||||
s1 = Strspl(*pv, STRslash);
|
||||
sp->word = Strspl(s1, sp->word);
|
||||
xfree((ptr_t) s1);
|
||||
if (str == NULL)
|
||||
prlex(cshout, lexp);
|
||||
else
|
||||
(void)Strcpy(str, sp->word);
|
||||
xfree((ptr_t) sp->word);
|
||||
}
|
||||
found = 1;
|
||||
}
|
||||
else {
|
||||
if (str == NULL) {
|
||||
if (aliased)
|
||||
prlex(cshout, lexp);
|
||||
(void)fprintf(csherr,
|
||||
"%s: Command not found.\n", vis_str(sp->word));
|
||||
}
|
||||
else
|
||||
(void)Strcpy(str, sp->word);
|
||||
found = 0;
|
||||
}
|
||||
sp->word = s0; /* we save and then restore this */
|
||||
xfree((ptr_t) cmd);
|
||||
return found;
|
||||
}
|
661
bin/csh/exp.c
Normal file
661
bin/csh/exp.c
Normal file
|
@ -0,0 +1,661 @@
|
|||
/* $NetBSD: exp.c,v 1.20 2009/02/14 07:12:29 lukem Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1980, 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)exp.c 8.1 (Berkeley) 5/31/93";
|
||||
#else
|
||||
__RCSID("$NetBSD: exp.c,v 1.20 2009/02/14 07:12:29 lukem Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef SHORT_STRINGS
|
||||
#include <string.h>
|
||||
#endif /* SHORT_STRINGS */
|
||||
|
||||
#include "csh.h"
|
||||
#include "extern.h"
|
||||
|
||||
#define IGNORE 1 /* in ignore, it means to ignore value, just parse */
|
||||
#define NOGLOB 2 /* in ignore, it means not to globone */
|
||||
|
||||
#define ADDOP 1
|
||||
#define MULOP 2
|
||||
#define EQOP 4
|
||||
#define RELOP 8
|
||||
#define RESTOP 16
|
||||
#define ANYOP 31
|
||||
|
||||
#define EQEQ 1
|
||||
#define GTR 2
|
||||
#define LSS 4
|
||||
#define NOTEQ 6
|
||||
#define EQMATCH 7
|
||||
#define NOTEQMATCH 8
|
||||
|
||||
static int exp1(Char ***, int);
|
||||
static int csh_exp2(Char ***, int);
|
||||
static int exp2a(Char ***, int);
|
||||
static int exp2b(Char ***, int);
|
||||
static int exp2c(Char ***, int);
|
||||
static Char *exp3(Char ***, int);
|
||||
static Char *exp3a(Char ***, int);
|
||||
static Char *exp4(Char ***, int);
|
||||
static Char *exp5(Char ***, int);
|
||||
static Char *exp6(Char ***, int);
|
||||
static void evalav(Char **);
|
||||
static int isa(Char *, int);
|
||||
static int egetn(Char *);
|
||||
|
||||
#ifdef EDEBUG
|
||||
static void etracc(char *, Char *, Char ***);
|
||||
static void etraci(char *, int, Char ***);
|
||||
#endif
|
||||
|
||||
int
|
||||
expr(Char ***vp)
|
||||
{
|
||||
return (exp0(vp, 0));
|
||||
}
|
||||
|
||||
int
|
||||
exp0(Char ***vp, int ignore)
|
||||
{
|
||||
int p1;
|
||||
|
||||
p1 = exp1(vp, ignore);
|
||||
#ifdef EDEBUG
|
||||
etraci("exp0 p1", p1, vp);
|
||||
#endif
|
||||
if (**vp && eq(**vp, STRor2)) {
|
||||
int p2;
|
||||
|
||||
(*vp)++;
|
||||
p2 = exp0(vp, (ignore & IGNORE) || p1);
|
||||
#ifdef EDEBUG
|
||||
etraci("exp0 p2", p2, vp);
|
||||
#endif
|
||||
return (p1 || p2);
|
||||
}
|
||||
return (p1);
|
||||
}
|
||||
|
||||
static int
|
||||
exp1(Char ***vp, int ignore)
|
||||
{
|
||||
int p1;
|
||||
|
||||
p1 = csh_exp2(vp, ignore);
|
||||
#ifdef EDEBUG
|
||||
etraci("exp1 p1", p1, vp);
|
||||
#endif
|
||||
if (**vp && eq(**vp, STRand2)) {
|
||||
int p2;
|
||||
|
||||
(*vp)++;
|
||||
p2 = exp1(vp, (ignore & IGNORE) || !p1);
|
||||
#ifdef EDEBUG
|
||||
etraci("exp1 p2", p2, vp);
|
||||
#endif
|
||||
return (p1 && p2);
|
||||
}
|
||||
return (p1);
|
||||
}
|
||||
|
||||
static int
|
||||
csh_exp2(Char ***vp, int ignore)
|
||||
{
|
||||
int p1;
|
||||
|
||||
p1 = exp2a(vp, ignore);
|
||||
#ifdef EDEBUG
|
||||
etraci("exp3 p1", p1, vp);
|
||||
#endif
|
||||
if (**vp && eq(**vp, STRor)) {
|
||||
int p2;
|
||||
|
||||
(*vp)++;
|
||||
p2 = csh_exp2(vp, ignore);
|
||||
#ifdef EDEBUG
|
||||
etraci("exp3 p2", p2, vp);
|
||||
#endif
|
||||
return (p1 | p2);
|
||||
}
|
||||
return (p1);
|
||||
}
|
||||
|
||||
static int
|
||||
exp2a(Char ***vp, int ignore)
|
||||
{
|
||||
int p1;
|
||||
|
||||
p1 = exp2b(vp, ignore);
|
||||
#ifdef EDEBUG
|
||||
etraci("exp2a p1", p1, vp);
|
||||
#endif
|
||||
if (**vp && eq(**vp, STRcaret)) {
|
||||
int p2;
|
||||
|
||||
(*vp)++;
|
||||
p2 = exp2a(vp, ignore);
|
||||
#ifdef EDEBUG
|
||||
etraci("exp2a p2", p2, vp);
|
||||
#endif
|
||||
return (p1 ^ p2);
|
||||
}
|
||||
return (p1);
|
||||
}
|
||||
|
||||
static int
|
||||
exp2b(Char ***vp, int ignore)
|
||||
{
|
||||
int p1;
|
||||
|
||||
p1 = exp2c(vp, ignore);
|
||||
#ifdef EDEBUG
|
||||
etraci("exp2b p1", p1, vp);
|
||||
#endif
|
||||
if (**vp && eq(**vp, STRand)) {
|
||||
int p2;
|
||||
|
||||
(*vp)++;
|
||||
p2 = exp2b(vp, ignore);
|
||||
#ifdef EDEBUG
|
||||
etraci("exp2b p2", p2, vp);
|
||||
#endif
|
||||
return (p1 & p2);
|
||||
}
|
||||
return (p1);
|
||||
}
|
||||
|
||||
static int
|
||||
exp2c(Char ***vp, int ignore)
|
||||
{
|
||||
Char *p1, *p2;
|
||||
int i;
|
||||
|
||||
p1 = exp3(vp, ignore);
|
||||
#ifdef EDEBUG
|
||||
etracc("exp2c p1", p1, vp);
|
||||
#endif
|
||||
if ((i = isa(**vp, EQOP)) != 0) {
|
||||
(*vp)++;
|
||||
if (i == EQMATCH || i == NOTEQMATCH)
|
||||
ignore |= NOGLOB;
|
||||
p2 = exp3(vp, ignore);
|
||||
#ifdef EDEBUG
|
||||
etracc("exp2c p2", p2, vp);
|
||||
#endif
|
||||
if (!(ignore & IGNORE))
|
||||
switch (i) {
|
||||
case EQEQ:
|
||||
i = eq(p1, p2);
|
||||
break;
|
||||
case EQMATCH:
|
||||
i = Gmatch(p1, p2);
|
||||
break;
|
||||
case NOTEQ:
|
||||
i = !eq(p1, p2);
|
||||
break;
|
||||
case NOTEQMATCH:
|
||||
i = !Gmatch(p1, p2);
|
||||
break;
|
||||
}
|
||||
xfree((ptr_t) p1);
|
||||
xfree((ptr_t) p2);
|
||||
return (i);
|
||||
}
|
||||
i = egetn(p1);
|
||||
xfree((ptr_t) p1);
|
||||
return (i);
|
||||
}
|
||||
|
||||
static Char *
|
||||
exp3(Char ***vp, int ignore)
|
||||
{
|
||||
Char *p1, *p2;
|
||||
int i;
|
||||
|
||||
p1 = exp3a(vp, ignore);
|
||||
#ifdef EDEBUG
|
||||
etracc("exp3 p1", p1, vp);
|
||||
#endif
|
||||
if ((i = isa(**vp, RELOP)) != 0) {
|
||||
(*vp)++;
|
||||
if (**vp && eq(**vp, STRequal))
|
||||
i |= 1, (*vp)++;
|
||||
p2 = exp3(vp, ignore);
|
||||
#ifdef EDEBUG
|
||||
etracc("exp3 p2", p2, vp);
|
||||
#endif
|
||||
if (!(ignore & IGNORE))
|
||||
switch (i) {
|
||||
case GTR:
|
||||
i = egetn(p1) > egetn(p2);
|
||||
break;
|
||||
case GTR | 1:
|
||||
i = egetn(p1) >= egetn(p2);
|
||||
break;
|
||||
case LSS:
|
||||
i = egetn(p1) < egetn(p2);
|
||||
break;
|
||||
case LSS | 1:
|
||||
i = egetn(p1) <= egetn(p2);
|
||||
break;
|
||||
}
|
||||
xfree((ptr_t) p1);
|
||||
xfree((ptr_t) p2);
|
||||
return (putn(i));
|
||||
}
|
||||
return (p1);
|
||||
}
|
||||
|
||||
static Char *
|
||||
exp3a(Char ***vp, int ignore)
|
||||
{
|
||||
Char *op, *p1, *p2;
|
||||
int i;
|
||||
|
||||
p1 = exp4(vp, ignore);
|
||||
#ifdef EDEBUG
|
||||
etracc("exp3a p1", p1, vp);
|
||||
#endif
|
||||
op = **vp;
|
||||
if (op && any("<>", op[0]) && op[0] == op[1]) {
|
||||
(*vp)++;
|
||||
p2 = exp3a(vp, ignore);
|
||||
#ifdef EDEBUG
|
||||
etracc("exp3a p2", p2, vp);
|
||||
#endif
|
||||
if (op[0] == '<')
|
||||
i = egetn(p1) << egetn(p2);
|
||||
else
|
||||
i = egetn(p1) >> egetn(p2);
|
||||
xfree((ptr_t) p1);
|
||||
xfree((ptr_t) p2);
|
||||
return (putn(i));
|
||||
}
|
||||
return (p1);
|
||||
}
|
||||
|
||||
static Char *
|
||||
exp4(Char ***vp, int ignore)
|
||||
{
|
||||
Char *p1, *p2;
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
p1 = exp5(vp, ignore);
|
||||
#ifdef EDEBUG
|
||||
etracc("exp4 p1", p1, vp);
|
||||
#endif
|
||||
if (isa(**vp, ADDOP)) {
|
||||
Char *op;
|
||||
|
||||
op = *(*vp)++;
|
||||
p2 = exp4(vp, ignore);
|
||||
#ifdef EDEBUG
|
||||
etracc("exp4 p2", p2, vp);
|
||||
#endif
|
||||
if (!(ignore & IGNORE))
|
||||
switch (op[0]) {
|
||||
case '+':
|
||||
i = egetn(p1) + egetn(p2);
|
||||
break;
|
||||
case '-':
|
||||
i = egetn(p1) - egetn(p2);
|
||||
break;
|
||||
}
|
||||
xfree((ptr_t) p1);
|
||||
xfree((ptr_t) p2);
|
||||
return (putn(i));
|
||||
}
|
||||
return (p1);
|
||||
}
|
||||
|
||||
static Char *
|
||||
exp5(Char ***vp, int ignore)
|
||||
{
|
||||
Char *p1, *p2;
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
p1 = exp6(vp, ignore);
|
||||
#ifdef EDEBUG
|
||||
etracc("exp5 p1", p1, vp);
|
||||
#endif
|
||||
if (isa(**vp, MULOP)) {
|
||||
Char *op;
|
||||
|
||||
op = *(*vp)++;
|
||||
p2 = exp5(vp, ignore);
|
||||
#ifdef EDEBUG
|
||||
etracc("exp5 p2", p2, vp);
|
||||
#endif
|
||||
if (!(ignore & IGNORE))
|
||||
switch (op[0]) {
|
||||
case '*':
|
||||
i = egetn(p1) * egetn(p2);
|
||||
break;
|
||||
case '/':
|
||||
i = egetn(p2);
|
||||
if (i == 0)
|
||||
stderror(ERR_DIV0);
|
||||
i = egetn(p1) / i;
|
||||
break;
|
||||
case '%':
|
||||
i = egetn(p2);
|
||||
if (i == 0)
|
||||
stderror(ERR_MOD0);
|
||||
i = egetn(p1) % i;
|
||||
break;
|
||||
}
|
||||
xfree((ptr_t) p1);
|
||||
xfree((ptr_t) p2);
|
||||
return (putn(i));
|
||||
}
|
||||
return (p1);
|
||||
}
|
||||
|
||||
static Char *
|
||||
exp6(Char ***vp, int ignore)
|
||||
{
|
||||
Char *cp, *dp, *ep;
|
||||
int ccode, i;
|
||||
|
||||
i = 0;
|
||||
if (**vp == 0)
|
||||
stderror(ERR_NAME | ERR_EXPRESSION);
|
||||
if (eq(**vp, STRbang)) {
|
||||
(*vp)++;
|
||||
cp = exp6(vp, ignore);
|
||||
#ifdef EDEBUG
|
||||
etracc("exp6 ! cp", cp, vp);
|
||||
#endif
|
||||
i = egetn(cp);
|
||||
xfree((ptr_t) cp);
|
||||
return (putn(!i));
|
||||
}
|
||||
if (eq(**vp, STRtilde)) {
|
||||
(*vp)++;
|
||||
cp = exp6(vp, ignore);
|
||||
#ifdef EDEBUG
|
||||
etracc("exp6 ~ cp", cp, vp);
|
||||
#endif
|
||||
i = egetn(cp);
|
||||
xfree((ptr_t) cp);
|
||||
return (putn(~i));
|
||||
}
|
||||
if (eq(**vp, STRLparen)) {
|
||||
(*vp)++;
|
||||
ccode = exp0(vp, ignore);
|
||||
#ifdef EDEBUG
|
||||
etraci("exp6 () ccode", ccode, vp);
|
||||
#endif
|
||||
if (**vp == 0 || ***vp != ')')
|
||||
stderror(ERR_NAME | ERR_EXPRESSION);
|
||||
(*vp)++;
|
||||
return (putn(ccode));
|
||||
}
|
||||
if (eq(**vp, STRLbrace)) {
|
||||
struct command faket;
|
||||
Char *fakecom[2];
|
||||
Char **v;
|
||||
|
||||
faket.t_dtyp = NODE_COMMAND;
|
||||
faket.t_dflg = 0;
|
||||
faket.t_dcar = faket.t_dcdr = faket.t_dspr = NULL;
|
||||
faket.t_dcom = fakecom;
|
||||
fakecom[0] = STRfakecom;
|
||||
fakecom[1] = NULL;
|
||||
(*vp)++;
|
||||
v = *vp;
|
||||
for (;;) {
|
||||
if (!**vp)
|
||||
stderror(ERR_NAME | ERR_MISSING, '}');
|
||||
if (eq(*(*vp)++, STRRbrace))
|
||||
break;
|
||||
}
|
||||
if (ignore & IGNORE)
|
||||
return (Strsave(STRNULL));
|
||||
psavejob();
|
||||
if (pfork(&faket, -1) == 0) {
|
||||
*--(*vp) = 0;
|
||||
evalav(v);
|
||||
exitstat();
|
||||
}
|
||||
pwait();
|
||||
prestjob();
|
||||
#ifdef EDEBUG
|
||||
etraci("exp6 {} status", egetn(value(STRstatus)), vp);
|
||||
#endif
|
||||
return (putn(egetn(value(STRstatus)) == 0));
|
||||
}
|
||||
if (isa(**vp, ANYOP))
|
||||
return (Strsave(STRNULL));
|
||||
cp = *(*vp)++;
|
||||
if (*cp == '-' && any("erwxfdzopls", cp[1])) {
|
||||
struct stat stb;
|
||||
|
||||
if (cp[2] != '\0')
|
||||
stderror(ERR_NAME | ERR_FILEINQ);
|
||||
/*
|
||||
* Detect missing file names by checking for operator in the file name
|
||||
* position. However, if an operator name appears there, we must make
|
||||
* sure that there's no file by that name (e.g., "/") before announcing
|
||||
* an error. Even this check isn't quite right, since it doesn't take
|
||||
* globbing into account.
|
||||
*/
|
||||
if (isa(**vp, ANYOP) && stat(short2str(**vp), &stb))
|
||||
stderror(ERR_NAME | ERR_FILENAME);
|
||||
|
||||
dp = *(*vp)++;
|
||||
if (ignore & IGNORE)
|
||||
return (Strsave(STRNULL));
|
||||
ep = globone(dp, G_ERROR);
|
||||
switch (cp[1]) {
|
||||
case 'r':
|
||||
i = !access(short2str(ep), R_OK);
|
||||
break;
|
||||
case 'w':
|
||||
i = !access(short2str(ep), W_OK);
|
||||
break;
|
||||
case 'x':
|
||||
i = !access(short2str(ep), X_OK);
|
||||
break;
|
||||
default:
|
||||
if (cp[1] == 'l' ?
|
||||
lstat(short2str(ep), &stb) : stat(short2str(ep), &stb)) {
|
||||
xfree((ptr_t) ep);
|
||||
return (Strsave(STR0));
|
||||
}
|
||||
switch (cp[1]) {
|
||||
case 'd':
|
||||
i = S_ISDIR(stb.st_mode);
|
||||
break;
|
||||
case 'e':
|
||||
i = 1;
|
||||
break;
|
||||
case 'f':
|
||||
i = S_ISREG(stb.st_mode);
|
||||
break;
|
||||
case 'l':
|
||||
#ifdef S_ISLNK
|
||||
i = S_ISLNK(stb.st_mode);
|
||||
#else
|
||||
i = 0;
|
||||
#endif
|
||||
break;
|
||||
case 'o':
|
||||
i = stb.st_uid == (uid_t)uid;
|
||||
break;
|
||||
case 'p':
|
||||
#ifdef S_ISFIFO
|
||||
i = S_ISFIFO(stb.st_mode);
|
||||
#else
|
||||
i = 0;
|
||||
#endif
|
||||
break;
|
||||
case 's':
|
||||
#ifdef S_ISSOCK
|
||||
i = S_ISSOCK(stb.st_mode);
|
||||
#else
|
||||
i = 0;
|
||||
#endif
|
||||
break;
|
||||
case 'z':
|
||||
i = stb.st_size == 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef EDEBUG
|
||||
etraci("exp6 -? i", i, vp);
|
||||
#endif
|
||||
xfree((ptr_t) ep);
|
||||
return (putn(i));
|
||||
}
|
||||
#ifdef EDEBUG
|
||||
etracc("exp6 default", cp, vp);
|
||||
#endif
|
||||
return (ignore & NOGLOB ? Strsave(cp) : globone(cp, G_ERROR));
|
||||
}
|
||||
|
||||
static void
|
||||
evalav(Char **v)
|
||||
{
|
||||
struct wordent *hp, paraml1, *wdp;
|
||||
struct command *t;
|
||||
|
||||
hp = ¶ml1;
|
||||
wdp = hp;
|
||||
set(STRstatus, Strsave(STR0));
|
||||
hp->prev = hp->next = hp;
|
||||
hp->word = STRNULL;
|
||||
while (*v) {
|
||||
struct wordent *new;
|
||||
|
||||
new = (struct wordent *)xcalloc(1, sizeof *wdp);
|
||||
new->prev = wdp;
|
||||
new->next = hp;
|
||||
wdp->next = new;
|
||||
wdp = new;
|
||||
wdp->word = Strsave(*v++);
|
||||
}
|
||||
hp->prev = wdp;
|
||||
alias(¶ml1);
|
||||
t = syntax(paraml1.next, ¶ml1, 0);
|
||||
if (seterr)
|
||||
stderror(ERR_OLD);
|
||||
execute(t, -1, NULL, NULL);
|
||||
freelex(¶ml1), freesyn(t);
|
||||
}
|
||||
|
||||
static int
|
||||
isa(Char *cp, int what)
|
||||
{
|
||||
if (cp == 0)
|
||||
return ((what & RESTOP) != 0);
|
||||
if (cp[1] == 0) {
|
||||
if (what & ADDOP && (*cp == '+' || *cp == '-'))
|
||||
return (1);
|
||||
if (what & MULOP && (*cp == '*' || *cp == '/' || *cp == '%'))
|
||||
return (1);
|
||||
if (what & RESTOP && (*cp == '(' || *cp == ')' || *cp == '!' ||
|
||||
*cp == '~' || *cp == '^' || *cp == '"'))
|
||||
return (1);
|
||||
}
|
||||
else if (cp[2] == 0) {
|
||||
if (what & RESTOP) {
|
||||
if (cp[0] == '|' && cp[1] == '&')
|
||||
return (1);
|
||||
if (cp[0] == '<' && cp[1] == '<')
|
||||
return (1);
|
||||
if (cp[0] == '>' && cp[1] == '>')
|
||||
return (1);
|
||||
}
|
||||
if (what & EQOP) {
|
||||
if (cp[0] == '=') {
|
||||
if (cp[1] == '=')
|
||||
return (EQEQ);
|
||||
if (cp[1] == '~')
|
||||
return (EQMATCH);
|
||||
}
|
||||
else if (cp[0] == '!') {
|
||||
if (cp[1] == '=')
|
||||
return (NOTEQ);
|
||||
if (cp[1] == '~')
|
||||
return (NOTEQMATCH);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (what & RELOP) {
|
||||
if (*cp == '<')
|
||||
return (LSS);
|
||||
if (*cp == '>')
|
||||
return (GTR);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
egetn(Char *cp)
|
||||
{
|
||||
if (*cp && *cp != '-' && !Isdigit(*cp))
|
||||
stderror(ERR_NAME | ERR_EXPRESSION);
|
||||
return (getn(cp));
|
||||
}
|
||||
|
||||
/* Phew! */
|
||||
|
||||
#ifdef EDEBUG
|
||||
static void
|
||||
etraci(char *str, int i, Char ***vp)
|
||||
{
|
||||
(void)fprintf(csherr, "%s=%d\t", str, i);
|
||||
blkpr(csherr, *vp);
|
||||
(void)fprintf(csherr, "\n");
|
||||
}
|
||||
static void
|
||||
etracc(char *str, Char *cp, Char ***vp)
|
||||
{
|
||||
(void)fprintf(csherr, "%s=%s\t", str, vis_str(cp));
|
||||
blkpr(csherr, *vp);
|
||||
(void)fprintf(csherr, "\n");
|
||||
}
|
||||
#endif
|
341
bin/csh/extern.h
Normal file
341
bin/csh/extern.h
Normal file
|
@ -0,0 +1,341 @@
|
|||
/* $NetBSD: extern.h,v 1.29 2013/07/16 17:47:43 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)extern.h 8.1 (Berkeley) 5/31/93
|
||||
*/
|
||||
|
||||
#ifndef _EXTERN_H_
|
||||
#define _EXTERN_H_
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
/*
|
||||
* csh.c
|
||||
*/
|
||||
int gethdir(Char *);
|
||||
void dosource(Char **, struct command *);
|
||||
__dead void exitstat(void);
|
||||
__dead void goodbye(void);
|
||||
void importpath(Char *);
|
||||
void initdesc(void);
|
||||
__dead void pintr(int);
|
||||
__dead void pintr1(int);
|
||||
void printprompt(void);
|
||||
#ifdef EDIT
|
||||
char *printpromptstr(EditLine *);
|
||||
#endif
|
||||
void process(int);
|
||||
void rechist(void);
|
||||
void untty(void);
|
||||
int vis_fputc(int, FILE *);
|
||||
|
||||
#ifdef PROF
|
||||
__dead void done(int);
|
||||
#else
|
||||
__dead void xexit(int);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* dir.c
|
||||
*/
|
||||
void dinit(Char *);
|
||||
void dodirs(Char **, struct command *);
|
||||
Char *dcanon(Char *, Char *);
|
||||
void dtildepr(Char *, Char *);
|
||||
void dtilde(void);
|
||||
void dochngd(Char **, struct command *);
|
||||
Char *dnormalize(Char *);
|
||||
void dopushd(Char **, struct command *);
|
||||
void dopopd(Char **, struct command *);
|
||||
struct directory;
|
||||
void dfree(struct directory *);
|
||||
|
||||
/*
|
||||
* dol.c
|
||||
*/
|
||||
void Dfix(struct command *);
|
||||
Char *Dfix1(Char *);
|
||||
void heredoc(Char *);
|
||||
|
||||
/*
|
||||
* err.c
|
||||
*/
|
||||
void seterror(int, ...);
|
||||
__dead void stderror(int, ...);
|
||||
|
||||
/*
|
||||
* exec.c
|
||||
*/
|
||||
__dead void doexec(Char **, struct command *);
|
||||
void dohash(Char **, struct command *);
|
||||
void dounhash(Char **, struct command *);
|
||||
void dowhich(Char **, struct command *);
|
||||
void execash(Char **, struct command *);
|
||||
void hashstat(Char **, struct command *);
|
||||
void xechoit(Char **);
|
||||
|
||||
/*
|
||||
* exp.c
|
||||
*/
|
||||
int expr(Char ***);
|
||||
int exp0(Char ***, int);
|
||||
|
||||
/*
|
||||
* file.c
|
||||
*/
|
||||
#ifdef FILEC
|
||||
ssize_t tenex(Char *, size_t);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* func.c
|
||||
*/
|
||||
void Setenv(Char *, Char *);
|
||||
void doalias(Char **, struct command *);
|
||||
void dobreak(Char **, struct command *);
|
||||
void docontin(Char **, struct command *);
|
||||
void doecho(Char **, struct command *);
|
||||
void doelse(Char **, struct command *);
|
||||
void doend(Char **, struct command *);
|
||||
void doeval(Char **, struct command *);
|
||||
void doexit(Char **, struct command *);
|
||||
void doforeach(Char **, struct command *);
|
||||
void doglob(Char **, struct command *);
|
||||
void dogoto(Char **, struct command *);
|
||||
void doif(Char **, struct command *);
|
||||
void dolimit(Char **, struct command *);
|
||||
__dead void dologin(Char **, struct command *);
|
||||
__dead void dologout(Char **, struct command *);
|
||||
void donohup(Char **, struct command *);
|
||||
void doonintr(Char **, struct command *);
|
||||
void doprintf(Char **, struct command *);
|
||||
void dorepeat(Char **, struct command *);
|
||||
void dosetenv(Char **, struct command *);
|
||||
void dosuspend(Char **, struct command *);
|
||||
void doswbrk(Char **, struct command *);
|
||||
void doswitch(Char **, struct command *);
|
||||
void doumask(Char **, struct command *);
|
||||
void dounlimit(Char **, struct command *);
|
||||
void dounsetenv(Char **, struct command *);
|
||||
void dowhile(Char **, struct command *);
|
||||
void dozip(Char **, struct command *);
|
||||
void func(struct command *, struct biltins *);
|
||||
struct biltins *isbfunc(struct command *);
|
||||
void prvars(void);
|
||||
void gotolab(Char *);
|
||||
int srchx(Char *);
|
||||
void unalias(Char **, struct command *);
|
||||
void wfree(void);
|
||||
|
||||
/*
|
||||
* glob.c
|
||||
*/
|
||||
Char **dobackp(Char *, int);
|
||||
void Gcat(Char *, Char *);
|
||||
Char *globone(Char *, int);
|
||||
int Gmatch(Char *, Char *);
|
||||
void ginit(void);
|
||||
Char **globall(Char **);
|
||||
void rscan(Char **, void (*)(int));
|
||||
void tglob(Char **);
|
||||
void trim(Char **);
|
||||
#ifdef FILEC
|
||||
int sortscmp(const ptr_t, const ptr_t);
|
||||
#endif /* FILEC */
|
||||
|
||||
/*
|
||||
* hist.c
|
||||
*/
|
||||
void dohist(Char **, struct command *);
|
||||
struct Hist *enthist(int, struct wordent *, int);
|
||||
#ifdef EDIT
|
||||
void loadhist(struct Hist *);
|
||||
#endif
|
||||
void savehist(struct wordent *);
|
||||
|
||||
/*
|
||||
* lex.c
|
||||
*/
|
||||
void addla(Char *);
|
||||
void bseek(struct Ain *);
|
||||
void btell(struct Ain *);
|
||||
void btoeof(void);
|
||||
void copylex(struct wordent *, struct wordent *);
|
||||
Char *domod(Char *, int);
|
||||
void freelex(struct wordent *);
|
||||
int lex(struct wordent *);
|
||||
void prlex(FILE *, struct wordent *);
|
||||
#ifdef EDIT
|
||||
int sprlex(char **, struct wordent *);
|
||||
#endif
|
||||
int readc(int);
|
||||
void settell(void);
|
||||
void unreadc(int);
|
||||
|
||||
/*
|
||||
* misc.c
|
||||
*/
|
||||
int any(const char *, int);
|
||||
Char **blkcat(Char **, Char **);
|
||||
Char **blkcpy(Char **, Char **);
|
||||
Char **blkend(Char **);
|
||||
void blkfree(Char **);
|
||||
int blklen(Char **);
|
||||
void blkpr(FILE *, Char **);
|
||||
Char **blkspl(Char **, Char **);
|
||||
void closem(void);
|
||||
Char **copyblk(Char **);
|
||||
int dcopy(int, int);
|
||||
int dmove(int, int);
|
||||
void donefds(void);
|
||||
Char lastchr(Char *);
|
||||
void lshift(Char **, size_t);
|
||||
int number(Char *);
|
||||
int prefix(Char *, Char *);
|
||||
Char **saveblk(Char **);
|
||||
Char *strip(Char *);
|
||||
Char *quote(Char *);
|
||||
char *strsave(const char *);
|
||||
char *strspl(char *, char *);
|
||||
__dead void udvar(Char *);
|
||||
|
||||
#ifndef SHORT_STRINGS
|
||||
# ifdef NOTUSED
|
||||
char *strstr(const char *, const char *);
|
||||
# endif /* NOTUSED */
|
||||
char *strend(char *);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* parse.c
|
||||
*/
|
||||
void alias(struct wordent *);
|
||||
void freesyn(struct command *);
|
||||
struct command *syntax(struct wordent *, struct wordent *, int);
|
||||
|
||||
|
||||
/*
|
||||
* proc.c
|
||||
*/
|
||||
void dobg(Char **, struct command *);
|
||||
void dobg1(Char **, struct command *);
|
||||
void dofg(Char **, struct command *);
|
||||
void dofg1(Char **, struct command *);
|
||||
void dojobs(Char **, struct command *);
|
||||
void dokill(Char **, struct command *);
|
||||
void donotify(Char **, struct command *);
|
||||
void dostop(Char **, struct command *);
|
||||
void dowait(Char **, struct command *);
|
||||
void palloc(int, struct command *);
|
||||
void panystop(int);
|
||||
void pchild(int);
|
||||
void pendjob(void);
|
||||
struct process *pfind(Char *);
|
||||
int pfork(struct command *, int);
|
||||
void pgetty(int, int);
|
||||
void pjwait(struct process *);
|
||||
void pnote(void);
|
||||
void prestjob(void);
|
||||
void psavejob(void);
|
||||
void pstart(struct process *, int);
|
||||
void pwait(void);
|
||||
|
||||
/*
|
||||
* sem.c
|
||||
*/
|
||||
void execute(struct command *, int, int *, int *);
|
||||
void mypipe(int *);
|
||||
|
||||
/*
|
||||
* set.c
|
||||
*/
|
||||
struct varent*adrof1(Char *, struct varent *);
|
||||
void doset(Char **, struct command *);
|
||||
void dolet(Char **, struct command *);
|
||||
Char *putn(int);
|
||||
int getn(Char *);
|
||||
Char *value1(Char *, struct varent *);
|
||||
void set(Char *, Char *);
|
||||
void set1(Char *, Char **, struct varent *);
|
||||
void setq(Char *, Char **, struct varent *);
|
||||
void unset(Char **, struct command *);
|
||||
void unset1(Char *[], struct varent *);
|
||||
void unsetv(Char *);
|
||||
void setNS(Char *);
|
||||
void shift(Char **, struct command *);
|
||||
void plist(struct varent *);
|
||||
|
||||
/*
|
||||
* time.c
|
||||
*/
|
||||
void donice(Char **, struct command *);
|
||||
void dotime(Char **, struct command *);
|
||||
void prusage(FILE *, struct rusage *, struct rusage *, struct timespec *,
|
||||
struct timespec *);
|
||||
void ruadd(struct rusage *, struct rusage *);
|
||||
void settimes(void);
|
||||
void psecs(long);
|
||||
|
||||
/*
|
||||
* alloc.c
|
||||
*/
|
||||
void Free(ptr_t);
|
||||
ptr_t Malloc(size_t);
|
||||
ptr_t Realloc(ptr_t, size_t);
|
||||
ptr_t Calloc(size_t, size_t);
|
||||
|
||||
/*
|
||||
* str.c:
|
||||
*/
|
||||
#ifdef SHORT_STRINGS
|
||||
Char *s_strchr(const Char *, int);
|
||||
Char *s_strrchr(const Char *, int);
|
||||
Char *s_strcat(Char *, const Char *);
|
||||
#ifdef NOTUSED
|
||||
Char *s_strncat(Char *, const Char *, size_t);
|
||||
#endif
|
||||
Char *s_strcpy(Char *, const Char *);
|
||||
Char *s_strncpy(Char *, const Char *, size_t);
|
||||
Char *s_strspl(const Char *, const Char *);
|
||||
size_t s_strlen(const Char *);
|
||||
int s_strcmp(const Char *, const Char *);
|
||||
int s_strncmp(const Char *, const Char *, size_t);
|
||||
Char *s_strsave(const Char *);
|
||||
Char *s_strend(const Char *);
|
||||
Char *s_strstr(const Char *, const Char *);
|
||||
Char *str2short(const char *);
|
||||
Char **blk2short(char **);
|
||||
char *short2str(const Char *);
|
||||
char **short2blk(Char * const *);
|
||||
#endif
|
||||
char *short2qstr(const Char *);
|
||||
char *vis_str(const Char *);
|
||||
|
||||
#endif /* !_EXTERN_H_ */
|
729
bin/csh/file.c
Normal file
729
bin/csh/file.c
Normal file
|
@ -0,0 +1,729 @@
|
|||
/* $NetBSD: file.c,v 1.30 2013/07/16 17:47:43 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1980, 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)file.c 8.2 (Berkeley) 3/19/94";
|
||||
#else
|
||||
__RCSID("$NetBSD: file.c,v 1.30 2013/07/16 17:47:43 christos Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#ifdef FILEC
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/tty.h>
|
||||
|
||||
#include <dirent.h>
|
||||
#include <pwd.h>
|
||||
#include <termios.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef SHORT_STRINGS
|
||||
#include <string.h>
|
||||
#endif /* SHORT_STRINGS */
|
||||
|
||||
#include "csh.h"
|
||||
#include "extern.h"
|
||||
|
||||
/*
|
||||
* Tenex style file name recognition, .. and more.
|
||||
* History:
|
||||
* Author: Ken Greer, Sept. 1975, CMU.
|
||||
* Finally got around to adding to the Cshell., Ken Greer, Dec. 1981.
|
||||
*/
|
||||
|
||||
#define ON 1
|
||||
#define OFF 0
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#define ESC '\033'
|
||||
|
||||
typedef enum {
|
||||
LIST, RECOGNIZE
|
||||
} COMMAND;
|
||||
|
||||
static void setup_tty(int);
|
||||
static void back_to_col_1(void);
|
||||
static int pushback(Char *);
|
||||
static void catn(Char *, Char *, size_t);
|
||||
static void copyn(Char *, Char *, size_t);
|
||||
static Char filetype(Char *, Char *);
|
||||
static void print_by_column(Char *, Char *[], size_t);
|
||||
static Char *tilde(Char *, Char *);
|
||||
static void retype(void);
|
||||
static void beep(void);
|
||||
static void print_recognized_stuff(Char *);
|
||||
static void extract_dir_and_name(Char *, Char *, Char *);
|
||||
static Char *getentry(DIR *, int);
|
||||
static void free_items(Char **, size_t);
|
||||
static size_t tsearch(Char *, COMMAND, size_t);
|
||||
static int recognize(Char *, Char *, size_t, size_t);
|
||||
static int is_prefix(Char *, Char *);
|
||||
static int is_suffix(Char *, Char *);
|
||||
static int ignored(Char *);
|
||||
|
||||
/*
|
||||
* Put this here so the binary can be patched with adb to enable file
|
||||
* completion by default. Filec controls completion, nobeep controls
|
||||
* ringing the terminal bell on incomplete expansions.
|
||||
*/
|
||||
int filec = 0;
|
||||
|
||||
static void
|
||||
setup_tty(int on)
|
||||
{
|
||||
struct termios tchars;
|
||||
|
||||
(void)tcgetattr(SHIN, &tchars);
|
||||
|
||||
if (on) {
|
||||
tchars.c_cc[VEOL] = ESC;
|
||||
if (tchars.c_lflag & ICANON)
|
||||
on = TCSADRAIN;
|
||||
else {
|
||||
tchars.c_lflag |= ICANON;
|
||||
on = TCSAFLUSH;
|
||||
}
|
||||
}
|
||||
else {
|
||||
tchars.c_cc[VEOL] = _POSIX_VDISABLE;
|
||||
on = TCSADRAIN;
|
||||
}
|
||||
|
||||
(void)tcsetattr(SHIN, on, &tchars);
|
||||
}
|
||||
|
||||
/*
|
||||
* Move back to beginning of current line
|
||||
*/
|
||||
static void
|
||||
back_to_col_1(void)
|
||||
{
|
||||
struct termios tty, tty_normal;
|
||||
sigset_t nsigset, osigset;
|
||||
|
||||
sigemptyset(&nsigset);
|
||||
(void)sigaddset(&nsigset, SIGINT);
|
||||
(void)sigprocmask(SIG_BLOCK, &nsigset, &osigset);
|
||||
(void)tcgetattr(SHOUT, &tty);
|
||||
tty_normal = tty;
|
||||
tty.c_iflag &= ~INLCR;
|
||||
tty.c_oflag &= ~ONLCR;
|
||||
(void)tcsetattr(SHOUT, TCSADRAIN, &tty);
|
||||
(void)write(SHOUT, "\r", 1);
|
||||
(void)tcsetattr(SHOUT, TCSADRAIN, &tty_normal);
|
||||
(void)sigprocmask(SIG_SETMASK, &osigset, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Push string contents back into tty queue
|
||||
*/
|
||||
static int
|
||||
pushback(Char *string)
|
||||
{
|
||||
struct termios tty, tty_normal;
|
||||
char buf[64], svchars[sizeof(buf)];
|
||||
sigset_t nsigset, osigset;
|
||||
Char *p;
|
||||
size_t bufidx, i, len_str, nbuf, nsv, onsv, retrycnt;
|
||||
char c;
|
||||
|
||||
nsv = 0;
|
||||
sigemptyset(&nsigset);
|
||||
(void)sigaddset(&nsigset, SIGINT);
|
||||
(void)sigprocmask(SIG_BLOCK, &nsigset, &osigset);
|
||||
(void)tcgetattr(SHOUT, &tty);
|
||||
tty_normal = tty;
|
||||
tty.c_lflag &= ~(ECHOKE | ECHO | ECHOE | ECHOK | ECHONL | ECHOPRT | ECHOCTL);
|
||||
/* FIONREAD works only in noncanonical mode. */
|
||||
tty.c_lflag &= ~ICANON;
|
||||
tty.c_cc[VMIN] = 0;
|
||||
(void)tcsetattr(SHOUT, TCSADRAIN, &tty);
|
||||
|
||||
for (retrycnt = 5; ; retrycnt--) {
|
||||
/*
|
||||
* Push back characters.
|
||||
*/
|
||||
for (p = string; (c = (char)*p) != '\0'; p++)
|
||||
(void)ioctl(SHOUT, TIOCSTI, (ioctl_t) &c);
|
||||
for (i = 0; i < nsv; i++)
|
||||
(void)ioctl(SHOUT, TIOCSTI, (ioctl_t) &svchars[i]);
|
||||
|
||||
if (retrycnt == 0)
|
||||
break; /* give up salvaging characters */
|
||||
|
||||
len_str = (size_t)(p - string);
|
||||
|
||||
if (ioctl(SHOUT, FIONREAD, (ioctl_t) &nbuf) ||
|
||||
nbuf <= len_str + nsv || /* The string fit. */
|
||||
nbuf > sizeof(buf)) /* For future binary compatibility
|
||||
(and safety). */
|
||||
break;
|
||||
|
||||
/*
|
||||
* User has typed characters before the pushback finished.
|
||||
* Salvage the characters.
|
||||
*/
|
||||
|
||||
/* This read() should be in noncanonical mode. */
|
||||
if (read(SHOUT, &buf, nbuf) != (ssize_t)nbuf)
|
||||
continue; /* hangup? */
|
||||
|
||||
onsv = nsv;
|
||||
for (bufidx = 0, i = 0; bufidx < nbuf; bufidx++, i++) {
|
||||
c = buf[bufidx];
|
||||
if ((i < len_str) ? c != (char)string[i] :
|
||||
(i < len_str + onsv) ? c != svchars[i - len_str] : 1) {
|
||||
/* Salvage a character. */
|
||||
if (nsv < (int)(sizeof svchars / sizeof svchars[0])) {
|
||||
svchars[nsv++] = c;
|
||||
i--; /* try this comparison with the next char */
|
||||
} else
|
||||
break; /* too many */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 1
|
||||
/*
|
||||
* XXX Is this a bug or a feature of kernel tty driver?
|
||||
*
|
||||
* FIONREAD in canonical mode does not return correct byte count
|
||||
* in tty input queue, but this is required to avoid unwanted echo.
|
||||
*/
|
||||
tty.c_lflag |= ICANON;
|
||||
(void)tcsetattr(SHOUT, TCSADRAIN, &tty);
|
||||
(void)ioctl(SHOUT, FIONREAD, (ioctl_t) &i);
|
||||
#endif
|
||||
(void)tcsetattr(SHOUT, TCSADRAIN, &tty_normal);
|
||||
(void)sigprocmask(SIG_SETMASK, &osigset, NULL);
|
||||
|
||||
return (int)nsv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Concatenate src onto tail of des.
|
||||
* Des is a string whose maximum length is count.
|
||||
* Always null terminate.
|
||||
*/
|
||||
static void
|
||||
catn(Char *des, Char *src, size_t count)
|
||||
{
|
||||
while (count-- > 0 && *des)
|
||||
des++;
|
||||
while (count-- > 0)
|
||||
if ((*des++ = *src++) == 0)
|
||||
return;
|
||||
*des = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* Like strncpy but always leave room for trailing \0
|
||||
* and always null terminate.
|
||||
*/
|
||||
static void
|
||||
copyn(Char *des, Char *src, size_t count)
|
||||
{
|
||||
while (count-- > 0)
|
||||
if ((*des++ = *src++) == 0)
|
||||
return;
|
||||
*des = '\0';
|
||||
}
|
||||
|
||||
static Char
|
||||
filetype(Char *dir, Char *file)
|
||||
{
|
||||
struct stat statb;
|
||||
Char path[MAXPATHLEN];
|
||||
|
||||
catn(Strcpy(path, dir), file, sizeof(path) / sizeof(Char));
|
||||
if (lstat(short2str(path), &statb) == 0) {
|
||||
switch (statb.st_mode & S_IFMT) {
|
||||
case S_IFDIR:
|
||||
return ('/');
|
||||
case S_IFLNK:
|
||||
if (stat(short2str(path), &statb) == 0 && /* follow it out */
|
||||
S_ISDIR(statb.st_mode))
|
||||
return ('>');
|
||||
else
|
||||
return ('@');
|
||||
case S_IFSOCK:
|
||||
return ('=');
|
||||
default:
|
||||
if (statb.st_mode & 0111)
|
||||
return ('*');
|
||||
}
|
||||
}
|
||||
return (' ');
|
||||
}
|
||||
|
||||
static struct winsize win;
|
||||
|
||||
/*
|
||||
* Print sorted down columns
|
||||
*/
|
||||
static void
|
||||
print_by_column(Char *dir, Char *items[], size_t count)
|
||||
{
|
||||
size_t c, columns, i, maxwidth, r, rows;
|
||||
|
||||
maxwidth = 0;
|
||||
|
||||
if (ioctl(SHOUT, TIOCGWINSZ, (ioctl_t) & win) < 0 || win.ws_col == 0)
|
||||
win.ws_col = 80;
|
||||
for (i = 0; i < count; i++)
|
||||
maxwidth = maxwidth > (r = Strlen(items[i])) ? maxwidth : r;
|
||||
maxwidth += 2; /* for the file tag and space */
|
||||
columns = win.ws_col / maxwidth;
|
||||
if (columns == 0)
|
||||
columns = 1;
|
||||
rows = (count + (columns - 1)) / columns;
|
||||
for (r = 0; r < rows; r++) {
|
||||
for (c = 0; c < columns; c++) {
|
||||
i = c * rows + r;
|
||||
if (i < count) {
|
||||
size_t w;
|
||||
|
||||
(void)fprintf(cshout, "%s", vis_str(items[i]));
|
||||
(void)fputc(dir ? filetype(dir, items[i]) : ' ', cshout);
|
||||
if (c < columns - 1) { /* last column? */
|
||||
w = Strlen(items[i]) + 1;
|
||||
for (; w < maxwidth; w++)
|
||||
(void) fputc(' ', cshout);
|
||||
}
|
||||
}
|
||||
}
|
||||
(void)fputc('\r', cshout);
|
||||
(void)fputc('\n', cshout);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Expand file name with possible tilde usage
|
||||
* ~person/mumble
|
||||
* expands to
|
||||
* home_directory_of_person/mumble
|
||||
*/
|
||||
static Char *
|
||||
tilde(Char *new, Char *old)
|
||||
{
|
||||
static Char person[40];
|
||||
struct passwd *pw;
|
||||
Char *o, *p;
|
||||
|
||||
if (old[0] != '~')
|
||||
return (Strcpy(new, old));
|
||||
|
||||
for (p = person, o = &old[1]; *o && *o != '/'; *p++ = *o++)
|
||||
continue;
|
||||
*p = '\0';
|
||||
if (person[0] == '\0')
|
||||
(void)Strcpy(new, value(STRhome));
|
||||
else {
|
||||
pw = getpwnam(short2str(person));
|
||||
if (pw == NULL)
|
||||
return (NULL);
|
||||
(void)Strcpy(new, str2short(pw->pw_dir));
|
||||
}
|
||||
(void)Strcat(new, o);
|
||||
return (new);
|
||||
}
|
||||
|
||||
/*
|
||||
* Cause pending line to be printed
|
||||
*/
|
||||
static void
|
||||
retype(void)
|
||||
{
|
||||
struct termios tty;
|
||||
|
||||
(void)tcgetattr(SHOUT, &tty);
|
||||
tty.c_lflag |= PENDIN;
|
||||
(void)tcsetattr(SHOUT, TCSADRAIN, &tty);
|
||||
}
|
||||
|
||||
static void
|
||||
beep(void)
|
||||
{
|
||||
if (adrof(STRnobeep) == 0)
|
||||
(void)write(SHOUT, "\007", 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Erase that silly ^[ and
|
||||
* print the recognized part of the string
|
||||
*/
|
||||
static void
|
||||
print_recognized_stuff(Char *recognized_part)
|
||||
{
|
||||
/* An optimized erasing of that silly ^[ */
|
||||
(void)fputc('\b', cshout);
|
||||
(void)fputc('\b', cshout);
|
||||
switch (Strlen(recognized_part)) {
|
||||
case 0: /* erase two Characters: ^[ */
|
||||
(void)fputc(' ', cshout);
|
||||
(void)fputc(' ', cshout);
|
||||
(void)fputc('\b', cshout);
|
||||
(void)fputc('\b', cshout);
|
||||
break;
|
||||
case 1: /* overstrike the ^, erase the [ */
|
||||
(void)fprintf(cshout, "%s", vis_str(recognized_part));
|
||||
(void)fputc(' ', cshout);
|
||||
(void)fputc('\b', cshout);
|
||||
break;
|
||||
default: /* overstrike both Characters ^[ */
|
||||
(void)fprintf(cshout, "%s", vis_str(recognized_part));
|
||||
break;
|
||||
}
|
||||
(void)fflush(cshout);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse full path in file into 2 parts: directory and file names
|
||||
* Should leave final slash (/) at end of dir.
|
||||
*/
|
||||
static void
|
||||
extract_dir_and_name(Char *path, Char *dir, Char *name)
|
||||
{
|
||||
Char *p;
|
||||
|
||||
p = Strrchr(path, '/');
|
||||
if (p == NULL) {
|
||||
copyn(name, path, MAXNAMLEN);
|
||||
dir[0] = '\0';
|
||||
}
|
||||
else {
|
||||
copyn(name, ++p, MAXNAMLEN);
|
||||
copyn(dir, path, (size_t)(p - path));
|
||||
}
|
||||
}
|
||||
|
||||
static Char *
|
||||
getentry(DIR *dir_fd, int looking_for_lognames)
|
||||
{
|
||||
struct dirent *dirp;
|
||||
struct passwd *pw;
|
||||
|
||||
if (looking_for_lognames) {
|
||||
if ((pw = getpwent()) == NULL)
|
||||
return (NULL);
|
||||
return (str2short(pw->pw_name));
|
||||
}
|
||||
if ((dirp = readdir(dir_fd)) != NULL)
|
||||
return (str2short(dirp->d_name));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
free_items(Char **items, size_t numitems)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < numitems; i++)
|
||||
xfree((ptr_t) items[i]);
|
||||
xfree((ptr_t) items);
|
||||
}
|
||||
|
||||
#define FREE_ITEMS(items, numitems) { \
|
||||
sigset_t nsigset, osigset;\
|
||||
\
|
||||
sigemptyset(&nsigset);\
|
||||
(void) sigaddset(&nsigset, SIGINT);\
|
||||
(void) sigprocmask(SIG_BLOCK, &nsigset, &osigset);\
|
||||
free_items(items, numitems);\
|
||||
(void) sigprocmask(SIG_SETMASK, &osigset, NULL);\
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform a RECOGNIZE or LIST command on string "word".
|
||||
*/
|
||||
static size_t
|
||||
tsearch(Char *word, COMMAND command, size_t max_word_length)
|
||||
{
|
||||
Char dir[MAXPATHLEN + 1], extended_name[MAXNAMLEN + 1];
|
||||
Char name[MAXNAMLEN + 1], tilded_dir[MAXPATHLEN + 1];
|
||||
DIR *dir_fd;
|
||||
Char *entry;
|
||||
int ignoring, looking_for_lognames;
|
||||
size_t name_length, nignored, numitems;
|
||||
Char **items = NULL;
|
||||
size_t maxitems = 0;
|
||||
|
||||
numitems = 0;
|
||||
ignoring = TRUE;
|
||||
nignored = 0;
|
||||
|
||||
looking_for_lognames = (*word == '~') && (Strchr(word, '/') == NULL);
|
||||
if (looking_for_lognames) {
|
||||
(void)setpwent();
|
||||
copyn(name, &word[1], MAXNAMLEN); /* name sans ~ */
|
||||
dir_fd = NULL;
|
||||
}
|
||||
else {
|
||||
extract_dir_and_name(word, dir, name);
|
||||
if (tilde(tilded_dir, dir) == 0)
|
||||
return (0);
|
||||
dir_fd = opendir(*tilded_dir ? short2str(tilded_dir) : ".");
|
||||
if (dir_fd == NULL)
|
||||
return (0);
|
||||
}
|
||||
|
||||
again: /* search for matches */
|
||||
name_length = Strlen(name);
|
||||
for (numitems = 0; (entry = getentry(dir_fd, looking_for_lognames)) != NULL;) {
|
||||
if (!is_prefix(name, entry))
|
||||
continue;
|
||||
/* Don't match . files on null prefix match */
|
||||
if (name_length == 0 && entry[0] == '.' &&
|
||||
!looking_for_lognames)
|
||||
continue;
|
||||
if (command == LIST) {
|
||||
if ((size_t)numitems >= maxitems) {
|
||||
maxitems += 1024;
|
||||
if (items == NULL)
|
||||
items = xmalloc(sizeof(*items) * maxitems);
|
||||
else
|
||||
items = xrealloc((ptr_t) items,
|
||||
sizeof(*items) * maxitems);
|
||||
}
|
||||
items[numitems] = xmalloc((size_t) (Strlen(entry) + 1) *
|
||||
sizeof(Char));
|
||||
copyn(items[numitems], entry, MAXNAMLEN);
|
||||
numitems++;
|
||||
}
|
||||
else { /* RECOGNIZE command */
|
||||
if (ignoring && ignored(entry))
|
||||
nignored++;
|
||||
else if (recognize(extended_name,
|
||||
entry, name_length, ++numitems))
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ignoring && numitems == 0 && nignored > 0) {
|
||||
ignoring = FALSE;
|
||||
nignored = 0;
|
||||
if (looking_for_lognames)
|
||||
(void)setpwent();
|
||||
else
|
||||
rewinddir(dir_fd);
|
||||
goto again;
|
||||
}
|
||||
|
||||
if (looking_for_lognames)
|
||||
(void)endpwent();
|
||||
else
|
||||
(void)closedir(dir_fd);
|
||||
if (numitems == 0)
|
||||
return (0);
|
||||
if (command == RECOGNIZE) {
|
||||
if (looking_for_lognames)
|
||||
copyn(word, STRtilde, 1);
|
||||
else
|
||||
/* put back dir part */
|
||||
copyn(word, dir, max_word_length);
|
||||
/* add extended name */
|
||||
catn(word, extended_name, max_word_length);
|
||||
return (numitems);
|
||||
}
|
||||
else { /* LIST */
|
||||
qsort((ptr_t) items, numitems, sizeof(items[0]),
|
||||
(int (*) (const void *, const void *)) sortscmp);
|
||||
print_by_column(looking_for_lognames ? NULL : tilded_dir,
|
||||
items, numitems);
|
||||
if (items != NULL)
|
||||
FREE_ITEMS(items, numitems);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Object: extend what user typed up to an ambiguity.
|
||||
* Algorithm:
|
||||
* On first match, copy full entry (assume it'll be the only match)
|
||||
* On subsequent matches, shorten extended_name to the first
|
||||
* Character mismatch between extended_name and entry.
|
||||
* If we shorten it back to the prefix length, stop searching.
|
||||
*/
|
||||
static int
|
||||
recognize(Char *extended_name, Char *entry, size_t name_length, size_t numitems)
|
||||
{
|
||||
if (numitems == 1) /* 1st match */
|
||||
copyn(extended_name, entry, MAXNAMLEN);
|
||||
else { /* 2nd & subsequent matches */
|
||||
Char *ent, *x;
|
||||
size_t len = 0;
|
||||
|
||||
x = extended_name;
|
||||
for (ent = entry; *x && *x == *ent++; x++, len++)
|
||||
continue;
|
||||
*x = '\0'; /* Shorten at 1st Char diff */
|
||||
if (len == name_length) /* Ambiguous to prefix? */
|
||||
return (-1); /* So stop now and save time */
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if check matches initial Chars in template.
|
||||
* This differs from PWB imatch in that if check is null
|
||||
* it matches anything.
|
||||
*/
|
||||
static int
|
||||
is_prefix(Char *check, Char *template)
|
||||
{
|
||||
do
|
||||
if (*check == 0)
|
||||
return (TRUE);
|
||||
while (*check++ == *template++);
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if the Chars in template appear at the
|
||||
* end of check, I.e., are its suffix.
|
||||
*/
|
||||
static int
|
||||
is_suffix(Char *check, Char *template)
|
||||
{
|
||||
Char *c, *t;
|
||||
|
||||
for (c = check; *c++;)
|
||||
continue;
|
||||
for (t = template; *t++;)
|
||||
continue;
|
||||
for (;;) {
|
||||
if (t == template)
|
||||
return 1;
|
||||
if (c == check || *--t != *--c)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t
|
||||
tenex(Char *inputline, size_t inputline_size)
|
||||
{
|
||||
char tinputline[BUFSIZE];
|
||||
ssize_t num_read;
|
||||
size_t numitems;
|
||||
|
||||
setup_tty(ON);
|
||||
|
||||
while ((num_read = read(SHIN, tinputline, BUFSIZE)) > 0) {
|
||||
size_t i, nr = (size_t) num_read;
|
||||
|
||||
|
||||
static Char delims[] = {' ', '\'', '"', '\t', ';', '&', '<',
|
||||
'>', '(', ')', '|', '^', '%', '\0'};
|
||||
Char *str_end, *word_start, last_Char, should_retype;
|
||||
size_t space_left;
|
||||
COMMAND command;
|
||||
|
||||
for (i = 0; i < nr; i++)
|
||||
inputline[i] = (unsigned char) tinputline[i];
|
||||
last_Char = inputline[nr - 1] & ASCII;
|
||||
|
||||
if (last_Char == '\n' || nr == inputline_size)
|
||||
break;
|
||||
command = (last_Char == ESC) ? RECOGNIZE : LIST;
|
||||
if (command == LIST)
|
||||
(void)fputc('\n', cshout);
|
||||
str_end = &inputline[nr];
|
||||
if (last_Char == ESC)
|
||||
--str_end; /* wipeout trailing cmd Char */
|
||||
*str_end = '\0';
|
||||
/*
|
||||
* Find LAST occurence of a delimiter in the inputline. The word start
|
||||
* is one Character past it.
|
||||
*/
|
||||
for (word_start = str_end; word_start > inputline; --word_start)
|
||||
if (Strchr(delims, word_start[-1]))
|
||||
break;
|
||||
space_left = inputline_size - (size_t)(word_start - inputline) - 1;
|
||||
numitems = tsearch(word_start, command, space_left);
|
||||
|
||||
if (command == RECOGNIZE) {
|
||||
/* print from str_end on */
|
||||
print_recognized_stuff(str_end);
|
||||
if (numitems != 1) /* Beep = No match/ambiguous */
|
||||
beep();
|
||||
}
|
||||
|
||||
/*
|
||||
* Tabs in the input line cause trouble after a pushback. tty driver
|
||||
* won't backspace over them because column positions are now
|
||||
* incorrect. This is solved by retyping over current line.
|
||||
*/
|
||||
should_retype = FALSE;
|
||||
if (Strchr(inputline, '\t')) { /* tab Char in input line? */
|
||||
back_to_col_1();
|
||||
should_retype = TRUE;
|
||||
}
|
||||
if (command == LIST) /* Always retype after a LIST */
|
||||
should_retype = TRUE;
|
||||
if (pushback(inputline))
|
||||
should_retype = TRUE;
|
||||
if (should_retype) {
|
||||
if (command == RECOGNIZE)
|
||||
(void) fputc('\n', cshout);
|
||||
printprompt();
|
||||
}
|
||||
if (should_retype)
|
||||
retype();
|
||||
}
|
||||
setup_tty(OFF);
|
||||
return num_read;
|
||||
}
|
||||
|
||||
static int
|
||||
ignored(Char *entry)
|
||||
{
|
||||
struct varent *vp;
|
||||
Char **cp;
|
||||
|
||||
if ((vp = adrof(STRfignore)) == NULL || (cp = vp->vec) == NULL)
|
||||
return (FALSE);
|
||||
for (; *cp != NULL; cp++)
|
||||
if (is_suffix(entry, *cp))
|
||||
return (TRUE);
|
||||
return (FALSE);
|
||||
}
|
||||
#endif /* FILEC */
|
1456
bin/csh/func.c
Normal file
1456
bin/csh/func.c
Normal file
File diff suppressed because it is too large
Load diff
923
bin/csh/glob.c
Normal file
923
bin/csh/glob.c
Normal file
|
@ -0,0 +1,923 @@
|
|||
/* $NetBSD: glob.c,v 1.27 2013/07/16 17:47:43 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1980, 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)glob.c 8.1 (Berkeley) 5/31/93";
|
||||
#else
|
||||
__RCSID("$NetBSD: glob.c,v 1.27 2013/07/16 17:47:43 christos Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <glob.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "csh.h"
|
||||
#include "extern.h"
|
||||
|
||||
static int noglob;
|
||||
static int gargsiz, pargsiz;
|
||||
|
||||
/*
|
||||
* Values for gflag
|
||||
*/
|
||||
#define G_NONE 0 /* No globbing needed */
|
||||
#define G_GLOB 1 /* string contains *?[] characters */
|
||||
#define G_CSH 2 /* string contains ~`{ characters */
|
||||
|
||||
#define GLOBSPACE 100 /* Alloc increment */
|
||||
|
||||
#define LBRC '{'
|
||||
#define RBRC '}'
|
||||
#define LBRK '['
|
||||
#define RBRK ']'
|
||||
#define EOS '\0'
|
||||
|
||||
Char **gargv = NULL;
|
||||
Char **pargv = NULL;
|
||||
long gargc = 0;
|
||||
long pargc = 0;
|
||||
|
||||
/*
|
||||
* globbing is now done in two stages. In the first pass we expand
|
||||
* csh globbing idioms ~`{ and then we proceed doing the normal
|
||||
* globbing if needed ?*[
|
||||
*
|
||||
* Csh type globbing is handled in globexpand() and the rest is
|
||||
* handled in glob() which is part of the 4.4BSD libc.
|
||||
*
|
||||
*/
|
||||
static Char *globtilde(Char **, Char *);
|
||||
static Char *handleone(Char *, Char **, int);
|
||||
static Char **libglob(Char **);
|
||||
static Char **globexpand(Char **);
|
||||
static int globbrace(Char *, Char *, Char ***);
|
||||
static void expbrace(Char ***, Char ***, size_t);
|
||||
static int pmatch(Char *, Char *);
|
||||
static void pword(void);
|
||||
static void psave(int);
|
||||
static void backeval(Char *, int);
|
||||
|
||||
static Char *
|
||||
globtilde(Char **nv, Char *s)
|
||||
{
|
||||
Char gbuf[MAXPATHLEN], *b, *e, *gstart, *u;
|
||||
|
||||
gstart = gbuf;
|
||||
*gstart++ = *s++;
|
||||
u = s;
|
||||
for (b = gstart, e = &gbuf[MAXPATHLEN - 1];
|
||||
*s && *s != '/' && *s != ':' && b < e;
|
||||
*b++ = *s++)
|
||||
continue;
|
||||
*b = EOS;
|
||||
if (gethdir(gstart)) {
|
||||
blkfree(nv);
|
||||
if (*gstart)
|
||||
stderror(ERR_UNKUSER, vis_str(gstart));
|
||||
else
|
||||
stderror(ERR_NOHOME);
|
||||
}
|
||||
b = &gstart[Strlen(gstart)];
|
||||
while (*s)
|
||||
*b++ = *s++;
|
||||
*b = EOS;
|
||||
--u;
|
||||
xfree((ptr_t) u);
|
||||
return (Strsave(gstart));
|
||||
}
|
||||
|
||||
static int
|
||||
globbrace(Char *s, Char *p, Char ***bl)
|
||||
{
|
||||
Char gbuf[MAXPATHLEN];
|
||||
Char *lm, *pe, *pl, *pm, **nv, **vl;
|
||||
int i, len, size;
|
||||
|
||||
size = GLOBSPACE;
|
||||
nv = vl = xmalloc(sizeof(Char *) * (size_t)size);
|
||||
*vl = NULL;
|
||||
len = 0;
|
||||
/* copy part up to the brace */
|
||||
for (lm = gbuf, p = s; *p != LBRC; *lm++ = *p++)
|
||||
continue;
|
||||
|
||||
/* check for balanced braces */
|
||||
for (i = 0, pe = ++p; *pe; pe++)
|
||||
if (*pe == LBRK) {
|
||||
/* Ignore everything between [] */
|
||||
for (++pe; *pe != RBRK && *pe != EOS; pe++)
|
||||
continue;
|
||||
if (*pe == EOS) {
|
||||
blkfree(nv);
|
||||
return (-RBRK);
|
||||
}
|
||||
}
|
||||
else if (*pe == LBRC)
|
||||
i++;
|
||||
else if (*pe == RBRC) {
|
||||
if (i == 0)
|
||||
break;
|
||||
i--;
|
||||
}
|
||||
|
||||
if (i != 0 || *pe == '\0') {
|
||||
blkfree(nv);
|
||||
return (-RBRC);
|
||||
}
|
||||
|
||||
for (i = 0, pl = pm = p; pm <= pe; pm++)
|
||||
switch (*pm) {
|
||||
case LBRK:
|
||||
for (++pm; *pm != RBRK && *pm != EOS; pm++)
|
||||
continue;
|
||||
if (*pm == EOS) {
|
||||
*vl = NULL;
|
||||
blkfree(nv);
|
||||
return (-RBRK);
|
||||
}
|
||||
break;
|
||||
case LBRC:
|
||||
i++;
|
||||
break;
|
||||
case RBRC:
|
||||
if (i) {
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case ',':
|
||||
if (i && *pm == ',')
|
||||
break;
|
||||
else {
|
||||
Char savec = *pm;
|
||||
|
||||
*pm = EOS;
|
||||
(void)Strcpy(lm, pl);
|
||||
(void)Strcat(gbuf, pe + 1);
|
||||
*pm = savec;
|
||||
*vl++ = Strsave(gbuf);
|
||||
len++;
|
||||
pl = pm + 1;
|
||||
if (vl == &nv[size]) {
|
||||
size += GLOBSPACE;
|
||||
nv = (Char **)xrealloc((ptr_t) nv,
|
||||
(size_t)size * sizeof(Char *));
|
||||
vl = &nv[size - GLOBSPACE];
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
*vl = NULL;
|
||||
*bl = nv;
|
||||
return (len);
|
||||
}
|
||||
|
||||
static void
|
||||
expbrace(Char ***nvp, Char ***elp, size_t size)
|
||||
{
|
||||
Char **ex, **nv, *s, **vl;
|
||||
|
||||
vl = nv = *nvp;
|
||||
if (elp != NULL)
|
||||
ex = *elp;
|
||||
else
|
||||
for (ex = vl; *ex; ex++)
|
||||
continue;
|
||||
|
||||
for (s = *vl; s; s = *++vl) {
|
||||
Char *b, **bp, **vp;
|
||||
|
||||
/* leave {} untouched for find */
|
||||
if (s[0] == '{' && (s[1] == '\0' || (s[1] == '}' && s[2] == '\0')))
|
||||
continue;
|
||||
if ((b = Strchr(s, '{')) != NULL) {
|
||||
Char **bl;
|
||||
int len;
|
||||
|
||||
if ((len = globbrace(s, b, &bl)) < 0) {
|
||||
xfree((ptr_t)nv);
|
||||
stderror(ERR_MISSING, -len);
|
||||
}
|
||||
xfree((ptr_t) s);
|
||||
if (len == 1) {
|
||||
*vl-- = *bl;
|
||||
xfree((ptr_t) bl);
|
||||
continue;
|
||||
}
|
||||
len = blklen(bl);
|
||||
if (&ex[len] >= &nv[size]) {
|
||||
ptrdiff_t l, e;
|
||||
|
||||
l = &ex[len] - &nv[size];
|
||||
size += (size_t)(GLOBSPACE > l ? GLOBSPACE : l);
|
||||
l = vl - nv;
|
||||
e = ex - nv;
|
||||
nv = (Char **)xrealloc((ptr_t)nv,
|
||||
(size_t)size * sizeof(Char *));
|
||||
vl = nv + l;
|
||||
ex = nv + e;
|
||||
}
|
||||
vp = vl--;
|
||||
*vp = *bl;
|
||||
len--;
|
||||
for (bp = ex; bp != vp; bp--)
|
||||
bp[len] = *bp;
|
||||
ex += len;
|
||||
vp++;
|
||||
for (bp = bl + 1; *bp; *vp++ = *bp++)
|
||||
continue;
|
||||
xfree((ptr_t)bl);
|
||||
}
|
||||
|
||||
}
|
||||
if (elp != NULL)
|
||||
*elp = ex;
|
||||
*nvp = nv;
|
||||
}
|
||||
|
||||
static Char **
|
||||
globexpand(Char **v)
|
||||
{
|
||||
Char **ex, **nv, *s, **vl;
|
||||
size_t size;
|
||||
|
||||
size = GLOBSPACE;
|
||||
nv = vl = xmalloc(sizeof(Char *) * size);
|
||||
*vl = NULL;
|
||||
|
||||
/*
|
||||
* Step 1: expand backquotes.
|
||||
*/
|
||||
while ((s = *v++) != NULL) {
|
||||
if (Strchr(s, '`')) {
|
||||
int i;
|
||||
|
||||
(void) dobackp(s, 0);
|
||||
for (i = 0; i < pargc; i++) {
|
||||
*vl++ = pargv[i];
|
||||
if (vl == &nv[size]) {
|
||||
size += GLOBSPACE;
|
||||
nv = (Char **)xrealloc((ptr_t) nv,
|
||||
(size_t)size * sizeof(Char *));
|
||||
vl = &nv[size - GLOBSPACE];
|
||||
}
|
||||
}
|
||||
xfree((ptr_t)pargv);
|
||||
pargv = NULL;
|
||||
}
|
||||
else {
|
||||
*vl++ = Strsave(s);
|
||||
if (vl == &nv[size]) {
|
||||
size += GLOBSPACE;
|
||||
nv = (Char **)xrealloc((ptr_t)nv,
|
||||
size * sizeof(Char *));
|
||||
vl = &nv[size - GLOBSPACE];
|
||||
}
|
||||
}
|
||||
}
|
||||
*vl = NULL;
|
||||
|
||||
if (noglob)
|
||||
return (nv);
|
||||
|
||||
/*
|
||||
* Step 2: expand braces
|
||||
*/
|
||||
ex = vl;
|
||||
expbrace(&nv, &ex, size);
|
||||
|
||||
/*
|
||||
* Step 3: expand ~
|
||||
*/
|
||||
vl = nv;
|
||||
for (s = *vl; s; s = *++vl)
|
||||
if (*s == '~')
|
||||
*vl = globtilde(nv, s);
|
||||
vl = nv;
|
||||
return (vl);
|
||||
}
|
||||
|
||||
static Char *
|
||||
handleone(Char *str, Char **vl, int action)
|
||||
{
|
||||
Char *cp, **vlp;
|
||||
|
||||
vlp = vl;
|
||||
switch (action) {
|
||||
case G_ERROR:
|
||||
setname(vis_str(str));
|
||||
blkfree(vl);
|
||||
stderror(ERR_NAME | ERR_AMBIG);
|
||||
/* NOTREACHED */
|
||||
case G_APPEND:
|
||||
trim(vlp);
|
||||
str = Strsave(*vlp++);
|
||||
do {
|
||||
cp = Strspl(str, STRspace);
|
||||
xfree((ptr_t)str);
|
||||
str = Strspl(cp, *vlp);
|
||||
xfree((ptr_t)cp);
|
||||
}
|
||||
while (*++vlp);
|
||||
blkfree(vl);
|
||||
break;
|
||||
case G_IGNORE:
|
||||
str = Strsave(strip(*vlp));
|
||||
blkfree(vl);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return (str);
|
||||
}
|
||||
|
||||
static Char **
|
||||
libglob(Char **vl)
|
||||
{
|
||||
glob_t globv;
|
||||
char *ptr;
|
||||
int gflgs, magic, match, nonomatch;
|
||||
|
||||
gflgs = GLOB_NOMAGIC;
|
||||
magic = 0;
|
||||
match = 0;
|
||||
nonomatch = adrof(STRnonomatch) != 0;
|
||||
|
||||
if (!vl || !vl[0])
|
||||
return (vl);
|
||||
|
||||
globv.gl_offs = 0;
|
||||
globv.gl_pathv = 0;
|
||||
globv.gl_pathc = 0;
|
||||
|
||||
if (nonomatch)
|
||||
gflgs |= GLOB_NOCHECK;
|
||||
|
||||
do {
|
||||
ptr = short2qstr(*vl);
|
||||
switch (glob(ptr, gflgs, 0, &globv)) {
|
||||
case GLOB_ABORTED:
|
||||
setname(vis_str(*vl));
|
||||
stderror(ERR_NAME | ERR_GLOB);
|
||||
/* NOTREACHED */
|
||||
case GLOB_NOSPACE:
|
||||
stderror(ERR_NOMEM);
|
||||
/* NOTREACHED */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (globv.gl_flags & GLOB_MAGCHAR) {
|
||||
match |= (globv.gl_matchc != 0);
|
||||
magic = 1;
|
||||
}
|
||||
gflgs |= GLOB_APPEND;
|
||||
}
|
||||
while (*++vl);
|
||||
vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ?
|
||||
NULL : blk2short(globv.gl_pathv);
|
||||
globfree(&globv);
|
||||
return (vl);
|
||||
}
|
||||
|
||||
Char *
|
||||
globone(Char *str, int action)
|
||||
{
|
||||
Char *v[2], **vl, **vo;
|
||||
int gflg;
|
||||
|
||||
noglob = adrof(STRnoglob) != 0;
|
||||
gflag = 0;
|
||||
v[0] = str;
|
||||
v[1] = 0;
|
||||
tglob(v);
|
||||
gflg = gflag;
|
||||
if (gflg == G_NONE)
|
||||
return (strip(Strsave(str)));
|
||||
|
||||
if (gflg & G_CSH) {
|
||||
/*
|
||||
* Expand back-quote, tilde and brace
|
||||
*/
|
||||
vo = globexpand(v);
|
||||
if (noglob || (gflg & G_GLOB) == 0) {
|
||||
if (vo[0] == NULL) {
|
||||
xfree((ptr_t)vo);
|
||||
return (Strsave(STRNULL));
|
||||
}
|
||||
if (vo[1] != NULL)
|
||||
return (handleone(str, vo, action));
|
||||
else {
|
||||
str = strip(vo[0]);
|
||||
xfree((ptr_t) vo);
|
||||
return (str);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (noglob || (gflg & G_GLOB) == 0)
|
||||
return (strip(Strsave(str)));
|
||||
else
|
||||
vo = v;
|
||||
|
||||
vl = libglob(vo);
|
||||
if ((gflg & G_CSH) && vl != vo)
|
||||
blkfree(vo);
|
||||
if (vl == NULL) {
|
||||
setname(vis_str(str));
|
||||
stderror(ERR_NAME | ERR_NOMATCH);
|
||||
}
|
||||
if (vl[0] == NULL) {
|
||||
xfree((ptr_t)vl);
|
||||
return (Strsave(STRNULL));
|
||||
}
|
||||
if (vl[1] != NULL)
|
||||
return (handleone(str, vl, action));
|
||||
else {
|
||||
str = strip(*vl);
|
||||
xfree((ptr_t)vl);
|
||||
return (str);
|
||||
}
|
||||
}
|
||||
|
||||
Char **
|
||||
globall(Char **v)
|
||||
{
|
||||
Char **vl, **vo;
|
||||
int gflg;
|
||||
|
||||
gflg = gflag;
|
||||
if (!v || !v[0]) {
|
||||
gargv = saveblk(v);
|
||||
gargc = blklen(gargv);
|
||||
return (gargv);
|
||||
}
|
||||
|
||||
noglob = adrof(STRnoglob) != 0;
|
||||
|
||||
if (gflg & G_CSH)
|
||||
/*
|
||||
* Expand back-quote, tilde and brace
|
||||
*/
|
||||
vl = vo = globexpand(v);
|
||||
else
|
||||
vl = vo = saveblk(v);
|
||||
|
||||
if (!noglob && (gflg & G_GLOB)) {
|
||||
vl = libglob(vo);
|
||||
if ((gflg & G_CSH) && vl != vo)
|
||||
blkfree(vo);
|
||||
}
|
||||
else
|
||||
trim(vl);
|
||||
|
||||
gargc = vl ? blklen(vl) : 0;
|
||||
return (gargv = vl);
|
||||
}
|
||||
|
||||
void
|
||||
ginit(void)
|
||||
{
|
||||
gargsiz = GLOBSPACE;
|
||||
gargv = xmalloc(sizeof(Char *) * (size_t)gargsiz);
|
||||
gargv[0] = 0;
|
||||
gargc = 0;
|
||||
}
|
||||
|
||||
void
|
||||
rscan(Char **t, void (*f)(int))
|
||||
{
|
||||
Char *p;
|
||||
|
||||
while ((p = *t++) != NULL)
|
||||
while (*p)
|
||||
(*f) (*p++);
|
||||
}
|
||||
|
||||
void
|
||||
trim(Char **t)
|
||||
{
|
||||
Char *p;
|
||||
|
||||
while ((p = *t++) != NULL)
|
||||
while (*p)
|
||||
*p++ &= TRIM;
|
||||
}
|
||||
|
||||
void
|
||||
tglob(Char **t)
|
||||
{
|
||||
Char *p, c;
|
||||
|
||||
while ((p = *t++) != NULL) {
|
||||
if (*p == '~' || *p == '=')
|
||||
gflag |= G_CSH;
|
||||
else if (*p == '{' &&
|
||||
(p[1] == '\0' || (p[1] == '}' && p[2] == '\0')))
|
||||
continue;
|
||||
while ((c = *p++) != '\0') {
|
||||
/*
|
||||
* eat everything inside the matching backquotes
|
||||
*/
|
||||
if (c == '`') {
|
||||
gflag |= G_CSH;
|
||||
while (*p && *p != '`')
|
||||
if (*p++ == '\\') {
|
||||
if (*p) /* Quoted chars */
|
||||
p++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (*p) /* The matching ` */
|
||||
p++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
else if (c == '{')
|
||||
gflag |= G_CSH;
|
||||
else if (isglob(c))
|
||||
gflag |= G_GLOB;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Command substitute cp. If literal, then this is a substitution from a
|
||||
* << redirection, and so we should not crunch blanks and tabs, separating
|
||||
* words only at newlines.
|
||||
*/
|
||||
Char **
|
||||
dobackp(Char *cp, int literal)
|
||||
{
|
||||
Char word[MAXPATHLEN], *ep, *lp, *rp;
|
||||
|
||||
if (pargv) {
|
||||
#ifdef notdef
|
||||
abort();
|
||||
#endif
|
||||
blkfree(pargv);
|
||||
}
|
||||
pargsiz = GLOBSPACE;
|
||||
pargv = xmalloc(sizeof(Char *) * (size_t)pargsiz);
|
||||
pargv[0] = NULL;
|
||||
pargcp = pargs = word;
|
||||
pargc = 0;
|
||||
pnleft = MAXPATHLEN - 4;
|
||||
for (;;) {
|
||||
for (lp = cp; *lp != '`'; lp++) {
|
||||
if (*lp == 0) {
|
||||
if (pargcp != pargs)
|
||||
pword();
|
||||
return (pargv);
|
||||
}
|
||||
psave(*lp);
|
||||
}
|
||||
lp++;
|
||||
for (rp = lp; *rp && *rp != '`'; rp++)
|
||||
if (*rp == '\\') {
|
||||
rp++;
|
||||
if (!*rp)
|
||||
goto oops;
|
||||
}
|
||||
if (!*rp) {
|
||||
oops:
|
||||
stderror(ERR_UNMATCHED, '`');
|
||||
}
|
||||
ep = Strsave(lp);
|
||||
ep[rp - lp] = 0;
|
||||
backeval(ep, literal);
|
||||
cp = rp + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
backeval(Char *cp, int literal)
|
||||
{
|
||||
struct command faket;
|
||||
char tibuf[BUFSIZE];
|
||||
Char ibuf[BUFSIZE], *fakecom[2], *ip;
|
||||
int pvec[2], c, quoted;
|
||||
ssize_t icnt;
|
||||
int hadnl;
|
||||
|
||||
hadnl = 0;
|
||||
icnt = 0;
|
||||
quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0;
|
||||
faket.t_dtyp = NODE_COMMAND;
|
||||
faket.t_dflg = 0;
|
||||
faket.t_dlef = 0;
|
||||
faket.t_drit = 0;
|
||||
faket.t_dspr = 0;
|
||||
faket.t_dcom = fakecom;
|
||||
fakecom[0] = STRfakecom1;
|
||||
fakecom[1] = 0;
|
||||
|
||||
/*
|
||||
* We do the psave job to temporarily change the current job so that the
|
||||
* following fork is considered a separate job. This is so that when
|
||||
* backquotes are used in a builtin function that calls glob the "current
|
||||
* job" is not corrupted. We only need one level of pushed jobs as long as
|
||||
* we are sure to fork here.
|
||||
*/
|
||||
psavejob();
|
||||
|
||||
/*
|
||||
* It would be nicer if we could integrate this redirection more with the
|
||||
* routines in sh.sem.c by doing a fake execute on a builtin function that
|
||||
* was piped out.
|
||||
*/
|
||||
mypipe(pvec);
|
||||
if (pfork(&faket, -1) == 0) {
|
||||
struct wordent fparaml;
|
||||
struct command *t;
|
||||
|
||||
(void)close(pvec[0]);
|
||||
(void)dmove(pvec[1], 1);
|
||||
(void)dmove(SHERR, 2);
|
||||
initdesc();
|
||||
/*
|
||||
* Bugfix for nested backquotes by Michael Greim <greim@sbsvax.UUCP>,
|
||||
* posted to comp.bugs.4bsd 12 Sep. 1989.
|
||||
*/
|
||||
if (pargv) /* mg, 21.dec.88 */
|
||||
blkfree(pargv), pargv = 0, pargsiz = 0;
|
||||
/* mg, 21.dec.88 */
|
||||
arginp = cp;
|
||||
for (arginp = cp; *cp; cp++) {
|
||||
*cp &= TRIM;
|
||||
if (*cp == '\n' || *cp == '\r')
|
||||
*cp = ';';
|
||||
}
|
||||
|
||||
/*
|
||||
* In the child ``forget'' everything about current aliases or
|
||||
* eval vectors.
|
||||
*/
|
||||
alvec = NULL;
|
||||
evalvec = NULL;
|
||||
alvecp = NULL;
|
||||
evalp = NULL;
|
||||
(void) lex(&fparaml);
|
||||
if (seterr)
|
||||
stderror(ERR_OLD);
|
||||
alias(&fparaml);
|
||||
t = syntax(fparaml.next, &fparaml, 0);
|
||||
if (seterr)
|
||||
stderror(ERR_OLD);
|
||||
if (t)
|
||||
t->t_dflg |= F_NOFORK;
|
||||
(void)signal(SIGTSTP, SIG_IGN);
|
||||
(void)signal(SIGTTIN, SIG_IGN);
|
||||
(void)signal(SIGTTOU, SIG_IGN);
|
||||
execute(t, -1, NULL, NULL);
|
||||
exitstat();
|
||||
}
|
||||
xfree((ptr_t)cp);
|
||||
(void)close(pvec[1]);
|
||||
c = 0;
|
||||
ip = NULL;
|
||||
do {
|
||||
int cnt;
|
||||
|
||||
cnt = 0;
|
||||
|
||||
for (;;) {
|
||||
if (icnt == 0) {
|
||||
int i;
|
||||
|
||||
ip = ibuf;
|
||||
do
|
||||
icnt = read(pvec[0], tibuf, BUFSIZE);
|
||||
while (icnt == -1 && errno == EINTR);
|
||||
if (icnt <= 0) {
|
||||
c = -1;
|
||||
break;
|
||||
}
|
||||
for (i = 0; i < icnt; i++)
|
||||
ip[i] = (unsigned char) tibuf[i];
|
||||
}
|
||||
if (hadnl)
|
||||
break;
|
||||
--icnt;
|
||||
c = (*ip++ & TRIM);
|
||||
if (c == 0)
|
||||
break;
|
||||
if (c == '\n') {
|
||||
/*
|
||||
* Continue around the loop one more time, so that we can eat
|
||||
* the last newline without terminating this word.
|
||||
*/
|
||||
hadnl = 1;
|
||||
continue;
|
||||
}
|
||||
if (!quoted && (c == ' ' || c == '\t'))
|
||||
break;
|
||||
cnt++;
|
||||
psave(c | quoted);
|
||||
}
|
||||
/*
|
||||
* Unless at end-of-file, we will form a new word here if there were
|
||||
* characters in the word, or in any case when we take text literally.
|
||||
* If we didn't make empty words here when literal was set then we
|
||||
* would lose blank lines.
|
||||
*/
|
||||
if (c != -1 && (cnt || literal))
|
||||
pword();
|
||||
hadnl = 0;
|
||||
} while (c >= 0);
|
||||
(void)close(pvec[0]);
|
||||
pwait();
|
||||
prestjob();
|
||||
}
|
||||
|
||||
static void
|
||||
psave(int c)
|
||||
{
|
||||
if (--pnleft <= 0)
|
||||
stderror(ERR_WTOOLONG);
|
||||
*pargcp++ = (Char)c;
|
||||
}
|
||||
|
||||
static void
|
||||
pword(void)
|
||||
{
|
||||
psave(0);
|
||||
if (pargc == pargsiz - 1) {
|
||||
pargsiz += GLOBSPACE;
|
||||
pargv = (Char **)xrealloc((ptr_t)pargv,
|
||||
(size_t)pargsiz * sizeof(Char *));
|
||||
}
|
||||
pargv[pargc++] = Strsave(pargs);
|
||||
pargv[pargc] = NULL;
|
||||
pargcp = pargs;
|
||||
pnleft = MAXPATHLEN - 4;
|
||||
}
|
||||
|
||||
int
|
||||
Gmatch(Char *string, Char *pattern)
|
||||
{
|
||||
Char **blk, **p;
|
||||
int gpol, gres;
|
||||
|
||||
gpol = 1;
|
||||
gres = 0;
|
||||
|
||||
if (*pattern == '^') {
|
||||
gpol = 0;
|
||||
pattern++;
|
||||
}
|
||||
|
||||
blk = xmalloc(GLOBSPACE * sizeof(Char *));
|
||||
blk[0] = Strsave(pattern);
|
||||
blk[1] = NULL;
|
||||
|
||||
expbrace(&blk, NULL, GLOBSPACE);
|
||||
|
||||
for (p = blk; *p; p++)
|
||||
gres |= pmatch(string, *p);
|
||||
|
||||
blkfree(blk);
|
||||
return(gres == gpol);
|
||||
}
|
||||
|
||||
static int
|
||||
pmatch(Char *string, Char *pattern)
|
||||
{
|
||||
int match, negate_range;
|
||||
Char patternc, rangec, stringc;
|
||||
|
||||
for (;; ++string) {
|
||||
stringc = *string & TRIM;
|
||||
patternc = *pattern++;
|
||||
switch (patternc) {
|
||||
case 0:
|
||||
return (stringc == 0);
|
||||
case '?':
|
||||
if (stringc == 0)
|
||||
return (0);
|
||||
break;
|
||||
case '*':
|
||||
if (!*pattern)
|
||||
return (1);
|
||||
while (*string)
|
||||
if (Gmatch(string++, pattern))
|
||||
return (1);
|
||||
return (0);
|
||||
case '[':
|
||||
match = 0;
|
||||
if ((negate_range = (*pattern == '^')) != 0)
|
||||
pattern++;
|
||||
while ((rangec = *pattern++) != '\0') {
|
||||
if (rangec == ']')
|
||||
break;
|
||||
if (match)
|
||||
continue;
|
||||
if (rangec == '-' && *(pattern-2) != '[' && *pattern != ']') {
|
||||
match = (stringc <= (*pattern & TRIM) &&
|
||||
(*(pattern-2) & TRIM) <= stringc);
|
||||
pattern++;
|
||||
}
|
||||
else
|
||||
match = (stringc == (rangec & TRIM));
|
||||
}
|
||||
if (rangec == 0)
|
||||
stderror(ERR_NAME | ERR_MISSING, ']');
|
||||
if (match == negate_range)
|
||||
return (0);
|
||||
break;
|
||||
default:
|
||||
if ((patternc & TRIM) != stringc)
|
||||
return (0);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Gcat(Char *s1, Char *s2)
|
||||
{
|
||||
Char *p, *q;
|
||||
ptrdiff_t n;
|
||||
|
||||
for (p = s1; *p++;)
|
||||
continue;
|
||||
for (q = s2; *q++;)
|
||||
continue;
|
||||
n = (p - s1) + (q - s2) - 1;
|
||||
if (++gargc >= gargsiz) {
|
||||
gargsiz += GLOBSPACE;
|
||||
gargv = (Char **)xrealloc((ptr_t)gargv,
|
||||
(size_t)gargsiz * sizeof(Char *));
|
||||
}
|
||||
gargv[gargc] = 0;
|
||||
p = gargv[gargc - 1] = xmalloc((size_t)n * sizeof(Char));
|
||||
for (q = s1; (*p++ = *q++) != '\0';)
|
||||
continue;
|
||||
for (p--, q = s2; (*p++ = *q++) != '\0';)
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef FILEC
|
||||
int
|
||||
sortscmp(const ptr_t a, const ptr_t b)
|
||||
{
|
||||
#if defined(NLS) && !defined(NOSTRCOLL)
|
||||
char buf[2048];
|
||||
#endif
|
||||
|
||||
if (!a) /* check for NULL */
|
||||
return (b ? 1 : 0);
|
||||
if (!b)
|
||||
return (-1);
|
||||
|
||||
if (!*(Char **)a) /* check for NULL */
|
||||
return (*(Char **)b ? 1 : 0);
|
||||
if (!*(Char **)b)
|
||||
return (-1);
|
||||
|
||||
#if defined(NLS) && !defined(NOSTRCOLL)
|
||||
(void)strcpy(buf, short2str(*(Char **)a));
|
||||
return ((int)strcoll(buf, short2str(*(Char **)b)));
|
||||
#else
|
||||
return ((int)Strcmp(*(Char **)a, *(Char **)b));
|
||||
#endif
|
||||
}
|
||||
#endif /* FILEC */
|
207
bin/csh/hist.c
Normal file
207
bin/csh/hist.c
Normal file
|
@ -0,0 +1,207 @@
|
|||
/* $NetBSD: hist.c,v 1.20 2013/07/16 17:47:43 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1980, 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)hist.c 8.1 (Berkeley) 5/31/93";
|
||||
#else
|
||||
__RCSID("$NetBSD: hist.c,v 1.20 2013/07/16 17:47:43 christos Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "csh.h"
|
||||
#include "extern.h"
|
||||
|
||||
static void hfree(struct Hist *);
|
||||
static void dohist1(struct Hist *, int *, int, int);
|
||||
static void phist(struct Hist *, int);
|
||||
|
||||
void
|
||||
savehist(struct wordent *sp)
|
||||
{
|
||||
struct Hist *hp, *np;
|
||||
Char *cp;
|
||||
int histlen;
|
||||
|
||||
histlen = 0;
|
||||
|
||||
/* throw away null lines */
|
||||
if (sp->next->word[0] == '\n')
|
||||
return;
|
||||
cp = value(STRhistory);
|
||||
if (*cp) {
|
||||
Char *p = cp;
|
||||
|
||||
while (*p) {
|
||||
if (!Isdigit(*p)) {
|
||||
histlen = 0;
|
||||
break;
|
||||
}
|
||||
histlen = histlen * 10 + *p++ - '0';
|
||||
}
|
||||
}
|
||||
for (hp = &Histlist; (np = hp->Hnext) != NULL;)
|
||||
if (eventno - np->Href >= histlen || histlen == 0)
|
||||
hp->Hnext = np->Hnext, hfree(np);
|
||||
else
|
||||
hp = np;
|
||||
(void) enthist(++eventno, sp, 1);
|
||||
}
|
||||
|
||||
#ifdef EDIT
|
||||
void
|
||||
loadhist(struct Hist *hp) {
|
||||
char *h = NULL;
|
||||
|
||||
if (hi == NULL || hp == NULL)
|
||||
return;
|
||||
loadhist(hp->Hnext);
|
||||
if (sprlex(&h, &hp->Hlex) != -1) {
|
||||
HistEvent ev;
|
||||
history(hi, &ev, H_ENTER, h);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
struct Hist *
|
||||
enthist(int event, struct wordent *lp, int docopy)
|
||||
{
|
||||
struct Hist *np;
|
||||
|
||||
#ifdef EDIT
|
||||
if (hi) {
|
||||
char *h = NULL;
|
||||
if (sprlex(&h, lp) != -1) {
|
||||
HistEvent ev;
|
||||
history(hi, &ev, H_ENTER, h);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
np = xmalloc(sizeof(*np));
|
||||
np->Hnum = np->Href = event;
|
||||
if (docopy) {
|
||||
copylex(&np->Hlex, lp);
|
||||
}
|
||||
else {
|
||||
np->Hlex.next = lp->next;
|
||||
lp->next->prev = &np->Hlex;
|
||||
np->Hlex.prev = lp->prev;
|
||||
lp->prev->next = &np->Hlex;
|
||||
}
|
||||
np->Hnext = Histlist.Hnext;
|
||||
Histlist.Hnext = np;
|
||||
return (np);
|
||||
}
|
||||
|
||||
static void
|
||||
hfree(struct Hist *hp)
|
||||
{
|
||||
freelex(&hp->Hlex);
|
||||
xfree((ptr_t) hp);
|
||||
}
|
||||
|
||||
void
|
||||
/*ARGSUSED*/
|
||||
dohist(Char **v, struct command *t)
|
||||
{
|
||||
sigset_t nsigset;
|
||||
int hflg, n, rflg;
|
||||
|
||||
hflg = 0;
|
||||
rflg = 0;
|
||||
|
||||
if (getn(value(STRhistory)) == 0)
|
||||
return;
|
||||
if (setintr) {
|
||||
sigemptyset(&nsigset);
|
||||
(void)sigaddset(&nsigset, SIGINT);
|
||||
(void)sigprocmask(SIG_UNBLOCK, &nsigset, NULL);
|
||||
}
|
||||
while (*++v && **v == '-') {
|
||||
Char *vp = *v;
|
||||
|
||||
while (*++vp)
|
||||
switch (*vp) {
|
||||
case 'h':
|
||||
hflg++;
|
||||
break;
|
||||
case 'r':
|
||||
rflg++;
|
||||
break;
|
||||
case '-': /* ignore multiple '-'s */
|
||||
break;
|
||||
default:
|
||||
stderror(ERR_HISTUS);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
if (*v)
|
||||
n = getn(*v);
|
||||
else {
|
||||
n = getn(value(STRhistory));
|
||||
}
|
||||
dohist1(Histlist.Hnext, &n, rflg, hflg);
|
||||
}
|
||||
|
||||
static void
|
||||
dohist1(struct Hist *hp, int *np, int rflg, int hflg)
|
||||
{
|
||||
int print;
|
||||
|
||||
print = (*np) > 0;
|
||||
|
||||
for (; hp != 0; hp = hp->Hnext) {
|
||||
(*np)--;
|
||||
hp->Href++;
|
||||
if (rflg == 0) {
|
||||
dohist1(hp->Hnext, np, rflg, hflg);
|
||||
if (print)
|
||||
phist(hp, hflg);
|
||||
return;
|
||||
}
|
||||
if (*np >= 0)
|
||||
phist(hp, hflg);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
phist(struct Hist *hp, int hflg)
|
||||
{
|
||||
if (hflg == 0)
|
||||
(void)fprintf(cshout, "%6d\t", hp->Hnum);
|
||||
prlex(cshout, &hp->Hlex);
|
||||
}
|
131
bin/csh/init.c
Normal file
131
bin/csh/init.c
Normal file
|
@ -0,0 +1,131 @@
|
|||
/* $NetBSD: init.c,v 1.11 2013/01/22 19:28:00 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1980, 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)init.c 8.1 (Berkeley) 5/31/93";
|
||||
#else
|
||||
__RCSID("$NetBSD: init.c,v 1.11 2013/01/22 19:28:00 christos Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "csh.h"
|
||||
#include "extern.h"
|
||||
|
||||
#define INF 1000
|
||||
|
||||
struct biltins bfunc[] =
|
||||
{
|
||||
{ "@", dolet, 0, INF },
|
||||
{ "alias", doalias, 0, INF },
|
||||
{ "bg", dobg, 0, INF },
|
||||
{ "break", dobreak, 0, 0 },
|
||||
{ "breaksw", doswbrk, 0, 0 },
|
||||
{ "case", dozip, 0, 1 },
|
||||
{ "cd", dochngd, 0, INF },
|
||||
{ "chdir", dochngd, 0, INF },
|
||||
{ "continue", docontin, 0, 0 },
|
||||
{ "default", dozip, 0, 0 },
|
||||
{ "dirs", dodirs, 0, INF },
|
||||
{ "echo", doecho, 0, INF },
|
||||
{ "else", doelse, 0, INF },
|
||||
{ "end", doend, 0, 0 },
|
||||
{ "endif", dozip, 0, 0 },
|
||||
{ "endsw", dozip, 0, 0 },
|
||||
{ "eval", doeval, 0, INF },
|
||||
{ "exec", execash, 1, INF },
|
||||
{ "exit", doexit, 0, INF },
|
||||
{ "fg", dofg, 0, INF },
|
||||
{ "foreach", doforeach, 3, INF },
|
||||
{ "glob", doglob, 0, INF },
|
||||
{ "goto", dogoto, 1, 1 },
|
||||
{ "hashstat", hashstat, 0, 0 },
|
||||
{ "history", dohist, 0, 2 },
|
||||
{ "if", doif, 1, INF },
|
||||
{ "jobs", dojobs, 0, 1 },
|
||||
{ "kill", dokill, 1, INF },
|
||||
{ "limit", dolimit, 0, 3 },
|
||||
{ "linedit", doecho, 0, INF },
|
||||
{ "login", dologin, 0, 1 },
|
||||
{ "logout", dologout, 0, 0 },
|
||||
{ "nice", donice, 0, INF },
|
||||
{ "nohup", donohup, 0, INF },
|
||||
{ "notify", donotify, 0, INF },
|
||||
{ "onintr", doonintr, 0, 2 },
|
||||
{ "popd", dopopd, 0, INF },
|
||||
{ "printf", doprintf, 1, INF },
|
||||
{ "pushd", dopushd, 0, INF },
|
||||
{ "rehash", dohash, 0, 0 },
|
||||
{ "repeat", dorepeat, 2, INF },
|
||||
{ "set", doset, 0, INF },
|
||||
{ "setenv", dosetenv, 0, 2 },
|
||||
{ "shift", shift, 0, 1 },
|
||||
{ "source", dosource, 1, 2 },
|
||||
{ "stop", dostop, 1, INF },
|
||||
{ "suspend", dosuspend, 0, 0 },
|
||||
{ "switch", doswitch, 1, INF },
|
||||
{ "time", dotime, 0, INF },
|
||||
{ "umask", doumask, 0, 1 },
|
||||
{ "unalias", unalias, 1, INF },
|
||||
{ "unhash", dounhash, 0, 0 },
|
||||
{ "unlimit", dounlimit, 0, INF },
|
||||
{ "unset", unset, 1, INF },
|
||||
{ "unsetenv", dounsetenv, 1, INF },
|
||||
{ "wait", dowait, 0, 0 },
|
||||
{ "which", dowhich, 1, INF },
|
||||
{ "while", dowhile, 1, INF }
|
||||
};
|
||||
int nbfunc = sizeof(bfunc) / sizeof(*bfunc);
|
||||
|
||||
struct srch srchn[] =
|
||||
{
|
||||
{ "@", T_LET },
|
||||
{ "break", T_BREAK },
|
||||
{ "breaksw", T_BRKSW },
|
||||
{ "case", T_CASE },
|
||||
{ "default", T_DEFAULT },
|
||||
{ "else", T_ELSE },
|
||||
{ "end", T_END },
|
||||
{ "endif", T_ENDIF },
|
||||
{ "endsw", T_ENDSW },
|
||||
{ "exit", T_EXIT },
|
||||
{ "foreach", T_FOREACH },
|
||||
{ "goto", T_GOTO },
|
||||
{ "if", T_IF },
|
||||
{ "label", T_LABEL },
|
||||
{ "set", T_SET },
|
||||
{ "switch", T_SWITCH },
|
||||
{ "while", T_WHILE }
|
||||
};
|
||||
int nsrchn = sizeof(srchn) / sizeof(*srchn);
|
1631
bin/csh/lex.c
Normal file
1631
bin/csh/lex.c
Normal file
File diff suppressed because it is too large
Load diff
407
bin/csh/misc.c
Normal file
407
bin/csh/misc.c
Normal file
|
@ -0,0 +1,407 @@
|
|||
/* $NetBSD: misc.c,v 1.20 2013/07/16 17:47:43 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1980, 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)misc.c 8.1 (Berkeley) 5/31/93";
|
||||
#else
|
||||
__RCSID("$NetBSD: misc.c,v 1.20 2013/07/16 17:47:43 christos Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "csh.h"
|
||||
#include "extern.h"
|
||||
|
||||
static int renum(int, int);
|
||||
|
||||
int
|
||||
any(const char *s, int c)
|
||||
{
|
||||
if (!s)
|
||||
return (0); /* Check for nil pointer */
|
||||
while (*s)
|
||||
if (*s++ == c)
|
||||
return (1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
char *
|
||||
strsave(const char *s)
|
||||
{
|
||||
const char *n;
|
||||
char *p, *r;
|
||||
|
||||
if (s == NULL)
|
||||
s = "";
|
||||
for (n = s; *n++;)
|
||||
continue;
|
||||
r = p = xmalloc((size_t)(n - s) * sizeof(*p));
|
||||
while ((*p++ = *s++) != '\0')
|
||||
continue;
|
||||
return (r);
|
||||
}
|
||||
|
||||
Char **
|
||||
blkend(Char **up)
|
||||
{
|
||||
while (*up)
|
||||
up++;
|
||||
return (up);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
blkpr(FILE *fp, Char **av)
|
||||
{
|
||||
for (; *av; av++) {
|
||||
(void)fprintf(fp, "%s", vis_str(*av));
|
||||
if (av[1])
|
||||
(void)fprintf(fp, " ");
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
blklen(Char **av)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
while (*av++)
|
||||
i++;
|
||||
return (i);
|
||||
}
|
||||
|
||||
Char **
|
||||
blkcpy(Char **oav, Char **bv)
|
||||
{
|
||||
Char **av;
|
||||
|
||||
av = oav;
|
||||
while ((*av++ = *bv++) != NULL)
|
||||
continue;
|
||||
return (oav);
|
||||
}
|
||||
|
||||
Char **
|
||||
blkcat(Char **up, Char **vp)
|
||||
{
|
||||
(void)blkcpy(blkend(up), vp);
|
||||
return (up);
|
||||
}
|
||||
|
||||
void
|
||||
blkfree(Char **av0)
|
||||
{
|
||||
Char **av;
|
||||
|
||||
av = av0;
|
||||
if (!av0)
|
||||
return;
|
||||
for (; *av; av++)
|
||||
xfree((ptr_t) * av);
|
||||
xfree((ptr_t) av0);
|
||||
}
|
||||
|
||||
Char **
|
||||
saveblk(Char **v)
|
||||
{
|
||||
Char **newv, **onewv;
|
||||
|
||||
if (v == NULL)
|
||||
return NULL;
|
||||
|
||||
newv = xcalloc((size_t)(blklen(v) + 1), sizeof(*newv));
|
||||
onewv = newv;
|
||||
while (*v)
|
||||
*newv++ = Strsave(*v++);
|
||||
return (onewv);
|
||||
}
|
||||
|
||||
#ifdef NOTUSED
|
||||
char *
|
||||
strstr(char *s, char *t)
|
||||
{
|
||||
do {
|
||||
char *ss;
|
||||
char *tt;
|
||||
|
||||
ss = s;
|
||||
tt = t;
|
||||
|
||||
do
|
||||
if (*tt == '\0')
|
||||
return (s);
|
||||
while (*ss++ == *tt++);
|
||||
} while (*s++ != '\0');
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
#endif /* NOTUSED */
|
||||
|
||||
#ifndef SHORT_STRINGS
|
||||
char *
|
||||
strspl(char *cp, char *dp)
|
||||
{
|
||||
char *ep, *p, *q;
|
||||
|
||||
if (!cp)
|
||||
cp = "";
|
||||
if (!dp)
|
||||
dp = "";
|
||||
for (p = cp; *p++;)
|
||||
continue;
|
||||
for (q = dp; *q++;)
|
||||
continue;
|
||||
ep = xmalloc((size_t)(((p - cp) + (q - dp) - 1) * sizeof(*ep)));
|
||||
for (p = ep, q = cp; *p++ = *q++;)
|
||||
continue;
|
||||
for (p--, q = dp; *p++ = *q++;)
|
||||
continue;
|
||||
return (ep);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Char **
|
||||
blkspl(Char **up, Char **vp)
|
||||
{
|
||||
Char **wp;
|
||||
|
||||
wp = xcalloc((size_t)(blklen(up) + blklen(vp) + 1), sizeof(*wp));
|
||||
(void)blkcpy(wp, up);
|
||||
return (blkcat(wp, vp));
|
||||
}
|
||||
|
||||
Char
|
||||
lastchr(Char *cp)
|
||||
{
|
||||
if (!cp)
|
||||
return (0);
|
||||
if (!*cp)
|
||||
return (0);
|
||||
while (cp[1])
|
||||
cp++;
|
||||
return (*cp);
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine is called after an error to close up
|
||||
* any units which may have been left open accidentally.
|
||||
*/
|
||||
void
|
||||
closem(void)
|
||||
{
|
||||
int f;
|
||||
int nofile;
|
||||
|
||||
#ifdef F_CLOSEM
|
||||
nofile = FOLDSTD + 1;
|
||||
if (fcntl(nofile, F_CLOSEM, 0) == -1)
|
||||
#endif
|
||||
nofile = NOFILE;
|
||||
|
||||
for (f = 0; f < nofile; f++)
|
||||
if (f != SHIN && f != SHOUT && f != SHERR && f != OLDSTD &&
|
||||
f != FSHTTY)
|
||||
(void) close(f);
|
||||
}
|
||||
|
||||
void
|
||||
donefds(void)
|
||||
{
|
||||
(void)close(0);
|
||||
(void)close(1);
|
||||
(void)close(2);
|
||||
|
||||
didfds = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Move descriptor i to j.
|
||||
* If j is -1 then we just want to get i to a safe place,
|
||||
* i.e. to a unit > 2. This also happens in dcopy.
|
||||
*/
|
||||
int
|
||||
dmove(int i, int j)
|
||||
{
|
||||
if (i == j || i < 0)
|
||||
return (i);
|
||||
if (j >= 0) {
|
||||
(void)dup2(i, j);
|
||||
if (j != i)
|
||||
(void)close(i);
|
||||
return (j);
|
||||
}
|
||||
j = dcopy(i, j);
|
||||
if (j != i)
|
||||
(void)close(i);
|
||||
return (j);
|
||||
}
|
||||
|
||||
int
|
||||
dcopy(int i, int j)
|
||||
{
|
||||
if (i == j || i < 0 || (j < 0 && i > 2))
|
||||
return (i);
|
||||
if (j >= 0) {
|
||||
(void)dup2(i, j);
|
||||
return (j);
|
||||
}
|
||||
return (renum(i, j));
|
||||
}
|
||||
|
||||
static int
|
||||
renum(int i, int j)
|
||||
{
|
||||
int k;
|
||||
|
||||
k = dup(i);
|
||||
if (k < 0)
|
||||
return (-1);
|
||||
if (j == -1 && k > 2)
|
||||
return (k);
|
||||
if (k != j) {
|
||||
j = renum(k, j);
|
||||
(void)close(k);
|
||||
return (j);
|
||||
}
|
||||
return (k);
|
||||
}
|
||||
|
||||
/*
|
||||
* Left shift a command argument list, discarding
|
||||
* the first c arguments. Used in "shift" commands
|
||||
* as well as by commands like "repeat".
|
||||
*/
|
||||
void
|
||||
lshift(Char **v, size_t c)
|
||||
{
|
||||
Char **u;
|
||||
|
||||
for (u = v; *u && c-- > 0; u++)
|
||||
xfree((ptr_t) *u);
|
||||
(void)blkcpy(v, u);
|
||||
}
|
||||
|
||||
int
|
||||
number(Char *cp)
|
||||
{
|
||||
if (!cp)
|
||||
return(0);
|
||||
if (*cp == '-') {
|
||||
cp++;
|
||||
if (!Isdigit(*cp))
|
||||
return (0);
|
||||
cp++;
|
||||
}
|
||||
while (*cp && Isdigit(*cp))
|
||||
cp++;
|
||||
return (*cp == 0);
|
||||
}
|
||||
|
||||
Char **
|
||||
copyblk(Char **v)
|
||||
{
|
||||
Char **nv;
|
||||
|
||||
nv = xcalloc((size_t)(blklen(v) + 1), sizeof(*nv));
|
||||
|
||||
return (blkcpy(nv, v));
|
||||
}
|
||||
|
||||
#ifndef SHORT_STRINGS
|
||||
char *
|
||||
strend(char *cp)
|
||||
{
|
||||
if (!cp)
|
||||
return (cp);
|
||||
while (*cp)
|
||||
cp++;
|
||||
return (cp);
|
||||
}
|
||||
|
||||
#endif /* SHORT_STRINGS */
|
||||
|
||||
Char *
|
||||
strip(Char *cp)
|
||||
{
|
||||
Char *dp;
|
||||
|
||||
dp = cp;
|
||||
if (!cp)
|
||||
return (cp);
|
||||
while ((*dp++ &= TRIM) != '\0')
|
||||
continue;
|
||||
return (cp);
|
||||
}
|
||||
|
||||
Char *
|
||||
quote(Char *cp)
|
||||
{
|
||||
Char *dp;
|
||||
|
||||
dp = cp;
|
||||
if (!cp)
|
||||
return (cp);
|
||||
while (*dp != '\0')
|
||||
*dp++ |= QUOTE;
|
||||
return (cp);
|
||||
}
|
||||
|
||||
void
|
||||
udvar(Char *name)
|
||||
{
|
||||
setname(vis_str(name));
|
||||
stderror(ERR_NAME | ERR_UNDVAR);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
int
|
||||
prefix(Char *sub, Char *str)
|
||||
{
|
||||
for (;;) {
|
||||
if (*sub == 0)
|
||||
return (1);
|
||||
if (*str == 0)
|
||||
return (0);
|
||||
if (*sub++ != *str++)
|
||||
return (0);
|
||||
}
|
||||
}
|
640
bin/csh/parse.c
Normal file
640
bin/csh/parse.c
Normal file
|
@ -0,0 +1,640 @@
|
|||
/* $NetBSD: parse.c,v 1.17 2007/07/16 18:26:10 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1980, 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)parse.c 8.1 (Berkeley) 5/31/93";
|
||||
#else
|
||||
__RCSID("$NetBSD: parse.c,v 1.17 2007/07/16 18:26:10 christos Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "csh.h"
|
||||
#include "extern.h"
|
||||
|
||||
static void asyntax(struct wordent *, struct wordent *);
|
||||
static void asyn0(struct wordent *, struct wordent *);
|
||||
static void asyn3(struct wordent *, struct wordent *);
|
||||
static struct wordent *freenod(struct wordent *, struct wordent *);
|
||||
static struct command *syn0(struct wordent *, struct wordent *, int);
|
||||
static struct command *syn1(struct wordent *, struct wordent *, int);
|
||||
static struct command *syn1a(struct wordent *, struct wordent *, int);
|
||||
static struct command *syn1b(struct wordent *, struct wordent *, int);
|
||||
static struct command *syn2(struct wordent *, struct wordent *, int);
|
||||
static struct command *syn3(struct wordent *, struct wordent *, int);
|
||||
|
||||
#define ALEFT 21 /* max of 20 alias expansions */
|
||||
#define HLEFT 11 /* max of 10 history expansions */
|
||||
/*
|
||||
* Perform aliasing on the word list lex
|
||||
* Do a (very rudimentary) parse to separate into commands.
|
||||
* If word 0 of a command has an alias, do it.
|
||||
* Repeat a maximum of 20 times.
|
||||
*/
|
||||
static int aleft;
|
||||
extern int hleft;
|
||||
|
||||
void
|
||||
alias(struct wordent *lexp)
|
||||
{
|
||||
jmp_buf osetexit;
|
||||
|
||||
aleft = ALEFT;
|
||||
hleft = HLEFT;
|
||||
getexit(osetexit);
|
||||
(void)setexit();
|
||||
if (haderr) {
|
||||
resexit(osetexit);
|
||||
reset();
|
||||
}
|
||||
if (--aleft == 0)
|
||||
stderror(ERR_ALIASLOOP);
|
||||
asyntax(lexp->next, lexp);
|
||||
resexit(osetexit);
|
||||
}
|
||||
|
||||
static void
|
||||
asyntax(struct wordent *p1, struct wordent *p2)
|
||||
{
|
||||
while (p1 != p2)
|
||||
if (any(";&\n", p1->word[0]))
|
||||
p1 = p1->next;
|
||||
else {
|
||||
asyn0(p1, p2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
asyn0(struct wordent *p1, struct wordent *p2)
|
||||
{
|
||||
struct wordent *p;
|
||||
int l;
|
||||
|
||||
l = 0;
|
||||
for (p = p1; p != p2; p = p->next)
|
||||
switch (p->word[0]) {
|
||||
case '(':
|
||||
l++;
|
||||
continue;
|
||||
case ')':
|
||||
l--;
|
||||
if (l < 0)
|
||||
stderror(ERR_TOOMANYRP);
|
||||
continue;
|
||||
case '>':
|
||||
if (p->next != p2 && eq(p->next->word, STRand))
|
||||
p = p->next;
|
||||
continue;
|
||||
case '&':
|
||||
case '|':
|
||||
case ';':
|
||||
case '\n':
|
||||
if (l != 0)
|
||||
continue;
|
||||
asyn3(p1, p);
|
||||
asyntax(p->next, p2);
|
||||
return;
|
||||
}
|
||||
if (l == 0)
|
||||
asyn3(p1, p2);
|
||||
}
|
||||
|
||||
static void
|
||||
asyn3(struct wordent *p1, struct wordent *p2)
|
||||
{
|
||||
struct varent *ap;
|
||||
struct wordent alout;
|
||||
int redid;
|
||||
|
||||
if (p1 == p2)
|
||||
return;
|
||||
if (p1->word[0] == '(') {
|
||||
for (p2 = p2->prev; p2->word[0] != ')'; p2 = p2->prev)
|
||||
if (p2 == p1)
|
||||
return;
|
||||
if (p2 == p1->next)
|
||||
return;
|
||||
asyn0(p1->next, p2);
|
||||
return;
|
||||
}
|
||||
ap = adrof1(p1->word, &aliases);
|
||||
if (ap == 0)
|
||||
return;
|
||||
alhistp = p1->prev;
|
||||
alhistt = p2;
|
||||
alvec = ap->vec;
|
||||
redid = lex(&alout);
|
||||
alhistp = alhistt = 0;
|
||||
alvec = 0;
|
||||
if (seterr) {
|
||||
freelex(&alout);
|
||||
stderror(ERR_OLD);
|
||||
}
|
||||
if (p1->word[0] && eq(p1->word, alout.next->word)) {
|
||||
Char *cp;
|
||||
|
||||
cp = alout.next->word;
|
||||
alout.next->word = Strspl(STRQNULL, cp);
|
||||
xfree((ptr_t) cp);
|
||||
}
|
||||
p1 = freenod(p1, redid ? p2 : p1->next);
|
||||
if (alout.next != &alout) {
|
||||
p1->next->prev = alout.prev->prev;
|
||||
alout.prev->prev->next = p1->next;
|
||||
alout.next->prev = p1;
|
||||
p1->next = alout.next;
|
||||
xfree((ptr_t)alout.prev->word);
|
||||
xfree((ptr_t)(alout.prev));
|
||||
}
|
||||
reset(); /* throw! */
|
||||
}
|
||||
|
||||
static struct wordent *
|
||||
freenod(struct wordent *p1, struct wordent *p2)
|
||||
{
|
||||
struct wordent *retp;
|
||||
|
||||
retp = p1->prev;
|
||||
while (p1 != p2) {
|
||||
xfree((ptr_t)p1->word);
|
||||
p1 = p1->next;
|
||||
xfree((ptr_t) (p1->prev));
|
||||
}
|
||||
retp->next = p2;
|
||||
p2->prev = retp;
|
||||
return (retp);
|
||||
}
|
||||
|
||||
#define PHERE 1
|
||||
#define PIN 2
|
||||
#define POUT 4
|
||||
#define PERR 8
|
||||
|
||||
/*
|
||||
* syntax
|
||||
* empty
|
||||
* syn0
|
||||
*/
|
||||
struct command *
|
||||
syntax(struct wordent *p1, struct wordent *p2, int flags)
|
||||
{
|
||||
while (p1 != p2)
|
||||
if (any(";&\n", p1->word[0]))
|
||||
p1 = p1->next;
|
||||
else
|
||||
return (syn0(p1, p2, flags));
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* syn0
|
||||
* syn1
|
||||
* syn1 & syntax
|
||||
*/
|
||||
static struct command *
|
||||
syn0(struct wordent *p1, struct wordent *p2, int flags)
|
||||
{
|
||||
struct wordent *p;
|
||||
struct command *t, *t1;
|
||||
int l;
|
||||
|
||||
l = 0;
|
||||
for (p = p1; p != p2; p = p->next)
|
||||
switch (p->word[0]) {
|
||||
case '(':
|
||||
l++;
|
||||
continue;
|
||||
case ')':
|
||||
l--;
|
||||
if (l < 0)
|
||||
seterror(ERR_TOOMANYRP);
|
||||
continue;
|
||||
case '|':
|
||||
if (p->word[1] == '|')
|
||||
continue;
|
||||
/* FALLTHROUGH */
|
||||
case '>':
|
||||
if (p->next != p2 && eq(p->next->word, STRand))
|
||||
p = p->next;
|
||||
continue;
|
||||
case '&':
|
||||
if (l != 0)
|
||||
break;
|
||||
if (p->word[1] == '&')
|
||||
continue;
|
||||
t1 = syn1(p1, p, flags);
|
||||
if (t1->t_dtyp == NODE_LIST ||
|
||||
t1->t_dtyp == NODE_AND ||
|
||||
t1->t_dtyp == NODE_OR) {
|
||||
t = (struct command *)xcalloc(1, sizeof(*t));
|
||||
t->t_dtyp = NODE_PAREN;
|
||||
t->t_dflg = F_AMPERSAND | F_NOINTERRUPT;
|
||||
t->t_dspr = t1;
|
||||
t1 = t;
|
||||
}
|
||||
else
|
||||
t1->t_dflg |= F_AMPERSAND | F_NOINTERRUPT;
|
||||
t = (struct command *)xcalloc(1, sizeof(*t));
|
||||
t->t_dtyp = NODE_LIST;
|
||||
t->t_dflg = 0;
|
||||
t->t_dcar = t1;
|
||||
t->t_dcdr = syntax(p, p2, flags);
|
||||
return (t);
|
||||
}
|
||||
if (l == 0)
|
||||
return (syn1(p1, p2, flags));
|
||||
seterror(ERR_TOOMANYLP);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* syn1
|
||||
* syn1a
|
||||
* syn1a ; syntax
|
||||
*/
|
||||
static struct command *
|
||||
syn1(struct wordent *p1, struct wordent *p2, int flags)
|
||||
{
|
||||
struct wordent *p;
|
||||
struct command *t;
|
||||
int l;
|
||||
|
||||
l = 0;
|
||||
for (p = p1; p != p2; p = p->next)
|
||||
switch (p->word[0]) {
|
||||
case '(':
|
||||
l++;
|
||||
continue;
|
||||
case ')':
|
||||
l--;
|
||||
continue;
|
||||
case ';':
|
||||
case '\n':
|
||||
if (l != 0)
|
||||
break;
|
||||
t = (struct command *) xcalloc(1, sizeof(*t));
|
||||
t->t_dtyp = NODE_LIST;
|
||||
t->t_dcar = syn1a(p1, p, flags);
|
||||
t->t_dcdr = syntax(p->next, p2, flags);
|
||||
if (t->t_dcdr == 0)
|
||||
t->t_dcdr = t->t_dcar, t->t_dcar = 0;
|
||||
return (t);
|
||||
}
|
||||
return (syn1a(p1, p2, flags));
|
||||
}
|
||||
|
||||
/*
|
||||
* syn1a
|
||||
* syn1b
|
||||
* syn1b || syn1a
|
||||
*/
|
||||
static struct command *
|
||||
syn1a(struct wordent *p1, struct wordent *p2, int flags)
|
||||
{
|
||||
struct wordent *p;
|
||||
struct command *t;
|
||||
int l;
|
||||
|
||||
l = 0;
|
||||
for (p = p1; p != p2; p = p->next)
|
||||
switch (p->word[0]) {
|
||||
case '(':
|
||||
l++;
|
||||
continue;
|
||||
case ')':
|
||||
l--;
|
||||
continue;
|
||||
case '|':
|
||||
if (p->word[1] != '|')
|
||||
continue;
|
||||
if (l == 0) {
|
||||
t = (struct command *)xcalloc(1, sizeof(*t));
|
||||
t->t_dtyp = NODE_OR;
|
||||
t->t_dcar = syn1b(p1, p, flags);
|
||||
t->t_dcdr = syn1a(p->next, p2, flags);
|
||||
t->t_dflg = 0;
|
||||
return (t);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
return (syn1b(p1, p2, flags));
|
||||
}
|
||||
|
||||
/*
|
||||
* syn1b
|
||||
* syn2
|
||||
* syn2 && syn1b
|
||||
*/
|
||||
static struct command *
|
||||
syn1b(struct wordent *p1, struct wordent *p2, int flags)
|
||||
{
|
||||
struct wordent *p;
|
||||
struct command *t;
|
||||
int l;
|
||||
|
||||
l = 0;
|
||||
for (p = p1; p != p2; p = p->next)
|
||||
switch (p->word[0]) {
|
||||
case '(':
|
||||
l++;
|
||||
continue;
|
||||
case ')':
|
||||
l--;
|
||||
continue;
|
||||
case '&':
|
||||
if (p->word[1] == '&' && l == 0) {
|
||||
t = (struct command *)xcalloc(1, sizeof(*t));
|
||||
t->t_dtyp = NODE_AND;
|
||||
t->t_dcar = syn2(p1, p, flags);
|
||||
t->t_dcdr = syn1b(p->next, p2, flags);
|
||||
t->t_dflg = 0;
|
||||
return (t);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
return (syn2(p1, p2, flags));
|
||||
}
|
||||
|
||||
/*
|
||||
* syn2
|
||||
* syn3
|
||||
* syn3 | syn2
|
||||
* syn3 |& syn2
|
||||
*/
|
||||
static struct command *
|
||||
syn2(struct wordent *p1, struct wordent *p2, int flags)
|
||||
{
|
||||
struct wordent *p, *pn;
|
||||
struct command *t;
|
||||
int f, l;
|
||||
|
||||
l = 0;
|
||||
for (p = p1; p != p2; p = p->next)
|
||||
switch (p->word[0]) {
|
||||
case '(':
|
||||
l++;
|
||||
continue;
|
||||
case ')':
|
||||
l--;
|
||||
continue;
|
||||
case '|':
|
||||
if (l != 0)
|
||||
continue;
|
||||
t = (struct command *)xcalloc(1, sizeof(*t));
|
||||
f = flags | POUT;
|
||||
pn = p->next;
|
||||
if (pn != p2 && pn->word[0] == '&') {
|
||||
f |= PERR;
|
||||
t->t_dflg |= F_STDERR;
|
||||
}
|
||||
t->t_dtyp = NODE_PIPE;
|
||||
t->t_dcar = syn3(p1, p, f);
|
||||
if (pn != p2 && pn->word[0] == '&')
|
||||
p = pn;
|
||||
t->t_dcdr = syn2(p->next, p2, flags | PIN);
|
||||
return (t);
|
||||
}
|
||||
return (syn3(p1, p2, flags));
|
||||
}
|
||||
|
||||
static char RELPAR[] = {'<', '>', '(', ')', '\0'};
|
||||
|
||||
/*
|
||||
* syn3
|
||||
* ( syn0 ) [ < in ] [ > out ]
|
||||
* word word* [ < in ] [ > out ]
|
||||
* KEYWORD ( word* ) word* [ < in ] [ > out ]
|
||||
*
|
||||
* KEYWORD = (@ exit foreach if set switch test while)
|
||||
*/
|
||||
static struct command *
|
||||
syn3(struct wordent *p1, struct wordent *p2, int flags)
|
||||
{
|
||||
struct wordent *lp, *p, *rp;
|
||||
struct command *t;
|
||||
Char **av;
|
||||
int c, l, n;
|
||||
int specp;
|
||||
|
||||
specp = 0;
|
||||
if (p1 != p2) {
|
||||
p = p1;
|
||||
again:
|
||||
switch (srchx(p->word)) {
|
||||
case T_ELSE:
|
||||
p = p->next;
|
||||
if (p != p2)
|
||||
goto again;
|
||||
break;
|
||||
case T_EXIT:
|
||||
case T_FOREACH:
|
||||
case T_IF:
|
||||
case T_LET:
|
||||
case T_SET:
|
||||
case T_SWITCH:
|
||||
case T_WHILE:
|
||||
specp = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
n = 0;
|
||||
l = 0;
|
||||
for (p = p1; p != p2; p = p->next)
|
||||
switch (p->word[0]) {
|
||||
case '(':
|
||||
if (specp)
|
||||
n++;
|
||||
l++;
|
||||
continue;
|
||||
case ')':
|
||||
if (specp)
|
||||
n++;
|
||||
l--;
|
||||
continue;
|
||||
case '>':
|
||||
case '<':
|
||||
if (l != 0) {
|
||||
if (specp)
|
||||
n++;
|
||||
continue;
|
||||
}
|
||||
if (p->next == p2)
|
||||
continue;
|
||||
if (any(RELPAR, p->next->word[0]))
|
||||
continue;
|
||||
n--;
|
||||
continue;
|
||||
default:
|
||||
if (!specp && l != 0)
|
||||
continue;
|
||||
n++;
|
||||
continue;
|
||||
}
|
||||
if (n < 0)
|
||||
n = 0;
|
||||
t = (struct command *)xcalloc(1, sizeof(*t));
|
||||
av = (Char **)xcalloc((size_t)(n + 1), sizeof(Char **));
|
||||
t->t_dcom = av;
|
||||
n = 0;
|
||||
if (p2->word[0] == ')')
|
||||
t->t_dflg = F_NOFORK;
|
||||
lp = 0;
|
||||
rp = 0;
|
||||
l = 0;
|
||||
for (p = p1; p != p2; p = p->next) {
|
||||
c = p->word[0];
|
||||
switch (c) {
|
||||
case '(':
|
||||
if (l == 0) {
|
||||
if (lp != 0 && !specp)
|
||||
seterror(ERR_BADPLP);
|
||||
lp = p->next;
|
||||
}
|
||||
l++;
|
||||
goto savep;
|
||||
case ')':
|
||||
l--;
|
||||
if (l == 0)
|
||||
rp = p;
|
||||
goto savep;
|
||||
case '>':
|
||||
if (l != 0)
|
||||
goto savep;
|
||||
if (p->word[1] == '>')
|
||||
t->t_dflg |= F_APPEND;
|
||||
if (p->next != p2 && eq(p->next->word, STRand)) {
|
||||
t->t_dflg |= F_STDERR, p = p->next;
|
||||
if (flags & (POUT | PERR)) {
|
||||
seterror(ERR_OUTRED);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (p->next != p2 && eq(p->next->word, STRbang))
|
||||
t->t_dflg |= F_OVERWRITE, p = p->next;
|
||||
if (p->next == p2) {
|
||||
seterror(ERR_MISRED);
|
||||
continue;
|
||||
}
|
||||
p = p->next;
|
||||
if (any(RELPAR, p->word[0])) {
|
||||
seterror(ERR_MISRED);
|
||||
continue;
|
||||
}
|
||||
if ((flags & POUT) && ((flags & PERR) == 0 || t->t_drit))
|
||||
seterror(ERR_OUTRED);
|
||||
else
|
||||
t->t_drit = Strsave(p->word);
|
||||
continue;
|
||||
case '<':
|
||||
if (l != 0)
|
||||
goto savep;
|
||||
if (p->word[1] == '<')
|
||||
t->t_dflg |= F_READ;
|
||||
if (p->next == p2) {
|
||||
seterror(ERR_MISRED);
|
||||
continue;
|
||||
}
|
||||
p = p->next;
|
||||
if (any(RELPAR, p->word[0])) {
|
||||
seterror(ERR_MISRED);
|
||||
continue;
|
||||
}
|
||||
if ((flags & PHERE) && (t->t_dflg & F_READ))
|
||||
seterror(ERR_REDPAR);
|
||||
else if ((flags & PIN) || t->t_dlef)
|
||||
seterror(ERR_INRED);
|
||||
else
|
||||
t->t_dlef = Strsave(p->word);
|
||||
continue;
|
||||
savep:
|
||||
if (!specp)
|
||||
continue;
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
if (l != 0 && !specp)
|
||||
continue;
|
||||
if (seterr == 0)
|
||||
av[n] = Strsave(p->word);
|
||||
n++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (lp != 0 && !specp) {
|
||||
if (n != 0)
|
||||
seterror(ERR_BADPLPS);
|
||||
t->t_dtyp = NODE_PAREN;
|
||||
t->t_dspr = syn0(lp, rp, PHERE);
|
||||
}
|
||||
else {
|
||||
if (n == 0)
|
||||
seterror(ERR_NULLCOM);
|
||||
t->t_dtyp = NODE_COMMAND;
|
||||
}
|
||||
return (t);
|
||||
}
|
||||
|
||||
void
|
||||
freesyn(struct command *t)
|
||||
{
|
||||
Char **v;
|
||||
|
||||
if (t == 0)
|
||||
return;
|
||||
switch (t->t_dtyp) {
|
||||
case NODE_COMMAND:
|
||||
for (v = t->t_dcom; *v; v++)
|
||||
xfree((ptr_t) * v);
|
||||
xfree((ptr_t)(t->t_dcom));
|
||||
xfree((ptr_t)t->t_dlef);
|
||||
xfree((ptr_t)t->t_drit);
|
||||
break;
|
||||
case NODE_PAREN:
|
||||
freesyn(t->t_dspr);
|
||||
xfree((ptr_t)t->t_dlef);
|
||||
xfree((ptr_t)t->t_drit);
|
||||
break;
|
||||
case NODE_AND:
|
||||
case NODE_OR:
|
||||
case NODE_PIPE:
|
||||
case NODE_LIST:
|
||||
freesyn(t->t_dcar), freesyn(t->t_dcdr);
|
||||
break;
|
||||
}
|
||||
xfree((ptr_t)t);
|
||||
}
|
44
bin/csh/pathnames.h
Normal file
44
bin/csh/pathnames.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
/* $NetBSD: pathnames.h,v 1.8 2003/08/07 09:05:06 agc Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1988, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)pathnames.h 8.1 (Berkeley) 5/31/93
|
||||
*/
|
||||
|
||||
#ifndef _PATHNAMES_H_
|
||||
#define _PATHNAMES_H_
|
||||
|
||||
#define _PATH_BIN "/bin"
|
||||
#define _PATH_DOTCSHRC "/etc/csh.cshrc"
|
||||
#define _PATH_DOTLOGIN "/etc/csh.login"
|
||||
#define _PATH_DOTLOGOUT "/etc/csh.logout"
|
||||
#define _PATH_LOGIN "/usr/bin/login"
|
||||
#define _PATH_USRBIN "/usr/bin"
|
||||
|
||||
#endif /* !_PATHNAMES_H_ */
|
1359
bin/csh/proc.c
Normal file
1359
bin/csh/proc.c
Normal file
File diff suppressed because it is too large
Load diff
104
bin/csh/proc.h
Normal file
104
bin/csh/proc.h
Normal file
|
@ -0,0 +1,104 @@
|
|||
/* $NetBSD: proc.h,v 1.14 2013/07/16 17:47:43 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1980, 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)proc.h 8.1 (Berkeley) 5/31/93
|
||||
*/
|
||||
|
||||
#ifndef _PROC_H_
|
||||
#define _PROC_H_
|
||||
|
||||
/*
|
||||
* Structure for each process the shell knows about:
|
||||
* allocated and filled by pcreate.
|
||||
* flushed by pflush; freeing always happens at top level
|
||||
* so the interrupt level has less to worry about.
|
||||
* processes are related to "friends" when in a pipeline;
|
||||
* p_friends links makes a circular list of such jobs
|
||||
*/
|
||||
struct process {
|
||||
struct process *p_next; /* next in global "proclist" */
|
||||
struct process *p_friends; /* next in job list (or self) */
|
||||
struct directory *p_cwd; /* cwd of the job (only in head) */
|
||||
int p_flags; /* various job status flags */
|
||||
int p_reason; /* reason for entering this state */
|
||||
int p_index; /* shorthand job index */
|
||||
pid_t p_pid;
|
||||
pid_t p_jobid; /* pid of job leader */
|
||||
/* if a job is stopped/background p_jobid gives its pgrp */
|
||||
struct timespec p_btime; /* begin time */
|
||||
struct timespec p_etime; /* end time */
|
||||
struct rusage p_rusage;
|
||||
Char *p_command; /* first PMAXLEN chars of command */
|
||||
};
|
||||
|
||||
/* flag values for p_flags */
|
||||
#define PRUNNING (1<<0) /* running */
|
||||
#define PSTOPPED (1<<1) /* stopped */
|
||||
#define PNEXITED (1<<2) /* normally exited */
|
||||
#define PAEXITED (1<<3) /* abnormally exited */
|
||||
#define PSIGNALED (1<<4) /* terminated by a signal != SIGINT */
|
||||
#define PNOTIFY (1<<5) /* notify async when done */
|
||||
#define PTIME (1<<6) /* job times should be printed */
|
||||
#define PAWAITED (1<<7) /* top level is waiting for it */
|
||||
#define PFOREGND (1<<8) /* started in shells pgrp */
|
||||
#define PDUMPED (1<<9) /* process dumped core */
|
||||
#define PERR (1<<10) /* diagnostic output also piped out */
|
||||
#define PPOU (1<<11) /* piped output */
|
||||
#define PREPORTED (1<<12) /* status has been reported */
|
||||
#define PINTERRUPTED (1<<13) /* job stopped via interrupt signal */
|
||||
#define PPTIME (1<<14) /* time individual process */
|
||||
#define PNEEDNOTE (1<<15) /* notify as soon as practical */
|
||||
|
||||
#define PALLSTATES (PRUNNING|PSTOPPED|PNEXITED|PAEXITED|PSIGNALED|PINTERRUPTED)
|
||||
|
||||
#define PMAXLEN 80
|
||||
|
||||
/* defines for arguments to pprint */
|
||||
#define NUMBER 01
|
||||
#define NAME 02
|
||||
#define REASON 04
|
||||
#define AMPERSAND 010
|
||||
#define FANCY 020
|
||||
#define SHELLDIR 040 /* print shell's dir if not the same */
|
||||
#define JOBDIR 0100 /* print job's dir if not the same */
|
||||
#define AREASON 0200
|
||||
|
||||
struct process proclist; /* list head of all processes */
|
||||
int pnoprocesses; /* pchild found nothing to wait for */
|
||||
|
||||
struct process *pholdjob; /* one level stack of current jobs */
|
||||
|
||||
struct process *pcurrjob; /* current job */
|
||||
struct process *pcurrent; /* current job in table */
|
||||
struct process *pprevious; /* previous job in table */
|
||||
|
||||
int pmaxindex; /* current maximum job index */
|
||||
|
||||
#endif /* !_PROC_H_ */
|
646
bin/csh/sem.c
Normal file
646
bin/csh/sem.c
Normal file
|
@ -0,0 +1,646 @@
|
|||
/* $NetBSD: sem.c,v 1.29 2011/08/29 14:51:17 joerg Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1980, 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)sem.c 8.1 (Berkeley) 5/31/93";
|
||||
#else
|
||||
__RCSID("$NetBSD: sem.c,v 1.29 2011/08/29 14:51:17 joerg Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "csh.h"
|
||||
#include "extern.h"
|
||||
#include "proc.h"
|
||||
|
||||
__dead static void vffree(int);
|
||||
static Char *splicepipe(struct command *t, Char *);
|
||||
static void doio(struct command *t, int *, int *);
|
||||
static void chkclob(char *);
|
||||
|
||||
void
|
||||
execute(struct command *t, int wtty, int *pipein, int *pipeout)
|
||||
{
|
||||
static sigset_t csigset, ocsigset;
|
||||
static int nosigchld = 0, onosigchld = 0;
|
||||
volatile int wanttty = wtty;
|
||||
struct biltins * volatile bifunc;
|
||||
int pv[2], pid;
|
||||
sigset_t nsigset;
|
||||
int forked;
|
||||
|
||||
UNREGISTER(forked);
|
||||
UNREGISTER(bifunc);
|
||||
UNREGISTER(wanttty);
|
||||
|
||||
forked = 0;
|
||||
pid = 0;
|
||||
|
||||
if (t == 0)
|
||||
return;
|
||||
|
||||
if (t->t_dflg & F_AMPERSAND)
|
||||
wanttty = 0;
|
||||
switch (t->t_dtyp) {
|
||||
case NODE_COMMAND:
|
||||
if ((t->t_dcom[0][0] & (QUOTE | TRIM)) == QUOTE)
|
||||
(void)Strcpy(t->t_dcom[0], t->t_dcom[0] + 1);
|
||||
if ((t->t_dflg & F_REPEAT) == 0)
|
||||
Dfix(t); /* $ " ' \ */
|
||||
if (t->t_dcom[0] == 0)
|
||||
return;
|
||||
/* FALLTHROUGH */
|
||||
case NODE_PAREN:
|
||||
if (t->t_dflg & F_PIPEOUT)
|
||||
mypipe(pipeout);
|
||||
/*
|
||||
* Must do << early so parent will know where input pointer should be.
|
||||
* If noexec then this is all we do.
|
||||
*/
|
||||
if (t->t_dflg & F_READ) {
|
||||
(void)close(0);
|
||||
heredoc(t->t_dlef);
|
||||
if (noexec)
|
||||
(void)close(0);
|
||||
}
|
||||
|
||||
set(STRstatus, Strsave(STR0));
|
||||
|
||||
/*
|
||||
* This mess is the necessary kludge to handle the prefix builtins:
|
||||
* nice, nohup, time. These commands can also be used by themselves,
|
||||
* and this is not handled here. This will also work when loops are
|
||||
* parsed.
|
||||
*/
|
||||
while (t->t_dtyp == NODE_COMMAND)
|
||||
if (eq(t->t_dcom[0], STRnice)) {
|
||||
if (t->t_dcom[1]) {
|
||||
if (strchr("+-", t->t_dcom[1][0])) {
|
||||
if (t->t_dcom[2]) {
|
||||
setname("nice");
|
||||
t->t_nice =
|
||||
getn(t->t_dcom[1]);
|
||||
lshift(t->t_dcom, 2);
|
||||
t->t_dflg |= F_NICE;
|
||||
}
|
||||
else
|
||||
break;
|
||||
} else {
|
||||
t->t_nice = 4;
|
||||
lshift(t->t_dcom, 1);
|
||||
t->t_dflg |= F_NICE;
|
||||
}
|
||||
} else
|
||||
break;
|
||||
} else if (eq(t->t_dcom[0], STRnohup)) {
|
||||
if (t->t_dcom[1]) {
|
||||
t->t_dflg |= F_NOHUP;
|
||||
lshift(t->t_dcom, 1);
|
||||
}
|
||||
else
|
||||
break;
|
||||
} else if (eq(t->t_dcom[0], STRtime)) {
|
||||
if (t->t_dcom[1]) {
|
||||
t->t_dflg |= F_TIME;
|
||||
lshift(t->t_dcom, 1);
|
||||
}
|
||||
else
|
||||
break;
|
||||
} else
|
||||
break;
|
||||
|
||||
/* is it a command */
|
||||
if (t->t_dtyp == NODE_COMMAND) {
|
||||
/*
|
||||
* Check if we have a builtin function and remember which one.
|
||||
*/
|
||||
bifunc = isbfunc(t);
|
||||
if (noexec && bifunc != NULL) {
|
||||
/*
|
||||
* Continue for builtins that are part of the scripting language
|
||||
*/
|
||||
if (bifunc->bfunct != dobreak && bifunc->bfunct != docontin &&
|
||||
bifunc->bfunct != doelse && bifunc->bfunct != doend &&
|
||||
bifunc->bfunct != doforeach && bifunc->bfunct != dogoto &&
|
||||
bifunc->bfunct != doif && bifunc->bfunct != dorepeat &&
|
||||
bifunc->bfunct != doswbrk && bifunc->bfunct != doswitch &&
|
||||
bifunc->bfunct != dowhile && bifunc->bfunct != dozip)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else { /* not a command */
|
||||
bifunc = NULL;
|
||||
if (noexec)
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* We fork only if we are timed, or are not the end of a parenthesized
|
||||
* list and not a simple builtin function. Simple meaning one that is
|
||||
* not pipedout, niced, nohupped, or &'d. It would be nice(?) to not
|
||||
* fork in some of these cases.
|
||||
*/
|
||||
/*
|
||||
* Prevent forking cd, pushd, popd, chdir cause this will cause the
|
||||
* shell not to change dir!
|
||||
*/
|
||||
if (bifunc && (bifunc->bfunct == dochngd ||
|
||||
bifunc->bfunct == dopushd ||
|
||||
bifunc->bfunct == dopopd))
|
||||
t->t_dflg &= ~(F_NICE);
|
||||
if (((t->t_dflg & F_TIME) || ((t->t_dflg & F_NOFORK) == 0 &&
|
||||
(!bifunc || t->t_dflg &
|
||||
(F_PIPEOUT | F_AMPERSAND | F_NICE | F_NOHUP)))) ||
|
||||
/*
|
||||
* We have to fork for eval too.
|
||||
*/
|
||||
(bifunc && (t->t_dflg & (F_PIPEIN | F_PIPEOUT)) != 0 &&
|
||||
bifunc->bfunct == doeval)) {
|
||||
if (t->t_dtyp == NODE_PAREN ||
|
||||
t->t_dflg & (F_REPEAT | F_AMPERSAND) || bifunc) {
|
||||
forked++;
|
||||
/*
|
||||
* We need to block SIGCHLD here, so that if the process does
|
||||
* not die before we can set the process group
|
||||
*/
|
||||
if (wanttty >= 0 && !nosigchld) {
|
||||
sigemptyset(&nsigset);
|
||||
(void)sigaddset(&nsigset, SIGCHLD);
|
||||
(void)sigprocmask(SIG_BLOCK, &nsigset, &csigset);
|
||||
nosigchld = 1;
|
||||
}
|
||||
|
||||
pid = pfork(t, wanttty);
|
||||
if (pid == 0 && nosigchld) {
|
||||
(void)sigprocmask(SIG_SETMASK, &csigset, NULL);
|
||||
nosigchld = 0;
|
||||
}
|
||||
else if (pid != 0 && (t->t_dflg & F_AMPERSAND))
|
||||
backpid = pid;
|
||||
|
||||
}
|
||||
else {
|
||||
int ochild, osetintr, ohaderr, odidfds;
|
||||
int oSHIN, oSHOUT, oSHERR, oOLDSTD, otpgrp;
|
||||
sigset_t osigset;
|
||||
|
||||
/*
|
||||
* Prepare for the vfork by saving everything that the child
|
||||
* corrupts before it exec's. Note that in some signal
|
||||
* implementations which keep the signal info in user space
|
||||
* (e.g. Sun's) it will also be necessary to save and restore
|
||||
* the current sigaction's for the signals the child touches
|
||||
* before it exec's.
|
||||
*/
|
||||
if (wanttty >= 0 && !nosigchld && !noexec) {
|
||||
sigemptyset(&nsigset);
|
||||
(void)sigaddset(&nsigset, SIGCHLD);
|
||||
(void)sigprocmask(SIG_BLOCK, &nsigset, &csigset);
|
||||
nosigchld = 1;
|
||||
}
|
||||
sigemptyset(&nsigset);
|
||||
(void)sigaddset(&nsigset, SIGCHLD);
|
||||
(void)sigaddset(&nsigset, SIGINT);
|
||||
(void)sigprocmask(SIG_BLOCK, &nsigset, &osigset);
|
||||
ochild = child;
|
||||
osetintr = setintr;
|
||||
ohaderr = haderr;
|
||||
odidfds = didfds;
|
||||
oSHIN = SHIN;
|
||||
oSHOUT = SHOUT;
|
||||
oSHERR = SHERR;
|
||||
oOLDSTD = OLDSTD;
|
||||
otpgrp = tpgrp;
|
||||
ocsigset = csigset;
|
||||
onosigchld = nosigchld;
|
||||
Vsav = Vdp = 0;
|
||||
Vexpath = 0;
|
||||
Vt = 0;
|
||||
pid = vfork();
|
||||
|
||||
if (pid < 0) {
|
||||
(void)sigprocmask(SIG_SETMASK, &osigset, NULL);
|
||||
stderror(ERR_NOPROC);
|
||||
}
|
||||
forked++;
|
||||
if (pid) { /* parent */
|
||||
child = ochild;
|
||||
setintr = osetintr;
|
||||
haderr = ohaderr;
|
||||
didfds = odidfds;
|
||||
SHIN = oSHIN;
|
||||
SHOUT = oSHOUT;
|
||||
SHERR = oSHERR;
|
||||
OLDSTD = oOLDSTD;
|
||||
tpgrp = otpgrp;
|
||||
csigset = ocsigset;
|
||||
nosigchld = onosigchld;
|
||||
|
||||
xfree((ptr_t) Vsav);
|
||||
Vsav = 0;
|
||||
xfree((ptr_t) Vdp);
|
||||
Vdp = 0;
|
||||
xfree((ptr_t) Vexpath);
|
||||
Vexpath = 0;
|
||||
blkfree((Char **) Vt);
|
||||
Vt = 0;
|
||||
/* this is from pfork() */
|
||||
palloc(pid, t);
|
||||
(void)sigprocmask(SIG_SETMASK, &osigset, NULL);
|
||||
}
|
||||
else { /* child */
|
||||
/* this is from pfork() */
|
||||
int pgrp;
|
||||
int ignint = 0;
|
||||
|
||||
if (nosigchld) {
|
||||
(void)sigprocmask(SIG_SETMASK, &csigset, NULL);
|
||||
nosigchld = 0;
|
||||
}
|
||||
|
||||
if (setintr)
|
||||
ignint =
|
||||
(tpgrp == -1 &&
|
||||
(t->t_dflg & F_NOINTERRUPT))
|
||||
|| (gointr && eq(gointr, STRminus));
|
||||
pgrp = pcurrjob ? pcurrjob->p_jobid : getpid();
|
||||
child++;
|
||||
if (setintr) {
|
||||
setintr = 0;
|
||||
if (ignint) {
|
||||
(void)signal(SIGINT, SIG_IGN);
|
||||
(void)signal(SIGQUIT, SIG_IGN);
|
||||
}
|
||||
else {
|
||||
(void)signal(SIGINT, vffree);
|
||||
(void)signal(SIGQUIT, SIG_DFL);
|
||||
}
|
||||
|
||||
if (wanttty >= 0) {
|
||||
(void)signal(SIGTSTP, SIG_DFL);
|
||||
(void)signal(SIGTTIN, SIG_DFL);
|
||||
(void)signal(SIGTTOU, SIG_DFL);
|
||||
}
|
||||
|
||||
(void)signal(SIGTERM, parterm);
|
||||
}
|
||||
else if (tpgrp == -1 &&
|
||||
(t->t_dflg & F_NOINTERRUPT)) {
|
||||
(void)signal(SIGINT, SIG_IGN);
|
||||
(void)signal(SIGQUIT, SIG_IGN);
|
||||
}
|
||||
|
||||
pgetty(wanttty, pgrp);
|
||||
if (t->t_dflg & F_NOHUP)
|
||||
(void)signal(SIGHUP, SIG_IGN);
|
||||
if (t->t_dflg & F_NICE)
|
||||
(void)setpriority(PRIO_PROCESS, 0, t->t_nice);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (pid != 0) {
|
||||
/*
|
||||
* It would be better if we could wait for the whole job when we
|
||||
* knew the last process had been started. Pwait, in fact, does
|
||||
* wait for the whole job anyway, but this test doesn't really
|
||||
* express our intentions.
|
||||
*/
|
||||
if (didfds == 0 && t->t_dflg & F_PIPEIN) {
|
||||
(void)close(pipein[0]);
|
||||
(void)close(pipein[1]);
|
||||
}
|
||||
if ((t->t_dflg & F_PIPEOUT) == 0) {
|
||||
if (nosigchld) {
|
||||
(void)sigprocmask(SIG_SETMASK, &csigset, NULL);
|
||||
nosigchld = 0;
|
||||
}
|
||||
if ((t->t_dflg & F_AMPERSAND) == 0)
|
||||
pwait();
|
||||
}
|
||||
break;
|
||||
}
|
||||
doio(t, pipein, pipeout);
|
||||
if (t->t_dflg & F_PIPEOUT) {
|
||||
(void)close(pipeout[0]);
|
||||
(void)close(pipeout[1]);
|
||||
}
|
||||
/*
|
||||
* Perform a builtin function. If we are not forked, arrange for
|
||||
* possible stopping
|
||||
*/
|
||||
if (bifunc) {
|
||||
func(t, bifunc);
|
||||
if (forked)
|
||||
exitstat();
|
||||
break;
|
||||
}
|
||||
if (t->t_dtyp != NODE_PAREN)
|
||||
doexec(NULL, t);
|
||||
/*
|
||||
* For () commands must put new 0,1,2 in FSH* and recurse
|
||||
*/
|
||||
(void) ioctl(OLDSTD = dcopy(0, FOLDSTD), FIOCLEX, NULL);
|
||||
(void) ioctl(SHOUT = dcopy(1, FSHOUT), FIOCLEX, NULL);
|
||||
(void) ioctl(SHERR = dcopy(2, FSHERR), FIOCLEX, NULL);
|
||||
(void) close(SHIN);
|
||||
|
||||
SHIN = -1;
|
||||
didfds = 0;
|
||||
wanttty = -1;
|
||||
t->t_dspr->t_dflg |= t->t_dflg & F_NOINTERRUPT;
|
||||
execute(t->t_dspr, wanttty, NULL, NULL);
|
||||
exitstat();
|
||||
/* NOTREACHED */
|
||||
case NODE_PIPE:
|
||||
t->t_dcar->t_dflg |= F_PIPEOUT |
|
||||
(t->t_dflg & (F_PIPEIN | F_AMPERSAND | F_STDERR | F_NOINTERRUPT));
|
||||
execute(t->t_dcar, wanttty, pipein, pv);
|
||||
t->t_dcdr->t_dflg |= F_PIPEIN | (t->t_dflg &
|
||||
(F_PIPEOUT | F_AMPERSAND | F_NOFORK | F_NOINTERRUPT));
|
||||
if (wanttty > 0)
|
||||
wanttty = 0; /* got tty already */
|
||||
execute(t->t_dcdr, wanttty, pv, pipeout);
|
||||
break;
|
||||
case NODE_LIST:
|
||||
if (t->t_dcar) {
|
||||
t->t_dcar->t_dflg |= t->t_dflg & F_NOINTERRUPT;
|
||||
execute(t->t_dcar, wanttty, NULL, NULL);
|
||||
/*
|
||||
* In strange case of A&B make a new job after A
|
||||
*/
|
||||
if (t->t_dcar->t_dflg & F_AMPERSAND && t->t_dcdr &&
|
||||
(t->t_dcdr->t_dflg & F_AMPERSAND) == 0)
|
||||
pendjob();
|
||||
}
|
||||
if (t->t_dcdr) {
|
||||
t->t_dcdr->t_dflg |= t->t_dflg &
|
||||
(F_NOFORK | F_NOINTERRUPT);
|
||||
execute(t->t_dcdr, wanttty, NULL, NULL);
|
||||
}
|
||||
break;
|
||||
case NODE_OR:
|
||||
case NODE_AND:
|
||||
if (t->t_dcar) {
|
||||
t->t_dcar->t_dflg |= t->t_dflg & F_NOINTERRUPT;
|
||||
execute(t->t_dcar, wanttty, NULL, NULL);
|
||||
if ((getn(value(STRstatus)) == 0) !=
|
||||
(t->t_dtyp == NODE_AND))
|
||||
return;
|
||||
}
|
||||
if (t->t_dcdr) {
|
||||
t->t_dcdr->t_dflg |= t->t_dflg &
|
||||
(F_NOFORK | F_NOINTERRUPT);
|
||||
execute(t->t_dcdr, wanttty, NULL, NULL);
|
||||
}
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Fall through for all breaks from switch
|
||||
*
|
||||
* If there will be no more executions of this command, flush all file
|
||||
* descriptors. Places that turn on the F_REPEAT bit are responsible for
|
||||
* doing donefds after the last re-execution
|
||||
*/
|
||||
if (didfds && !(t->t_dflg & F_REPEAT))
|
||||
donefds();
|
||||
}
|
||||
|
||||
static void
|
||||
vffree(int i)
|
||||
{
|
||||
Char **v;
|
||||
|
||||
if ((v = gargv) != NULL) {
|
||||
gargv = 0;
|
||||
xfree((ptr_t) v);
|
||||
}
|
||||
if ((v = pargv) != NULL) {
|
||||
pargv = 0;
|
||||
xfree((ptr_t) v);
|
||||
}
|
||||
_exit(i);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/*
|
||||
* Expand and glob the words after an i/o redirection.
|
||||
* If more than one word is generated, then update the command vector.
|
||||
*
|
||||
* This is done differently in all the shells:
|
||||
* 1. in the bourne shell and ksh globbing is not performed
|
||||
* 2. Bash/csh say ambiguous
|
||||
* 3. zsh does i/o to/from all the files
|
||||
* 4. itcsh concatenates the words.
|
||||
*
|
||||
* I don't know what is best to do. I think that Ambiguous is better
|
||||
* than restructuring the command vector, because the user can get
|
||||
* unexpected results. In any case, the command vector restructuring
|
||||
* code is present and the user can choose it by setting noambiguous
|
||||
*/
|
||||
static Char *
|
||||
splicepipe(struct command *t, Char *cp /* word after < or > */)
|
||||
{
|
||||
Char *blk[2];
|
||||
|
||||
if (adrof(STRnoambiguous)) {
|
||||
Char **pv;
|
||||
|
||||
blk[0] = Dfix1(cp); /* expand $ */
|
||||
blk[1] = NULL;
|
||||
|
||||
gflag = 0, tglob(blk);
|
||||
if (gflag) {
|
||||
pv = globall(blk);
|
||||
if (pv == NULL) {
|
||||
setname(vis_str(blk[0]));
|
||||
xfree((ptr_t) blk[0]);
|
||||
stderror(ERR_NAME | ERR_NOMATCH);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
gargv = NULL;
|
||||
if (pv[1] != NULL) { /* we need to fix the command vector */
|
||||
Char **av = blkspl(t->t_dcom, &pv[1]);
|
||||
xfree((ptr_t) t->t_dcom);
|
||||
t->t_dcom = av;
|
||||
}
|
||||
xfree((ptr_t) blk[0]);
|
||||
blk[0] = pv[0];
|
||||
xfree((ptr_t) pv);
|
||||
}
|
||||
}
|
||||
else {
|
||||
blk[0] = globone(blk[1] = Dfix1(cp), G_ERROR);
|
||||
xfree((ptr_t) blk[1]);
|
||||
}
|
||||
return(blk[0]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform io redirection.
|
||||
* We may or maynot be forked here.
|
||||
*/
|
||||
static void
|
||||
doio(struct command *t, int *pipein, int *pipeout)
|
||||
{
|
||||
Char *cp;
|
||||
int fd, flags;
|
||||
|
||||
flags = t->t_dflg;
|
||||
if (didfds || (flags & F_REPEAT))
|
||||
return;
|
||||
if ((flags & F_READ) == 0) {/* F_READ already done */
|
||||
if (t->t_dlef) {
|
||||
char tmp[MAXPATHLEN+1];
|
||||
|
||||
/*
|
||||
* so < /dev/std{in,out,err} work
|
||||
*/
|
||||
(void)dcopy(SHIN, 0);
|
||||
(void)dcopy(SHOUT, 1);
|
||||
(void)dcopy(SHERR, 2);
|
||||
cp = splicepipe(t, t->t_dlef);
|
||||
(void)strlcpy(tmp, short2str(cp), sizeof(tmp));
|
||||
xfree((ptr_t) cp);
|
||||
if ((fd = open(tmp, O_RDONLY)) < 0) {
|
||||
stderror(ERR_SYSTEM, tmp, strerror(errno));
|
||||
/* NOTREACHED */
|
||||
}
|
||||
(void)dmove(fd, 0);
|
||||
}
|
||||
else if (flags & F_PIPEIN) {
|
||||
(void)close(0);
|
||||
(void)dup(pipein[0]);
|
||||
(void)close(pipein[0]);
|
||||
(void)close(pipein[1]);
|
||||
}
|
||||
else if ((flags & F_NOINTERRUPT) && tpgrp == -1) {
|
||||
(void)close(0);
|
||||
(void)open(_PATH_DEVNULL, O_RDONLY);
|
||||
}
|
||||
else {
|
||||
(void)close(0);
|
||||
(void)dup(OLDSTD);
|
||||
(void)ioctl(0, FIONCLEX, NULL);
|
||||
}
|
||||
}
|
||||
if (t->t_drit) {
|
||||
char tmp[MAXPATHLEN+1];
|
||||
|
||||
cp = splicepipe(t, t->t_drit);
|
||||
(void)strlcpy(tmp, short2str(cp), sizeof(tmp));
|
||||
xfree((ptr_t) cp);
|
||||
/*
|
||||
* so > /dev/std{out,err} work
|
||||
*/
|
||||
(void)dcopy(SHOUT, 1);
|
||||
(void)dcopy(SHERR, 2);
|
||||
if ((flags & F_APPEND) &&
|
||||
#ifdef O_APPEND
|
||||
(fd = open(tmp, O_WRONLY | O_APPEND)) >= 0);
|
||||
#else
|
||||
(fd = open(tmp, O_WRONLY)) >= 0)
|
||||
(void)lseek(1, (off_t) 0, SEEK_END);
|
||||
#endif
|
||||
else {
|
||||
if (!(flags & F_OVERWRITE) && adrof(STRnoclobber)) {
|
||||
if (flags & F_APPEND) {
|
||||
stderror(ERR_SYSTEM, tmp, strerror(errno));
|
||||
/* NOTREACHED */
|
||||
}
|
||||
chkclob(tmp);
|
||||
}
|
||||
if ((fd = open(tmp, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) {
|
||||
stderror(ERR_SYSTEM, tmp, strerror(errno));
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
(void)dmove(fd, 1);
|
||||
}
|
||||
else if (flags & F_PIPEOUT) {
|
||||
(void)close(1);
|
||||
(void)dup(pipeout[1]);
|
||||
}
|
||||
else {
|
||||
(void)close(1);
|
||||
(void)dup(SHOUT);
|
||||
(void)ioctl(1, FIONCLEX, NULL);
|
||||
}
|
||||
|
||||
(void)close(2);
|
||||
if (flags & F_STDERR) {
|
||||
(void)dup(1);
|
||||
}
|
||||
else {
|
||||
(void)dup(SHERR);
|
||||
(void)ioctl(2, FIONCLEX, NULL);
|
||||
}
|
||||
didfds = 1;
|
||||
}
|
||||
|
||||
void
|
||||
mypipe(int *pv)
|
||||
{
|
||||
if (pipe(pv) < 0)
|
||||
goto oops;
|
||||
pv[0] = dmove(pv[0], -1);
|
||||
pv[1] = dmove(pv[1], -1);
|
||||
if (pv[0] >= 0 && pv[1] >= 0)
|
||||
return;
|
||||
oops:
|
||||
stderror(ERR_PIPE);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
static void
|
||||
chkclob(char *cp)
|
||||
{
|
||||
struct stat stb;
|
||||
|
||||
if (stat(cp, &stb) < 0)
|
||||
return;
|
||||
if (S_ISCHR(stb.st_mode))
|
||||
return;
|
||||
stderror(ERR_EXISTS, cp);
|
||||
/* NOTREACHED */
|
||||
}
|
820
bin/csh/set.c
Normal file
820
bin/csh/set.c
Normal file
|
@ -0,0 +1,820 @@
|
|||
/* $NetBSD: set.c,v 1.33 2013/07/16 17:47:43 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1980, 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)set.c 8.1 (Berkeley) 5/31/93";
|
||||
#else
|
||||
__RCSID("$NetBSD: set.c,v 1.33 2013/07/16 17:47:43 christos Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef SHORT_STRINGS
|
||||
#include <string.h>
|
||||
#endif /* SHORT_STRINGS */
|
||||
|
||||
#include "csh.h"
|
||||
#include "extern.h"
|
||||
|
||||
static Char *getinx(Char *, int *);
|
||||
static void asx(Char *, int, Char *);
|
||||
static struct varent *getvx(Char *, int);
|
||||
static Char *xset(Char *, Char ***);
|
||||
static Char *operate(int, Char *, Char *);
|
||||
static void putn1(int);
|
||||
static struct varent *madrof(Char *, struct varent *);
|
||||
static void unsetv1(struct varent *);
|
||||
static void exportpath(Char **);
|
||||
static void balance(struct varent *, int, int);
|
||||
|
||||
/*
|
||||
* C Shell
|
||||
*/
|
||||
|
||||
static void
|
||||
update_vars(Char *vp)
|
||||
{
|
||||
if (eq(vp, STRpath)) {
|
||||
struct varent *pt = adrof(STRpath);
|
||||
if (pt == NULL)
|
||||
stderror(ERR_NAME | ERR_UNDVAR);
|
||||
else {
|
||||
exportpath(pt->vec);
|
||||
dohash(NULL, NULL);
|
||||
}
|
||||
}
|
||||
else if (eq(vp, STRhistchars)) {
|
||||
Char *pn = value(STRhistchars);
|
||||
|
||||
HIST = *pn++;
|
||||
HISTSUB = *pn;
|
||||
}
|
||||
else if (eq(vp, STRuser)) {
|
||||
Setenv(STRUSER, value(vp));
|
||||
Setenv(STRLOGNAME, value(vp));
|
||||
}
|
||||
else if (eq(vp, STRwordchars)) {
|
||||
word_chars = value(vp);
|
||||
}
|
||||
else if (eq(vp, STRterm))
|
||||
Setenv(STRTERM, value(vp));
|
||||
else if (eq(vp, STRhome)) {
|
||||
Char *cp;
|
||||
|
||||
cp = Strsave(value(vp)); /* get the old value back */
|
||||
|
||||
/*
|
||||
* convert to canonical pathname (possibly resolving symlinks)
|
||||
*/
|
||||
cp = dcanon(cp, cp);
|
||||
|
||||
set(vp, Strsave(cp)); /* have to save the new val */
|
||||
|
||||
/* and now mirror home with HOME */
|
||||
Setenv(STRHOME, cp);
|
||||
/* fix directory stack for new tilde home */
|
||||
dtilde();
|
||||
xfree((ptr_t)cp);
|
||||
}
|
||||
#ifdef FILEC
|
||||
else if (eq(vp, STRfilec))
|
||||
filec = 1;
|
||||
#endif
|
||||
#ifdef EDIT
|
||||
else if (eq(vp, STRedit)) {
|
||||
HistEvent ev;
|
||||
editing = 1;
|
||||
el = el_init_fd(getprogname(), cshin, cshout, csherr,
|
||||
SHIN, SHOUT, SHERR);
|
||||
el_set(el, EL_EDITOR, "emacs");
|
||||
el_set(el, EL_PROMPT, printpromptstr);
|
||||
hi = history_init();
|
||||
history(hi, &ev, H_SETSIZE, getn(value(STRhistory)));
|
||||
loadhist(Histlist.Hnext);
|
||||
el_set(el, EL_HIST, history, hi);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
/*ARGSUSED*/
|
||||
doset(Char **v, struct command *t)
|
||||
{
|
||||
Char op, *p, **vecp, *vp;
|
||||
int subscr = 0; /* XXX: GCC */
|
||||
int hadsub;
|
||||
|
||||
v++;
|
||||
p = *v++;
|
||||
if (p == 0) {
|
||||
prvars();
|
||||
return;
|
||||
}
|
||||
do {
|
||||
hadsub = 0;
|
||||
vp = p;
|
||||
if (letter(*p))
|
||||
for (; alnum(*p); p++)
|
||||
continue;
|
||||
if (vp == p || !letter(*vp))
|
||||
stderror(ERR_NAME | ERR_VARBEGIN);
|
||||
if ((p - vp) > MAXVARLEN)
|
||||
stderror(ERR_NAME | ERR_VARTOOLONG);
|
||||
if (*p == '[') {
|
||||
hadsub++;
|
||||
p = getinx(p, &subscr);
|
||||
}
|
||||
if ((op = *p) != '\0') {
|
||||
*p++ = 0;
|
||||
if (*p == 0 && *v && **v == '(')
|
||||
p = *v++;
|
||||
}
|
||||
else if (*v && eq(*v, STRequal)) {
|
||||
op = '=', v++;
|
||||
if (*v)
|
||||
p = *v++;
|
||||
}
|
||||
if (op && op != '=')
|
||||
stderror(ERR_NAME | ERR_SYNTAX);
|
||||
if (eq(p, STRLparen)) {
|
||||
Char **e = v;
|
||||
|
||||
if (hadsub)
|
||||
stderror(ERR_NAME | ERR_SYNTAX);
|
||||
for (;;) {
|
||||
if (!*e)
|
||||
stderror(ERR_NAME | ERR_MISSING, ')');
|
||||
if (**e == ')')
|
||||
break;
|
||||
e++;
|
||||
}
|
||||
p = *e;
|
||||
*e = 0;
|
||||
vecp = saveblk(v);
|
||||
set1(vp, vecp, &shvhed);
|
||||
*e = p;
|
||||
v = e + 1;
|
||||
}
|
||||
else if (hadsub)
|
||||
asx(vp, subscr, Strsave(p));
|
||||
else
|
||||
set(vp, Strsave(p));
|
||||
update_vars(vp);
|
||||
} while ((p = *v++) != NULL);
|
||||
}
|
||||
|
||||
static Char *
|
||||
getinx(Char *cp, int *ip)
|
||||
{
|
||||
*ip = 0;
|
||||
*cp++ = 0;
|
||||
while (*cp && Isdigit(*cp))
|
||||
*ip = *ip * 10 + *cp++ - '0';
|
||||
if (*cp++ != ']')
|
||||
stderror(ERR_NAME | ERR_SUBSCRIPT);
|
||||
return (cp);
|
||||
}
|
||||
|
||||
static void
|
||||
asx(Char *vp, int subscr, Char *p)
|
||||
{
|
||||
struct varent *v;
|
||||
|
||||
v = getvx(vp, subscr);
|
||||
xfree((ptr_t) v->vec[subscr - 1]);
|
||||
v->vec[subscr - 1] = globone(p, G_APPEND);
|
||||
}
|
||||
|
||||
static struct varent *
|
||||
getvx(Char *vp, int subscr)
|
||||
{
|
||||
struct varent *v;
|
||||
|
||||
v = adrof(vp);
|
||||
if (v == 0)
|
||||
udvar(vp);
|
||||
if (subscr < 1 || subscr > blklen(v->vec))
|
||||
stderror(ERR_NAME | ERR_RANGE);
|
||||
return (v);
|
||||
}
|
||||
|
||||
void
|
||||
/*ARGSUSED*/
|
||||
dolet(Char **v, struct command *t)
|
||||
{
|
||||
Char c, op, *p, *vp;
|
||||
int subscr = 0; /* XXX: GCC */
|
||||
int hadsub;
|
||||
|
||||
v++;
|
||||
p = *v++;
|
||||
if (p == 0) {
|
||||
prvars();
|
||||
return;
|
||||
}
|
||||
do {
|
||||
hadsub = 0;
|
||||
vp = p;
|
||||
if (letter(*p))
|
||||
for (; alnum(*p); p++)
|
||||
continue;
|
||||
if (vp == p || !letter(*vp))
|
||||
stderror(ERR_NAME | ERR_VARBEGIN);
|
||||
if ((p - vp) > MAXVARLEN)
|
||||
stderror(ERR_NAME | ERR_VARTOOLONG);
|
||||
if (*p == '[') {
|
||||
hadsub++;
|
||||
p = getinx(p, &subscr);
|
||||
}
|
||||
if (*p == 0 && *v)
|
||||
p = *v++;
|
||||
if ((op = *p) != '\0')
|
||||
*p++ = 0;
|
||||
else
|
||||
stderror(ERR_NAME | ERR_ASSIGN);
|
||||
|
||||
if (*p == '\0' && *v == NULL)
|
||||
stderror(ERR_NAME | ERR_ASSIGN);
|
||||
|
||||
vp = Strsave(vp);
|
||||
if (op == '=') {
|
||||
c = '=';
|
||||
p = xset(p, &v);
|
||||
}
|
||||
else {
|
||||
c = *p++;
|
||||
if (any("+-", c)) {
|
||||
if (c != op || *p)
|
||||
stderror(ERR_NAME | ERR_UNKNOWNOP);
|
||||
p = Strsave(STR1);
|
||||
}
|
||||
else {
|
||||
if (any("<>", op)) {
|
||||
if (c != op)
|
||||
stderror(ERR_NAME | ERR_UNKNOWNOP);
|
||||
c = *p++;
|
||||
stderror(ERR_NAME | ERR_SYNTAX);
|
||||
}
|
||||
if (c != '=')
|
||||
stderror(ERR_NAME | ERR_UNKNOWNOP);
|
||||
p = xset(p, &v);
|
||||
}
|
||||
}
|
||||
if (op == '=') {
|
||||
if (hadsub)
|
||||
asx(vp, subscr, p);
|
||||
else
|
||||
set(vp, p);
|
||||
} else if (hadsub) {
|
||||
struct varent *gv = getvx(vp, subscr);
|
||||
|
||||
asx(vp, subscr, operate(op, gv->vec[subscr - 1], p));
|
||||
}
|
||||
else
|
||||
set(vp, operate(op, value(vp), p));
|
||||
if (eq(vp, STRpath)) {
|
||||
struct varent *pt = adrof(STRpath);
|
||||
if (pt == NULL)
|
||||
stderror(ERR_NAME | ERR_UNDVAR);
|
||||
else {
|
||||
exportpath(pt->vec);
|
||||
dohash(NULL, NULL);
|
||||
}
|
||||
}
|
||||
xfree((ptr_t) vp);
|
||||
if (c != '=')
|
||||
xfree((ptr_t) p);
|
||||
} while ((p = *v++) != NULL);
|
||||
}
|
||||
|
||||
static Char *
|
||||
xset(Char *cp, Char ***vp)
|
||||
{
|
||||
Char *dp;
|
||||
|
||||
if (*cp) {
|
||||
dp = Strsave(cp);
|
||||
--(*vp);
|
||||
xfree((ptr_t) ** vp);
|
||||
**vp = dp;
|
||||
}
|
||||
return (putn(expr(vp)));
|
||||
}
|
||||
|
||||
static Char *
|
||||
operate(int op, Char *vp, Char *p)
|
||||
{
|
||||
Char opr[2], **v, *vec[5], **vecp;
|
||||
int i;
|
||||
|
||||
v = vec;
|
||||
vecp = v;
|
||||
if (op != '=') {
|
||||
if (*vp)
|
||||
*v++ = vp;
|
||||
opr[0] = (Char)op;
|
||||
opr[1] = 0;
|
||||
*v++ = opr;
|
||||
if (op == '<' || op == '>')
|
||||
*v++ = opr;
|
||||
}
|
||||
*v++ = p;
|
||||
*v++ = 0;
|
||||
i = expr(&vecp);
|
||||
if (*vecp)
|
||||
stderror(ERR_NAME | ERR_EXPRESSION);
|
||||
return (putn(i));
|
||||
}
|
||||
|
||||
static Char *putp;
|
||||
|
||||
Char *
|
||||
putn(int n)
|
||||
{
|
||||
static Char numbers[15];
|
||||
|
||||
putp = numbers;
|
||||
if (n < 0) {
|
||||
n = -n;
|
||||
*putp++ = '-';
|
||||
}
|
||||
if ((unsigned int)n == 0x80000000U) {
|
||||
*putp++ = '2';
|
||||
n = 147483648;
|
||||
}
|
||||
putn1(n);
|
||||
*putp = 0;
|
||||
return (Strsave(numbers));
|
||||
}
|
||||
|
||||
static void
|
||||
putn1(int n)
|
||||
{
|
||||
if (n > 9)
|
||||
putn1(n / 10);
|
||||
*putp++ = (Char)(n % 10 + '0');
|
||||
}
|
||||
|
||||
int
|
||||
getn(Char *cp)
|
||||
{
|
||||
int n, sign;
|
||||
|
||||
sign = 0;
|
||||
if (cp[0] == '+' && cp[1])
|
||||
cp++;
|
||||
if (*cp == '-') {
|
||||
sign++;
|
||||
cp++;
|
||||
if (!Isdigit(*cp))
|
||||
stderror(ERR_NAME | ERR_BADNUM);
|
||||
}
|
||||
n = 0;
|
||||
while (Isdigit(*cp))
|
||||
n = n * 10 + *cp++ - '0';
|
||||
if (*cp)
|
||||
stderror(ERR_NAME | ERR_BADNUM);
|
||||
return (sign ? -n : n);
|
||||
}
|
||||
|
||||
Char *
|
||||
value1(Char *var, struct varent *head)
|
||||
{
|
||||
struct varent *vp;
|
||||
|
||||
vp = adrof1(var, head);
|
||||
return (vp == 0 || vp->vec[0] == 0 ? STRNULL : vp->vec[0]);
|
||||
}
|
||||
|
||||
static struct varent *
|
||||
madrof(Char *pat, struct varent *vp)
|
||||
{
|
||||
struct varent *vp1;
|
||||
|
||||
for (; vp; vp = vp->v_right) {
|
||||
if (vp->v_left && (vp1 = madrof(pat, vp->v_left)))
|
||||
return vp1;
|
||||
if (Gmatch(vp->v_name, pat))
|
||||
return vp;
|
||||
}
|
||||
return vp;
|
||||
}
|
||||
|
||||
struct varent *
|
||||
adrof1(Char *name, struct varent *v)
|
||||
{
|
||||
int cmp;
|
||||
|
||||
v = v->v_left;
|
||||
while (v && ((cmp = *name - *v->v_name) ||
|
||||
(cmp = Strcmp(name, v->v_name))))
|
||||
if (cmp < 0)
|
||||
v = v->v_left;
|
||||
else
|
||||
v = v->v_right;
|
||||
return v;
|
||||
}
|
||||
|
||||
/*
|
||||
* The caller is responsible for putting value in a safe place
|
||||
*/
|
||||
void
|
||||
set(Char *var, Char *val)
|
||||
{
|
||||
Char **vec;
|
||||
|
||||
vec = xmalloc(2 * sizeof(*vec));
|
||||
vec[0] = val;
|
||||
vec[1] = 0;
|
||||
set1(var, vec, &shvhed);
|
||||
}
|
||||
|
||||
void
|
||||
set1(Char *var, Char **vec, struct varent *head)
|
||||
{
|
||||
Char **oldv;
|
||||
|
||||
oldv = vec;
|
||||
gflag = 0;
|
||||
tglob(oldv);
|
||||
if (gflag) {
|
||||
vec = globall(oldv);
|
||||
if (vec == 0) {
|
||||
blkfree(oldv);
|
||||
stderror(ERR_NAME | ERR_NOMATCH);
|
||||
}
|
||||
blkfree(oldv);
|
||||
gargv = 0;
|
||||
}
|
||||
setq(var, vec, head);
|
||||
}
|
||||
|
||||
void
|
||||
setq(Char *name, Char **vec, struct varent *p)
|
||||
{
|
||||
struct varent *c;
|
||||
int f;
|
||||
|
||||
f = 0; /* tree hangs off the header's left link */
|
||||
while ((c = p->v_link[f]) != NULL) {
|
||||
if ((f = *name - *c->v_name) == 0 &&
|
||||
(f = Strcmp(name, c->v_name)) == 0) {
|
||||
blkfree(c->vec);
|
||||
goto found;
|
||||
}
|
||||
p = c;
|
||||
f = f > 0;
|
||||
}
|
||||
p->v_link[f] = c = xmalloc(sizeof(*c));
|
||||
c->v_name = Strsave(name);
|
||||
c->v_bal = 0;
|
||||
c->v_left = c->v_right = 0;
|
||||
c->v_parent = p;
|
||||
balance(p, f, 0);
|
||||
found:
|
||||
trim(c->vec = vec);
|
||||
}
|
||||
|
||||
void
|
||||
/*ARGSUSED*/
|
||||
unset(Char **v, struct command *t)
|
||||
{
|
||||
unset1(v, &shvhed);
|
||||
if (adrof(STRhistchars) == 0) {
|
||||
HIST = '!';
|
||||
HISTSUB = '^';
|
||||
}
|
||||
else if (adrof(STRwordchars) == 0)
|
||||
word_chars = STR_WORD_CHARS;
|
||||
#ifdef FILEC
|
||||
else if (adrof(STRfilec) == 0)
|
||||
filec = 0;
|
||||
#endif
|
||||
#ifdef EDIT
|
||||
else if (adrof(STRedit) == 0) {
|
||||
el_end(el);
|
||||
history_end(hi);
|
||||
el = NULL;
|
||||
hi = NULL;
|
||||
editing = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
unset1(Char *v[], struct varent *head)
|
||||
{
|
||||
struct varent *vp;
|
||||
int cnt;
|
||||
|
||||
while (*++v) {
|
||||
cnt = 0;
|
||||
while ((vp = madrof(*v, head->v_left)) != NULL)
|
||||
unsetv1(vp), cnt++;
|
||||
if (cnt == 0)
|
||||
setname(vis_str(*v));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
unsetv(Char *var)
|
||||
{
|
||||
struct varent *vp;
|
||||
|
||||
if ((vp = adrof1(var, &shvhed)) == 0)
|
||||
udvar(var);
|
||||
unsetv1(vp);
|
||||
}
|
||||
|
||||
static void
|
||||
unsetv1(struct varent *p)
|
||||
{
|
||||
struct varent *c, *pp;
|
||||
int f;
|
||||
|
||||
/*
|
||||
* Free associated memory first to avoid complications.
|
||||
*/
|
||||
blkfree(p->vec);
|
||||
xfree((ptr_t) p->v_name);
|
||||
/*
|
||||
* If p is missing one child, then we can move the other into where p is.
|
||||
* Otherwise, we find the predecessor of p, which is guaranteed to have no
|
||||
* right child, copy it into p, and move its left child into it.
|
||||
*/
|
||||
if (p->v_right == 0)
|
||||
c = p->v_left;
|
||||
else if (p->v_left == 0)
|
||||
c = p->v_right;
|
||||
else {
|
||||
for (c = p->v_left; c->v_right; c = c->v_right)
|
||||
continue;
|
||||
p->v_name = c->v_name;
|
||||
p->vec = c->vec;
|
||||
p = c;
|
||||
c = p->v_left;
|
||||
}
|
||||
/*
|
||||
* Move c into where p is.
|
||||
*/
|
||||
pp = p->v_parent;
|
||||
f = pp->v_right == p;
|
||||
if ((pp->v_link[f] = c) != NULL)
|
||||
c->v_parent = pp;
|
||||
/*
|
||||
* Free the deleted node, and rebalance.
|
||||
*/
|
||||
xfree((ptr_t) p);
|
||||
balance(pp, f, 1);
|
||||
}
|
||||
|
||||
void
|
||||
setNS(Char *cp)
|
||||
{
|
||||
set(cp, Strsave(STRNULL));
|
||||
}
|
||||
|
||||
void
|
||||
/*ARGSUSED*/
|
||||
shift(Char **v, struct command *t)
|
||||
{
|
||||
struct varent *argv;
|
||||
Char *name;
|
||||
|
||||
v++;
|
||||
name = *v;
|
||||
if (name == 0)
|
||||
name = STRargv;
|
||||
else
|
||||
(void) strip(name);
|
||||
argv = adrof(name);
|
||||
if (argv == 0)
|
||||
udvar(name);
|
||||
if (argv->vec[0] == 0)
|
||||
stderror(ERR_NAME | ERR_NOMORE);
|
||||
lshift(argv->vec, 1);
|
||||
update_vars(name);
|
||||
}
|
||||
|
||||
static void
|
||||
exportpath(Char **val)
|
||||
{
|
||||
Char exppath[BUFSIZE];
|
||||
|
||||
exppath[0] = 0;
|
||||
if (val)
|
||||
while (*val) {
|
||||
if (Strlen(*val) + Strlen(exppath) + 2 > BUFSIZE) {
|
||||
(void)fprintf(csherr,
|
||||
"Warning: ridiculously long PATH truncated\n");
|
||||
break;
|
||||
}
|
||||
(void)Strcat(exppath, *val++);
|
||||
if (*val == 0 || eq(*val, STRRparen))
|
||||
break;
|
||||
(void)Strcat(exppath, STRcolon);
|
||||
}
|
||||
Setenv(STRPATH, exppath);
|
||||
}
|
||||
|
||||
#ifndef lint
|
||||
/*
|
||||
* Lint thinks these have null effect
|
||||
*/
|
||||
/* macros to do single rotations on node p */
|
||||
#define rright(p) (\
|
||||
t = (p)->v_left,\
|
||||
(t)->v_parent = (p)->v_parent,\
|
||||
((p)->v_left = t->v_right) ? (t->v_right->v_parent = (p)) : 0,\
|
||||
(t->v_right = (p))->v_parent = t,\
|
||||
(p) = t)
|
||||
#define rleft(p) (\
|
||||
t = (p)->v_right,\
|
||||
(t)->v_parent = (p)->v_parent,\
|
||||
((p)->v_right = t->v_left) ? (t->v_left->v_parent = (p)) : 0,\
|
||||
(t->v_left = (p))->v_parent = t,\
|
||||
(p) = t)
|
||||
#else
|
||||
struct varent *
|
||||
rleft(struct varent *p)
|
||||
{
|
||||
return (p);
|
||||
}
|
||||
struct varent *
|
||||
rright(struct varent *p)
|
||||
{
|
||||
return (p);
|
||||
}
|
||||
#endif /* ! lint */
|
||||
|
||||
|
||||
/*
|
||||
* Rebalance a tree, starting at p and up.
|
||||
* F == 0 means we've come from p's left child.
|
||||
* D == 1 means we've just done a delete, otherwise an insert.
|
||||
*/
|
||||
static void
|
||||
balance(struct varent *p, int f, int d)
|
||||
{
|
||||
struct varent *pp;
|
||||
|
||||
#ifndef lint
|
||||
struct varent *t; /* used by the rotate macros */
|
||||
|
||||
#endif
|
||||
int ff;
|
||||
|
||||
/*
|
||||
* Ok, from here on, p is the node we're operating on; pp is its parent; f
|
||||
* is the branch of p from which we have come; ff is the branch of pp which
|
||||
* is p.
|
||||
*/
|
||||
for (; (pp = p->v_parent) != NULL; p = pp, f = ff) {
|
||||
ff = pp->v_right == p;
|
||||
if (f ^ d) { /* right heavy */
|
||||
switch (p->v_bal) {
|
||||
case -1: /* was left heavy */
|
||||
p->v_bal = 0;
|
||||
break;
|
||||
case 0: /* was balanced */
|
||||
p->v_bal = 1;
|
||||
break;
|
||||
case 1: /* was already right heavy */
|
||||
switch (p->v_right->v_bal) {
|
||||
case 1: /* single rotate */
|
||||
pp->v_link[ff] = rleft(p);
|
||||
p->v_left->v_bal = 0;
|
||||
p->v_bal = 0;
|
||||
break;
|
||||
case 0: /* single rotate */
|
||||
pp->v_link[ff] = rleft(p);
|
||||
p->v_left->v_bal = 1;
|
||||
p->v_bal = -1;
|
||||
break;
|
||||
case -1: /* double rotate */
|
||||
(void) rright(p->v_right);
|
||||
pp->v_link[ff] = rleft(p);
|
||||
p->v_left->v_bal =
|
||||
p->v_bal < 1 ? 0 : -1;
|
||||
p->v_right->v_bal =
|
||||
p->v_bal > -1 ? 0 : 1;
|
||||
p->v_bal = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else { /* left heavy */
|
||||
switch (p->v_bal) {
|
||||
case 1: /* was right heavy */
|
||||
p->v_bal = 0;
|
||||
break;
|
||||
case 0: /* was balanced */
|
||||
p->v_bal = -1;
|
||||
break;
|
||||
case -1: /* was already left heavy */
|
||||
switch (p->v_left->v_bal) {
|
||||
case -1: /* single rotate */
|
||||
pp->v_link[ff] = rright(p);
|
||||
p->v_right->v_bal = 0;
|
||||
p->v_bal = 0;
|
||||
break;
|
||||
case 0: /* single rotate */
|
||||
pp->v_link[ff] = rright(p);
|
||||
p->v_right->v_bal = -1;
|
||||
p->v_bal = 1;
|
||||
break;
|
||||
case 1: /* double rotate */
|
||||
(void) rleft(p->v_left);
|
||||
pp->v_link[ff] = rright(p);
|
||||
p->v_left->v_bal =
|
||||
p->v_bal < 1 ? 0 : -1;
|
||||
p->v_right->v_bal =
|
||||
p->v_bal > -1 ? 0 : 1;
|
||||
p->v_bal = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If from insert, then we terminate when p is balanced. If from
|
||||
* delete, then we terminate when p is unbalanced.
|
||||
*/
|
||||
if ((p->v_bal == 0) ^ d)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
plist(struct varent *p)
|
||||
{
|
||||
struct varent *c;
|
||||
sigset_t nsigset;
|
||||
int len;
|
||||
|
||||
if (setintr) {
|
||||
sigemptyset(&nsigset);
|
||||
(void)sigaddset(&nsigset, SIGINT);
|
||||
(void)sigprocmask(SIG_UNBLOCK, &nsigset, NULL);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
while (p->v_left)
|
||||
p = p->v_left;
|
||||
x:
|
||||
if (p->v_parent == 0) /* is it the header? */
|
||||
return;
|
||||
len = blklen(p->vec);
|
||||
(void)fprintf(cshout, "%s\t", short2str(p->v_name));
|
||||
if (len != 1)
|
||||
(void)fputc('(', cshout);
|
||||
blkpr(cshout, p->vec);
|
||||
if (len != 1)
|
||||
(void)fputc(')', cshout);
|
||||
(void)fputc('\n', cshout);
|
||||
if (p->v_right) {
|
||||
p = p->v_right;
|
||||
continue;
|
||||
}
|
||||
do {
|
||||
c = p;
|
||||
p = p->v_parent;
|
||||
} while (p->v_right == c);
|
||||
goto x;
|
||||
}
|
||||
}
|
441
bin/csh/str.c
Normal file
441
bin/csh/str.c
Normal file
|
@ -0,0 +1,441 @@
|
|||
/* $NetBSD: str.c,v 1.15 2013/07/16 17:47:43 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)str.c 8.1 (Berkeley) 5/31/93";
|
||||
#else
|
||||
__RCSID("$NetBSD: str.c,v 1.15 2013/07/16 17:47:43 christos Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#define MALLOC_INCR 128
|
||||
|
||||
/*
|
||||
* tc.str.c: Short string package
|
||||
* This has been a lesson of how to write buggy code!
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <vis.h>
|
||||
|
||||
#include "csh.h"
|
||||
#include "extern.h"
|
||||
|
||||
#ifdef SHORT_STRINGS
|
||||
|
||||
Char **
|
||||
blk2short(char **src)
|
||||
{
|
||||
Char **dst, **sdst;
|
||||
size_t n;
|
||||
|
||||
/*
|
||||
* Count
|
||||
*/
|
||||
for (n = 0; src[n] != NULL; n++)
|
||||
continue;
|
||||
sdst = dst = xmalloc((size_t)((n + 1) * sizeof(*dst)));
|
||||
|
||||
for (; *src != NULL; src++)
|
||||
*dst++ = SAVE(*src);
|
||||
*dst = NULL;
|
||||
return (sdst);
|
||||
}
|
||||
|
||||
char **
|
||||
short2blk(Char *const *src)
|
||||
{
|
||||
char **dst, **sdst;
|
||||
size_t n;
|
||||
|
||||
/*
|
||||
* Count
|
||||
*/
|
||||
for (n = 0; src[n] != NULL; n++)
|
||||
continue;
|
||||
sdst = dst = xmalloc((size_t)((n + 1) * sizeof(*dst)));
|
||||
|
||||
for (; *src != NULL; src++)
|
||||
*dst++ = strsave(short2str(*src));
|
||||
*dst = NULL;
|
||||
return (sdst);
|
||||
}
|
||||
|
||||
Char *
|
||||
str2short(const char *src)
|
||||
{
|
||||
static Char *sdst;
|
||||
Char *dst, *edst;
|
||||
static size_t dstsize = 0;
|
||||
|
||||
if (src == NULL)
|
||||
return (NULL);
|
||||
|
||||
if (sdst == (NULL)) {
|
||||
dstsize = MALLOC_INCR;
|
||||
sdst = xmalloc((size_t)dstsize * sizeof(*sdst));
|
||||
}
|
||||
|
||||
dst = sdst;
|
||||
edst = &dst[dstsize];
|
||||
while (*src) {
|
||||
*dst++ = (Char) ((unsigned char) *src++);
|
||||
if (dst == edst) {
|
||||
dstsize += MALLOC_INCR;
|
||||
sdst = xrealloc((ptr_t)sdst,
|
||||
(size_t)dstsize * sizeof(*sdst));
|
||||
edst = &sdst[dstsize];
|
||||
dst = &edst[-MALLOC_INCR];
|
||||
}
|
||||
}
|
||||
*dst = 0;
|
||||
return (sdst);
|
||||
}
|
||||
|
||||
char *
|
||||
short2str(const Char *src)
|
||||
{
|
||||
static char *sdst = NULL;
|
||||
static size_t dstsize = 0;
|
||||
char *dst, *edst;
|
||||
|
||||
if (src == NULL)
|
||||
return (NULL);
|
||||
|
||||
if (sdst == NULL) {
|
||||
dstsize = MALLOC_INCR;
|
||||
sdst = xmalloc((size_t)dstsize * sizeof(*sdst));
|
||||
}
|
||||
dst = sdst;
|
||||
edst = &dst[dstsize];
|
||||
while (*src) {
|
||||
*dst++ = (char) *src++;
|
||||
if (dst == edst) {
|
||||
dstsize += MALLOC_INCR;
|
||||
sdst = xrealloc((ptr_t)sdst,
|
||||
(size_t)dstsize * sizeof(*sdst));
|
||||
edst = &sdst[dstsize];
|
||||
dst = &edst[-MALLOC_INCR];
|
||||
}
|
||||
}
|
||||
*dst = 0;
|
||||
return (sdst);
|
||||
}
|
||||
|
||||
Char *
|
||||
s_strcpy(Char *dst, const Char *src)
|
||||
{
|
||||
Char *sdst;
|
||||
|
||||
sdst = dst;
|
||||
while ((*dst++ = *src++) != '\0')
|
||||
continue;
|
||||
return (sdst);
|
||||
}
|
||||
|
||||
Char *
|
||||
s_strncpy(Char *dst, const Char *src, size_t n)
|
||||
{
|
||||
Char *sdst;
|
||||
|
||||
if (n == 0)
|
||||
return(dst);
|
||||
|
||||
sdst = dst;
|
||||
do
|
||||
if ((*dst++ = *src++) == '\0') {
|
||||
while (--n != 0)
|
||||
*dst++ = '\0';
|
||||
return(sdst);
|
||||
}
|
||||
while (--n != 0);
|
||||
return (sdst);
|
||||
}
|
||||
|
||||
Char *
|
||||
s_strcat(Char *dst, const Char *src)
|
||||
{
|
||||
short *sdst;
|
||||
|
||||
sdst = dst;
|
||||
while (*dst++)
|
||||
continue;
|
||||
--dst;
|
||||
while ((*dst++ = *src++) != '\0')
|
||||
continue;
|
||||
return (sdst);
|
||||
}
|
||||
|
||||
#ifdef NOTUSED
|
||||
Char *
|
||||
s_strncat(Char *dst, Char *src, size_t n)
|
||||
{
|
||||
Char *sdst;
|
||||
|
||||
if (n == 0)
|
||||
return (dst);
|
||||
|
||||
sdst = dst;
|
||||
|
||||
while (*dst++)
|
||||
continue;
|
||||
--dst;
|
||||
|
||||
do
|
||||
if ((*dst++ = *src++) == '\0')
|
||||
return(sdst);
|
||||
while (--n != 0)
|
||||
continue;
|
||||
|
||||
*dst = '\0';
|
||||
return (sdst);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Char *
|
||||
s_strchr(const Char *str, int ch)
|
||||
{
|
||||
do
|
||||
if (*str == ch)
|
||||
return __UNCONST(str);
|
||||
while (*str++);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
Char *
|
||||
s_strrchr(const Char *str, int ch)
|
||||
{
|
||||
const Char *rstr;
|
||||
|
||||
rstr = NULL;
|
||||
do
|
||||
if (*str == ch)
|
||||
rstr = str;
|
||||
while (*str++);
|
||||
return __UNCONST(rstr);
|
||||
}
|
||||
|
||||
size_t
|
||||
s_strlen(const Char *str)
|
||||
{
|
||||
size_t n;
|
||||
|
||||
for (n = 0; *str++; n++)
|
||||
continue;
|
||||
return (n);
|
||||
}
|
||||
|
||||
int
|
||||
s_strcmp(const Char *str1, const Char *str2)
|
||||
{
|
||||
for (; *str1 && *str1 == *str2; str1++, str2++)
|
||||
continue;
|
||||
/*
|
||||
* The following case analysis is necessary so that characters which look
|
||||
* negative collate low against normal characters but high against the
|
||||
* end-of-string NUL.
|
||||
*/
|
||||
if (*str1 == '\0' && *str2 == '\0')
|
||||
return (0);
|
||||
else if (*str1 == '\0')
|
||||
return (-1);
|
||||
else if (*str2 == '\0')
|
||||
return (1);
|
||||
else
|
||||
return (*str1 - *str2);
|
||||
}
|
||||
|
||||
int
|
||||
s_strncmp(const Char *str1, const Char *str2, size_t n)
|
||||
{
|
||||
if (n == 0)
|
||||
return (0);
|
||||
do {
|
||||
if (*str1 != *str2) {
|
||||
/*
|
||||
* The following case analysis is necessary so that characters
|
||||
* which look negative collate low against normal characters
|
||||
* but high against the end-of-string NUL.
|
||||
*/
|
||||
if (*str1 == '\0')
|
||||
return (-1);
|
||||
else if (*str2 == '\0')
|
||||
return (1);
|
||||
else
|
||||
return (*str1 - *str2);
|
||||
}
|
||||
if (*str1 == '\0')
|
||||
return(0);
|
||||
str1++, str2++;
|
||||
} while (--n != 0);
|
||||
return(0);
|
||||
}
|
||||
|
||||
Char *
|
||||
s_strsave(const Char *s)
|
||||
{
|
||||
const Char *p;
|
||||
Char *n;
|
||||
|
||||
if (s == 0)
|
||||
s = STRNULL;
|
||||
for (p = s; *p++;)
|
||||
continue;
|
||||
p = n = xmalloc((size_t)(p - s) * sizeof(*n));
|
||||
while ((*n++ = *s++) != '\0')
|
||||
continue;
|
||||
return __UNCONST(p);
|
||||
}
|
||||
|
||||
Char *
|
||||
s_strspl(const Char *cp, const Char *dp)
|
||||
{
|
||||
Char *ep, *d;
|
||||
const Char *p, *q;
|
||||
|
||||
if (!cp)
|
||||
cp = STRNULL;
|
||||
if (!dp)
|
||||
dp = STRNULL;
|
||||
for (p = cp; *p++;)
|
||||
continue;
|
||||
for (q = dp; *q++;)
|
||||
continue;
|
||||
ep = xmalloc((size_t)((p - cp) + (q - dp) - 1) * sizeof(*ep));
|
||||
for (d = ep, q = cp; (*d++ = *q++) != '\0';)
|
||||
continue;
|
||||
for (d--, q = dp; (*d++ = *q++) != '\0';)
|
||||
continue;
|
||||
return (ep);
|
||||
}
|
||||
|
||||
Char *
|
||||
s_strend(const Char *cp)
|
||||
{
|
||||
if (!cp)
|
||||
return __UNCONST(cp);
|
||||
while (*cp)
|
||||
cp++;
|
||||
return __UNCONST(cp);
|
||||
}
|
||||
|
||||
Char *
|
||||
s_strstr(const Char *s, const Char *t)
|
||||
{
|
||||
do {
|
||||
const Char *ss = s;
|
||||
const Char *tt = t;
|
||||
|
||||
do
|
||||
if (*tt == '\0')
|
||||
return __UNCONST(s);
|
||||
while (*ss++ == *tt++);
|
||||
} while (*s++ != '\0');
|
||||
return (NULL);
|
||||
}
|
||||
#endif /* SHORT_STRINGS */
|
||||
|
||||
char *
|
||||
short2qstr(const Char *src)
|
||||
{
|
||||
static char *sdst = NULL;
|
||||
static size_t dstsize = 0;
|
||||
char *dst, *edst;
|
||||
|
||||
if (src == NULL)
|
||||
return (NULL);
|
||||
|
||||
if (sdst == NULL) {
|
||||
dstsize = MALLOC_INCR;
|
||||
sdst = xmalloc((size_t)dstsize * sizeof(*sdst));
|
||||
}
|
||||
dst = sdst;
|
||||
edst = &dst[dstsize];
|
||||
while (*src) {
|
||||
|
||||
if (*src & QUOTE) {
|
||||
*dst++ = '\\';
|
||||
if (dst == edst) {
|
||||
dstsize += MALLOC_INCR;
|
||||
sdst = xrealloc((ptr_t) sdst,
|
||||
(size_t)dstsize * sizeof(*sdst));
|
||||
edst = &sdst[dstsize];
|
||||
dst = &edst[-MALLOC_INCR];
|
||||
}
|
||||
}
|
||||
*dst++ = (char) *src++;
|
||||
if (dst == edst) {
|
||||
dstsize += MALLOC_INCR;
|
||||
sdst = xrealloc((ptr_t) sdst,
|
||||
(size_t)dstsize * sizeof(*sdst));
|
||||
edst = &sdst[dstsize];
|
||||
dst = &edst[-MALLOC_INCR];
|
||||
}
|
||||
}
|
||||
*dst = 0;
|
||||
return (sdst);
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX: Should we worry about QUOTE'd chars?
|
||||
*/
|
||||
char *
|
||||
vis_str(const Char *cp)
|
||||
{
|
||||
static char *sdst = NULL;
|
||||
static size_t dstsize = 0;
|
||||
const Char *dp;
|
||||
size_t n;
|
||||
|
||||
if (cp == NULL)
|
||||
return (NULL);
|
||||
|
||||
for (dp = cp; *dp++;)
|
||||
continue;
|
||||
n = ((size_t)(dp - cp) << 2) + 1; /* 4 times + NULL */
|
||||
if (dstsize < n) {
|
||||
sdst = (dstsize ?
|
||||
xrealloc(sdst, (size_t)n * sizeof(*sdst)) :
|
||||
xmalloc((size_t)n * sizeof(*sdst)));
|
||||
dstsize = n;
|
||||
}
|
||||
/*
|
||||
* XXX: When we are in AsciiOnly we want all characters >= 0200 to
|
||||
* be encoded, but currently there is no way in vis to do that.
|
||||
*/
|
||||
(void)strvis(sdst, short2str(cp), VIS_NOSLASH);
|
||||
return (sdst);
|
||||
}
|
285
bin/csh/time.c
Normal file
285
bin/csh/time.c
Normal file
|
@ -0,0 +1,285 @@
|
|||
/* $NetBSD: time.c,v 1.20 2013/07/16 17:47:43 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1980, 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)time.c 8.1 (Berkeley) 5/31/93";
|
||||
#else
|
||||
__RCSID("$NetBSD: time.c,v 1.20 2013/07/16 17:47:43 christos Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NOT_CSH
|
||||
#include <sys/types.h>
|
||||
#include <stdarg.h>
|
||||
#include "csh.h"
|
||||
#include "extern.h"
|
||||
#endif
|
||||
#include <util.h>
|
||||
|
||||
/*
|
||||
* C Shell - routines handling process timing and niceing
|
||||
*/
|
||||
static void pdeltat(FILE *, struct timeval *, struct timeval *);
|
||||
static void pcsecs(FILE *, long);
|
||||
|
||||
#ifndef NOT_CSH
|
||||
void
|
||||
settimes(void)
|
||||
{
|
||||
struct rusage ruch;
|
||||
|
||||
(void)clock_gettime(CLOCK_MONOTONIC, &time0);
|
||||
(void)getrusage(RUSAGE_SELF, &ru0);
|
||||
(void)getrusage(RUSAGE_CHILDREN, &ruch);
|
||||
ruadd(&ru0, &ruch);
|
||||
}
|
||||
|
||||
/*
|
||||
* dotime is only called if it is truly a builtin function and not a
|
||||
* prefix to another command
|
||||
*/
|
||||
void
|
||||
/*ARGSUSED*/
|
||||
dotime(Char **v, struct command *t)
|
||||
{
|
||||
struct rusage ru1, ruch;
|
||||
struct timespec timedol;
|
||||
|
||||
(void)getrusage(RUSAGE_SELF, &ru1);
|
||||
(void)getrusage(RUSAGE_CHILDREN, &ruch);
|
||||
ruadd(&ru1, &ruch);
|
||||
(void)clock_gettime(CLOCK_MONOTONIC, &timedol);
|
||||
prusage(cshout, &ru0, &ru1, &timedol, &time0);
|
||||
}
|
||||
|
||||
/*
|
||||
* donice is only called when it on the line by itself or with a +- value
|
||||
*/
|
||||
void
|
||||
/*ARGSUSED*/
|
||||
donice(Char **v, struct command *t)
|
||||
{
|
||||
Char *cp;
|
||||
int nval;
|
||||
|
||||
nval = 0;
|
||||
v++;
|
||||
cp = *v++;
|
||||
if (cp == 0)
|
||||
nval = 4;
|
||||
else if (*v == 0 && any("+-", cp[0]))
|
||||
nval = getn(cp);
|
||||
(void)setpriority(PRIO_PROCESS, 0, nval);
|
||||
}
|
||||
|
||||
void
|
||||
ruadd(struct rusage *ru, struct rusage *ru2)
|
||||
{
|
||||
timeradd(&ru->ru_utime, &ru2->ru_utime, &ru->ru_utime);
|
||||
timeradd(&ru->ru_stime, &ru2->ru_stime, &ru->ru_stime);
|
||||
if (ru2->ru_maxrss > ru->ru_maxrss)
|
||||
ru->ru_maxrss = ru2->ru_maxrss;
|
||||
|
||||
ru->ru_ixrss += ru2->ru_ixrss;
|
||||
ru->ru_idrss += ru2->ru_idrss;
|
||||
ru->ru_isrss += ru2->ru_isrss;
|
||||
ru->ru_minflt += ru2->ru_minflt;
|
||||
ru->ru_majflt += ru2->ru_majflt;
|
||||
ru->ru_nswap += ru2->ru_nswap;
|
||||
ru->ru_inblock += ru2->ru_inblock;
|
||||
ru->ru_oublock += ru2->ru_oublock;
|
||||
ru->ru_msgsnd += ru2->ru_msgsnd;
|
||||
ru->ru_msgrcv += ru2->ru_msgrcv;
|
||||
ru->ru_nsignals += ru2->ru_nsignals;
|
||||
ru->ru_nvcsw += ru2->ru_nvcsw;
|
||||
ru->ru_nivcsw += ru2->ru_nivcsw;
|
||||
}
|
||||
#endif /* NOT_CSH */
|
||||
|
||||
void
|
||||
prusage(FILE *fp, struct rusage *r0, struct rusage *r1, struct timespec *e,
|
||||
struct timespec *b)
|
||||
{
|
||||
#ifndef NOT_CSH
|
||||
struct varent *vp;
|
||||
#endif
|
||||
const char *cp;
|
||||
long i;
|
||||
time_t t;
|
||||
time_t ms;
|
||||
|
||||
cp = "%Uu %Ss %E %P %X+%Dk %I+%Oio %Fpf+%Ww";
|
||||
ms = (e->tv_sec - b->tv_sec) * 100 + (e->tv_nsec - b->tv_nsec) / 10000000;
|
||||
t = (r1->ru_utime.tv_sec - r0->ru_utime.tv_sec) * 100 +
|
||||
(r1->ru_utime.tv_usec - r0->ru_utime.tv_usec) / 10000 +
|
||||
(r1->ru_stime.tv_sec - r0->ru_stime.tv_sec) * 100 +
|
||||
(r1->ru_stime.tv_usec - r0->ru_stime.tv_usec) / 10000;
|
||||
#ifndef NOT_CSH
|
||||
vp = adrof(STRtime);
|
||||
|
||||
if (vp && vp->vec[0] && vp->vec[1])
|
||||
cp = short2str(vp->vec[1]);
|
||||
#endif
|
||||
|
||||
for (; *cp; cp++)
|
||||
if (*cp != '%')
|
||||
(void) fputc(*cp, fp);
|
||||
else if (cp[1])
|
||||
switch (*++cp) {
|
||||
case 'D': /* (average) unshared data size */
|
||||
(void)fprintf(fp, "%ld", t == 0 ? 0L :
|
||||
(long)((r1->ru_idrss + r1->ru_isrss -
|
||||
(r0->ru_idrss + r0->ru_isrss)) / t));
|
||||
break;
|
||||
case 'E': /* elapsed (wall-clock) time */
|
||||
pcsecs(fp, (long) ms);
|
||||
break;
|
||||
case 'F': /* page faults */
|
||||
(void)fprintf(fp, "%ld", r1->ru_majflt - r0->ru_majflt);
|
||||
break;
|
||||
case 'I': /* FS blocks in */
|
||||
(void)fprintf(fp, "%ld", r1->ru_inblock - r0->ru_inblock);
|
||||
break;
|
||||
case 'K': /* (average) total data memory used */
|
||||
(void)fprintf(fp, "%ld", t == 0 ? 0L :
|
||||
(long)(((r1->ru_ixrss + r1->ru_isrss + r1->ru_idrss) -
|
||||
(r0->ru_ixrss + r0->ru_idrss + r0->ru_isrss)) / t));
|
||||
break;
|
||||
case 'M': /* max. Resident Set Size */
|
||||
(void)fprintf(fp, "%ld", r1->ru_maxrss / 2L);
|
||||
break;
|
||||
case 'O': /* FS blocks out */
|
||||
(void)fprintf(fp, "%ld", r1->ru_oublock - r0->ru_oublock);
|
||||
break;
|
||||
case 'P': /* percent time spent running */
|
||||
/* check if it did not run at all */
|
||||
if (ms == 0) {
|
||||
(void)fputs("0.0%", fp);
|
||||
} else {
|
||||
char pb[32];
|
||||
(void)fputs(strpct(pb, sizeof(pb),
|
||||
(uintmax_t)t, (uintmax_t)ms, 1), fp);
|
||||
(void)fputc('%', fp);
|
||||
}
|
||||
break;
|
||||
case 'R': /* page reclaims */
|
||||
(void)fprintf(fp, "%ld", r1->ru_minflt - r0->ru_minflt);
|
||||
break;
|
||||
case 'S': /* system CPU time used */
|
||||
pdeltat(fp, &r1->ru_stime, &r0->ru_stime);
|
||||
break;
|
||||
case 'U': /* user CPU time used */
|
||||
pdeltat(fp, &r1->ru_utime, &r0->ru_utime);
|
||||
break;
|
||||
case 'W': /* number of swaps */
|
||||
i = r1->ru_nswap - r0->ru_nswap;
|
||||
(void)fprintf(fp, "%ld", i);
|
||||
break;
|
||||
case 'X': /* (average) shared text size */
|
||||
(void)fprintf(fp, "%ld", t == 0 ? 0L :
|
||||
(long)((r1->ru_ixrss - r0->ru_ixrss) / t));
|
||||
break;
|
||||
case 'c': /* num. involuntary context switches */
|
||||
(void)fprintf(fp, "%ld", r1->ru_nivcsw - r0->ru_nivcsw);
|
||||
break;
|
||||
case 'k': /* number of signals received */
|
||||
(void)fprintf(fp, "%ld", r1->ru_nsignals-r0->ru_nsignals);
|
||||
break;
|
||||
case 'r': /* socket messages received */
|
||||
(void)fprintf(fp, "%ld", r1->ru_msgrcv - r0->ru_msgrcv);
|
||||
break;
|
||||
case 's': /* socket messages sent */
|
||||
(void)fprintf(fp, "%ld", r1->ru_msgsnd - r0->ru_msgsnd);
|
||||
break;
|
||||
case 'w': /* num. voluntary context switches (waits) */
|
||||
(void)fprintf(fp, "%ld", r1->ru_nvcsw - r0->ru_nvcsw);
|
||||
break;
|
||||
}
|
||||
(void)fputc('\n', fp);
|
||||
}
|
||||
|
||||
static void
|
||||
pdeltat(FILE *fp, struct timeval *t1, struct timeval *t0)
|
||||
{
|
||||
struct timeval td;
|
||||
|
||||
timersub(t1, t0, &td);
|
||||
(void)fprintf(fp, "%ld.%01ld", (long)td.tv_sec,
|
||||
(long)(td.tv_usec / 100000));
|
||||
}
|
||||
|
||||
#define P2DIG(fp, i) (void)fprintf(fp, "%ld%ld", (i) / 10, (i) % 10)
|
||||
|
||||
#ifndef NOT_CSH
|
||||
void
|
||||
psecs(long l)
|
||||
{
|
||||
long i;
|
||||
|
||||
i = l / 3600;
|
||||
if (i) {
|
||||
(void)fprintf(cshout, "%ld:", i);
|
||||
i = l % 3600;
|
||||
P2DIG(cshout, i / 60);
|
||||
goto minsec;
|
||||
}
|
||||
i = l;
|
||||
(void)fprintf(cshout, "%ld", i / 60);
|
||||
minsec:
|
||||
i %= 60;
|
||||
(void)fputc(':', cshout);
|
||||
P2DIG(cshout, i);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
pcsecs(FILE *fp, long l) /* PWP: print mm:ss.dd, l is in sec*100 */
|
||||
{
|
||||
long i;
|
||||
|
||||
i = l / 360000;
|
||||
if (i) {
|
||||
(void)fprintf(fp, "%ld:", i);
|
||||
i = (l % 360000) / 100;
|
||||
P2DIG(fp, i / 60);
|
||||
goto minsec;
|
||||
}
|
||||
i = l / 100;
|
||||
(void)fprintf(fp, "%ld", i / 60);
|
||||
minsec:
|
||||
i %= 60;
|
||||
(void)fputc(':', fp);
|
||||
P2DIG(fp, i);
|
||||
(void)fputc('.', fp);
|
||||
P2DIG(fp, (l % 100));
|
||||
}
|
|
@ -16,6 +16,7 @@
|
|||
./bin/command minix-sys obsolete
|
||||
./bin/cp minix-sys
|
||||
./bin/cpio minix-sys
|
||||
./bin/csh minix-sys
|
||||
./bin/date minix-sys
|
||||
./bin/dd minix-sys
|
||||
./bin/df minix-sys
|
||||
|
@ -2310,6 +2311,7 @@
|
|||
./usr/man/man1/[.1 minix-sys
|
||||
./usr/man/man1/..1 minix-sys obsolete
|
||||
./usr/man/man1/addr2line.1 minix-sys binutils
|
||||
./usr/man/man1/alias.1 minix-sys
|
||||
./usr/man/man1/apropos.1 minix-sys
|
||||
./usr/man/man1/ar.1 minix-sys binutils
|
||||
./usr/man/man1/as.1 minix-sys binutils
|
||||
|
@ -2328,6 +2330,7 @@
|
|||
./usr/man/man1/banner.1 minix-sys
|
||||
./usr/man/man1/basename.1 minix-sys
|
||||
./usr/man/man1/bdes.1 minix-sys
|
||||
./usr/man/man1/bg.1 minix-sys
|
||||
./usr/man/man1/break.1 minix-sys obsolete
|
||||
./usr/man/man1/bsdtar.1 minix-sys
|
||||
./usr/man/man1/bsfilt.1 minix-sys
|
||||
|
@ -2369,6 +2372,7 @@
|
|||
./usr/man/man1/cpp.1 minix-sys gcccmds
|
||||
./usr/man/man1/crc.1 minix-sys
|
||||
./usr/man/man1/crontab.1 minix-sys
|
||||
./usr/man/man1/csh.1 minix-sys
|
||||
./usr/man/man1/csplit.1 minix-sys
|
||||
./usr/man/man1/ctags.1 minix-sys
|
||||
./usr/man/man1/cut.1 minix-sys
|
||||
|
@ -2380,6 +2384,7 @@
|
|||
./usr/man/man1/dhrystone.1 minix-sys
|
||||
./usr/man/man1/diff.1 minix-sys
|
||||
./usr/man/man1/dirname.1 minix-sys
|
||||
./usr/man/man1/dirs.1 minix-sys
|
||||
./usr/man/man1/domainname.1 minix-sys
|
||||
./usr/man/man1/dosdir.1 minix-sys
|
||||
./usr/man/man1/dosread.1 minix-sys
|
||||
|
@ -2400,6 +2405,7 @@
|
|||
./usr/man/man1/expr.1 minix-sys
|
||||
./usr/man/man1/false.1 minix-sys
|
||||
./usr/man/man1/fetch.1 minix-sys
|
||||
./usr/man/man1/fg.1 minix-sys
|
||||
./usr/man/man1/fgrep.1 minix-sys
|
||||
./usr/man/man1/file.1 minix-sys
|
||||
./usr/man/man1/find.1 minix-sys
|
||||
|
@ -2409,6 +2415,7 @@
|
|||
./usr/man/man1/flock.1 minix-sys
|
||||
./usr/man/man1/fold.1 minix-sys
|
||||
./usr/man/man1/for.1 minix-sys obsolete
|
||||
./usr/man/man1/foreach.1 minix-sys
|
||||
./usr/man/man1/format.1 minix-sys
|
||||
./usr/man/man1/fpr.1 minix-sys
|
||||
./usr/man/man1/from.1 minix-sys
|
||||
|
@ -2432,6 +2439,7 @@
|
|||
./usr/man/man1/hash.1 minix-sys obsolete
|
||||
./usr/man/man1/head.1 minix-sys
|
||||
./usr/man/man1/hexdump.1 minix-sys
|
||||
./usr/man/man1/history.1 minix-sys
|
||||
./usr/man/man1/host.1 minix-sys
|
||||
./usr/man/man1/hostaddr.1 minix-sys
|
||||
./usr/man/man1/hostname.1 minix-sys
|
||||
|
@ -2447,7 +2455,7 @@
|
|||
./usr/man/man1/isodir.1 minix-sys
|
||||
./usr/man/man1/isoinfo.1 minix-sys
|
||||
./usr/man/man1/isoread.1 minix-sys
|
||||
./usr/man/man1/jobs.1 minix-sys obsolete
|
||||
./usr/man/man1/jobs.1 minix-sys
|
||||
./usr/man/man1/join.1 minix-sys
|
||||
./usr/man/man1/jot.1 minix-sys
|
||||
./usr/man/man1/kill.1 minix-sys
|
||||
|
@ -2476,6 +2484,7 @@
|
|||
./usr/man/man1/lessecho.1 minix-sys
|
||||
./usr/man/man1/lesskey.1 minix-sys
|
||||
./usr/man/man1/lex.1 minix-sys
|
||||
./usr/man/man1/limit.1 minix-sys
|
||||
./usr/man/man1/linkfarm.1 minix-sys obsolete
|
||||
./usr/man/man1/ln.1 minix-sys
|
||||
./usr/man/man1/loadfont.1 minix-sys
|
||||
|
@ -2541,12 +2550,14 @@
|
|||
./usr/man/man1/ping.1 minix-sys obsolete
|
||||
./usr/man/man1/pkg_view.1 minix-sys obsolete
|
||||
./usr/man/man1/playwave.1 minix-sys
|
||||
./usr/man/man1/popd.1 minix-sys
|
||||
./usr/man/man1/pr.1 minix-sys
|
||||
./usr/man/man1/prep.1 minix-sys
|
||||
./usr/man/man1/printenv.1 minix-sys
|
||||
./usr/man/man1/printf.1 minix-sys
|
||||
./usr/man/man1/profile.1 minix-sys
|
||||
./usr/man/man1/ps.1 minix-sys
|
||||
./usr/man/man1/pushd.1 minix-sys
|
||||
./usr/man/man1/pwd.1 minix-sys
|
||||
./usr/man/man1/pwhash.1 minix-sys
|
||||
./usr/man/man1/ranlib.1 minix-sys binutils
|
||||
|
@ -2557,7 +2568,9 @@
|
|||
./usr/man/man1/readlink.1 minix-sys
|
||||
./usr/man/man1/readonly.1 minix-sys obsolete
|
||||
./usr/man/man1/recwave.1 minix-sys
|
||||
./usr/man/man1/rehash.1 minix-sys
|
||||
./usr/man/man1/remsync.1 minix-sys
|
||||
./usr/man/man1/repeat.1 minix-sys
|
||||
./usr/man/man1/return.1 minix-sys obsolete
|
||||
./usr/man/man1/rev.1 minix-sys
|
||||
./usr/man/man1/rget.1 minix-sys
|
||||
|
@ -2582,15 +2595,18 @@
|
|||
./usr/man/man1/sleep.1 minix-sys
|
||||
./usr/man/man1/soelim.1 minix-sys
|
||||
./usr/man/man1/sort.1 minix-sys
|
||||
./usr/man/man1/source.1 minix-sys
|
||||
./usr/man/man1/spell.1 minix-sys
|
||||
./usr/man/man1/split.1 minix-sys
|
||||
./usr/man/man1/sqlite3.1 minix-sys
|
||||
./usr/man/man1/stat.1 minix-sys
|
||||
./usr/man/man1/stop.1 minix-sys
|
||||
./usr/man/man1/strings.1 minix-sys binutils
|
||||
./usr/man/man1/strip.1 minix-sys binutils
|
||||
./usr/man/man1/stty.1 minix-sys
|
||||
./usr/man/man1/su.1 minix-sys
|
||||
./usr/man/man1/sum.1 minix-sys
|
||||
./usr/man/man1/suspend.1 minix-sys
|
||||
./usr/man/man1/svc.1 minix-sys obsolete
|
||||
./usr/man/man1/svrctl.1 minix-sys
|
||||
./usr/man/man1/synctree.1 minix-sys
|
||||
|
@ -5420,6 +5436,15 @@
|
|||
./usr/share/doc/usd/03.shell/t3 minix-sys
|
||||
./usr/share/doc/usd/03.shell/t4 minix-sys
|
||||
./usr/share/doc/usd/03.shell/t.mac minix-sys
|
||||
./usr/share/doc/usd/04.csh minix-sys
|
||||
./usr/share/doc/usd/04.csh/Makefile minix-sys
|
||||
./usr/share/doc/usd/04.csh/csh.1 minix-sys
|
||||
./usr/share/doc/usd/04.csh/csh.2 minix-sys
|
||||
./usr/share/doc/usd/04.csh/csh.3 minix-sys
|
||||
./usr/share/doc/usd/04.csh/csh.4 minix-sys
|
||||
./usr/share/doc/usd/04.csh/csh.ap minix-sys
|
||||
./usr/share/doc/usd/04.csh/csh.g minix-sys
|
||||
./usr/share/doc/usd/04.csh/tabs minix-sys
|
||||
./usr/share/doc/usd/30.rogue minix-sys
|
||||
./usr/share/doc/usd/30.rogue/Makefile minix-sys
|
||||
./usr/share/doc/usd/30.rogue/rogue.me minix-sys
|
||||
|
|
|
@ -131,6 +131,7 @@
|
|||
./usr/share/doc/psd/19.curses
|
||||
./usr/share/doc/usd
|
||||
./usr/share/doc/usd/03.shell
|
||||
./usr/share/doc/usd/04.csh
|
||||
./usr/share/doc/usd/30.rogue
|
||||
./usr/share/examples
|
||||
./usr/share/examples/tmux
|
||||
|
|
Loading…
Reference in a new issue