Importing bin/sh
/etc/profile enables by default tabcompletion, as well as emacs mode, in order to keep the old MINIX ash behavior. Note: The shell now refuses to source a script without a relative or absolute path. This means: - '. myscript.sh' fails, while - '. ./myscript.sh' succeeds Change-Id: I0be89b0747bd005e4c05cadb937af86883627dc6
This commit is contained in:
parent
2d64210c1d
commit
d90bee9749
117 changed files with 12265 additions and 10664 deletions
|
@ -2,7 +2,7 @@
|
|||
# @(#)Makefile 8.1 (Berkeley) 5/31/93
|
||||
|
||||
SUBDIR= cat chmod cp date df echo ed expr hostname \
|
||||
kill ksh ln ls mkdir mv pax pwd rm rmdir \
|
||||
kill ksh ln ls mkdir mv pax pwd rm rmdir sh \
|
||||
sleep stty sync test
|
||||
|
||||
.include <bsd.subdir.mk>
|
||||
|
|
88
bin/sh/Makefile
Normal file
88
bin/sh/Makefile
Normal file
|
@ -0,0 +1,88 @@
|
|||
# $NetBSD: Makefile,v 1.99 2012/12/02 12:55:27 apb Exp $
|
||||
# @(#)Makefile 8.4 (Berkeley) 5/5/95
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
YHEADER=1
|
||||
PROG= sh
|
||||
SHSRCS= alias.c cd.c echo.c error.c eval.c exec.c expand.c \
|
||||
histedit.c input.c jobs.c mail.c main.c memalloc.c miscbltin.c \
|
||||
mystring.c options.c parser.c redir.c show.c trap.c output.c var.c \
|
||||
test.c kill.c syntax.c
|
||||
GENSRCS=arith.c arith_lex.c builtins.c init.c nodes.c
|
||||
GENHDRS=arith.h builtins.h nodes.h token.h
|
||||
SRCS= ${SHSRCS} ${GENSRCS}
|
||||
|
||||
DPSRCS+=${GENHDRS}
|
||||
|
||||
LDADD+= -ll -ledit -lterminfo
|
||||
DPADD+= ${LIBL} ${LIBEDIT} ${LIBTERMINFO}
|
||||
|
||||
LFLAGS= -8 # 8-bit lex scanner for arithmetic
|
||||
|
||||
# Environment for scripts executed during build.
|
||||
SCRIPT_ENV= \
|
||||
AWK=${TOOL_AWK:Q} \
|
||||
SED=${TOOL_SED:Q}
|
||||
|
||||
# The .depend file can get references to these temporary files
|
||||
.OPTIONAL: lex.yy.c y.tab.c
|
||||
|
||||
.ifdef CRUNCHEDPROG
|
||||
LFLAGS+=-L
|
||||
YFLAGS+=-l
|
||||
.endif
|
||||
|
||||
CPPFLAGS+=-DSHELL -I. -I${.CURDIR}
|
||||
#XXX: For testing only.
|
||||
#CPPFLAGS+=-DDEBUG=2
|
||||
#COPTS+=-g
|
||||
#CFLAGS+=-funsigned-char
|
||||
#TARGET_CHARFLAG?= -DTARGET_CHAR="unsigned char" -funsigned-char
|
||||
|
||||
.ifdef SMALLPROG
|
||||
CPPFLAGS+=-DSMALL
|
||||
.else
|
||||
SRCS+=printf.c
|
||||
.endif
|
||||
|
||||
.PATH: ${.CURDIR}/bltin ${NETBSDSRCDIR}/bin/test \
|
||||
${NETBSDSRCDIR}/usr.bin/printf \
|
||||
${NETBSDSRCDIR}/bin/kill
|
||||
|
||||
CLEANFILES+= ${GENSRCS} ${GENHDRS} y.tab.h
|
||||
CLEANFILES+= trace
|
||||
|
||||
token.h: mktokens
|
||||
${_MKTARGET_CREATE}
|
||||
${SCRIPT_ENV} ${HOST_SH} ${.ALLSRC}
|
||||
|
||||
.ORDER: builtins.h builtins.c
|
||||
builtins.h builtins.c: mkbuiltins shell.h builtins.def
|
||||
${_MKTARGET_CREATE}
|
||||
${SCRIPT_ENV} ${HOST_SH} ${.ALLSRC} ${.OBJDIR}
|
||||
[ -f builtins.h ]
|
||||
|
||||
init.c: mkinit.sh ${SHSRCS}
|
||||
${_MKTARGET_CREATE}
|
||||
${SCRIPT_ENV} ${HOST_SH} ${.ALLSRC}
|
||||
|
||||
.ORDER: nodes.h nodes.c
|
||||
nodes.c nodes.h: mknodes.sh nodetypes nodes.c.pat
|
||||
${_MKTARGET_CREATE}
|
||||
${SCRIPT_ENV} ${HOST_SH} ${.ALLSRC} ${.OBJDIR}
|
||||
[ -f nodes.h ]
|
||||
|
||||
.if ${USETOOLS} == "yes"
|
||||
NBCOMPATLIB= -L${TOOLDIR}/lib -lnbcompat
|
||||
.endif
|
||||
|
||||
.if make(install)
|
||||
SUBDIR+=USD.doc
|
||||
.endif
|
||||
|
||||
COPTS.printf.c = -Wno-format-nonliteral
|
||||
COPTS.jobs.c = -Wno-format-nonliteral
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
.include <bsd.subdir.mk>
|
|
@ -1,5 +1,5 @@
|
|||
# $NetBSD: TOUR,v 1.10 2008/11/15 17:01:38 snj Exp $
|
||||
# @(#)TOUR 8.1 (Berkeley) 5/31/93
|
||||
# $FreeBSD: src/bin/sh/TOUR,v 1.6 1999/08/27 23:15:07 peter Exp $
|
||||
|
||||
NOTE -- This is the original TOUR paper distributed with ash and
|
||||
does not represent the current state of the shell. It is provided anyway
|
||||
|
@ -22,7 +22,7 @@ SOURCE CODE GENERATORS: Files whose names begin with "mk" are
|
|||
programs that generate source code. A complete list of these
|
||||
programs is:
|
||||
|
||||
program intput files generates
|
||||
program input files generates
|
||||
------- ------------ ---------
|
||||
mkbuiltins builtins builtins.h builtins.c
|
||||
mkinit *.c init.c
|
||||
|
@ -91,7 +91,7 @@ INTERRUPTS: In an interactive shell, an interrupt will cause an
|
|||
EXINT exception to return to the main command loop. (Exception:
|
||||
EXINT is not raised if the user traps interrupts using the trap
|
||||
command.) The INTOFF and INTON macros (defined in exception.h)
|
||||
provide uninterruptable critical sections. Between the execution
|
||||
provide uninterruptible critical sections. Between the execution
|
||||
of INTOFF and the execution of INTON, interrupt signals will be
|
||||
held for later delivery. INTOFF and INTON can be nested.
|
||||
|
||||
|
@ -110,7 +110,7 @@ string was going to be:
|
|||
p = stackptr;
|
||||
*p++ = c; /* repeated as many times as needed */
|
||||
stackptr = p;
|
||||
The folloing three macros (defined in memalloc.h) perform these
|
||||
The following three macros (defined in memalloc.h) perform these
|
||||
operations, but grow the stack if you run off the end:
|
||||
STARTSTACKSTR(p);
|
||||
STPUTC(c, p); /* repeated as many times as needed */
|
||||
|
@ -232,7 +232,7 @@ control is defined.
|
|||
REDIR.C: Ash allows file descriptors to be redirected and then
|
||||
restored without forking off a child process. This is accom-
|
||||
plished by duplicating the original file descriptors. The redir-
|
||||
tab structure records where the file descriptors have be dupli-
|
||||
tab structure records where the file descriptors have been dupli-
|
||||
cated to.
|
||||
|
||||
EXEC.C: The routine find_command locates a command, and enters
|
||||
|
@ -327,7 +327,7 @@ is called at appropriate points to actually handle the signal.
|
|||
When an interrupt is caught and no trap has been set for that
|
||||
signal, the routine "onint" in error.c is called.
|
||||
|
||||
OUTPUT: Ash uses it's own output routines. There are three out-
|
||||
OUTPUT: Ash uses its own output routines. There are three out-
|
||||
put structures allocated. "Output" represents the standard out-
|
||||
put, "errout" the standard error, and "memout" contains output
|
||||
which is to be stored in memory. This last is used when a buil-
|
||||
|
@ -355,6 +355,3 @@ cause the preprocessor can't handle functions with a variable
|
|||
number of arguments. Defining DEBUG also causes the shell to
|
||||
generate a core dump if it is sent a quit signal. The tracing
|
||||
code is in show.c.
|
||||
|
||||
#
|
||||
# $PchId: TOUR,v 1.3 2006/03/31 11:33:46 philip Exp $
|
12
bin/sh/USD.doc/Makefile
Normal file
12
bin/sh/USD.doc/Makefile
Normal file
|
@ -0,0 +1,12 @@
|
|||
# $NetBSD: Makefile,v 1.1 2010/08/22 01:58:16 perry Exp $
|
||||
# @(#)Makefile 8.1 (Berkeley) 8/14/93
|
||||
|
||||
DIR= usd/03.shell
|
||||
SRCS= Rv7man t.mac t1 t2 t3 t4
|
||||
MACROS= -ms
|
||||
|
||||
paper.ps: ${SRCS}
|
||||
${TOOL_REFER} -e -p ${SRCS} | \
|
||||
${TOOL_ROFF_PS} ${MACROS} > ${.TARGET}
|
||||
|
||||
.include <bsd.doc.mk>
|
405
bin/sh/USD.doc/Rv7man
Normal file
405
bin/sh/USD.doc/Rv7man
Normal file
|
@ -0,0 +1,405 @@
|
|||
%A L. P. Deutsch
|
||||
%A B. W. Lampson
|
||||
%T An online editor
|
||||
%J Comm. Assoc. Comp. Mach.
|
||||
%V 10
|
||||
%N 12
|
||||
%D December 1967
|
||||
%P 793-799, 803
|
||||
%K qed
|
||||
|
||||
.[
|
||||
%r 17
|
||||
%K cstr
|
||||
%R Comp. Sci. Tech. Rep. No. 17
|
||||
%I Bell Laboratories
|
||||
%C Murray Hill, New Jersey
|
||||
%A B. W. Kernighan
|
||||
%A L. L. Cherry
|
||||
%T A System for Typesetting Mathematics
|
||||
%d May 1974, revised April 1977
|
||||
%J Comm. Assoc. Comp. Mach.
|
||||
%K acm cacm
|
||||
%V 18
|
||||
%P 151-157
|
||||
%D March 1975
|
||||
.]
|
||||
|
||||
%T U\s-2NIX\s0 Time-Sharing System: Document Preparation
|
||||
%K unix bstj
|
||||
%A B. W. Kernighan
|
||||
%A M. E. Lesk
|
||||
%A J. F. Ossanna
|
||||
%J Bell Sys. Tech. J.
|
||||
%V 57
|
||||
%N 6
|
||||
%P 2115-2135
|
||||
%D 1978
|
||||
|
||||
%A T. A. Dolotta
|
||||
%A J. R. Mashey
|
||||
%T An Introduction to the Programmer's Workbench
|
||||
%J Proc. 2nd Int. Conf. on Software Engineering
|
||||
%D October 13-15, 1976
|
||||
%P 164-168
|
||||
|
||||
%T U\s-2NIX\s0 Time-Sharing System: The Programmer's Workbench
|
||||
%A T. A. Dolotta
|
||||
%A R. C. Haight
|
||||
%A J. R. Mashey
|
||||
%J Bell Sys. Tech. J.
|
||||
%V 57
|
||||
%N 6
|
||||
%P 2177-2200
|
||||
%D 1978
|
||||
%K unix bstj
|
||||
|
||||
%T U\s-2NIX\s0 Time-Sharing System: U\s-2NIX\s0 on a Microprocessor
|
||||
%K unix bstj
|
||||
%A H. Lycklama
|
||||
%J Bell Sys. Tech. J.
|
||||
%V 57
|
||||
%N 6
|
||||
%P 2087-2101
|
||||
%D 1978
|
||||
|
||||
%T The C Programming Language
|
||||
%A B. W. Kernighan
|
||||
%A D. M. Ritchie
|
||||
%I Prentice-Hall
|
||||
%C Englewood Cliffs, New Jersey
|
||||
%D 1978
|
||||
|
||||
%T Computer Recreations
|
||||
%A Aleph-null
|
||||
%J Software Practice and Experience
|
||||
%V 1
|
||||
%N 2
|
||||
%D April-June 1971
|
||||
%P 201-204
|
||||
|
||||
%T U\s-2NIX\s0 Time-Sharing System: The U\s-2NIX\s0 Shell
|
||||
%A S. R. Bourne
|
||||
%K unix bstj
|
||||
%J Bell Sys. Tech. J.
|
||||
%V 57
|
||||
%N 6
|
||||
%P 1971-1990
|
||||
%D 1978
|
||||
|
||||
%A L. P. Deutsch
|
||||
%A B. W. Lampson
|
||||
%T \*sSDS\*n 930 time-sharing system preliminary reference manual
|
||||
%R Doc. 30.10.10, Project \*sGENIE\*n
|
||||
%C Univ. Cal. at Berkeley
|
||||
%D April 1965
|
||||
|
||||
%A R. J. Feiertag
|
||||
%A E. I. Organick
|
||||
%T The Multics input-output system
|
||||
%J Proc. Third Symposium on Operating Systems Principles
|
||||
%D October 18-20, 1971
|
||||
%P 35-41
|
||||
|
||||
%A D. G. Bobrow
|
||||
%A J. D. Burchfiel
|
||||
%A D. L. Murphy
|
||||
%A R. S. Tomlinson
|
||||
%T \*sTENEX\*n, a Paged Time Sharing System for the \*sPDP\*n-10
|
||||
%J Comm. Assoc. Comp. Mach.
|
||||
%V 15
|
||||
%N 3
|
||||
%D March 1972
|
||||
%K tenex
|
||||
%P 135-143
|
||||
|
||||
%A R. E. Griswold
|
||||
%A D. R. Hanson
|
||||
%T An Overview of SL5
|
||||
%J SIGPLAN Notices
|
||||
%V 12
|
||||
%N 4
|
||||
%D April 1977
|
||||
%P 40-50
|
||||
|
||||
%A E. W. Dijkstra
|
||||
%T Cooperating Sequential Processes
|
||||
%B Programming Languages
|
||||
%E F. Genuys
|
||||
%I Academic Press
|
||||
%C New York
|
||||
%D 1968
|
||||
%P 43-112
|
||||
|
||||
%A J. A. Hawley
|
||||
%A W. B. Meyer
|
||||
%T M\s-2UNIX\s0, A Multiprocessing Version of U\s-2NIX\s0
|
||||
%K munix unix
|
||||
%R M.S. Thesis
|
||||
%I Naval Postgraduate School
|
||||
%C Monterey, Cal.
|
||||
%D 1975
|
||||
|
||||
%T The U\s-2NIX\s0 Time-Sharing System
|
||||
%K unix bstj
|
||||
%A D. M. Ritchie
|
||||
%A K. Thompson
|
||||
%J Bell Sys. Tech. J.
|
||||
%V 57
|
||||
%N 6
|
||||
%P 1905-1929
|
||||
%D 1978
|
||||
|
||||
%A E. I. Organick
|
||||
%T The M\s-2ULTICS\s0 System
|
||||
%K multics
|
||||
%I M.I.T. Press
|
||||
%C Cambridge, Mass.
|
||||
%D 1972
|
||||
|
||||
%T UNIX for Beginners
|
||||
%A B. W. Kernighan
|
||||
%D 1978
|
||||
|
||||
%T U\s-2NIX\s0 Programmer's Man\&ual
|
||||
%A K. Thompson
|
||||
%A D. M. Ritchie
|
||||
%K unix
|
||||
%I Bell Laboratories
|
||||
%O Seventh Edition.
|
||||
%D 1978
|
||||
|
||||
%A K. Thompson
|
||||
%T The U\s-2NIX\s0 Command Language
|
||||
%B Structured Programming\(emInfotech State of the Art Report
|
||||
%I Infotech International Ltd.
|
||||
%C Nicholson House, Maidenhead, Berkshire, England
|
||||
%D March 1975
|
||||
%P 375-384
|
||||
%K unix
|
||||
%X pwb
|
||||
Brief description of shell syntax and semantics, without much
|
||||
detail on implementation.
|
||||
Much on pipes and convenience of hooking programs together.
|
||||
Includes SERMONETTE:
|
||||
"Many familiar computing `concepts' are missing from UNIX.
|
||||
Files have no records. There are no access methods.
|
||||
There are no file types. These concepts fill a much-needed gap.
|
||||
I sincerely hope that when future systems are designed by
|
||||
manufacturers the value of some of these ingrained notions is re-examined.
|
||||
Like the politician and his `common man', manufacturers have
|
||||
their `average user'.
|
||||
|
||||
%A J. R. Mashey
|
||||
%T PWB/UNIX Shell Tutorial
|
||||
%D September 30, 1977
|
||||
|
||||
%A D. F. Hartley (Ed.)
|
||||
%T The Cambridge Multiple Access System \- Users Reference Manual
|
||||
%I University Mathematical Laboratory
|
||||
%C Cambridge, England
|
||||
%D 1968
|
||||
|
||||
%A P. A. Crisman (Ed.)
|
||||
%T The Compatible Time-Sharing System
|
||||
%I M.I.T. Press
|
||||
%K whole ctss book
|
||||
%C Cambridge, Mass.
|
||||
%D 1965
|
||||
|
||||
%T LR Parsing
|
||||
%A A. V. Aho
|
||||
%A S. C. Johnson
|
||||
%J Comp. Surveys
|
||||
%V 6
|
||||
%N 2
|
||||
%P 99-124
|
||||
%D June 1974
|
||||
|
||||
%T Deterministic Parsing of Ambiguous Grammars
|
||||
%A A. V. Aho
|
||||
%A S. C. Johnson
|
||||
%A J. D. Ullman
|
||||
%J Comm. Assoc. Comp. Mach.
|
||||
%K acm cacm
|
||||
%V 18
|
||||
%N 8
|
||||
%P 441-452
|
||||
%D August 1975
|
||||
|
||||
%A A. V. Aho
|
||||
%A J. D. Ullman
|
||||
%T Principles of Compiler Design
|
||||
%I Addison-Wesley
|
||||
%C Reading, Mass.
|
||||
%D 1977
|
||||
|
||||
.[
|
||||
%r 65
|
||||
%R Comp. Sci. Tech. Rep. No. 65
|
||||
%K CSTR
|
||||
%A S. C. Johnson
|
||||
%T Lint, a C Program Checker
|
||||
%D December 1977
|
||||
%O updated version TM 78-1273-3
|
||||
%D 1978
|
||||
.]
|
||||
|
||||
%T A Portable Compiler: Theory and Practice
|
||||
%A S. C. Johnson
|
||||
%J Proc. 5th ACM Symp. on Principles of Programming Languages
|
||||
%P 97-104
|
||||
%D January 1978
|
||||
|
||||
.[
|
||||
%r 39
|
||||
%K CSTR
|
||||
%R Comp. Sci. Tech. Rep. No. 39
|
||||
%I Bell Laboratories
|
||||
%C Murray Hill, New Jersey
|
||||
%A M. E. Lesk
|
||||
%T Lex \(em A Lexical Analyzer Generator
|
||||
%D October 1975
|
||||
.]
|
||||
|
||||
.[
|
||||
%r 32
|
||||
%K CSTR
|
||||
%R Comp. Sci. Tech. Rep. No. 32
|
||||
%I Bell Laboratories
|
||||
%C Murray Hill, New Jersey
|
||||
%A S. C. Johnson
|
||||
%T Yacc \(em Yet Another Compiler-Compiler
|
||||
%D July 1975
|
||||
.]
|
||||
|
||||
%T U\s-2NIX\s0 Time-Sharing System: Portability of C Programs and the U\s-2NIX\s0 System
|
||||
%K unix bstj
|
||||
%A S. C. Johnson
|
||||
%A D. M. Ritchie
|
||||
%J Bell Sys. Tech. J.
|
||||
%V 57
|
||||
%N 6
|
||||
%P 2021-2048
|
||||
%D 1978
|
||||
|
||||
%T Typing Documents on UNIX and GCOS: The -ms Macros for Troff
|
||||
%A M. E. Lesk
|
||||
%D 1977
|
||||
|
||||
%A K. Thompson
|
||||
%A D. M. Ritchie
|
||||
%T U\s-2NIX\s0 Programmer's Manual
|
||||
%K unix
|
||||
%I Bell Laboratories
|
||||
%O Sixth Edition
|
||||
%D May 1975
|
||||
|
||||
%T The Network U\s-2NIX\s0 System
|
||||
%K unix
|
||||
%A G. L. Chesson
|
||||
%J Operating Systems Review
|
||||
%V 9
|
||||
%N 5
|
||||
%P 60-66
|
||||
%D 1975
|
||||
%O Also in \f2Proc. 5th Symp. on Operating Systems Principles.\f1
|
||||
|
||||
%T Spider \(em An Experimental Data Communications System
|
||||
%Z ctr127
|
||||
%A A. G. Fraser
|
||||
%J Proc. IEEE Conf. on Communications
|
||||
%P 21F
|
||||
%O IEEE Cat. No. 74CH0859-9-CSCB.
|
||||
%D June 1974
|
||||
|
||||
%T A Virtual Channel Network
|
||||
%A A. G. Fraser
|
||||
%J Datamation
|
||||
%P 51-56
|
||||
%D February 1975
|
||||
|
||||
.[
|
||||
%r 41
|
||||
%K CSTR
|
||||
%R Comp. Sci. Tech. Rep. No. 41
|
||||
%I Bell Laboratories
|
||||
%C Murray Hill, New Jersey
|
||||
%A J. W. Hunt
|
||||
%A M. D. McIlroy
|
||||
%T An Algorithm for Differential File Comparison
|
||||
%D June 1976
|
||||
.]
|
||||
|
||||
%A F. P. Brooks, Jr.
|
||||
%T The Mythical Man-Month
|
||||
%I Addison-Wesley
|
||||
%C Reading, Mass.
|
||||
%D 1975
|
||||
%X pwb
|
||||
Readable, classic reference on software engineering and
|
||||
problems of large projects, from someone with experience in them.
|
||||
Required reading for any software engineer, even if conclusions may not
|
||||
always be agreed with.
|
||||
%br
|
||||
"The second is the most dangerous system a man every designs." p.55.
|
||||
%br
|
||||
"Hence plan to throw one away; you will, anyhow." p.116.
|
||||
%br
|
||||
"Cosgrove has perceptively pointed out that the programmer delivers
|
||||
satisfaction of a user need rather than any tangible product.
|
||||
And both the actual need and the user's perception of that need
|
||||
will change as programs are built, tested, and used." p.117.
|
||||
%br
|
||||
"The total cost of maintaining a widely used program is typically 40 percent
|
||||
or more of the cost of developing it." p.121.
|
||||
%br
|
||||
"As shown above, amalgamating prose and program reduces the total
|
||||
number of characters to be stored." p.175.
|
||||
|
||||
%T A Portable Compiler for the Language C
|
||||
%A A. Snyder
|
||||
%I Master's Thesis, M.I.T.
|
||||
%C Cambridge, Mass.
|
||||
%D 1974
|
||||
|
||||
%T The C Language Calling Sequence
|
||||
%A M. E. Lesk
|
||||
%A S. C. Johnson
|
||||
%A D. M. Ritchie
|
||||
%D 1977
|
||||
|
||||
%T Optimal Code Generation for Expression Trees
|
||||
%A A. V. Aho
|
||||
%A S. C. Johnson
|
||||
%D 1975
|
||||
%J J. Assoc. Comp. Mach.
|
||||
%K acm jacm
|
||||
%V 23
|
||||
%N 3
|
||||
%P 488-501
|
||||
%O Also in \f2Proc. ACM Symp. on Theory of Computing,\f1 pp. 207-217, 1975.
|
||||
|
||||
%A R. Sethi
|
||||
%A J. D. Ullman
|
||||
%T The Generation of Optimal Code for Arithmetic Expressions
|
||||
%J J. Assoc. Comp. Mach.
|
||||
%K acm jacm
|
||||
%V 17
|
||||
%N 4
|
||||
%D October 1970
|
||||
%P 715-728
|
||||
%O Reprinted as pp. 229-247 in \fICompiler Techniques\fR, ed. B. W. Pollack, Auerbach, Princeton NJ (1972).
|
||||
%X pwb
|
||||
Optimal approach for straight-line, fixed
|
||||
number of regs.
|
||||
|
||||
%T Code Generation for Machines with Multiregister
|
||||
Operations
|
||||
%A A. V. Aho
|
||||
%A S. C. Johnson
|
||||
%A J. D. Ullman
|
||||
%J Proc. 4th ACM Symp. on Principles of Programming Languages
|
||||
%P 21-28
|
||||
%D January 1977
|
||||
|
69
bin/sh/USD.doc/t.mac
Normal file
69
bin/sh/USD.doc/t.mac
Normal file
|
@ -0,0 +1,69 @@
|
|||
.\" $NetBSD: t.mac,v 1.2 2010/08/22 02:19:07 perry Exp $
|
||||
.\"
|
||||
.\" Copyright (C) Caldera International Inc. 2001-2002. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions are
|
||||
.\" met:
|
||||
.\"
|
||||
.\" Redistributions of source code and documentation must retain the above
|
||||
.\" copyright notice, this list of conditions and the following
|
||||
.\" disclaimer.
|
||||
.\"
|
||||
.\" Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\"
|
||||
.\" This product includes software developed or owned by Caldera
|
||||
.\" International, Inc. Neither the name of Caldera International, Inc.
|
||||
.\" nor the names of other contributors may be used to endorse or promote
|
||||
.\" products derived from this software without specific prior written
|
||||
.\" permission.
|
||||
.\"
|
||||
.\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
|
||||
.\" INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
|
||||
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
.\" DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
.\" OR OTHERWISE) RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)t.mac 8.1 (Berkeley) 8/14/93
|
||||
.\"
|
||||
.ds ZZ \fB.\|.\|.\fP
|
||||
.ds ST \v'.3m'\s+2*\s0\v'-.3m'
|
||||
.ds DO \h'\w'do 'u'
|
||||
.ds Ca \h'\w'case 'u'
|
||||
.ds WH \h'\w'while 'u'
|
||||
.ds VT \|\fB\(or\fP\|
|
||||
.ds TH \h'\w'then 'u'
|
||||
.ds DC \*(DO\*(Ca
|
||||
.ds AP >\h'-.2m'>
|
||||
.ds HE <\h'-.2m'<
|
||||
. \" macros for algol 68c reference manual
|
||||
.ds DA 1977 November 1
|
||||
.ds md \v'.25m'
|
||||
.ds mu \v'-.25m'
|
||||
.ds U \*(mu\s-3
|
||||
.ds V \s0\*(md
|
||||
.ds L \*(md\s-3
|
||||
.ds M \s0\*(mu
|
||||
.ds S \s-1
|
||||
.ds T \s0
|
||||
. \" small 1
|
||||
.ds O \*S1\*T
|
||||
.ds h \|
|
||||
.ds s \|\|
|
||||
. \" ellipsis
|
||||
.ds e .\|.\|.
|
||||
. \" subscripts
|
||||
.ds 1 \*(md\s-41\s0\*(mu
|
||||
.ds 2 \*(md\s-42\s0\*(mu
|
553
bin/sh/USD.doc/t1
Normal file
553
bin/sh/USD.doc/t1
Normal file
|
@ -0,0 +1,553 @@
|
|||
.\" $NetBSD: t1,v 1.3 2010/08/22 02:19:07 perry Exp $
|
||||
.\"
|
||||
.\" Copyright (C) Caldera International Inc. 2001-2002. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions are
|
||||
.\" met:
|
||||
.\"
|
||||
.\" Redistributions of source code and documentation must retain the above
|
||||
.\" copyright notice, this list of conditions and the following
|
||||
.\" disclaimer.
|
||||
.\"
|
||||
.\" Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgment:
|
||||
.\"
|
||||
.\" This product includes software developed or owned by Caldera
|
||||
.\" International, Inc. Neither the name of Caldera International, Inc.
|
||||
.\" nor the names of other contributors may be used to endorse or promote
|
||||
.\" products derived from this software without specific prior written
|
||||
.\" permission.
|
||||
.\"
|
||||
.\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
|
||||
.\" INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
|
||||
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
.\" DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
.\" OR OTHERWISE) RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)t1 8.1 (Berkeley) 8/14/93
|
||||
.\"
|
||||
.EH 'USD:3-%''An Introduction to the UNIX Shell'
|
||||
.OH 'An Introduction to the UNIX Shell''USD:3-%'
|
||||
.\".RP
|
||||
.TL
|
||||
An Introduction to the UNIX Shell
|
||||
.AU
|
||||
S. R. Bourne
|
||||
.AI
|
||||
Murray Hill, NJ
|
||||
.AU
|
||||
(Updated for 4.3BSD by Mark Seiden)
|
||||
.AU
|
||||
(Further updated by Perry E. Metzger)\(dg
|
||||
.AB
|
||||
.FS
|
||||
\(dg This paper was updated in 2010 to reflect most features of modern
|
||||
POSIX shells, which all follow the design of S.R. Bourne's original v7
|
||||
Unix shell.
|
||||
Among these are ash, bash, ksh and others.
|
||||
Typically one of these will be installed as /bin/sh on a modern system.
|
||||
It does not describe the behavior of the c shell (csh).
|
||||
If it's the c shell (csh) you're interested in, a good place to
|
||||
begin is William Joy's paper "An Introduction to the C shell" (USD:4).
|
||||
.FE
|
||||
.LP
|
||||
The
|
||||
.ul
|
||||
shell
|
||||
is a command programming language that provides an interface
|
||||
to the
|
||||
.UX
|
||||
operating system.
|
||||
Its features include
|
||||
control-flow primitives, parameter passing, variables and
|
||||
string substitution.
|
||||
Constructs such as
|
||||
.ul
|
||||
while, if then else, case
|
||||
and
|
||||
.ul
|
||||
for
|
||||
are available.
|
||||
Two-way communication is possible between the
|
||||
.ul
|
||||
shell
|
||||
and commands.
|
||||
String-valued parameters, typically file names or flags, may be
|
||||
passed to a command.
|
||||
A return code is set by commands that may be used to determine control-flow,
|
||||
and the standard output from a command may be used
|
||||
as shell input.
|
||||
.LP
|
||||
The
|
||||
.ul
|
||||
shell
|
||||
can modify the environment
|
||||
in which commands run.
|
||||
Input and output can be redirected
|
||||
to files, and processes that communicate through `pipes'
|
||||
can be invoked.
|
||||
Commands are found by
|
||||
searching directories
|
||||
in the file system in a
|
||||
sequence that can be defined by the user.
|
||||
Commands can be read either from the terminal or from a file,
|
||||
which allows command procedures to be
|
||||
stored for later use.
|
||||
.AE
|
||||
.ds ST \v'.3m'\s+2*\s0\v'-.3m'
|
||||
.SH
|
||||
1.0\ Introduction
|
||||
.LP
|
||||
The shell is both a command language
|
||||
and a programming language
|
||||
that provides an interface to the UNIX
|
||||
operating system.
|
||||
This memorandum describes, with
|
||||
examples, the UNIX shell.
|
||||
The first section covers most of the
|
||||
everyday requirements
|
||||
of terminal users.
|
||||
Some familiarity with UNIX
|
||||
is an advantage when reading this section;
|
||||
see, for example,
|
||||
"UNIX for beginners".
|
||||
.[
|
||||
unix beginn kernigh 1978
|
||||
.]
|
||||
Section 2 describes those features
|
||||
of the shell primarily intended
|
||||
for use within shell procedures.
|
||||
These include the control-flow
|
||||
primitives and string-valued variables
|
||||
provided by the shell.
|
||||
A knowledge of a programming language
|
||||
would be a help when reading this section.
|
||||
The last section describes the more
|
||||
advanced features of the shell.
|
||||
References of the form "see \fIpipe\fP (2)"
|
||||
are to a section of the UNIX manual.
|
||||
.[
|
||||
seventh 1978 ritchie thompson
|
||||
.]
|
||||
.SH
|
||||
1.1\ Simple\ commands
|
||||
.LP
|
||||
Simple commands consist of one or more words
|
||||
separated by blanks.
|
||||
The first word is the name of the command
|
||||
to be executed; any remaining words
|
||||
are passed as arguments to the command.
|
||||
For example,
|
||||
.DS
|
||||
who
|
||||
.DE
|
||||
is a command that prints the names
|
||||
of users logged in.
|
||||
The command
|
||||
.DS
|
||||
ls \(mil
|
||||
.DE
|
||||
prints a list of files in the current
|
||||
directory.
|
||||
The argument \fI\(mil\fP tells \fIls\fP
|
||||
to print status information, size and
|
||||
the creation date for each file.
|
||||
.SH
|
||||
1.2\ Input\ output\ redirection
|
||||
.LP
|
||||
Most commands produce output on the standard output
|
||||
that is initially connected to the terminal.
|
||||
This output may be sent to a file
|
||||
by writing, for example,
|
||||
.DS
|
||||
ls \(mil >file
|
||||
.DE
|
||||
The notation \fI>file\fP
|
||||
is interpreted by the shell and is not passed
|
||||
as an argument to \fIls.\fP
|
||||
If \fIfile\fP does not exist then the
|
||||
shell creates it;
|
||||
otherwise the original contents of
|
||||
\fIfile\fP are replaced with the output
|
||||
from \fIls.\fP
|
||||
Output may be appended to a file
|
||||
using the notation
|
||||
.DS
|
||||
ls \(mil \*(APfile
|
||||
.DE
|
||||
In this case \fIfile\fP is also created if it does not already
|
||||
exist.
|
||||
.LP
|
||||
The standard input of a command may be taken
|
||||
from a file instead of the terminal by
|
||||
writing, for example,
|
||||
.DS
|
||||
wc <file
|
||||
.DE
|
||||
The command \fIwc\fP reads its standard input
|
||||
(in this case redirected from \fIfile\fP)
|
||||
and prints the number of characters, words and
|
||||
lines found.
|
||||
If only the number of lines is required
|
||||
then
|
||||
.DS
|
||||
wc \(mil <file
|
||||
.DE
|
||||
could be used.
|
||||
.\" I considered adding the following, but have thought better of it
|
||||
.\" for now.
|
||||
.\" -- Perry Metzger
|
||||
.\"
|
||||
.\" .LP
|
||||
.\" Error messages are typically printed by commands on a different
|
||||
.\" channel, called standard error, which may also be redirected using the
|
||||
.\" notation 2>\|.
|
||||
.\" For example
|
||||
.\" .DS
|
||||
.\" command some args >out 2>errors
|
||||
.\" .DE
|
||||
.\" will redirect standard output to the file `out' but standard error
|
||||
.\" (and thus all error messages) to `errors'.
|
||||
.\" The notation 2>&1 sets standard error pointing to the same
|
||||
.\" place as standard out.
|
||||
.\" Thus:
|
||||
.\" .DS
|
||||
.\" command some args 2>&1 >everything
|
||||
.\" .DE
|
||||
.\" will put both standard out and standard error into the file `everything'.
|
||||
.\" See section 3.7 below for more details.
|
||||
.SH
|
||||
1.3\ Pipelines\ and\ filters
|
||||
.LP
|
||||
The standard output of one command may be
|
||||
connected to the standard input of another
|
||||
by writing
|
||||
the `pipe' operator,
|
||||
indicated by \*(VT,
|
||||
as in,
|
||||
.DS
|
||||
ls \(mil \*(VT wc
|
||||
.DE
|
||||
Two commands connected in this way constitute
|
||||
a \fIpipeline\fP and
|
||||
the overall effect is the same as
|
||||
.DS
|
||||
ls \(mil >file; wc <file
|
||||
.DE
|
||||
except that no \fIfile\fP is used.
|
||||
Instead the two \fIprocesses\fP are connected
|
||||
by a pipe (see \fIpipe\fP(2)) and are
|
||||
run in parallel.
|
||||
Pipes are unidirectional and
|
||||
synchronization is achieved by
|
||||
halting \fIwc\fP when there is
|
||||
nothing to read and halting \fIls\fP
|
||||
when the pipe is full.
|
||||
.LP
|
||||
A \fIfilter\fP is a command
|
||||
that reads its standard input,
|
||||
transforms it in some way,
|
||||
and prints the result as output.
|
||||
One such filter, \fIgrep,\fP
|
||||
selects from its input those lines
|
||||
that contain some specified string.
|
||||
For example,
|
||||
.DS
|
||||
ls \*(VT grep old
|
||||
.DE
|
||||
prints those lines, if any, of the output
|
||||
from \fIls\fP that contain
|
||||
the string \fIold.\fP
|
||||
Another useful filter is \fIsort\fP.
|
||||
For example,
|
||||
.DS
|
||||
who \*(VT sort
|
||||
.DE
|
||||
will print an alphabetically sorted list
|
||||
of logged in users.
|
||||
.LP
|
||||
A pipeline may consist of more than two commands,
|
||||
for example,
|
||||
.DS
|
||||
ls \*(VT grep old \*(VT wc \(mil
|
||||
.DE
|
||||
prints the number of file names
|
||||
in the current directory containing
|
||||
the string \fIold.\fP
|
||||
.SH
|
||||
1.4\ Background\ commands
|
||||
.LP
|
||||
To execute a command (or pipeline) the shell normally
|
||||
creates the new \fIprocesses\fP
|
||||
and waits for them to finish.
|
||||
A command may be run without waiting
|
||||
for it to finish.
|
||||
For example,
|
||||
.DS
|
||||
cc pgm.c &
|
||||
.DE
|
||||
calls the C compiler to compile
|
||||
the file \fIpgm.c\|.\fP
|
||||
The trailing \fB&\fP is an operator that instructs the shell
|
||||
not to wait for the command to finish.
|
||||
To help keep track of such a process
|
||||
the shell reports its job number (see below) and process
|
||||
id following its creation.
|
||||
Such a command is said to be running in the \fIbackground\fP.
|
||||
By contrast, a command executed without the \fB&\fP is said to be
|
||||
running in the \fIforeground\fP.\(dg
|
||||
.FS
|
||||
\(dg Even after execution, one may move commands from the foreground
|
||||
to the background, or temporarily suspend their execution (which is
|
||||
known as \fIstopping\fP a command.
|
||||
This is described in detail in section 3.10 on \fIJob Control\fB.
|
||||
.FE
|
||||
.LP
|
||||
A list of currently active processes, including ones not associated
|
||||
with the current shell, may be obtained using the \fIps\fP(1) command.
|
||||
.SH
|
||||
1.5\ File\ name\ generation
|
||||
.LP
|
||||
Many commands accept arguments
|
||||
which are file names.
|
||||
For example,
|
||||
.DS
|
||||
ls \(mil main.c
|
||||
.DE
|
||||
prints information relating to the file \fImain.c\fP\|.
|
||||
.LP
|
||||
The shell provides a mechanism
|
||||
for generating a list of file names
|
||||
that match a pattern.
|
||||
For example,
|
||||
.DS
|
||||
ls \(mil \*(ST.c
|
||||
.DE
|
||||
generates, as arguments to \fIls,\fP
|
||||
all file names in the current directory that end in \fI.c\|.\fP
|
||||
The character \*(ST is a pattern that will match any string
|
||||
including the null string.
|
||||
In general \fIpatterns\fP are specified
|
||||
as follows.
|
||||
.RS
|
||||
.IP \fB\*(ST\fR 8
|
||||
Matches any string of characters
|
||||
including the null string.
|
||||
.IP \fB?\fR 8
|
||||
Matches any single character.
|
||||
.IP \fB[\*(ZZ]\fR 8
|
||||
Matches any one of the characters
|
||||
enclosed.
|
||||
A pair of characters separated by a minus will
|
||||
match any character lexically between
|
||||
the pair.
|
||||
.RE
|
||||
.LP
|
||||
For example,
|
||||
.DS
|
||||
[a\(miz]\*(ST
|
||||
.DE
|
||||
matches all names in the current directory
|
||||
beginning with
|
||||
one of the letters \fIa\fP through \fIz.\fP
|
||||
.DS
|
||||
/usr/fred/test/?
|
||||
.DE
|
||||
matches all names in the directory
|
||||
\fB/usr/fred/test\fP that consist of a single character.
|
||||
If no file name is found that matches
|
||||
the pattern then the pattern is passed,
|
||||
unchanged, as an argument.
|
||||
.LP
|
||||
This mechanism is useful both to save typing
|
||||
and to select names according to some pattern.
|
||||
It may also be used to find files.
|
||||
For example,
|
||||
.DS
|
||||
echo /usr/fred/\*(ST/core
|
||||
.DE
|
||||
finds and prints the names of all \fIcore\fP files in sub-directories
|
||||
of \fB/usr/fred\|.\fP
|
||||
(\fIecho\fP is a standard UNIX command that prints
|
||||
its arguments, separated by blanks.)
|
||||
This last feature can be expensive,
|
||||
requiring a scan of all
|
||||
sub-directories of \fB/usr/fred\|.\fP
|
||||
.LP
|
||||
There is one exception to the general
|
||||
rules given for patterns.
|
||||
The character `\fB.\fP'
|
||||
at the start of a file name must be explicitly
|
||||
matched.
|
||||
.DS
|
||||
echo \*(ST
|
||||
.DE
|
||||
will therefore echo all file names in the current
|
||||
directory not beginning
|
||||
with `\fB.\fP'\|.
|
||||
.DS
|
||||
echo \fB.\fP\*(ST
|
||||
.DE
|
||||
will echo all those file names that begin with `\fB.\fP'\|.
|
||||
This avoids inadvertent matching
|
||||
of the names `\fB.\fP' and `\fB..\fP'
|
||||
which mean `the current directory'
|
||||
and `the parent directory'
|
||||
respectively.
|
||||
(Notice that \fIls\fP suppresses
|
||||
information for the files `\fB.\fP' and `\fB..\fP'\|.)
|
||||
.LP
|
||||
Finally, the tilde character, `\fB\(ap\fP', may be used to indicate the
|
||||
home directory of a user.
|
||||
The `\fB\(ap\fP' at the beginning of a path name followed by a
|
||||
non-alphabetic character expands to the current user's home
|
||||
directory.
|
||||
If the `\fB\(ap\fP' is followed by a login name, it expands to the named
|
||||
user's home directory.
|
||||
For example:
|
||||
.DS
|
||||
ls \(ap
|
||||
cd \(apegbert/
|
||||
.DE
|
||||
will list the contents of the user's home directory and then change
|
||||
to the home directory of the user ``egbert''.
|
||||
.SH
|
||||
1.6\ Quoting
|
||||
.LP
|
||||
Characters that have a special meaning
|
||||
to the shell, such as \fB< > \*(ST ? \*(VT &\|,\fR
|
||||
are called metacharacters.
|
||||
A complete list of metacharacters is given
|
||||
in appendix B.
|
||||
Any character preceded by a \fB\\\fR is \fIquoted\fP
|
||||
and loses its special meaning, if any.
|
||||
The \fB\\\fP is elided so that
|
||||
.DS
|
||||
echo \\?
|
||||
.DE
|
||||
will echo a single \fB?\|,\fP
|
||||
and
|
||||
.DS
|
||||
echo \\\\
|
||||
.DE
|
||||
will echo a single \fB\\\|.\fR
|
||||
To allow long strings to be continued over
|
||||
more than one line
|
||||
the sequence \fB\\newline\fP
|
||||
is ignored.
|
||||
.LP
|
||||
\fB\\\fP is convenient for quoting
|
||||
single characters.
|
||||
When more than one character needs
|
||||
quoting the above mechanism is clumsy and
|
||||
error prone.
|
||||
A string of characters may be quoted
|
||||
by enclosing the string between single quotes.
|
||||
For example,
|
||||
.DS
|
||||
echo xx\'\*(ST\*(ST\*(ST\*(ST\'xx
|
||||
.DE
|
||||
will echo
|
||||
.DS
|
||||
xx\*(ST\*(ST\*(ST\*(STxx
|
||||
.DE
|
||||
The quoted string may not contain
|
||||
a single quote
|
||||
but may contain newlines, which are preserved.
|
||||
This quoting mechanism is the most
|
||||
simple and is recommended
|
||||
for casual use.
|
||||
.LP
|
||||
A third quoting mechanism using double quotes
|
||||
is also available
|
||||
that prevents interpretation of some but not all
|
||||
metacharacters.
|
||||
Discussion of the
|
||||
details is deferred
|
||||
to section 3.5\|.
|
||||
.SH
|
||||
1.7\ Prompting
|
||||
.LP
|
||||
When the shell is used from a terminal it will
|
||||
issue a prompt before reading a command.
|
||||
By default this prompt is `\fB$\ \fR'\|.
|
||||
It may be changed by saying,
|
||||
for example,
|
||||
.DS
|
||||
\s-1PS1\s0="yesdear$ "
|
||||
.DE
|
||||
that sets the prompt to be the string \fIyesdear$\|.\fP
|
||||
If a newline is typed and further input is needed
|
||||
then the shell will issue the prompt `\fB>\ \fR'\|.
|
||||
Sometimes this can be caused by mistyping
|
||||
a quote mark.
|
||||
If it is unexpected then entering the interrupt character
|
||||
(typically \s-1CONTROL-C\s0)
|
||||
will return the shell to read another command.
|
||||
This prompt may be changed by saying, for example,
|
||||
.DS
|
||||
\s-1PS2\s0=more
|
||||
.DE
|
||||
Entering the interrupt character may also be used to terminate most
|
||||
programs running as the current foreground job.
|
||||
.LP
|
||||
(\s-1PS1\s0 and \s-1PS2\s0 are \fIshell variables\fP, which will be
|
||||
described in section 2.4 below.)
|
||||
.SH
|
||||
1.8\ The\ shell\ and\ login
|
||||
.LP
|
||||
Following \fIlogin\fP(1)
|
||||
the shell is called to read and execute
|
||||
commands typed at the terminal.
|
||||
If the user's login directory
|
||||
contains the file \fB.profile\fP
|
||||
then it is assumed to contain commands
|
||||
and is read by the shell before reading
|
||||
any commands from the terminal.
|
||||
.LP
|
||||
(Most versions of the shell also specify a file that is read and
|
||||
executed on start-up whether or not the shell is invoked by login.
|
||||
The \s-1ENV\s0 shell variable, described in section 2.4 below, can be
|
||||
used to override the name of this file.
|
||||
See the shell manual page for further information.)
|
||||
.SH
|
||||
1.9\ Summary
|
||||
.sp
|
||||
.RS
|
||||
.IP \(bu
|
||||
\fBls\fP
|
||||
.br
|
||||
Print the names of files in the current directory.
|
||||
.IP \(bu
|
||||
\fBls >file\fP
|
||||
.br
|
||||
Put the output from \fIls\fP into \fIfile.\fP
|
||||
.IP \(bu
|
||||
\fBls \*(VT wc \(mil\fR
|
||||
.br
|
||||
Print the number of files in the current directory.
|
||||
.IP \(bu
|
||||
\fBls \*(VT grep old\fR
|
||||
.br
|
||||
Print those file names containing the string \fIold.\fP
|
||||
.IP \(bu
|
||||
\fBls \*(VT grep old \*(VT wc \(mil\fR
|
||||
.br
|
||||
Print the number of files whose name contains the string \fIold.\fP
|
||||
.IP \(bu
|
||||
\fBcc pgm.c &\fR
|
||||
.br
|
||||
Run \fIcc\fP in the background.
|
||||
.RE
|
971
bin/sh/USD.doc/t2
Normal file
971
bin/sh/USD.doc/t2
Normal file
|
@ -0,0 +1,971 @@
|
|||
.\" $NetBSD: t2,v 1.3 2010/08/22 02:19:07 perry Exp $
|
||||
.\"
|
||||
.\" Copyright (C) Caldera International Inc. 2001-2002. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions are
|
||||
.\" met:
|
||||
.\"
|
||||
.\" Redistributions of source code and documentation must retain the above
|
||||
.\" copyright notice, this list of conditions and the following
|
||||
.\" disclaimer.
|
||||
.\"
|
||||
.\" Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgment:
|
||||
.\"
|
||||
.\" This product includes software developed or owned by Caldera
|
||||
.\" International, Inc. Neither the name of Caldera International, Inc.
|
||||
.\" nor the names of other contributors may be used to endorse or promote
|
||||
.\" products derived from this software without specific prior written
|
||||
.\" permission.
|
||||
.\"
|
||||
.\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
|
||||
.\" INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
|
||||
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
.\" DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
.\" OR OTHERWISE) RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)t2 8.1 (Berkeley) 6/8/93
|
||||
.\"
|
||||
.SH
|
||||
2.0\ Shell\ scripts
|
||||
.LP
|
||||
The shell may be used to read and execute commands
|
||||
contained in a file.
|
||||
For example,
|
||||
.DS
|
||||
sh file [ args \*(ZZ ]
|
||||
.DE
|
||||
calls the shell to read commands from \fIfile.\fP
|
||||
Such a file is called a \fIshell script.\fP
|
||||
Arguments may be supplied with the call
|
||||
and are referred to in \fIfile\fP
|
||||
using the positional parameters
|
||||
\fB$1, $2, \*(ZZ\|.\fR
|
||||
.LP
|
||||
For example, if the file \fIwg\fP contains
|
||||
.DS
|
||||
who \*(VT grep $1
|
||||
.DE
|
||||
then
|
||||
.DS
|
||||
sh wg fred
|
||||
.DE
|
||||
is equivalent to
|
||||
.DS
|
||||
who \*(VT grep fred
|
||||
.DE
|
||||
.LP
|
||||
UNIX files have three independent attributes,
|
||||
\fIread,\fP \fIwrite\fP and \fIexecute.\fP
|
||||
The UNIX command \fIchmod\fP(1) may be used
|
||||
to make a file executable.
|
||||
For example,
|
||||
.DS
|
||||
chmod +x wg
|
||||
.DE
|
||||
will ensure that the file \fIwg\fP has execute status.
|
||||
Following this, the command
|
||||
.DS
|
||||
wg fred
|
||||
.DE
|
||||
is equivalent to
|
||||
.DS
|
||||
sh wg fred
|
||||
.DE
|
||||
This allows shell scripts and other programs
|
||||
to be used interchangeably.
|
||||
In either case a new process is created to
|
||||
run the command.
|
||||
.LP
|
||||
The `\fB#\fP' character is used as a comment character by the shell.
|
||||
All characters following the `#' on a line are ignored.
|
||||
.LP
|
||||
A typical modern system has several different shells, some with differing
|
||||
command syntax, and it is desirable to specify which one should be
|
||||
invoked when an executable script is invoked.
|
||||
If the special comment
|
||||
.DS
|
||||
#!/\fIpath\fP/\fIto\fP/\fIinterpreter\fP
|
||||
.DE
|
||||
appears as the first line in a script, it is used to specify the
|
||||
absolute pathname of the shell (or other interpreter) that should be
|
||||
used to execute the file.
|
||||
(Without such a line, \fB/bin/sh\fP is assumed.)
|
||||
It is best if a script explicitly states
|
||||
what shell it is intended for in this manner.
|
||||
.LP
|
||||
As well as providing names for the positional
|
||||
parameters,
|
||||
the number of positional parameters to a script
|
||||
is available as \fB$#\|.\fP
|
||||
The name of the file being executed
|
||||
is available as \fB$0\|.\fP
|
||||
.LP
|
||||
A special shell parameter \fB$\*(ST\fP
|
||||
is used to substitute for all positional parameters
|
||||
except \fB$0\|.\fP
|
||||
A typical use of this is to provide
|
||||
some default arguments,
|
||||
as in,
|
||||
.DS
|
||||
nroff \(miT450 \(mims $\*(ST
|
||||
.DE
|
||||
which simply prepends some arguments
|
||||
to those already given.
|
||||
(The variable \fB$@\fP also expands to ``all positional
|
||||
parameters'', but is subtly different when expanded inside quotes.
|
||||
See section 3.5, below.)
|
||||
.SH
|
||||
2.1\ Control\ flow\ -\ for
|
||||
.LP
|
||||
A frequent use of shell scripts is to loop
|
||||
through the arguments (\fB$1, $2, \*(ZZ\fR)
|
||||
executing commands once for each argument.
|
||||
An example of such a script is
|
||||
\fItel\fP that searches the file
|
||||
\fB/usr/share/telnos\fR
|
||||
that contains lines of the form
|
||||
.DS
|
||||
\*(ZZ
|
||||
fred mh0123
|
||||
bert mh0789
|
||||
\*(ZZ
|
||||
.DE
|
||||
The text of \fItel\fP is
|
||||
.DS
|
||||
#!/bin/sh
|
||||
|
||||
for i
|
||||
do
|
||||
grep $i /usr/share/telnos
|
||||
done
|
||||
.DE
|
||||
The command
|
||||
.DS
|
||||
tel fred
|
||||
.DE
|
||||
prints those lines in \fB/usr/share/telnos\fR
|
||||
that contain the string \fIfred\|.\fP
|
||||
.DS
|
||||
tel fred bert
|
||||
.DE
|
||||
prints those lines containing \fIfred\fP
|
||||
followed by those for \fIbert.\fP
|
||||
.LP
|
||||
The \fBfor\fP loop notation is recognized by the shell
|
||||
and has the general form
|
||||
.DS
|
||||
\fBfor\fR \fIname\fR \fBin\fR \fIw1 w2 \*(ZZ\fR
|
||||
\fBdo\fR \fIcommand-list\fR
|
||||
\fBdone\fR
|
||||
.DE
|
||||
A \fIcommand-list\fP is a sequence of one or more
|
||||
simple commands separated or terminated by a newline or semicolon.
|
||||
Furthermore, reserved words
|
||||
like \fBdo\fP and \fBdone\fP are only
|
||||
recognized following a newline or
|
||||
semicolon.
|
||||
\fIname\fP is a shell variable that is set
|
||||
to the words \fIw1 w2 \*(ZZ\fR in turn each time the \fIcommand-list\fP
|
||||
following \fBdo\fP
|
||||
is executed.
|
||||
If \fBin\fR \fIw1 w2 \*(ZZ\fR
|
||||
is omitted then the loop
|
||||
is executed once for each positional parameter;
|
||||
that is, \fBin\fR \fI$\*(ST\fR is assumed.
|
||||
.LP
|
||||
Another example of the use of the \fBfor\fP
|
||||
loop is the \fIcreate\fP command
|
||||
whose text is
|
||||
.DS
|
||||
for i do >$i; done
|
||||
.DE
|
||||
The command
|
||||
.DS
|
||||
create alpha beta
|
||||
.DE
|
||||
ensures that two empty files
|
||||
\fIalpha\fP and \fIbeta\fP exist
|
||||
and are empty.
|
||||
The notation \fI>file\fP may be used on its
|
||||
own to create or clear the contents of a file.
|
||||
Notice also that a semicolon (or newline) is required before \fBdone.\fP
|
||||
.SH
|
||||
2.2\ Control\ flow\ -\ case
|
||||
.LP
|
||||
A multiple way branch is provided for by the
|
||||
\fBcase\fP notation.
|
||||
For example,
|
||||
.DS
|
||||
case $# in
|
||||
\*(Ca1) cat \*(AP$1 ;;
|
||||
\*(Ca2) cat \*(AP$2 <$1 ;;
|
||||
\*(Ca\*(ST) echo \'usage: append [ from ] to\' ;;
|
||||
esac
|
||||
.DE
|
||||
is an \fIappend\fP command.
|
||||
When called
|
||||
with one argument as
|
||||
.DS
|
||||
append file
|
||||
.DE
|
||||
\fB$#\fP is the string \fI1\fP and
|
||||
the standard input is copied onto the
|
||||
end of \fIfile\fP
|
||||
using the \fIcat\fP command.
|
||||
.DS
|
||||
append file1 file2
|
||||
.DE
|
||||
appends the contents of \fIfile1\fP
|
||||
onto \fIfile2.\fP
|
||||
If the number of arguments supplied to
|
||||
\fIappend\fP is other than 1 or 2
|
||||
then a message is printed indicating
|
||||
proper usage.
|
||||
.LP
|
||||
The general form of the \fBcase\fP command
|
||||
is
|
||||
.DS
|
||||
\fBcase \fIword \fBin
|
||||
\*(Ca\fIpattern\|\fB)\ \fIcommand-list\fB\|;;
|
||||
\*(Ca\*(ZZ
|
||||
\fBesac\fR
|
||||
.DE
|
||||
The shell attempts to match
|
||||
\fIword\fR with each \fIpattern,\fR
|
||||
in the order in which the patterns
|
||||
appear.
|
||||
If a match is found the
|
||||
associated \fIcommand-list\fP is
|
||||
executed and execution
|
||||
of the \fBcase\fP is complete.
|
||||
Since \*(ST is the pattern that matches any
|
||||
string it can be used for the default case.
|
||||
.LP
|
||||
A word of caution:
|
||||
no check is made to ensure that only
|
||||
one pattern matches
|
||||
the case argument.
|
||||
The first match found defines the set of commands
|
||||
to be executed.
|
||||
In the example below the commands following
|
||||
the second \*(ST will never be executed.
|
||||
.DS
|
||||
case $# in
|
||||
\*(Ca\*(ST) \*(ZZ ;;
|
||||
\*(Ca\*(ST) \*(ZZ ;;
|
||||
esac
|
||||
.DE
|
||||
.LP
|
||||
Another example of the use of the \fBcase\fP
|
||||
construction is to distinguish
|
||||
between different forms
|
||||
of an argument.
|
||||
The following example is a fragment of a \fIcc\fP command.
|
||||
.DS
|
||||
for i
|
||||
do case $i in
|
||||
\*(DC\(mi[ocs]) \*(ZZ ;;
|
||||
\*(DC\(mi\*(ST) echo "unknown flag $i" ;;
|
||||
\*(DC\*(ST.c) /lib/c0 $i \*(ZZ ;;
|
||||
\*(DC\*(ST) echo "unexpected argument $i" ;;
|
||||
\*(DOesac
|
||||
done
|
||||
.DE
|
||||
.LP
|
||||
To allow the same commands to be associated
|
||||
with more than one pattern
|
||||
the \fBcase\fP command provides
|
||||
for alternative patterns
|
||||
separated by a \*(VT\|.
|
||||
For example,
|
||||
.DS
|
||||
case $i in
|
||||
\*(Ca\(mix\*(VT\(miy) \*(ZZ
|
||||
esac
|
||||
.DE
|
||||
is equivalent to
|
||||
.DS
|
||||
case $i in
|
||||
\*(Ca\(mi[xy]) \*(ZZ
|
||||
esac
|
||||
.DE
|
||||
.LP
|
||||
The usual quoting conventions apply
|
||||
so that
|
||||
.DS
|
||||
case $i in
|
||||
\*(Ca\\?) \*(ZZ
|
||||
.DE
|
||||
will match the character \fB?\|.\fP
|
||||
.SH
|
||||
2.3\ Here\ documents
|
||||
.LP
|
||||
The shell script \fItel\fP
|
||||
in section 2.1 uses the file \fB/usr/share/telnos\fR
|
||||
to supply the data
|
||||
for \fIgrep.\fP
|
||||
An alternative is to include this
|
||||
data
|
||||
within the shell script as a \fIhere\fP document, as in,
|
||||
.DS
|
||||
for i
|
||||
do grep $i \*(HE!
|
||||
\*(DO\*(ZZ
|
||||
\*(DOfred mh0123
|
||||
\*(DObert mh0789
|
||||
\*(DO\*(ZZ
|
||||
!
|
||||
done
|
||||
.DE
|
||||
In this example
|
||||
the shell takes the lines between \fB\*(HE!\fR and \fB!\fR
|
||||
as the standard input for \fIgrep.\fP
|
||||
The string \fB!\fR is arbitrary, the document
|
||||
being terminated by a line that consists
|
||||
of the string following \*(HE\|.
|
||||
.LP
|
||||
Parameters are substituted in the document
|
||||
before it is made available to \fIgrep\fP
|
||||
as illustrated by the following script
|
||||
called \fIedg\|.\fP
|
||||
.DS
|
||||
ed $3 \*(HE%
|
||||
g/$1/s//$2/g
|
||||
w
|
||||
%
|
||||
.DE
|
||||
The call
|
||||
.DS
|
||||
edg string1 string2 file
|
||||
.DE
|
||||
is then equivalent to the command
|
||||
.DS
|
||||
ed file \*(HE%
|
||||
g/string1/s//string2/g
|
||||
w
|
||||
%
|
||||
.DE
|
||||
and changes all occurrences of \fIstring1\fP
|
||||
in \fIfile\fP to \fIstring2\|.\fP
|
||||
Substitution can be prevented using \\
|
||||
to quote the special character \fB$\fP
|
||||
as in
|
||||
.DS
|
||||
ed $3 \*(HE+
|
||||
1,\\$s/$1/$2/g
|
||||
w
|
||||
+
|
||||
.DE
|
||||
(This version of \fIedg\fP is equivalent to
|
||||
the first except that \fIed\fP will print
|
||||
a \fB?\fR if there are no occurrences of
|
||||
the string \fB$1\|.\fP)
|
||||
Substitution within a \fIhere\fP document
|
||||
may be prevented entirely by quoting
|
||||
the terminating string,
|
||||
for example,
|
||||
.DS
|
||||
grep $i \*(HE'end'
|
||||
\*(ZZ
|
||||
end
|
||||
.DE
|
||||
The document is presented
|
||||
without modification to \fIgrep.\fP
|
||||
If parameter substitution is not required
|
||||
in a \fIhere\fP document this latter form
|
||||
is more efficient.
|
||||
.SH
|
||||
2.4\ Shell\ variables\(dg
|
||||
.LP
|
||||
.FS
|
||||
Also known as \fIenvironment variables\fB, see \fIenvironment\fB(7).
|
||||
.FE
|
||||
The shell
|
||||
provides string-valued variables.
|
||||
Variable names begin with a letter
|
||||
and consist of letters, digits and
|
||||
underscores.
|
||||
Variables may be given values by writing, for example,
|
||||
.DS
|
||||
user=fred\ box=m000\ acct=mh0000
|
||||
.DE
|
||||
which assigns values to the variables
|
||||
\fBuser, box\fP and \fBacct.\fP
|
||||
A variable may be set to the null string
|
||||
by saying, for example,
|
||||
.DS
|
||||
null=
|
||||
.DE
|
||||
The value of a variable is substituted
|
||||
by preceding its name with \fB$\|\fP;
|
||||
for example,
|
||||
.DS
|
||||
echo $user
|
||||
.DE
|
||||
will echo \fIfred.\fP
|
||||
.LP
|
||||
Variables may be used interactively
|
||||
to provide abbreviations for frequently
|
||||
used strings.
|
||||
For example,
|
||||
.DS
|
||||
b=/usr/fred/bin
|
||||
mv pgm $b
|
||||
.DE
|
||||
will move the file \fIpgm\fP
|
||||
from the current directory to the directory \fB/usr/fred/bin\|.\fR
|
||||
A more general notation is available for parameter
|
||||
(or variable)
|
||||
substitution, as in,
|
||||
.DS
|
||||
echo ${user}
|
||||
.DE
|
||||
which is equivalent to
|
||||
.DS
|
||||
echo $user
|
||||
.DE
|
||||
and is used when the parameter name is
|
||||
followed by a letter or digit.
|
||||
For example,
|
||||
.DS
|
||||
tmp=/tmp/ps
|
||||
ps a >${tmp}a
|
||||
.DE
|
||||
will direct the output of \fIps\fR
|
||||
to the file \fB/tmp/psa,\fR
|
||||
whereas,
|
||||
.DS
|
||||
ps a >$tmpa
|
||||
.DE
|
||||
would cause the value of the variable \fBtmpa\fP
|
||||
to be substituted.
|
||||
.LP
|
||||
Except for \fB$?\fP the following
|
||||
are set initially by the shell.
|
||||
\fB$?\fP is set after executing each command.
|
||||
.RS
|
||||
.IP \fB$?\fP 8
|
||||
The exit status (return code)
|
||||
of the last command executed
|
||||
as a decimal string.
|
||||
Most commands return a zero exit status
|
||||
if they complete successfully,
|
||||
otherwise a non-zero exit status is returned.
|
||||
Testing the value of return codes is dealt with
|
||||
later under \fBif\fP and \fBwhile\fP commands.
|
||||
.IP \fB$#\fP 8
|
||||
The number of positional parameters
|
||||
(in decimal).
|
||||
Used, for example, in the \fIappend\fP command
|
||||
to check the number of parameters.
|
||||
.IP \fB$$\fP 8
|
||||
The process number of this shell (in decimal).
|
||||
Since process numbers are unique among
|
||||
all existing processes, this string is
|
||||
frequently used to generate
|
||||
unique
|
||||
temporary file names.
|
||||
For example,
|
||||
.DS
|
||||
ps a >/tmp/ps$$
|
||||
\*(ZZ
|
||||
rm /tmp/ps$$
|
||||
.DE
|
||||
.IP \fB$\|!\fP 8
|
||||
The process number of the last process
|
||||
run in the background (in decimal).
|
||||
.IP \fB$\(mi\fP 8
|
||||
The current shell flags, such as
|
||||
\fB\(mix\fR and \fB\(miv\|.\fR
|
||||
.RE
|
||||
.LP
|
||||
Some variables have a special meaning to the
|
||||
shell and should be avoided for general
|
||||
use.
|
||||
.RS
|
||||
.IP \fB$\s-1MAIL\s0\fP 8
|
||||
When used interactively
|
||||
the shell looks at the file
|
||||
specified by this variable
|
||||
before it issues a prompt.
|
||||
If the specified file has been modified
|
||||
since it
|
||||
was last looked at the shell
|
||||
prints the message
|
||||
\fIyou have mail\fP before prompting
|
||||
for the next command.
|
||||
This variable is typically set
|
||||
in the file \fB.profile,\fP
|
||||
in the user's login directory.
|
||||
For example,
|
||||
.DS
|
||||
\s-1MAIL\s0=/usr/spool/mail/fred
|
||||
.DE
|
||||
.IP \fB$\s-1HOME\s0\fP 8
|
||||
The default argument
|
||||
for the \fIcd\fP command.
|
||||
The current directory is used to resolve
|
||||
file name references that do not begin with
|
||||
a \fB/\|,\fR
|
||||
and is changed using the \fIcd\fP command.
|
||||
For example,
|
||||
.DS
|
||||
cd /usr/fred/bin
|
||||
.DE
|
||||
makes the current directory \fB/usr/fred/bin\|.\fR
|
||||
.DS
|
||||
cat wn
|
||||
.DE
|
||||
will print on the terminal the file \fIwn\fP
|
||||
in this directory.
|
||||
The command
|
||||
\fIcd\fP with no argument
|
||||
is equivalent to
|
||||
.DS
|
||||
cd $\s-1HOME\s0
|
||||
.DE
|
||||
This variable is also typically set in the
|
||||
the user's login profile.
|
||||
.IP \fB$\s-1PWD\s0\fP 8
|
||||
The current working directory. Set by the \fIcd\fB command.
|
||||
.IP \fB$\s-1PATH\s0\fP 8
|
||||
A list of directories that contain commands (the \fIsearch path\fR\|).
|
||||
Each time a command is executed by the shell
|
||||
a list of directories is searched
|
||||
for an executable file.
|
||||
.ne 5
|
||||
If \fB$\s-1PATH\s0\fP is not set
|
||||
then the current directory,
|
||||
\fB/bin\fP, and \fB/usr/bin\fP are searched by default.
|
||||
.ne 5
|
||||
Otherwise \fB$\s-1PATH\s0\fP consists of directory
|
||||
names separated by \fB:\|.\fP
|
||||
For example,
|
||||
.DS
|
||||
\s-1PATH\s0=\fB:\fP/usr/fred/bin\fB:\fP/bin\fB:\fP/usr/bin
|
||||
.DE
|
||||
specifies that the current directory
|
||||
(the null string before the first \fB:\fP\|),
|
||||
\fB/usr/fred/bin, /bin \fRand\fP /usr/bin\fR
|
||||
are to be searched in that order.
|
||||
In this way individual users
|
||||
can have their own `private' commands
|
||||
that are accessible independently
|
||||
of the current directory.
|
||||
If the command name contains a \fB/\fR then this directory search
|
||||
is not used; a single attempt
|
||||
is made to execute the command.
|
||||
.IP \fB$\s-1PS1\s0\fP 8
|
||||
The primary shell prompt string, by default, `\fB$\ \fR'.
|
||||
.IP \fB$\s-1PS2\s0\fP 8
|
||||
The shell prompt when further input is needed,
|
||||
by default, `\fB>\ \fR'.
|
||||
.IP \fB$\s-1IFS\s0\fP 8
|
||||
The set of characters used by \fIblank
|
||||
interpretation\fR (see section 3.5).
|
||||
.IP \fB$\s-1ENV\s0\fP 8
|
||||
The shell reads and executes the commands in the file
|
||||
specified by this variable when it is initially started.
|
||||
Unlike the \fB.profile\fP file, these commands are executed by all
|
||||
shells, not just the one started at login.
|
||||
(Most versions of the shell specify a filename that is used if
|
||||
\s-1ENV\s0 is not explicitly set. See the manual page for your shell.)
|
||||
.RE
|
||||
.SH
|
||||
2.5\ The\ test\ command
|
||||
.LP
|
||||
The \fItest\fP command, although not part of the shell,
|
||||
is intended for use by shell programs.
|
||||
For example,
|
||||
.DS
|
||||
test \(mif file
|
||||
.DE
|
||||
returns zero exit status if \fIfile\fP
|
||||
exists and non-zero exit status otherwise.
|
||||
In general \fItest\fP evaluates a predicate
|
||||
and returns the result as its exit status.
|
||||
Some of the more frequently used \fItest\fP
|
||||
arguments are given here, see \fItest\fP(1)
|
||||
for a complete specification.
|
||||
.DS
|
||||
test s true if the argument \fIs\fP is not the null string
|
||||
test \(mif file true if \fIfile\fP exists
|
||||
test \(mir file true if \fIfile\fP is readable
|
||||
test \(miw file true if \fIfile\fP is writable
|
||||
test \(mid file true if \fIfile\fP is a directory
|
||||
.DE
|
||||
The \fItest\fP command is known as `\fB[\fP' and may be invoked as
|
||||
such.
|
||||
For aesthetic reasons, the command ignores a close bracket `\fB]\fP' given
|
||||
at the end of a command so
|
||||
.DS
|
||||
[ -f filename ]
|
||||
.DE
|
||||
and
|
||||
.DS
|
||||
test -f filename
|
||||
.DE
|
||||
are completely equivalent.
|
||||
Typically, the bracket notation is used when \fItest\fP is invoked inside
|
||||
shell control constructs.
|
||||
.SH
|
||||
2.6\ Control\ flow\ -\ while
|
||||
.LP
|
||||
The actions of
|
||||
the \fBfor\fP loop and the \fBcase\fP
|
||||
branch are determined by data available to the shell.
|
||||
A \fBwhile\fP or \fBuntil\fP loop
|
||||
and an \fBif then else\fP branch
|
||||
are also provided whose
|
||||
actions are determined by the exit status
|
||||
returned by commands.
|
||||
A \fBwhile\fP loop has the general form
|
||||
.DS
|
||||
\fBwhile\fP \fIcommand-list\*1\fP
|
||||
\fBdo\fP \fIcommand-list\*2\fP
|
||||
\fBdone\fP
|
||||
.DE
|
||||
.LP
|
||||
The value tested by the \fBwhile\fP command
|
||||
is the exit status of the last simple command
|
||||
following \fBwhile.\fP
|
||||
Each time round the loop
|
||||
\fIcommand-list\*1\fP is executed;
|
||||
if a zero exit status is returned then
|
||||
\fIcommand-list\*2\fP
|
||||
is executed;
|
||||
otherwise, the loop terminates.
|
||||
For example,
|
||||
.DS
|
||||
while [ $1 ]
|
||||
do \*(ZZ
|
||||
\*(DOshift
|
||||
done
|
||||
.DE
|
||||
is equivalent to
|
||||
.DS
|
||||
for i
|
||||
do \*(ZZ
|
||||
done
|
||||
.DE
|
||||
\fIshift\fP is a shell command that
|
||||
renames the positional parameters
|
||||
\fB$2, $3, \*(ZZ\fR as \fB$1, $2, \*(ZZ\fR
|
||||
and loses \fB$1\|.\fP
|
||||
.LP
|
||||
Another kind of use for the \fBwhile/until\fP
|
||||
loop is to wait until some
|
||||
external event occurs and then run
|
||||
some commands.
|
||||
In an \fBuntil\fP loop
|
||||
the termination condition is reversed.
|
||||
For example,
|
||||
.DS
|
||||
until [ \(mif file ]
|
||||
do sleep 300; done
|
||||
\fIcommands\fP
|
||||
.DE
|
||||
will loop until \fIfile\fP exists.
|
||||
Each time round the loop it waits for
|
||||
5 minutes before trying again.
|
||||
(Presumably another process
|
||||
will eventually create the file.)
|
||||
.LP
|
||||
The most recent enclosing loop may be exited with the \fBbreak\fP
|
||||
command, or the rest of the body skipped and the next iteration begun
|
||||
with the \fBcontinue\fP command.
|
||||
.LP
|
||||
The commands \fItrue\fP(1) and \fIfalse\fP(1) return 0 and non-zero
|
||||
exit statuses respectively. They are sometimes of use in control flow,
|
||||
e.g.:
|
||||
.DS
|
||||
while true
|
||||
do date; sleep 5
|
||||
done
|
||||
.DE
|
||||
is an infinite loop that prints the date and time every five seconds.
|
||||
.SH
|
||||
2.7\ Control\ flow\ -\ if
|
||||
.LP
|
||||
Also available is a
|
||||
general conditional branch
|
||||
of the form,
|
||||
.DS
|
||||
\fBif\fP \fIcommand-list
|
||||
\fBthen \fIcommand-list
|
||||
\fBelse \fIcommand-list
|
||||
\fBfi\fR
|
||||
.DE
|
||||
that tests the value returned by the last simple command
|
||||
following \fBif.\fP
|
||||
.LP
|
||||
The \fBif\fP command may be used
|
||||
in conjunction with the \fItest\fP command
|
||||
to test for the existence of a file as in
|
||||
.DS
|
||||
if [ \(mif file ]
|
||||
then \fIprocess file\fP
|
||||
else \fIdo something else\fP
|
||||
fi
|
||||
.DE
|
||||
.LP
|
||||
An example of the use of \fBif, case\fP
|
||||
and \fBfor\fP constructions is given in
|
||||
section 2.10\|.
|
||||
.LP
|
||||
A multiple test \fBif\fP command
|
||||
of the form
|
||||
.DS
|
||||
if \*(ZZ
|
||||
then \*(ZZ
|
||||
else if \*(ZZ
|
||||
then \*(ZZ
|
||||
else if \*(ZZ
|
||||
\*(ZZ
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
.DE
|
||||
may be written using an extension of the \fBif\fP
|
||||
notation as,
|
||||
.DS
|
||||
if \*(ZZ
|
||||
then \*(ZZ
|
||||
elif \*(ZZ
|
||||
then \*(ZZ
|
||||
elif \*(ZZ
|
||||
\*(ZZ
|
||||
fi
|
||||
.DE
|
||||
.LP
|
||||
The following example is an implementation of the \fItouch\fP command
|
||||
which changes the `last modified' time for a list
|
||||
of files.
|
||||
The command may be used in conjunction
|
||||
with \fImake\fP(1) to force recompilation of a list
|
||||
of files.
|
||||
.DS
|
||||
#!/bin/sh
|
||||
|
||||
flag=
|
||||
for i
|
||||
do case $i in
|
||||
\*(DC\(mic) flag=N ;;
|
||||
\*(DC\*(ST) if [ \(mif $i ]
|
||||
\*(DC then cp $i junk$$; mv junk$$ $i
|
||||
\*(DC elif [ $flag ]
|
||||
\*(DC then echo file \\'$i\\' does not exist
|
||||
\*(DC else >$i
|
||||
\*(DC fi
|
||||
\*(DO esac
|
||||
done
|
||||
.DE
|
||||
The \fB\(mic\fP flag is used in this command to
|
||||
force subsequent files to be created if they do not already exist.
|
||||
Otherwise, if the file does not exist, an error message is printed.
|
||||
The shell variable \fIflag\fP
|
||||
is set to some non-null string if the \fB\(mic\fP
|
||||
argument is encountered.
|
||||
The commands
|
||||
.DS
|
||||
cp \*(ZZ; mv \*(ZZ
|
||||
.DE
|
||||
copy the file and then overwrite it with the copy,
|
||||
thus causing the last modified date to be updated.
|
||||
.LP
|
||||
The sequence
|
||||
.DS
|
||||
if command1
|
||||
then command2
|
||||
fi
|
||||
.DE
|
||||
may be written
|
||||
.DS
|
||||
command1 && command2
|
||||
.DE
|
||||
Conversely,
|
||||
.DS
|
||||
command1 \*(VT\*(VT command2
|
||||
.DE
|
||||
executes \fIcommand2\fP only if \fIcommand1\fP
|
||||
fails.
|
||||
In each case the value returned
|
||||
is that of the last simple command executed.
|
||||
.LP
|
||||
Placing a `\fB!\fP' in front of a pipeline inverts its exit
|
||||
status, almost in the manner of the C operator of the same name.
|
||||
Thus:
|
||||
.DS
|
||||
if ! [ -d $1 ]
|
||||
then
|
||||
echo $1 is not a directory
|
||||
fi
|
||||
.DE
|
||||
will print a message only if $1 is not a directory.
|
||||
.SH
|
||||
2.8\ Command\ grouping
|
||||
.LP
|
||||
Commands may be grouped in two ways,
|
||||
.DS
|
||||
\fB{\fI command-list\fB ; }\fR
|
||||
.DE
|
||||
and
|
||||
.DS
|
||||
\fB(\fI command-list\fB )\fR
|
||||
.DE
|
||||
.LP
|
||||
In the first \fIcommand-list\fP is simply executed.
|
||||
The second form executes \fIcommand-list\fP
|
||||
as a separate process.
|
||||
For example,
|
||||
.DS
|
||||
(cd x; rm junk )
|
||||
.DE
|
||||
executes \fIrm junk\fP in the directory
|
||||
\fBx\fP without changing the current
|
||||
directory of the invoking shell.
|
||||
.LP
|
||||
The commands
|
||||
.DS
|
||||
cd x; rm junk
|
||||
.DE
|
||||
have the same effect but leave the invoking
|
||||
shell in the directory \fBx.\fP
|
||||
.SH
|
||||
2.9\ Shell\ Functions
|
||||
.LP
|
||||
A function may be defined by the syntax
|
||||
.DS
|
||||
\fIfuncname\fP() \fB{\fI command-list\fB ; }\fR
|
||||
.DE
|
||||
Functions are invoked within a script as though they were separate
|
||||
commands of the same name.
|
||||
While they are executed, the
|
||||
positional parameters \fB$1, $2, \*(ZZ\fR are temporarily set to the
|
||||
arguments passed to the function. For example:
|
||||
.DS
|
||||
count() {
|
||||
echo $2 : $#
|
||||
}
|
||||
|
||||
count a b c
|
||||
.DE
|
||||
would print `b : 3'.
|
||||
.SH
|
||||
2.10\ Debugging\ shell\ scripts
|
||||
.LP
|
||||
The shell provides two tracing mechanisms
|
||||
to help when debugging shell scripts.
|
||||
The first is invoked within the script
|
||||
as
|
||||
.DS
|
||||
set \(miv
|
||||
.DE
|
||||
(\fBv\fP for verbose) and causes lines of the
|
||||
script to be printed as they are read.
|
||||
It is useful to help isolate syntax errors.
|
||||
It may be invoked without modifying the script
|
||||
by saying
|
||||
.DS
|
||||
sh \(miv \fIscript\fP \*(ZZ
|
||||
.DE
|
||||
where \fIscript\fP is the name of the shell script.
|
||||
This flag may be used in conjunction
|
||||
with the \fB\(min\fP flag which prevents
|
||||
execution of subsequent commands.
|
||||
(Note that saying \fIset \(min\fP at a terminal
|
||||
will render the terminal useless
|
||||
until an end-of-file is typed.)
|
||||
.LP
|
||||
The command
|
||||
.DS
|
||||
set \(mix
|
||||
.DE
|
||||
will produce an execution
|
||||
trace.
|
||||
Following parameter substitution
|
||||
each command is printed as it is executed.
|
||||
(Try these at the terminal to see
|
||||
what effect they have.)
|
||||
Both flags may be turned off by saying
|
||||
.DS
|
||||
set \(mi
|
||||
.DE
|
||||
and the current setting of the shell flags is available as \fB$\(mi\|\fR.
|
||||
.SH
|
||||
2.11\ The\ man\ command
|
||||
.LP
|
||||
The following is a simple implementation of the \fIman\fP command,
|
||||
which is used to display sections of the UNIX manual on your terminal.
|
||||
It is called, for example, as
|
||||
.DS
|
||||
man sh
|
||||
man \(mit ed
|
||||
man 2 fork
|
||||
.DE
|
||||
In the first the manual section for \fIsh\fP
|
||||
is displayed..
|
||||
Since no section is specified, section 1 is used.
|
||||
The second example will typeset (\fB\(mit\fP option)
|
||||
the manual section for \fIed.\fP
|
||||
The last prints the \fIfork\fP manual page
|
||||
from section 2, which covers system calls.
|
||||
.sp 2
|
||||
.DS
|
||||
#!/bin/sh
|
||||
|
||||
cd /usr/share/man
|
||||
|
||||
# "#" is the comment character
|
||||
# default is nroff ($N), section 1 ($s)
|
||||
N=n\ s=1
|
||||
|
||||
for i
|
||||
do case $i in
|
||||
.sp .5
|
||||
\*(DC[1\(mi9]\*(ST) s=$i ;;
|
||||
.sp .5
|
||||
\*(DC\(mit) N=t ;;
|
||||
.sp .5
|
||||
\*(DC\(min) N=n ;;
|
||||
.sp .5
|
||||
\*(DC\(mi\*(ST) echo unknown flag \\'$i\\' ;;
|
||||
.sp .5
|
||||
\*(DC\*(ST) if [ \(mif man$s/$i.$s ]
|
||||
\*(DC then
|
||||
\*(DC ${N}roff \(miman man$s/$i.$s
|
||||
\*(DC else # look through all manual sections
|
||||
\*(DC found=no
|
||||
\*(DC for j in 1 2 3 4 5 6 7 8 9
|
||||
\*(DC do
|
||||
\*(DC \*(DOif [ \(mif man$j/$i.$j ]
|
||||
\*(DC \*(DOthen
|
||||
\*(DC \*(DO\*(THman $j $i
|
||||
\*(DC \*(DO\*(THfound=yes
|
||||
\*(DC \*(DO\*(THbreak
|
||||
\*(DC \*(DOfi
|
||||
\*(DC done
|
||||
\*(DC case $found in
|
||||
\*(DC \*(Cano) echo \\'$i: manual page not found\\'
|
||||
\*(DC esac
|
||||
\*(DC fi
|
||||
\*(DOesac
|
||||
done
|
||||
.DE
|
||||
.ce
|
||||
.ft B
|
||||
Figure 1. A version of the man command
|
||||
.ft R
|
976
bin/sh/USD.doc/t3
Normal file
976
bin/sh/USD.doc/t3
Normal file
|
@ -0,0 +1,976 @@
|
|||
.\" $NetBSD: t3,v 1.3 2010/08/22 02:19:07 perry Exp $
|
||||
.\"
|
||||
.\" Copyright (C) Caldera International Inc. 2001-2002. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions are
|
||||
.\" met:
|
||||
.\"
|
||||
.\" Redistributions of source code and documentation must retain the above
|
||||
.\" copyright notice, this list of conditions and the following
|
||||
.\" disclaimer.
|
||||
.\"
|
||||
.\" Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\"
|
||||
.\" This product includes software developed or owned by Caldera
|
||||
.\" International, Inc. Neither the name of Caldera International, Inc.
|
||||
.\" nor the names of other contributors may be used to endorse or promote
|
||||
.\" products derived from this software without specific prior written
|
||||
.\" permission.
|
||||
.\"
|
||||
.\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
|
||||
.\" INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
|
||||
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
.\" DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
.\" OR OTHERWISE) RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)t3 8.1 (Berkeley) 6/8/93
|
||||
.\"
|
||||
.SH
|
||||
3.0\ Keyword\ parameters
|
||||
.LP
|
||||
Shell variables may be given values
|
||||
by assignment
|
||||
or when a shell script is invoked.
|
||||
An argument to a command of the form
|
||||
\fIname=value\fP
|
||||
that precedes the command name
|
||||
causes \fIvalue\fP
|
||||
to be assigned to \fIname\fP
|
||||
before execution of the command begins.
|
||||
The value of \fIname\fP in the invoking
|
||||
shell is not affected.
|
||||
For example,
|
||||
.DS
|
||||
user=fred\ command
|
||||
.DE
|
||||
will execute \fIcommand\fP with
|
||||
\fBuser\fP set to \fIfred\fP.
|
||||
.\" Removed by Perry Metzger because -k is not in POSIX
|
||||
.\"
|
||||
.\" The \fB\(mik\fR flag causes arguments of the form
|
||||
.\" \fIname=value\fP to be interpreted in this way
|
||||
.\" anywhere in the argument list.
|
||||
.\" Such \fInames\fP are sometimes
|
||||
.\" called keyword parameters.
|
||||
.\" If any arguments remain they
|
||||
.\" are available as positional
|
||||
.\" parameters \fB$1, $2, \*(ZZ\|.\fP
|
||||
.LP
|
||||
The \fIset\fP command
|
||||
may also be used to set positional parameters
|
||||
from within a script.
|
||||
For example,
|
||||
.DS
|
||||
set\ \(mi\(mi\ \*(ST
|
||||
.DE
|
||||
will set \fB$1\fP to the first file name
|
||||
in the current directory, \fB$2\fP to the next,
|
||||
and so on.
|
||||
Note that the first argument, \(mi\(mi, ensures correct treatment
|
||||
when the first file name begins with a \(mi\|.
|
||||
.LP
|
||||
.SH
|
||||
3.1\ Parameter\ transmission
|
||||
.LP
|
||||
When a command is executed both positional parameters
|
||||
and shell variables may be set on invocation.
|
||||
Variables are also made available implicitly
|
||||
to a command
|
||||
by specifying in advance that such parameters
|
||||
are to be exported from the invoking shell.
|
||||
For example,
|
||||
.DS
|
||||
export\ user\ box=red
|
||||
.DE
|
||||
marks the variables \fBuser\fP and \fBbox\fP
|
||||
for export (setting \fBbox\fP to ``red'' in the process).
|
||||
When a command is invoked
|
||||
copies are made of all exportable variables
|
||||
(also known as \fIenvironment variables\fP)
|
||||
for use within the invoked program.
|
||||
Modification of such variables
|
||||
within an invoked command does not
|
||||
affect the values in the invoking shell.
|
||||
It is generally true of
|
||||
a shell script or other program
|
||||
that it
|
||||
cannot modify the state
|
||||
of its caller without explicit
|
||||
actions on the part of the caller.
|
||||
.\" Removed by Perry Metzger because this is confusing to beginners.
|
||||
.\"
|
||||
.\" (Shared file descriptors are an
|
||||
.\" exception to this rule.)
|
||||
.LP
|
||||
Names whose value is intended to remain
|
||||
constant may be declared \fIreadonly\|.\fP
|
||||
The form of this command is the same as that of the \fIexport\fP
|
||||
command,
|
||||
.DS
|
||||
readonly name[=value] \*(ZZ
|
||||
.DE
|
||||
Subsequent attempts to set readonly variables
|
||||
are illegal.
|
||||
.SH
|
||||
3.2\ Parameter\ substitution
|
||||
.LP
|
||||
If a shell parameter is not set
|
||||
then the null string is substituted for it.
|
||||
For example, if the variable \fBd\fP
|
||||
is not set
|
||||
.DS
|
||||
echo $d
|
||||
.DE
|
||||
or
|
||||
.DS
|
||||
echo ${d}
|
||||
.DE
|
||||
will echo nothing.
|
||||
A default string may be given
|
||||
as in
|
||||
.DS
|
||||
echo ${d:\(mi\fB.\fR}
|
||||
.DE
|
||||
which will echo
|
||||
the value of the variable \fBd\fP
|
||||
if it is set and not null and `\fB.\fP' otherwise.
|
||||
The default string is evaluated using the usual
|
||||
quoting conventions so that
|
||||
.DS
|
||||
echo ${d:\(mi\'\*(ST\'}
|
||||
.DE
|
||||
will echo \fB\*(ST\fP if the variable \fBd\fP
|
||||
is not set or null.
|
||||
Similarly
|
||||
.DS
|
||||
echo ${d:\(mi$1}
|
||||
.DE
|
||||
will echo the value of \fBd\fP if it is set and not null
|
||||
and the value (if any) of \fB$1\fP otherwise.
|
||||
.LP
|
||||
The notation ${d:+\fB.\fR} performs the inverse operation. It
|
||||
substitutes `\fB.\fP' if \fBd\fP is set or not null, and otherwise
|
||||
substitutes null.
|
||||
.LP
|
||||
A variable may be assigned a default value
|
||||
using
|
||||
the notation
|
||||
.DS
|
||||
echo ${d:=\fB.\fR}
|
||||
.DE
|
||||
which substitutes the same string as
|
||||
.DS
|
||||
echo ${d:\(mi\fB.\fR}
|
||||
.DE
|
||||
and if \fBd\fP were not previously set or null
|
||||
then it will be set to the string `\fB.\fP'\|.
|
||||
.LP
|
||||
If there is no sensible default then
|
||||
the notation
|
||||
.DS
|
||||
echo ${d:?\fImessage\fP}
|
||||
.DE
|
||||
will echo the value of the variable \fBd\fP if it is set and not null,
|
||||
otherwise \fImessage\fP is printed by the shell and
|
||||
execution of the shell script is abandoned.
|
||||
If \fImessage\fP is absent then a standard message
|
||||
is printed.
|
||||
A shell script that requires some variables
|
||||
to be set might start as follows:
|
||||
.DS
|
||||
:\ ${user:?}\ ${acct:?}\ ${bin:?}
|
||||
\*(ZZ
|
||||
.DE
|
||||
Colon (\fB:\fP) is a command
|
||||
that is
|
||||
built in to the shell and does nothing
|
||||
once its arguments have been evaluated.
|
||||
If any of the variables \fBuser, acct\fP
|
||||
or \fBbin\fP are not set then the shell
|
||||
will abandon execution of the script.
|
||||
.SH
|
||||
3.3\ Command\ substitution
|
||||
.LP
|
||||
The standard output from a command can be
|
||||
substituted in a similar way to parameters.
|
||||
The command \fIpwd\fP prints on its standard
|
||||
output the name of the current directory.
|
||||
For example, if the current directory is
|
||||
\fB/usr/fred/bin\fR
|
||||
then the commands
|
||||
.DS
|
||||
d=$(pwd)
|
||||
.DE
|
||||
(or the older notation d=\`pwd\`)
|
||||
is equivalent to
|
||||
.DS
|
||||
d=/usr/fred/bin
|
||||
.DE
|
||||
.LP
|
||||
The entire string inside $(\*(ZZ)\| (or between grave accents \`\*(ZZ\`)
|
||||
is taken as the command
|
||||
to be executed
|
||||
and is replaced with the output from
|
||||
the command.
|
||||
(The difference between the $(\*(ZZ) and \`\*(ZZ\` notations is that
|
||||
the former may be nested, while the latter cannot be.)
|
||||
.LP
|
||||
The command is written using the usual quoting conventions,
|
||||
except that inside \`\*(ZZ\`
|
||||
a \fB\`\fR must be escaped using
|
||||
a \fB\\\|\fR.
|
||||
For example,
|
||||
.DS
|
||||
ls $(echo "$HOME")
|
||||
.DE
|
||||
is equivalent to
|
||||
.DS
|
||||
ls $HOME
|
||||
.DE
|
||||
Command substitution occurs in all contexts
|
||||
where parameter substitution occurs (including \fIhere\fP documents) and the
|
||||
treatment of the resulting text is the same
|
||||
in both cases.
|
||||
This mechanism allows string
|
||||
processing commands to be used within
|
||||
shell scripts.
|
||||
An example of such a command is \fIbasename\fP
|
||||
which removes a specified suffix from a string.
|
||||
For example,
|
||||
.DS
|
||||
basename main\fB.\fPc \fB.\fPc
|
||||
.DE
|
||||
will print the string \fImain\|.\fP
|
||||
Its use is illustrated by the following
|
||||
fragment from a \fIcc\fP command.
|
||||
.DS
|
||||
case $A in
|
||||
\*(Ca\*(ZZ
|
||||
\*(Ca\*(ST\fB.\fPc) B=$(basename $A \fB.\fPc)
|
||||
\*(Ca\*(ZZ
|
||||
esac
|
||||
.DE
|
||||
that sets \fBB\fP to the part of \fB$A\fP
|
||||
with the suffix \fB.c\fP stripped.
|
||||
.LP
|
||||
Here are some composite examples.
|
||||
.RS
|
||||
.IP \(bu
|
||||
.ft B
|
||||
for i in \`ls \(mit\`; do \*(ZZ
|
||||
.ft R
|
||||
.br
|
||||
The variable \fBi\fP is set
|
||||
to the names of files in time order,
|
||||
most recent first.
|
||||
.IP \(bu
|
||||
.ft B
|
||||
set \(mi\(mi\| \`date\`; echo $6 $2 $3, $4
|
||||
.ft R
|
||||
.br
|
||||
will print, e.g.,
|
||||
.ft I
|
||||
1977 Nov 1, 23:59:59
|
||||
.ft R
|
||||
.RE
|
||||
.SH
|
||||
3.4\ Arithmetic\ Expansion
|
||||
.LP
|
||||
Within a $((\*(ZZ)) construct, integer arithmetic operations are
|
||||
evaluated.
|
||||
(The $ in front of variable names is optional within $((\*(ZZ)).
|
||||
For example:
|
||||
.DS
|
||||
x=5; y=1
|
||||
echo $(($x+3*2))
|
||||
echo $((y+=x))
|
||||
echo $y
|
||||
.DE
|
||||
will print `11', then `6', then `6' again.
|
||||
Most of the constructs permitted in C arithmetic operations are
|
||||
permitted though some (like `++') are not universally supported \(em
|
||||
see the shell manual page for details.
|
||||
.SH
|
||||
3.5\ Evaluation\ and\ quoting
|
||||
.LP
|
||||
The shell is a macro processor that
|
||||
provides parameter substitution, command substitution and file
|
||||
name generation for the arguments to commands.
|
||||
This section discusses the order in which
|
||||
these evaluations occur and the
|
||||
effects of the various quoting mechanisms.
|
||||
.LP
|
||||
Commands are parsed initially according to the grammar
|
||||
given in appendix A.
|
||||
Before a command is executed
|
||||
the following
|
||||
substitutions occur.
|
||||
.RS
|
||||
.IP \(bu
|
||||
parameter substitution, e.g. \fB$user\fP
|
||||
.IP \(bu
|
||||
command substitution, e.g. \fB$(pwd)\fP or \fB\`pwd\`\fP
|
||||
.IP \(bu
|
||||
arithmetic expansion, e.g. \fB$(($count+1))\fP
|
||||
.RS
|
||||
.LP
|
||||
Only one evaluation occurs so that if, for example, the value of the variable
|
||||
\fBX\fP
|
||||
is the string \fI$y\fP
|
||||
then
|
||||
.DS
|
||||
echo $X
|
||||
.DE
|
||||
will echo \fI$y\|.\fP
|
||||
.RE
|
||||
.IP \(bu
|
||||
blank interpretation
|
||||
.RS
|
||||
.LP
|
||||
Following the above substitutions
|
||||
the resulting characters
|
||||
are broken into non-blank words (\fIblank interpretation\fP).
|
||||
For this purpose `blanks' are the characters of the string
|
||||
\fB$\s-1IFS\s0\fP.
|
||||
By default, this string consists of blank, tab and newline.
|
||||
The null string
|
||||
is not regarded as a word unless it is quoted.
|
||||
For example,
|
||||
.DS
|
||||
echo \'\'
|
||||
.DE
|
||||
will pass on the null string as the first argument to \fIecho\fP,
|
||||
whereas
|
||||
.DS
|
||||
echo $null
|
||||
.DE
|
||||
will call \fIecho\fR with no arguments
|
||||
if the variable \fBnull\fP is not set
|
||||
or set to the null string.
|
||||
.RE
|
||||
.IP \(bu
|
||||
file name generation
|
||||
.RS
|
||||
.LP
|
||||
Each word
|
||||
is then scanned for the file pattern characters
|
||||
\fB\*(ST, ?\fR and \fB[\*(ZZ]\fR
|
||||
and an alphabetical list of file names
|
||||
is generated to replace the word.
|
||||
Each such file name is a separate argument.
|
||||
.RE
|
||||
.RE
|
||||
.LP
|
||||
The evaluations just described also occur
|
||||
in the list of words associated with a \fBfor\fP
|
||||
loop.
|
||||
Only substitution occurs
|
||||
in the \fIword\fP used
|
||||
for a \fBcase\fP branch.
|
||||
.LP
|
||||
As well as the quoting mechanisms described
|
||||
earlier using \fB\\\fR and \fB\'\*(ZZ\'\fR
|
||||
a third quoting mechanism is provided using double quotes.
|
||||
Within double quotes parameter and command substitution
|
||||
occurs but file name generation and the interpretation
|
||||
of blanks does not.
|
||||
The following characters
|
||||
have a special meaning within double quotes
|
||||
and may be quoted using \fB\\\|.\fP
|
||||
.DS
|
||||
\fB$ \fPparameter substitution
|
||||
\fB$()\fP command substitution
|
||||
\fB\`\fP command substitution
|
||||
\fB"\fP ends the quoted string
|
||||
\fB\e\fP quotes the special characters \fB$ \` " \e\fP
|
||||
.DE
|
||||
For example,
|
||||
.DS
|
||||
echo "$x"
|
||||
.DE
|
||||
will pass the value of the variable \fBx\fP as a
|
||||
single argument to \fIecho.\fP
|
||||
Similarly,
|
||||
.DS
|
||||
echo "$\*(ST"
|
||||
.DE
|
||||
will pass the positional parameters as a single
|
||||
argument and is equivalent to
|
||||
.DS
|
||||
echo "$1 $2 \*(ZZ"
|
||||
.DE
|
||||
The notation \fB$@\fP
|
||||
is the same as \fB$\*(ST\fR
|
||||
except when it is quoted.
|
||||
.DS
|
||||
echo "$@"
|
||||
.DE
|
||||
will pass the positional parameters, unevaluated, to \fIecho\fR
|
||||
and is equivalent to
|
||||
.DS
|
||||
echo "$1" "$2" \*(ZZ
|
||||
.DE
|
||||
.LP
|
||||
The following table gives, for each quoting mechanism,
|
||||
the shell metacharacters that are evaluated.
|
||||
.DS
|
||||
.ce
|
||||
.ft I
|
||||
metacharacter
|
||||
.ft
|
||||
.in 1.5i
|
||||
\e $ * \` " \'
|
||||
\' n n n n n t
|
||||
\` y n n t n n
|
||||
" y y n y t n
|
||||
|
||||
t terminator
|
||||
y interpreted
|
||||
n not interpreted
|
||||
|
||||
.in
|
||||
.ft B
|
||||
.ce
|
||||
Figure 2. Quoting mechanisms
|
||||
.ft
|
||||
.DE
|
||||
.LP
|
||||
In cases where more than one evaluation of a string
|
||||
is required the built-in command \fIeval\fP
|
||||
may be used.
|
||||
For example,
|
||||
if the variable \fBX\fP has the value
|
||||
\fI$y\fP, and if \fBy\fP has the value \fIpqr\fP
|
||||
then
|
||||
.DS
|
||||
eval echo $X
|
||||
.DE
|
||||
will echo the string \fIpqr\|.\fP
|
||||
.LP
|
||||
In general the \fIeval\fP command
|
||||
evaluates its arguments (as do all commands)
|
||||
and treats the result as input to the shell.
|
||||
The input is read and the resulting command(s)
|
||||
executed.
|
||||
For example,
|
||||
.DS
|
||||
wg=\'eval who\*(VTgrep\'
|
||||
$wg fred
|
||||
.DE
|
||||
is equivalent to
|
||||
.DS
|
||||
who\*(VTgrep fred
|
||||
.DE
|
||||
In this example,
|
||||
\fIeval\fP is required
|
||||
since there is no interpretation
|
||||
of metacharacters, such as \fB\*(VT\|\fR, following
|
||||
substitution.
|
||||
.SH
|
||||
3.6\ Error\ handling
|
||||
.LP
|
||||
The treatment of errors detected by
|
||||
the shell depends on the type of error
|
||||
and on whether the shell is being
|
||||
used interactively.
|
||||
An interactive shell is one whose
|
||||
input and output are connected
|
||||
to a terminal.
|
||||
.\" Removed by Perry Metzger, obsolete and excess detail
|
||||
.\"
|
||||
.\" (as determined by
|
||||
.\" \fIgtty\fP (2)).
|
||||
A shell invoked with the \fB\(mii\fP
|
||||
flag is also interactive.
|
||||
.LP
|
||||
Execution of a command (see also 3.7) may fail
|
||||
for any of the following reasons.
|
||||
.IP \(bu
|
||||
Input output redirection may fail.
|
||||
For example, if a file does not exist
|
||||
or cannot be created.
|
||||
.IP \(bu
|
||||
The command itself does not exist
|
||||
or cannot be executed.
|
||||
.IP \(bu
|
||||
The command terminates abnormally,
|
||||
for example, with a "bus error"
|
||||
or "memory fault".
|
||||
See Figure 2 below for a complete list
|
||||
of UNIX signals.
|
||||
.IP \(bu
|
||||
The command terminates normally
|
||||
but returns a non-zero exit status.
|
||||
.LP
|
||||
In all of these cases the shell
|
||||
will go on to execute the next command.
|
||||
Except for the last case an error
|
||||
message will be printed by the shell.
|
||||
All remaining errors cause the shell
|
||||
to exit from a script.
|
||||
An interactive shell will return
|
||||
to read another command from the terminal.
|
||||
Such errors include the following.
|
||||
.IP \(bu
|
||||
Syntax errors.
|
||||
e.g., if \*(ZZ then \*(ZZ done
|
||||
.IP \(bu
|
||||
A signal such as interrupt.
|
||||
The shell waits for the current
|
||||
command, if any, to finish execution and
|
||||
then either exits or returns to the terminal.
|
||||
.IP \(bu
|
||||
Failure of any of the built-in commands
|
||||
such as \fIcd.\fP
|
||||
.LP
|
||||
The shell flag \fB\(mie\fP
|
||||
causes the shell to terminate
|
||||
if any error is detected.
|
||||
.DS
|
||||
1 hangup
|
||||
2 interrupt
|
||||
3* quit
|
||||
4* illegal instruction
|
||||
5* trace trap
|
||||
6* IOT instruction
|
||||
7* EMT instruction
|
||||
8* floating point exception
|
||||
9 kill (cannot be caught or ignored)
|
||||
10* bus error
|
||||
11* segmentation violation
|
||||
12* bad argument to system call
|
||||
13 write on a pipe with no one to read it
|
||||
14 alarm clock
|
||||
15 software termination (from \fIkill\fP (1))
|
||||
|
||||
.DE
|
||||
.ft B
|
||||
.ce
|
||||
Figure 3. UNIX signals\(dg
|
||||
.ft
|
||||
.FS
|
||||
\(dg Additional signals have been added in modern Unix.
|
||||
See \fIsigvec\fP(2) or \fIsignal\fP(3) for an up-to-date list.
|
||||
.FE
|
||||
Those signals marked with an asterisk
|
||||
produce a core dump
|
||||
if not caught.
|
||||
However,
|
||||
the shell itself ignores quit which is the only
|
||||
external signal that can cause a dump.
|
||||
The signals in this list of potential interest
|
||||
to shell programs are 1, 2, 3, 14 and 15.
|
||||
.SH
|
||||
3.7\ Fault\ handling
|
||||
.LP
|
||||
shell scripts normally terminate
|
||||
when an interrupt is received from the
|
||||
terminal.
|
||||
The \fItrap\fP command is used
|
||||
if some cleaning up is required, such
|
||||
as removing temporary files.
|
||||
For example,
|
||||
.DS
|
||||
trap\ \'rm\ /tmp/ps$$; exit\'\ 2
|
||||
.DE
|
||||
sets a trap for signal 2 (terminal
|
||||
interrupt), and if this signal is received
|
||||
will execute the commands
|
||||
.DS
|
||||
rm /tmp/ps$$; exit
|
||||
.DE
|
||||
\fIexit\fP is
|
||||
another built-in command
|
||||
that terminates execution of a shell script.
|
||||
The \fIexit\fP is required; otherwise,
|
||||
after the trap has been taken,
|
||||
the shell will resume executing
|
||||
the script
|
||||
at the place where it was interrupted.
|
||||
.LP
|
||||
UNIX signals can be handled in one of three ways.
|
||||
They can be ignored, in which case
|
||||
the signal is never sent to the process.
|
||||
They can be caught, in which case the process
|
||||
must decide what action to take when the
|
||||
signal is received.
|
||||
Lastly, they can be left to cause
|
||||
termination of the process without
|
||||
it having to take any further action.
|
||||
If a signal is being ignored
|
||||
on entry to the shell script, for example,
|
||||
by invoking it in the background (see 3.7) then \fItrap\fP
|
||||
commands (and the signal) are ignored.
|
||||
.LP
|
||||
The use of \fItrap\fP is illustrated
|
||||
by this modified version of the \fItouch\fP
|
||||
command (Figure 4).
|
||||
The cleanup action is to remove the file \fBjunk$$\fR\|.
|
||||
.DS
|
||||
#!/bin/sh
|
||||
|
||||
flag=
|
||||
trap\ \'rm\ \(mif\ junk$$;\ exit\'\ 1 2 3 15
|
||||
for i
|
||||
do\ case\ $i\ in
|
||||
\*(DC\(mic) flag=N ;;
|
||||
\*(DC\*(ST) if\ test\ \(mif\ $i
|
||||
\*(DC then cp\ $i\ junk$$;\ mv\ junk$$ $i
|
||||
\*(DC elif\ test\ $flag
|
||||
\*(DC then echo\ file\ \\'$i\\'\ does\ not\ exist
|
||||
\*(DC else >$i
|
||||
\*(DC fi
|
||||
\*(DOesac
|
||||
done
|
||||
.DE
|
||||
.sp
|
||||
.ft B
|
||||
.ce
|
||||
Figure 4. The touch command
|
||||
.ft
|
||||
.sp
|
||||
The \fItrap\fP command
|
||||
appears before the creation
|
||||
of the temporary file;
|
||||
otherwise it would be
|
||||
possible for the process
|
||||
to die without removing
|
||||
the file.
|
||||
.LP
|
||||
Since there is no signal 0 in UNIX
|
||||
it is used by the shell to indicate the
|
||||
commands to be executed on exit from the
|
||||
shell script.
|
||||
.LP
|
||||
A script may, itself, elect to
|
||||
ignore signals by specifying the null
|
||||
string as the argument to trap.
|
||||
The following fragment is taken from the
|
||||
\fInohup\fP command.
|
||||
.DS
|
||||
trap \'\' 1 2 3 15
|
||||
.DE
|
||||
which causes \fIhangup, interrupt, quit \fRand\fI kill\fR
|
||||
to be ignored both by the
|
||||
script and by invoked commands.
|
||||
.LP
|
||||
Traps may be reset by saying
|
||||
.DS
|
||||
trap 2 3
|
||||
.DE
|
||||
which resets the traps for signals 2 and 3 to their default values.
|
||||
A list of the current values of traps may be obtained
|
||||
by writing
|
||||
.DS
|
||||
trap
|
||||
.DE
|
||||
.LP
|
||||
The script \fIscan\fP (Figure 5) is an example
|
||||
of the use of \fItrap\fP where there is no exit
|
||||
in the trap command.
|
||||
\fIscan\fP takes each directory
|
||||
in the current directory, prompts
|
||||
with its name, and then executes
|
||||
commands typed at the terminal
|
||||
until an end of file or an interrupt is received.
|
||||
Interrupts are ignored while executing
|
||||
the requested commands but cause
|
||||
termination when \fIscan\fP is
|
||||
waiting for input.
|
||||
.DS
|
||||
d=\`pwd\`
|
||||
for\ i\ in\ \*(ST
|
||||
do\ if\ test\ \(mid\ $d/$i
|
||||
\*(DOthen\ cd\ $d/$i
|
||||
\*(DO\*(THwhile\ echo\ "$i:"
|
||||
\*(DO\*(TH\*(WHtrap\ exit\ 2
|
||||
\*(DO\*(TH\*(WHread\ x
|
||||
\*(DO\*(THdo\ trap\ :\ 2;\ eval\ $x;\ done
|
||||
\*(DOfi
|
||||
done
|
||||
.DE
|
||||
.sp
|
||||
.ft B
|
||||
.ce
|
||||
Figure 5. The scan command
|
||||
.ft
|
||||
.sp
|
||||
\fIread x\fR is a built-in command that reads one line from the
|
||||
standard input
|
||||
and places the result in the variable \fBx\|.\fP
|
||||
It returns a non-zero exit status if either
|
||||
an end-of-file is read or an interrupt
|
||||
is received.
|
||||
.SH
|
||||
3.8\ Command\ execution
|
||||
.LP
|
||||
To run a command (other than a built-in) the shell first creates
|
||||
a new process using the system call \fIfork.\fP
|
||||
The execution environment for the command
|
||||
includes input, output and the states of signals, and
|
||||
is established in the child process
|
||||
before the command is executed.
|
||||
The built-in command \fIexec\fP
|
||||
is used in the rare cases when no fork
|
||||
is required
|
||||
and simply replaces the shell with a new command.
|
||||
For example, a simple version of the \fInohup\fP
|
||||
command looks like
|
||||
.DS
|
||||
trap \\'\\' 1 2 3 15
|
||||
exec $\*(ST
|
||||
.DE
|
||||
The \fItrap\fP turns off the signals specified
|
||||
so that they are ignored by subsequently created commands
|
||||
and \fIexec\fP replaces the shell by the command
|
||||
specified.
|
||||
.LP
|
||||
Most forms of input output redirection have already been
|
||||
described.
|
||||
In the following \fIword\fP is only subject
|
||||
to parameter and command substitution.
|
||||
No file name generation or blank interpretation
|
||||
takes place so that, for example,
|
||||
.DS
|
||||
echo \*(ZZ >\*(ST.c
|
||||
.DE
|
||||
will write its output into a file whose name is \fB\*(ST.c\|.\fP
|
||||
Input output specifications are evaluated left to right
|
||||
as they appear in the command.
|
||||
.IP >\ \fIword\fP 12
|
||||
The standard output (file descriptor 1)
|
||||
is sent to the file \fIword\fP which is
|
||||
created if it does not already exist.
|
||||
.IP \*(AP\ \fIword\fP 12
|
||||
The standard output is sent to file \fIword.\fP
|
||||
If the file exists then output is appended
|
||||
(by seeking to the end);
|
||||
otherwise the file is created.
|
||||
.IP <\ \fIword\fP 12
|
||||
The standard input (file descriptor 0)
|
||||
is taken from the file \fIword.\fP
|
||||
.IP \*(HE\ \fIword\fP 12
|
||||
The standard input is taken from the lines
|
||||
of shell input that follow up to but not
|
||||
including a line consisting only of \fIword.\fP
|
||||
If \fIword\fP is quoted then no interpretation
|
||||
of the document occurs.
|
||||
If \fIword\fP is not quoted
|
||||
then parameter and command substitution
|
||||
occur and \fB\\\fP is used to quote
|
||||
the characters \fB\\\fP \fB$\fP \fB\`\fP and the first character
|
||||
of \fIword.\fP
|
||||
In the latter case \fB\\newline\fP is ignored (c.f. quoted strings).
|
||||
.IP >&\ \fIdigit\fP 12
|
||||
The file descriptor \fIdigit\fP is duplicated using the system
|
||||
call \fIdup\fP (2)
|
||||
and the result is used as the standard output.
|
||||
.IP <&\ \fIdigit\fP 12
|
||||
The standard input is duplicated from file descriptor \fIdigit.\fP
|
||||
.IP <&\(mi 12
|
||||
The standard input is closed.
|
||||
.IP >&\(mi 12
|
||||
The standard output is closed.
|
||||
.LP
|
||||
Any of the above may be preceded by a digit in which
|
||||
case the file descriptor created is that specified by the digit
|
||||
instead of the default 0 or 1.
|
||||
For example,
|
||||
.DS
|
||||
\*(ZZ 2>file
|
||||
.DE
|
||||
runs a command with message output (file descriptor 2)
|
||||
directed to \fIfile.\fP
|
||||
.DS
|
||||
\*(ZZ 2>&1
|
||||
.DE
|
||||
runs a command with its standard output and message output
|
||||
merged.
|
||||
(Strictly speaking file descriptor 2 is created
|
||||
by duplicating file descriptor 1 but the effect is usually to
|
||||
merge the two streams.)
|
||||
.\" Removed by Perry Metzger, most of this is now obsolete
|
||||
.\"
|
||||
.\" .LP
|
||||
.\" The environment for a command run in the background such as
|
||||
.\" .DS
|
||||
.\" list \*(ST.c \*(VT lpr &
|
||||
.\" .DE
|
||||
.\" is modified in two ways.
|
||||
.\" Firstly, the default standard input
|
||||
.\" for such a command is the empty file \fB/dev/null\|.\fR
|
||||
.\" This prevents two processes (the shell and the command),
|
||||
.\" which are running in parallel, from trying to
|
||||
.\" read the same input.
|
||||
.\" Chaos would ensue
|
||||
.\" if this were not the case.
|
||||
.\" For example,
|
||||
.\" .DS
|
||||
.\" ed file &
|
||||
.\" .DE
|
||||
.\" would allow both the editor and the shell
|
||||
.\" to read from the same input at the same time.
|
||||
.\" .LP
|
||||
.\" The other modification to the environment of a background
|
||||
.\" command is to turn off the QUIT and INTERRUPT signals
|
||||
.\" so that they are ignored by the command.
|
||||
.\" This allows these signals to be used
|
||||
.\" at the terminal without causing background
|
||||
.\" commands to terminate.
|
||||
.\" For this reason the UNIX convention
|
||||
.\" for a signal is that if it is set to 1
|
||||
.\" (ignored) then it is never changed
|
||||
.\" even for a short time.
|
||||
.\" Note that the shell command \fItrap\fP
|
||||
.\" has no effect for an ignored signal.
|
||||
.SH
|
||||
3.9\ Invoking\ the\ shell
|
||||
.LP
|
||||
The following flags are interpreted by the shell
|
||||
when it is invoked.
|
||||
If the first character of argument zero is a minus,
|
||||
then commands are read from the file \fB.profile\|.\fP
|
||||
.IP \fB\(mic\fP\ \fIstring\fP
|
||||
.br
|
||||
If the \fB\(mic\fP flag is present then
|
||||
commands are read from \fIstring\|.\fP
|
||||
.IP \fB\(mis\fP
|
||||
If the \fB\(mis\fP flag is present or if no
|
||||
arguments remain
|
||||
then commands are read from the standard input.
|
||||
Shell output is written to
|
||||
file descriptor 2.
|
||||
.IP \fB\(mii\fP
|
||||
If the \fB\(mii\fP flag is present or
|
||||
if the shell input and output are attached to a terminal (as told by \fIgtty\fP)
|
||||
then this shell is \fIinteractive.\fP
|
||||
In this case TERMINATE is ignored (so that \fBkill 0\fP
|
||||
does not kill an interactive shell) and INTERRUPT is caught and ignored
|
||||
(so that \fBwait\fP is interruptable).
|
||||
In all cases QUIT is ignored by the shell.
|
||||
.SH
|
||||
3.10\ Job\ Control
|
||||
.LP
|
||||
When a command or pipeline (also known as a \fIjob\fP) is running in
|
||||
the foreground, entering the stop character (typically
|
||||
\s-1CONTROL-Z\s0 but user settable with the \fIstty\fP(1) command)
|
||||
will usually cause the job to stop.
|
||||
.LP
|
||||
The jobs associated with the current shell may be listed by entering
|
||||
the \fIjobs\fP command.
|
||||
Each job has an associated \fIjob number\fP.
|
||||
Jobs that are stopped may be continued by entering
|
||||
.DS
|
||||
bg %\fIjobnumber\fP
|
||||
.DE
|
||||
and jobs may be moved to the foreground by entering
|
||||
.DS
|
||||
fg %\fIjobnumber\fP
|
||||
.DE
|
||||
If there is a sole job with a particular name (say only one instance
|
||||
of \fIcc\fP running), \fIfg\fP and \fIbg\fP may also use name of the
|
||||
command in place of the number, as in:
|
||||
.DS
|
||||
bg %cc
|
||||
.DE
|
||||
If no `\fB%\fP' clause is entered, most recently stopped job
|
||||
(indicated with a `+' by the \fIjobs\fP command) will be assumed.
|
||||
See the manual page for the shell for more details.
|
||||
.SH
|
||||
3.11\ Aliases
|
||||
.LP
|
||||
The \fIalias\fP command creates a so-called shell alias, which is an
|
||||
abbreviation that macro-expands at run time into some other command.
|
||||
For example:
|
||||
.DS
|
||||
alias ls="ls -F"
|
||||
.DE
|
||||
would cause the command sequence \fBls -F\fP to be executed whenever
|
||||
the user types \fBls\fP into the shell.
|
||||
Note that if the user types \fBls -a\fP, the shell will in fact
|
||||
execute \fBls -F -a\fP.
|
||||
The command \fBalias\fP on its own prints out all current aliases.
|
||||
The \fIunalias\fP command, as in:
|
||||
.DS
|
||||
unalias ls
|
||||
.DE
|
||||
will remove an existing alias.
|
||||
Aliases can shadow pre-existing commands, as in the example above.
|
||||
They are typically used to override the interactive behavior of
|
||||
commands in small ways, for example to always invoke some program with
|
||||
a favorite option, and are almost never found in scripts.
|
||||
.SH
|
||||
3.12\ Command\ Line\ Editing\ and\ Recall
|
||||
.LP
|
||||
When working interactively with the shell, it is often tedious to
|
||||
retype previously entered commands, especially if they are complicated.
|
||||
The shell therefore maintains a so-called \fIhistory\fP, which is
|
||||
stored in the file specified by the \fB\s-1HISTFILE\s0\fP environment
|
||||
variable if it is set.
|
||||
Users may view, edit, and re-enter previous lines of input using
|
||||
a small subset of the commands of the \fIvi\fP(1) or
|
||||
\fIemacs\fP(1)\(dg editors.
|
||||
.FS
|
||||
Technically, vi command editing is standardized by POSIX while emacs
|
||||
is not.
|
||||
However, all modern shells support both styles.
|
||||
.FE
|
||||
Emacs style editing may be selected by entering
|
||||
.DS
|
||||
set -o emacs
|
||||
.DE
|
||||
and vi style editing may be selected with
|
||||
.DS
|
||||
set -o vi
|
||||
.DE
|
||||
The details of how command line editing works are beyond the scope of
|
||||
this document.
|
||||
See the shell manual page for details.
|
||||
.SH
|
||||
Acknowledgements
|
||||
.LP
|
||||
The design of the shell is
|
||||
based in part on the original UNIX shell
|
||||
.[
|
||||
unix command language thompson
|
||||
.]
|
||||
and the PWB/UNIX shell,
|
||||
.[
|
||||
pwb shell mashey unix
|
||||
.]
|
||||
some
|
||||
features having been taken from both.
|
||||
Similarities also exist with the
|
||||
command interpreters
|
||||
of the Cambridge Multiple Access System
|
||||
.[
|
||||
cambridge multiple access system hartley
|
||||
.]
|
||||
and of CTSS.
|
||||
.[
|
||||
ctss
|
||||
.]
|
||||
.LP
|
||||
I would like to thank Dennis Ritchie
|
||||
and John Mashey for many
|
||||
discussions during the design of the shell.
|
||||
I am also grateful to the members of the Computing Science Research Center
|
||||
and to Joe Maranzano for their
|
||||
comments on drafts of this document.
|
||||
.SH
|
||||
.[
|
||||
$LIST$
|
||||
.]
|
180
bin/sh/USD.doc/t4
Normal file
180
bin/sh/USD.doc/t4
Normal file
|
@ -0,0 +1,180 @@
|
|||
.\" $NetBSD: t4,v 1.3 2010/08/22 02:19:07 perry Exp $
|
||||
.\"
|
||||
.\" Copyright (C) Caldera International Inc. 2001-2002. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions are
|
||||
.\" met:
|
||||
.\"
|
||||
.\" Redistributions of source code and documentation must retain the above
|
||||
.\" copyright notice, this list of conditions and the following
|
||||
.\" disclaimer.
|
||||
.\"
|
||||
.\" Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\"
|
||||
.\" This product includes software developed or owned by Caldera
|
||||
.\" International, Inc. Neither the name of Caldera International, Inc.
|
||||
.\" nor the names of other contributors may be used to endorse or promote
|
||||
.\" products derived from this software without specific prior written
|
||||
.\" permission.
|
||||
.\"
|
||||
.\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
|
||||
.\" INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
|
||||
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
.\" DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
.\" OR OTHERWISE) RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)t4 8.1 (Berkeley) 8/14/93
|
||||
.\"
|
||||
.bp
|
||||
.SH
|
||||
Appendix\ A\ -\ Grammar
|
||||
.LP
|
||||
Note: This grammar needs updating, it is obsolete.
|
||||
.LP
|
||||
.LD
|
||||
\fIitem: word
|
||||
input-output
|
||||
name = value
|
||||
.sp 0.7
|
||||
simple-command: item
|
||||
simple-command item
|
||||
.sp 0.7
|
||||
command: simple-command
|
||||
\fB( \fIcommand-list \fB)
|
||||
\fB{ \fIcommand-list \fB}
|
||||
\fBfor \fIname \fBdo \fIcommand-list \fBdone
|
||||
\fBfor \fIname \fBin \fIword \*(ZZ \fBdo \fIcommand-list \fBdone
|
||||
\fBwhile \fIcommand-list \fBdo \fIcommand-list \fBdone
|
||||
\fBuntil \fIcommand-list \fBdo \fIcommand-list \fBdone
|
||||
\fBcase \fIword \fBin \fIcase-part \*(ZZ \fBesac
|
||||
\fBif \fIcommand-list \fBthen \fIcommand-list \fIelse-part \fBfi
|
||||
.sp 0.7
|
||||
\fIpipeline: command
|
||||
pipeline \fB\*(VT\fI command
|
||||
.sp 0.7
|
||||
andor: pipeline
|
||||
andor \fB&&\fI pipeline
|
||||
andor \fB\*(VT\*(VT\fI pipeline
|
||||
.sp 0.7
|
||||
command-list: andor
|
||||
command-list \fB;\fI
|
||||
command-list \fB&\fI
|
||||
command-list \fB;\fI andor
|
||||
command-list \fB&\fI andor
|
||||
.sp 0.7
|
||||
input-output: \fB> \fIfile
|
||||
\fB< \fIfile
|
||||
\fB\*(AP \fIword
|
||||
\fB\*(HE \fIword
|
||||
.sp 0.7
|
||||
file: word
|
||||
\fB&\fI digit
|
||||
\fB&\fI \(mi
|
||||
.sp 0.7
|
||||
case-part: pattern\fB ) \fIcommand-list\fB ;;
|
||||
.sp 0.7
|
||||
\fIpattern: word
|
||||
pattern \fB\*(VT\fI word
|
||||
.sp 0.7
|
||||
\fIelse-part: \fBelif \fIcommand-list\fB then\fI command-list else-part\fP
|
||||
\fBelse \fIcommand-list\fI
|
||||
empty
|
||||
.sp 0.7
|
||||
empty:
|
||||
.sp 0.7
|
||||
word: \fRa sequence of non-blank characters\fI
|
||||
.sp 0.7
|
||||
name: \fRa sequence of letters, digits or underscores starting with a letter\fI
|
||||
.sp 0.7
|
||||
digit: \fB0 1 2 3 4 5 6 7 8 9\fP
|
||||
.DE
|
||||
.LP
|
||||
.bp
|
||||
.SH
|
||||
Appendix\ B\ -\ Meta-characters\ and\ Reserved\ Words
|
||||
.LP
|
||||
a) syntactic
|
||||
.RS
|
||||
.IP \fB\*(VT\fR 6
|
||||
pipe symbol
|
||||
.IP \fB&&\fR 6
|
||||
`andf' symbol
|
||||
.IP \fB\*(VT\*(VT\fR 6
|
||||
`orf' symbol
|
||||
.IP \fB;\fP 8
|
||||
command separator
|
||||
.IP \fB;;\fP 8
|
||||
case delimiter
|
||||
.IP \fB&\fP 8
|
||||
background commands
|
||||
.IP \fB(\ )\fP 8
|
||||
command grouping
|
||||
.IP \fB<\fP 8
|
||||
input redirection
|
||||
.IP \fB\*(HE\fP 8
|
||||
input from a here document
|
||||
.IP \fB>\fP 8
|
||||
output creation
|
||||
.IP \fB\*(AP\fP 8
|
||||
output append
|
||||
.sp 2
|
||||
.RE
|
||||
.LP
|
||||
b) patterns
|
||||
.RS
|
||||
.IP \fB\*(ST\fP 8
|
||||
match any character(s) including none
|
||||
.IP \fB?\fP 8
|
||||
match any single character
|
||||
.IP \fB[...]\fP 8
|
||||
match any of the enclosed characters
|
||||
.sp 2
|
||||
.RE
|
||||
.LP
|
||||
c) substitution
|
||||
.RS
|
||||
.IP \fB${...}\fP 8
|
||||
substitute shell variable
|
||||
.IP \fB$(...)\fP 8
|
||||
substitute command output
|
||||
.IP \fB\`...\`\fP 8
|
||||
substitute command output
|
||||
.IP \fB$((...))\fP 8
|
||||
substitute arithmetic expression
|
||||
.sp 2
|
||||
.RE
|
||||
.LP
|
||||
d) quoting
|
||||
.RS
|
||||
.IP \fB\e\fP 8
|
||||
quote the next character
|
||||
.IP \fB\'...\'\fP 8
|
||||
quote the enclosed characters except for \'
|
||||
.IP \fB"\&..."\fP 8
|
||||
quote the enclosed characters except
|
||||
for \fB$ \` \e "\fP
|
||||
.sp 2
|
||||
.RE
|
||||
.LP
|
||||
e) reserved words
|
||||
.DS
|
||||
.ft B
|
||||
if then else elif fi
|
||||
case in esac
|
||||
for while until do done
|
||||
! { }
|
||||
.ft
|
||||
.DE
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: alias.c,v 1.14 2011/06/18 21:18:46 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -30,15 +32,14 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)alias.c 8.3 (Berkeley) 5/4/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: alias.c,v 1.14 2011/06/18 21:18:46 christos Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
#include <sys/cdefs.h>
|
||||
/*
|
||||
__FBSDID("$FreeBSD: src/bin/sh/alias.c,v 1.18 2004/04/06 20:06:51 markm Exp $");
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "shell.h"
|
||||
|
@ -49,18 +50,20 @@ __FBSDID("$FreeBSD: src/bin/sh/alias.c,v 1.18 2004/04/06 20:06:51 markm Exp $");
|
|||
#include "mystring.h"
|
||||
#include "alias.h"
|
||||
#include "options.h" /* XXX for argptr (should remove?) */
|
||||
#include "builtins.h"
|
||||
#include "var.h"
|
||||
|
||||
#define ATABSIZE 39
|
||||
|
||||
STATIC struct alias *atab[ATABSIZE];
|
||||
struct alias *atab[ATABSIZE];
|
||||
|
||||
STATIC void setalias(const char *, const char *);
|
||||
STATIC int unalias(const char *);
|
||||
STATIC struct alias **hashalias(const char *);
|
||||
STATIC void setalias(char *, char *);
|
||||
STATIC int unalias(char *);
|
||||
STATIC struct alias **hashalias(char *);
|
||||
|
||||
STATIC
|
||||
void
|
||||
setalias(const char *name, const char *val)
|
||||
setalias(char *name, char *val)
|
||||
{
|
||||
struct alias *ap, **app;
|
||||
|
||||
|
@ -78,6 +81,7 @@ setalias(const char *name, const char *val)
|
|||
INTOFF;
|
||||
ap = ckmalloc(sizeof (struct alias));
|
||||
ap->name = savestr(name);
|
||||
ap->flag = 0;
|
||||
/*
|
||||
* XXX - HACK: in order that the parser will not finish reading the
|
||||
* alias value off the input before processing the next alias, we
|
||||
|
@ -87,7 +91,7 @@ setalias(const char *name, const char *val)
|
|||
* expanding an alias, the value of the alias is pushed back on the
|
||||
* input as a string and a pointer to the alias is stored with the
|
||||
* string. The alias is marked as being in use. When the input
|
||||
* routine finishes reading the string, it marks the alias not
|
||||
* routine finishes reading the string, it markes the alias not
|
||||
* in use. The problem is synchronization with the parser. Since
|
||||
* it reads ahead, the alias is marked not in use before the
|
||||
* resulting token(s) is next checked for further alias sub. The
|
||||
|
@ -106,14 +110,13 @@ setalias(const char *name, const char *val)
|
|||
ap->val[len+1] = '\0';
|
||||
}
|
||||
#endif
|
||||
ap->flag = 0;
|
||||
ap->next = *app;
|
||||
*app = ap;
|
||||
INTON;
|
||||
}
|
||||
|
||||
STATIC int
|
||||
unalias(const char *name)
|
||||
unalias(char *name)
|
||||
{
|
||||
struct alias *ap, **app;
|
||||
|
||||
|
@ -146,7 +149,8 @@ unalias(const char *name)
|
|||
}
|
||||
|
||||
#ifdef mkinit
|
||||
INCLUDE "alias.h"
|
||||
MKINIT void rmaliases(void);
|
||||
|
||||
SHELLPROC {
|
||||
rmaliases();
|
||||
}
|
||||
|
@ -174,7 +178,7 @@ rmaliases(void)
|
|||
}
|
||||
|
||||
struct alias *
|
||||
lookupalias(const char *name, int check)
|
||||
lookupalias(char *name, int check)
|
||||
{
|
||||
struct alias *ap = *hashalias(name);
|
||||
|
||||
|
@ -189,6 +193,17 @@ lookupalias(const char *name, int check)
|
|||
return (NULL);
|
||||
}
|
||||
|
||||
char *
|
||||
get_alias_text(char *name)
|
||||
{
|
||||
struct alias *ap;
|
||||
|
||||
ap = lookupalias(name, 0);
|
||||
if (ap == NULL)
|
||||
return NULL;
|
||||
return ap->val;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO - sort output
|
||||
*/
|
||||
|
@ -206,23 +221,23 @@ aliascmd(int argc, char **argv)
|
|||
for (ap = atab[i]; ap; ap = ap->next) {
|
||||
if (*ap->name != '\0') {
|
||||
out1fmt("alias %s=", ap->name);
|
||||
out1qstr(ap->val);
|
||||
print_quoted(ap->val);
|
||||
out1c('\n');
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
while ((n = *++argv) != NULL) {
|
||||
if ((v = strchr(n+1, '=')) == NULL) /* n+1: funny ksh stuff */
|
||||
if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
|
||||
if ((ap = lookupalias(n, 0)) == NULL) {
|
||||
outfmt(out2, "alias: %s not found\n", n);
|
||||
ret = 1;
|
||||
} else {
|
||||
out1fmt("alias %s=", n);
|
||||
out1qstr(ap->val);
|
||||
print_quoted(ap->val);
|
||||
out1c('\n');
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
*v++ = '\0';
|
||||
setalias(n, v);
|
||||
}
|
||||
|
@ -232,7 +247,7 @@ aliascmd(int argc, char **argv)
|
|||
}
|
||||
|
||||
int
|
||||
unaliascmd(int argc __unused, char **argv __unused)
|
||||
unaliascmd(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -249,7 +264,7 @@ unaliascmd(int argc __unused, char **argv __unused)
|
|||
}
|
||||
|
||||
STATIC struct alias **
|
||||
hashalias(const char *p)
|
||||
hashalias(char *p)
|
||||
{
|
||||
unsigned int hashval;
|
||||
|
||||
|
@ -258,7 +273,3 @@ hashalias(const char *p)
|
|||
hashval+= *p++;
|
||||
return &atab[hashval % ATABSIZE];
|
||||
}
|
||||
|
||||
/*
|
||||
* $PchId: alias.c,v 1.5 2006/05/22 12:41:12 philip Exp $
|
||||
*/
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: alias.h,v 1.7 2011/06/18 21:18:46 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -30,7 +32,6 @@
|
|||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)alias.h 8.2 (Berkeley) 5/4/95
|
||||
* $FreeBSD: src/bin/sh/alias.h,v 1.8 2004/04/06 20:06:51 markm Exp $
|
||||
*/
|
||||
|
||||
#define ALIASINUSE 1
|
||||
|
@ -42,11 +43,6 @@ struct alias {
|
|||
int flag;
|
||||
};
|
||||
|
||||
struct alias *lookupalias(const char *, int);
|
||||
int aliascmd(int, char **);
|
||||
int unaliascmd(int, char **);
|
||||
struct alias *lookupalias(char *, int);
|
||||
char *get_alias_text(char *);
|
||||
void rmaliases(void);
|
||||
|
||||
/*
|
||||
* $PchId: alias.h,v 1.4 2006/03/31 11:30:54 philip Exp $
|
||||
*/
|
206
bin/sh/arith.y
Normal file
206
bin/sh/arith.y
Normal file
|
@ -0,0 +1,206 @@
|
|||
%{
|
||||
/* $NetBSD: arith.y,v 1.22 2012/03/20 18:42:29 matt Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Kenneth Almquist.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)arith.y 8.3 (Berkeley) 5/4/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: arith.y,v 1.22 2012/03/20 18:42:29 matt Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "expand.h"
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "error.h"
|
||||
#include "output.h"
|
||||
#include "memalloc.h"
|
||||
|
||||
typedef intmax_t YYSTYPE;
|
||||
#define YYSTYPE YYSTYPE
|
||||
|
||||
intmax_t arith_result;
|
||||
const char *arith_buf, *arith_startbuf;
|
||||
|
||||
__dead static void yyerror(const char *);
|
||||
#ifdef TESTARITH
|
||||
int main(int , char *[]);
|
||||
int error(char *);
|
||||
#endif
|
||||
|
||||
%}
|
||||
%token ARITH_NUM ARITH_LPAREN ARITH_RPAREN
|
||||
|
||||
%left ARITH_OR
|
||||
%left ARITH_AND
|
||||
%left ARITH_BOR
|
||||
%left ARITH_BXOR
|
||||
%left ARITH_BAND
|
||||
%left ARITH_EQ ARITH_NE
|
||||
%left ARITH_LT ARITH_GT ARITH_GE ARITH_LE
|
||||
%left ARITH_LSHIFT ARITH_RSHIFT
|
||||
%left ARITH_ADD ARITH_SUB
|
||||
%left ARITH_MUL ARITH_DIV ARITH_REM
|
||||
%left ARITH_UNARYMINUS ARITH_UNARYPLUS ARITH_NOT ARITH_BNOT
|
||||
%%
|
||||
|
||||
exp: expr {
|
||||
/*
|
||||
* yyparse() returns int, so we have to save
|
||||
* the desired result elsewhere.
|
||||
*/
|
||||
arith_result = $1;
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
expr: ARITH_LPAREN expr ARITH_RPAREN { $$ = $2; }
|
||||
| expr ARITH_OR expr { $$ = $1 ? $1 : $3 ? $3 : 0; }
|
||||
| expr ARITH_AND expr { $$ = $1 ? ( $3 ? $3 : 0 ) : 0; }
|
||||
| expr ARITH_BOR expr { $$ = $1 | $3; }
|
||||
| expr ARITH_BXOR expr { $$ = $1 ^ $3; }
|
||||
| expr ARITH_BAND expr { $$ = $1 & $3; }
|
||||
| expr ARITH_EQ expr { $$ = $1 == $3; }
|
||||
| expr ARITH_GT expr { $$ = $1 > $3; }
|
||||
| expr ARITH_GE expr { $$ = $1 >= $3; }
|
||||
| expr ARITH_LT expr { $$ = $1 < $3; }
|
||||
| expr ARITH_LE expr { $$ = $1 <= $3; }
|
||||
| expr ARITH_NE expr { $$ = $1 != $3; }
|
||||
| expr ARITH_LSHIFT expr { $$ = $1 << $3; }
|
||||
| expr ARITH_RSHIFT expr { $$ = $1 >> $3; }
|
||||
| expr ARITH_ADD expr { $$ = $1 + $3; }
|
||||
| expr ARITH_SUB expr { $$ = $1 - $3; }
|
||||
| expr ARITH_MUL expr { $$ = $1 * $3; }
|
||||
| expr ARITH_DIV expr {
|
||||
if ($3 == 0)
|
||||
yyerror("division by zero");
|
||||
$$ = $1 / $3;
|
||||
}
|
||||
| expr ARITH_REM expr {
|
||||
if ($3 == 0)
|
||||
yyerror("division by zero");
|
||||
$$ = $1 % $3;
|
||||
}
|
||||
| ARITH_NOT expr { $$ = !($2); }
|
||||
| ARITH_BNOT expr { $$ = ~($2); }
|
||||
| ARITH_SUB expr %prec ARITH_UNARYMINUS { $$ = -($2); }
|
||||
| ARITH_ADD expr %prec ARITH_UNARYPLUS { $$ = $2; }
|
||||
| ARITH_NUM
|
||||
;
|
||||
%%
|
||||
intmax_t
|
||||
arith(const char *s)
|
||||
{
|
||||
intmax_t result;
|
||||
|
||||
arith_buf = arith_startbuf = s;
|
||||
|
||||
INTOFF;
|
||||
(void) yyparse();
|
||||
result = arith_result;
|
||||
arith_lex_reset(); /* reprime lex */
|
||||
INTON;
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The exp(1) builtin.
|
||||
*/
|
||||
int
|
||||
expcmd(int argc, char **argv)
|
||||
{
|
||||
const char *p;
|
||||
char *concat;
|
||||
char **ap;
|
||||
intmax_t i;
|
||||
|
||||
if (argc > 1) {
|
||||
p = argv[1];
|
||||
if (argc > 2) {
|
||||
/*
|
||||
* concatenate arguments
|
||||
*/
|
||||
STARTSTACKSTR(concat);
|
||||
ap = argv + 2;
|
||||
for (;;) {
|
||||
while (*p)
|
||||
STPUTC(*p++, concat);
|
||||
if ((p = *ap++) == NULL)
|
||||
break;
|
||||
STPUTC(' ', concat);
|
||||
}
|
||||
STPUTC('\0', concat);
|
||||
p = grabstackstr(concat);
|
||||
}
|
||||
} else
|
||||
p = "";
|
||||
|
||||
(void)arith(p);
|
||||
i = arith_result;
|
||||
|
||||
out1fmt("%"PRIdMAX"\n", i);
|
||||
return (! i);
|
||||
}
|
||||
|
||||
/*************************/
|
||||
#ifdef TEST_ARITH
|
||||
#include <stdio.h>
|
||||
main(argc, argv)
|
||||
char *argv[];
|
||||
{
|
||||
printf("%"PRIdMAX"\n", exp(argv[1]));
|
||||
}
|
||||
error(s)
|
||||
char *s;
|
||||
{
|
||||
fprintf(stderr, "exp: %s\n", s);
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
yyerror(const char *s)
|
||||
{
|
||||
|
||||
yyerrok;
|
||||
yyclearin;
|
||||
arith_lex_reset(); /* reprime lex */
|
||||
error("arithmetic expression: %s: \"%s\"", s, arith_startbuf);
|
||||
/* NOTREACHED */
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
%{
|
||||
/* $NetBSD: arith_lex.l,v 1.16 2012/03/20 18:42:29 matt Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -14,7 +16,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -31,103 +33,71 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#if 0
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)arith_lex.l 8.3 (Berkeley) 5/4/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: arith_lex.l,v 1.16 2012/03/20 18:42:29 matt Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
/*
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/bin/sh/arith_lex.l,v 1.22 2004/04/06 20:06:51 markm Exp $");
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "shell.h"
|
||||
#include <unistd.h>
|
||||
#include "arith.h"
|
||||
#include "error.h"
|
||||
#include "memalloc.h"
|
||||
#include "expand.h"
|
||||
#include "var.h"
|
||||
|
||||
extern char *arith_buf, *arith_startbuf;
|
||||
extern intmax_t yylval;
|
||||
extern const char *arith_buf, *arith_startbuf;
|
||||
#undef YY_INPUT
|
||||
#define YY_INPUT(buf,result,max) \
|
||||
result = (*buf = *arith_buf++) ? 1 : YY_NULL;
|
||||
#define YY_NO_UNPUT
|
||||
%}
|
||||
|
||||
%option nounput noinput
|
||||
|
||||
%%
|
||||
[ \t\n] { ; }
|
||||
|
||||
0x[a-fA-F0-9]+ {
|
||||
yylval.l_value = strtoarith_t(yytext, NULL, 16);
|
||||
0x[0-9a-fA-F]+ { yylval = strtoimax(yytext, 0, 0); return(ARITH_NUM); }
|
||||
0[0-7]* { yylval = strtoimax(yytext, 0, 0); return(ARITH_NUM); }
|
||||
[1-9][0-9]* { yylval = strtoimax(yytext, 0, 0); return(ARITH_NUM); }
|
||||
[A-Za-z_][A-Za-z_0-9]* { char *v = lookupvar(yytext);
|
||||
if (v) {
|
||||
yylval = strtoimax(v, &v, 0);
|
||||
if (*v == 0)
|
||||
return ARITH_NUM;
|
||||
}
|
||||
|
||||
0[0-7]+ {
|
||||
yylval.l_value = strtoarith_t(yytext, NULL, 8);
|
||||
return ARITH_NUM;
|
||||
}
|
||||
|
||||
[0-9]+ {
|
||||
yylval.l_value = strtoarith_t(yytext, NULL, 10);
|
||||
return ARITH_NUM;
|
||||
}
|
||||
|
||||
[A-Za-z][A-Za-z0-9_]* {
|
||||
/*
|
||||
* If variable doesn't exist, we should initialize
|
||||
* it to zero.
|
||||
*/
|
||||
char *temp;
|
||||
if (lookupvar(yytext) == NULL)
|
||||
setvarsafe(yytext, "0", 0);
|
||||
temp = (char *)ckmalloc(strlen(yytext) + 1);
|
||||
yylval.s_value = strcpy(temp, yytext);
|
||||
|
||||
return ARITH_VAR;
|
||||
}
|
||||
|
||||
"(" { return ARITH_LPAREN; }
|
||||
")" { return ARITH_RPAREN; }
|
||||
"||" { return ARITH_OR; }
|
||||
"&&" { return ARITH_AND; }
|
||||
"|" { return ARITH_BOR; }
|
||||
"^" { return ARITH_BXOR; }
|
||||
"&" { return ARITH_BAND; }
|
||||
"==" { return ARITH_EQ; }
|
||||
"!=" { return ARITH_NE; }
|
||||
">" { return ARITH_GT; }
|
||||
">=" { return ARITH_GE; }
|
||||
"<" { return ARITH_LT; }
|
||||
"<=" { return ARITH_LE; }
|
||||
"<<" { return ARITH_LSHIFT; }
|
||||
">>" { return ARITH_RSHIFT; }
|
||||
"*" { return ARITH_MUL; }
|
||||
"/" { return ARITH_DIV; }
|
||||
"%" { return ARITH_REM; }
|
||||
"+" { return ARITH_ADD; }
|
||||
"-" { return ARITH_SUB; }
|
||||
"~" { return ARITH_BNOT; }
|
||||
"!" { return ARITH_NOT; }
|
||||
"=" { return ARITH_ASSIGN; }
|
||||
"+=" { return ARITH_ADDASSIGN; }
|
||||
"-=" { return ARITH_SUBASSIGN; }
|
||||
"*=" { return ARITH_MULASSIGN; }
|
||||
"/=" { return ARITH_DIVASSIGN; }
|
||||
"%=" { return ARITH_REMASSIGN; }
|
||||
">>=" { return ARITH_RSHASSIGN; }
|
||||
"<<=" { return ARITH_LSHASSIGN; }
|
||||
"&=" { return ARITH_BANDASSIGN; }
|
||||
"^=" { return ARITH_BXORASSIGN; }
|
||||
"|=" { return ARITH_BORASSIGN; }
|
||||
. {
|
||||
error("arith: syntax error: \"%s\"\n", arith_startbuf);
|
||||
error("arith: syntax error: \"%s\"", arith_startbuf);
|
||||
}
|
||||
"(" { return(ARITH_LPAREN); }
|
||||
")" { return(ARITH_RPAREN); }
|
||||
"||" { return(ARITH_OR); }
|
||||
"&&" { return(ARITH_AND); }
|
||||
"|" { return(ARITH_BOR); }
|
||||
"^" { return(ARITH_BXOR); }
|
||||
"&" { return(ARITH_BAND); }
|
||||
"==" { return(ARITH_EQ); }
|
||||
"!=" { return(ARITH_NE); }
|
||||
">" { return(ARITH_GT); }
|
||||
">=" { return(ARITH_GE); }
|
||||
"<" { return(ARITH_LT); }
|
||||
"<=" { return(ARITH_LE); }
|
||||
"<<" { return(ARITH_LSHIFT); }
|
||||
">>" { return(ARITH_RSHIFT); }
|
||||
"*" { return(ARITH_MUL); }
|
||||
"/" { return(ARITH_DIV); }
|
||||
"%" { return(ARITH_REM); }
|
||||
"+" { return(ARITH_ADD); }
|
||||
"-" { return(ARITH_SUB); }
|
||||
"~" { return(ARITH_BNOT); }
|
||||
"!" { return(ARITH_NOT); }
|
||||
. { error("arith: syntax error: \"%s\"", arith_startbuf); }
|
||||
%%
|
||||
|
||||
void
|
||||
arith_lex_reset(void)
|
||||
{
|
||||
arith_lex_reset(void) {
|
||||
#ifdef YY_NEW_FILE
|
||||
YY_NEW_FILE;
|
||||
#endif
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: bltin.h,v 1.13 2008/10/12 01:40:37 dholland Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -29,63 +31,70 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)bltin.h 8.2 (Berkeley) 5/4/95
|
||||
* $FreeBSD: src/bin/sh/bltin/bltin.h,v 1.13 2004/04/06 20:06:53 markm Exp $
|
||||
* @(#)bltin.h 8.1 (Berkeley) 5/31/93
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is included by programs which are optionally built into the
|
||||
* shell. If SHELL is defined, we try to map the standard UNIX library
|
||||
* routines to ash routines using defines.
|
||||
* shell.
|
||||
*
|
||||
* We always define SHELL_BUILTIN, to allow other included headers to
|
||||
* hide some of their symbols if appropriate.
|
||||
*
|
||||
* If SHELL is defined, we try to map the standard UNIX library routines
|
||||
* to ash routines using defines.
|
||||
*/
|
||||
|
||||
#define SHELL_BUILTIN
|
||||
#include "../shell.h"
|
||||
#include "../mystring.h"
|
||||
#ifdef SHELL
|
||||
#include "builtins.h"
|
||||
#include "../output.h"
|
||||
#include "../error.h"
|
||||
#undef stdout
|
||||
#define stdout out1
|
||||
#undef stderr
|
||||
#define stderr out2
|
||||
#define printf out1fmt
|
||||
#undef putc
|
||||
#define putc(c, file) outc(c, file)
|
||||
#undef putchar
|
||||
#define putchar(c) out1c(c)
|
||||
#define fprintf outfmt
|
||||
#define fputs outstr
|
||||
#define fflush flushout
|
||||
#undef fileno
|
||||
#undef ferror
|
||||
#define FILE struct output
|
||||
#define stdout out1
|
||||
#define stderr out2
|
||||
#define _RETURN_INT(x) ((x), 0) /* map from void foo() to int bar() */
|
||||
#define fprintf(...) _RETURN_INT(outfmt(__VA_ARGS__))
|
||||
#define printf(...) _RETURN_INT(out1fmt(__VA_ARGS__))
|
||||
#define putc(c, file) _RETURN_INT(outc(c, file))
|
||||
#define putchar(c) _RETURN_INT(out1c(c))
|
||||
#define fputs(...) _RETURN_INT(outstr(__VA_ARGS__))
|
||||
#define fflush(f) _RETURN_INT(flushout(f))
|
||||
#define fileno(f) ((f)->fd)
|
||||
#define ferror(f) ((f)->flags & OUTPUT_ERR)
|
||||
#define INITARGS(argv)
|
||||
#define warnx1(a, b, c) { \
|
||||
char buf[64]; \
|
||||
(void)snprintf(buf, sizeof(buf), a); \
|
||||
error("%s", buf); \
|
||||
}
|
||||
#define warnx2(a, b, c) { \
|
||||
char buf[64]; \
|
||||
(void)snprintf(buf, sizeof(buf), a, b); \
|
||||
error("%s", buf); \
|
||||
}
|
||||
#define warnx3(a, b, c) { \
|
||||
char buf[64]; \
|
||||
(void)snprintf(buf, sizeof(buf), a, b, c); \
|
||||
error("%s", buf); \
|
||||
}
|
||||
#define err sh_err
|
||||
#define verr sh_verr
|
||||
#define errx sh_errx
|
||||
#define verrx sh_verrx
|
||||
#define warn sh_warn
|
||||
#define vwarn sh_vwarn
|
||||
#define warnx sh_warnx
|
||||
#define vwarnx sh_vwarnx
|
||||
#define exit sh_exit
|
||||
#define setprogname(s)
|
||||
#define getprogname() commandname
|
||||
#define setlocate(l,s) 0
|
||||
|
||||
#else
|
||||
#define getenv(p) bltinlookup((p),0)
|
||||
|
||||
#else /* ! SHELL */
|
||||
#undef NULL
|
||||
#include <stdio.h>
|
||||
#undef main
|
||||
#define INITARGS(argv) if ((commandname = argv[0]) == NULL) {fputs("Argc is zero\n", stderr); exit(2);} else
|
||||
#endif
|
||||
#endif /* ! SHELL */
|
||||
|
||||
pointer stalloc(int);
|
||||
void error(const char *, ...);
|
||||
|
||||
int echocmd(int, char **);
|
||||
|
||||
|
||||
extern char *commandname;
|
||||
|
||||
/*
|
||||
* $PchId: bltin.h,v 1.4 2006/03/29 11:39:00 philip Exp $
|
||||
*/
|
||||
extern const char *commandname;
|
109
bin/sh/bltin/echo.1
Normal file
109
bin/sh/bltin/echo.1
Normal file
|
@ -0,0 +1,109 @@
|
|||
.\" $NetBSD: echo.1,v 1.13 2003/08/07 09:05:40 agc Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1991, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" This code is derived from software contributed to Berkeley by
|
||||
.\" Kenneth Almquist.
|
||||
.\" Copyright 1989 by Kenneth Almquist
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. Neither the name of the University nor the names of its contributors
|
||||
.\" may be used to endorse or promote products derived from this software
|
||||
.\" without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)echo.1 8.1 (Berkeley) 5/31/93
|
||||
.\"
|
||||
.Dd May 31, 1993
|
||||
.Dt ECHO 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm echo
|
||||
.Nd produce message in a shell script
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl n | Fl e
|
||||
.Ar args ...
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
prints its arguments on the standard output, separated by spaces.
|
||||
Unless the
|
||||
.Fl n
|
||||
option is present, a newline is output following the arguments.
|
||||
The
|
||||
.Fl e
|
||||
option causes
|
||||
.Nm
|
||||
to treat the escape sequences specially, as described in the following
|
||||
paragraph.
|
||||
The
|
||||
.Fl e
|
||||
option is the default, and is provided solely for compatibility with
|
||||
other systems.
|
||||
Only one of the options
|
||||
.Fl n
|
||||
and
|
||||
.Fl e
|
||||
may be given.
|
||||
.Pp
|
||||
If any of the following sequences of characters is encountered during
|
||||
output, the sequence is not output. Instead, the specified action is
|
||||
performed:
|
||||
.Bl -tag -width indent
|
||||
.It Li \eb
|
||||
A backspace character is output.
|
||||
.It Li \ec
|
||||
Subsequent output is suppressed. This is normally used at the end of the
|
||||
last argument to suppress the trailing newline that
|
||||
.Nm
|
||||
would otherwise output.
|
||||
.It Li \ef
|
||||
Output a form feed.
|
||||
.It Li \en
|
||||
Output a newline character.
|
||||
.It Li \er
|
||||
Output a carriage return.
|
||||
.It Li \et
|
||||
Output a (horizontal) tab character.
|
||||
.It Li \ev
|
||||
Output a vertical tab.
|
||||
.It Li \e0 Ns Ar digits
|
||||
Output the character whose value is given by zero to three digits.
|
||||
If there are zero digits, a nul character is output.
|
||||
.It Li \e\e
|
||||
Output a backslash.
|
||||
.El
|
||||
.Sh HINTS
|
||||
Remember that backslash is special to the shell and needs to be escaped.
|
||||
To output a message to standard error, say
|
||||
.Pp
|
||||
.D1 echo message \*[Gt]\*[Am]2
|
||||
.Sh BUGS
|
||||
The octal character escape mechanism
|
||||
.Pq Li \e0 Ns Ar digits
|
||||
differs from the
|
||||
C language mechanism.
|
||||
.Pp
|
||||
There is no way to force
|
||||
.Nm
|
||||
to treat its arguments literally, rather than interpreting them as
|
||||
options and escape sequences.
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: echo.c,v 1.14 2008/10/12 01:40:37 dholland Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -29,61 +31,65 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)echo.c 8.2 (Berkeley) 5/4/95
|
||||
*/
|
||||
|
||||
/*
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/bin/sh/bltin/echo.c,v 1.14 2004/04/06 20:06:53 markm Exp $");
|
||||
* @(#)echo.c 8.1 (Berkeley) 5/31/93
|
||||
*/
|
||||
|
||||
/*
|
||||
* Echo command.
|
||||
*
|
||||
* echo is steeped in tradition - several of them!
|
||||
* netbsd has supported 'echo [-n | -e] args' in spite of -e not being
|
||||
* documented anywhere.
|
||||
* Posix requires that -n be supported, output from strings containing
|
||||
* \ is implementation defined
|
||||
* The Single Unix Spec requires that \ escapes be treated as if -e
|
||||
* were set, but that -n not be treated as an option.
|
||||
* (ksh supports 'echo [-eEn] args', but not -- so that it is actually
|
||||
* impossible to actually output '-n')
|
||||
*
|
||||
* It is suggested that 'printf "%b" "string"' be used to get \ sequences
|
||||
* expanded. printf is now a builtin of netbsd's sh and csh.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: echo.c,v 1.14 2008/10/12 01:40:37 dholland Exp $");
|
||||
|
||||
#define main echocmd
|
||||
|
||||
#include "bltin.h"
|
||||
|
||||
int
|
||||
echocmd(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
char **ap;
|
||||
char *p;
|
||||
char c;
|
||||
int count;
|
||||
int nflag = 0;
|
||||
#ifdef __minix
|
||||
int eflag = 0;
|
||||
#endif
|
||||
|
||||
ap = argv;
|
||||
if (argc)
|
||||
ap++;
|
||||
|
||||
if ((p = *ap) != NULL) {
|
||||
#ifdef __minix
|
||||
if (equal(p, "--")) {
|
||||
ap++;
|
||||
}
|
||||
#endif
|
||||
if (equal(p, "-n")) {
|
||||
nflag++;
|
||||
nflag = 1;
|
||||
ap++;
|
||||
} else if (equal(p, "-e")) {
|
||||
#ifdef __minix
|
||||
eflag++;
|
||||
#endif
|
||||
eflag = 1;
|
||||
ap++;
|
||||
}
|
||||
}
|
||||
|
||||
while ((p = *ap++) != NULL) {
|
||||
while ((c = *p++) != '\0') {
|
||||
if (c == '\\' && eflag) {
|
||||
switch (*p++) {
|
||||
case 'a': c = '\a'; break;
|
||||
case 'a': c = '\a'; break; /* bell */
|
||||
case 'b': c = '\b'; break;
|
||||
case 'c': return 0; /* exit */
|
||||
case 'e': c = '\033'; break;
|
||||
case 'e': c = 033; break; /* escape */
|
||||
case 'f': c = '\f'; break;
|
||||
case 'n': c = '\n'; break;
|
||||
case 'r': c = '\r'; break;
|
||||
|
@ -97,6 +103,7 @@ echocmd(argc, argv)
|
|||
c = (c << 3) + (*p++ - '0');
|
||||
break;
|
||||
default:
|
||||
/* Output the '/' and char following */
|
||||
p--;
|
||||
break;
|
||||
}
|
||||
|
@ -108,9 +115,8 @@ echocmd(argc, argv)
|
|||
}
|
||||
if (! nflag)
|
||||
putchar('\n');
|
||||
fflush(stdout);
|
||||
if (ferror(stdout))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* $PchId: echo.c,v 1.5 2006/05/23 12:05:56 philip Exp $
|
||||
*/
|
|
@ -1,4 +1,5 @@
|
|||
#!/bin/sh -
|
||||
# $NetBSD: builtins.def,v 1.22 2012/12/31 14:10:15 dsl Exp $
|
||||
#
|
||||
# Copyright (c) 1991, 1993
|
||||
# The Regents of the University of California. All rights reserved.
|
||||
|
@ -14,7 +15,7 @@
|
|||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 4. Neither the name of the University nor the names of its contributors
|
||||
# 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.
|
||||
#
|
||||
|
@ -31,63 +32,62 @@
|
|||
# SUCH DAMAGE.
|
||||
#
|
||||
# @(#)builtins.def 8.4 (Berkeley) 5/4/95
|
||||
# $FreeBSD: src/bin/sh/builtins.def,v 1.14 2004/04/06 20:06:51 markm Exp $
|
||||
|
||||
#
|
||||
# This file lists all the builtin commands. The first column is the name
|
||||
# of a C routine. The -j flag, if present, specifies that this command
|
||||
# is to be excluded from systems without job control, and the -h flag,
|
||||
# if present specifies that this command is to be excluded from systems
|
||||
# based on the NO_HISTORY compile-time symbol. The rest of the line
|
||||
# specifies the command name or names used to run the command. The entry
|
||||
# for bltincmd, which is run when the user does not specify a command, must
|
||||
# come first.
|
||||
#
|
||||
# NOTE: bltincmd must come first!
|
||||
# of a C routine.
|
||||
# The -j flag specifies that this command is to be excluded from systems
|
||||
# without job control.
|
||||
# The -h flag specifies that this command is to be excluded from systems
|
||||
# based on the SMALL compile-time symbol.
|
||||
# The -s flag specifies that this is a posix 'special builtin' command.
|
||||
# The -u flag specifies that this is a posix 'standard utility'.
|
||||
# The rest of the line specifies the command name or names used to run
|
||||
# the command.
|
||||
|
||||
bltincmd builtin
|
||||
commandcmd command
|
||||
#if JOBS
|
||||
bgcmd -j bg
|
||||
#endif
|
||||
breakcmd break continue
|
||||
#catfcmd catf
|
||||
cdcmd cd chdir
|
||||
dotcmd .
|
||||
bltincmd -u command
|
||||
bgcmd -j -u bg
|
||||
breakcmd -s break -s continue
|
||||
cdcmd -u cd chdir
|
||||
dotcmd -s .
|
||||
echocmd echo
|
||||
evalcmd eval
|
||||
execcmd exec
|
||||
exitcmd exit
|
||||
evalcmd -s eval
|
||||
execcmd -s exec
|
||||
exitcmd -s exit
|
||||
expcmd exp let
|
||||
exportcmd export readonly
|
||||
exprcmd expr test [
|
||||
falsecmd false
|
||||
histcmd -h fc
|
||||
#if JOBS
|
||||
fgcmd -j fg
|
||||
#endif
|
||||
getoptscmd getopts
|
||||
exportcmd -s export -s readonly
|
||||
falsecmd -u false
|
||||
histcmd -h -u fc
|
||||
inputrc inputrc
|
||||
fgcmd -j -u fg
|
||||
fgcmd_percent -j -u %
|
||||
getoptscmd -u getopts
|
||||
hashcmd hash
|
||||
jobidcmd jobid
|
||||
jobscmd jobs
|
||||
jobscmd -u jobs
|
||||
localcmd local
|
||||
#ifndef SMALL
|
||||
#printfcmd printf
|
||||
printfcmd printf
|
||||
#endif
|
||||
pwdcmd pwd
|
||||
readcmd read
|
||||
returncmd return
|
||||
setcmd set
|
||||
pwdcmd -u pwd
|
||||
readcmd -u read
|
||||
returncmd -s return
|
||||
setcmd -s set
|
||||
setvarcmd setvar
|
||||
shiftcmd shift
|
||||
trapcmd trap
|
||||
truecmd : true
|
||||
shiftcmd -s shift
|
||||
timescmd -s times
|
||||
trapcmd -s trap
|
||||
truecmd -s : -u true
|
||||
typecmd type
|
||||
umaskcmd umask
|
||||
unaliascmd unalias
|
||||
unsetcmd unset
|
||||
waitcmd wait
|
||||
aliascmd alias
|
||||
umaskcmd -u umask
|
||||
unaliascmd -u unalias
|
||||
unsetcmd -s unset
|
||||
waitcmd -u wait
|
||||
aliascmd -u alias
|
||||
ulimitcmd ulimit
|
||||
bindcmd bind
|
||||
testcmd test [
|
||||
killcmd -u kill # mandated by posix for 'kill %job'
|
||||
wordexpcmd wordexp
|
||||
#newgrp -u newgrp # optional command in posix
|
||||
|
||||
#exprcmd expr
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: cd.c,v 1.44 2011/08/31 16:24:54 plunky Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -30,15 +32,14 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)cd.c 8.2 (Berkeley) 5/4/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: cd.c,v 1.44 2011/08/31 16:24:54 plunky Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
/*
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/bin/sh/cd.c,v 1.34 2004/04/06 20:06:51 markm Exp $");
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
@ -46,7 +47,6 @@ __FBSDID("$FreeBSD: src/bin/sh/cd.c,v 1.34 2004/04/06 20:06:51 markm Exp $");
|
|||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
|
||||
/*
|
||||
* The cd and pwd commands.
|
||||
|
@ -57,68 +57,74 @@ __FBSDID("$FreeBSD: src/bin/sh/cd.c,v 1.34 2004/04/06 20:06:51 markm Exp $");
|
|||
#include "nodes.h" /* for jobs.h */
|
||||
#include "jobs.h"
|
||||
#include "options.h"
|
||||
#include "builtins.h"
|
||||
#include "output.h"
|
||||
#include "memalloc.h"
|
||||
#include "error.h"
|
||||
#include "exec.h"
|
||||
#include "redir.h"
|
||||
#include "mystring.h"
|
||||
#include "builtins.h"
|
||||
#include "show.h"
|
||||
#include "cd.h"
|
||||
|
||||
STATIC int cdlogical(const char *);
|
||||
STATIC int cdphysical(const char *);
|
||||
STATIC int docd(const char *, int, int);
|
||||
STATIC int docd(const char *, int);
|
||||
STATIC char *getcomponent(void);
|
||||
STATIC int updatepwd(const char *);
|
||||
STATIC void updatepwd(const char *);
|
||||
STATIC void find_curdir(int noerror);
|
||||
|
||||
STATIC char *curdir = NULL; /* current working directory */
|
||||
STATIC char *prevdir; /* previous working directory */
|
||||
char *curdir = NULL; /* current working directory */
|
||||
char *prevdir; /* previous working directory */
|
||||
STATIC char *cdcomppath;
|
||||
|
||||
int
|
||||
cdcmd(int argc, char **argv)
|
||||
{
|
||||
char *dest;
|
||||
char *path;
|
||||
char *p;
|
||||
const char *dest;
|
||||
const char *path, *p;
|
||||
char *d;
|
||||
struct stat statb;
|
||||
int ch, phys, print = 0;
|
||||
int print = cdprint; /* set -cdprint to enable */
|
||||
|
||||
optreset = 1; optind = 1; opterr = 0; /* initialize getopt */
|
||||
phys = Pflag;
|
||||
while ((ch = getopt(argc, argv, "LP")) != -1) {
|
||||
switch (ch) {
|
||||
case 'L':
|
||||
phys = 0;
|
||||
break;
|
||||
case 'P':
|
||||
phys = 1;
|
||||
break;
|
||||
default:
|
||||
error("unknown option: -%c", optopt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
while (nextopt("P") != '\0')
|
||||
;
|
||||
|
||||
if (argc > 1)
|
||||
error("too many arguments");
|
||||
|
||||
if ((dest = *argv) == NULL && (dest = bltinlookup("HOME", 1)) == NULL)
|
||||
/*
|
||||
* Try (quite hard) to have 'curdir' defined, nothing has set
|
||||
* it on entry to the shell, but we want 'cd fred; cd -' to work.
|
||||
*/
|
||||
getpwd(1);
|
||||
dest = *argptr;
|
||||
if (dest == NULL) {
|
||||
dest = bltinlookup("HOME", 1);
|
||||
if (dest == NULL)
|
||||
error("HOME not set");
|
||||
if (*dest == '\0')
|
||||
dest = ".";
|
||||
} else {
|
||||
if (argptr[1]) {
|
||||
/* Do 'ksh' style substitution */
|
||||
if (!curdir)
|
||||
error("PWD not set");
|
||||
p = strstr(curdir, dest);
|
||||
if (!p)
|
||||
error("bad substitution");
|
||||
d = stalloc(strlen(curdir) + strlen(argptr[1]) + 1);
|
||||
memcpy(d, curdir, p - curdir);
|
||||
strcpy(d + (p - curdir), argptr[1]);
|
||||
strcat(d, p + strlen(dest));
|
||||
dest = d;
|
||||
print = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (dest[0] == '-' && dest[1] == '\0') {
|
||||
dest = prevdir ? prevdir : curdir;
|
||||
if (dest)
|
||||
print = 1;
|
||||
else
|
||||
dest = ".";
|
||||
}
|
||||
if (*dest == '/' || (path = bltinlookup("CDPATH", 1)) == NULL)
|
||||
if (*dest == '\0')
|
||||
dest = ".";
|
||||
p = dest;
|
||||
if (*p == '.' && *++p == '.')
|
||||
p++;
|
||||
if (*p == 0 || *p == '/' || (path = bltinlookup("CDPATH", 1)) == NULL)
|
||||
path = nullstr;
|
||||
while ((p = padvance(&path, dest)) != NULL) {
|
||||
if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
|
||||
|
@ -127,41 +133,27 @@ cdcmd(int argc, char **argv)
|
|||
* XXX - rethink
|
||||
*/
|
||||
if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
|
||||
p += 2;
|
||||
print = strcmp(p + 2, dest);
|
||||
else
|
||||
print = strcmp(p, dest);
|
||||
}
|
||||
if (docd(p, print, phys) >= 0)
|
||||
if (docd(p, print) >= 0)
|
||||
return 0;
|
||||
|
||||
}
|
||||
}
|
||||
error("can't cd to %s", dest);
|
||||
/* NOTREACHED */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Actually change the directory. In an interactive shell, print the
|
||||
* Actually do the chdir. In an interactive shell, print the
|
||||
* directory name if "print" is nonzero.
|
||||
*/
|
||||
STATIC int
|
||||
docd(const char *dest, int print, int phys)
|
||||
{
|
||||
|
||||
TRACE(("docd(\"%s\", %d, %d) called\n", dest, print, phys));
|
||||
|
||||
/* If logical cd fails, fall back to physical. */
|
||||
if ((phys || cdlogical(dest) < 0) && cdphysical(dest) < 0)
|
||||
return (-1);
|
||||
|
||||
if (print && iflag && curdir)
|
||||
out1fmt("%s\n", curdir);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
STATIC int
|
||||
cdlogical(const char *dest)
|
||||
docd(const char *dest, int print)
|
||||
{
|
||||
char *p;
|
||||
char *q;
|
||||
|
@ -170,6 +162,8 @@ cdlogical(const char *dest)
|
|||
int first;
|
||||
int badstat;
|
||||
|
||||
TRACE(("docd(\"%s\", %d) called\n", dest, print));
|
||||
|
||||
/*
|
||||
* Check each component of the path. If we find a symlink or
|
||||
* something we can't stat, clear curdir to force a getcwd()
|
||||
|
@ -196,38 +190,32 @@ cdlogical(const char *dest)
|
|||
if (equal(component, ".."))
|
||||
continue;
|
||||
STACKSTRNUL(p);
|
||||
if (lstat(stackblock(), &statb) < 0) {
|
||||
if ((lstat(stackblock(), &statb) < 0)
|
||||
|| (S_ISLNK(statb.st_mode))) {
|
||||
/* print = 1; */
|
||||
badstat = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
INTOFF;
|
||||
if (updatepwd(badstat ? NULL : dest) < 0 || chdir(curdir) < 0) {
|
||||
if (chdir(dest) < 0) {
|
||||
INTON;
|
||||
return (-1);
|
||||
return -1;
|
||||
}
|
||||
updatepwd(badstat ? NULL : dest);
|
||||
INTON;
|
||||
return (0);
|
||||
if (print && iflag == 1 && curdir)
|
||||
out1fmt("%s\n", curdir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
STATIC int
|
||||
cdphysical(const char *dest)
|
||||
{
|
||||
|
||||
INTOFF;
|
||||
if (chdir(dest) < 0 || updatepwd(NULL) < 0) {
|
||||
INTON;
|
||||
return (-1);
|
||||
}
|
||||
INTON;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the next component of the path name pointed to by cdcomppath.
|
||||
* This routine overwrites the string pointed to by cdcomppath.
|
||||
*/
|
||||
|
||||
STATIC char *
|
||||
getcomponent(void)
|
||||
{
|
||||
|
@ -249,12 +237,14 @@ getcomponent(void)
|
|||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Update curdir (the name of the current directory) in response to a
|
||||
* cd command. We also call hashcd to let the routines in exec.c know
|
||||
* that the current directory has changed.
|
||||
*/
|
||||
STATIC int
|
||||
|
||||
STATIC void
|
||||
updatepwd(const char *dir)
|
||||
{
|
||||
char *new;
|
||||
|
@ -273,14 +263,14 @@ updatepwd(const char *dir)
|
|||
INTOFF;
|
||||
prevdir = curdir;
|
||||
curdir = NULL;
|
||||
if (getpwd() == NULL) {
|
||||
getpwd(1);
|
||||
INTON;
|
||||
return (-1);
|
||||
}
|
||||
setvar("PWD", curdir, VEXPORT);
|
||||
if (curdir) {
|
||||
setvar("OLDPWD", prevdir, VEXPORT);
|
||||
INTON;
|
||||
return (0);
|
||||
setvar("PWD", curdir, VEXPORT);
|
||||
} else
|
||||
unsetvar("PWD", 0);
|
||||
return;
|
||||
}
|
||||
cdcomppath = stalloc(strlen(dir) + 1);
|
||||
scopy(dir, cdcomppath);
|
||||
|
@ -309,82 +299,166 @@ updatepwd(const char *dir)
|
|||
ckfree(prevdir);
|
||||
prevdir = curdir;
|
||||
curdir = savestr(stackblock());
|
||||
setvar("PWD", curdir, VEXPORT);
|
||||
setvar("OLDPWD", prevdir, VEXPORT);
|
||||
setvar("PWD", curdir, VEXPORT);
|
||||
INTON;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Posix says the default should be 'pwd -L' (as below), however
|
||||
* the 'cd' command (above) does something much nearer to the
|
||||
* posix 'cd -P' (not the posix default of 'cd -L').
|
||||
* If 'cd' is changed to support -P/L then the default here
|
||||
* needs to be revisited if the historic behaviour is to be kept.
|
||||
*/
|
||||
|
||||
int
|
||||
pwdcmd(int argc, char **argv)
|
||||
{
|
||||
char buf[PATH_MAX];
|
||||
int ch, phys;
|
||||
int i;
|
||||
char opt = 'L';
|
||||
|
||||
optreset = 1; optind = 1; opterr = 0; /* initialize getopt */
|
||||
phys = Pflag;
|
||||
while ((ch = getopt(argc, argv, "LP")) != -1) {
|
||||
switch (ch) {
|
||||
case 'L':
|
||||
phys = 0;
|
||||
break;
|
||||
case 'P':
|
||||
phys = 1;
|
||||
break;
|
||||
default:
|
||||
error("unknown option: -%c", optopt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
while ((i = nextopt("LP")) != '\0')
|
||||
opt = i;
|
||||
if (*argptr)
|
||||
error("unexpected argument");
|
||||
|
||||
if (argc != 0)
|
||||
error("too many arguments");
|
||||
if (opt == 'L')
|
||||
getpwd(0);
|
||||
else
|
||||
find_curdir(0);
|
||||
|
||||
if (!phys && getpwd()) {
|
||||
setvar("OLDPWD", prevdir, VEXPORT);
|
||||
setvar("PWD", curdir, VEXPORT);
|
||||
out1str(curdir);
|
||||
out1c('\n');
|
||||
} else {
|
||||
if (getcwd(buf, sizeof(buf)) == NULL)
|
||||
error(".: %s", strerror(errno));
|
||||
out1str(buf);
|
||||
out1c('\n');
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
initpwd(void)
|
||||
{
|
||||
getpwd(1);
|
||||
if (curdir)
|
||||
setvar("PWD", curdir, VEXPORT);
|
||||
else
|
||||
sh_warnx("Cannot determine current working directory");
|
||||
}
|
||||
|
||||
#define MAXPWD 256
|
||||
|
||||
/*
|
||||
* Find out what the current directory is. If we already know the current
|
||||
* directory, this routine returns immediately.
|
||||
*/
|
||||
char *
|
||||
getpwd(void)
|
||||
void
|
||||
getpwd(int noerror)
|
||||
{
|
||||
char buf[PATH_MAX];
|
||||
char *pwd;
|
||||
struct stat stdot, stpwd;
|
||||
static int first = 1;
|
||||
|
||||
if (curdir)
|
||||
return curdir;
|
||||
if (getcwd(buf, sizeof(buf)) == NULL) {
|
||||
char *pwd = getenv("PWD");
|
||||
struct stat stdot, stpwd;
|
||||
return;
|
||||
|
||||
if (first) {
|
||||
first = 0;
|
||||
pwd = getenv("PWD");
|
||||
if (pwd && *pwd == '/' && stat(".", &stdot) != -1 &&
|
||||
stat(pwd, &stpwd) != -1 &&
|
||||
stdot.st_dev == stpwd.st_dev &&
|
||||
stdot.st_ino == stpwd.st_ino) {
|
||||
curdir = savestr(pwd);
|
||||
return curdir;
|
||||
return;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
curdir = savestr(buf);
|
||||
|
||||
return curdir;
|
||||
find_curdir(noerror);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
STATIC void
|
||||
find_curdir(int noerror)
|
||||
{
|
||||
int i;
|
||||
char *pwd;
|
||||
|
||||
/*
|
||||
* $PchId: cd.c,v 1.6 2006/05/22 12:42:03 philip Exp $
|
||||
* Things are a bit complicated here; we could have just used
|
||||
* getcwd, but traditionally getcwd is implemented using popen
|
||||
* to /bin/pwd. This creates a problem for us, since we cannot
|
||||
* keep track of the job if it is being ran behind our backs.
|
||||
* So we re-implement getcwd(), and we suppress interrupts
|
||||
* throughout the process. This is not completely safe, since
|
||||
* the user can still break out of it by killing the pwd program.
|
||||
* We still try to use getcwd for systems that we know have a
|
||||
* c implementation of getcwd, that does not open a pipe to
|
||||
* /bin/pwd.
|
||||
*/
|
||||
#if defined(__NetBSD__) || defined(__SVR4) || defined(__minix)
|
||||
|
||||
for (i = MAXPWD;; i *= 2) {
|
||||
pwd = stalloc(i);
|
||||
if (getcwd(pwd, i) != NULL) {
|
||||
curdir = savestr(pwd);
|
||||
return;
|
||||
}
|
||||
stunalloc(pwd);
|
||||
if (errno == ERANGE)
|
||||
continue;
|
||||
if (!noerror)
|
||||
error("getcwd() failed: %s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
#else
|
||||
{
|
||||
char *p;
|
||||
int status;
|
||||
struct job *jp;
|
||||
int pip[2];
|
||||
|
||||
pwd = stalloc(MAXPWD);
|
||||
INTOFF;
|
||||
if (pipe(pip) < 0)
|
||||
error("Pipe call failed");
|
||||
jp = makejob(NULL, 1);
|
||||
if (forkshell(jp, NULL, FORK_NOJOB) == 0) {
|
||||
(void) close(pip[0]);
|
||||
if (pip[1] != 1) {
|
||||
close(1);
|
||||
copyfd(pip[1], 1, 1);
|
||||
close(pip[1]);
|
||||
}
|
||||
(void) execl("/bin/pwd", "pwd", (char *)0);
|
||||
error("Cannot exec /bin/pwd");
|
||||
}
|
||||
(void) close(pip[1]);
|
||||
pip[1] = -1;
|
||||
p = pwd;
|
||||
while ((i = read(pip[0], p, pwd + MAXPWD - p)) > 0
|
||||
|| (i == -1 && errno == EINTR)) {
|
||||
if (i > 0)
|
||||
p += i;
|
||||
}
|
||||
(void) close(pip[0]);
|
||||
pip[0] = -1;
|
||||
status = waitforjob(jp);
|
||||
if (status != 0)
|
||||
error((char *)0);
|
||||
if (i < 0 || p == pwd || p[-1] != '\n') {
|
||||
if (noerror) {
|
||||
INTON;
|
||||
return;
|
||||
}
|
||||
error("pwd command failed");
|
||||
}
|
||||
p[-1] = '\0';
|
||||
INTON;
|
||||
curdir = savestr(pwd);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: cd.h,v 1.6 2011/06/18 21:18:46 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1995
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -10,7 +12,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -26,13 +28,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD: src/bin/sh/cd.h,v 1.7 2004/04/06 20:06:51 markm Exp $
|
||||
*/
|
||||
|
||||
char *getpwd(void);
|
||||
int cdcmd (int, char **);
|
||||
int pwdcmd(int, char **);
|
||||
|
||||
/*
|
||||
* $PchId: cd.h,v 1.3 2006/03/31 09:59:04 philip Exp $
|
||||
*/
|
||||
void initpwd(void);
|
||||
void getpwd(int);
|
370
bin/sh/error.c
Normal file
370
bin/sh/error.c
Normal file
|
@ -0,0 +1,370 @@
|
|||
/* $NetBSD: error.c,v 1.38 2012/03/15 02:02:20 joerg Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Kenneth Almquist.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)error.c 8.2 (Berkeley) 5/4/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: error.c,v 1.38 2012/03/15 02:02:20 joerg Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* Errors and exceptions.
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "shell.h"
|
||||
#include "eval.h" /* for commandname */
|
||||
#include "main.h"
|
||||
#include "options.h"
|
||||
#include "output.h"
|
||||
#include "error.h"
|
||||
#include "show.h"
|
||||
|
||||
|
||||
/*
|
||||
* Code to handle exceptions in C.
|
||||
*/
|
||||
|
||||
struct jmploc *handler;
|
||||
int exception;
|
||||
volatile int suppressint;
|
||||
volatile int intpending;
|
||||
|
||||
|
||||
static void exverror(int, const char *, va_list) __dead;
|
||||
|
||||
/*
|
||||
* Called to raise an exception. Since C doesn't include exceptions, we
|
||||
* just do a longjmp to the exception handler. The type of exception is
|
||||
* stored in the global variable "exception".
|
||||
*/
|
||||
|
||||
void
|
||||
exraise(int e)
|
||||
{
|
||||
if (handler == NULL)
|
||||
abort();
|
||||
exception = e;
|
||||
longjmp(handler->loc, 1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Called from trap.c when a SIGINT is received. (If the user specifies
|
||||
* that SIGINT is to be trapped or ignored using the trap builtin, then
|
||||
* this routine is not called.) Suppressint is nonzero when interrupts
|
||||
* are held using the INTOFF macro. The call to _exit is necessary because
|
||||
* there is a short period after a fork before the signal handlers are
|
||||
* set to the appropriate value for the child. (The test for iflag is
|
||||
* just defensive programming.)
|
||||
*/
|
||||
|
||||
void
|
||||
onint(void)
|
||||
{
|
||||
sigset_t nsigset;
|
||||
|
||||
if (suppressint) {
|
||||
intpending = 1;
|
||||
return;
|
||||
}
|
||||
intpending = 0;
|
||||
sigemptyset(&nsigset);
|
||||
sigprocmask(SIG_SETMASK, &nsigset, NULL);
|
||||
if (rootshell && iflag)
|
||||
exraise(EXINT);
|
||||
else {
|
||||
signal(SIGINT, SIG_DFL);
|
||||
raise(SIGINT);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
static __printflike(2, 0) void
|
||||
exvwarning(int sv_errno, const char *msg, va_list ap)
|
||||
{
|
||||
/* Partially emulate line buffered output so that:
|
||||
* printf '%d\n' 1 a 2
|
||||
* and
|
||||
* printf '%d %d %d\n' 1 a 2
|
||||
* both generate sensible text when stdout and stderr are merged.
|
||||
*/
|
||||
if (output.nextc != output.buf && output.nextc[-1] == '\n')
|
||||
flushout(&output);
|
||||
if (commandname)
|
||||
outfmt(&errout, "%s: ", commandname);
|
||||
else
|
||||
outfmt(&errout, "%s: ", getprogname());
|
||||
if (msg != NULL) {
|
||||
doformat(&errout, msg, ap);
|
||||
if (sv_errno >= 0)
|
||||
outfmt(&errout, ": ");
|
||||
}
|
||||
if (sv_errno >= 0)
|
||||
outfmt(&errout, "%s", strerror(sv_errno));
|
||||
out2c('\n');
|
||||
flushout(&errout);
|
||||
}
|
||||
|
||||
/*
|
||||
* Exverror is called to raise the error exception. If the second argument
|
||||
* is not NULL then error prints an error message using printf style
|
||||
* formatting. It then raises the error exception.
|
||||
*/
|
||||
static __printflike(2, 0) void
|
||||
exverror(int cond, const char *msg, va_list ap)
|
||||
{
|
||||
CLEAR_PENDING_INT;
|
||||
INTOFF;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (msg) {
|
||||
TRACE(("exverror(%d, \"", cond));
|
||||
TRACEV((msg, ap));
|
||||
TRACE(("\") pid=%d\n", getpid()));
|
||||
} else
|
||||
TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
|
||||
#endif
|
||||
if (msg)
|
||||
exvwarning(-1, msg, ap);
|
||||
|
||||
flushall();
|
||||
exraise(cond);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
error(const char *msg, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, msg);
|
||||
exverror(EXERROR, msg, ap);
|
||||
/* NOTREACHED */
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
exerror(int cond, const char *msg, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, msg);
|
||||
exverror(cond, msg, ap);
|
||||
/* NOTREACHED */
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/*
|
||||
* error/warning routines for external builtins
|
||||
*/
|
||||
|
||||
void
|
||||
sh_exit(int rval)
|
||||
{
|
||||
exerrno = rval & 255;
|
||||
exraise(EXEXEC);
|
||||
}
|
||||
|
||||
void
|
||||
sh_err(int status, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
exvwarning(errno, fmt, ap);
|
||||
va_end(ap);
|
||||
sh_exit(status);
|
||||
}
|
||||
|
||||
void
|
||||
sh_verr(int status, const char *fmt, va_list ap)
|
||||
{
|
||||
exvwarning(errno, fmt, ap);
|
||||
sh_exit(status);
|
||||
}
|
||||
|
||||
void
|
||||
sh_errx(int status, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
exvwarning(-1, fmt, ap);
|
||||
va_end(ap);
|
||||
sh_exit(status);
|
||||
}
|
||||
|
||||
void
|
||||
sh_verrx(int status, const char *fmt, va_list ap)
|
||||
{
|
||||
exvwarning(-1, fmt, ap);
|
||||
sh_exit(status);
|
||||
}
|
||||
|
||||
void
|
||||
sh_warn(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
exvwarning(errno, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
sh_vwarn(const char *fmt, va_list ap)
|
||||
{
|
||||
exvwarning(errno, fmt, ap);
|
||||
}
|
||||
|
||||
void
|
||||
sh_warnx(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
exvwarning(-1, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
sh_vwarnx(const char *fmt, va_list ap)
|
||||
{
|
||||
exvwarning(-1, fmt, ap);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Table of error messages.
|
||||
*/
|
||||
|
||||
struct errname {
|
||||
short errcode; /* error number */
|
||||
short action; /* operation which encountered the error */
|
||||
const char *msg; /* text describing the error */
|
||||
};
|
||||
|
||||
|
||||
#define ALL (E_OPEN|E_CREAT|E_EXEC)
|
||||
|
||||
STATIC const struct errname errormsg[] = {
|
||||
{ EINTR, ALL, "interrupted" },
|
||||
{ EACCES, ALL, "permission denied" },
|
||||
{ EIO, ALL, "I/O error" },
|
||||
{ EEXIST, ALL, "file exists" },
|
||||
{ ENOENT, E_OPEN, "no such file" },
|
||||
{ ENOENT, E_CREAT,"directory nonexistent" },
|
||||
{ ENOENT, E_EXEC, "not found" },
|
||||
{ ENOTDIR, E_OPEN, "no such file" },
|
||||
{ ENOTDIR, E_CREAT,"directory nonexistent" },
|
||||
{ ENOTDIR, E_EXEC, "not found" },
|
||||
{ EISDIR, ALL, "is a directory" },
|
||||
#ifdef EMFILE
|
||||
{ EMFILE, ALL, "too many open files" },
|
||||
#endif
|
||||
{ ENFILE, ALL, "file table overflow" },
|
||||
{ ENOSPC, ALL, "file system full" },
|
||||
#ifdef EDQUOT
|
||||
{ EDQUOT, ALL, "disk quota exceeded" },
|
||||
#endif
|
||||
#ifdef ENOSR
|
||||
{ ENOSR, ALL, "no streams resources" },
|
||||
#endif
|
||||
{ ENXIO, ALL, "no such device or address" },
|
||||
{ EROFS, ALL, "read-only file system" },
|
||||
{ ETXTBSY, ALL, "text busy" },
|
||||
#ifdef EAGAIN
|
||||
{ EAGAIN, E_EXEC, "not enough memory" },
|
||||
#endif
|
||||
{ ENOMEM, ALL, "not enough memory" },
|
||||
#ifdef ENOLINK
|
||||
{ ENOLINK, ALL, "remote access failed" },
|
||||
#endif
|
||||
#ifdef EMULTIHOP
|
||||
{ EMULTIHOP, ALL, "remote access failed" },
|
||||
#endif
|
||||
#ifdef ECOMM
|
||||
{ ECOMM, ALL, "remote access failed" },
|
||||
#endif
|
||||
#ifdef ESTALE
|
||||
{ ESTALE, ALL, "remote access failed" },
|
||||
#endif
|
||||
#ifdef ETIMEDOUT
|
||||
{ ETIMEDOUT, ALL, "remote access failed" },
|
||||
#endif
|
||||
#ifdef ELOOP
|
||||
{ ELOOP, ALL, "symbolic link loop" },
|
||||
#endif
|
||||
#ifdef ENAMETOOLONG
|
||||
{ ENAMETOOLONG, ALL, "file name too long" },
|
||||
#endif
|
||||
{ E2BIG, E_EXEC, "argument list too long" },
|
||||
#ifdef ELIBACC
|
||||
{ ELIBACC, E_EXEC, "shared library missing" },
|
||||
#endif
|
||||
{ 0, 0, NULL },
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Return a string describing an error. The returned string may be a
|
||||
* pointer to a static buffer that will be overwritten on the next call.
|
||||
* Action describes the operation that got the error.
|
||||
*/
|
||||
|
||||
const char *
|
||||
errmsg(int e, int action)
|
||||
{
|
||||
struct errname const *ep;
|
||||
static char buf[12];
|
||||
|
||||
for (ep = errormsg ; ep->errcode ; ep++) {
|
||||
if (ep->errcode == e && (ep->action & action) != 0)
|
||||
return ep->msg;
|
||||
}
|
||||
fmtstr(buf, sizeof buf, "error %d", e);
|
||||
return buf;
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: error.h,v 1.19 2012/03/15 02:02:20 joerg Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -30,28 +32,38 @@
|
|||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)error.h 8.2 (Berkeley) 5/4/95
|
||||
* $FreeBSD: src/bin/sh/error.h,v 1.17 2004/04/06 20:06:51 markm Exp $
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
/*
|
||||
* Types of operations (passed to the errmsg routine).
|
||||
*/
|
||||
|
||||
#define E_OPEN 01 /* opening a file */
|
||||
#define E_CREAT 02 /* creating a file */
|
||||
#define E_EXEC 04 /* executing a program */
|
||||
|
||||
|
||||
/*
|
||||
* We enclose jmp_buf in a structure so that we can declare pointers to
|
||||
* jump locations. The global variable handler contains the location to
|
||||
* jump to when an exception occurs, and the global variable exception
|
||||
* contains a code identifying the exception. To implement nested
|
||||
* contains a code identifying the exeception. To implement nested
|
||||
* exception handlers, the user should save the value of handler on entry
|
||||
* to an inner scope, set handler to point to a jmploc structure for the
|
||||
* inner scope, and restore handler on exit from the scope.
|
||||
*/
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
|
||||
struct jmploc {
|
||||
jmp_buf loc;
|
||||
};
|
||||
|
||||
extern struct jmploc *handler;
|
||||
extern volatile sig_atomic_t exception;
|
||||
extern int exception;
|
||||
extern int exerrno; /* error for EXEXEC */
|
||||
|
||||
/* exceptions */
|
||||
#define EXINT 0 /* SIGINT received */
|
||||
|
@ -67,8 +79,8 @@ extern volatile sig_atomic_t exception;
|
|||
* more fun than worrying about efficiency and portability. :-))
|
||||
*/
|
||||
|
||||
extern volatile sig_atomic_t suppressint;
|
||||
extern volatile sig_atomic_t intpending;
|
||||
extern volatile int suppressint;
|
||||
extern volatile int intpending;
|
||||
|
||||
#define INTOFF suppressint++
|
||||
#define INTON { if (--suppressint == 0 && intpending) onint(); }
|
||||
|
@ -76,12 +88,24 @@ extern volatile sig_atomic_t intpending;
|
|||
#define CLEAR_PENDING_INT intpending = 0
|
||||
#define int_pending() intpending
|
||||
|
||||
#define __printf0like(a,b)
|
||||
|
||||
void exraise(int);
|
||||
#if ! defined(SHELL_BUILTIN)
|
||||
void exraise(int) __dead;
|
||||
void onint(void);
|
||||
void error(const char *, ...) __printf0like(1, 2);
|
||||
void exerror(int, const char *, ...) __printf0like(2, 3);
|
||||
void error(const char *, ...) __dead __printflike(1, 2);
|
||||
void exerror(int, const char *, ...) __dead __printflike(2, 3);
|
||||
const char *errmsg(int, int);
|
||||
#endif /* ! SHELL_BUILTIN */
|
||||
|
||||
void sh_err(int, const char *, ...) __dead __printflike(2, 3);
|
||||
void sh_verr(int, const char *, va_list) __dead __printflike(2, 0);
|
||||
void sh_errx(int, const char *, ...) __dead __printflike(2, 3);
|
||||
void sh_verrx(int, const char *, va_list) __dead __printflike(2, 0);
|
||||
void sh_warn(const char *, ...) __printflike(1, 2);
|
||||
void sh_vwarn(const char *, va_list) __printflike(1, 0);
|
||||
void sh_warnx(const char *, ...) __printflike(1, 2);
|
||||
void sh_vwarnx(const char *, va_list) __printflike(1, 0);
|
||||
|
||||
void sh_exit(int) __dead;
|
||||
|
||||
|
||||
/*
|
||||
|
@ -89,13 +113,7 @@ void exerror(int, const char *, ...) __printf0like(2, 3);
|
|||
* so we use _setjmp instead.
|
||||
*/
|
||||
|
||||
#ifdef BSD
|
||||
#ifndef __minix
|
||||
#if defined(BSD) && !defined(__SVR4)
|
||||
#define setjmp(jmploc) _setjmp(jmploc)
|
||||
#define longjmp(jmploc, val) _longjmp(jmploc, val)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* $PchId: error.h,v 1.5 2006/04/10 14:36:43 philip Exp $
|
||||
*/
|
File diff suppressed because it is too large
Load diff
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: eval.h,v 1.15 2008/02/15 17:26:06 matt Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -30,11 +32,11 @@
|
|||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)eval.h 8.2 (Berkeley) 5/4/95
|
||||
* $FreeBSD: src/bin/sh/eval.h,v 1.10 2004/04/06 20:06:51 markm Exp $
|
||||
*/
|
||||
|
||||
extern char *commandname; /* currently executing command */
|
||||
extern const char *commandname; /* currently executing command */
|
||||
extern int exitstatus; /* exit status of last command */
|
||||
extern int back_exitstatus; /* exit status of backquoted command */
|
||||
extern struct strlist *cmdenviron; /* environment for builtin command */
|
||||
|
||||
|
||||
|
@ -45,18 +47,10 @@ struct backcmd { /* result of evalbackcmd */
|
|||
struct job *jp; /* job structure for command */
|
||||
};
|
||||
|
||||
int evalcmd(int, char **);
|
||||
void evalstring(char *);
|
||||
void evalstring(char *, int);
|
||||
union node; /* BLETCH for ansi C */
|
||||
void evaltree(union node *, int);
|
||||
void evalbackcmd(union node *, struct backcmd *);
|
||||
int bltincmd(int, char **);
|
||||
int breakcmd(int, char **);
|
||||
int returncmd(int, char **);
|
||||
int falsecmd(int, char **);
|
||||
int truecmd(int, char **);
|
||||
int execcmd(int, char **);
|
||||
int commandcmd(int, char **);
|
||||
|
||||
/* in_function returns nonzero if we are currently evaluating a function */
|
||||
#define in_function() funcnest
|
||||
|
@ -68,7 +62,3 @@ extern int evalskip;
|
|||
#define SKIPCONT 2
|
||||
#define SKIPFUNC 3
|
||||
#define SKIPFILE 4
|
||||
|
||||
/*
|
||||
* $PchId: eval.h,v 1.3 2006/03/30 15:39:25 philip Exp $
|
||||
*/
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: exec.c,v 1.45 2013/11/01 16:49:02 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -30,21 +32,22 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)exec.c 8.4 (Berkeley) 6/8/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: exec.c,v 1.45 2013/11/01 16:49:02 christos Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
#include <sys/cdefs.h>
|
||||
/*
|
||||
__FBSDID("$FreeBSD: src/bin/sh/exec.c,v 1.24.2.1 2004/09/30 04:41:55 des Exp $");
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
|
@ -97,13 +100,18 @@ STATIC int builtinloc = -1; /* index in path of %builtin, or -1 */
|
|||
int exerrno = 0; /* Last exec error */
|
||||
|
||||
|
||||
STATIC void tryexec(char *, char **, char **);
|
||||
STATIC void tryexec(char *, char **, char **, int);
|
||||
STATIC void printentry(struct tblentry *, int);
|
||||
STATIC struct tblentry *cmdlookup(char *, int);
|
||||
STATIC void clearcmdentry(int);
|
||||
STATIC struct tblentry *cmdlookup(const char *, int);
|
||||
STATIC void delete_cmd_entry(void);
|
||||
STATIC void addcmdentry(char *, struct cmdentry *);
|
||||
|
||||
#ifndef BSD
|
||||
STATIC void execinterp(char **, char **);
|
||||
#endif
|
||||
|
||||
|
||||
extern const char *const parsekwd[];
|
||||
|
||||
/*
|
||||
* Exec a program. Never returns. If you change this routine, you may
|
||||
|
@ -111,19 +119,19 @@ STATIC void addcmdentry(char *, struct cmdentry *);
|
|||
*/
|
||||
|
||||
void
|
||||
shellexec(char **argv, char **envp, char *path, int index)
|
||||
shellexec(char **argv, char **envp, const char *path, int idx, int vforked)
|
||||
{
|
||||
char *cmdname;
|
||||
int e;
|
||||
|
||||
if (strchr(argv[0], '/') != NULL) {
|
||||
tryexec(argv[0], argv, envp);
|
||||
tryexec(argv[0], argv, envp, vforked);
|
||||
e = errno;
|
||||
} else {
|
||||
e = ENOENT;
|
||||
while ((cmdname = padvance(&path, argv[0])) != NULL) {
|
||||
if (--index < 0 && pathopt == NULL) {
|
||||
tryexec(cmdname, argv, envp);
|
||||
if (--idx < 0 && pathopt == NULL) {
|
||||
tryexec(cmdname, argv, envp, vforked);
|
||||
if (errno != ENOENT && errno != ENOTDIR)
|
||||
e = errno;
|
||||
}
|
||||
|
@ -143,31 +151,137 @@ shellexec(char **argv, char **envp, char *path, int index)
|
|||
exerrno = 2;
|
||||
break;
|
||||
}
|
||||
if (e == ENOENT || e == ENOTDIR)
|
||||
exerror(EXEXEC, "%s: not found", argv[0]);
|
||||
exerror(EXEXEC, "%s: %s", argv[0], strerror(e));
|
||||
TRACE(("shellexec failed for %s, errno %d, vforked %d, suppressint %d\n",
|
||||
argv[0], e, vforked, suppressint ));
|
||||
exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
||||
STATIC void
|
||||
tryexec(char *cmd, char **argv, char **envp)
|
||||
tryexec(char *cmd, char **argv, char **envp, int vforked)
|
||||
{
|
||||
int e;
|
||||
#ifndef BSD
|
||||
char *p;
|
||||
#endif
|
||||
|
||||
#ifdef SYSV
|
||||
do {
|
||||
execve(cmd, argv, envp);
|
||||
|
||||
} while (errno == EINTR);
|
||||
#else
|
||||
execve(cmd, argv, envp);
|
||||
#endif
|
||||
e = errno;
|
||||
if (e == ENOEXEC) {
|
||||
if (vforked) {
|
||||
/* We are currently vfork(2)ed, so raise an
|
||||
* exception, and evalcommand will try again
|
||||
* with a normal fork(2).
|
||||
*/
|
||||
exraise(EXSHELLPROC);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
TRACE(("execve(cmd=%s) returned ENOEXEC\n", cmd));
|
||||
#endif
|
||||
initshellproc();
|
||||
setinputfile(cmd, 0);
|
||||
commandname = arg0 = savestr(argv[0]);
|
||||
#ifndef BSD
|
||||
pgetc(); pungetc(); /* fill up input buffer */
|
||||
p = parsenextc;
|
||||
if (parsenleft > 2 && p[0] == '#' && p[1] == '!') {
|
||||
argv[0] = cmd;
|
||||
execinterp(argv, envp);
|
||||
}
|
||||
#endif
|
||||
setparam(argv + 1);
|
||||
exraise(EXSHELLPROC);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
errno = e;
|
||||
}
|
||||
|
||||
|
||||
#ifndef BSD
|
||||
/*
|
||||
* Execute an interpreter introduced by "#!", for systems where this
|
||||
* feature has not been built into the kernel. If the interpreter is
|
||||
* the shell, return (effectively ignoring the "#!"). If the execution
|
||||
* of the interpreter fails, exit.
|
||||
*
|
||||
* This code peeks inside the input buffer in order to avoid actually
|
||||
* reading any input. It would benefit from a rewrite.
|
||||
*/
|
||||
|
||||
#define NEWARGS 5
|
||||
|
||||
STATIC void
|
||||
execinterp(char **argv, char **envp)
|
||||
{
|
||||
int n;
|
||||
char *inp;
|
||||
char *outp;
|
||||
char c;
|
||||
char *p;
|
||||
char **ap;
|
||||
char *newargs[NEWARGS];
|
||||
int i;
|
||||
char **ap2;
|
||||
char **new;
|
||||
|
||||
n = parsenleft - 2;
|
||||
inp = parsenextc + 2;
|
||||
ap = newargs;
|
||||
for (;;) {
|
||||
while (--n >= 0 && (*inp == ' ' || *inp == '\t'))
|
||||
inp++;
|
||||
if (n < 0)
|
||||
goto bad;
|
||||
if ((c = *inp++) == '\n')
|
||||
break;
|
||||
if (ap == &newargs[NEWARGS])
|
||||
bad: error("Bad #! line");
|
||||
STARTSTACKSTR(outp);
|
||||
do {
|
||||
STPUTC(c, outp);
|
||||
} while (--n >= 0 && (c = *inp++) != ' ' && c != '\t' && c != '\n');
|
||||
STPUTC('\0', outp);
|
||||
n++, inp--;
|
||||
*ap++ = grabstackstr(outp);
|
||||
}
|
||||
if (ap == newargs + 1) { /* if no args, maybe no exec is needed */
|
||||
p = newargs[0];
|
||||
for (;;) {
|
||||
if (equal(p, "sh") || equal(p, "ash")) {
|
||||
return;
|
||||
}
|
||||
while (*p != '/') {
|
||||
if (*p == '\0')
|
||||
goto break2;
|
||||
p++;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
break2:;
|
||||
}
|
||||
i = (char *)ap - (char *)newargs; /* size in bytes */
|
||||
if (i == 0)
|
||||
error("Bad #! line");
|
||||
for (ap2 = argv ; *ap2++ != NULL ; );
|
||||
new = ckmalloc(i + ((char *)ap2 - (char *)argv));
|
||||
ap = newargs, ap2 = new;
|
||||
while ((i -= sizeof (char **)) >= 0)
|
||||
*ap2++ = *ap++;
|
||||
ap = argv;
|
||||
while (*ap2++ = *ap++);
|
||||
shellexec(new, envp, pathval(), 0);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Do a path search. The variable path (passed by reference) should be
|
||||
* set to the start of the path before the first call; padvance will update
|
||||
|
@ -178,13 +292,14 @@ tryexec(char *cmd, char **argv, char **envp)
|
|||
* NULL.
|
||||
*/
|
||||
|
||||
char *pathopt;
|
||||
const char *pathopt;
|
||||
|
||||
char *
|
||||
padvance(char **path, char *name)
|
||||
padvance(const char **path, const char *name)
|
||||
{
|
||||
char *p, *q;
|
||||
char *start;
|
||||
const char *p;
|
||||
char *q;
|
||||
const char *start;
|
||||
int len;
|
||||
|
||||
if (*path == NULL)
|
||||
|
@ -219,7 +334,7 @@ padvance(char **path, char *name)
|
|||
|
||||
|
||||
int
|
||||
hashcmd(int argc __unused, char **argv __unused)
|
||||
hashcmd(int argc, char **argv)
|
||||
{
|
||||
struct tblentry **pp;
|
||||
struct tblentry *cmdp;
|
||||
|
@ -239,7 +354,7 @@ hashcmd(int argc __unused, char **argv __unused)
|
|||
if (*argptr == NULL) {
|
||||
for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
|
||||
for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
|
||||
if (cmdp->cmdtype == CMDNORMAL)
|
||||
if (verbose || cmdp->cmdtype == CMDNORMAL)
|
||||
printentry(cmdp, verbose);
|
||||
}
|
||||
}
|
||||
|
@ -250,14 +365,12 @@ hashcmd(int argc __unused, char **argv __unused)
|
|||
&& (cmdp->cmdtype == CMDNORMAL
|
||||
|| (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
|
||||
delete_cmd_entry();
|
||||
find_command(name, &entry, 1, pathval());
|
||||
find_command(name, &entry, DO_ERR, pathval());
|
||||
if (verbose) {
|
||||
if (entry.cmdtype != CMDUNKNOWN) { /* if no error msg */
|
||||
cmdp = cmdlookup(name, 0);
|
||||
if (cmdp != NULL)
|
||||
printentry(cmdp, verbose);
|
||||
else
|
||||
outfmt(&errout, "%s: not found\n", name);
|
||||
}
|
||||
flushall();
|
||||
}
|
||||
|
@ -270,34 +383,40 @@ hashcmd(int argc __unused, char **argv __unused)
|
|||
STATIC void
|
||||
printentry(struct tblentry *cmdp, int verbose)
|
||||
{
|
||||
int index;
|
||||
char *path;
|
||||
int idx;
|
||||
const char *path;
|
||||
char *name;
|
||||
|
||||
if (cmdp->cmdtype == CMDNORMAL) {
|
||||
index = cmdp->param.index;
|
||||
switch (cmdp->cmdtype) {
|
||||
case CMDNORMAL:
|
||||
idx = cmdp->param.index;
|
||||
path = pathval();
|
||||
do {
|
||||
name = padvance(&path, cmdp->cmdname);
|
||||
stunalloc(name);
|
||||
} while (--index >= 0);
|
||||
} while (--idx >= 0);
|
||||
out1str(name);
|
||||
} else if (cmdp->cmdtype == CMDBUILTIN) {
|
||||
break;
|
||||
case CMDSPLBLTIN:
|
||||
out1fmt("special builtin %s", cmdp->cmdname);
|
||||
break;
|
||||
case CMDBUILTIN:
|
||||
out1fmt("builtin %s", cmdp->cmdname);
|
||||
} else if (cmdp->cmdtype == CMDFUNCTION) {
|
||||
break;
|
||||
case CMDFUNCTION:
|
||||
out1fmt("function %s", cmdp->cmdname);
|
||||
if (verbose) {
|
||||
struct procstat ps;
|
||||
INTOFF;
|
||||
name = commandtext(cmdp->param.func);
|
||||
out1c(' ');
|
||||
out1str(name);
|
||||
ckfree(name);
|
||||
commandtext(&ps, cmdp->param.func);
|
||||
INTON;
|
||||
out1str("() { ");
|
||||
out1str(ps.cmd);
|
||||
out1str("; }");
|
||||
}
|
||||
#if DEBUG
|
||||
} else {
|
||||
error("internal error: cmdtype %d", cmdp->cmdtype);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
error("internal error: %s cmdtype %d", cmdp->cmdname, cmdp->cmdtype);
|
||||
}
|
||||
if (cmdp->rehash)
|
||||
out1c('*');
|
||||
|
@ -312,36 +431,78 @@ printentry(struct tblentry *cmdp, int verbose)
|
|||
*/
|
||||
|
||||
void
|
||||
find_command(char *name, struct cmdentry *entry, int printerr, char *path)
|
||||
find_command(char *name, struct cmdentry *entry, int act, const char *path)
|
||||
{
|
||||
struct tblentry *cmdp;
|
||||
int index;
|
||||
struct tblentry *cmdp, loc_cmd;
|
||||
int idx;
|
||||
int prev;
|
||||
char *fullname;
|
||||
struct stat statb;
|
||||
int e;
|
||||
int i;
|
||||
int (*bltin)(int,char **);
|
||||
|
||||
/* If name contains a slash, don't use the hash table */
|
||||
/* If name contains a slash, don't use PATH or hash table */
|
||||
if (strchr(name, '/') != NULL) {
|
||||
if (act & DO_ABS) {
|
||||
while (stat(name, &statb) < 0) {
|
||||
#ifdef SYSV
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
#endif
|
||||
if (errno != ENOENT && errno != ENOTDIR)
|
||||
e = errno;
|
||||
entry->cmdtype = CMDUNKNOWN;
|
||||
entry->u.index = -1;
|
||||
return;
|
||||
}
|
||||
entry->cmdtype = CMDNORMAL;
|
||||
entry->u.index = -1;
|
||||
return;
|
||||
}
|
||||
entry->cmdtype = CMDNORMAL;
|
||||
entry->u.index = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* If name is in the table, and not invalidated by cd, we're done */
|
||||
if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0)
|
||||
if (path != pathval())
|
||||
act |= DO_ALTPATH;
|
||||
|
||||
if (act & DO_ALTPATH && strstr(path, "%builtin") != NULL)
|
||||
act |= DO_ALTBLTIN;
|
||||
|
||||
/* If name is in the table, check answer will be ok */
|
||||
if ((cmdp = cmdlookup(name, 0)) != NULL) {
|
||||
do {
|
||||
switch (cmdp->cmdtype) {
|
||||
case CMDNORMAL:
|
||||
if (act & DO_ALTPATH) {
|
||||
cmdp = NULL;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case CMDFUNCTION:
|
||||
if (act & DO_NOFUNC) {
|
||||
cmdp = NULL;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case CMDBUILTIN:
|
||||
if ((act & DO_ALTBLTIN) || builtinloc >= 0) {
|
||||
cmdp = NULL;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* if not invalidated by cd, we're done */
|
||||
if (cmdp->rehash == 0)
|
||||
goto success;
|
||||
} while (0);
|
||||
}
|
||||
|
||||
/* If %builtin not in path, check for builtin next */
|
||||
if (builtinloc < 0 && (i = find_builtin(name)) >= 0) {
|
||||
INTOFF;
|
||||
cmdp = cmdlookup(name, 1);
|
||||
cmdp->cmdtype = CMDBUILTIN;
|
||||
cmdp->param.index = i;
|
||||
INTON;
|
||||
goto success;
|
||||
}
|
||||
if ((act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc < 0) &&
|
||||
(bltin = find_builtin(name)) != 0)
|
||||
goto builtin_success;
|
||||
|
||||
/* We have to search path. */
|
||||
prev = -1; /* where to start */
|
||||
|
@ -353,35 +514,35 @@ find_command(char *name, struct cmdentry *entry, int printerr, char *path)
|
|||
}
|
||||
|
||||
e = ENOENT;
|
||||
index = -1;
|
||||
idx = -1;
|
||||
loop:
|
||||
while ((fullname = padvance(&path, name)) != NULL) {
|
||||
stunalloc(fullname);
|
||||
index++;
|
||||
idx++;
|
||||
if (pathopt) {
|
||||
if (prefix("builtin", pathopt)) {
|
||||
if ((i = find_builtin(name)) < 0)
|
||||
if ((bltin = find_builtin(name)) == 0)
|
||||
goto loop;
|
||||
INTOFF;
|
||||
cmdp = cmdlookup(name, 1);
|
||||
cmdp->cmdtype = CMDBUILTIN;
|
||||
cmdp->param.index = i;
|
||||
INTON;
|
||||
goto success;
|
||||
goto builtin_success;
|
||||
} else if (prefix("func", pathopt)) {
|
||||
/* handled below */
|
||||
} else {
|
||||
goto loop; /* ignore unimplemented options */
|
||||
/* ignore unimplemented options */
|
||||
goto loop;
|
||||
}
|
||||
}
|
||||
/* if rehash, don't redo absolute path names */
|
||||
if (fullname[0] == '/' && index <= prev) {
|
||||
if (index < prev)
|
||||
if (fullname[0] == '/' && idx <= prev) {
|
||||
if (idx < prev)
|
||||
goto loop;
|
||||
TRACE(("searchexec \"%s\": no change\n", name));
|
||||
goto success;
|
||||
}
|
||||
if (stat(fullname, &statb) < 0) {
|
||||
while (stat(fullname, &statb) < 0) {
|
||||
#ifdef SYSV
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
#endif
|
||||
if (errno != ENOENT && errno != ENOTDIR)
|
||||
e = errno;
|
||||
goto loop;
|
||||
|
@ -390,14 +551,19 @@ loop:
|
|||
if (!S_ISREG(statb.st_mode))
|
||||
goto loop;
|
||||
if (pathopt) { /* this is a %func directory */
|
||||
if (act & DO_NOFUNC)
|
||||
goto loop;
|
||||
stalloc(strlen(fullname) + 1);
|
||||
readcmdfile(fullname);
|
||||
if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
|
||||
if ((cmdp = cmdlookup(name, 0)) == NULL ||
|
||||
cmdp->cmdtype != CMDFUNCTION)
|
||||
error("%s not defined in %s", name, fullname);
|
||||
stunalloc(fullname);
|
||||
goto success;
|
||||
}
|
||||
#ifdef notdef
|
||||
/* XXX this code stops root executing stuff, and is buggy
|
||||
if you need a group from the group list. */
|
||||
if (statb.st_uid == geteuid()) {
|
||||
if ((statb.st_mode & 0100) == 0)
|
||||
goto loop;
|
||||
|
@ -411,9 +577,13 @@ loop:
|
|||
#endif
|
||||
TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
|
||||
INTOFF;
|
||||
if (act & DO_ALTPATH) {
|
||||
stalloc(strlen(fullname) + 1);
|
||||
cmdp = &loc_cmd;
|
||||
} else
|
||||
cmdp = cmdlookup(name, 1);
|
||||
cmdp->cmdtype = CMDNORMAL;
|
||||
cmdp->param.index = index;
|
||||
cmdp->param.index = idx;
|
||||
INTON;
|
||||
goto success;
|
||||
}
|
||||
|
@ -421,19 +591,30 @@ loop:
|
|||
/* We failed. If there was an entry for this command, delete it */
|
||||
if (cmdp)
|
||||
delete_cmd_entry();
|
||||
if (printerr) {
|
||||
if (e == ENOENT || e == ENOTDIR)
|
||||
outfmt(out2, "%s: not found\n", name);
|
||||
else
|
||||
outfmt(out2, "%s: %s\n", name, strerror(e));
|
||||
}
|
||||
if (act & DO_ERR)
|
||||
outfmt(out2, "%s: %s\n", name, errmsg(e, E_EXEC));
|
||||
entry->cmdtype = CMDUNKNOWN;
|
||||
return;
|
||||
|
||||
builtin_success:
|
||||
INTOFF;
|
||||
if (act & DO_ALTPATH)
|
||||
cmdp = &loc_cmd;
|
||||
else
|
||||
cmdp = cmdlookup(name, 1);
|
||||
if (cmdp->cmdtype == CMDFUNCTION)
|
||||
/* DO_NOFUNC must have been set */
|
||||
cmdp = &loc_cmd;
|
||||
cmdp->cmdtype = CMDBUILTIN;
|
||||
cmdp->param.bltin = bltin;
|
||||
INTON;
|
||||
success:
|
||||
if (cmdp) {
|
||||
cmdp->rehash = 0;
|
||||
entry->cmdtype = cmdp->cmdtype;
|
||||
entry->u = cmdp->param;
|
||||
} else
|
||||
entry->cmdtype = CMDUNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
|
@ -443,15 +624,48 @@ success:
|
|||
*/
|
||||
|
||||
int
|
||||
find_builtin(char *name)
|
||||
(*find_builtin(char *name))(int, char **)
|
||||
{
|
||||
const struct builtincmd *bp;
|
||||
|
||||
for (bp = builtincmd ; bp->name ; bp++) {
|
||||
if (*bp->name == *name && equal(bp->name, name))
|
||||
return bp->code;
|
||||
if (*bp->name == *name
|
||||
&& (*name == '%' || equal(bp->name, name)))
|
||||
return bp->builtin;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
(*find_splbltin(char *name))(int, char **)
|
||||
{
|
||||
const struct builtincmd *bp;
|
||||
|
||||
for (bp = splbltincmd ; bp->name ; bp++) {
|
||||
if (*bp->name == *name && equal(bp->name, name))
|
||||
return bp->builtin;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* At shell startup put special builtins into hash table.
|
||||
* ensures they are executed first (see posix).
|
||||
* We stop functions being added with the same name
|
||||
* (as they are impossible to call)
|
||||
*/
|
||||
|
||||
void
|
||||
hash_special_builtins(void)
|
||||
{
|
||||
const struct builtincmd *bp;
|
||||
struct tblentry *cmdp;
|
||||
|
||||
for (bp = splbltincmd ; bp->name ; bp++) {
|
||||
cmdp = cmdlookup(bp->name, 1);
|
||||
cmdp->cmdtype = CMDSPLBLTIN;
|
||||
cmdp->param.bltin = bp->builtin;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -479,27 +693,28 @@ hashcd(void)
|
|||
|
||||
|
||||
/*
|
||||
* Fix command hash table when PATH changed.
|
||||
* Called before PATH is changed. The argument is the new value of PATH;
|
||||
* pathval() still returns the old value at this point. Called with
|
||||
* interrupts off.
|
||||
* pathval() still returns the old value at this point.
|
||||
* Called with interrupts off.
|
||||
*/
|
||||
|
||||
void
|
||||
changepath(const char *newval)
|
||||
{
|
||||
const char *old, *new;
|
||||
int index;
|
||||
int idx;
|
||||
int firstchange;
|
||||
int bltin;
|
||||
|
||||
old = pathval();
|
||||
new = newval;
|
||||
firstchange = 9999; /* assume no change */
|
||||
index = 0;
|
||||
idx = 0;
|
||||
bltin = -1;
|
||||
for (;;) {
|
||||
if (*old != *new) {
|
||||
firstchange = index;
|
||||
firstchange = idx;
|
||||
if ((*old == '\0' && *new == ':')
|
||||
|| (*old == ':' && *new == '\0'))
|
||||
firstchange++;
|
||||
|
@ -508,9 +723,9 @@ changepath(const char *newval)
|
|||
if (*new == '\0')
|
||||
break;
|
||||
if (*new == '%' && bltin < 0 && prefix("builtin", new + 1))
|
||||
bltin = index;
|
||||
bltin = idx;
|
||||
if (*new == ':') {
|
||||
index++;
|
||||
idx++;
|
||||
}
|
||||
new++, old++;
|
||||
}
|
||||
|
@ -528,7 +743,7 @@ changepath(const char *newval)
|
|||
* PATH which has changed.
|
||||
*/
|
||||
|
||||
void
|
||||
STATIC void
|
||||
clearcmdentry(int firstchange)
|
||||
{
|
||||
struct tblentry **tblp;
|
||||
|
@ -559,7 +774,13 @@ clearcmdentry(int firstchange)
|
|||
*/
|
||||
|
||||
#ifdef mkinit
|
||||
INCLUDE "exec.h"
|
||||
MKINIT void deletefuncs(void);
|
||||
MKINIT void hash_special_builtins(void);
|
||||
|
||||
INIT {
|
||||
hash_special_builtins();
|
||||
}
|
||||
|
||||
SHELLPROC {
|
||||
deletefuncs();
|
||||
}
|
||||
|
@ -598,14 +819,14 @@ deletefuncs(void)
|
|||
* entry.
|
||||
*/
|
||||
|
||||
STATIC struct tblentry **lastcmdentry;
|
||||
struct tblentry **lastcmdentry;
|
||||
|
||||
|
||||
STATIC struct tblentry *
|
||||
cmdlookup(char *name, int add)
|
||||
cmdlookup(const char *name, int add)
|
||||
{
|
||||
int hashval;
|
||||
char *p;
|
||||
const char *p;
|
||||
struct tblentry *cmdp;
|
||||
struct tblentry **pp;
|
||||
|
||||
|
@ -652,23 +873,42 @@ delete_cmd_entry(void)
|
|||
|
||||
|
||||
|
||||
#ifdef notdef
|
||||
void
|
||||
getcmdentry(char *name, struct cmdentry *entry)
|
||||
{
|
||||
struct tblentry *cmdp = cmdlookup(name, 0);
|
||||
|
||||
if (cmdp) {
|
||||
entry->u = cmdp->param;
|
||||
entry->cmdtype = cmdp->cmdtype;
|
||||
} else {
|
||||
entry->cmdtype = CMDUNKNOWN;
|
||||
entry->u.index = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Add a new command entry, replacing any existing command entry for
|
||||
* the same name.
|
||||
* the same name - except special builtins.
|
||||
*/
|
||||
|
||||
static void
|
||||
STATIC void
|
||||
addcmdentry(char *name, struct cmdentry *entry)
|
||||
{
|
||||
struct tblentry *cmdp;
|
||||
|
||||
INTOFF;
|
||||
cmdp = cmdlookup(name, 1);
|
||||
if (cmdp->cmdtype != CMDSPLBLTIN) {
|
||||
if (cmdp->cmdtype == CMDFUNCTION) {
|
||||
freefunc(cmdp->param.func);
|
||||
}
|
||||
cmdp->cmdtype = entry->cmdtype;
|
||||
cmdp->param = entry->u;
|
||||
}
|
||||
INTON;
|
||||
}
|
||||
|
||||
|
@ -699,16 +939,17 @@ unsetfunc(char *name)
|
|||
{
|
||||
struct tblentry *cmdp;
|
||||
|
||||
if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
|
||||
if ((cmdp = cmdlookup(name, 0)) != NULL &&
|
||||
cmdp->cmdtype == CMDFUNCTION) {
|
||||
freefunc(cmdp->param.func);
|
||||
delete_cmd_entry();
|
||||
return (0);
|
||||
}
|
||||
return (0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Locate and print what a word is...
|
||||
* also used for 'command -[v|V]'
|
||||
*/
|
||||
|
||||
int
|
||||
|
@ -716,76 +957,115 @@ typecmd(int argc, char **argv)
|
|||
{
|
||||
struct cmdentry entry;
|
||||
struct tblentry *cmdp;
|
||||
char **pp;
|
||||
const char * const *pp;
|
||||
struct alias *ap;
|
||||
int i;
|
||||
int error = 0;
|
||||
extern char *const parsekwd[];
|
||||
int err = 0;
|
||||
char *arg;
|
||||
int c;
|
||||
int V_flag = 0;
|
||||
int v_flag = 0;
|
||||
int p_flag = 0;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
out1str(argv[i]);
|
||||
while ((c = nextopt("vVp")) != 0) {
|
||||
switch (c) {
|
||||
case 'v': v_flag = 1; break;
|
||||
case 'V': V_flag = 1; break;
|
||||
case 'p': p_flag = 1; break;
|
||||
}
|
||||
}
|
||||
|
||||
if (p_flag && (v_flag || V_flag))
|
||||
error("cannot specify -p with -v or -V");
|
||||
|
||||
while ((arg = *argptr++)) {
|
||||
if (!v_flag)
|
||||
out1str(arg);
|
||||
/* First look at the keywords */
|
||||
for (pp = (char **)parsekwd; *pp; pp++)
|
||||
if (**pp == *argv[i] && equal(*pp, argv[i]))
|
||||
for (pp = parsekwd; *pp; pp++)
|
||||
if (**pp == *arg && equal(*pp, arg))
|
||||
break;
|
||||
|
||||
if (*pp) {
|
||||
if (v_flag)
|
||||
err = 1;
|
||||
else
|
||||
out1str(" is a shell keyword\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Then look at the aliases */
|
||||
if ((ap = lookupalias(argv[i], 1)) != NULL) {
|
||||
out1fmt(" is an alias for %s\n", ap->val);
|
||||
if ((ap = lookupalias(arg, 1)) != NULL) {
|
||||
if (!v_flag)
|
||||
out1fmt(" is an alias for \n");
|
||||
out1fmt("%s\n", ap->val);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Then check if it is a tracked alias */
|
||||
if ((cmdp = cmdlookup(argv[i], 0)) != NULL) {
|
||||
if ((cmdp = cmdlookup(arg, 0)) != NULL) {
|
||||
entry.cmdtype = cmdp->cmdtype;
|
||||
entry.u = cmdp->param;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
/* Finally use brute force */
|
||||
find_command(argv[i], &entry, 0, pathval());
|
||||
find_command(arg, &entry, DO_ABS, pathval());
|
||||
}
|
||||
|
||||
switch (entry.cmdtype) {
|
||||
case CMDNORMAL: {
|
||||
if (strchr(argv[i], '/') == NULL) {
|
||||
char *path = pathval(), *name;
|
||||
if (strchr(arg, '/') == NULL) {
|
||||
const char *path = pathval();
|
||||
char *name;
|
||||
int j = entry.u.index;
|
||||
do {
|
||||
name = padvance(&path, argv[i]);
|
||||
name = padvance(&path, arg);
|
||||
stunalloc(name);
|
||||
} while (--j >= 0);
|
||||
out1fmt(" is%s %s\n",
|
||||
cmdp ? " a tracked alias for" : "", name);
|
||||
if (!v_flag)
|
||||
out1fmt(" is%s ",
|
||||
cmdp ? " a tracked alias for" : "");
|
||||
out1fmt("%s\n", name);
|
||||
} else {
|
||||
if (access(argv[i], X_OK) == 0)
|
||||
out1fmt(" is %s\n", argv[i]);
|
||||
if (access(arg, X_OK) == 0) {
|
||||
if (!v_flag)
|
||||
out1fmt(" is ");
|
||||
out1fmt("%s\n", arg);
|
||||
} else {
|
||||
if (!v_flag)
|
||||
out1fmt(": %s\n",
|
||||
strerror(errno));
|
||||
else
|
||||
out1fmt(": %s\n", strerror(errno));
|
||||
err = 126;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CMDFUNCTION:
|
||||
if (!v_flag)
|
||||
out1str(" is a shell function\n");
|
||||
else
|
||||
out1fmt("%s\n", arg);
|
||||
break;
|
||||
|
||||
case CMDBUILTIN:
|
||||
if (!v_flag)
|
||||
out1str(" is a shell builtin\n");
|
||||
else
|
||||
out1fmt("%s\n", arg);
|
||||
break;
|
||||
|
||||
case CMDSPLBLTIN:
|
||||
if (!v_flag)
|
||||
out1str(" is a special shell builtin\n");
|
||||
else
|
||||
out1fmt("%s\n", arg);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!v_flag)
|
||||
out1str(": not found\n");
|
||||
error |= 127;
|
||||
err = 127;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return error;
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* $PchId: exec.c,v 1.6 2006/04/10 14:47:03 philip Exp $
|
||||
*/
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: exec.h,v 1.23 2012/03/15 02:02:20 joerg Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -30,41 +32,45 @@
|
|||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)exec.h 8.3 (Berkeley) 6/8/95
|
||||
* $FreeBSD: src/bin/sh/exec.h,v 1.12 2004/04/06 20:06:51 markm Exp $
|
||||
*/
|
||||
|
||||
/* values of cmdtype */
|
||||
#define CMDUNKNOWN -1 /* no entry in table for command */
|
||||
#define CMDNORMAL 0 /* command is an executable program */
|
||||
#define CMDBUILTIN 1 /* command is a shell builtin */
|
||||
#define CMDFUNCTION 2 /* command is a shell function */
|
||||
#define CMDFUNCTION 1 /* command is a shell function */
|
||||
#define CMDBUILTIN 2 /* command is a shell builtin */
|
||||
#define CMDSPLBLTIN 3 /* command is a special shell builtin */
|
||||
|
||||
|
||||
struct cmdentry {
|
||||
int cmdtype;
|
||||
union param {
|
||||
int index;
|
||||
int (*bltin)(int, char**);
|
||||
union node *func;
|
||||
} u;
|
||||
};
|
||||
|
||||
|
||||
extern char *pathopt; /* set by padvance */
|
||||
extern int exerrno; /* last exec error */
|
||||
/* action to find_command() */
|
||||
#define DO_ERR 0x01 /* prints errors */
|
||||
#define DO_ABS 0x02 /* checks absolute paths */
|
||||
#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
|
||||
#define DO_ALTPATH 0x08 /* using alternate path */
|
||||
#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
|
||||
|
||||
void shellexec(char **, char **, char *, int);
|
||||
char *padvance(char **, char *);
|
||||
int hashcmd(int, char **);
|
||||
void find_command(char *, struct cmdentry *, int, char *);
|
||||
int find_builtin(char *);
|
||||
extern const char *pathopt; /* set by padvance */
|
||||
|
||||
void shellexec(char **, char **, const char *, int, int) __dead;
|
||||
char *padvance(const char **, const char *);
|
||||
void find_command(char *, struct cmdentry *, int, const char *);
|
||||
int (*find_builtin(char *))(int, char **);
|
||||
int (*find_splbltin(char *))(int, char **);
|
||||
void hashcd(void);
|
||||
void changepath(const char *);
|
||||
void deletefuncs(void);
|
||||
void getcmdentry(char *, struct cmdentry *);
|
||||
void addcmdentry(char *, struct cmdentry *);
|
||||
void defun(char *, union node *);
|
||||
int unsetfunc(char *);
|
||||
int typecmd(int, char **);
|
||||
void clearcmdentry(int);
|
||||
|
||||
/*
|
||||
* $PchId: exec.h,v 1.5 2006/04/10 14:47:34 philip Exp $
|
||||
*/
|
||||
void hash_special_builtins(void);
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: expand.c,v 1.90 2013/10/06 21:05:50 ast Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -30,26 +32,25 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)expand.c 8.5 (Berkeley) 5/15/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: expand.c,v 1.90 2013/10/06 21:05:50 ast Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
#include <sys/cdefs.h>
|
||||
/*
|
||||
__FBSDID("$FreeBSD: src/bin/sh/expand.c,v 1.46 2004/04/06 20:06:51 markm Exp $");
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <pwd.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* Routines to expand arguments to commands. We have to deal with
|
||||
|
@ -65,13 +66,13 @@ __FBSDID("$FreeBSD: src/bin/sh/expand.c,v 1.46 2004/04/06 20:06:51 markm Exp $")
|
|||
#include "parser.h"
|
||||
#include "jobs.h"
|
||||
#include "options.h"
|
||||
#include "builtins.h"
|
||||
#include "var.h"
|
||||
#include "input.h"
|
||||
#include "output.h"
|
||||
#include "memalloc.h"
|
||||
#include "error.h"
|
||||
#include "mystring.h"
|
||||
#include "arith.h"
|
||||
#include "show.h"
|
||||
|
||||
/*
|
||||
|
@ -83,15 +84,15 @@ struct ifsregion {
|
|||
struct ifsregion *next; /* next region in list */
|
||||
int begoff; /* offset of start of region */
|
||||
int endoff; /* offset of end of region */
|
||||
int nulonly; /* search for nul bytes only */
|
||||
int inquotes; /* search for nul bytes only */
|
||||
};
|
||||
|
||||
|
||||
STATIC char *expdest; /* output of current string */
|
||||
STATIC struct nodelist *argbackq; /* list of back quote expressions */
|
||||
STATIC struct ifsregion ifsfirst; /* first struct in list of ifs regions */
|
||||
STATIC struct ifsregion *ifslastp; /* last struct in list */
|
||||
STATIC struct arglist exparg; /* holds expanded arg list */
|
||||
char *expdest; /* output of current string */
|
||||
struct nodelist *argbackq; /* list of back quote expressions */
|
||||
struct ifsregion ifsfirst; /* first struct in list of ifs regions */
|
||||
struct ifsregion *ifslastp; /* last struct in list */
|
||||
struct arglist exparg; /* holds expanded arg list */
|
||||
|
||||
STATIC void argstr(char *, int);
|
||||
STATIC char *exptilde(char *, int);
|
||||
|
@ -99,10 +100,11 @@ STATIC void expbackq(union node *, int, int);
|
|||
STATIC int subevalvar(char *, char *, int, int, int, int);
|
||||
STATIC char *evalvar(char *, int);
|
||||
STATIC int varisset(char *, int);
|
||||
STATIC void varvalue(char *, int, int);
|
||||
STATIC void varvalue(char *, int, int, int);
|
||||
STATIC void recordregion(int, int, int);
|
||||
STATIC void removerecordregions(int);
|
||||
STATIC void ifsbreakup(char *, struct arglist *);
|
||||
STATIC void ifsfree(void);
|
||||
STATIC void expandmeta(struct strlist *, int);
|
||||
STATIC void expmeta(char *, char *);
|
||||
STATIC void addfname(char *);
|
||||
|
@ -110,30 +112,16 @@ STATIC struct strlist *expsort(struct strlist *);
|
|||
STATIC struct strlist *msort(struct strlist *, int);
|
||||
STATIC int pmatch(char *, char *, int);
|
||||
STATIC char *cvtnum(int, char *);
|
||||
STATIC int collate_range_cmp(int, int);
|
||||
STATIC void expari(int);
|
||||
|
||||
STATIC int
|
||||
collate_range_cmp(int c1, int c2)
|
||||
{
|
||||
static char s1[2], s2[2];
|
||||
|
||||
s1[0] = c1;
|
||||
s2[0] = c2;
|
||||
return (strcoll(s1, s2));
|
||||
}
|
||||
|
||||
/*
|
||||
* Expand shell variables and backquotes inside a here document.
|
||||
* union node *arg the document
|
||||
* int fd; where to write the expanded version
|
||||
*/
|
||||
|
||||
void
|
||||
expandhere(union node *arg, int fd)
|
||||
{
|
||||
herefd = fd;
|
||||
expandarg(arg, (struct arglist *)NULL, 0);
|
||||
expandarg(arg, NULL, 0);
|
||||
xwrite(fd, stackblock(), expdest - stackblock());
|
||||
}
|
||||
|
||||
|
@ -178,14 +166,7 @@ expandarg(union node *arg, struct arglist *arglist, int flag)
|
|||
*exparg.lastp = sp;
|
||||
exparg.lastp = &sp->next;
|
||||
}
|
||||
while (ifsfirst.next != NULL) {
|
||||
struct ifsregion *ifsp;
|
||||
INTOFF;
|
||||
ifsp = ifsfirst.next->next;
|
||||
ckfree(ifsfirst.next);
|
||||
ifsfirst.next = ifsp;
|
||||
INTON;
|
||||
}
|
||||
ifsfree();
|
||||
*exparg.lastp = NULL;
|
||||
if (exparg.list) {
|
||||
*arglist->lastp = exparg.list;
|
||||
|
@ -196,31 +177,40 @@ expandarg(union node *arg, struct arglist *arglist, int flag)
|
|||
|
||||
|
||||
/*
|
||||
* Perform variable and command substitution. If EXP_FULL is set, output CTLESC
|
||||
* characters to allow for further processing. Otherwise treat
|
||||
* $@ like $* since no splitting will be performed.
|
||||
* Perform variable and command substitution.
|
||||
* If EXP_FULL is set, output CTLESC characters to allow for further processing.
|
||||
* Otherwise treat $@ like $* since no splitting will be performed.
|
||||
*/
|
||||
|
||||
STATIC void
|
||||
argstr(char *p, int flag)
|
||||
{
|
||||
char c;
|
||||
int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR); /* do CTLESC */
|
||||
int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
|
||||
int firsteq = 1;
|
||||
const char *ifs = NULL;
|
||||
int ifs_split = EXP_IFS_SPLIT;
|
||||
|
||||
if (flag & EXP_IFS_SPLIT)
|
||||
ifs = ifsset() ? ifsval() : " \t\n";
|
||||
|
||||
if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
|
||||
p = exptilde(p, flag);
|
||||
for (;;) {
|
||||
switch (c = *p++) {
|
||||
case '\0':
|
||||
case CTLENDVAR: /* ??? */
|
||||
goto breakloop;
|
||||
case CTLENDVAR: /* end of expanding yyy in ${xxx-yyy} */
|
||||
return;
|
||||
case CTLQUOTEMARK:
|
||||
/* "$@" syntax adherence hack */
|
||||
if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
|
||||
break;
|
||||
if ((flag & EXP_FULL) != 0)
|
||||
STPUTC(c, expdest);
|
||||
ifs_split = 0;
|
||||
break;
|
||||
case CTLQUOTEEND:
|
||||
ifs_split = EXP_IFS_SPLIT;
|
||||
break;
|
||||
case CTLESC:
|
||||
if (quotes)
|
||||
|
@ -229,7 +219,7 @@ argstr(char *p, int flag)
|
|||
STPUTC(c, expdest);
|
||||
break;
|
||||
case CTLVAR:
|
||||
p = evalvar(p, flag);
|
||||
p = evalvar(p, (flag & ~EXP_IFS_SPLIT) | (flag & ifs_split));
|
||||
break;
|
||||
case CTLBACKQ:
|
||||
case CTLBACKQ|CTLQUOTE:
|
||||
|
@ -258,9 +248,14 @@ argstr(char *p, int flag)
|
|||
break;
|
||||
default:
|
||||
STPUTC(c, expdest);
|
||||
if (flag & ifs_split && strchr(ifs, c) != NULL) {
|
||||
/* We need to get the output split here... */
|
||||
recordregion(expdest - stackblock() - 1,
|
||||
expdest - stackblock(), 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
breakloop:;
|
||||
}
|
||||
|
||||
STATIC char *
|
||||
|
@ -268,8 +263,8 @@ exptilde(char *p, int flag)
|
|||
{
|
||||
char c, *startp = p;
|
||||
struct passwd *pw;
|
||||
char *home;
|
||||
int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
|
||||
const char *home;
|
||||
int quotes = flag & (EXP_FULL | EXP_CASE);
|
||||
|
||||
while ((c = *p) != '\0') {
|
||||
switch(c) {
|
||||
|
@ -350,40 +345,42 @@ removerecordregions(int endoff)
|
|||
ifslastp->endoff = endoff;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Expand arithmetic expression. Backup to start of expression,
|
||||
* evaluate, place result in (backed up) result, adjust string position.
|
||||
*/
|
||||
STATIC void
|
||||
void
|
||||
expari(int flag)
|
||||
{
|
||||
char *p, *start;
|
||||
int result;
|
||||
intmax_t result;
|
||||
int adjustment;
|
||||
int begoff;
|
||||
int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
|
||||
int quotes = flag & (EXP_FULL | EXP_CASE);
|
||||
int quoted;
|
||||
|
||||
/* ifsfree(); */
|
||||
|
||||
/*
|
||||
* This routine is slightly over-complicated for
|
||||
* efficiency. First we make sure there is
|
||||
* enough space for the result, which may be bigger
|
||||
* than the expression if we add exponentiation. Next we
|
||||
* than the expression if we add exponentation. Next we
|
||||
* scan backwards looking for the start of arithmetic. If the
|
||||
* next previous character is a CTLESC character, then we
|
||||
* have to rescan starting from the beginning since CTLESC
|
||||
* characters have to be processed left to right.
|
||||
*/
|
||||
#if INT_MAX / 1000000000 >= 10 || INT_MIN / 1000000000 <= -10
|
||||
#error "integers with more than 10 digits are not supported"
|
||||
#endif
|
||||
CHECKSTRSPACE(12 - 2, expdest);
|
||||
/* SPACE_NEEDED is enough for all digits, plus possible "-", plus 2 (why?) */
|
||||
#define SPACE_NEEDED ((sizeof(intmax_t) * CHAR_BIT + 2) / 3 + 1 + 2)
|
||||
CHECKSTRSPACE((int)(SPACE_NEEDED - 2), expdest);
|
||||
USTPUTC('\0', expdest);
|
||||
start = stackblock();
|
||||
p = expdest - 2;
|
||||
while (p >= start && *p != CTLARI)
|
||||
p = expdest - 1;
|
||||
while (*p != CTLARI && p >= start)
|
||||
--p;
|
||||
if (p < start || *p != CTLARI)
|
||||
if (*p != CTLARI)
|
||||
error("missing CTLARI (shouldn't happen)");
|
||||
if (p > start && *(p-1) == CTLESC)
|
||||
for (p = start; *p != CTLARI; p++)
|
||||
|
@ -399,13 +396,15 @@ expari(int flag)
|
|||
if (quotes)
|
||||
rmescapes(p+2);
|
||||
result = arith(p+2);
|
||||
fmtstr(p, 12, "%d", result);
|
||||
fmtstr(p, SPACE_NEEDED, "%"PRIdMAX, result);
|
||||
|
||||
while (*p++)
|
||||
;
|
||||
|
||||
if (quoted == 0)
|
||||
recordregion(begoff, p - 1 - start, 0);
|
||||
result = expdest - p + 1;
|
||||
STADJUST(-result, expdest);
|
||||
adjustment = expdest - p + 1;
|
||||
STADJUST(-adjustment, expdest);
|
||||
}
|
||||
|
||||
|
||||
|
@ -427,7 +426,7 @@ expbackq(union node *cmd, int quoted, int flag)
|
|||
int startloc = dest - stackblock();
|
||||
char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
|
||||
int saveherefd;
|
||||
int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
|
||||
int quotes = flag & (EXP_FULL | EXP_CASE);
|
||||
int nnl;
|
||||
|
||||
INTOFF;
|
||||
|
@ -447,7 +446,6 @@ expbackq(union node *cmd, int quoted, int flag)
|
|||
p = in.buf;
|
||||
lastc = '\0';
|
||||
nnl = 0;
|
||||
/* Don't copy trailing newlines */
|
||||
for (;;) {
|
||||
if (--in.nleft < 0) {
|
||||
if (in.fd < 0)
|
||||
|
@ -461,16 +459,17 @@ expbackq(union node *cmd, int quoted, int flag)
|
|||
}
|
||||
lastc = *p++;
|
||||
if (lastc != '\0') {
|
||||
if (quotes && syntax[(int)lastc] == CCTL)
|
||||
STPUTC(CTLESC, dest);
|
||||
if (lastc == '\n') {
|
||||
if (lastc == '\n')
|
||||
nnl++;
|
||||
} else {
|
||||
else {
|
||||
CHECKSTRSPACE(nnl + 2, dest);
|
||||
while (nnl > 0) {
|
||||
nnl--;
|
||||
STPUTC('\n', dest);
|
||||
USTPUTC('\n', dest);
|
||||
}
|
||||
STPUTC(lastc, dest);
|
||||
if (quotes && syntax[(int)lastc] == CCTL)
|
||||
USTPUTC(CTLESC, dest);
|
||||
USTPUTC(lastc, dest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -480,12 +479,12 @@ expbackq(union node *cmd, int quoted, int flag)
|
|||
if (in.buf)
|
||||
ckfree(in.buf);
|
||||
if (in.jp)
|
||||
exitstatus = waitforjob(in.jp, (int *)NULL);
|
||||
back_exitstatus = waitforjob(in.jp);
|
||||
if (quoted == 0)
|
||||
recordregion(startloc, dest - stackblock(), 0);
|
||||
TRACE(("evalbackq: size=%d: \"%.*s\"\n",
|
||||
(dest - stackblock()) - startloc,
|
||||
(dest - stackblock()) - startloc,
|
||||
(int)((dest - stackblock()) - startloc),
|
||||
(int)((dest - stackblock()) - startloc),
|
||||
stackblock() + startloc));
|
||||
expdest = dest;
|
||||
INTON;
|
||||
|
@ -494,8 +493,7 @@ expbackq(union node *cmd, int quoted, int flag)
|
|||
|
||||
|
||||
STATIC int
|
||||
subevalvar(char *p, char *str, int strloc, int subtype, int startloc,
|
||||
int varflags)
|
||||
subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags)
|
||||
{
|
||||
char *startp;
|
||||
char *loc = NULL;
|
||||
|
@ -503,10 +501,21 @@ subevalvar(char *p, char *str, int strloc, int subtype, int startloc,
|
|||
int c = 0;
|
||||
int saveherefd = herefd;
|
||||
struct nodelist *saveargbackq = argbackq;
|
||||
int amount;
|
||||
int amount, how;
|
||||
|
||||
herefd = -1;
|
||||
argstr(p, 0);
|
||||
switch (subtype) {
|
||||
case VSTRIMLEFT:
|
||||
case VSTRIMLEFTMAX:
|
||||
case VSTRIMRIGHT:
|
||||
case VSTRIMRIGHTMAX:
|
||||
how = (varflags & VSQUOTE) ? 0 : EXP_CASE;
|
||||
break;
|
||||
default:
|
||||
how = 0;
|
||||
break;
|
||||
}
|
||||
argstr(p, how);
|
||||
STACKSTRNUL(expdest);
|
||||
herefd = saveherefd;
|
||||
argbackq = saveargbackq;
|
||||
|
@ -520,28 +529,25 @@ subevalvar(char *p, char *str, int strloc, int subtype, int startloc,
|
|||
amount = startp - expdest;
|
||||
STADJUST(amount, expdest);
|
||||
varflags &= ~VSNUL;
|
||||
if (c != 0)
|
||||
*loc = c;
|
||||
return 1;
|
||||
|
||||
case VSQUESTION:
|
||||
if (*p != CTLENDVAR) {
|
||||
outfmt(&errout, "%s\n", startp);
|
||||
error((char *)NULL);
|
||||
error(NULL);
|
||||
}
|
||||
error("%.*s: parameter %snot set", (int)(p - str - 1),
|
||||
error("%.*s: parameter %snot set",
|
||||
(int)(p - str - 1),
|
||||
str, (varflags & VSNUL) ? "null or "
|
||||
: nullstr);
|
||||
return 0;
|
||||
/* NOTREACHED */
|
||||
|
||||
case VSTRIMLEFT:
|
||||
for (loc = startp; loc < str; loc++) {
|
||||
c = *loc;
|
||||
*loc = '\0';
|
||||
if (patmatch(str, startp, varflags & VSQUOTE)) {
|
||||
*loc = c;
|
||||
if (patmatch(str, startp, varflags & VSQUOTE))
|
||||
goto recordleft;
|
||||
}
|
||||
*loc = c;
|
||||
if ((varflags & VSQUOTE) && *loc == CTLESC)
|
||||
loc++;
|
||||
|
@ -552,10 +558,8 @@ subevalvar(char *p, char *str, int strloc, int subtype, int startloc,
|
|||
for (loc = str - 1; loc >= startp;) {
|
||||
c = *loc;
|
||||
*loc = '\0';
|
||||
if (patmatch(str, startp, varflags & VSQUOTE)) {
|
||||
*loc = c;
|
||||
if (patmatch(str, startp, varflags & VSQUOTE))
|
||||
goto recordleft;
|
||||
}
|
||||
*loc = c;
|
||||
loc--;
|
||||
if ((varflags & VSQUOTE) && loc > startp &&
|
||||
|
@ -571,11 +575,8 @@ subevalvar(char *p, char *str, int strloc, int subtype, int startloc,
|
|||
|
||||
case VSTRIMRIGHT:
|
||||
for (loc = str - 1; loc >= startp;) {
|
||||
if (patmatch(str, loc, varflags & VSQUOTE)) {
|
||||
amount = loc - expdest;
|
||||
STADJUST(amount, expdest);
|
||||
return 1;
|
||||
}
|
||||
if (patmatch(str, loc, varflags & VSQUOTE))
|
||||
goto recordright;
|
||||
loc--;
|
||||
if ((varflags & VSQUOTE) && loc > startp &&
|
||||
*(loc - 1) == CTLESC) {
|
||||
|
@ -590,27 +591,31 @@ subevalvar(char *p, char *str, int strloc, int subtype, int startloc,
|
|||
|
||||
case VSTRIMRIGHTMAX:
|
||||
for (loc = startp; loc < str - 1; loc++) {
|
||||
if (patmatch(str, loc, varflags & VSQUOTE)) {
|
||||
amount = loc - expdest;
|
||||
STADJUST(amount, expdest);
|
||||
return 1;
|
||||
}
|
||||
if (patmatch(str, loc, varflags & VSQUOTE))
|
||||
goto recordright;
|
||||
if ((varflags & VSQUOTE) && *loc == CTLESC)
|
||||
loc++;
|
||||
}
|
||||
return 0;
|
||||
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
recordleft:
|
||||
*loc = c;
|
||||
amount = ((str - 1) - (loc - startp)) - expdest;
|
||||
STADJUST(amount, expdest);
|
||||
while (loc != str - 1)
|
||||
*startp++ = *loc++;
|
||||
return 1;
|
||||
|
||||
recordright:
|
||||
amount = loc - expdest;
|
||||
STADJUST(amount, expdest);
|
||||
STPUTC('\0', expdest);
|
||||
STADJUST(-1, expdest);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -632,31 +637,37 @@ evalvar(char *p, int flag)
|
|||
int special;
|
||||
int startloc;
|
||||
int varlen;
|
||||
int easy;
|
||||
int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
|
||||
int apply_ifs;
|
||||
int quotes = flag & (EXP_FULL | EXP_CASE);
|
||||
|
||||
varflags = *p++;
|
||||
varflags = (unsigned char)*p++;
|
||||
subtype = varflags & VSTYPE;
|
||||
var = p;
|
||||
special = 0;
|
||||
if (! is_name(*p))
|
||||
special = 1;
|
||||
special = !is_name(*p);
|
||||
p = strchr(p, '=') + 1;
|
||||
|
||||
again: /* jump here after setting a variable with ${var=text} */
|
||||
if (special) {
|
||||
if (varflags & VSLINENO) {
|
||||
set = 1;
|
||||
special = 0;
|
||||
val = var;
|
||||
p[-1] = '\0';
|
||||
} else if (special) {
|
||||
set = varisset(var, varflags & VSNUL);
|
||||
val = NULL;
|
||||
} else {
|
||||
val = bltinlookup(var, 1);
|
||||
val = lookupvar(var);
|
||||
if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
|
||||
val = NULL;
|
||||
set = 0;
|
||||
} else
|
||||
set = 1;
|
||||
}
|
||||
|
||||
varlen = 0;
|
||||
startloc = expdest - stackblock();
|
||||
if (!set && uflag) {
|
||||
|
||||
if (!set && uflag && *var != '@' && *var != '*') {
|
||||
switch (subtype) {
|
||||
case VSNORMAL:
|
||||
case VSTRIMLEFT:
|
||||
|
@ -664,14 +675,16 @@ again: /* jump here after setting a variable with ${var=text} */
|
|||
case VSTRIMRIGHT:
|
||||
case VSTRIMRIGHTMAX:
|
||||
case VSLENGTH:
|
||||
error("%.*s: parameter not set", (int)(p - var - 1),
|
||||
var);
|
||||
error("%.*s: parameter not set",
|
||||
(int)(p - var - 1), var);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
|
||||
if (set && subtype != VSPLUS) {
|
||||
/* insert the value of the variable */
|
||||
if (special) {
|
||||
varvalue(var, varflags & VSQUOTE, flag & EXP_FULL);
|
||||
varvalue(var, varflags & VSQUOTE, subtype, flag);
|
||||
if (subtype == VSLENGTH) {
|
||||
varlen = expdest - stackblock() - startloc;
|
||||
STADJUST(-varlen, expdest);
|
||||
|
@ -683,11 +696,9 @@ again: /* jump here after setting a variable with ${var=text} */
|
|||
if (subtype == VSLENGTH) {
|
||||
for (;*val; val++)
|
||||
varlen++;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
while (*val) {
|
||||
if (quotes &&
|
||||
syntax[(int)*val] == CCTL)
|
||||
if (quotes && syntax[(int)*val] == CCTL)
|
||||
STPUTC(CTLESC, expdest);
|
||||
STPUTC(*val++, expdest);
|
||||
}
|
||||
|
@ -696,34 +707,45 @@ again: /* jump here after setting a variable with ${var=text} */
|
|||
}
|
||||
}
|
||||
|
||||
if (subtype == VSPLUS)
|
||||
set = ! set;
|
||||
|
||||
easy = ((varflags & VSQUOTE) == 0 ||
|
||||
(*var == '@' && shellparam.nparam != 1));
|
||||
|
||||
if (flag & EXP_IN_QUOTES)
|
||||
apply_ifs = 0;
|
||||
else if (varflags & VSQUOTE) {
|
||||
if (*var == '@' && shellparam.nparam != 1)
|
||||
apply_ifs = 1;
|
||||
else {
|
||||
/*
|
||||
* Mark so that we don't apply IFS if we recurse through
|
||||
* here expanding $bar from "${foo-$bar}".
|
||||
*/
|
||||
flag |= EXP_IN_QUOTES;
|
||||
apply_ifs = 0;
|
||||
}
|
||||
} else
|
||||
apply_ifs = 1;
|
||||
|
||||
switch (subtype) {
|
||||
case VSLENGTH:
|
||||
expdest = cvtnum(varlen, expdest);
|
||||
goto record;
|
||||
break;
|
||||
|
||||
case VSNORMAL:
|
||||
if (!easy)
|
||||
break;
|
||||
record:
|
||||
recordregion(startloc, expdest - stackblock(),
|
||||
varflags & VSQUOTE);
|
||||
break;
|
||||
|
||||
case VSPLUS:
|
||||
set = !set;
|
||||
/* FALLTHROUGH */
|
||||
case VSMINUS:
|
||||
if (!set) {
|
||||
argstr(p, flag);
|
||||
break;
|
||||
argstr(p, flag | (apply_ifs ? EXP_IFS_SPLIT : 0));
|
||||
/*
|
||||
* ${x-a b c} doesn't get split, but removing the
|
||||
* 'apply_ifs = 0' apparently breaks ${1+"$@"}..
|
||||
* ${x-'a b' c} should generate 2 args.
|
||||
*/
|
||||
/* We should have marked stuff already */
|
||||
apply_ifs = 0;
|
||||
}
|
||||
if (easy)
|
||||
goto record;
|
||||
break;
|
||||
|
||||
case VSTRIMLEFT:
|
||||
|
@ -745,11 +767,13 @@ record:
|
|||
}
|
||||
/* Remove any recorded regions beyond start of variable */
|
||||
removerecordregions(startloc);
|
||||
goto record;
|
||||
apply_ifs = 1;
|
||||
break;
|
||||
|
||||
case VSASSIGN:
|
||||
case VSQUESTION:
|
||||
if (!set) {
|
||||
if (set)
|
||||
break;
|
||||
if (subevalvar(p, var, 0, subtype, startloc, varflags)) {
|
||||
varflags &= ~VSNUL;
|
||||
/*
|
||||
|
@ -759,15 +783,17 @@ record:
|
|||
removerecordregions(startloc);
|
||||
goto again;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (easy)
|
||||
goto record;
|
||||
apply_ifs = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
p[-1] = '='; /* recover overwritten '=' */
|
||||
|
||||
if (apply_ifs)
|
||||
recordregion(startloc, expdest - stackblock(),
|
||||
varflags & VSQUOTE);
|
||||
|
||||
if (subtype != VSNORMAL) { /* skip to end of alternative */
|
||||
int nesting = 1;
|
||||
|
@ -798,7 +824,6 @@ record:
|
|||
STATIC int
|
||||
varisset(char *name, int nulok)
|
||||
{
|
||||
|
||||
if (*name == '!')
|
||||
return backgndpid != -1;
|
||||
else if (*name == '@' || *name == '*') {
|
||||
|
@ -838,19 +863,18 @@ varisset(char *name, int nulok)
|
|||
*/
|
||||
|
||||
STATIC void
|
||||
varvalue(char *name, int quoted, int allow_split)
|
||||
varvalue(char *name, int quoted, int subtype, int flag)
|
||||
{
|
||||
int num;
|
||||
char *p;
|
||||
int i;
|
||||
extern int oexitstatus;
|
||||
char sep;
|
||||
char **ap;
|
||||
char const *syntax;
|
||||
|
||||
#define STRTODEST(p) \
|
||||
do {\
|
||||
if (allow_split) { \
|
||||
if (flag & (EXP_FULL | EXP_CASE) && subtype != VSLENGTH) { \
|
||||
syntax = quoted? DQSYNTAX : BASESYNTAX; \
|
||||
while (*p) { \
|
||||
if (syntax[(int)*p] == CCTL) \
|
||||
|
@ -868,7 +892,7 @@ varvalue(char *name, int quoted, int allow_split)
|
|||
num = rootpid;
|
||||
goto numvar;
|
||||
case '?':
|
||||
num = oexitstatus;
|
||||
num = exitstatus;
|
||||
goto numvar;
|
||||
case '#':
|
||||
num = shellparam.nparam;
|
||||
|
@ -879,21 +903,22 @@ numvar:
|
|||
expdest = cvtnum(num, expdest);
|
||||
break;
|
||||
case '-':
|
||||
for (i = 0 ; i < NOPTS ; i++) {
|
||||
if (optlist[i].val)
|
||||
for (i = 0; optlist[i].name; i++) {
|
||||
if (optlist[i].val && optlist[i].letter)
|
||||
STPUTC(optlist[i].letter, expdest);
|
||||
}
|
||||
break;
|
||||
case '@':
|
||||
if (allow_split && quoted) {
|
||||
if (flag & EXP_FULL && quoted) {
|
||||
for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
|
||||
STRTODEST(p);
|
||||
if (*ap)
|
||||
/* A NUL separates args inside "" */
|
||||
STPUTC('\0', expdest);
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
/* fall through */
|
||||
case '*':
|
||||
if (ifsset() != 0)
|
||||
sep = ifsval()[0];
|
||||
|
@ -924,18 +949,24 @@ numvar:
|
|||
|
||||
|
||||
/*
|
||||
* Record the the fact that we have to scan this region of the
|
||||
* Record the fact that we have to scan this region of the
|
||||
* string for IFS characters.
|
||||
*/
|
||||
|
||||
STATIC void
|
||||
recordregion(int start, int end, int nulonly)
|
||||
recordregion(int start, int end, int inquotes)
|
||||
{
|
||||
struct ifsregion *ifsp;
|
||||
|
||||
if (ifslastp == NULL) {
|
||||
ifsp = &ifsfirst;
|
||||
} else {
|
||||
if (ifslastp->endoff == start
|
||||
&& ifslastp->inquotes == inquotes) {
|
||||
/* extend previous area */
|
||||
ifslastp->endoff = end;
|
||||
return;
|
||||
}
|
||||
ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
|
||||
ifslastp->next = ifsp;
|
||||
}
|
||||
|
@ -943,7 +974,7 @@ recordregion(int start, int end, int nulonly)
|
|||
ifslastp->next = NULL;
|
||||
ifslastp->begoff = start;
|
||||
ifslastp->endoff = end;
|
||||
ifslastp->nulonly = nulonly;
|
||||
ifslastp->inquotes = inquotes;
|
||||
}
|
||||
|
||||
|
||||
|
@ -961,82 +992,109 @@ ifsbreakup(char *string, struct arglist *arglist)
|
|||
char *start;
|
||||
char *p;
|
||||
char *q;
|
||||
char *ifs;
|
||||
int ifsspc;
|
||||
int nulonly;
|
||||
|
||||
const char *ifs;
|
||||
const char *ifsspc;
|
||||
int had_param_ch = 0;
|
||||
|
||||
start = string;
|
||||
ifsspc = 0;
|
||||
nulonly = 0;
|
||||
if (ifslastp != NULL) {
|
||||
ifsp = &ifsfirst;
|
||||
do {
|
||||
|
||||
if (ifslastp == NULL) {
|
||||
/* Return entire argument, IFS doesn't apply to any of it */
|
||||
sp = (struct strlist *)stalloc(sizeof *sp);
|
||||
sp->text = start;
|
||||
*arglist->lastp = sp;
|
||||
arglist->lastp = &sp->next;
|
||||
return;
|
||||
}
|
||||
|
||||
ifs = ifsset() ? ifsval() : " \t\n";
|
||||
|
||||
for (ifsp = &ifsfirst; ifsp != NULL; ifsp = ifsp->next) {
|
||||
p = string + ifsp->begoff;
|
||||
nulonly = ifsp->nulonly;
|
||||
ifs = nulonly ? nullstr :
|
||||
( ifsset() ? ifsval() : " \t\n" );
|
||||
ifsspc = 0;
|
||||
while (p < string + ifsp->endoff) {
|
||||
had_param_ch = 1;
|
||||
q = p;
|
||||
if (*p == CTLESC)
|
||||
p++;
|
||||
if (strchr(ifs, *p)) {
|
||||
if (!nulonly)
|
||||
ifsspc = (strchr(" \t\n", *p) != NULL);
|
||||
if (ifsp->inquotes) {
|
||||
/* Only NULs (should be from "$@") end args */
|
||||
if (*p != 0) {
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
ifsspc = NULL;
|
||||
} else {
|
||||
if (!strchr(ifs, *p)) {
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
had_param_ch = 0;
|
||||
ifsspc = strchr(" \t\n", *p);
|
||||
|
||||
/* Ignore IFS whitespace at start */
|
||||
if (q == start && ifsspc) {
|
||||
if (q == start && ifsspc != NULL) {
|
||||
p++;
|
||||
start = p;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Save this argument... */
|
||||
*q = '\0';
|
||||
sp = (struct strlist *)stalloc(sizeof *sp);
|
||||
sp->text = start;
|
||||
*arglist->lastp = sp;
|
||||
arglist->lastp = &sp->next;
|
||||
p++;
|
||||
if (!nulonly) {
|
||||
for (;;) {
|
||||
if (p >= string + ifsp->endoff) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (ifsspc != NULL) {
|
||||
/* Ignore further trailing IFS whitespace */
|
||||
for (; p < string + ifsp->endoff; p++) {
|
||||
q = p;
|
||||
if (*p == CTLESC)
|
||||
p++;
|
||||
if (strchr(ifs, *p) == NULL) {
|
||||
p = q;
|
||||
break;
|
||||
} else if (strchr(" \t\n",*p) == NULL) {
|
||||
if (ifsspc) {
|
||||
}
|
||||
if (strchr(" \t\n", *p) == NULL) {
|
||||
p++;
|
||||
ifsspc = 0;
|
||||
} else {
|
||||
p = q;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
p++;
|
||||
}
|
||||
}
|
||||
start = p;
|
||||
} else
|
||||
p++;
|
||||
}
|
||||
} while ((ifsp = ifsp->next) != NULL);
|
||||
if (*start || (!ifsspc && start > string &&
|
||||
(nulonly || 1))) {
|
||||
}
|
||||
|
||||
/*
|
||||
* Save anything left as an argument.
|
||||
* Traditionally we have treated 'IFS=':'; set -- x$IFS' as
|
||||
* generating 2 arguments, the second of which is empty.
|
||||
* Some recent clarification of the Posix spec say that it
|
||||
* should only generate one....
|
||||
*/
|
||||
if (had_param_ch || *start != 0) {
|
||||
sp = (struct strlist *)stalloc(sizeof *sp);
|
||||
sp->text = start;
|
||||
*arglist->lastp = sp;
|
||||
arglist->lastp = &sp->next;
|
||||
}
|
||||
} else {
|
||||
sp = (struct strlist *)stalloc(sizeof *sp);
|
||||
sp->text = start;
|
||||
*arglist->lastp = sp;
|
||||
arglist->lastp = &sp->next;
|
||||
}
|
||||
|
||||
STATIC void
|
||||
ifsfree(void)
|
||||
{
|
||||
while (ifsfirst.next != NULL) {
|
||||
struct ifsregion *ifsp;
|
||||
INTOFF;
|
||||
ifsp = ifsfirst.next->next;
|
||||
ckfree(ifsfirst.next);
|
||||
ifsfirst.next = ifsp;
|
||||
INTON;
|
||||
}
|
||||
ifslastp = NULL;
|
||||
ifsfirst.next = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1046,11 +1104,11 @@ ifsbreakup(char *string, struct arglist *arglist)
|
|||
* should be escapes. The results are stored in the list exparg.
|
||||
*/
|
||||
|
||||
STATIC char *expdir;
|
||||
char *expdir;
|
||||
|
||||
|
||||
STATIC void
|
||||
expandmeta(struct strlist *str, int flag __unused)
|
||||
expandmeta(struct strlist *str, int flag)
|
||||
{
|
||||
char *p;
|
||||
struct strlist **savelastp;
|
||||
|
@ -1107,6 +1165,7 @@ STATIC void
|
|||
expmeta(char *enddir, char *name)
|
||||
{
|
||||
char *p;
|
||||
const char *cp;
|
||||
char *q;
|
||||
char *start;
|
||||
char *endname;
|
||||
|
@ -1124,7 +1183,7 @@ expmeta(char *enddir, char *name)
|
|||
metaflag = 1;
|
||||
else if (*p == '[') {
|
||||
q = p + 1;
|
||||
if (*q == '!' || *q == '^')
|
||||
if (*q == '!')
|
||||
q++;
|
||||
for (;;) {
|
||||
while (*q == CTLQUOTEMARK)
|
||||
|
@ -1164,7 +1223,7 @@ expmeta(char *enddir, char *name)
|
|||
if (*p == '\0')
|
||||
break;
|
||||
}
|
||||
if (metaflag == 0 || stat(expdir, &statb) >= 0)
|
||||
if (metaflag == 0 || lstat(expdir, &statb) >= 0)
|
||||
addfname(expdir);
|
||||
return;
|
||||
}
|
||||
|
@ -1180,14 +1239,14 @@ expmeta(char *enddir, char *name)
|
|||
}
|
||||
}
|
||||
if (enddir == expdir) {
|
||||
p = ".";
|
||||
cp = ".";
|
||||
} else if (enddir == expdir + 1 && *expdir == '/') {
|
||||
p = "/";
|
||||
cp = "/";
|
||||
} else {
|
||||
p = expdir;
|
||||
cp = expdir;
|
||||
enddir[-1] = '\0';
|
||||
}
|
||||
if ((dirp = opendir(p)) == NULL)
|
||||
if ((dirp = opendir(cp)) == NULL)
|
||||
return;
|
||||
if (enddir != expdir)
|
||||
enddir[-1] = '/';
|
||||
|
@ -1213,9 +1272,8 @@ expmeta(char *enddir, char *name)
|
|||
scopy(dp->d_name, enddir);
|
||||
addfname(expdir);
|
||||
} else {
|
||||
char *q;
|
||||
for (p = enddir, q = dp->d_name;
|
||||
(*p++ = *q++) != '\0';)
|
||||
for (p = enddir, cp = dp->d_name;
|
||||
(*p++ = *cp++) != '\0';)
|
||||
continue;
|
||||
p[-1] = '/';
|
||||
expmeta(p, endname);
|
||||
|
@ -1380,7 +1438,7 @@ pmatch(char *pattern, char *string, int squoted)
|
|||
char chr;
|
||||
|
||||
endp = p;
|
||||
if (*endp == '!' || *endp == '^')
|
||||
if (*endp == '!')
|
||||
endp++;
|
||||
for (;;) {
|
||||
while (*endp == CTLQUOTEMARK)
|
||||
|
@ -1393,7 +1451,7 @@ pmatch(char *pattern, char *string, int squoted)
|
|||
break;
|
||||
}
|
||||
invert = 0;
|
||||
if (*p == '!' || *p == '^') {
|
||||
if (*p == '!') {
|
||||
invert++;
|
||||
p++;
|
||||
}
|
||||
|
@ -1415,9 +1473,7 @@ pmatch(char *pattern, char *string, int squoted)
|
|||
p++;
|
||||
if (*p == CTLESC)
|
||||
p++;
|
||||
if ( collate_range_cmp(chr, c) >= 0
|
||||
&& collate_range_cmp(chr, *p) <= 0
|
||||
)
|
||||
if (chr >= c && chr <= *p)
|
||||
found = 1;
|
||||
p++;
|
||||
} else {
|
||||
|
@ -1532,17 +1588,15 @@ wordexpcmd(int argc, char **argv)
|
|||
size_t len;
|
||||
int i;
|
||||
|
||||
out1fmt("%08x", argc - 1);
|
||||
out1fmt("%d", argc - 1);
|
||||
out1c('\0');
|
||||
for (i = 1, len = 0; i < argc; i++)
|
||||
len += strlen(argv[i]);
|
||||
out1fmt("%08x", (int)len);
|
||||
out1fmt("%zu", len);
|
||||
out1c('\0');
|
||||
for (i = 1; i < argc; i++) {
|
||||
out1str(argv[i]);
|
||||
out1c('\0');
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* $PchId: expand.c,v 1.6 2006/04/10 14:52:06 philip Exp $
|
||||
*/
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: expand.h,v 1.19 2012/12/22 20:15:22 dsl Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -30,9 +32,10 @@
|
|||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)expand.h 8.2 (Berkeley) 5/4/95
|
||||
* $FreeBSD: src/bin/sh/expand.h,v 1.12 2004/04/06 20:06:51 markm Exp $
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
struct strlist {
|
||||
struct strlist *next;
|
||||
char *text;
|
||||
|
@ -52,23 +55,19 @@ struct arglist {
|
|||
#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
|
||||
#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
|
||||
#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
|
||||
#define EXP_IFS_SPLIT 0x20 /* need to record arguments for ifs breakup */
|
||||
#define EXP_IN_QUOTES 0x40 /* don't set EXP_IFS_SPLIT again */
|
||||
|
||||
|
||||
union node;
|
||||
void expandhere(union node *, int);
|
||||
void expandarg(union node *, struct arglist *, int);
|
||||
void expari(int);
|
||||
int patmatch(char *, char *, int);
|
||||
void rmescapes(char *);
|
||||
int casematch(union node *, char *);
|
||||
int wordexpcmd(int, char **);
|
||||
|
||||
/* From arith.y */
|
||||
int arith(char *);
|
||||
int arith_assign(char *, arith_t);
|
||||
int expcmd(int , char **);
|
||||
intmax_t arith(const char *);
|
||||
void arith_lex_reset(void);
|
||||
|
||||
|
||||
/*
|
||||
* $PchId: expand.h,v 1.4 2006/03/30 14:50:52 philip Exp $
|
||||
*/
|
||||
int yylex(void);
|
9
minix/commands/ash/funcs/cmv → bin/sh/funcs/cmv
Executable file → Normal file
9
minix/commands/ash/funcs/cmv → bin/sh/funcs/cmv
Executable file → Normal file
|
@ -1,3 +1,4 @@
|
|||
# $NetBSD: cmv,v 1.7 1995/05/11 21:31:05 christos Exp $
|
||||
# Copyright (c) 1991, 1993
|
||||
# The Regents of the University of California. All rights reserved.
|
||||
#
|
||||
|
@ -12,6 +13,10 @@
|
|||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. All advertising materials mentioning features or use of this software
|
||||
# must display the following acknowledgement:
|
||||
# This product includes software developed by the University of
|
||||
# California, Berkeley and its contributors.
|
||||
# 4. Neither the name of the University nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
|
@ -29,7 +34,6 @@
|
|||
# SUCH DAMAGE.
|
||||
#
|
||||
# @(#)cmv 8.2 (Berkeley) 5/4/95
|
||||
# $FreeBSD: src/bin/sh/funcs/cmv,v 1.7 2004/04/06 20:06:53 markm Exp $
|
||||
|
||||
# Conditional move--don't replace an existing file.
|
||||
|
||||
|
@ -44,6 +48,3 @@ cmv() {
|
|||
fi
|
||||
/bin/mv "$1" "$2"
|
||||
}
|
||||
|
||||
#
|
||||
# $PchId: cmv,v 1.2 2006/03/29 10:43:18 philip Exp $
|
9
minix/commands/ash/funcs/dirs → bin/sh/funcs/dirs
Executable file → Normal file
9
minix/commands/ash/funcs/dirs → bin/sh/funcs/dirs
Executable file → Normal file
|
@ -1,3 +1,4 @@
|
|||
# $NetBSD: dirs,v 1.7 1995/05/11 21:31:08 christos Exp $
|
||||
# Copyright (c) 1991, 1993
|
||||
# The Regents of the University of California. All rights reserved.
|
||||
#
|
||||
|
@ -12,6 +13,10 @@
|
|||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. All advertising materials mentioning features or use of this software
|
||||
# must display the following acknowledgement:
|
||||
# This product includes software developed by the University of
|
||||
# California, Berkeley and its contributors.
|
||||
# 4. Neither the name of the University nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
|
@ -29,7 +34,6 @@
|
|||
# SUCH DAMAGE.
|
||||
#
|
||||
# @(#)dirs 8.2 (Berkeley) 5/4/95
|
||||
# $FreeBSD: src/bin/sh/funcs/dirs,v 1.7 2004/04/06 20:06:53 markm Exp $
|
||||
|
||||
# pushd, popd, and dirs --- written by Chris Bertin
|
||||
# Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris
|
||||
|
@ -68,6 +72,3 @@ dirs () {
|
|||
echo "`pwd` $DSTACK"
|
||||
return 0
|
||||
}
|
||||
|
||||
#
|
||||
# $PchId: dirs,v 1.2 2006/03/29 10:43:18 philip Exp $
|
9
minix/commands/ash/funcs/kill → bin/sh/funcs/kill
Executable file → Normal file
9
minix/commands/ash/funcs/kill → bin/sh/funcs/kill
Executable file → Normal file
|
@ -1,3 +1,4 @@
|
|||
# $NetBSD: kill,v 1.7 1995/05/11 21:31:10 christos Exp $
|
||||
# Copyright (c) 1991, 1993
|
||||
# The Regents of the University of California. All rights reserved.
|
||||
#
|
||||
|
@ -12,6 +13,10 @@
|
|||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. All advertising materials mentioning features or use of this software
|
||||
# must display the following acknowledgement:
|
||||
# This product includes software developed by the University of
|
||||
# California, Berkeley and its contributors.
|
||||
# 4. Neither the name of the University nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
|
@ -29,7 +34,6 @@
|
|||
# SUCH DAMAGE.
|
||||
#
|
||||
# @(#)kill 8.2 (Berkeley) 5/4/95
|
||||
# $FreeBSD: src/bin/sh/funcs/kill,v 1.7 2004/04/06 20:06:53 markm Exp $
|
||||
|
||||
# Convert job names to process ids and then run /bin/kill.
|
||||
|
||||
|
@ -44,6 +48,3 @@ kill() {
|
|||
done
|
||||
/bin/kill $args
|
||||
}
|
||||
|
||||
#
|
||||
# $PchId: kill,v 1.2 2006/03/29 10:43:18 philip Exp $
|
9
minix/commands/ash/funcs/login → bin/sh/funcs/login
Executable file → Normal file
9
minix/commands/ash/funcs/login → bin/sh/funcs/login
Executable file → Normal file
|
@ -1,3 +1,4 @@
|
|||
# $NetBSD: login,v 1.7 1995/05/11 21:31:11 christos Exp $
|
||||
# Copyright (c) 1991, 1993
|
||||
# The Regents of the University of California. All rights reserved.
|
||||
#
|
||||
|
@ -12,6 +13,10 @@
|
|||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. All advertising materials mentioning features or use of this software
|
||||
# must display the following acknowledgement:
|
||||
# This product includes software developed by the University of
|
||||
# California, Berkeley and its contributors.
|
||||
# 4. Neither the name of the University nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
|
@ -29,10 +34,6 @@
|
|||
# SUCH DAMAGE.
|
||||
#
|
||||
# @(#)login 8.2 (Berkeley) 5/4/95
|
||||
# $FreeBSD: src/bin/sh/funcs/login,v 1.7 2004/04/06 20:06:53 markm Exp $
|
||||
|
||||
# replaces the login builtin in the BSD shell
|
||||
login () exec login "$@"
|
||||
|
||||
#
|
||||
# $PchId: login,v 1.2 2006/03/29 10:43:18 philip Exp $
|
9
minix/commands/ash/funcs/newgrp → bin/sh/funcs/newgrp
Executable file → Normal file
9
minix/commands/ash/funcs/newgrp → bin/sh/funcs/newgrp
Executable file → Normal file
|
@ -1,3 +1,4 @@
|
|||
# $NetBSD: newgrp,v 1.7 1995/05/11 21:31:12 christos Exp $
|
||||
# Copyright (c) 1991, 1993
|
||||
# The Regents of the University of California. All rights reserved.
|
||||
#
|
||||
|
@ -12,6 +13,10 @@
|
|||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. All advertising materials mentioning features or use of this software
|
||||
# must display the following acknowledgement:
|
||||
# This product includes software developed by the University of
|
||||
# California, Berkeley and its contributors.
|
||||
# 4. Neither the name of the University nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
|
@ -29,9 +34,5 @@
|
|||
# SUCH DAMAGE.
|
||||
#
|
||||
# @(#)newgrp 8.2 (Berkeley) 5/4/95
|
||||
# $FreeBSD: src/bin/sh/funcs/newgrp,v 1.7 2004/04/06 20:06:53 markm Exp $
|
||||
|
||||
newgrp() exec newgrp "$@"
|
||||
|
||||
#
|
||||
# $PchId: newgrp,v 1.2 2006/03/29 10:43:18 philip Exp $
|
9
minix/commands/ash/funcs/popd → bin/sh/funcs/popd
Executable file → Normal file
9
minix/commands/ash/funcs/popd → bin/sh/funcs/popd
Executable file → Normal file
|
@ -1,3 +1,4 @@
|
|||
# $NetBSD: popd,v 1.7 1995/05/11 21:31:13 christos Exp $
|
||||
# Copyright (c) 1991, 1993
|
||||
# The Regents of the University of California. All rights reserved.
|
||||
#
|
||||
|
@ -12,6 +13,10 @@
|
|||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. All advertising materials mentioning features or use of this software
|
||||
# must display the following acknowledgement:
|
||||
# This product includes software developed by the University of
|
||||
# California, Berkeley and its contributors.
|
||||
# 4. Neither the name of the University nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
|
@ -29,7 +34,6 @@
|
|||
# SUCH DAMAGE.
|
||||
#
|
||||
# @(#)popd 8.2 (Berkeley) 5/4/95
|
||||
# $FreeBSD: src/bin/sh/funcs/popd,v 1.7 2004/04/06 20:06:53 markm Exp $
|
||||
|
||||
# pushd, popd, and dirs --- written by Chris Bertin
|
||||
# Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris
|
||||
|
@ -68,6 +72,3 @@ dirs () {
|
|||
echo "`pwd` $DSTACK"
|
||||
return 0
|
||||
}
|
||||
|
||||
#
|
||||
# $PchId: popd,v 1.2 2006/03/29 10:43:18 philip Exp $
|
9
minix/commands/ash/funcs/pushd → bin/sh/funcs/pushd
Executable file → Normal file
9
minix/commands/ash/funcs/pushd → bin/sh/funcs/pushd
Executable file → Normal file
|
@ -1,3 +1,4 @@
|
|||
# $NetBSD: pushd,v 1.7 1995/05/11 21:31:15 christos Exp $
|
||||
# Copyright (c) 1991, 1993
|
||||
# The Regents of the University of California. All rights reserved.
|
||||
#
|
||||
|
@ -12,6 +13,10 @@
|
|||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. All advertising materials mentioning features or use of this software
|
||||
# must display the following acknowledgement:
|
||||
# This product includes software developed by the University of
|
||||
# California, Berkeley and its contributors.
|
||||
# 4. Neither the name of the University nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
|
@ -29,7 +34,6 @@
|
|||
# SUCH DAMAGE.
|
||||
#
|
||||
# @(#)pushd 8.2 (Berkeley) 5/4/95
|
||||
# $FreeBSD: src/bin/sh/funcs/pushd,v 1.7 2004/04/06 20:06:53 markm Exp $
|
||||
|
||||
# pushd, popd, and dirs --- written by Chris Bertin
|
||||
# Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris
|
||||
|
@ -68,6 +72,3 @@ dirs () {
|
|||
echo "`pwd` $DSTACK"
|
||||
return 0
|
||||
}
|
||||
|
||||
#
|
||||
# $PchId: pushd,v 1.2 2006/03/29 10:43:18 philip Exp $
|
9
minix/commands/ash/funcs/suspend → bin/sh/funcs/suspend
Executable file → Normal file
9
minix/commands/ash/funcs/suspend → bin/sh/funcs/suspend
Executable file → Normal file
|
@ -1,3 +1,4 @@
|
|||
# $NetBSD: suspend,v 1.7 1995/05/11 21:31:17 christos Exp $
|
||||
# Copyright (c) 1991, 1993
|
||||
# The Regents of the University of California. All rights reserved.
|
||||
#
|
||||
|
@ -12,6 +13,10 @@
|
|||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. All advertising materials mentioning features or use of this software
|
||||
# must display the following acknowledgement:
|
||||
# This product includes software developed by the University of
|
||||
# California, Berkeley and its contributors.
|
||||
# 4. Neither the name of the University nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
|
@ -29,13 +34,9 @@
|
|||
# SUCH DAMAGE.
|
||||
#
|
||||
# @(#)suspend 8.2 (Berkeley) 5/4/95
|
||||
# $FreeBSD: src/bin/sh/funcs/suspend,v 1.7 2004/04/06 20:06:53 markm Exp $
|
||||
|
||||
suspend() {
|
||||
local -
|
||||
set +j
|
||||
kill -TSTP 0
|
||||
}
|
||||
|
||||
#
|
||||
# $PchId: suspend,v 1.2 2006/03/29 10:43:18 philip Exp $
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: histedit.c,v 1.45 2012/03/20 18:42:29 matt Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -30,20 +32,17 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)histedit.c 8.2 (Berkeley) 5/4/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: histedit.c,v 1.45 2012/03/20 18:42:29 matt Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
/*
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/bin/sh/histedit.c,v 1.26 2004/04/06 20:06:51 markm Exp $");
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#ifndef NO_PATHS_H
|
||||
#include <sys/param.h>
|
||||
#include <paths.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
@ -54,14 +53,13 @@ __FBSDID("$FreeBSD: src/bin/sh/histedit.c,v 1.26 2004/04/06 20:06:51 markm Exp $
|
|||
#include "parser.h"
|
||||
#include "var.h"
|
||||
#include "options.h"
|
||||
#include "builtins.h"
|
||||
#include "main.h"
|
||||
#include "output.h"
|
||||
#include "mystring.h"
|
||||
#include "builtins.h"
|
||||
#if !defined(NO_HISTORY)
|
||||
#include "myhistedit.h"
|
||||
#include "complete.h"
|
||||
#include "error.h"
|
||||
#ifndef SMALL
|
||||
#include "eval.h"
|
||||
#include "memalloc.h"
|
||||
|
||||
|
@ -71,11 +69,14 @@ __FBSDID("$FreeBSD: src/bin/sh/histedit.c,v 1.26 2004/04/06 20:06:51 markm Exp $
|
|||
History *hist; /* history cookie */
|
||||
EditLine *el; /* editline cookie */
|
||||
int displayhist;
|
||||
static FILE *el_in, *el_out, *el_err;
|
||||
static FILE *el_in, *el_out;
|
||||
unsigned char _el_fn_complete(EditLine *, int);
|
||||
|
||||
STATIC char *fc_replace(const char *, char *, char *);
|
||||
STATIC int not_fcnumber(char *);
|
||||
STATIC int str_to_event(char *, int);
|
||||
STATIC const char *fc_replace(const char *, char *, char *);
|
||||
|
||||
#ifdef DEBUG
|
||||
extern FILE *tracefile;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Set history and editing status. Called whenever the status may
|
||||
|
@ -84,10 +85,11 @@ STATIC int str_to_event(char *, int);
|
|||
void
|
||||
histedit(void)
|
||||
{
|
||||
FILE *el_err;
|
||||
|
||||
#define editing (Eflag || Vflag)
|
||||
|
||||
if (iflag) {
|
||||
if (iflag == 1) {
|
||||
if (!hist) {
|
||||
/*
|
||||
* turn history on
|
||||
|
@ -105,20 +107,37 @@ histedit(void)
|
|||
/*
|
||||
* turn editing on
|
||||
*/
|
||||
char *term, *shname;
|
||||
|
||||
INTOFF;
|
||||
if (el_in == NULL)
|
||||
el_in = fdopen(0, "r");
|
||||
if (el_err == NULL)
|
||||
el_err = fdopen(1, "w");
|
||||
if (el_out == NULL)
|
||||
el_out = fdopen(2, "w");
|
||||
if (el_in == NULL || el_err == NULL || el_out == NULL)
|
||||
if (el_in == NULL || el_out == NULL)
|
||||
goto bad;
|
||||
el = el_init(arg0, el_in, el_out, el_err);
|
||||
el_err = el_out;
|
||||
#if DEBUG
|
||||
if (tracefile)
|
||||
el_err = tracefile;
|
||||
#endif
|
||||
term = lookupvar("TERM");
|
||||
if (term)
|
||||
setenv("TERM", term, 1);
|
||||
else
|
||||
unsetenv("TERM");
|
||||
shname = arg0;
|
||||
if (shname[0] == '-')
|
||||
shname++;
|
||||
el = el_init(shname, el_in, el_out, el_err);
|
||||
if (el != NULL) {
|
||||
if (hist)
|
||||
el_set(el, EL_HIST, history, hist);
|
||||
el_set(el, EL_PROMPT, getprompt);
|
||||
el_set(el, EL_SIGNAL, 1);
|
||||
el_set(el, EL_ADDFN, "rl-complete",
|
||||
"ReadLine compatible completion function",
|
||||
_el_fn_complete);
|
||||
} else {
|
||||
bad:
|
||||
out2str("sh: can't initialize editing\n");
|
||||
|
@ -131,27 +150,13 @@ bad:
|
|||
INTON;
|
||||
}
|
||||
if (el) {
|
||||
el_source(el, NULL);
|
||||
if (Vflag)
|
||||
el_set(el, EL_EDITOR, "vi");
|
||||
else if (Eflag)
|
||||
el_set(el, EL_EDITOR, "emacs");
|
||||
el_set(el, EL_ADDFN, "ed-do-complete",
|
||||
"Complete Argument", complete);
|
||||
el_set(el, EL_ADDFN, "ed-list-complete",
|
||||
"List Argument Completions", complete_list);
|
||||
el_set(el, EL_ADDFN, "ed-maybe-complete",
|
||||
"Complete Argument Or List Completions",
|
||||
complete_or_list);
|
||||
el_set(el, EL_ADDFN, "ed-expand",
|
||||
"Expand Completions", complete_expand);
|
||||
el_set(el, EL_BIND, "^I", "ed-maybe-complete", NULL);
|
||||
el_set(el, EL_BIND, "-a", "=", "ed-list-complete",
|
||||
NULL);
|
||||
el_set(el, EL_BIND, "-a", "\\\\", "ed-do-complete",
|
||||
NULL);
|
||||
el_set(el, EL_BIND, "-a", "*", "ed-expand",
|
||||
NULL);
|
||||
el_source(el, NULL);
|
||||
el_set(el, EL_BIND, "^I",
|
||||
tabcomplete ? "rl-complete" : "ed-insert", NULL);
|
||||
}
|
||||
} else {
|
||||
INTOFF;
|
||||
|
@ -169,8 +174,7 @@ bad:
|
|||
|
||||
|
||||
void
|
||||
sethistsize(hs)
|
||||
const char *hs;
|
||||
sethistsize(const char *hs)
|
||||
{
|
||||
int histsize;
|
||||
HistEvent he;
|
||||
|
@ -180,40 +184,63 @@ sethistsize(hs)
|
|||
(histsize = atoi(hs)) < 0)
|
||||
histsize = 100;
|
||||
history(hist, &he, H_SETSIZE, histsize);
|
||||
history(hist, &he, H_SETUNIQUE, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
setterm(const char *term)
|
||||
{
|
||||
if (el != NULL && term != NULL)
|
||||
if (el_set(el, EL_TERMINAL, term) != 0) {
|
||||
outfmt(out2, "sh: Can't set terminal type %s\n", term);
|
||||
outfmt(out2, "sh: Using dumb terminal settings.\n");
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
inputrc(int argc, char **argv)
|
||||
{
|
||||
if (argc != 2) {
|
||||
out2str("usage: inputrc file\n");
|
||||
return 1;
|
||||
}
|
||||
if (el != NULL) {
|
||||
if (el_source(el, argv[1])) {
|
||||
out2str("inputrc: failed\n");
|
||||
return 1;
|
||||
} else
|
||||
return 0;
|
||||
} else {
|
||||
out2str("sh: inputrc ignored, not editing\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This command is provided since POSIX decided to standardize
|
||||
* the Korn shell fc command. Oh well...
|
||||
*/
|
||||
int
|
||||
histcmd(int argc, char **argv)
|
||||
{
|
||||
int ch;
|
||||
char *editor = NULL;
|
||||
const char * volatile editor = NULL;
|
||||
HistEvent he;
|
||||
int lflg = 0, nflg = 0, rflg = 0, sflg = 0;
|
||||
int lflg = 0;
|
||||
volatile int nflg = 0, rflg = 0, sflg = 0;
|
||||
int i, retval;
|
||||
char *firststr, *laststr;
|
||||
const char *firststr, *laststr;
|
||||
int first, last, direction;
|
||||
char *pat = NULL, *repl;
|
||||
char *pat = NULL, *repl; /* ksh "fc old=new" crap */
|
||||
static int active = 0;
|
||||
struct jmploc jmploc;
|
||||
struct jmploc *volatile savehandler;
|
||||
char editfile[PATH_MAX];
|
||||
char editfile[MAXPATHLEN + 1];
|
||||
FILE *efp;
|
||||
int oldhistnum;
|
||||
#ifdef __GNUC__
|
||||
/* Avoid longjmp clobbering */
|
||||
(void) &editor;
|
||||
(void) &lflg;
|
||||
(void) &nflg;
|
||||
(void) &rflg;
|
||||
(void) &sflg;
|
||||
(void) &firststr;
|
||||
(void) &laststr;
|
||||
(void) &pat;
|
||||
(void) &repl;
|
||||
(void) &efp;
|
||||
(void) &argc;
|
||||
(void) &argv;
|
||||
repl = NULL; /* XXX gcc4 */
|
||||
efp = NULL; /* XXX gcc4 */
|
||||
#endif
|
||||
|
||||
if (hist == NULL)
|
||||
|
@ -223,12 +250,11 @@ histcmd(int argc, char **argv)
|
|||
error("missing history argument");
|
||||
|
||||
optreset = 1; optind = 1; /* initialize getopt */
|
||||
opterr = 0;
|
||||
while (not_fcnumber(argv[optind]) &&
|
||||
(ch = getopt(argc, argv, ":e:lnrs")) != -1)
|
||||
switch ((char)ch) {
|
||||
case 'e':
|
||||
editor = optarg;
|
||||
editor = optionarg;
|
||||
break;
|
||||
case 'l':
|
||||
lflg = 1;
|
||||
|
@ -244,9 +270,11 @@ histcmd(int argc, char **argv)
|
|||
break;
|
||||
case ':':
|
||||
error("option -%c expects argument", optopt);
|
||||
/* NOTREACHED */
|
||||
case '?':
|
||||
default:
|
||||
error("unknown option: -%c", optopt);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
argc -= optind, argv += optind;
|
||||
|
||||
|
@ -260,6 +288,7 @@ histcmd(int argc, char **argv)
|
|||
* Catch interrupts to reset active counter and
|
||||
* cleanup temp files.
|
||||
*/
|
||||
savehandler = handler;
|
||||
if (setjmp(jmploc.loc)) {
|
||||
active = 0;
|
||||
if (*editfile)
|
||||
|
@ -267,7 +296,6 @@ histcmd(int argc, char **argv)
|
|||
handler = savehandler;
|
||||
longjmp(handler->loc, 1);
|
||||
}
|
||||
savehandler = handler;
|
||||
handler = &jmploc;
|
||||
if (++active > MAXHISTLOOPS) {
|
||||
active = 0;
|
||||
|
@ -298,6 +326,13 @@ histcmd(int argc, char **argv)
|
|||
*repl++ = '\0';
|
||||
argc--, argv++;
|
||||
}
|
||||
|
||||
/*
|
||||
* If -s is specified, accept only one operand
|
||||
*/
|
||||
if (sflg && argc >= 2)
|
||||
error("too many args");
|
||||
|
||||
/*
|
||||
* determine [first] and [last]
|
||||
*/
|
||||
|
@ -316,6 +351,7 @@ histcmd(int argc, char **argv)
|
|||
break;
|
||||
default:
|
||||
error("too many args");
|
||||
/* NOTREACHED */
|
||||
}
|
||||
/*
|
||||
* Turn into event numbers.
|
||||
|
@ -341,7 +377,7 @@ histcmd(int argc, char **argv)
|
|||
if (editor) {
|
||||
int fd;
|
||||
INTOFF; /* easier */
|
||||
sprintf(editfile, "%s/_shXXXXXX", _PATH_TMP);
|
||||
snprintf(editfile, sizeof(editfile), "%s_shXXXXXX", _PATH_TMP);
|
||||
if ((fd = mkstemp(editfile)) < 0)
|
||||
error("can't create temporary file %s", editfile);
|
||||
if ((efp = fdopen(fd, "w")) == NULL) {
|
||||
|
@ -366,34 +402,29 @@ histcmd(int argc, char **argv)
|
|||
out1fmt("%5d ", he.num);
|
||||
out1str(he.str);
|
||||
} else {
|
||||
char *s = pat ?
|
||||
fc_replace(he.str, pat, repl) : (char *)he.str;
|
||||
const char *s = pat ?
|
||||
fc_replace(he.str, pat, repl) : he.str;
|
||||
|
||||
if (sflg) {
|
||||
if (displayhist) {
|
||||
out2str(s);
|
||||
}
|
||||
evalstring(s);
|
||||
|
||||
evalstring(strcpy(stalloc(strlen(s) + 1), s), 0);
|
||||
if (displayhist && hist) {
|
||||
/*
|
||||
* XXX what about recursive and
|
||||
* relative histnums.
|
||||
*/
|
||||
oldhistnum = he.num;
|
||||
history(hist, &he, H_ENTER, s);
|
||||
/*
|
||||
* XXX H_ENTER moves the internal
|
||||
* cursor, set it back to the current
|
||||
* entry.
|
||||
*/
|
||||
retval = history(hist, &he,
|
||||
H_NEXT_EVENT, oldhistnum);
|
||||
}
|
||||
|
||||
break;
|
||||
} else
|
||||
fputs(s, efp);
|
||||
}
|
||||
/*
|
||||
* At end? (if we were to loose last, we'd sure be
|
||||
* At end? (if we were to lose last, we'd sure be
|
||||
* messed up).
|
||||
*/
|
||||
if (he.num == last)
|
||||
|
@ -405,7 +436,7 @@ histcmd(int argc, char **argv)
|
|||
fclose(efp);
|
||||
editcmd = stalloc(strlen(editor) + strlen(editfile) + 2);
|
||||
sprintf(editcmd, "%s %s", editor, editfile);
|
||||
evalstring(editcmd); /* XXX - should use no JC command */
|
||||
evalstring(editcmd, 0); /* XXX - should use no JC command */
|
||||
INTON;
|
||||
readcmdfile(editfile); /* XXX - should read back - quick tst */
|
||||
unlink(editfile);
|
||||
|
@ -418,7 +449,7 @@ histcmd(int argc, char **argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
STATIC char *
|
||||
STATIC const char *
|
||||
fc_replace(const char *s, char *p, char *r)
|
||||
{
|
||||
char *dest;
|
||||
|
@ -440,21 +471,21 @@ fc_replace(const char *s, char *p, char *r)
|
|||
return (dest);
|
||||
}
|
||||
|
||||
STATIC int
|
||||
int
|
||||
not_fcnumber(char *s)
|
||||
{
|
||||
if (s == NULL)
|
||||
return (0);
|
||||
return 0;
|
||||
if (*s == '-')
|
||||
s++;
|
||||
return (!is_number(s));
|
||||
}
|
||||
|
||||
STATIC int
|
||||
str_to_event(char *str, int last)
|
||||
int
|
||||
str_to_event(const char *str, int last)
|
||||
{
|
||||
HistEvent he;
|
||||
char *s = str;
|
||||
const char *s = str;
|
||||
int relative = 0;
|
||||
int i, retval;
|
||||
|
||||
|
@ -481,7 +512,8 @@ str_to_event(char *str, int last)
|
|||
* the notion of first and last is
|
||||
* backwards to that of the history package
|
||||
*/
|
||||
retval = history(hist, &he, last ? H_FIRST : H_LAST);
|
||||
retval = history(hist, &he,
|
||||
last ? H_FIRST : H_LAST);
|
||||
}
|
||||
}
|
||||
if (retval == -1)
|
||||
|
@ -497,37 +529,17 @@ str_to_event(char *str, int last)
|
|||
}
|
||||
return (he.num);
|
||||
}
|
||||
|
||||
int
|
||||
bindcmd(int argc, char **argv)
|
||||
{
|
||||
|
||||
if (el == NULL)
|
||||
error("line editing is disabled");
|
||||
return (el_parse(el, argc, argv));
|
||||
}
|
||||
|
||||
#else
|
||||
#include "error.h"
|
||||
|
||||
int
|
||||
histcmd(int argc, char **argv)
|
||||
{
|
||||
|
||||
error("not compiled with history support");
|
||||
/* NOTREACHED */
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
bindcmd(int argc, char **argv)
|
||||
inputrc(int argc, char **argv)
|
||||
{
|
||||
|
||||
error("not compiled with line editing support");
|
||||
return (0);
|
||||
error("not compiled with history support");
|
||||
/* NOTREACHED */
|
||||
}
|
||||
#endif /* !NO_HISTORY */
|
||||
|
||||
/*
|
||||
* $PchId: histedit.c,v 1.6 2006/04/10 14:52:58 philip Exp $
|
||||
*/
|
||||
#endif
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: init.h,v 1.10 2003/08/07 09:05:32 agc Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -30,13 +32,8 @@
|
|||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)init.h 8.2 (Berkeley) 5/4/95
|
||||
* $FreeBSD: src/bin/sh/init.h,v 1.8 2004/04/06 20:06:51 markm Exp $
|
||||
*/
|
||||
|
||||
void init(void);
|
||||
void reset(void);
|
||||
void initshellproc(void);
|
||||
|
||||
/*
|
||||
* $PchId: init.h,v 1.3 2006/03/30 14:31:06 philip Exp $
|
||||
*/
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: input.c,v 1.46 2013/10/30 08:38:40 mrg Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -30,24 +32,22 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)input.c 8.3 (Berkeley) 6/9/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: input.c,v 1.46 2013/10/30 08:38:40 mrg Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
#include <sys/cdefs.h>
|
||||
/*
|
||||
__FBSDID("$FreeBSD: src/bin/sh/input.c,v 1.22 2004/04/06 20:06:51 markm Exp $");
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h> /* defines BUFSIZ */
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
/*
|
||||
* This file implements the input routines used by the parser.
|
||||
|
@ -64,10 +64,6 @@ __FBSDID("$FreeBSD: src/bin/sh/input.c,v 1.22 2004/04/06 20:06:51 markm Exp $");
|
|||
#include "alias.h"
|
||||
#include "parser.h"
|
||||
#include "myhistedit.h"
|
||||
#include "redir.h"
|
||||
#include "trap.h"
|
||||
|
||||
static void popstring(void);
|
||||
|
||||
#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
|
||||
|
||||
|
@ -91,7 +87,7 @@ struct parsefile {
|
|||
int linno; /* current line */
|
||||
int fd; /* file descriptor (or -1 if string) */
|
||||
int nleft; /* number of chars left in this line */
|
||||
int lleft; /* number of lines left in this buffer */
|
||||
int lleft; /* number of chars left in this buffer */
|
||||
char *nextc; /* next char in buffer */
|
||||
char *buf; /* input buffer */
|
||||
struct strpush *strpush; /* for pushing strings at this level */
|
||||
|
@ -100,27 +96,24 @@ struct parsefile {
|
|||
|
||||
|
||||
int plinno = 1; /* input line number */
|
||||
MKINIT int parsenleft; /* copy of parsefile->nleft */
|
||||
int parsenleft; /* copy of parsefile->nleft */
|
||||
MKINIT int parselleft; /* copy of parsefile->lleft */
|
||||
char *parsenextc; /* copy of parsefile->nextc */
|
||||
MKINIT struct parsefile basepf; /* top level input file */
|
||||
char basebuf[BUFSIZ]; /* buffer for top level input file */
|
||||
STATIC struct parsefile *parsefile = &basepf; /* current input file */
|
||||
MKINIT char basebuf[BUFSIZ]; /* buffer for top level input file */
|
||||
struct parsefile *parsefile = &basepf; /* current input file */
|
||||
int init_editline = 0; /* editline library initialized? */
|
||||
int whichprompt; /* -1 == PSE, 1 == PS1, 2 == PS2 */
|
||||
|
||||
EditLine *el; /* cookie for editline package */
|
||||
int whichprompt; /* 1 == PS1, 2 == PS2 */
|
||||
|
||||
STATIC void pushfile(void);
|
||||
static int preadfd(void);
|
||||
|
||||
#ifdef mkinit
|
||||
INCLUDE <stdio.h>
|
||||
INCLUDE "input.h"
|
||||
INCLUDE "error.h"
|
||||
|
||||
INIT {
|
||||
extern char basebuf[];
|
||||
|
||||
basepf.nextc = basepf.buf = basebuf;
|
||||
}
|
||||
|
||||
|
@ -180,35 +173,40 @@ static int
|
|||
preadfd(void)
|
||||
{
|
||||
int nr;
|
||||
parsenextc = parsefile->buf;
|
||||
char *buf = parsefile->buf;
|
||||
parsenextc = buf;
|
||||
|
||||
#if !defined(NO_HISTORY)
|
||||
if (el != NULL && gotwinch) {
|
||||
gotwinch = 0;
|
||||
el_resize(el);
|
||||
}
|
||||
#endif
|
||||
retry:
|
||||
#ifndef NO_HISTORY
|
||||
#ifndef SMALL
|
||||
if (parsefile->fd == 0 && el) {
|
||||
const char *rl_cp;
|
||||
static const char *rl_cp;
|
||||
static int el_len;
|
||||
|
||||
rl_cp = el_gets(el, &nr);
|
||||
if (rl_cp == NULL)
|
||||
nr = 0;
|
||||
rl_cp = el_gets(el, &el_len);
|
||||
if (rl_cp == NULL)
|
||||
nr = el_len == 0 ? 0 : -1;
|
||||
else {
|
||||
/* XXX - BUFSIZE should redesign so not necessary */
|
||||
(void) strcpy(parsenextc, rl_cp);
|
||||
nr = el_len;
|
||||
if (nr > BUFSIZ - 8)
|
||||
nr = BUFSIZ - 8;
|
||||
memcpy(buf, rl_cp, nr);
|
||||
if (nr != el_len) {
|
||||
el_len -= nr;
|
||||
rl_cp += nr;
|
||||
} else
|
||||
rl_cp = 0;
|
||||
}
|
||||
|
||||
} else
|
||||
#endif
|
||||
nr = read(parsefile->fd, parsenextc, BUFSIZ - 1);
|
||||
nr = read(parsefile->fd, buf, BUFSIZ - 8);
|
||||
|
||||
|
||||
if (nr <= 0) {
|
||||
if (nr < 0) {
|
||||
if (errno == EINTR)
|
||||
goto retry;
|
||||
#ifdef EWOULDBLOCK
|
||||
if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
|
||||
int flags = fcntl(0, F_GETFL, 0);
|
||||
if (flags >= 0 && flags & O_NONBLOCK) {
|
||||
|
@ -219,7 +217,6 @@ retry:
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif /* EWOULDBLOCK */
|
||||
}
|
||||
nr = -1;
|
||||
}
|
||||
|
@ -232,7 +229,7 @@ retry:
|
|||
* 1) If a string was pushed back on the input, pop it;
|
||||
* 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
|
||||
* from a string so we can't refill the buffer, return EOF.
|
||||
* 3) If there is more in this buffer, use it else call read to fill it.
|
||||
* 3) If the is more stuff in this buffer, use it else call read to fill it.
|
||||
* 4) Process input up to the next newline, deleting nul characters.
|
||||
*/
|
||||
|
||||
|
@ -241,7 +238,9 @@ preadbuffer(void)
|
|||
{
|
||||
char *p, *q;
|
||||
int more;
|
||||
#ifndef SMALL
|
||||
int something;
|
||||
#endif
|
||||
char savec;
|
||||
|
||||
if (parsefile->strpush) {
|
||||
|
@ -265,7 +264,9 @@ again:
|
|||
q = p = parsenextc;
|
||||
|
||||
/* delete nul characters */
|
||||
#ifndef SMALL
|
||||
something = 0;
|
||||
#endif
|
||||
for (more = 1; more;) {
|
||||
switch (*p) {
|
||||
case '\0':
|
||||
|
@ -282,7 +283,9 @@ again:
|
|||
break;
|
||||
|
||||
default:
|
||||
#ifndef SMALL
|
||||
something = 1;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -300,11 +303,11 @@ check:
|
|||
savec = *q;
|
||||
*q = '\0';
|
||||
|
||||
#if !defined(NO_HISTORY)
|
||||
#ifndef SMALL
|
||||
if (parsefile->fd == 0 && hist && something) {
|
||||
HistEvent he;
|
||||
INTOFF;
|
||||
history(hist, &he, whichprompt == 1 ? H_ENTER : H_ADD,
|
||||
history(hist, &he, whichprompt == 1? H_ENTER : H_APPEND,
|
||||
parsenextc);
|
||||
INTON;
|
||||
}
|
||||
|
@ -342,7 +345,7 @@ pushstring(char *s, int len, void *ap)
|
|||
struct strpush *sp;
|
||||
|
||||
INTOFF;
|
||||
/*dbgprintf("*** calling pushstring: %s, %d\n", s, len);*/
|
||||
/*debugprintf("*** calling pushstring: %s, %d\n", s, len);*/
|
||||
if (parsefile->strpush) {
|
||||
sp = ckmalloc(sizeof (struct strpush));
|
||||
sp->prev = parsefile->strpush;
|
||||
|
@ -360,7 +363,7 @@ pushstring(char *s, int len, void *ap)
|
|||
INTON;
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
popstring(void)
|
||||
{
|
||||
struct strpush *sp = parsefile->strpush;
|
||||
|
@ -369,7 +372,7 @@ popstring(void)
|
|||
parsenextc = sp->prevstring;
|
||||
parsenleft = sp->prevnleft;
|
||||
parselleft = sp->prevlleft;
|
||||
/*dbgprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
|
||||
/*debugprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
|
||||
if (sp->ap)
|
||||
sp->ap->flag &= ~ALIASINUSE;
|
||||
parsefile->strpush = sp->prev;
|
||||
|
@ -384,27 +387,32 @@ popstring(void)
|
|||
*/
|
||||
|
||||
void
|
||||
setinputfile(char *fname, int push)
|
||||
setinputfile(const char *fname, int push)
|
||||
{
|
||||
unsigned char magic[4];
|
||||
int fd;
|
||||
int fd2;
|
||||
struct stat statbuf;
|
||||
int saved_errno;
|
||||
|
||||
INTOFF;
|
||||
if ((fd = open(fname, O_RDONLY)) < 0)
|
||||
error("Can't open %s: %s", fname, strerror(errno));
|
||||
if (fstat(fd, &statbuf) < 0) {
|
||||
saved_errno = errno;
|
||||
close(fd);
|
||||
error("Can't stat %s: %s", fname, strerror(saved_errno));
|
||||
error("Can't open %s", fname);
|
||||
|
||||
/* Since the message "Syntax error: "(" unexpected" is not very
|
||||
* helpful, we check if the file starts with the ELF magic to
|
||||
* avoid that message. The first lseek tries to make sure that
|
||||
* we can later rewind the file.
|
||||
*/
|
||||
if (lseek(fd, 0, SEEK_SET) == 0) {
|
||||
if (read(fd, magic, 4) == 4) {
|
||||
if (memcmp(magic, "\177ELF", 4) == 0)
|
||||
error("Cannot execute ELF binary %s", fname);
|
||||
}
|
||||
if (!S_ISREG(statbuf.st_mode)) {
|
||||
close(fd);
|
||||
error("Can't open %s: %s", fname, strerror(ENOEXEC));
|
||||
if (lseek(fd, 0, SEEK_SET) != 0)
|
||||
error("Cannot rewind the file %s", fname);
|
||||
}
|
||||
|
||||
if (fd < 10) {
|
||||
fd2 = fcntl(fd, F_DUPFD, 10);
|
||||
fd2 = copyfd(fd, 10, 0);
|
||||
close(fd);
|
||||
if (fd2 < 0)
|
||||
error("Out of file descriptors");
|
||||
|
@ -518,18 +526,25 @@ popallfiles(void)
|
|||
/*
|
||||
* Close the file(s) that the shell is reading commands from. Called
|
||||
* after a fork is done.
|
||||
*
|
||||
* Takes one arg, vfork, which tells it to not modify its global vars
|
||||
* as it is still running in the parent.
|
||||
*
|
||||
* This code is (probably) unnecessary as the 'close on exec' flag is
|
||||
* set and should be enough. In the vfork case it is definitely wrong
|
||||
* to close the fds as another fork() may be done later to feed data
|
||||
* from a 'here' document into a pipe and we don't want to close the
|
||||
* pipe!
|
||||
*/
|
||||
|
||||
void
|
||||
closescript(void)
|
||||
closescript(int vforked)
|
||||
{
|
||||
if (vforked)
|
||||
return;
|
||||
popallfiles();
|
||||
if (parsefile->fd > 0) {
|
||||
close(parsefile->fd);
|
||||
parsefile->fd = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* $PchId: input.c,v 1.7 2006/05/29 13:09:38 philip Exp $
|
||||
*/
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: input.h,v 1.15 2003/08/07 09:05:33 agc Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -30,7 +32,6 @@
|
|||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)input.h 8.2 (Berkeley) 5/4/95
|
||||
* $FreeBSD: src/bin/sh/input.h,v 1.9 2004/04/06 20:06:51 markm Exp $
|
||||
*/
|
||||
|
||||
/* PEOF (the end of file marker) is defined in syntax.h */
|
||||
|
@ -50,15 +51,12 @@ int pgetc(void);
|
|||
int preadbuffer(void);
|
||||
void pungetc(void);
|
||||
void pushstring(char *, int, void *);
|
||||
void setinputfile(char *, int);
|
||||
void popstring(void);
|
||||
void setinputfile(const char *, int);
|
||||
void setinputfd(int, int);
|
||||
void setinputstring(char *, int);
|
||||
void popfile(void);
|
||||
void popallfiles(void);
|
||||
void closescript(void);
|
||||
void closescript(int);
|
||||
|
||||
#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
|
||||
|
||||
/*
|
||||
* $PchId: input.h,v 1.3 2006/03/30 13:49:37 philip Exp $
|
||||
*/
|
1527
bin/sh/jobs.c
Normal file
1527
bin/sh/jobs.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: jobs.h,v 1.20 2011/06/18 21:18:46 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -30,15 +32,24 @@
|
|||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)jobs.h 8.2 (Berkeley) 5/4/95
|
||||
* $FreeBSD: src/bin/sh/jobs.h,v 1.18 2004/04/06 20:06:51 markm Exp $
|
||||
*/
|
||||
|
||||
#include "output.h"
|
||||
|
||||
/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
|
||||
#define FORK_FG 0
|
||||
#define FORK_BG 1
|
||||
#define FORK_NOJOB 2
|
||||
|
||||
#include <signal.h> /* for sig_atomic_t */
|
||||
/* mode flags for showjob(s) */
|
||||
#define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
|
||||
#define SHOW_MULTILINE 0x02 /* one line per process */
|
||||
#define SHOW_PID 0x04 /* include process pid */
|
||||
#define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
|
||||
#define SHOW_SIGNALLED 0x10 /* only if stopped/exited on signal */
|
||||
#define SHOW_ISSIG 0x20 /* job was signalled */
|
||||
#define SHOW_NO_FREE 0x40 /* do not free job */
|
||||
|
||||
|
||||
/*
|
||||
* A job structure contains information about a job. A job is either a
|
||||
|
@ -46,57 +57,45 @@
|
|||
* latter case, pidlist will be non-NULL, and will point to a -1 terminated
|
||||
* array of pids.
|
||||
*/
|
||||
#define MAXCMDTEXT 200
|
||||
|
||||
struct procstat {
|
||||
pid_t pid; /* process id */
|
||||
int status; /* status flags (defined above) */
|
||||
char *cmd; /* text of command being run */
|
||||
int status; /* last process status from wait() */
|
||||
char cmd[MAXCMDTEXT];/* text of command being run */
|
||||
};
|
||||
|
||||
|
||||
/* states */
|
||||
#define JOBSTOPPED 1 /* all procs are stopped */
|
||||
#define JOBDONE 2 /* all procs are completed */
|
||||
|
||||
|
||||
struct job {
|
||||
struct procstat ps0; /* status of process */
|
||||
struct procstat *ps; /* status or processes when more than one */
|
||||
short nprocs; /* number of processes */
|
||||
int nprocs; /* number of processes */
|
||||
pid_t pgrp; /* process group of this job */
|
||||
char state; /* true if job is finished */
|
||||
char state;
|
||||
#define JOBRUNNING 0 /* at least one proc running */
|
||||
#define JOBSTOPPED 1 /* all procs are stopped */
|
||||
#define JOBDONE 2 /* all procs are completed */
|
||||
char used; /* true if this entry is in used */
|
||||
char changed; /* true if status has changed */
|
||||
char foreground; /* true if running in the foreground */
|
||||
#if JOBS
|
||||
char jobctl; /* job running under job control */
|
||||
struct job *next; /* job used after this one */
|
||||
int prev_job; /* previous job index */
|
||||
#endif
|
||||
};
|
||||
|
||||
extern pid_t backgndpid; /* pid of last background process */
|
||||
extern int job_warning; /* user was warned about stopped jobs */
|
||||
extern int in_waitcmd; /* are we in waitcmd()? */
|
||||
extern int in_dowait; /* are we in dowait()? */
|
||||
extern volatile sig_atomic_t breakwaitcmd; /* break wait to process traps? */
|
||||
|
||||
void setjobctl(int);
|
||||
int fgcmd(int, char **);
|
||||
int bgcmd(int, char **);
|
||||
int jobscmd(int, char **);
|
||||
void showjobs(int, int, int);
|
||||
int waitcmd(int, char **);
|
||||
int jobidcmd(int, char **);
|
||||
void showjobs(struct output *, int);
|
||||
struct job *makejob(union node *, int);
|
||||
pid_t forkshell(struct job *, union node *, int);
|
||||
int waitforjob(struct job *, int *);
|
||||
int forkshell(struct job *, union node *, int);
|
||||
void forkchild(struct job *, union node *, int, int);
|
||||
int forkparent(struct job *, union node *, int, pid_t);
|
||||
int waitforjob(struct job *);
|
||||
int stoppedjobs(void);
|
||||
char *commandtext(union node *);
|
||||
void commandtext(struct procstat *, union node *);
|
||||
int getjobpgrp(const char *);
|
||||
|
||||
#if ! JOBS
|
||||
#define setjobctl(on) /* do nothing */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* $PchId: jobs.h,v 1.4 2006/03/30 12:07:24 philip Exp $
|
||||
*/
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: machdep.h,v 1.11 2003/08/07 09:05:33 agc Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,11 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -41,15 +39,9 @@
|
|||
* in some way. The following macro will get this right on many machines.
|
||||
*/
|
||||
|
||||
#ifndef ALIGN
|
||||
union align {
|
||||
int i;
|
||||
char *cp;
|
||||
};
|
||||
|
||||
#define ALIGN(nbytes) (((nbytes) + sizeof(union align) - 1) & ~(sizeof(union align) - 1))
|
||||
#endif
|
||||
|
||||
#define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1)
|
||||
/*
|
||||
* $PchId: machdep.h,v 1.2 2001/05/15 16:36:26 philip Exp $
|
||||
* It appears that grabstackstr() will barf with such alignments
|
||||
* because stalloc() will return a string allocated in a new stackblock.
|
||||
*/
|
||||
#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: mail.c,v 1.16 2003/08/07 09:05:33 agc Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -30,19 +32,21 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)mail.c 8.2 (Berkeley) 5/4/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: mail.c,v 1.16 2003/08/07 09:05:33 agc Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
/*
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/bin/sh/mail.c,v 1.13 2004/04/06 20:06:51 markm Exp $");
|
||||
*/
|
||||
|
||||
/*
|
||||
* Routines to check for mail. (Perhaps make part of main.c?)
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "shell.h"
|
||||
#include "exec.h" /* defines padvance() */
|
||||
|
@ -51,9 +55,6 @@ __FBSDID("$FreeBSD: src/bin/sh/mail.c,v 1.13 2004/04/06 20:06:51 markm Exp $");
|
|||
#include "memalloc.h"
|
||||
#include "error.h"
|
||||
#include "mail.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
#define MAXMBOXES 10
|
||||
|
@ -74,7 +75,7 @@ void
|
|||
chkmail(int silent)
|
||||
{
|
||||
int i;
|
||||
char *mpath;
|
||||
const char *mpath;
|
||||
char *p;
|
||||
char *q;
|
||||
struct stackmark smark;
|
||||
|
@ -117,7 +118,3 @@ chkmail(int silent)
|
|||
nmboxes = i;
|
||||
popstackmark(&smark);
|
||||
}
|
||||
|
||||
/*
|
||||
* $PchId: mail.c,v 1.5 2006/05/22 12:02:37 philip Exp $
|
||||
*/
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: mail.h,v 1.10 2003/08/07 09:05:34 agc Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -30,11 +32,6 @@
|
|||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)mail.h 8.2 (Berkeley) 5/4/95
|
||||
* $FreeBSD: src/bin/sh/mail.h,v 1.8 2004/04/06 20:06:51 markm Exp $
|
||||
*/
|
||||
|
||||
void chkmail(int);
|
||||
|
||||
/*
|
||||
* $PchId: mail.h,v 1.3 2006/03/30 11:53:44 philip Exp $
|
||||
*/
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: main.c,v 1.57 2011/06/18 21:18:46 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -30,34 +32,35 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
static char const copyright[] =
|
||||
"@(#) Copyright (c) 1991, 1993\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
__COPYRIGHT("@(#) Copyright (c) 1991, 1993\
|
||||
The Regents of the University of California. All rights reserved.");
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)main.c 8.6 (Berkeley) 5/28/95";
|
||||
static char sccsid[] = "@(#)main.c 8.7 (Berkeley) 7/19/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: main.c,v 1.57 2011/06/18 21:18:46 christos Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
/*
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/bin/sh/main.c,v 1.26 2004/04/06 20:06:51 markm Exp $");
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <locale.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
|
||||
#include "shell.h"
|
||||
#include "main.h"
|
||||
#include "mail.h"
|
||||
#include "options.h"
|
||||
#include "builtins.h"
|
||||
#include "output.h"
|
||||
#include "parser.h"
|
||||
#include "nodes.h"
|
||||
|
@ -74,13 +77,20 @@ __FBSDID("$FreeBSD: src/bin/sh/main.c,v 1.26 2004/04/06 20:06:51 markm Exp $");
|
|||
#include "mystring.h"
|
||||
#include "exec.h"
|
||||
#include "cd.h"
|
||||
#include "builtins.h"
|
||||
|
||||
#define PROFILE 0
|
||||
|
||||
int rootpid;
|
||||
int rootshell;
|
||||
int posix;
|
||||
#if PROFILE
|
||||
short profile_buf[16384];
|
||||
extern int etext();
|
||||
#endif
|
||||
|
||||
STATIC void read_profile(char *);
|
||||
STATIC void read_profile(const char *);
|
||||
STATIC char *find_dot_file(char *);
|
||||
int main(int, char **);
|
||||
|
||||
/*
|
||||
* Main routine. We initialize things, parse the arguments, execute
|
||||
|
@ -91,14 +101,19 @@ STATIC char *find_dot_file(char *);
|
|||
*/
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct jmploc jmploc;
|
||||
struct stackmark smark;
|
||||
volatile int state;
|
||||
char *shinit;
|
||||
|
||||
(void) setlocale(LC_ALL, "");
|
||||
setlocale(LC_ALL, "");
|
||||
|
||||
posix = getenv("POSIXLY_CORRECT") != NULL;
|
||||
#if PROFILE
|
||||
monitor(4, etext, profile_buf, sizeof profile_buf, 50);
|
||||
#endif
|
||||
state = 0;
|
||||
if (setjmp(jmploc.loc)) {
|
||||
/*
|
||||
|
@ -131,7 +146,11 @@ main(int argc, char *argv[])
|
|||
exitshell(exitstatus);
|
||||
}
|
||||
reset();
|
||||
if (exception == EXINT) {
|
||||
if (exception == EXINT
|
||||
#if ATTY
|
||||
&& (! attyset() || equal(termval(), "emacs"))
|
||||
#endif
|
||||
) {
|
||||
out2c('\n');
|
||||
flushout(&errout);
|
||||
}
|
||||
|
@ -147,30 +166,30 @@ main(int argc, char *argv[])
|
|||
goto state4;
|
||||
}
|
||||
handler = &jmploc;
|
||||
#if DEBUG
|
||||
#ifdef DEBUG
|
||||
#if DEBUG == 2
|
||||
debug = 1;
|
||||
#endif
|
||||
opentrace();
|
||||
trputs("Shell args: "); trargs(argv);
|
||||
#endif
|
||||
rootpid = getpid();
|
||||
rootshell = 1;
|
||||
init();
|
||||
initpwd();
|
||||
setstackmark(&smark);
|
||||
procargs(argc, argv);
|
||||
if (getpwd() == NULL && iflag)
|
||||
out2str("sh: cannot determine working directory\n");
|
||||
if (argv[0] && argv[0][0] == '-') {
|
||||
state = 1;
|
||||
read_profile("/etc/profile");
|
||||
state1:
|
||||
state = 2;
|
||||
if (privileged == 0)
|
||||
read_profile(".profile");
|
||||
else
|
||||
read_profile("/etc/suid_profile");
|
||||
}
|
||||
state2:
|
||||
state = 3;
|
||||
if (!privileged && iflag) {
|
||||
if ((iflag || !posix) &&
|
||||
getuid() == geteuid() && getgid() == getegid()) {
|
||||
if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
|
||||
state = 3;
|
||||
read_profile(shinit);
|
||||
|
@ -178,16 +197,33 @@ state2:
|
|||
}
|
||||
state3:
|
||||
state = 4;
|
||||
if (minusc) {
|
||||
evalstring(minusc);
|
||||
if (sflag == 0 || minusc) {
|
||||
static int sigs[] = {
|
||||
SIGINT, SIGQUIT, SIGHUP,
|
||||
#ifdef SIGTSTP
|
||||
SIGTSTP,
|
||||
#endif
|
||||
SIGPIPE
|
||||
};
|
||||
#define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0]))
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < SIGSSIZE; i++)
|
||||
setsignal(sigs[i], 0);
|
||||
}
|
||||
|
||||
if (minusc)
|
||||
evalstring(minusc, 0);
|
||||
|
||||
if (sflag || minusc == NULL) {
|
||||
state4: /* XXX ??? - why isn't this before the "if" statement */
|
||||
cmdloop(1);
|
||||
}
|
||||
#if PROFILE
|
||||
monitor(0);
|
||||
#endif
|
||||
exitshell(exitstatus);
|
||||
/* NOTREACHED */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -210,11 +246,11 @@ cmdloop(int top)
|
|||
if (pendingsigs)
|
||||
dotrap();
|
||||
inter = 0;
|
||||
if (iflag && top) {
|
||||
inter++;
|
||||
showjobs(1, 0, 0);
|
||||
if (iflag == 1 && top) {
|
||||
inter = 1;
|
||||
showjobs(out2, SHOW_CHANGED);
|
||||
chkmail(0);
|
||||
flushout(&output);
|
||||
flushout(&errout);
|
||||
}
|
||||
n = parsecmd(inter);
|
||||
/* showtree(n); DEBUG */
|
||||
|
@ -249,9 +285,11 @@ cmdloop(int top)
|
|||
*/
|
||||
|
||||
STATIC void
|
||||
read_profile(char *name)
|
||||
read_profile(const char *name)
|
||||
{
|
||||
int fd;
|
||||
int xflag_set = 0;
|
||||
int vflag_set = 0;
|
||||
|
||||
INTOFF;
|
||||
if ((fd = open(name, O_RDONLY)) >= 0)
|
||||
|
@ -259,7 +297,20 @@ read_profile(char *name)
|
|||
INTON;
|
||||
if (fd < 0)
|
||||
return;
|
||||
/* -q turns off -x and -v just when executing init files */
|
||||
if (qflag) {
|
||||
if (xflag)
|
||||
xflag = 0, xflag_set = 1;
|
||||
if (vflag)
|
||||
vflag = 0, vflag_set = 1;
|
||||
}
|
||||
cmdloop(0);
|
||||
if (qflag) {
|
||||
if (xflag_set)
|
||||
xflag = 1;
|
||||
if (vflag_set)
|
||||
vflag = 1;
|
||||
}
|
||||
popfile();
|
||||
}
|
||||
|
||||
|
@ -278,7 +329,7 @@ readcmdfile(char *name)
|
|||
if ((fd = open(name, O_RDONLY)) >= 0)
|
||||
setinputfd(fd, 1);
|
||||
else
|
||||
error("Can't open %s: %s", name, strerror(errno));
|
||||
error("Can't open %s", name);
|
||||
INTON;
|
||||
cmdloop(0);
|
||||
popfile();
|
||||
|
@ -295,9 +346,8 @@ readcmdfile(char *name)
|
|||
STATIC char *
|
||||
find_dot_file(char *basename)
|
||||
{
|
||||
static char localname[FILENAME_MAX+1];
|
||||
char *fullname;
|
||||
char *path = pathval();
|
||||
const char *path = pathval();
|
||||
struct stat statb;
|
||||
|
||||
/* don't try this for absolute or relative paths */
|
||||
|
@ -305,30 +355,37 @@ find_dot_file(char *basename)
|
|||
return basename;
|
||||
|
||||
while ((fullname = padvance(&path, basename)) != NULL) {
|
||||
strcpy(localname, fullname);
|
||||
stunalloc(fullname);
|
||||
if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode))
|
||||
return localname;
|
||||
if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
|
||||
/*
|
||||
* Don't bother freeing here, since it will
|
||||
* be freed by the caller.
|
||||
*/
|
||||
return fullname;
|
||||
}
|
||||
return basename;
|
||||
stunalloc(fullname);
|
||||
}
|
||||
|
||||
/* not found in the PATH */
|
||||
error("%s: not found", basename);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
int
|
||||
dotcmd(int argc, char **argv)
|
||||
{
|
||||
struct strlist *sp;
|
||||
exitstatus = 0;
|
||||
|
||||
for (sp = cmdenviron; sp ; sp = sp->next)
|
||||
setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
|
||||
|
||||
if (argc >= 2) { /* That's what SVR2 does */
|
||||
char *fullname = find_dot_file(argv[1]);
|
||||
char *fullname;
|
||||
struct stackmark smark;
|
||||
|
||||
setstackmark(&smark);
|
||||
fullname = find_dot_file(argv[1]);
|
||||
setinputfile(fullname, 1);
|
||||
commandname = fullname;
|
||||
cmdloop(0);
|
||||
popfile();
|
||||
popstackmark(&smark);
|
||||
}
|
||||
return exitstatus;
|
||||
}
|
||||
|
@ -337,19 +394,10 @@ dotcmd(int argc, char **argv)
|
|||
int
|
||||
exitcmd(int argc, char **argv)
|
||||
{
|
||||
extern int oexitstatus;
|
||||
|
||||
if (stoppedjobs())
|
||||
return 0;
|
||||
if (argc > 1)
|
||||
exitstatus = number(argv[1]);
|
||||
else
|
||||
exitstatus = oexitstatus;
|
||||
exitshell(exitstatus);
|
||||
/* NOTREACHED */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* $PchId: main.c,v 1.5 2006/05/22 12:03:02 philip Exp $
|
||||
*/
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: main.h,v 1.11 2011/06/18 21:18:46 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -30,7 +32,6 @@
|
|||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)main.h 8.2 (Berkeley) 5/4/95
|
||||
* $FreeBSD: src/bin/sh/main.h,v 1.8 2004/04/06 20:06:51 markm Exp $
|
||||
*/
|
||||
|
||||
extern int rootpid; /* pid of main shell */
|
||||
|
@ -38,9 +39,3 @@ extern int rootshell; /* true if we aren't a child of the main shell */
|
|||
|
||||
void readcmdfile(char *);
|
||||
void cmdloop(int);
|
||||
int dotcmd(int, char **);
|
||||
int exitcmd(int, char **);
|
||||
|
||||
/*
|
||||
* $PchId: main.h,v 1.3 2006/03/30 11:43:59 philip Exp $
|
||||
*/
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: memalloc.c,v 1.29 2008/02/15 17:26:06 matt Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -30,36 +32,36 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)memalloc.c 8.3 (Berkeley) 5/4/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: memalloc.c,v 1.29 2008/02/15 17:26:06 matt Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
/*
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/bin/sh/memalloc.c,v 1.26 2004/04/06 20:06:51 markm Exp $");
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "shell.h"
|
||||
#include "output.h"
|
||||
#include "machdep.h"
|
||||
#include "memalloc.h"
|
||||
#include "error.h"
|
||||
#include "machdep.h"
|
||||
#include "mystring.h"
|
||||
#include "expand.h"
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/*
|
||||
* Like malloc, but returns an error when out of space.
|
||||
*/
|
||||
|
||||
pointer
|
||||
ckmalloc(int nbytes)
|
||||
ckmalloc(size_t nbytes)
|
||||
{
|
||||
pointer p;
|
||||
|
||||
if ((p = malloc(nbytes)) == NULL)
|
||||
p = malloc(nbytes);
|
||||
if (p == NULL)
|
||||
error("Out of space");
|
||||
return p;
|
||||
}
|
||||
|
@ -72,7 +74,8 @@ ckmalloc(int nbytes)
|
|||
pointer
|
||||
ckrealloc(pointer p, int nbytes)
|
||||
{
|
||||
if ((p = realloc(p, nbytes)) == NULL)
|
||||
p = realloc(p, nbytes);
|
||||
if (p == NULL)
|
||||
error("Out of space");
|
||||
return p;
|
||||
}
|
||||
|
@ -98,56 +101,46 @@ savestr(const char *s)
|
|||
* to make this more efficient, and also to avoid all sorts of exception
|
||||
* handling code to handle interrupts in the middle of a parse.
|
||||
*
|
||||
* The size 496 was chosen because with 16-byte alignment the total size
|
||||
* for the allocated block is 512.
|
||||
* The size 504 was chosen because the Ultrix malloc handles that size
|
||||
* well.
|
||||
*/
|
||||
|
||||
#define MINSIZE 496 /* minimum size of a block. */
|
||||
|
||||
#define MINSIZE 504 /* minimum size of a block */
|
||||
|
||||
struct stack_block {
|
||||
struct stack_block *prev;
|
||||
/* Data follows */
|
||||
char space[MINSIZE];
|
||||
};
|
||||
#define SPACE(sp) ((char*)(sp) + ALIGN(sizeof(struct stack_block)))
|
||||
|
||||
STATIC struct stack_block *stackp;
|
||||
STATIC struct stackmark *markp;
|
||||
char *stacknxt;
|
||||
int stacknleft;
|
||||
struct stack_block stackbase;
|
||||
struct stack_block *stackp = &stackbase;
|
||||
struct stackmark *markp;
|
||||
char *stacknxt = stackbase.space;
|
||||
int stacknleft = MINSIZE;
|
||||
int sstrnleft;
|
||||
int herefd = -1;
|
||||
|
||||
|
||||
static void
|
||||
stnewblock(int nbytes)
|
||||
{
|
||||
struct stack_block *sp;
|
||||
int allocsize;
|
||||
|
||||
if (nbytes < MINSIZE)
|
||||
nbytes = MINSIZE;
|
||||
|
||||
allocsize = ALIGN(sizeof(struct stack_block)) + ALIGN(nbytes);
|
||||
|
||||
INTOFF;
|
||||
sp = ckmalloc(allocsize);
|
||||
sp->prev = stackp;
|
||||
stacknxt = SPACE(sp);
|
||||
stacknleft = allocsize - (stacknxt - (char*)sp);
|
||||
stackp = sp;
|
||||
INTON;
|
||||
}
|
||||
|
||||
|
||||
pointer
|
||||
stalloc(int nbytes)
|
||||
{
|
||||
char *p;
|
||||
|
||||
nbytes = ALIGN(nbytes);
|
||||
if (nbytes > stacknleft)
|
||||
stnewblock(nbytes);
|
||||
nbytes = SHELL_ALIGN(nbytes);
|
||||
if (nbytes > stacknleft) {
|
||||
int blocksize;
|
||||
struct stack_block *sp;
|
||||
|
||||
blocksize = nbytes;
|
||||
if (blocksize < MINSIZE)
|
||||
blocksize = MINSIZE;
|
||||
INTOFF;
|
||||
sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
|
||||
sp->prev = stackp;
|
||||
stacknxt = sp->space;
|
||||
stacknleft = blocksize;
|
||||
stackp = sp;
|
||||
INTON;
|
||||
}
|
||||
p = stacknxt;
|
||||
stacknxt += nbytes;
|
||||
stacknleft -= nbytes;
|
||||
|
@ -159,7 +152,7 @@ void
|
|||
stunalloc(pointer p)
|
||||
{
|
||||
if (p == NULL) { /*DEBUG */
|
||||
write(STDERR_FILENO, "stunalloc\n", 10);
|
||||
write(2, "stunalloc\n", 10);
|
||||
abort();
|
||||
}
|
||||
stacknleft += stacknxt - (char *)p;
|
||||
|
@ -210,28 +203,23 @@ popstackmark(struct stackmark *mark)
|
|||
void
|
||||
growstackblock(void)
|
||||
{
|
||||
char *p;
|
||||
int newlen;
|
||||
char *oldspace;
|
||||
int oldlen;
|
||||
struct stack_block *sp;
|
||||
int newlen = SHELL_ALIGN(stacknleft * 2 + 100);
|
||||
|
||||
if (stacknxt == stackp->space && stackp != &stackbase) {
|
||||
struct stack_block *oldstackp;
|
||||
struct stackmark *xmark;
|
||||
struct stack_block *sp;
|
||||
|
||||
newlen = (stacknleft == 0) ? MINSIZE : stacknleft * 2 + 100;
|
||||
newlen = ALIGN(newlen);
|
||||
oldspace = stacknxt;
|
||||
oldlen = stacknleft;
|
||||
|
||||
if (stackp != NULL && stacknxt == SPACE(stackp)) {
|
||||
INTOFF;
|
||||
oldstackp = stackp;
|
||||
stackp = oldstackp->prev;
|
||||
sp = ckrealloc((pointer)oldstackp, newlen);
|
||||
sp = stackp;
|
||||
stackp = sp->prev;
|
||||
sp = ckrealloc((pointer)sp,
|
||||
sizeof(struct stack_block) - MINSIZE + newlen);
|
||||
sp->prev = stackp;
|
||||
stackp = sp;
|
||||
stacknxt = SPACE(sp);
|
||||
stacknleft = newlen - (stacknxt - (char*)sp);
|
||||
stacknxt = sp->space;
|
||||
stacknleft = newlen;
|
||||
|
||||
/*
|
||||
* Stack marks pointing to the start of the old block
|
||||
|
@ -246,27 +234,26 @@ growstackblock(void)
|
|||
}
|
||||
INTON;
|
||||
} else {
|
||||
p = stalloc(newlen);
|
||||
if (oldlen != 0)
|
||||
memcpy(p, oldspace, oldlen);
|
||||
stunalloc(p);
|
||||
char *oldspace = stacknxt;
|
||||
int oldlen = stacknleft;
|
||||
char *p = stalloc(newlen);
|
||||
|
||||
(void)memcpy(p, oldspace, oldlen);
|
||||
stacknxt = p; /* free the space */
|
||||
stacknleft += newlen; /* we just allocated */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
grabstackblock(int len)
|
||||
{
|
||||
len = ALIGN(len);
|
||||
len = SHELL_ALIGN(len);
|
||||
stacknxt += len;
|
||||
stacknleft -= len;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* The following routines are somewhat easier to use that the above.
|
||||
* The following routines are somewhat easier to use than the above.
|
||||
* The user declares a variable of type STACKSTR, which may be declared
|
||||
* to be a register. The macro STARTSTACKSTR initializes things. Then
|
||||
* the user uses the macro STPUTC to add characters to the string. In
|
||||
|
@ -283,13 +270,10 @@ grabstackblock(int len)
|
|||
* is space for at least one character.
|
||||
*/
|
||||
|
||||
|
||||
char *
|
||||
growstackstr(void)
|
||||
{
|
||||
int len;
|
||||
|
||||
len = stackblocksize();
|
||||
int len = stackblocksize();
|
||||
if (herefd >= 0 && len >= 1024) {
|
||||
xwrite(herefd, stackblock(), len);
|
||||
sstrnleft = len - 1;
|
||||
|
@ -300,7 +284,6 @@ growstackstr(void)
|
|||
return stackblock() + len;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Called from CHECKSTRSPACE.
|
||||
*/
|
||||
|
@ -308,24 +291,17 @@ growstackstr(void)
|
|||
char *
|
||||
makestrspace(void)
|
||||
{
|
||||
int len;
|
||||
|
||||
len = stackblocksize() - sstrnleft;
|
||||
int len = stackblocksize() - sstrnleft;
|
||||
growstackblock();
|
||||
sstrnleft = stackblocksize() - len;
|
||||
return stackblock() + len;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
ungrabstackstr(char *s, char *p)
|
||||
{
|
||||
stacknleft += stacknxt - s;
|
||||
stacknxt = s;
|
||||
sstrnleft = stacknleft - (p - s);
|
||||
}
|
||||
|
||||
/*
|
||||
* $PchId: memalloc.c,v 1.5 2006/05/22 12:03:26 philip Exp $
|
||||
*/
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: memalloc.h,v 1.15 2008/02/15 17:26:06 matt Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -30,7 +32,6 @@
|
|||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)memalloc.h 8.2 (Berkeley) 5/4/95
|
||||
* $FreeBSD: src/bin/sh/memalloc.h,v 1.9 2004/04/06 20:06:51 markm Exp $
|
||||
*/
|
||||
|
||||
struct stackmark {
|
||||
|
@ -46,7 +47,7 @@ extern int stacknleft;
|
|||
extern int sstrnleft;
|
||||
extern int herefd;
|
||||
|
||||
pointer ckmalloc(int);
|
||||
pointer ckmalloc(size_t);
|
||||
pointer ckrealloc(pointer, int);
|
||||
char *savestr(const char *);
|
||||
pointer stalloc(int);
|
||||
|
@ -74,7 +75,3 @@ void ungrabstackstr(char *, char *);
|
|||
#define grabstackstr(p) stalloc(stackblocksize() - sstrnleft)
|
||||
|
||||
#define ckfree(p) free((pointer)(p))
|
||||
|
||||
/*
|
||||
* $PchId: memalloc.h,v 1.3 2006/03/30 11:39:41 philip Exp $
|
||||
*/
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: miscbltin.c,v 1.42 2012/06/11 18:28:10 njoly Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -30,32 +32,28 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)miscbltin.c 8.4 (Berkeley) 5/4/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: miscbltin.c,v 1.42 2012/06/11 18:28:10 njoly Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
#include <sys/cdefs.h>
|
||||
/*
|
||||
__FBSDID("$FreeBSD: src/bin/sh/miscbltin.c,v 1.30 2004/04/06 20:06:51 markm Exp $");
|
||||
*/
|
||||
|
||||
/*
|
||||
* Miscellaneous builtins.
|
||||
* Miscelaneous builtins.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/types.h> /* quad_t */
|
||||
#include <sys/param.h> /* BSD4_4 */
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/select.h>
|
||||
#include <time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <termios.h>
|
||||
|
||||
#include "shell.h"
|
||||
#include "options.h"
|
||||
|
@ -63,159 +61,148 @@ __FBSDID("$FreeBSD: src/bin/sh/miscbltin.c,v 1.30 2004/04/06 20:06:51 markm Exp
|
|||
#include "output.h"
|
||||
#include "memalloc.h"
|
||||
#include "error.h"
|
||||
#include "mystring.h"
|
||||
#include "builtins.h"
|
||||
#include "mystring.h"
|
||||
|
||||
#undef rflag
|
||||
|
||||
|
||||
#undef eflag
|
||||
|
||||
/*
|
||||
* The read builtin. The -r option causes backslashes to be treated like
|
||||
* ordinary characters.
|
||||
* The read builtin.
|
||||
* Backslahes escape the next char unless -r is specified.
|
||||
*
|
||||
* This uses unbuffered input, which may be avoidable in some cases.
|
||||
*
|
||||
* Note that if IFS=' :' then read x y should work so that:
|
||||
* 'a b' x='a', y='b'
|
||||
* ' a b ' x='a', y='b'
|
||||
* ':b' x='', y='b'
|
||||
* ':' x='', y=''
|
||||
* '::' x='', y=''
|
||||
* ': :' x='', y=''
|
||||
* ':::' x='', y='::'
|
||||
* ':b c:' x='', y='b c:'
|
||||
*/
|
||||
|
||||
int
|
||||
readcmd(int argc __unused, char **argv __unused)
|
||||
readcmd(int argc, char **argv)
|
||||
{
|
||||
char **ap;
|
||||
int backslash;
|
||||
char c;
|
||||
int rflag;
|
||||
char *prompt;
|
||||
char *ifs;
|
||||
const char *ifs;
|
||||
char *p;
|
||||
int startword;
|
||||
int status;
|
||||
int i;
|
||||
struct timeval tv;
|
||||
char *tvptr;
|
||||
#ifndef __minix
|
||||
fd_set ifds;
|
||||
struct termios told, tnew;
|
||||
int tsaved;
|
||||
#endif
|
||||
int is_ifs;
|
||||
int saveall = 0;
|
||||
|
||||
rflag = 0;
|
||||
prompt = NULL;
|
||||
tv.tv_sec = -1;
|
||||
tv.tv_usec = 0;
|
||||
while ((i = nextopt("erp:t:")) != '\0') {
|
||||
switch(i) {
|
||||
case 'p':
|
||||
prompt = shoptarg;
|
||||
break;
|
||||
case 'e':
|
||||
break;
|
||||
case 'r':
|
||||
while ((i = nextopt("p:r")) != '\0') {
|
||||
if (i == 'p')
|
||||
prompt = optionarg;
|
||||
else
|
||||
rflag = 1;
|
||||
break;
|
||||
case 't':
|
||||
tv.tv_sec = strtol(shoptarg, &tvptr, 0);
|
||||
if (tvptr == shoptarg)
|
||||
error("timeout value");
|
||||
switch(*tvptr) {
|
||||
case 0:
|
||||
case 's':
|
||||
break;
|
||||
case 'h':
|
||||
tv.tv_sec *= 60;
|
||||
/* FALLTHROUGH */
|
||||
case 'm':
|
||||
tv.tv_sec *= 60;
|
||||
break;
|
||||
default:
|
||||
error("timeout unit");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (prompt && isatty(0)) {
|
||||
out2str(prompt);
|
||||
flushall();
|
||||
}
|
||||
|
||||
if (*(ap = argptr) == NULL)
|
||||
error("arg count");
|
||||
if ((ifs = bltinlookup("IFS", 1)) == NULL)
|
||||
ifs = nullstr;
|
||||
|
||||
if (tv.tv_sec >= 0) {
|
||||
#ifdef __minix
|
||||
abort();
|
||||
#else
|
||||
/*
|
||||
* See if we can disable input processing; this will
|
||||
* not give the desired result if we are in a pipeline
|
||||
* and someone upstream is still in line-by-line mode.
|
||||
*/
|
||||
tsaved = 0;
|
||||
if (tcgetattr(0, &told) == 0) {
|
||||
memcpy(&tnew, &told, sizeof(told));
|
||||
cfmakeraw(&tnew);
|
||||
tcsetattr(0, TCSANOW, &tnew);
|
||||
tsaved = 1;
|
||||
}
|
||||
/*
|
||||
* Wait for something to become available.
|
||||
*/
|
||||
FD_ZERO(&ifds);
|
||||
FD_SET(0, &ifds);
|
||||
status = select(1, &ifds, NULL, NULL, &tv);
|
||||
if (tsaved)
|
||||
tcsetattr(0, TCSANOW, &told);
|
||||
/*
|
||||
* If there's nothing ready, return an error.
|
||||
*/
|
||||
if (status <= 0)
|
||||
return(1);
|
||||
#endif
|
||||
}
|
||||
if ((ifs = bltinlookup("IFS", 1)) == NULL)
|
||||
ifs = " \t\n";
|
||||
|
||||
status = 0;
|
||||
startword = 1;
|
||||
backslash = 0;
|
||||
startword = 2;
|
||||
STARTSTACKSTR(p);
|
||||
for (;;) {
|
||||
if (read(STDIN_FILENO, &c, 1) != 1) {
|
||||
if (read(0, &c, 1) != 1) {
|
||||
status = 1;
|
||||
break;
|
||||
}
|
||||
if (c == '\0')
|
||||
continue;
|
||||
if (backslash) {
|
||||
backslash = 0;
|
||||
if (c == '\\' && !rflag) {
|
||||
if (read(0, &c, 1) != 1) {
|
||||
status = 1;
|
||||
break;
|
||||
}
|
||||
if (c != '\n')
|
||||
STPUTC(c, p);
|
||||
continue;
|
||||
}
|
||||
if (!rflag && c == '\\') {
|
||||
backslash++;
|
||||
continue;
|
||||
}
|
||||
if (c == '\n')
|
||||
break;
|
||||
if (startword && *ifs == ' ' && strchr(ifs, c)) {
|
||||
if (strchr(ifs, c))
|
||||
is_ifs = strchr(" \t\n", c) ? 1 : 2;
|
||||
else
|
||||
is_ifs = 0;
|
||||
|
||||
if (startword != 0) {
|
||||
if (is_ifs == 1) {
|
||||
/* Ignore leading IFS whitespace */
|
||||
if (saveall)
|
||||
STPUTC(c, p);
|
||||
continue;
|
||||
}
|
||||
startword = 0;
|
||||
if (backslash && c == '\\') {
|
||||
if (read(STDIN_FILENO, &c, 1) != 1) {
|
||||
status = 1;
|
||||
break;
|
||||
}
|
||||
if (is_ifs == 2 && startword == 1) {
|
||||
/* Only one non-whitespace IFS per word */
|
||||
startword = 2;
|
||||
if (saveall)
|
||||
STPUTC(c, p);
|
||||
} else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_ifs == 0) {
|
||||
/* append this character to the current variable */
|
||||
startword = 0;
|
||||
if (saveall)
|
||||
/* Not just a spare terminator */
|
||||
saveall++;
|
||||
STPUTC(c, p);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* end of variable... */
|
||||
startword = is_ifs;
|
||||
|
||||
if (ap[1] == NULL) {
|
||||
/* Last variable needs all IFS chars */
|
||||
saveall++;
|
||||
STPUTC(c, p);
|
||||
continue;
|
||||
}
|
||||
|
||||
STACKSTRNUL(p);
|
||||
setvar(*ap, stackblock(), 0);
|
||||
ap++;
|
||||
startword = 1;
|
||||
STARTSTACKSTR(p);
|
||||
} else {
|
||||
STPUTC(c, p);
|
||||
}
|
||||
}
|
||||
STACKSTRNUL(p);
|
||||
|
||||
/* Remove trailing IFS chars */
|
||||
for (; stackblock() <= --p; *p = 0) {
|
||||
if (!strchr(ifs, *p))
|
||||
break;
|
||||
if (strchr(" \t\n", *p))
|
||||
/* Always remove whitespace */
|
||||
continue;
|
||||
if (saveall > 1)
|
||||
/* Don't remove non-whitespace unless it was naked */
|
||||
break;
|
||||
}
|
||||
setvar(*ap, stackblock(), 0);
|
||||
|
||||
/* Set any remaining args to "" */
|
||||
while (*++ap != NULL)
|
||||
setvar(*ap, nullstr, 0);
|
||||
return status;
|
||||
|
@ -224,7 +211,7 @@ readcmd(int argc __unused, char **argv __unused)
|
|||
|
||||
|
||||
int
|
||||
umaskcmd(int argc __unused, char **argv)
|
||||
umaskcmd(int argc, char **argv)
|
||||
{
|
||||
char *ap;
|
||||
int mask;
|
||||
|
@ -276,7 +263,7 @@ umaskcmd(int argc __unused, char **argv)
|
|||
out1fmt("%.4o\n", mask);
|
||||
}
|
||||
} else {
|
||||
if (isdigit(*ap)) {
|
||||
if (isdigit((unsigned char)*ap)) {
|
||||
mask = 0;
|
||||
do {
|
||||
if (*ap >= '8' || *ap < '0')
|
||||
|
@ -286,44 +273,23 @@ umaskcmd(int argc __unused, char **argv)
|
|||
umask(mask);
|
||||
} else {
|
||||
void *set;
|
||||
if ((set = setmode (ap)) == 0)
|
||||
error("Illegal number: %s", ap);
|
||||
|
||||
INTOFF;
|
||||
if ((set = setmode(ap)) != 0) {
|
||||
mask = getmode(set, ~mask & 0777);
|
||||
ckfree(set);
|
||||
}
|
||||
INTON;
|
||||
if (!set)
|
||||
error("Cannot set mode `%s' (%s)", ap,
|
||||
strerror(errno));
|
||||
|
||||
umask(~mask & 0777);
|
||||
free(set);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef __minix
|
||||
struct rlimit
|
||||
{
|
||||
unsigned long rlim_cur; /* current (soft) limit */
|
||||
unsigned long rlim_max; /* maximum value for rlim_cur */
|
||||
};
|
||||
#define RLIM_INFINITY (((unsigned long)1 << 31) - 1)
|
||||
|
||||
int getrlimit (int, struct rlimit *);
|
||||
int setrlimit (int, const struct rlimit *);
|
||||
|
||||
int getrlimit(resource, rlp)
|
||||
int resource;
|
||||
struct rlimit *rlp;
|
||||
{
|
||||
errno= ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
int setrlimit(resource, rlp)
|
||||
int resource;
|
||||
const struct rlimit *rlp;
|
||||
{
|
||||
errno= ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ulimit builtin
|
||||
*
|
||||
|
@ -336,7 +302,7 @@ const struct rlimit *rlp;
|
|||
|
||||
struct limits {
|
||||
const char *name;
|
||||
const char *units;
|
||||
const char *unit;
|
||||
int cmd;
|
||||
int factor; /* multiply by to get rlim_{cur,max} values */
|
||||
char option;
|
||||
|
@ -344,49 +310,52 @@ struct limits {
|
|||
|
||||
static const struct limits limits[] = {
|
||||
#ifdef RLIMIT_CPU
|
||||
{ "cpu time", "seconds", RLIMIT_CPU, 1, 't' },
|
||||
{ "time", "seconds", RLIMIT_CPU, 1, 't' },
|
||||
#endif
|
||||
#ifdef RLIMIT_FSIZE
|
||||
{ "file size", "512-blocks", RLIMIT_FSIZE, 512, 'f' },
|
||||
{ "file", "blocks", RLIMIT_FSIZE, 512, 'f' },
|
||||
#endif
|
||||
#ifdef RLIMIT_DATA
|
||||
{ "data seg size", "kbytes", RLIMIT_DATA, 1024, 'd' },
|
||||
{ "data", "kbytes", RLIMIT_DATA, 1024, 'd' },
|
||||
#endif
|
||||
#ifdef RLIMIT_STACK
|
||||
{ "stack size", "kbytes", RLIMIT_STACK, 1024, 's' },
|
||||
{ "stack", "kbytes", RLIMIT_STACK, 1024, 's' },
|
||||
#endif
|
||||
#ifdef RLIMIT_CORE
|
||||
{ "core file size", "512-blocks", RLIMIT_CORE, 512, 'c' },
|
||||
{ "coredump", "blocks", RLIMIT_CORE, 512, 'c' },
|
||||
#endif
|
||||
#ifdef RLIMIT_RSS
|
||||
{ "max memory size", "kbytes", RLIMIT_RSS, 1024, 'm' },
|
||||
{ "memory", "kbytes", RLIMIT_RSS, 1024, 'm' },
|
||||
#endif
|
||||
#ifdef RLIMIT_MEMLOCK
|
||||
{ "locked memory","kbytes", RLIMIT_MEMLOCK, 1024, 'l' },
|
||||
#endif
|
||||
#ifdef RLIMIT_NTHR
|
||||
{ "thread", "threads", RLIMIT_NTHR, 1, 'r' },
|
||||
#endif
|
||||
#ifdef RLIMIT_NPROC
|
||||
{ "max user processes", (char *)0, RLIMIT_NPROC, 1, 'u' },
|
||||
{ "process", "processes", RLIMIT_NPROC, 1, 'p' },
|
||||
#endif
|
||||
#ifdef RLIMIT_NOFILE
|
||||
{ "open files", (char *)0, RLIMIT_NOFILE, 1, 'n' },
|
||||
{ "nofiles", "descriptors", RLIMIT_NOFILE, 1, 'n' },
|
||||
#endif
|
||||
#ifdef RLIMIT_VMEM
|
||||
{ "virtual mem size", "kbytes", RLIMIT_VMEM, 1024, 'v' },
|
||||
{ "vmemory", "kbytes", RLIMIT_VMEM, 1024, 'v' },
|
||||
#endif
|
||||
#ifdef RLIMIT_SWAP
|
||||
{ "swap limit", "kbytes", RLIMIT_SWAP, 1024, 'w' },
|
||||
{ "swap", "kbytes", RLIMIT_SWAP, 1024, 'w' },
|
||||
#endif
|
||||
#ifdef RLIMIT_SBSIZE
|
||||
{ "sbsize", "bytes", RLIMIT_SBSIZE, 1, 'b' },
|
||||
#endif
|
||||
{ (char *) 0, (char *)0, 0, 0, '\0' }
|
||||
{ NULL, NULL, 0, 0, '\0' }
|
||||
};
|
||||
|
||||
int
|
||||
ulimitcmd(int argc __unused, char **argv __unused)
|
||||
ulimitcmd(int argc, char **argv)
|
||||
{
|
||||
int c;
|
||||
intmax_t val = 0;
|
||||
rlim_t val = 0;
|
||||
enum { SOFT = 0x1, HARD = 0x2 }
|
||||
how = SOFT | HARD;
|
||||
const struct limits *l;
|
||||
|
@ -395,7 +364,7 @@ ulimitcmd(int argc __unused, char **argv __unused)
|
|||
struct rlimit limit;
|
||||
|
||||
what = 'f';
|
||||
while ((optc = nextopt("HSatfdsmcnuvlb")) != '\0')
|
||||
while ((optc = nextopt("HSabtfdscmlrpnv")) != '\0')
|
||||
switch (optc) {
|
||||
case 'H':
|
||||
how = HARD;
|
||||
|
@ -424,14 +393,10 @@ ulimitcmd(int argc __unused, char **argv __unused)
|
|||
if (strcmp(p, "unlimited") == 0)
|
||||
val = RLIM_INFINITY;
|
||||
else {
|
||||
val = 0;
|
||||
val = (rlim_t) 0;
|
||||
|
||||
while ((c = *p++) >= '0' && c <= '9')
|
||||
{
|
||||
val = (val * 10) + (long)(c - '0');
|
||||
if (val < 0)
|
||||
break;
|
||||
}
|
||||
if (c)
|
||||
error("bad number");
|
||||
val *= l->factor;
|
||||
|
@ -439,41 +404,37 @@ ulimitcmd(int argc __unused, char **argv __unused)
|
|||
}
|
||||
if (all) {
|
||||
for (l = limits; l->name; l++) {
|
||||
char optbuf[40];
|
||||
if (getrlimit(l->cmd, &limit) < 0)
|
||||
error("can't get limit: %s", strerror(errno));
|
||||
getrlimit(l->cmd, &limit);
|
||||
if (how & SOFT)
|
||||
val = limit.rlim_cur;
|
||||
else if (how & HARD)
|
||||
val = limit.rlim_max;
|
||||
|
||||
if (l->units)
|
||||
snprintf(optbuf, sizeof(optbuf),
|
||||
"(%s, -%c) ", l->units, l->option);
|
||||
else
|
||||
snprintf(optbuf, sizeof(optbuf),
|
||||
"(-%c) ", l->option);
|
||||
out1fmt("%-18s %18s ", l->name, optbuf);
|
||||
out1fmt("%-13s (-%c %-11s) ", l->name, l->option,
|
||||
l->unit);
|
||||
if (val == RLIM_INFINITY)
|
||||
out1fmt("unlimited\n");
|
||||
else
|
||||
{
|
||||
val /= l->factor;
|
||||
out1fmt("%jd\n", (intmax_t)val);
|
||||
#ifdef BSD4_4
|
||||
out1fmt("%lld\n", (long long) val);
|
||||
#else
|
||||
out1fmt("%ld\n", (long) val);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (getrlimit(l->cmd, &limit) < 0)
|
||||
error("can't get limit: %s", strerror(errno));
|
||||
getrlimit(l->cmd, &limit);
|
||||
if (set) {
|
||||
if (how & SOFT)
|
||||
limit.rlim_cur = val;
|
||||
if (how & HARD)
|
||||
limit.rlim_max = val;
|
||||
if (how & SOFT)
|
||||
limit.rlim_cur = val;
|
||||
if (setrlimit(l->cmd, &limit) < 0)
|
||||
error("bad limit: %s", strerror(errno));
|
||||
error("error setting limit (%s)", strerror(errno));
|
||||
} else {
|
||||
if (how & SOFT)
|
||||
val = limit.rlim_cur;
|
||||
|
@ -485,12 +446,12 @@ ulimitcmd(int argc __unused, char **argv __unused)
|
|||
else
|
||||
{
|
||||
val /= l->factor;
|
||||
out1fmt("%jd\n", (intmax_t)val);
|
||||
#ifdef BSD4_4
|
||||
out1fmt("%lld\n", (long long) val);
|
||||
#else
|
||||
out1fmt("%ld\n", (long) val);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* $PchId: miscbltin.c,v 1.7 2006/05/23 11:59:08 philip Exp $
|
||||
*/
|
31
bin/sh/miscbltin.h
Normal file
31
bin/sh/miscbltin.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/* $NetBSD: miscbltin.h,v 1.3 2003/08/21 17:57:53 christos Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1997 Christos Zoulas. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
int readcmd(int, char **);
|
||||
int umaskcmd(int, char **);
|
||||
int ulimitcmd(int, char **);
|
128
minix/commands/ash/mkbuiltins.sh → bin/sh/mkbuiltins
Executable file → Normal file
128
minix/commands/ash/mkbuiltins.sh → bin/sh/mkbuiltins
Executable file → Normal file
|
@ -1,4 +1,5 @@
|
|||
#!/bin/sh -
|
||||
# $NetBSD: mkbuiltins,v 1.22 2009/10/06 19:56:58 apb Exp $
|
||||
#
|
||||
# Copyright (c) 1991, 1993
|
||||
# The Regents of the University of California. All rights reserved.
|
||||
|
@ -14,7 +15,7 @@
|
|||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 4. Neither the name of the University nor the names of its contributors
|
||||
# 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.
|
||||
#
|
||||
|
@ -31,68 +32,105 @@
|
|||
# SUCH DAMAGE.
|
||||
#
|
||||
# @(#)mkbuiltins 8.2 (Berkeley) 5/4/95
|
||||
# $FreeBSD: src/bin/sh/mkbuiltins,v 1.13 2004/04/06 20:06:51 markm Exp $
|
||||
|
||||
#temp=`/usr/bin/mktemp -t ka`
|
||||
temp=/tmp/mkb$$
|
||||
havehist=1
|
||||
if [ "X$1" = "X-h" ]; then
|
||||
if [ x"$1" = x"-h" ]; then
|
||||
havehist=0
|
||||
shift
|
||||
fi
|
||||
|
||||
shell=$1
|
||||
builtins=$2
|
||||
objdir=$3
|
||||
|
||||
havejobs=0
|
||||
if [ "X$1" = "X-j" ]; then
|
||||
havejobs=0
|
||||
shift
|
||||
elif grep '^#define[ ]*JOBS[ ]*1' $2 > /dev/null
|
||||
then havejobs=1
|
||||
if grep '^#define JOBS[ ]*1' ${shell} > /dev/null
|
||||
then
|
||||
havejobs=1
|
||||
fi
|
||||
objdir=$1
|
||||
exec > ${objdir}/builtins.c
|
||||
cat <<\!
|
||||
/*
|
||||
|
||||
exec <$builtins 3> ${objdir}/builtins.c 4> ${objdir}/builtins.h
|
||||
|
||||
echo '/*
|
||||
* This file was generated by the mkbuiltins program.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "shell.h"
|
||||
#include "builtins.h"
|
||||
|
||||
!
|
||||
awk '/^[^#]/ {if(('$havejobs' || $2 != "-j") && ('$havehist' || $2 != "-h")) \
|
||||
print $0}' $3 | sed 's/-[hj]//' > $temp
|
||||
#awk '{ printf "int %s();\n", $1}' $temp
|
||||
echo '
|
||||
int (*const builtinfunc[]) (int, char **) = {'
|
||||
awk '/^[^#]/ { printf "\t%s,\n", $1}' $temp
|
||||
echo '};
|
||||
const struct builtincmd builtincmd[] = {
|
||||
' >&3
|
||||
|
||||
const struct builtincmd builtincmd[] = {'
|
||||
awk '{ for (i = 2 ; i <= NF ; i++) {
|
||||
printf "\t{ \"%s\", %d },\n", $i, NR-1
|
||||
}}' $temp
|
||||
echo ' { NULL, 0 }
|
||||
};'
|
||||
|
||||
exec > ${objdir}/builtins.h
|
||||
cat <<\!
|
||||
/*
|
||||
echo '/*
|
||||
* This file was generated by the mkbuiltins program.
|
||||
*/
|
||||
|
||||
!
|
||||
tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ < $temp |
|
||||
awk '{ printf "#define %s %d\n", $1, NR-1}'
|
||||
echo '
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
struct builtincmd {
|
||||
char *name;
|
||||
int code;
|
||||
const char *name;
|
||||
int (*builtin)(int, char **);
|
||||
};
|
||||
|
||||
extern int (*const builtinfunc[]) (int, char **);
|
||||
extern const struct builtincmd builtincmd[];'
|
||||
awk '{ printf "int %s (int, char **);\n", $1 }' < $temp
|
||||
rm -f $temp
|
||||
extern const struct builtincmd builtincmd[];
|
||||
extern const struct builtincmd splbltincmd[];
|
||||
|
||||
#
|
||||
# $PchId: mkbuiltins,v 1.6 2006/05/22 12:42:58 philip Exp $
|
||||
' >&4
|
||||
|
||||
specials=
|
||||
|
||||
while read line
|
||||
do
|
||||
set -- $line
|
||||
[ -z "$1" ] && continue
|
||||
case "$1" in
|
||||
\#if*|\#def*|\#end*)
|
||||
echo $line >&3
|
||||
echo $line >&4
|
||||
continue
|
||||
;;
|
||||
\#*)
|
||||
continue
|
||||
;;
|
||||
esac
|
||||
|
||||
func=$1
|
||||
shift
|
||||
[ x"$1" = x'-j' ] && {
|
||||
[ $havejobs = 0 ] && continue
|
||||
shift
|
||||
}
|
||||
[ x"$1" = x'-h' ] && {
|
||||
[ $havehist = 0 ] && continue
|
||||
shift
|
||||
}
|
||||
echo 'int '"$func"'(int, char **);' >&4
|
||||
while
|
||||
[ $# != 0 ] && [ x"$1" != x'#' ]
|
||||
do
|
||||
[ x"$1" = x'-s' ] && {
|
||||
specials="$specials $2 $func"
|
||||
shift 2
|
||||
continue;
|
||||
}
|
||||
[ x"$1" = x'-u' ] && shift
|
||||
echo ' { "'$1'", '"$func"' },' >&3
|
||||
shift
|
||||
done
|
||||
done
|
||||
|
||||
echo ' { 0, 0 },' >&3
|
||||
echo '};' >&3
|
||||
echo >&3
|
||||
echo 'const struct builtincmd splbltincmd[] = {' >&3
|
||||
|
||||
set -- $specials
|
||||
while
|
||||
[ $# != 0 ]
|
||||
do
|
||||
echo ' { "'$1'", '"$2"' },' >&3
|
||||
shift 2
|
||||
done
|
||||
|
||||
echo ' { 0, 0 },' >&3
|
||||
echo "};" >&3
|
170
bin/sh/mkinit.sh
Executable file
170
bin/sh/mkinit.sh
Executable file
|
@ -0,0 +1,170 @@
|
|||
#! /bin/sh
|
||||
# $NetBSD: mkinit.sh,v 1.5 2008/10/23 20:21:57 apb Exp $
|
||||
|
||||
# Copyright (c) 2003 The NetBSD Foundation, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# This code is derived from software contributed to The NetBSD Foundation
|
||||
# by David Laight.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
srcs="$*"
|
||||
|
||||
nl='
|
||||
'
|
||||
openparen='('
|
||||
backslash='\'
|
||||
|
||||
includes=' "shell.h" "mystring.h" "init.h" '
|
||||
defines=
|
||||
decles=
|
||||
event_init=
|
||||
event_reset=
|
||||
event_shellproc=
|
||||
|
||||
for src in $srcs; do
|
||||
exec <$src
|
||||
decnl="$nl"
|
||||
while IFS=; read -r line; do
|
||||
[ "$line" = x ]
|
||||
case "$line " in
|
||||
INIT["{ "]* ) event=init;;
|
||||
RESET["{ "]* ) event=reset;;
|
||||
SHELLPROC["{ "]* ) event=shellproc;;
|
||||
INCLUDE[\ \ ]* )
|
||||
IFS=' '
|
||||
set -- $line
|
||||
# ignore duplicates
|
||||
[ "${includes}" != "${includes%* $2 }" ] && continue
|
||||
includes="$includes$2 "
|
||||
continue
|
||||
;;
|
||||
MKINIT\ )
|
||||
# struct declaration
|
||||
decles="$decles$nl"
|
||||
while
|
||||
read -r line
|
||||
decles="${decles}${line}${nl}"
|
||||
[ "$line" != "};" ]
|
||||
do
|
||||
:
|
||||
done
|
||||
decnl="$nl"
|
||||
continue
|
||||
;;
|
||||
MKINIT["{ "]* )
|
||||
# strip initialiser
|
||||
def=${line#MKINIT}
|
||||
comment="${def#*;}"
|
||||
def="${def%;$comment}"
|
||||
def="${def%%=*}"
|
||||
def="${def% }"
|
||||
decles="${decles}${decnl}extern${def};${comment}${nl}"
|
||||
decnl=
|
||||
continue
|
||||
;;
|
||||
\#define[\ \ ]* )
|
||||
IFS=' '
|
||||
set -- $line
|
||||
# Ignore those with arguments
|
||||
[ "$2" = "${2##*$openparen}" ] || continue
|
||||
# and multiline definitions
|
||||
[ "$line" = "${line%$backslash}" ] || continue
|
||||
defines="${defines}#undef $2${nl}${line}${nl}"
|
||||
continue
|
||||
;;
|
||||
* ) continue;;
|
||||
esac
|
||||
# code for events
|
||||
ev="${nl} /* from $src: */${nl} {${nl}"
|
||||
# Indent the text by an extra <tab>
|
||||
while
|
||||
read -r line
|
||||
[ "$line" != "}" ]
|
||||
do
|
||||
[ -n "$line" -a "$line" = "${line###}" ] &&
|
||||
line=" $line"
|
||||
ev="${ev}${line}${nl}"
|
||||
done
|
||||
ev="${ev} }${nl}"
|
||||
eval event_$event=\"\$event_$event\$ev\"
|
||||
done
|
||||
done
|
||||
|
||||
exec >init.c.tmp
|
||||
|
||||
echo "/*"
|
||||
echo " * This file was generated by the mkinit program."
|
||||
echo " */"
|
||||
echo
|
||||
|
||||
IFS=' '
|
||||
for f in $includes; do
|
||||
echo "#include $f"
|
||||
done
|
||||
|
||||
echo
|
||||
echo
|
||||
echo
|
||||
echo "$defines"
|
||||
echo
|
||||
echo "$decles"
|
||||
echo
|
||||
echo
|
||||
echo "/*"
|
||||
echo " * Initialization code."
|
||||
echo " */"
|
||||
echo
|
||||
echo "void"
|
||||
echo "init(void)"
|
||||
echo "{"
|
||||
echo "${event_init}"
|
||||
echo "}"
|
||||
echo
|
||||
echo
|
||||
echo
|
||||
echo "/*"
|
||||
echo " * This routine is called when an error or an interrupt occurs in an"
|
||||
echo " * interactive shell and control is returned to the main command loop."
|
||||
echo " */"
|
||||
echo
|
||||
echo "void"
|
||||
echo "reset(void)"
|
||||
echo "{"
|
||||
echo "${event_reset}"
|
||||
echo "}"
|
||||
echo
|
||||
echo
|
||||
echo
|
||||
echo "/*"
|
||||
echo " * This routine is called to initialize the shell to run a shell procedure."
|
||||
echo " */"
|
||||
echo
|
||||
echo "void"
|
||||
echo "initshellproc(void)"
|
||||
echo "{"
|
||||
echo "${event_shellproc}"
|
||||
echo "}"
|
||||
|
||||
exec >&-
|
||||
mv init.c.tmp init.c
|
214
bin/sh/mknodes.sh
Executable file
214
bin/sh/mknodes.sh
Executable file
|
@ -0,0 +1,214 @@
|
|||
#! /bin/sh
|
||||
# $NetBSD: mknodes.sh,v 1.2 2008/04/29 06:53:00 martin Exp $
|
||||
|
||||
# Copyright (c) 2003 The NetBSD Foundation, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# This code is derived from software contributed to The NetBSD Foundation
|
||||
# by David Laight.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
nodetypes=$1
|
||||
nodes_pat=$2
|
||||
objdir="$3"
|
||||
|
||||
exec <$nodetypes
|
||||
exec >$objdir/nodes.h.tmp
|
||||
|
||||
echo "/*"
|
||||
echo " * This file was generated by mknodes.sh"
|
||||
echo " */"
|
||||
echo
|
||||
|
||||
tagno=0
|
||||
while IFS=; read -r line; do
|
||||
line="${line%%#*}"
|
||||
IFS=' '
|
||||
set -- $line
|
||||
IFS=
|
||||
[ -z "$2" ] && continue
|
||||
case "$line" in
|
||||
[" "]* )
|
||||
IFS=' '
|
||||
[ $field = 0 ] && struct_list="$struct_list $struct"
|
||||
eval field_${struct}_$field=\"\$*\"
|
||||
eval numfld_$struct=\$field
|
||||
field=$(($field + 1))
|
||||
;;
|
||||
* )
|
||||
define=$1
|
||||
struct=$2
|
||||
echo "#define $define $tagno"
|
||||
tagno=$(($tagno + 1))
|
||||
eval define_$struct=\"\$define_$struct \$define\"
|
||||
struct_define="$struct_define $struct"
|
||||
field=0
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
echo
|
||||
|
||||
IFS=' '
|
||||
for struct in $struct_list; do
|
||||
echo
|
||||
echo
|
||||
echo "struct $struct {"
|
||||
field=0
|
||||
while
|
||||
eval line=\"\$field_${struct}_$field\"
|
||||
field=$(($field + 1))
|
||||
[ -n "$line" ]
|
||||
do
|
||||
IFS=' '
|
||||
set -- $line
|
||||
name=$1
|
||||
case $2 in
|
||||
nodeptr ) type="union node *";;
|
||||
nodelist ) type="struct nodelist *";;
|
||||
string ) type="char *";;
|
||||
int ) type="int ";;
|
||||
* ) name=; shift 2; type="$*";;
|
||||
esac
|
||||
echo " $type$name;"
|
||||
done
|
||||
echo "};"
|
||||
done
|
||||
|
||||
echo
|
||||
echo
|
||||
echo "union node {"
|
||||
echo " int type;"
|
||||
for struct in $struct_list; do
|
||||
echo " struct $struct $struct;"
|
||||
done
|
||||
echo "};"
|
||||
echo
|
||||
echo
|
||||
echo "struct nodelist {"
|
||||
echo " struct nodelist *next;"
|
||||
echo " union node *n;"
|
||||
echo "};"
|
||||
echo
|
||||
echo
|
||||
echo "union node *copyfunc(union node *);"
|
||||
echo "void freefunc(union node *);"
|
||||
|
||||
mv $objdir/nodes.h.tmp $objdir/nodes.h || exit 1
|
||||
|
||||
exec <$nodes_pat
|
||||
exec >$objdir/nodes.c.tmp
|
||||
|
||||
echo "/*"
|
||||
echo " * This file was generated by mknodes.sh"
|
||||
echo " */"
|
||||
echo
|
||||
|
||||
while IFS=; read -r line; do
|
||||
IFS=' '
|
||||
set -- $line
|
||||
IFS=
|
||||
case "$1" in
|
||||
'%SIZES' )
|
||||
echo "static const short nodesize[$tagno] = {"
|
||||
IFS=' '
|
||||
for struct in $struct_define; do
|
||||
echo " SHELL_ALIGN(sizeof (struct $struct)),"
|
||||
done
|
||||
echo "};"
|
||||
;;
|
||||
'%CALCSIZE' )
|
||||
echo " if (n == NULL)"
|
||||
echo " return;"
|
||||
echo " funcblocksize += nodesize[n->type];"
|
||||
echo " switch (n->type) {"
|
||||
IFS=' '
|
||||
for struct in $struct_list; do
|
||||
eval defines=\"\$define_$struct\"
|
||||
for define in $defines; do
|
||||
echo " case $define:"
|
||||
done
|
||||
eval field=\$numfld_$struct
|
||||
while
|
||||
[ $field != 0 ]
|
||||
do
|
||||
eval line=\"\$field_${struct}_$field\"
|
||||
field=$(($field - 1))
|
||||
IFS=' '
|
||||
set -- $line
|
||||
name=$1
|
||||
cl=")"
|
||||
case $2 in
|
||||
nodeptr ) fn=calcsize;;
|
||||
nodelist ) fn=sizenodelist;;
|
||||
string ) fn="funcstringsize += strlen"
|
||||
cl=") + 1";;
|
||||
* ) continue;;
|
||||
esac
|
||||
echo " ${fn}(n->$struct.$name${cl};"
|
||||
done
|
||||
echo " break;"
|
||||
done
|
||||
echo " };"
|
||||
;;
|
||||
'%COPY' )
|
||||
echo " if (n == NULL)"
|
||||
echo " return NULL;"
|
||||
echo " new = funcblock;"
|
||||
echo " funcblock = (char *) funcblock + nodesize[n->type];"
|
||||
echo " switch (n->type) {"
|
||||
IFS=' '
|
||||
for struct in $struct_list; do
|
||||
eval defines=\"\$define_$struct\"
|
||||
for define in $defines; do
|
||||
echo " case $define:"
|
||||
done
|
||||
eval field=\$numfld_$struct
|
||||
while
|
||||
[ $field != 0 ]
|
||||
do
|
||||
eval line=\"\$field_${struct}_$field\"
|
||||
field=$(($field - 1))
|
||||
IFS=' '
|
||||
set -- $line
|
||||
name=$1
|
||||
case $2 in
|
||||
nodeptr ) fn="copynode(";;
|
||||
nodelist ) fn="copynodelist(";;
|
||||
string ) fn="nodesavestr(";;
|
||||
int ) fn=;;
|
||||
* ) continue;;
|
||||
esac
|
||||
f="$struct.$name"
|
||||
echo " new->$f = ${fn}n->$f${fn:+)};"
|
||||
done
|
||||
echo " break;"
|
||||
done
|
||||
echo " };"
|
||||
echo " new->type = n->type;"
|
||||
;;
|
||||
* ) echo "$line";;
|
||||
esac
|
||||
done
|
||||
|
||||
mv $objdir/nodes.c.tmp $objdir/nodes.c || exit 1
|
59
minix/commands/ash/mktokens.sh → bin/sh/mktokens
Executable file → Normal file
59
minix/commands/ash/mktokens.sh → bin/sh/mktokens
Executable file → Normal file
|
@ -1,4 +1,5 @@
|
|||
#!/bin/sh -
|
||||
# $NetBSD: mktokens,v 1.12 2008/10/25 22:18:15 apb Exp $
|
||||
#
|
||||
# Copyright (c) 1991, 1993
|
||||
# The Regents of the University of California. All rights reserved.
|
||||
|
@ -14,7 +15,7 @@
|
|||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 4. Neither the name of the University nor the names of its contributors
|
||||
# 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.
|
||||
#
|
||||
|
@ -31,17 +32,15 @@
|
|||
# SUCH DAMAGE.
|
||||
#
|
||||
# @(#)mktokens 8.1 (Berkeley) 5/31/93
|
||||
# $FreeBSD: src/bin/sh/mktokens,v 1.9 2004/04/06 20:06:51 markm Exp $
|
||||
|
||||
# All calls to awk removed, because Minix bawk is deficient. (kjb)
|
||||
: ${AWK:=awk}
|
||||
: ${SED:=sed}
|
||||
|
||||
# The following is a list of tokens. The second column is nonzero if the
|
||||
# token marks the end of a list. The third column is the name to print in
|
||||
# error messages.
|
||||
|
||||
#temp=`/usr/bin/mktemp -t ka`
|
||||
temp=/tmp/mkt$$
|
||||
cat > $temp <<\!
|
||||
cat > /tmp/ka$$ <<\!
|
||||
TEOF 1 end of file
|
||||
TNL 0 newline
|
||||
TSEMI 0 ";"
|
||||
|
@ -71,54 +70,26 @@ TCASE 0 "case"
|
|||
TESAC 1 "esac"
|
||||
TNOT 0 "!"
|
||||
!
|
||||
nl=`wc -l $temp`
|
||||
nl=`wc -l /tmp/ka$$`
|
||||
exec > token.h
|
||||
i=0
|
||||
while read line
|
||||
do
|
||||
set -$- $line
|
||||
echo "#define $1 $i"
|
||||
i=`expr $i + 1`
|
||||
done <$temp
|
||||
${AWK} '{print "#define " $1 " " NR-1}' /tmp/ka$$
|
||||
echo '
|
||||
/* Array indicating which tokens mark the end of a list */
|
||||
const char tokendlist[] = {'
|
||||
while read line
|
||||
do
|
||||
set -$- $line
|
||||
echo " $2,"
|
||||
done <$temp
|
||||
${AWK} '{print "\t" $2 ","}' /tmp/ka$$
|
||||
echo '};
|
||||
|
||||
const char *const tokname[] = {'
|
||||
sed -e 's/"/\\"/g' \
|
||||
${SED} -e 's/"/\\"/g' \
|
||||
-e 's/[^ ]*[ ][ ]*[^ ]*[ ][ ]*\(.*\)/ "\1",/' \
|
||||
$temp
|
||||
/tmp/ka$$
|
||||
echo '};
|
||||
'
|
||||
i=0
|
||||
go=
|
||||
sed 's/"//g' $temp |
|
||||
while read line
|
||||
do
|
||||
set -$- $line
|
||||
if [ "$1" = TIF ]
|
||||
then
|
||||
echo "#define KWDOFFSET $i"
|
||||
echo
|
||||
echo "const char *const parsekwd[] = {"
|
||||
go=true
|
||||
fi
|
||||
if [ "$go" ]
|
||||
then
|
||||
echo " \"$3\","
|
||||
fi
|
||||
i=`expr $i + 1`
|
||||
done
|
||||
${SED} 's/"//g' /tmp/ka$$ | ${AWK} '
|
||||
/TIF/{print "#define KWDOFFSET " NR-1; print "";
|
||||
print "const char *const parsekwd[] = {"}
|
||||
/TIF/,/neverfound/{print " \"" $3 "\","}'
|
||||
echo ' 0
|
||||
};'
|
||||
|
||||
rm $temp
|
||||
|
||||
#
|
||||
# $PchId: mktokens,v 1.5 2006/05/22 12:43:35 philip Exp $
|
||||
rm /tmp/ka$$
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: myhistedit.h,v 1.11 2011/06/18 21:18:46 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -10,7 +12,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -27,7 +29,6 @@
|
|||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)myhistedit.h 8.2 (Berkeley) 5/4/95
|
||||
* $FreeBSD: src/bin/sh/myhistedit.h,v 1.10 2004/04/06 20:06:51 markm Exp $
|
||||
*/
|
||||
|
||||
#include <histedit.h>
|
||||
|
@ -38,13 +39,8 @@ extern int displayhist;
|
|||
|
||||
void histedit(void);
|
||||
void sethistsize(const char *);
|
||||
int histcmd(int, char **);
|
||||
int bindcmd(int, char **);
|
||||
|
||||
/* From libedit */
|
||||
void re_goto_bottom(EditLine *);
|
||||
|
||||
/*
|
||||
* $PchId: myhistedit.h,v 1.5 2006/03/29 15:55:18 philip Exp $
|
||||
*/
|
||||
void setterm(const char *);
|
||||
int inputrc(int, char **);
|
||||
int not_fcnumber(char *);
|
||||
int str_to_event(const char *, int);
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: mystring.c,v 1.17 2013/04/28 17:01:28 dholland Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -30,15 +32,14 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)mystring.c 8.2 (Berkeley) 5/4/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: mystring.c,v 1.17 2013/04/28 17:01:28 dholland Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
/*
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/bin/sh/mystring.c,v 1.13 2004/04/06 20:06:51 markm Exp $");
|
||||
*/
|
||||
|
||||
/*
|
||||
* String functions.
|
||||
|
@ -57,7 +58,7 @@ __FBSDID("$FreeBSD: src/bin/sh/mystring.c,v 1.13 2004/04/06 20:06:51 markm Exp $
|
|||
#include "mystring.h"
|
||||
|
||||
|
||||
char nullstr[1]; /* zero length string */
|
||||
const char nullstr[1]; /* zero length string */
|
||||
|
||||
/*
|
||||
* equal - #defined in mystring.h
|
||||
|
@ -109,8 +110,9 @@ prefix(const char *pfx, const char *string)
|
|||
int
|
||||
number(const char *s)
|
||||
{
|
||||
|
||||
if (! is_number(s))
|
||||
error("Illegal number: %s", (char *)s);
|
||||
error("Illegal number: %s", s);
|
||||
return atoi(s);
|
||||
}
|
||||
|
||||
|
@ -129,7 +131,3 @@ is_number(const char *p)
|
|||
} while (*++p != '\0');
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* $PchId: mystring.c,v 1.4 2006/05/22 12:21:53 philip Exp $
|
||||
*/
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: mystring.h,v 1.11 2003/08/07 09:05:35 agc Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -30,7 +32,6 @@
|
|||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)mystring.h 8.2 (Berkeley) 5/4/95
|
||||
* $FreeBSD: src/bin/sh/mystring.h,v 1.8 2004/04/06 20:06:51 markm Exp $
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
@ -42,7 +43,3 @@ int is_number(const char *);
|
|||
|
||||
#define equal(s1, s2) (strcmp(s1, s2) == 0)
|
||||
#define scopy(s1, s2) ((void)strcpy(s2, s1))
|
||||
|
||||
/*
|
||||
* $PchId: mystring.h,v 1.3 2006/03/29 15:49:08 philip Exp $
|
||||
*/
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: nodes.c.pat,v 1.13 2012/03/20 18:42:29 matt Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -30,7 +32,6 @@
|
|||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)nodes.c.pat 8.2 (Berkeley) 5/4/95
|
||||
* $FreeBSD: src/bin/sh/nodes.c.pat,v 1.15 2004/04/06 20:06:51 markm Exp $
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
@ -41,17 +42,14 @@
|
|||
#include "shell.h"
|
||||
#include "nodes.h"
|
||||
#include "memalloc.h"
|
||||
#include "machdep.h"
|
||||
#include "mystring.h"
|
||||
|
||||
#ifndef __minix
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
#include "machdep.h"
|
||||
|
||||
STATIC int funcblocksize; /* size of structures in function */
|
||||
STATIC int funcstringsize; /* size of strings in node */
|
||||
STATIC pointer funcblock; /* block to allocate function from */
|
||||
STATIC char *funcstring; /* block to allocate strings from */
|
||||
int funcblocksize; /* size of structures in function */
|
||||
int funcstringsize; /* size of strings in node */
|
||||
pointer funcblock; /* block to allocate function from */
|
||||
char *funcstring; /* block to allocate strings from */
|
||||
|
||||
%SIZES
|
||||
|
||||
|
@ -95,7 +93,7 @@ STATIC void
|
|||
sizenodelist(struct nodelist *lp)
|
||||
{
|
||||
while (lp) {
|
||||
funcblocksize += ALIGN(sizeof(struct nodelist));
|
||||
funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
|
||||
calcsize(lp->n);
|
||||
lp = lp->next;
|
||||
}
|
||||
|
@ -122,7 +120,8 @@ copynodelist(struct nodelist *lp)
|
|||
lpp = &start;
|
||||
while (lp) {
|
||||
*lpp = funcblock;
|
||||
funcblock = (char *)funcblock + ALIGN(sizeof(struct nodelist));
|
||||
funcblock = (char *) funcblock +
|
||||
SHELL_ALIGN(sizeof(struct nodelist));
|
||||
(*lpp)->n = copynode(lp->n);
|
||||
lp = lp->next;
|
||||
lpp = &(*lpp)->next;
|
||||
|
@ -136,11 +135,11 @@ copynodelist(struct nodelist *lp)
|
|||
STATIC char *
|
||||
nodesavestr(char *s)
|
||||
{
|
||||
char *p = s;
|
||||
char *q = funcstring;
|
||||
register char *p = s;
|
||||
register char *q = funcstring;
|
||||
char *rtn = funcstring;
|
||||
|
||||
while ((*q++ = *p++) != '\0')
|
||||
while ((*q++ = *p++) != 0)
|
||||
continue;
|
||||
funcstring = q;
|
||||
return rtn;
|
||||
|
@ -158,7 +157,3 @@ freefunc(union node *n)
|
|||
if (n)
|
||||
ckfree(n);
|
||||
}
|
||||
|
||||
/*
|
||||
* $PchId: nodes.c.pat,v 1.5 2006/05/22 12:43:57 philip Exp $
|
||||
*/
|
|
@ -1,4 +1,4 @@
|
|||
#
|
||||
# $NetBSD: nodetypes,v 1.13 2009/05/26 07:30:51 joerg Exp $
|
||||
# Copyright (c) 1991, 1993
|
||||
# The Regents of the University of California. All rights reserved.
|
||||
#
|
||||
|
@ -13,7 +13,7 @@
|
|||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 4. Neither the name of the University nor the names of its contributors
|
||||
# 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.
|
||||
#
|
||||
|
@ -30,7 +30,6 @@
|
|||
# SUCH DAMAGE.
|
||||
#
|
||||
# @(#)nodetypes 8.2 (Berkeley) 5/4/95
|
||||
# $FreeBSD: src/bin/sh/nodetypes,v 1.9 2004/04/06 20:06:51 markm Exp $
|
||||
|
||||
# This file describes the nodes used in parse trees. Unindented lines
|
||||
# contain a node type followed by a structure tag. Subsequent indented
|
||||
|
@ -65,7 +64,7 @@ NPIPE npipe # a pipeline
|
|||
backgnd int # set to run pipeline in background
|
||||
cmdlist nodelist # the commands in the pipeline
|
||||
|
||||
NREDIR nredir # redirection (of a compex command)
|
||||
NREDIR nredir # redirection (of a complex command)
|
||||
type int
|
||||
n nodeptr # the command
|
||||
redirect nodeptr # list of file redirections
|
||||
|
@ -113,10 +112,10 @@ NARG narg # represents a word
|
|||
backquote nodelist # list of commands in back quotes
|
||||
|
||||
NTO nfile # fd> fname
|
||||
NCLOBBER nfile # fd>| fname
|
||||
NFROM nfile # fd< fname
|
||||
NFROMTO nfile # fd<> fname
|
||||
NAPPEND nfile # fd>> fname
|
||||
NCLOBBER nfile # fd>| fname
|
||||
type int
|
||||
next nodeptr # next redirection in list
|
||||
fd int # file descriptor being redirected
|
||||
|
@ -142,6 +141,3 @@ NXHERE nhere # fd<<!
|
|||
NNOT nnot # ! command (actually pipeline)
|
||||
type int
|
||||
com nodeptr
|
||||
|
||||
#
|
||||
# $PchId: nodetypes,v 1.3 2006/03/29 15:43:35 philip Exp $
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: options.c,v 1.43 2012/03/20 18:42:29 matt Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -30,15 +32,14 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)options.c 8.2 (Berkeley) 5/4/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: options.c,v 1.43 2012/03/20 18:42:29 matt Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
/*
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/bin/sh/options.c,v 1.21 2004/04/06 20:06:51 markm Exp $");
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
@ -48,6 +49,7 @@ __FBSDID("$FreeBSD: src/bin/sh/options.c,v 1.21 2004/04/06 20:06:51 markm Exp $"
|
|||
#define DEFINE_OPTIONS
|
||||
#include "options.h"
|
||||
#undef DEFINE_OPTIONS
|
||||
#include "builtins.h"
|
||||
#include "nodes.h" /* for other header files */
|
||||
#include "eval.h"
|
||||
#include "jobs.h"
|
||||
|
@ -58,17 +60,16 @@ __FBSDID("$FreeBSD: src/bin/sh/options.c,v 1.21 2004/04/06 20:06:51 markm Exp $"
|
|||
#include "memalloc.h"
|
||||
#include "error.h"
|
||||
#include "mystring.h"
|
||||
#include "builtins.h"
|
||||
#if !defined(NO_HISTORY)
|
||||
#ifndef SMALL
|
||||
#include "myhistedit.h"
|
||||
#endif
|
||||
#include "show.h"
|
||||
|
||||
char *arg0; /* value of $0 */
|
||||
struct shparam shellparam; /* current positional parameters */
|
||||
char **argptr; /* argument list for builtin commands */
|
||||
char *shoptarg; /* set by nextopt (like getopt) */
|
||||
char *optionarg; /* set by nextopt (like getopt) */
|
||||
char *optptr; /* used by nextopt */
|
||||
int editable; /* isatty(0) && isatty(1) */
|
||||
|
||||
char *minusc; /* argument to -c option */
|
||||
|
||||
|
@ -86,33 +87,43 @@ STATIC int getopts(char *, char *, char **, char ***, char **);
|
|||
void
|
||||
procargs(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
size_t i;
|
||||
|
||||
argptr = argv;
|
||||
if (argc > 0)
|
||||
argptr++;
|
||||
for (i = 0; i < NOPTS; i++)
|
||||
optlist[i].val = 2;
|
||||
privileged = (getuid() != geteuid() || getgid() != getegid());
|
||||
options(1);
|
||||
if (*argptr == NULL && minusc == NULL)
|
||||
sflag = 1;
|
||||
editable = (isatty(0) && isatty(1));
|
||||
if (iflag == 2 && sflag == 1 && editable)
|
||||
if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
|
||||
iflag = 1;
|
||||
if (iflag == 1 && sflag == 2)
|
||||
iflag = 2;
|
||||
if (mflag == 2)
|
||||
mflag = iflag;
|
||||
for (i = 0; i < NOPTS; i++)
|
||||
if (optlist[i].val == 2)
|
||||
optlist[i].val = 0;
|
||||
#if DEBUG == 2
|
||||
debug = 1;
|
||||
#endif
|
||||
arg0 = argv[0];
|
||||
if (sflag == 0 && minusc == NULL) {
|
||||
commandname = arg0 = *argptr++;
|
||||
setinputfile(commandname, 0);
|
||||
commandname = argv[0];
|
||||
arg0 = *argptr++;
|
||||
setinputfile(arg0, 0);
|
||||
commandname = arg0;
|
||||
}
|
||||
/* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
|
||||
if (argptr && minusc && *argptr)
|
||||
if (minusc != NULL) {
|
||||
if (argptr == NULL || *argptr == NULL)
|
||||
error("Bad -c option");
|
||||
minusc = *argptr++;
|
||||
if (*argptr != 0)
|
||||
arg0 = *argptr++;
|
||||
}
|
||||
|
||||
shellparam.p = argptr;
|
||||
shellparam.reset = 1;
|
||||
|
@ -121,9 +132,6 @@ procargs(int argc, char **argv)
|
|||
shellparam.nparam++;
|
||||
argptr++;
|
||||
}
|
||||
#ifdef __minix
|
||||
if(!Eflag && !Vflag) Eflag = 1;
|
||||
#endif
|
||||
optschanged();
|
||||
}
|
||||
|
||||
|
@ -132,7 +140,7 @@ void
|
|||
optschanged(void)
|
||||
{
|
||||
setinteractive(iflag);
|
||||
#if !defined(NO_HISTORY)
|
||||
#ifndef SMALL
|
||||
histedit();
|
||||
#endif
|
||||
setjobctl(mflag);
|
||||
|
@ -146,6 +154,7 @@ optschanged(void)
|
|||
STATIC void
|
||||
options(int cmdline)
|
||||
{
|
||||
static char empty[] = "";
|
||||
char *p;
|
||||
int val;
|
||||
int c;
|
||||
|
@ -175,65 +184,62 @@ options(int cmdline)
|
|||
}
|
||||
while ((c = *p++) != '\0') {
|
||||
if (c == 'c' && cmdline) {
|
||||
char *q;
|
||||
#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */
|
||||
if (*p == '\0')
|
||||
#endif
|
||||
q = *argptr++;
|
||||
if (q == NULL || minusc != NULL)
|
||||
error("Bad -c option");
|
||||
minusc = q;
|
||||
#ifdef NOHACK
|
||||
break;
|
||||
#endif
|
||||
/* command is after shell args*/
|
||||
minusc = empty;
|
||||
} else if (c == 'o') {
|
||||
minus_o(*argptr, val);
|
||||
if (*argptr)
|
||||
argptr++;
|
||||
} else {
|
||||
if (c == 'p' && !val && privileged) {
|
||||
(void) setuid(getuid());
|
||||
(void) setgid(getgid());
|
||||
}
|
||||
setoption(c, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_opt_val(size_t i, int val)
|
||||
{
|
||||
size_t j;
|
||||
int flag;
|
||||
|
||||
if (val && (flag = optlist[i].opt_set)) {
|
||||
/* some options (eg vi/emacs) are mutually exclusive */
|
||||
for (j = 0; j < NOPTS; j++)
|
||||
if (optlist[j].opt_set == flag)
|
||||
optlist[j].val = 0;
|
||||
}
|
||||
optlist[i].val = val;
|
||||
#ifdef DEBUG
|
||||
if (&optlist[i].val == &debug)
|
||||
opentrace();
|
||||
#endif
|
||||
}
|
||||
|
||||
STATIC void
|
||||
minus_o(char *name, int val)
|
||||
{
|
||||
int doneset, i;
|
||||
size_t i;
|
||||
|
||||
if (name == NULL) {
|
||||
if (val) {
|
||||
/* "Pretty" output. */
|
||||
out1str("Current option settings\n");
|
||||
for (i = 0; i < NOPTS; i++)
|
||||
for (i = 0; i < NOPTS; i++) {
|
||||
out1fmt("%-16s%s\n", optlist[i].name,
|
||||
optlist[i].val ? "on" : "off");
|
||||
}
|
||||
} else {
|
||||
/* Output suitable for re-input to shell. */
|
||||
for (doneset = i = 0; i < NOPTS; i++)
|
||||
if (optlist[i].val) {
|
||||
if (!doneset) {
|
||||
out1str("set");
|
||||
doneset = 1;
|
||||
for (i = 0; i < NOPTS; i++) {
|
||||
out1fmt(" %co %s",
|
||||
"+-"[optlist[i].val], optlist[i].name);
|
||||
}
|
||||
out1fmt(" -o %s", optlist[i].name);
|
||||
}
|
||||
if (doneset)
|
||||
out1c('\n');
|
||||
out1str("\n");
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < NOPTS; i++)
|
||||
if (equal(name, optlist[i].name)) {
|
||||
if (!val && privileged && equal(name, "privileged")) {
|
||||
(void) setuid(getuid());
|
||||
(void) setgid(getgid());
|
||||
}
|
||||
setoption(optlist[i].letter, val);
|
||||
set_opt_val(i, val);
|
||||
return;
|
||||
}
|
||||
error("Illegal option -o %s", name);
|
||||
|
@ -244,21 +250,15 @@ minus_o(char *name, int val)
|
|||
STATIC void
|
||||
setoption(int flag, int val)
|
||||
{
|
||||
int i;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < NOPTS; i++)
|
||||
if (optlist[i].letter == flag) {
|
||||
optlist[i].val = val;
|
||||
if (val) {
|
||||
/* #%$ hack for ksh semantics */
|
||||
if (flag == 'V')
|
||||
Eflag = 0;
|
||||
else if (flag == 'E')
|
||||
Vflag = 0;
|
||||
}
|
||||
set_opt_val( i, val );
|
||||
return;
|
||||
}
|
||||
error("Illegal option -%c", flag);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
||||
|
@ -269,7 +269,7 @@ INCLUDE "options.h"
|
|||
SHELLPROC {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NOPTS; i++)
|
||||
for (i = 0; optlist[i].name; i++)
|
||||
optlist[i].val = 0;
|
||||
optschanged();
|
||||
|
||||
|
@ -288,7 +288,8 @@ setparam(char **argv)
|
|||
char **ap;
|
||||
int nparam;
|
||||
|
||||
for (nparam = 0 ; argv[nparam] ; nparam++);
|
||||
for (nparam = 0 ; argv[nparam] ; nparam++)
|
||||
continue;
|
||||
ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
|
||||
while (*argv) {
|
||||
*ap++ = savestr(*argv++);
|
||||
|
@ -307,7 +308,7 @@ setparam(char **argv)
|
|||
*/
|
||||
|
||||
void
|
||||
freeparam(struct shparam *param)
|
||||
freeparam(volatile struct shparam *param)
|
||||
{
|
||||
char **ap;
|
||||
|
||||
|
@ -358,7 +359,7 @@ int
|
|||
setcmd(int argc, char **argv)
|
||||
{
|
||||
if (argc == 1)
|
||||
return showvarscmd(argc, argv);
|
||||
return showvars(0, 0, 1);
|
||||
INTOFF;
|
||||
options(0);
|
||||
optschanged();
|
||||
|
@ -389,7 +390,7 @@ getoptsreset(const char *value)
|
|||
int
|
||||
getoptscmd(int argc, char **argv)
|
||||
{
|
||||
char **optbase = NULL;
|
||||
char **optbase;
|
||||
|
||||
if (argc < 3)
|
||||
error("usage: getopts optstring var [arg]");
|
||||
|
@ -409,17 +410,16 @@ getoptscmd(int argc, char **argv)
|
|||
}
|
||||
|
||||
STATIC int
|
||||
getopts(char *optstr, char *optvar, char **optfirst, char ***optnext,
|
||||
char **optptr)
|
||||
getopts(char *optstr, char *optvar, char **optfirst, char ***optnext, char **optpptr)
|
||||
{
|
||||
char *p, *q;
|
||||
char c = '?';
|
||||
int done = 0;
|
||||
int ind = 0;
|
||||
int err = 0;
|
||||
char s[10];
|
||||
char s[12];
|
||||
|
||||
if ((p = *optptr) == NULL || *p == '\0') {
|
||||
if ((p = *optpptr) == NULL || *p == '\0') {
|
||||
/* Current word is done, advance */
|
||||
if (*optnext == NULL)
|
||||
return 1;
|
||||
|
@ -444,10 +444,9 @@ atend:
|
|||
s[0] = c;
|
||||
s[1] = '\0';
|
||||
err |= setvarsafe("OPTARG", s, 0);
|
||||
}
|
||||
else {
|
||||
out1fmt("Illegal option -%c\n", c);
|
||||
(void) unsetvar("OPTARG");
|
||||
} else {
|
||||
outfmt(&errout, "Illegal option -%c\n", c);
|
||||
(void) unsetvar("OPTARG", 0);
|
||||
}
|
||||
c = '?';
|
||||
goto bad;
|
||||
|
@ -463,10 +462,9 @@ atend:
|
|||
s[1] = '\0';
|
||||
err |= setvarsafe("OPTARG", s, 0);
|
||||
c = ':';
|
||||
}
|
||||
else {
|
||||
out1fmt("No arg for -%c option\n", c);
|
||||
(void) unsetvar("OPTARG");
|
||||
} else {
|
||||
outfmt(&errout, "No arg for -%c option\n", c);
|
||||
(void) unsetvar("OPTARG", 0);
|
||||
c = '?';
|
||||
}
|
||||
goto bad;
|
||||
|
@ -474,11 +472,10 @@ atend:
|
|||
|
||||
if (p == **optnext)
|
||||
(*optnext)++;
|
||||
setvarsafe("OPTARG", p, 0);
|
||||
err |= setvarsafe("OPTARG", p, 0);
|
||||
p = NULL;
|
||||
}
|
||||
else
|
||||
setvarsafe("OPTARG", "", 0);
|
||||
} else
|
||||
err |= setvarsafe("OPTARG", "", 0);
|
||||
ind = *optnext - optfirst + 1;
|
||||
goto out;
|
||||
|
||||
|
@ -487,7 +484,7 @@ bad:
|
|||
*optnext = NULL;
|
||||
p = NULL;
|
||||
out:
|
||||
*optptr = p;
|
||||
*optpptr = p;
|
||||
fmtstr(s, sizeof(s), "%d", ind);
|
||||
err |= setvarsafe("OPTIND", s, VNOFUNC);
|
||||
s[0] = c;
|
||||
|
@ -495,7 +492,7 @@ out:
|
|||
err |= setvarsafe(optvar, s, 0);
|
||||
if (err) {
|
||||
*optnext = NULL;
|
||||
*optptr = NULL;
|
||||
*optpptr = NULL;
|
||||
flushall();
|
||||
exraise(EXERROR);
|
||||
}
|
||||
|
@ -514,9 +511,10 @@ out:
|
|||
*/
|
||||
|
||||
int
|
||||
nextopt(char *optstring)
|
||||
nextopt(const char *optstring)
|
||||
{
|
||||
char *p, *q;
|
||||
char *p;
|
||||
const char *q;
|
||||
char c;
|
||||
|
||||
if ((p = optptr) == NULL || *p == '\0') {
|
||||
|
@ -537,13 +535,9 @@ nextopt(char *optstring)
|
|||
if (*++q == ':') {
|
||||
if (*p == '\0' && (p = *argptr++) == NULL)
|
||||
error("No arg for -%c option", c);
|
||||
shoptarg = p;
|
||||
optionarg = p;
|
||||
p = NULL;
|
||||
}
|
||||
optptr = p;
|
||||
return c;
|
||||
}
|
||||
|
||||
/*
|
||||
* $PchId: options.c,v 1.6 2006/05/29 13:09:12 philip Exp $
|
||||
*/
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: options.h,v 1.20 2011/06/18 21:18:46 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -30,7 +32,6 @@
|
|||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)options.h 8.2 (Berkeley) 5/4/95
|
||||
* $FreeBSD: src/bin/sh/options.h,v 1.13 2004/04/06 20:06:51 markm Exp $
|
||||
*/
|
||||
|
||||
struct shparam {
|
||||
|
@ -43,57 +44,74 @@ struct shparam {
|
|||
};
|
||||
|
||||
|
||||
|
||||
#define eflag optlist[0].val
|
||||
#define fflag optlist[1].val
|
||||
#define Iflag optlist[2].val
|
||||
#define iflag optlist[3].val
|
||||
#define mflag optlist[4].val
|
||||
#define nflag optlist[5].val
|
||||
#define sflag optlist[6].val
|
||||
#define xflag optlist[7].val
|
||||
#define vflag optlist[8].val
|
||||
#define Vflag optlist[9].val
|
||||
#define Eflag optlist[10].val
|
||||
#define Cflag optlist[11].val
|
||||
#define aflag optlist[12].val
|
||||
#define bflag optlist[13].val
|
||||
#define uflag optlist[14].val
|
||||
#define privileged optlist[15].val
|
||||
#define Tflag optlist[16].val
|
||||
#define Pflag optlist[17].val
|
||||
|
||||
#define NOPTS 18
|
||||
|
||||
struct optent {
|
||||
const char *name;
|
||||
const char letter;
|
||||
char val;
|
||||
const char *name; /* for set -o <name> */
|
||||
const char letter; /* set [+/-]<letter> and $- */
|
||||
const char opt_set; /* mutually exclusive option set */
|
||||
unsigned char val; /* value of <letter>flag */
|
||||
};
|
||||
|
||||
/* Those marked [U] are required by posix, but have no effect! */
|
||||
|
||||
#ifdef DEFINE_OPTIONS
|
||||
struct optent optlist[NOPTS] = {
|
||||
{ "errexit", 'e', 0 },
|
||||
{ "noglob", 'f', 0 },
|
||||
{ "ignoreeof", 'I', 0 },
|
||||
{ "interactive",'i', 0 },
|
||||
{ "monitor", 'm', 0 },
|
||||
{ "noexec", 'n', 0 },
|
||||
{ "stdin", 's', 0 },
|
||||
{ "xtrace", 'x', 0 },
|
||||
{ "verbose", 'v', 0 },
|
||||
{ "vi", 'V', 0 },
|
||||
{ "emacs", 'E', 0 },
|
||||
{ "noclobber", 'C', 0 },
|
||||
{ "allexport", 'a', 0 },
|
||||
{ "notify", 'b', 0 },
|
||||
{ "nounset", 'u', 0 },
|
||||
{ "privileged", 'p', 0 },
|
||||
{ "trapsasync", 'T', 0 },
|
||||
{ "physical", 'P', 0 },
|
||||
};
|
||||
#define DEF_OPTS(name, letter, opt_set) {name, letter, opt_set, 0},
|
||||
struct optent optlist[] = {
|
||||
#else
|
||||
extern struct optent optlist[NOPTS];
|
||||
#define DEF_OPTS(name, letter, opt_set)
|
||||
#endif
|
||||
#define DEF_OPT(name,letter) DEF_OPTS(name, letter, 0)
|
||||
|
||||
DEF_OPT( "errexit", 'e' ) /* exit on error */
|
||||
#define eflag optlist[0].val
|
||||
DEF_OPT( "noglob", 'f' ) /* no pathname expansion */
|
||||
#define fflag optlist[1].val
|
||||
DEF_OPT( "ignoreeof", 'I' ) /* do not exit on EOF */
|
||||
#define Iflag optlist[2].val
|
||||
DEF_OPT( "interactive",'i' ) /* interactive shell */
|
||||
#define iflag optlist[3].val
|
||||
DEF_OPT( "monitor", 'm' ) /* job control */
|
||||
#define mflag optlist[4].val
|
||||
DEF_OPT( "noexec", 'n' ) /* [U] do not exec commands */
|
||||
#define nflag optlist[5].val
|
||||
DEF_OPT( "stdin", 's' ) /* read from stdin */
|
||||
#define sflag optlist[6].val
|
||||
DEF_OPT( "xtrace", 'x' ) /* trace after expansion */
|
||||
#define xflag optlist[7].val
|
||||
DEF_OPT( "verbose", 'v' ) /* trace read input */
|
||||
#define vflag optlist[8].val
|
||||
DEF_OPTS( "vi", 'V', 'V' ) /* vi style editing */
|
||||
#define Vflag optlist[9].val
|
||||
DEF_OPTS( "emacs", 'E', 'V' ) /* emacs style editing */
|
||||
#define Eflag optlist[10].val
|
||||
DEF_OPT( "noclobber", 'C' ) /* do not overwrite files with > */
|
||||
#define Cflag optlist[11].val
|
||||
DEF_OPT( "allexport", 'a' ) /* export all variables */
|
||||
#define aflag optlist[12].val
|
||||
DEF_OPT( "notify", 'b' ) /* [U] report completion of background jobs */
|
||||
#define bflag optlist[13].val
|
||||
DEF_OPT( "nounset", 'u' ) /* error expansion of unset variables */
|
||||
#define uflag optlist[14].val
|
||||
DEF_OPT( "quietprofile", 'q' )
|
||||
#define qflag optlist[15].val
|
||||
DEF_OPT( "nolog", 0 ) /* [U] no functon defs in command history */
|
||||
#define nolog optlist[16].val
|
||||
DEF_OPT( "cdprint", 0 ) /* always print result of cd */
|
||||
#define cdprint optlist[17].val
|
||||
DEF_OPT( "tabcomplete", 0 ) /* <tab> causes filename expansion */
|
||||
#define tabcomplete optlist[18].val
|
||||
#ifdef DEBUG
|
||||
DEF_OPT( "debug", 0 ) /* enable debug prints */
|
||||
#define debug optlist[19].val
|
||||
#endif
|
||||
|
||||
#ifdef DEFINE_OPTIONS
|
||||
{ 0, 0, 0, 0 },
|
||||
};
|
||||
#define NOPTS (sizeof optlist / sizeof optlist[0] - 1)
|
||||
int sizeof_optlist = sizeof optlist;
|
||||
#else
|
||||
extern struct optent optlist[];
|
||||
extern int sizeof_optlist;
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -101,20 +119,12 @@ extern char *minusc; /* argument to -c option */
|
|||
extern char *arg0; /* $0 */
|
||||
extern struct shparam shellparam; /* $@ */
|
||||
extern char **argptr; /* argument list for builtin commands */
|
||||
extern char *shoptarg; /* set by nextopt */
|
||||
extern char *optionarg; /* set by nextopt */
|
||||
extern char *optptr; /* used by nextopt */
|
||||
extern int editable; /* isatty(0) && isatty(1) */
|
||||
|
||||
void procargs(int, char **);
|
||||
void optschanged(void);
|
||||
void setparam(char **);
|
||||
void freeparam(struct shparam *);
|
||||
int shiftcmd(int, char **);
|
||||
int setcmd(int, char **);
|
||||
int getoptscmd(int, char **);
|
||||
int nextopt(char *);
|
||||
void freeparam(volatile struct shparam *);
|
||||
int nextopt(const char *);
|
||||
void getoptsreset(const char *);
|
||||
|
||||
/*
|
||||
* $PchId: options.h,v 1.5 2006/05/29 13:08:45 philip Exp $
|
||||
*/
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: output.c,v 1.33 2010/08/30 06:27:14 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -30,9 +32,12 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)output.c 8.1 (Berkeley) 5/31/93";
|
||||
static char sccsid[] = "@(#)output.c 8.2 (Berkeley) 5/4/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: output.c,v 1.33 2010/08/30 06:27:14 christos Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
|
@ -47,28 +52,26 @@ static char sccsid[] = "@(#)output.c 8.1 (Berkeley) 5/31/93";
|
|||
* Our output routines may be smaller than the stdio routines.
|
||||
*/
|
||||
|
||||
#include <sys/types.h> /* quad_t */
|
||||
#include <sys/param.h> /* BSD4_4 */
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <stdio.h> /* defines BUFSIZ */
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "shell.h"
|
||||
#include "syntax.h"
|
||||
#include "output.h"
|
||||
#include "memalloc.h"
|
||||
#include "error.h"
|
||||
#include "var.h"
|
||||
#ifdef __STDC__
|
||||
#include "stdarg.h"
|
||||
#else
|
||||
#include <varargs.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
#define OUTBUFSIZ BUFSIZ
|
||||
#define BLOCK_OUT -2 /* output to a fixed block of memory */
|
||||
#define MEM_OUT -3 /* output to dynamically allocated memory */
|
||||
#define OUTPUT_ERR 01 /* error occurred on output */
|
||||
|
||||
|
||||
struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
|
||||
|
@ -102,10 +105,7 @@ RESET {
|
|||
*/
|
||||
|
||||
void
|
||||
open_mem(block, length, file)
|
||||
char *block;
|
||||
int length;
|
||||
struct output *file;
|
||||
open_mem(char *block, int length, struct output *file)
|
||||
{
|
||||
file->nextc = block;
|
||||
file->nleft = --length;
|
||||
|
@ -116,18 +116,11 @@ open_mem(block, length, file)
|
|||
|
||||
|
||||
void
|
||||
out1str(p)
|
||||
const char *p;
|
||||
out1str(const char *p)
|
||||
{
|
||||
outstr(p, out1);
|
||||
}
|
||||
|
||||
void
|
||||
out1qstr(const char *p)
|
||||
{
|
||||
outqstr(p, out1);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
out2str(const char *p)
|
||||
|
@ -137,9 +130,7 @@ out2str(const char *p)
|
|||
|
||||
|
||||
void
|
||||
outstr(p, file)
|
||||
register const char *p;
|
||||
register struct output *file;
|
||||
outstr(const char *p, struct output *file)
|
||||
{
|
||||
while (*p)
|
||||
outc(*p++, file);
|
||||
|
@ -147,33 +138,41 @@ outstr(p, file)
|
|||
flushout(file);
|
||||
}
|
||||
|
||||
/* Like outstr(), but quote for re-input into the shell. */
|
||||
|
||||
void
|
||||
outqstr(const char *p, struct output *file)
|
||||
out2shstr(const char *p)
|
||||
{
|
||||
char ch;
|
||||
|
||||
if (p[strcspn(p, "|&;<>()$`\\\"'")] == '\0' && (!ifsset() ||
|
||||
p[strcspn(p, ifsval())] == '\0')) {
|
||||
outstr(p, file);
|
||||
return;
|
||||
outshstr(p, out2);
|
||||
}
|
||||
|
||||
out1c('\'');
|
||||
while ((ch = *p++) != '\0') {
|
||||
switch (ch) {
|
||||
case '\'':
|
||||
/*
|
||||
* Can't quote single quotes inside single quotes;
|
||||
* close them, write escaped single quote, open again.
|
||||
*/
|
||||
outstr("'\\''", file);
|
||||
break;
|
||||
default:
|
||||
outc(ch, file);
|
||||
|
||||
void
|
||||
outshstr(const char *p, struct output *file)
|
||||
{
|
||||
static const char norm_chars [] \
|
||||
= "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/-=";
|
||||
int need_q = p[0] == 0 || p[strspn(p, norm_chars)] != 0;
|
||||
char c;
|
||||
|
||||
if (need_q)
|
||||
outc('\'', file);
|
||||
|
||||
while (c = *p++, c != 0){
|
||||
if (c != '\''){
|
||||
outc(c, file);
|
||||
}else{
|
||||
outc('\'', file);
|
||||
outc('\\', file);
|
||||
outc(c, file);
|
||||
outc('\'', file);
|
||||
}
|
||||
}
|
||||
out1c('\'');
|
||||
|
||||
if (need_q)
|
||||
outc('\'', file);
|
||||
|
||||
if (file == out2)
|
||||
flushout(file);
|
||||
}
|
||||
|
||||
|
||||
|
@ -181,8 +180,7 @@ char out_junk[16];
|
|||
|
||||
|
||||
void
|
||||
emptyoutbuf(dest)
|
||||
struct output *dest;
|
||||
emptyoutbuf(struct output *dest)
|
||||
{
|
||||
int offset;
|
||||
|
||||
|
@ -212,15 +210,15 @@ emptyoutbuf(dest)
|
|||
|
||||
|
||||
void
|
||||
flushall() {
|
||||
flushall(void)
|
||||
{
|
||||
flushout(&output);
|
||||
flushout(&errout);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
flushout(dest)
|
||||
struct output *dest;
|
||||
flushout(struct output *dest)
|
||||
{
|
||||
|
||||
if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0)
|
||||
|
@ -233,7 +231,8 @@ flushout(dest)
|
|||
|
||||
|
||||
void
|
||||
freestdout() {
|
||||
freestdout(void)
|
||||
{
|
||||
INTOFF;
|
||||
if (output.buf) {
|
||||
ckfree(output.buf);
|
||||
|
@ -244,7 +243,6 @@ freestdout() {
|
|||
}
|
||||
|
||||
|
||||
#ifdef __STDC__
|
||||
void
|
||||
outfmt(struct output *file, const char *fmt, ...)
|
||||
{
|
||||
|
@ -266,8 +264,9 @@ out1fmt(const char *fmt, ...)
|
|||
va_end(ap);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
dbgprintf(const char *fmt, ...)
|
||||
debugprintf(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
|
@ -276,9 +275,10 @@ dbgprintf(const char *fmt, ...)
|
|||
va_end(ap);
|
||||
flushout(out2);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
fmtstr(char *outbuf, int length, const char *fmt, ...)
|
||||
fmtstr(char *outbuf, size_t length, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
struct output strout;
|
||||
|
@ -295,82 +295,11 @@ fmtstr(char *outbuf, int length, const char *fmt, ...)
|
|||
va_end(ap);
|
||||
}
|
||||
|
||||
#else /* not __STDC__ */
|
||||
|
||||
void
|
||||
outfmt(va_alist)
|
||||
va_dcl
|
||||
{
|
||||
va_list ap;
|
||||
struct output *file;
|
||||
char *fmt;
|
||||
|
||||
va_start(ap);
|
||||
file = va_arg(ap, struct output *);
|
||||
fmt = va_arg(ap, char *);
|
||||
doformat(file, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
out1fmt(va_alist)
|
||||
va_dcl
|
||||
{
|
||||
va_list ap;
|
||||
char *fmt;
|
||||
|
||||
va_start(ap);
|
||||
fmt = va_arg(ap, char *);
|
||||
doformat(out1, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
dbgprintf(va_alist)
|
||||
va_dcl
|
||||
{
|
||||
va_list ap;
|
||||
char *fmt;
|
||||
|
||||
va_start(ap);
|
||||
fmt = va_arg(ap, char *);
|
||||
doformat(out2, fmt, ap);
|
||||
va_end(ap);
|
||||
flushout(out2);
|
||||
}
|
||||
|
||||
void
|
||||
fmtstr(va_alist)
|
||||
va_dcl
|
||||
{
|
||||
va_list ap;
|
||||
struct output strout;
|
||||
char *outbuf;
|
||||
int length;
|
||||
char *fmt;
|
||||
|
||||
va_start(ap);
|
||||
outbuf = va_arg(ap, char *);
|
||||
length = va_arg(ap, int);
|
||||
fmt = va_arg(ap, char *);
|
||||
strout.nextc = outbuf;
|
||||
strout.nleft = length;
|
||||
strout.fd = BLOCK_OUT;
|
||||
strout.flags = 0;
|
||||
doformat(&strout, fmt, ap);
|
||||
outc('\0', &strout);
|
||||
if (strout.flags & OUTPUT_ERR)
|
||||
outbuf[length - 1] = '\0';
|
||||
}
|
||||
#endif /* __STDC__ */
|
||||
|
||||
|
||||
/*
|
||||
* Formatted output. This routine handles a subset of the printf formats:
|
||||
* - Formats supported: d, u, o, X, s, and c.
|
||||
* - Formats supported: d, u, o, p, X, s, and c.
|
||||
* - The x format is also accepted but is treated like X.
|
||||
* - The l modifier is accepted.
|
||||
* - The l, ll and q modifiers are accepted.
|
||||
* - The - and # flags are accepted; # only works with the o format.
|
||||
* - Width and precision may be specified with any format except c.
|
||||
* - An * may be given for the width or precision.
|
||||
|
@ -381,27 +310,40 @@ fmtstr(va_alist)
|
|||
|
||||
#define TEMPSIZE 24
|
||||
|
||||
#ifdef __STDC__
|
||||
static const char digit[16] = "0123456789ABCDEF";
|
||||
#else
|
||||
static const char digit[17] = "0123456789ABCDEF";
|
||||
#ifdef BSD4_4
|
||||
#define HAVE_VASPRINTF 1
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
doformat(struct output *dest, const char *f, va_list ap)
|
||||
{
|
||||
register char c;
|
||||
#if HAVE_VASPRINTF
|
||||
char *s;
|
||||
|
||||
vasprintf(&s, f, ap);
|
||||
if (s == NULL)
|
||||
error("Could not allocate formatted output buffer");
|
||||
outstr(s, dest);
|
||||
free(s);
|
||||
#else /* !HAVE_VASPRINTF */
|
||||
static const char digit[] = "0123456789ABCDEF";
|
||||
char c;
|
||||
char temp[TEMPSIZE];
|
||||
int flushleft;
|
||||
int sharp;
|
||||
int width;
|
||||
int prec;
|
||||
int islong;
|
||||
int isquad;
|
||||
char *p;
|
||||
int sign;
|
||||
#ifdef BSD4_4
|
||||
quad_t l;
|
||||
u_quad_t num;
|
||||
#else
|
||||
long l;
|
||||
unsigned long num;
|
||||
u_long num;
|
||||
#endif
|
||||
unsigned base;
|
||||
int len;
|
||||
int size;
|
||||
|
@ -417,6 +359,7 @@ doformat(struct output *dest, const char *f, va_list ap)
|
|||
width = 0;
|
||||
prec = -1;
|
||||
islong = 0;
|
||||
isquad = 0;
|
||||
for (;;) {
|
||||
if (*f == '-')
|
||||
flushleft++;
|
||||
|
@ -446,11 +389,23 @@ doformat(struct output *dest, const char *f, va_list ap)
|
|||
}
|
||||
}
|
||||
if (*f == 'l') {
|
||||
f++;
|
||||
if (*f == 'l') {
|
||||
isquad++;
|
||||
f++;
|
||||
} else
|
||||
islong++;
|
||||
} else if (*f == 'q') {
|
||||
isquad++;
|
||||
f++;
|
||||
}
|
||||
switch (*f) {
|
||||
case 'd':
|
||||
#ifdef BSD4_4
|
||||
if (isquad)
|
||||
l = va_arg(ap, quad_t);
|
||||
else
|
||||
#endif
|
||||
if (islong)
|
||||
l = va_arg(ap, long);
|
||||
else
|
||||
|
@ -469,12 +424,21 @@ doformat(struct output *dest, const char *f, va_list ap)
|
|||
case 'o':
|
||||
base = 8;
|
||||
goto uns_number;
|
||||
case 'p':
|
||||
outc('0', dest);
|
||||
outc('x', dest);
|
||||
/*FALLTHROUGH*/
|
||||
case 'x':
|
||||
/* we don't implement 'x'; treat like 'X' */
|
||||
case 'X':
|
||||
base = 16;
|
||||
uns_number: /* an unsigned number */
|
||||
sign = 0;
|
||||
#ifdef BSD4_4
|
||||
if (isquad)
|
||||
num = va_arg(ap, u_quad_t);
|
||||
else
|
||||
#endif
|
||||
if (islong)
|
||||
num = va_arg(ap, unsigned long);
|
||||
else
|
||||
|
@ -542,6 +506,7 @@ number: /* process a number */
|
|||
}
|
||||
f++;
|
||||
}
|
||||
#endif /* !HAVE_VASPRINTF */
|
||||
}
|
||||
|
||||
|
||||
|
@ -551,10 +516,7 @@ number: /* process a number */
|
|||
*/
|
||||
|
||||
int
|
||||
xwrite(fd, buf, nbytes)
|
||||
int fd;
|
||||
char *buf;
|
||||
int nbytes;
|
||||
xwrite(int fd, char *buf, int nbytes)
|
||||
{
|
||||
int ntry;
|
||||
int i;
|
||||
|
@ -578,6 +540,17 @@ xwrite(fd, buf, nbytes)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $PchId: output.c,v 1.6 2006/05/22 12:46:03 philip Exp $
|
||||
* Version of ioctl that retries after a signal is caught.
|
||||
* XXX unused function
|
||||
*/
|
||||
|
||||
int
|
||||
xioctl(int fd, unsigned long request, char *arg)
|
||||
{
|
||||
int i;
|
||||
|
||||
while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR);
|
||||
return i;
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: output.h,v 1.24 2012/03/15 02:02:20 joerg Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -30,7 +32,6 @@
|
|||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)output.h 8.2 (Berkeley) 5/4/95
|
||||
* $FreeBSD: src/bin/sh/output.h,v 1.13 2004/04/06 20:06:51 markm Exp $
|
||||
*/
|
||||
|
||||
#ifndef OUTPUT_INCL
|
||||
|
@ -46,41 +47,38 @@ struct output {
|
|||
short flags;
|
||||
};
|
||||
|
||||
/* flags for ->flags */
|
||||
#define OUTPUT_ERR 01 /* error occurred on output */
|
||||
|
||||
extern struct output output;
|
||||
extern struct output errout;
|
||||
extern struct output memout;
|
||||
extern struct output *out1;
|
||||
extern struct output *out2;
|
||||
|
||||
#ifndef __printflike
|
||||
#define __printflike(a,b)
|
||||
#endif
|
||||
|
||||
void open_mem(char *, int, struct output *);
|
||||
void out1str(const char *);
|
||||
void out1qstr(const char *);
|
||||
void out2str(const char *);
|
||||
void out2qstr(const char *);
|
||||
void outstr(const char *, struct output *);
|
||||
void outqstr(const char *, struct output *);
|
||||
void out2shstr(const char *);
|
||||
void outshstr(const char *, struct output *);
|
||||
void emptyoutbuf(struct output *);
|
||||
void flushall(void);
|
||||
void flushout(struct output *);
|
||||
void freestdout(void);
|
||||
void outfmt(struct output *, const char *, ...) __printflike(2, 3);
|
||||
void out1fmt(const char *, ...) __printflike(1, 2);
|
||||
void dbgprintf(const char *, ...) __printflike(1, 2);
|
||||
void fmtstr(char *, int, const char *, ...) __printflike(3, 4);
|
||||
#ifdef DEBUG
|
||||
void debugprintf(const char *, ...) __printflike(1, 2);
|
||||
#endif
|
||||
void fmtstr(char *, size_t, const char *, ...) __printflike(3, 4);
|
||||
void doformat(struct output *, const char *, va_list) __printflike(2, 0);
|
||||
int xwrite(int, char *, int);
|
||||
int xioctl(int, unsigned long, char *);
|
||||
|
||||
#define outc(c, file) (--(file)->nleft < 0? (emptyoutbuf(file), *(file)->nextc++ = (c)) : (*(file)->nextc++ = (c)))
|
||||
#define out1c(c) outc(c, out1);
|
||||
#define out2c(c) outc(c, out2);
|
||||
#define out1c(c) outc(c, out1)
|
||||
#define out2c(c) outc(c, out2)
|
||||
|
||||
#define OUTPUT_INCL
|
||||
#endif
|
||||
|
||||
/*
|
||||
* $PchId: output.h,v 1.5 2006/05/23 12:04:54 philip Exp $
|
||||
*/
|
File diff suppressed because it is too large
Load diff
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: parser.h,v 1.18 2013/10/02 19:52:58 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -30,23 +32,27 @@
|
|||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)parser.h 8.3 (Berkeley) 5/4/95
|
||||
* $FreeBSD: src/bin/sh/parser.h,v 1.10 2004/04/06 20:06:51 markm Exp $
|
||||
*/
|
||||
|
||||
/* control characters in argument strings */
|
||||
#define CTLESC '\201'
|
||||
#define CTLVAR '\202'
|
||||
#define CTL_FIRST '\201' /* first 'special' character */
|
||||
#define CTLESC '\201' /* escape next character */
|
||||
#define CTLVAR '\202' /* variable defn */
|
||||
#define CTLENDVAR '\203'
|
||||
#define CTLBACKQ '\204'
|
||||
#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
|
||||
/* CTLBACKQ | CTLQUOTE == '\205' */
|
||||
#define CTLARI '\206'
|
||||
#define CTLARI '\206' /* arithmetic expression */
|
||||
#define CTLENDARI '\207'
|
||||
#define CTLQUOTEMARK '\210'
|
||||
#define CTLQUOTEEND '\211' /* only inside ${...} */
|
||||
#define CTL_LAST '\211' /* last 'special' character */
|
||||
|
||||
/* variable substitution byte (follows CTLVAR) */
|
||||
#define VSTYPE 0x0f /* type of variable substitution */
|
||||
#define VSNUL 0x10 /* colon--treat the empty string as unset */
|
||||
#define VSLINENO 0x20 /* expansion of $LINENO, the line number
|
||||
follows immediately */
|
||||
#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
|
||||
|
||||
/* values of VSTYPE field */
|
||||
|
@ -75,8 +81,4 @@ extern int whichprompt; /* 1 == PS1, 2 == PS2 */
|
|||
union node *parsecmd(int);
|
||||
void fixredir(union node *, const char *, int);
|
||||
int goodname(char *);
|
||||
char *getprompt(void *);
|
||||
|
||||
/*
|
||||
* $PchId: parser.h,v 1.3 2006/03/29 14:33:35 philip Exp $
|
||||
*/
|
||||
const char *getprompt(void *);
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: redir.c,v 1.35 2013/06/27 23:22:04 yamt Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -30,18 +32,17 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)redir.c 8.2 (Berkeley) 5/4/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: redir.c,v 1.35 2013/06/27 23:22:04 yamt Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
/*
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/bin/sh/redir.c,v 1.26 2004/04/06 20:06:51 markm Exp $");
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/param.h> /* PIPE_BUF */
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
|
@ -53,25 +54,31 @@ __FBSDID("$FreeBSD: src/bin/sh/redir.c,v 1.26 2004/04/06 20:06:51 markm Exp $");
|
|||
* Code for dealing with input/output redirection.
|
||||
*/
|
||||
|
||||
#include "main.h"
|
||||
#include "shell.h"
|
||||
#include "nodes.h"
|
||||
#include "jobs.h"
|
||||
#include "options.h"
|
||||
#include "expand.h"
|
||||
#include "redir.h"
|
||||
#include "output.h"
|
||||
#include "memalloc.h"
|
||||
#include "error.h"
|
||||
#include "options.h"
|
||||
|
||||
|
||||
#define EMPTY -2 /* marks an unused slot in redirtab */
|
||||
#define CLOSED -1 /* fd was not open before redir */
|
||||
#ifndef PIPE_BUF
|
||||
# define PIPESIZE 4096 /* amount of buffering in a pipe */
|
||||
#else
|
||||
# define PIPESIZE PIPE_BUF
|
||||
#endif
|
||||
|
||||
|
||||
MKINIT
|
||||
struct redirtab {
|
||||
struct redirtab *next;
|
||||
int renamed[10];
|
||||
short renamed[10];
|
||||
};
|
||||
|
||||
|
||||
|
@ -82,10 +89,10 @@ MKINIT struct redirtab *redirlist;
|
|||
* background commands, where we want to redirect fd0 to /dev/null only
|
||||
* if it hasn't already been redirected.
|
||||
*/
|
||||
STATIC int fd0_redirected = 0;
|
||||
int fd0_redirected = 0;
|
||||
|
||||
STATIC void openredirect(union node *, char[10 ]);
|
||||
STATIC int openhere(union node *);
|
||||
STATIC void openredirect(union node *, char[10], int);
|
||||
STATIC int openhere(const union node *);
|
||||
|
||||
|
||||
/*
|
||||
|
@ -103,13 +110,15 @@ redirect(union node *redir, int flags)
|
|||
struct redirtab *sv = NULL;
|
||||
int i;
|
||||
int fd;
|
||||
int try;
|
||||
char memory[10]; /* file descriptors to write to memory */
|
||||
|
||||
for (i = 10 ; --i >= 0 ; )
|
||||
memory[i] = 0;
|
||||
memory[1] = flags & REDIR_BACKQ;
|
||||
if (flags & REDIR_PUSH) {
|
||||
/* We don't have to worry about REDIR_VFORK here, as
|
||||
* flags & REDIR_PUSH is never true if REDIR_VFORK is set.
|
||||
*/
|
||||
sv = ckmalloc(sizeof (struct redirtab));
|
||||
for (i = 0 ; i < 10 ; i++)
|
||||
sv->renamed[i] = EMPTY;
|
||||
|
@ -118,38 +127,32 @@ redirect(union node *redir, int flags)
|
|||
}
|
||||
for (n = redir ; n ; n = n->nfile.next) {
|
||||
fd = n->nfile.fd;
|
||||
try = 0;
|
||||
if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
|
||||
n->ndup.dupfd == fd)
|
||||
continue; /* redirect from/to same file descriptor */
|
||||
|
||||
if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
|
||||
INTOFF;
|
||||
again:
|
||||
if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
|
||||
switch (errno) {
|
||||
case EBADF:
|
||||
if (!try) {
|
||||
openredirect(n, memory);
|
||||
try++;
|
||||
goto again;
|
||||
}
|
||||
/* FALLTHROUGH*/
|
||||
i = CLOSED;
|
||||
break;
|
||||
default:
|
||||
INTON;
|
||||
error("%d: %s", fd, strerror(errno));
|
||||
break;
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
if (!try) {
|
||||
} else
|
||||
(void)fcntl(i, F_SETFD, FD_CLOEXEC);
|
||||
sv->renamed[fd] = i;
|
||||
}
|
||||
INTON;
|
||||
} else {
|
||||
close(fd);
|
||||
}
|
||||
if (fd == 0)
|
||||
fd0_redirected++;
|
||||
if (!try)
|
||||
openredirect(n, memory);
|
||||
openredirect(n, memory, flags);
|
||||
}
|
||||
if (memory[1])
|
||||
out1 = &memout;
|
||||
|
@ -159,15 +162,12 @@ again:
|
|||
|
||||
|
||||
STATIC void
|
||||
openredirect(union node *redir, char memory[10])
|
||||
openredirect(union node *redir, char memory[10], int flags)
|
||||
{
|
||||
struct stat sb;
|
||||
int fd = redir->nfile.fd;
|
||||
char *fname;
|
||||
int f;
|
||||
|
||||
/* Assume redirection succeeds. */
|
||||
{ extern int exitstatus; exitstatus = 0; }
|
||||
int oflags = O_WRONLY|O_CREAT|O_TRUNC, eflags;
|
||||
|
||||
/*
|
||||
* We suppress interrupts so that we won't leave open file
|
||||
|
@ -179,56 +179,64 @@ openredirect(union node *redir, char memory[10])
|
|||
switch (redir->nfile.type) {
|
||||
case NFROM:
|
||||
fname = redir->nfile.expfname;
|
||||
if ((f = open(fname, O_RDONLY)) < 0)
|
||||
error("cannot open %s: %s", fname, strerror(errno));
|
||||
movefd:
|
||||
if (f != fd) {
|
||||
dup2(f, fd);
|
||||
close(f);
|
||||
}
|
||||
if (flags & REDIR_VFORK)
|
||||
eflags = O_NONBLOCK;
|
||||
else
|
||||
eflags = 0;
|
||||
if ((f = open(fname, O_RDONLY|eflags)) < 0)
|
||||
goto eopen;
|
||||
if (eflags)
|
||||
(void)fcntl(f, F_SETFL, fcntl(f, F_GETFL, 0) & ~eflags);
|
||||
break;
|
||||
case NFROMTO:
|
||||
fname = redir->nfile.expfname;
|
||||
if ((f = open(fname, O_RDWR|O_CREAT, 0666)) < 0)
|
||||
error("cannot create %s: %s", fname, strerror(errno));
|
||||
goto movefd;
|
||||
if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
|
||||
goto ecreate;
|
||||
break;
|
||||
case NTO:
|
||||
fname = redir->nfile.expfname;
|
||||
if (Cflag && stat(fname, &sb) != -1 && S_ISREG(sb.st_mode))
|
||||
error("cannot create %s: %s", fname,
|
||||
strerror(EEXIST));
|
||||
if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
|
||||
error("cannot create %s: %s", fname, strerror(errno));
|
||||
goto movefd;
|
||||
if (Cflag)
|
||||
oflags |= O_EXCL;
|
||||
/* FALLTHROUGH */
|
||||
case NCLOBBER:
|
||||
fname = redir->nfile.expfname;
|
||||
if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
|
||||
error("cannot create %s: %s", fname, strerror(errno));
|
||||
goto movefd;
|
||||
if ((f = open(fname, oflags, 0666)) < 0)
|
||||
goto ecreate;
|
||||
break;
|
||||
case NAPPEND:
|
||||
fname = redir->nfile.expfname;
|
||||
if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
|
||||
error("cannot create %s: %s", fname, strerror(errno));
|
||||
goto movefd;
|
||||
goto ecreate;
|
||||
break;
|
||||
case NTOFD:
|
||||
case NFROMFD:
|
||||
if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
|
||||
if (memory[redir->ndup.dupfd])
|
||||
memory[fd] = 1;
|
||||
else
|
||||
dup2(redir->ndup.dupfd, fd);
|
||||
} else {
|
||||
close(fd);
|
||||
copyfd(redir->ndup.dupfd, fd, 1);
|
||||
}
|
||||
break;
|
||||
INTON;
|
||||
return;
|
||||
case NHERE:
|
||||
case NXHERE:
|
||||
f = openhere(redir);
|
||||
goto movefd;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
if (f != fd) {
|
||||
copyfd(f, fd, 1);
|
||||
close(f);
|
||||
}
|
||||
INTON;
|
||||
return;
|
||||
ecreate:
|
||||
exerrno = 1;
|
||||
error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
|
||||
eopen:
|
||||
exerrno = 1;
|
||||
error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
|
||||
}
|
||||
|
||||
|
||||
|
@ -239,13 +247,13 @@ movefd:
|
|||
*/
|
||||
|
||||
STATIC int
|
||||
openhere(union node *redir)
|
||||
openhere(const union node *redir)
|
||||
{
|
||||
int pip[2];
|
||||
int len = 0;
|
||||
|
||||
if (pipe(pip) < 0)
|
||||
error("Pipe call failed: %s", strerror(errno));
|
||||
error("Pipe call failed");
|
||||
if (redir->type == NHERE) {
|
||||
len = strlen(redir->nhere.doc->narg.text);
|
||||
if (len <= PIPESIZE) {
|
||||
|
@ -253,12 +261,14 @@ openhere(union node *redir)
|
|||
goto out;
|
||||
}
|
||||
}
|
||||
if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
|
||||
if (forkshell(NULL, NULL, FORK_NOJOB) == 0) {
|
||||
close(pip[0]);
|
||||
signal(SIGINT, SIG_IGN);
|
||||
signal(SIGQUIT, SIG_IGN);
|
||||
signal(SIGHUP, SIG_IGN);
|
||||
#ifdef SIGTSTP
|
||||
signal(SIGTSTP, SIG_IGN);
|
||||
#endif
|
||||
signal(SIGPIPE, SIG_DFL);
|
||||
if (redir->type == NHERE)
|
||||
xwrite(pip[1], redir->nhere.doc->narg.text, len);
|
||||
|
@ -287,11 +297,10 @@ popredir(void)
|
|||
if (rp->renamed[i] != EMPTY) {
|
||||
if (i == 0)
|
||||
fd0_redirected--;
|
||||
if (rp->renamed[i] >= 0) {
|
||||
dup2(rp->renamed[i], i);
|
||||
close(rp->renamed[i]);
|
||||
} else {
|
||||
close(i);
|
||||
if (rp->renamed[i] >= 0) {
|
||||
copyfd(rp->renamed[i], i, 1);
|
||||
close(rp->renamed[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -315,15 +324,14 @@ RESET {
|
|||
}
|
||||
|
||||
SHELLPROC {
|
||||
clearredir();
|
||||
clearredir(0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Return true if fd 0 has already been redirected at least once. */
|
||||
int
|
||||
fd0_redirected_p(void)
|
||||
{
|
||||
fd0_redirected_p (void) {
|
||||
return fd0_redirected != 0;
|
||||
}
|
||||
|
||||
|
@ -332,7 +340,7 @@ fd0_redirected_p(void)
|
|||
*/
|
||||
|
||||
void
|
||||
clearredir(void)
|
||||
clearredir(int vforked)
|
||||
{
|
||||
struct redirtab *rp;
|
||||
int i;
|
||||
|
@ -342,11 +350,34 @@ clearredir(void)
|
|||
if (rp->renamed[i] >= 0) {
|
||||
close(rp->renamed[i]);
|
||||
}
|
||||
if (!vforked)
|
||||
rp->renamed[i] = EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* $PchId: redir.c,v 1.5 2006/05/22 12:27:37 philip Exp $
|
||||
* Copy a file descriptor to be >= to. Returns -1
|
||||
* if the source file descriptor is closed, EMPTY if there are no unused
|
||||
* file descriptors left.
|
||||
*/
|
||||
|
||||
int
|
||||
copyfd(int from, int to, int equal)
|
||||
{
|
||||
int newfd;
|
||||
|
||||
if (equal)
|
||||
newfd = dup2(from, to);
|
||||
else
|
||||
newfd = fcntl(from, F_DUPFD, to);
|
||||
if (newfd < 0) {
|
||||
if (errno == EMFILE)
|
||||
return EMPTY;
|
||||
else
|
||||
error("%d: %s", from, strerror(errno));
|
||||
}
|
||||
return newfd;
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: redir.h,v 1.16 2011/02/17 15:13:49 pooka Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -30,20 +32,17 @@
|
|||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)redir.h 8.2 (Berkeley) 5/4/95
|
||||
* $FreeBSD: src/bin/sh/redir.h,v 1.10 2004/04/06 20:06:51 markm Exp $
|
||||
*/
|
||||
|
||||
/* flags passed to redirect */
|
||||
#define REDIR_PUSH 01 /* save previous values of file descriptors */
|
||||
#define REDIR_BACKQ 02 /* save the command output in memory */
|
||||
#define REDIR_VFORK 04 /* running under vfork(2), be careful */
|
||||
|
||||
union node;
|
||||
void redirect(union node *, int);
|
||||
void popredir(void);
|
||||
int fd0_redirected_p(void);
|
||||
void clearredir(void);
|
||||
void clearredir(int);
|
||||
int copyfd(int, int, int);
|
||||
|
||||
|
||||
/*
|
||||
* $PchId: redir.h,v 1.3 2006/03/29 14:13:34 philip Exp $
|
||||
*/
|
2002
bin/sh/sh.1
Normal file
2002
bin/sh/sh.1
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: shell.h,v 1.18 2013/04/28 17:01:28 dholland Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -30,57 +32,58 @@
|
|||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)shell.h 8.2 (Berkeley) 5/4/95
|
||||
* $FreeBSD: src/bin/sh/shell.h,v 1.17 2004/04/06 20:06:51 markm Exp $
|
||||
*/
|
||||
|
||||
#include <sys/types.h> /* for mode_t */
|
||||
|
||||
/*
|
||||
* The follow should be set to reflect the type of system you have:
|
||||
* JOBS -> 1 if you have Berkeley job control, 0 otherwise.
|
||||
* TILDE -> 1 if you want the shell to expand ~logname.
|
||||
* USEGETPW -> 1 if getpwnam() must be used to look up a name.
|
||||
* READLINE -> 1 if line editing by readline() should be enabled.
|
||||
* SHORTNAMES -> 1 if your linker cannot handle long names.
|
||||
* define BSD if you are running 4.2 BSD or later.
|
||||
* define SYSV if you are running under System V.
|
||||
* define DEBUG=1 to compile in debugging (set global "debug" to turn on)
|
||||
* define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
|
||||
* define DEBUG=2 to compile in and turn on debugging.
|
||||
* define DO_SHAREDVFORK to indicate that vfork(2) shares its address
|
||||
* with its parent.
|
||||
*
|
||||
* When debugging is on, debugging info will be written to $HOME/trace and
|
||||
* When debugging is on, debugging info will be written to ./trace and
|
||||
* a quit signal will generate a core dump.
|
||||
*/
|
||||
|
||||
#ifndef JOBS
|
||||
#include <sys/param.h>
|
||||
|
||||
#if defined(__minix)
|
||||
#define JOBS 0
|
||||
#else
|
||||
#define JOBS 1
|
||||
#endif
|
||||
#endif /* defined(__minix) */
|
||||
#ifndef BSD
|
||||
#define BSD 1
|
||||
#endif
|
||||
#ifndef DEBUG
|
||||
#define DEBUG 0
|
||||
#endif
|
||||
#define POSIX 1
|
||||
|
||||
/*
|
||||
* Type of used arithmetics. SUSv3 requires us to have at least signed long.
|
||||
*/
|
||||
typedef long arith_t;
|
||||
#define ARITH_FORMAT_STR "%ld"
|
||||
#define atoarith_t(arg) strtol(arg, NULL, 0)
|
||||
#define strtoarith_t(nptr, endptr, base) strtol(nptr, endptr, base)
|
||||
#ifndef DO_SHAREDVFORK
|
||||
#if !defined(__minix)
|
||||
#if __NetBSD_Version__ >= 104000000
|
||||
#define DO_SHAREDVFORK
|
||||
#endif
|
||||
#endif /* !defined(__minix) */
|
||||
#endif
|
||||
|
||||
typedef void *pointer;
|
||||
#define STATIC static
|
||||
#ifndef NULL
|
||||
#define NULL (void *)0
|
||||
#endif
|
||||
#define STATIC /* empty */
|
||||
#define MKINIT /* empty */
|
||||
|
||||
extern char nullstr[1]; /* null string */
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#if DEBUG
|
||||
#define TRACE(param) sh_trace param
|
||||
extern const char nullstr[1]; /* null string */
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
#define TRACE(param) trace param
|
||||
#define TRACEV(param) tracev param
|
||||
#else
|
||||
#define TRACE(param)
|
||||
#define TRACEV(param)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* $PchId: shell.h,v 1.7 2006/05/22 12:47:00 philip Exp $
|
||||
*/
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: show.c,v 1.28 2011/08/23 10:01:32 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -30,39 +32,37 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)show.c 8.3 (Berkeley) 5/4/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: show.c,v 1.28 2011/08/23 10:01:32 christos Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
/*
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/bin/sh/show.c,v 1.21 2004/04/06 20:06:51 markm Exp $");
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "shell.h"
|
||||
#include "parser.h"
|
||||
#include "nodes.h"
|
||||
#include "mystring.h"
|
||||
#include "show.h"
|
||||
#include "options.h"
|
||||
|
||||
#if DEBUG
|
||||
static void trputc(int c);
|
||||
|
||||
#ifdef DEBUG
|
||||
static void shtree(union node *, int, char *, FILE*);
|
||||
static void shcmd(union node *, FILE *);
|
||||
static void sharg(union node *, FILE *);
|
||||
static void indent(int, char *, FILE *);
|
||||
static void trstring(char *);
|
||||
static void showtree(union node *n);
|
||||
|
||||
|
||||
static void
|
||||
void
|
||||
showtree(union node *n)
|
||||
{
|
||||
trputs("showtree called\n");
|
||||
|
@ -74,7 +74,7 @@ static void
|
|||
shtree(union node *n, int ind, char *pfx, FILE *fp)
|
||||
{
|
||||
struct nodelist *lp;
|
||||
char *s;
|
||||
const char *s;
|
||||
|
||||
if (n == NULL)
|
||||
return;
|
||||
|
@ -126,7 +126,7 @@ shcmd(union node *cmd, FILE *fp)
|
|||
{
|
||||
union node *np;
|
||||
int first;
|
||||
char *s;
|
||||
const char *s;
|
||||
int dftfd;
|
||||
|
||||
first = 1;
|
||||
|
@ -141,22 +141,19 @@ shcmd(union node *cmd, FILE *fp)
|
|||
putchar(' ');
|
||||
switch (np->nfile.type) {
|
||||
case NTO: s = ">"; dftfd = 1; break;
|
||||
case NCLOBBER: s = ">|"; dftfd = 1; break;
|
||||
case NAPPEND: s = ">>"; dftfd = 1; break;
|
||||
case NTOFD: s = ">&"; dftfd = 1; break;
|
||||
case NCLOBBER: s = ">|"; dftfd = 1; break;
|
||||
case NFROM: s = "<"; dftfd = 0; break;
|
||||
case NFROMTO: s = "<>"; dftfd = 0; break;
|
||||
case NFROMFD: s = "<&"; dftfd = 0; break;
|
||||
case NFROMTO: s = "<>"; dftfd = 0; break;
|
||||
default: s = "*error*"; dftfd = 0; break;
|
||||
}
|
||||
if (np->nfile.fd != dftfd)
|
||||
fprintf(fp, "%d", np->nfile.fd);
|
||||
fputs(s, fp);
|
||||
if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
|
||||
if (np->ndup.dupfd >= 0)
|
||||
fprintf(fp, "%d", np->ndup.dupfd);
|
||||
else
|
||||
fprintf(fp, "-");
|
||||
} else {
|
||||
sharg(np->nfile.fname, fp);
|
||||
}
|
||||
|
@ -175,7 +172,6 @@ sharg(union node *arg, FILE *fp)
|
|||
|
||||
if (arg->type != NARG) {
|
||||
printf("<node type %d>\n", arg->type);
|
||||
fflush(stdout);
|
||||
abort();
|
||||
}
|
||||
bqlist = arg->narg.backquote;
|
||||
|
@ -262,6 +258,8 @@ indent(int amount, char *pfx, FILE *fp)
|
|||
putc('\t', fp);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
@ -271,46 +269,52 @@ indent(int amount, char *pfx, FILE *fp)
|
|||
|
||||
FILE *tracefile;
|
||||
|
||||
#if DEBUG == 2
|
||||
int debug = 1;
|
||||
#else
|
||||
int debug = 0;
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
#ifdef DEBUG
|
||||
void
|
||||
trputc(int c)
|
||||
{
|
||||
if (tracefile == NULL)
|
||||
if (debug != 1 || !tracefile)
|
||||
return;
|
||||
putc(c, tracefile);
|
||||
if (c == '\n')
|
||||
fflush(tracefile);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void
|
||||
sh_trace(const char *fmt, ...)
|
||||
trace(const char *fmt, ...)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
if (tracefile != NULL) {
|
||||
(void) vfprintf(tracefile, fmt, va);
|
||||
if (strchr(fmt, '\n'))
|
||||
(void) fflush(tracefile);
|
||||
}
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
if (debug != 1 || !tracefile)
|
||||
return;
|
||||
va_start(va, fmt);
|
||||
(void) vfprintf(tracefile, fmt, va);
|
||||
va_end(va);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
trputs(char *s)
|
||||
tracev(const char *fmt, va_list va)
|
||||
{
|
||||
if (tracefile == NULL)
|
||||
#ifdef DEBUG
|
||||
va_list ap;
|
||||
if (debug != 1 || !tracefile)
|
||||
return;
|
||||
va_copy(ap, va);
|
||||
(void) vfprintf(tracefile, fmt, ap);
|
||||
va_end(ap);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
trputs(const char *s)
|
||||
{
|
||||
if (debug != 1 || !tracefile)
|
||||
return;
|
||||
fputs(s, tracefile);
|
||||
if (strchr(s, '\n'))
|
||||
fflush(tracefile);
|
||||
}
|
||||
|
||||
|
||||
|
@ -320,7 +324,7 @@ trstring(char *s)
|
|||
char *p;
|
||||
char c;
|
||||
|
||||
if (tracefile == NULL)
|
||||
if (debug != 1 || !tracefile)
|
||||
return;
|
||||
putc('"', tracefile);
|
||||
for (p = s ; *p ; p++) {
|
||||
|
@ -352,12 +356,14 @@ backslash: putc('\\', tracefile);
|
|||
}
|
||||
putc('"', tracefile);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
trargs(char **ap)
|
||||
{
|
||||
if (tracefile == NULL)
|
||||
#ifdef DEBUG
|
||||
if (debug != 1 || !tracefile)
|
||||
return;
|
||||
while (*ap) {
|
||||
trstring(*ap++);
|
||||
|
@ -366,18 +372,25 @@ trargs(char **ap)
|
|||
else
|
||||
putc('\n', tracefile);
|
||||
}
|
||||
fflush(tracefile);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
opentrace(void)
|
||||
{
|
||||
char s[100];
|
||||
#ifdef O_APPEND
|
||||
int flags;
|
||||
#endif
|
||||
|
||||
if (!debug)
|
||||
if (debug != 1) {
|
||||
if (tracefile)
|
||||
fflush(tracefile);
|
||||
/* leave open because libedit might be using it */
|
||||
return;
|
||||
}
|
||||
#ifdef not_this_way
|
||||
{
|
||||
char *p;
|
||||
|
@ -391,19 +404,27 @@ opentrace(void)
|
|||
strcat(s, "/trace");
|
||||
}
|
||||
#else
|
||||
scopy("./trace", s);
|
||||
snprintf(s, sizeof(s), "./trace.%d", (int)getpid());
|
||||
#endif /* not_this_way */
|
||||
if ((tracefile = fopen(s, "a")) == NULL) {
|
||||
fprintf(stderr, "Can't open %s: %s\n", s, strerror(errno));
|
||||
if (tracefile) {
|
||||
if (!freopen(s, "a", tracefile)) {
|
||||
fprintf(stderr, "Can't re-open %s\n", s);
|
||||
tracefile = NULL;
|
||||
debug = 0;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if ((tracefile = fopen(s, "a")) == NULL) {
|
||||
fprintf(stderr, "Can't open %s\n", s);
|
||||
debug = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
#ifdef O_APPEND
|
||||
if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
|
||||
fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
|
||||
#endif
|
||||
setlinebuf(tracefile);
|
||||
fputs("\nTracing started.\n", tracefile);
|
||||
fflush(tracefile);
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
/*
|
||||
* $PchId: show.c,v 1.6 2006/05/22 12:27:51 philip Exp $
|
||||
*/
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: show.h,v 1.7 2003/08/07 09:05:38 agc Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1995
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -10,7 +12,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -27,16 +29,17 @@
|
|||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)show.h 1.1 (Berkeley) 5/4/95
|
||||
* $FreeBSD: src/bin/sh/show.h,v 1.11 2004/04/06 20:06:51 markm Exp $
|
||||
*/
|
||||
|
||||
#ifdef DEBUG
|
||||
void sh_trace(const char *, ...);
|
||||
#include <stdarg.h>
|
||||
|
||||
union node;
|
||||
void showtree(union node *);
|
||||
void trace(const char *, ...);
|
||||
void tracev(const char *, va_list);
|
||||
void trargs(char **);
|
||||
void trputs(char *);
|
||||
#ifdef DEBUG
|
||||
void trputc(int);
|
||||
void trputs(const char *);
|
||||
void opentrace(void);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* $PchId: show.h,v 1.4 2006/03/29 13:28:45 philip Exp $
|
||||
*/
|
105
bin/sh/syntax.c
Normal file
105
bin/sh/syntax.c
Normal file
|
@ -0,0 +1,105 @@
|
|||
/* $NetBSD: syntax.c,v 1.3 2012/03/28 20:11:25 christos Exp $ */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: syntax.c,v 1.3 2012/03/28 20:11:25 christos Exp $");
|
||||
|
||||
#include <limits.h>
|
||||
#include "shell.h"
|
||||
#include "syntax.h"
|
||||
#include "parser.h"
|
||||
|
||||
#if CWORD != 0
|
||||
#error initialisation assumes 'CWORD' is zero
|
||||
#endif
|
||||
|
||||
#define ndx(ch) (ch + 1 - CHAR_MIN)
|
||||
#define set(ch, val) [ndx(ch)] = val,
|
||||
#define set_range(s, e, val) [ndx(s) ... ndx(e)] = val,
|
||||
|
||||
/* syntax table used when not in quotes */
|
||||
const char basesyntax[257] = { CEOF,
|
||||
set_range(CTL_FIRST, CTL_LAST, CCTL)
|
||||
set('\n', CNL)
|
||||
set('\\', CBACK)
|
||||
set('\'', CSQUOTE)
|
||||
set('"', CDQUOTE)
|
||||
set('`', CBQUOTE)
|
||||
set('$', CVAR)
|
||||
set('}', CENDVAR)
|
||||
set('<', CSPCL)
|
||||
set('>', CSPCL)
|
||||
set('(', CSPCL)
|
||||
set(')', CSPCL)
|
||||
set(';', CSPCL)
|
||||
set('&', CSPCL)
|
||||
set('|', CSPCL)
|
||||
set(' ', CSPCL)
|
||||
set('\t', CSPCL)
|
||||
};
|
||||
|
||||
/* syntax table used when in double quotes */
|
||||
const char dqsyntax[257] = { CEOF,
|
||||
set_range(CTL_FIRST, CTL_LAST, CCTL)
|
||||
set('\n', CNL)
|
||||
set('\\', CBACK)
|
||||
set('"', CDQUOTE)
|
||||
set('`', CBQUOTE)
|
||||
set('$', CVAR)
|
||||
set('}', CENDVAR)
|
||||
/* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
|
||||
set('!', CCTL)
|
||||
set('*', CCTL)
|
||||
set('?', CCTL)
|
||||
set('[', CCTL)
|
||||
set('=', CCTL)
|
||||
set('~', CCTL)
|
||||
set(':', CCTL)
|
||||
set('/', CCTL)
|
||||
set('-', CCTL)
|
||||
};
|
||||
|
||||
/* syntax table used when in single quotes */
|
||||
const char sqsyntax[257] = { CEOF,
|
||||
set_range(CTL_FIRST, CTL_LAST, CCTL)
|
||||
set('\n', CNL)
|
||||
set('\'', CSQUOTE)
|
||||
/* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
|
||||
set('!', CCTL)
|
||||
set('*', CCTL)
|
||||
set('?', CCTL)
|
||||
set('[', CCTL)
|
||||
set('=', CCTL)
|
||||
set('~', CCTL)
|
||||
set(':', CCTL)
|
||||
set('/', CCTL)
|
||||
set('-', CCTL)
|
||||
};
|
||||
|
||||
/* syntax table used when in arithmetic */
|
||||
const char arisyntax[257] = { CEOF,
|
||||
set_range(CTL_FIRST, CTL_LAST, CCTL)
|
||||
set('\n', CNL)
|
||||
set('\\', CBACK)
|
||||
set('`', CBQUOTE)
|
||||
set('\'', CSQUOTE)
|
||||
set('"', CDQUOTE)
|
||||
set('$', CVAR)
|
||||
set('}', CENDVAR)
|
||||
set('(', CLP)
|
||||
set(')', CRP)
|
||||
};
|
||||
|
||||
/* character classification table */
|
||||
const char is_type[257] = { 0,
|
||||
set_range('0', '9', ISDIGIT)
|
||||
set_range('a', 'z', ISLOWER)
|
||||
set_range('A', 'Z', ISUPPER)
|
||||
set('_', ISUNDER)
|
||||
set('#', ISSPECL)
|
||||
set('?', ISSPECL)
|
||||
set('$', ISSPECL)
|
||||
set('!', ISSPECL)
|
||||
set('-', ISSPECL)
|
||||
set('*', ISSPECL)
|
||||
set('@', ISSPECL)
|
||||
};
|
83
bin/sh/syntax.h
Normal file
83
bin/sh/syntax.h
Normal file
|
@ -0,0 +1,83 @@
|
|||
/* $NetBSD: syntax.h,v 1.2 2004/01/17 17:38:12 dsl Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Kenneth Almquist.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/* Syntax classes */
|
||||
#define CWORD 0 /* character is nothing special */
|
||||
#define CNL 1 /* newline character */
|
||||
#define CBACK 2 /* a backslash character */
|
||||
#define CSQUOTE 3 /* single quote */
|
||||
#define CDQUOTE 4 /* double quote */
|
||||
#define CBQUOTE 5 /* backwards single quote */
|
||||
#define CVAR 6 /* a dollar sign */
|
||||
#define CENDVAR 7 /* a '}' character */
|
||||
#define CLP 8 /* a left paren in arithmetic */
|
||||
#define CRP 9 /* a right paren in arithmetic */
|
||||
#define CEOF 10 /* end of file */
|
||||
#define CCTL 11 /* like CWORD, except it must be escaped */
|
||||
#define CSPCL 12 /* these terminate a word */
|
||||
|
||||
/* Syntax classes for is_ functions */
|
||||
#define ISDIGIT 01 /* a digit */
|
||||
#define ISUPPER 02 /* an upper case letter */
|
||||
#define ISLOWER 04 /* a lower case letter */
|
||||
#define ISUNDER 010 /* an underscore */
|
||||
#define ISSPECL 020 /* the name of a special parameter */
|
||||
|
||||
#define PEOF (CHAR_MIN - 1)
|
||||
#define SYNBASE (-PEOF)
|
||||
/* XXX UPEOF is CHAR_MAX, so is a valid 'char' value... */
|
||||
#define UPEOF ((char)PEOF)
|
||||
|
||||
|
||||
#define BASESYNTAX (basesyntax + SYNBASE)
|
||||
#define DQSYNTAX (dqsyntax + SYNBASE)
|
||||
#define SQSYNTAX (sqsyntax + SYNBASE)
|
||||
#define ARISYNTAX (arisyntax + SYNBASE)
|
||||
|
||||
/* These defines assume that the digits are contiguous */
|
||||
#define is_digit(c) ((unsigned)((c) - '0') <= 9)
|
||||
#define is_alpha(c) (((char)(c)) != UPEOF && ((c) < CTL_FIRST || (c) > CTL_LAST) && isalpha((unsigned char)(c)))
|
||||
#define is_name(c) (((char)(c)) != UPEOF && ((c) < CTL_FIRST || (c) > CTL_LAST) && ((c) == '_' || isalpha((unsigned char)(c))))
|
||||
#define is_in_name(c) (((char)(c)) != UPEOF && ((c) < CTL_FIRST || (c) > CTL_LAST) && ((c) == '_' || isalnum((unsigned char)(c))))
|
||||
#define is_special(c) ((is_type+SYNBASE)[c] & (ISSPECL|ISDIGIT))
|
||||
#define digit_val(c) ((c) - '0')
|
||||
|
||||
extern const char basesyntax[];
|
||||
extern const char dqsyntax[];
|
||||
extern const char sqsyntax[];
|
||||
extern const char arisyntax[];
|
||||
extern const char is_type[];
|
475
bin/sh/trap.c
Normal file
475
bin/sh/trap.c
Normal file
|
@ -0,0 +1,475 @@
|
|||
/* $NetBSD: trap.c,v 1.35 2011/06/18 21:18:46 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Kenneth Almquist.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)trap.c 8.5 (Berkeley) 6/5/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: trap.c,v 1.35 2011/06/18 21:18:46 christos Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "shell.h"
|
||||
#include "main.h"
|
||||
#include "nodes.h" /* for other headers */
|
||||
#include "eval.h"
|
||||
#include "jobs.h"
|
||||
#include "show.h"
|
||||
#include "options.h"
|
||||
#include "builtins.h"
|
||||
#include "syntax.h"
|
||||
#include "output.h"
|
||||
#include "memalloc.h"
|
||||
#include "error.h"
|
||||
#include "trap.h"
|
||||
#include "mystring.h"
|
||||
#include "var.h"
|
||||
|
||||
|
||||
/*
|
||||
* Sigmode records the current value of the signal handlers for the various
|
||||
* modes. A value of zero means that the current handler is not known.
|
||||
* S_HARD_IGN indicates that the signal was ignored on entry to the shell,
|
||||
*/
|
||||
|
||||
#define S_DFL 1 /* default signal handling (SIG_DFL) */
|
||||
#define S_CATCH 2 /* signal is caught */
|
||||
#define S_IGN 3 /* signal is ignored (SIG_IGN) */
|
||||
#define S_HARD_IGN 4 /* signal is ignored permenantly */
|
||||
#define S_RESET 5 /* temporary - to reset a hard ignored sig */
|
||||
|
||||
|
||||
char *trap[NSIG+1]; /* trap handler commands */
|
||||
MKINIT char sigmode[NSIG]; /* current value of signal */
|
||||
volatile char gotsig[NSIG]; /* indicates specified signal received */
|
||||
int pendingsigs; /* indicates some signal received */
|
||||
|
||||
static int getsigaction(int, sig_t *);
|
||||
|
||||
/*
|
||||
* return the signal number described by `p' (as a number or a name)
|
||||
* or -1 if it isn't one
|
||||
*/
|
||||
|
||||
static int
|
||||
signame_to_signum(const char *p)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (is_number(p))
|
||||
return number(p);
|
||||
|
||||
if (strcasecmp(p, "exit") == 0 )
|
||||
return 0;
|
||||
|
||||
if (strncasecmp(p, "sig", 3) == 0)
|
||||
p += 3;
|
||||
|
||||
for (i = 0; i < NSIG; ++i)
|
||||
if (strcasecmp (p, sys_signame[i]) == 0)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Print a list of valid signal names
|
||||
*/
|
||||
static void
|
||||
printsignals(void)
|
||||
{
|
||||
int n;
|
||||
|
||||
out1str("EXIT ");
|
||||
|
||||
for (n = 1; n < NSIG; n++) {
|
||||
out1fmt("%s", sys_signame[n]);
|
||||
if ((n == NSIG/2) || n == (NSIG - 1))
|
||||
out1str("\n");
|
||||
else
|
||||
out1c(' ');
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The trap builtin.
|
||||
*/
|
||||
|
||||
int
|
||||
trapcmd(int argc, char **argv)
|
||||
{
|
||||
char *action;
|
||||
char **ap;
|
||||
int signo;
|
||||
|
||||
if (argc <= 1) {
|
||||
for (signo = 0 ; signo <= NSIG ; signo++)
|
||||
if (trap[signo] != NULL) {
|
||||
out1fmt("trap -- ");
|
||||
print_quoted(trap[signo]);
|
||||
out1fmt(" %s\n",
|
||||
(signo) ? sys_signame[signo] : "EXIT");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
ap = argv + 1;
|
||||
|
||||
action = NULL;
|
||||
|
||||
if (strcmp(*ap, "--") == 0)
|
||||
if (*++ap == NULL)
|
||||
return 0;
|
||||
|
||||
if (signame_to_signum(*ap) == -1) {
|
||||
if ((*ap)[0] == '-') {
|
||||
if ((*ap)[1] == '\0')
|
||||
ap++;
|
||||
else if ((*ap)[1] == 'l' && (*ap)[2] == '\0') {
|
||||
printsignals();
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
error("bad option %s\n", *ap);
|
||||
}
|
||||
else
|
||||
action = *ap++;
|
||||
}
|
||||
|
||||
while (*ap) {
|
||||
if (is_number(*ap))
|
||||
signo = number(*ap);
|
||||
else
|
||||
signo = signame_to_signum(*ap);
|
||||
|
||||
if (signo < 0 || signo > NSIG)
|
||||
error("%s: bad trap", *ap);
|
||||
|
||||
INTOFF;
|
||||
if (action)
|
||||
action = savestr(action);
|
||||
|
||||
if (trap[signo])
|
||||
ckfree(trap[signo]);
|
||||
|
||||
trap[signo] = action;
|
||||
|
||||
if (signo != 0)
|
||||
setsignal(signo, 0);
|
||||
INTON;
|
||||
ap++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Clear traps on a fork or vfork.
|
||||
* Takes one arg vfork, to tell it to not be destructive of
|
||||
* the parents variables.
|
||||
*/
|
||||
|
||||
void
|
||||
clear_traps(int vforked)
|
||||
{
|
||||
char **tp;
|
||||
|
||||
for (tp = trap ; tp <= &trap[NSIG] ; tp++) {
|
||||
if (*tp && **tp) { /* trap not NULL or SIG_IGN */
|
||||
INTOFF;
|
||||
if (!vforked) {
|
||||
ckfree(*tp);
|
||||
*tp = NULL;
|
||||
}
|
||||
if (tp != &trap[0])
|
||||
setsignal(tp - trap, vforked);
|
||||
INTON;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Set the signal handler for the specified signal. The routine figures
|
||||
* out what it should be set to.
|
||||
*/
|
||||
|
||||
sig_t
|
||||
setsignal(int signo, int vforked)
|
||||
{
|
||||
int action;
|
||||
sig_t sigact = SIG_DFL, sig;
|
||||
char *t, tsig;
|
||||
|
||||
if ((t = trap[signo]) == NULL)
|
||||
action = S_DFL;
|
||||
else if (*t != '\0')
|
||||
action = S_CATCH;
|
||||
else
|
||||
action = S_IGN;
|
||||
if (rootshell && !vforked && action == S_DFL) {
|
||||
switch (signo) {
|
||||
case SIGINT:
|
||||
if (iflag || minusc || sflag == 0)
|
||||
action = S_CATCH;
|
||||
break;
|
||||
case SIGQUIT:
|
||||
#ifdef DEBUG
|
||||
if (debug)
|
||||
break;
|
||||
#endif
|
||||
/* FALLTHROUGH */
|
||||
case SIGTERM:
|
||||
if (iflag)
|
||||
action = S_IGN;
|
||||
break;
|
||||
#if JOBS
|
||||
case SIGTSTP:
|
||||
case SIGTTOU:
|
||||
if (mflag)
|
||||
action = S_IGN;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
t = &sigmode[signo - 1];
|
||||
tsig = *t;
|
||||
if (tsig == 0) {
|
||||
/*
|
||||
* current setting unknown
|
||||
*/
|
||||
if (!getsigaction(signo, &sigact)) {
|
||||
/*
|
||||
* Pretend it worked; maybe we should give a warning
|
||||
* here, but other shells don't. We don't alter
|
||||
* sigmode, so that we retry every time.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
if (sigact == SIG_IGN) {
|
||||
/*
|
||||
* POSIX 3.14.13 states that non-interactive shells
|
||||
* should ignore trap commands for signals that were
|
||||
* ignored upon entry, and leaves the behavior
|
||||
* unspecified for interactive shells. On interactive
|
||||
* shells, or if job control is on, and we have a job
|
||||
* control related signal, we allow the trap to work.
|
||||
*
|
||||
* This change allows us to be POSIX compliant, and
|
||||
* at the same time override the default behavior if
|
||||
* we need to by setting the interactive flag.
|
||||
*/
|
||||
if ((mflag && (signo == SIGTSTP ||
|
||||
signo == SIGTTIN || signo == SIGTTOU)) || iflag) {
|
||||
tsig = S_IGN;
|
||||
} else
|
||||
tsig = S_HARD_IGN;
|
||||
} else {
|
||||
tsig = S_RESET; /* force to be set */
|
||||
}
|
||||
}
|
||||
if (tsig == S_HARD_IGN || tsig == action)
|
||||
return 0;
|
||||
switch (action) {
|
||||
case S_DFL: sigact = SIG_DFL; break;
|
||||
case S_CATCH: sigact = onsig; break;
|
||||
case S_IGN: sigact = SIG_IGN; break;
|
||||
}
|
||||
sig = signal(signo, sigact);
|
||||
if (sig != SIG_ERR) {
|
||||
sigset_t ss;
|
||||
if (!vforked)
|
||||
*t = action;
|
||||
if (action == S_CATCH)
|
||||
(void)siginterrupt(signo, 1);
|
||||
/*
|
||||
* If our parent accidentally blocked signals for
|
||||
* us make sure we unblock them
|
||||
*/
|
||||
(void)sigemptyset(&ss);
|
||||
(void)sigaddset(&ss, signo);
|
||||
(void)sigprocmask(SIG_UNBLOCK, &ss, NULL);
|
||||
}
|
||||
return sig;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the current setting for sig w/o changing it.
|
||||
*/
|
||||
static int
|
||||
getsigaction(int signo, sig_t *sigact)
|
||||
{
|
||||
struct sigaction sa;
|
||||
|
||||
if (sigaction(signo, (struct sigaction *)0, &sa) == -1)
|
||||
return 0;
|
||||
*sigact = (sig_t) sa.sa_handler;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ignore a signal.
|
||||
*/
|
||||
|
||||
void
|
||||
ignoresig(int signo, int vforked)
|
||||
{
|
||||
if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
|
||||
signal(signo, SIG_IGN);
|
||||
}
|
||||
if (!vforked)
|
||||
sigmode[signo - 1] = S_HARD_IGN;
|
||||
}
|
||||
|
||||
|
||||
#ifdef mkinit
|
||||
INCLUDE <signal.h>
|
||||
INCLUDE "trap.h"
|
||||
|
||||
SHELLPROC {
|
||||
char *sm;
|
||||
|
||||
clear_traps(0);
|
||||
for (sm = sigmode ; sm < sigmode + NSIG ; sm++) {
|
||||
if (*sm == S_IGN)
|
||||
*sm = S_HARD_IGN;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Signal handler.
|
||||
*/
|
||||
|
||||
void
|
||||
onsig(int signo)
|
||||
{
|
||||
signal(signo, onsig);
|
||||
if (signo == SIGINT && trap[SIGINT] == NULL) {
|
||||
onint();
|
||||
return;
|
||||
}
|
||||
gotsig[signo - 1] = 1;
|
||||
pendingsigs++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Called to execute a trap. Perhaps we should avoid entering new trap
|
||||
* handlers while we are executing a trap handler.
|
||||
*/
|
||||
|
||||
void
|
||||
dotrap(void)
|
||||
{
|
||||
int i;
|
||||
int savestatus;
|
||||
|
||||
for (;;) {
|
||||
for (i = 1 ; ; i++) {
|
||||
if (gotsig[i - 1])
|
||||
break;
|
||||
if (i >= NSIG)
|
||||
goto done;
|
||||
}
|
||||
gotsig[i - 1] = 0;
|
||||
savestatus=exitstatus;
|
||||
evalstring(trap[i], 0);
|
||||
exitstatus=savestatus;
|
||||
}
|
||||
done:
|
||||
pendingsigs = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Controls whether the shell is interactive or not.
|
||||
*/
|
||||
|
||||
|
||||
void
|
||||
setinteractive(int on)
|
||||
{
|
||||
static int is_interactive;
|
||||
|
||||
if (on == is_interactive)
|
||||
return;
|
||||
setsignal(SIGINT, 0);
|
||||
setsignal(SIGQUIT, 0);
|
||||
setsignal(SIGTERM, 0);
|
||||
is_interactive = on;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Called to exit the shell.
|
||||
*/
|
||||
|
||||
void
|
||||
exitshell(int status)
|
||||
{
|
||||
struct jmploc loc1, loc2;
|
||||
char *p;
|
||||
|
||||
TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
|
||||
if (setjmp(loc1.loc)) {
|
||||
goto l1;
|
||||
}
|
||||
if (setjmp(loc2.loc)) {
|
||||
goto l2;
|
||||
}
|
||||
handler = &loc1;
|
||||
if ((p = trap[0]) != NULL && *p != '\0') {
|
||||
trap[0] = NULL;
|
||||
evalstring(p, 0);
|
||||
}
|
||||
l1: handler = &loc2; /* probably unnecessary */
|
||||
flushall();
|
||||
#if JOBS
|
||||
setjobctl(0);
|
||||
#endif
|
||||
l2: _exit(status);
|
||||
/* NOTREACHED */
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: trap.h,v 1.20 2012/03/15 02:02:20 joerg Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -30,23 +32,14 @@
|
|||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)trap.h 8.3 (Berkeley) 6/5/95
|
||||
* $FreeBSD: src/bin/sh/trap.h,v 1.12 2004/04/06 20:06:51 markm Exp $
|
||||
*/
|
||||
|
||||
extern int pendingsigs;
|
||||
extern int in_dotrap;
|
||||
extern int is_interactive;
|
||||
extern volatile sig_atomic_t gotwinch;
|
||||
|
||||
int trapcmd(int, char **);
|
||||
void clear_traps(void);
|
||||
void setsignal(int);
|
||||
void ignoresig(int);
|
||||
void clear_traps(int);
|
||||
sig_t setsignal(int, int);
|
||||
void ignoresig(int, int);
|
||||
void onsig(int);
|
||||
void dotrap(void);
|
||||
void setinteractive(int);
|
||||
void exitshell(int);
|
||||
char *strsiglist(int);
|
||||
|
||||
/*
|
||||
* $PchId: trap.h,v 1.6 2006/05/22 12:48:30 philip Exp $
|
||||
*/
|
||||
void exitshell(int) __dead;
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: var.c,v 1.43 2013/11/01 16:49:02 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -30,28 +32,25 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 5/4/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: var.c,v 1.43 2013/11/01 16:49:02 christos Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
#include <sys/cdefs.h>
|
||||
/*
|
||||
__FBSDID("$FreeBSD: src/bin/sh/var.c,v 1.26.2.1 2004/09/30 04:41:55 des Exp $");
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#ifndef NO_PATHS_H
|
||||
#include <string.h>
|
||||
#include <paths.h>
|
||||
#endif
|
||||
#include <limits.h>
|
||||
|
||||
/*
|
||||
* Shell variables.
|
||||
*/
|
||||
|
||||
#include <locale.h>
|
||||
|
||||
#include "shell.h"
|
||||
#include "output.h"
|
||||
#include "expand.h"
|
||||
|
@ -60,49 +59,57 @@ __FBSDID("$FreeBSD: src/bin/sh/var.c,v 1.26.2.1 2004/09/30 04:41:55 des Exp $");
|
|||
#include "exec.h"
|
||||
#include "syntax.h"
|
||||
#include "options.h"
|
||||
#include "builtins.h"
|
||||
#include "mail.h"
|
||||
#include "var.h"
|
||||
#include "memalloc.h"
|
||||
#include "error.h"
|
||||
#include "mystring.h"
|
||||
#include "parser.h"
|
||||
#if !defined(NO_HISTORY)
|
||||
#include "show.h"
|
||||
#ifndef SMALL
|
||||
#include "myhistedit.h"
|
||||
#endif
|
||||
|
||||
#include "builtins.h"
|
||||
|
||||
#ifndef _PATH_DEFPATH
|
||||
#define _PATH_DEFPATH "/usr/bin:/bin"
|
||||
#endif
|
||||
|
||||
#ifdef SMALL
|
||||
#define VTABSIZE 39
|
||||
#else
|
||||
#define VTABSIZE 517
|
||||
#endif
|
||||
|
||||
|
||||
struct varinit {
|
||||
struct var *var;
|
||||
int flags;
|
||||
char *text;
|
||||
const char *text;
|
||||
void (*func)(const char *);
|
||||
};
|
||||
|
||||
struct localvar *localvars;
|
||||
|
||||
#ifndef NO_HISTORY
|
||||
#if ATTY
|
||||
struct var vatty;
|
||||
#endif
|
||||
#ifndef SMALL
|
||||
struct var vhistsize;
|
||||
struct var vterm;
|
||||
#endif
|
||||
struct var vifs;
|
||||
struct var vmail;
|
||||
struct var vmpath;
|
||||
struct var vpath;
|
||||
struct var vppid;
|
||||
struct var vps1;
|
||||
struct var vps2;
|
||||
struct var vpse;
|
||||
struct var vps4;
|
||||
struct var vvers;
|
||||
STATIC struct var voptind;
|
||||
struct var voptind;
|
||||
|
||||
STATIC const struct varinit varinit[] = {
|
||||
#if !defined(NO_HISTORY)
|
||||
const struct varinit varinit[] = {
|
||||
#if ATTY
|
||||
{ &vatty, VSTRFIXED|VTEXTFIXED|VUNSET, "ATTY=",
|
||||
NULL },
|
||||
#endif
|
||||
#ifndef SMALL
|
||||
{ &vhistsize, VSTRFIXED|VTEXTFIXED|VUNSET, "HISTSIZE=",
|
||||
sethistsize },
|
||||
#endif
|
||||
|
@ -114,26 +121,27 @@ STATIC const struct varinit varinit[] = {
|
|||
NULL },
|
||||
{ &vpath, VSTRFIXED|VTEXTFIXED, "PATH=" _PATH_DEFPATH,
|
||||
changepath },
|
||||
{ &vppid, VSTRFIXED|VTEXTFIXED|VUNSET, "PPID=",
|
||||
NULL },
|
||||
/*
|
||||
* vps1 depends on uid
|
||||
*/
|
||||
{ &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ",
|
||||
NULL },
|
||||
{ &vpse, VSTRFIXED|VTEXTFIXED|VUNSET, "PSE=",
|
||||
{ &vps4, VSTRFIXED|VTEXTFIXED, "PS4=+ ",
|
||||
NULL },
|
||||
{ &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1",
|
||||
#ifndef SMALL
|
||||
{ &vterm, VSTRFIXED|VTEXTFIXED|VUNSET, "TERM=",
|
||||
setterm },
|
||||
#endif
|
||||
{ &voptind, VSTRFIXED|VTEXTFIXED|VNOFUNC, "OPTIND=1",
|
||||
getoptsreset },
|
||||
{ NULL, 0, NULL,
|
||||
NULL }
|
||||
};
|
||||
|
||||
STATIC struct var *vartab[VTABSIZE];
|
||||
struct var *vartab[VTABSIZE];
|
||||
|
||||
STATIC struct var **hashvar(char *);
|
||||
STATIC int varequal(char *, char *);
|
||||
STATIC int localevar(char *);
|
||||
STATIC int strequal(const char *, const char *);
|
||||
STATIC struct var *find_var(const char *, struct var ***, int *);
|
||||
|
||||
/*
|
||||
* Initialize the varable symbol tables and import the environment
|
||||
|
@ -141,9 +149,9 @@ STATIC int localevar(char *);
|
|||
|
||||
#ifdef mkinit
|
||||
INCLUDE "var.h"
|
||||
MKINIT char **environ;
|
||||
INIT {
|
||||
char **envp;
|
||||
extern char **environ;
|
||||
|
||||
initvar();
|
||||
for (envp = environ ; *envp ; envp++) {
|
||||
|
@ -163,35 +171,28 @@ INIT {
|
|||
void
|
||||
initvar(void)
|
||||
{
|
||||
char ppid[20];
|
||||
const struct varinit *ip;
|
||||
struct var *vp;
|
||||
struct var **vpp;
|
||||
|
||||
for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
|
||||
if ((vp->flags & VEXPORT) == 0) {
|
||||
vpp = hashvar(ip->text);
|
||||
if (find_var(ip->text, &vpp, &vp->name_len) != NULL)
|
||||
continue;
|
||||
vp->next = *vpp;
|
||||
*vpp = vp;
|
||||
vp->text = ip->text;
|
||||
vp->text = strdup(ip->text);
|
||||
vp->flags = ip->flags;
|
||||
vp->func = ip->func;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* PS1 depends on uid
|
||||
*/
|
||||
if ((vps1.flags & VEXPORT) == 0) {
|
||||
vpp = hashvar("PS1=");
|
||||
if (find_var("PS1", &vpp, &vps1.name_len) == NULL) {
|
||||
vps1.next = *vpp;
|
||||
*vpp = &vps1;
|
||||
vps1.text = geteuid() ? "PS1=$ " : "PS1=# ";
|
||||
vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# ");
|
||||
vps1.flags = VSTRFIXED|VTEXTFIXED;
|
||||
}
|
||||
if ((vppid.flags & VEXPORT) == 0) {
|
||||
fmtstr(ppid, sizeof(ppid), "%d", (int)getppid());
|
||||
setvarsafe("PPID", ppid, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -199,15 +200,11 @@ initvar(void)
|
|||
*/
|
||||
|
||||
int
|
||||
setvarsafe(char *name, char *val, int flags)
|
||||
setvarsafe(const char *name, const char *val, int flags)
|
||||
{
|
||||
struct jmploc jmploc;
|
||||
struct jmploc *volatile savehandler = handler;
|
||||
int err = 0;
|
||||
#if __GNUC__
|
||||
/* Avoid longjmp clobbering */
|
||||
(void) &err;
|
||||
#endif
|
||||
int volatile err = 0;
|
||||
|
||||
if (setjmp(jmploc.loc))
|
||||
err = 1;
|
||||
|
@ -220,14 +217,16 @@ setvarsafe(char *name, char *val, int flags)
|
|||
}
|
||||
|
||||
/*
|
||||
* Set the value of a variable. The flags argument is tored with the
|
||||
* Set the value of a variable. The flags argument is ored with the
|
||||
* flags of the variable. If val is NULL, the variable is unset.
|
||||
*/
|
||||
|
||||
void
|
||||
setvar(char *name, char *val, int flags)
|
||||
setvar(const char *name, const char *val, int flags)
|
||||
{
|
||||
char *p, *q;
|
||||
const char *p;
|
||||
const char *q;
|
||||
char *d;
|
||||
int len;
|
||||
int namelen;
|
||||
char *nameeq;
|
||||
|
@ -255,37 +254,18 @@ setvar(char *name, char *val, int flags)
|
|||
} else {
|
||||
len += strlen(val);
|
||||
}
|
||||
p = nameeq = ckmalloc(len);
|
||||
d = nameeq = ckmalloc(len);
|
||||
q = name;
|
||||
while (--namelen >= 0)
|
||||
*p++ = *q++;
|
||||
*p++ = '=';
|
||||
*p = '\0';
|
||||
*d++ = *q++;
|
||||
*d++ = '=';
|
||||
*d = '\0';
|
||||
if (val)
|
||||
scopy(val, p);
|
||||
scopy(val, d);
|
||||
setvareq(nameeq, flags);
|
||||
}
|
||||
|
||||
STATIC int
|
||||
localevar(char *s)
|
||||
{
|
||||
static char *lnames[7] = {
|
||||
"ALL", "COLLATE", "CTYPE", "MONETARY",
|
||||
"NUMERIC", "TIME", NULL
|
||||
};
|
||||
char **ss;
|
||||
|
||||
if (*s != 'L')
|
||||
return 0;
|
||||
if (varequal(s + 1, "ANG"))
|
||||
return 1;
|
||||
if (strncmp(s + 1, "C_", 2) != 0)
|
||||
return 0;
|
||||
for (ss = lnames; *ss ; ss++)
|
||||
if (varequal(s + 3, *ss))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Same as setvar except that the variable and value are passed in
|
||||
|
@ -298,27 +278,26 @@ void
|
|||
setvareq(char *s, int flags)
|
||||
{
|
||||
struct var *vp, **vpp;
|
||||
int len;
|
||||
int nlen;
|
||||
|
||||
if (aflag)
|
||||
flags |= VEXPORT;
|
||||
vpp = hashvar(s);
|
||||
for (vp = *vpp ; vp ; vp = vp->next) {
|
||||
if (varequal(s, vp->text)) {
|
||||
if (vp->flags & VREADONLY) {
|
||||
len = strchr(s, '=') - s;
|
||||
error("%.*s: is read only", len, s);
|
||||
}
|
||||
vp = find_var(s, &vpp, &nlen);
|
||||
if (vp != NULL) {
|
||||
if (vp->flags & VREADONLY)
|
||||
error("%.*s: is read only", vp->name_len, s);
|
||||
if (flags & VNOSET)
|
||||
return;
|
||||
INTOFF;
|
||||
|
||||
if (vp->func && (flags & VNOFUNC) == 0)
|
||||
(*vp->func)(strchr(s, '=') + 1);
|
||||
(*vp->func)(s + vp->name_len + 1);
|
||||
|
||||
if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
|
||||
ckfree(vp->text);
|
||||
|
||||
vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
|
||||
vp->flags |= flags;
|
||||
vp->flags |= flags & ~VNOFUNC;
|
||||
vp->text = s;
|
||||
|
||||
/*
|
||||
|
@ -327,27 +306,19 @@ setvareq(char *s, int flags)
|
|||
*/
|
||||
if (vp == &vmpath || (vp == &vmail && ! mpathset()))
|
||||
chkmail(1);
|
||||
if ((vp->flags & VEXPORT) && localevar(s)) {
|
||||
putenv(s);
|
||||
(void) setlocale(LC_ALL, "");
|
||||
}
|
||||
INTON;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* not found */
|
||||
if (flags & VNOSET)
|
||||
return;
|
||||
vp = ckmalloc(sizeof (*vp));
|
||||
vp->flags = flags;
|
||||
vp->flags = flags & ~VNOFUNC;
|
||||
vp->text = s;
|
||||
vp->name_len = nlen;
|
||||
vp->next = *vpp;
|
||||
vp->func = NULL;
|
||||
INTOFF;
|
||||
*vpp = vp;
|
||||
if ((vp->flags & VEXPORT) && localevar(s)) {
|
||||
putenv(s);
|
||||
(void) setlocale(LC_ALL, "");
|
||||
}
|
||||
INTON;
|
||||
}
|
||||
|
||||
|
||||
|
@ -357,17 +328,25 @@ setvareq(char *s, int flags)
|
|||
*/
|
||||
|
||||
void
|
||||
listsetvar(struct strlist *list)
|
||||
listsetvar(struct strlist *list, int flags)
|
||||
{
|
||||
struct strlist *lp;
|
||||
|
||||
INTOFF;
|
||||
for (lp = list ; lp ; lp = lp->next) {
|
||||
setvareq(savestr(lp->text), 0);
|
||||
setvareq(savestr(lp->text), flags);
|
||||
}
|
||||
INTON;
|
||||
}
|
||||
|
||||
void
|
||||
listmklocal(struct strlist *list, int flags)
|
||||
{
|
||||
struct strlist *lp;
|
||||
|
||||
for (lp = list ; lp ; lp = lp->next)
|
||||
mklocal(lp->text, flags);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
@ -375,18 +354,14 @@ listsetvar(struct strlist *list)
|
|||
*/
|
||||
|
||||
char *
|
||||
lookupvar(char *name)
|
||||
lookupvar(const char *name)
|
||||
{
|
||||
struct var *v;
|
||||
|
||||
for (v = *hashvar(name) ; v ; v = v->next) {
|
||||
if (varequal(v->text, name)) {
|
||||
if (v->flags & VUNSET)
|
||||
return NULL;
|
||||
return strchr(v->text, '=') + 1;
|
||||
}
|
||||
}
|
||||
v = find_var(name, NULL, NULL);
|
||||
if (v == NULL || v->flags & VUNSET)
|
||||
return NULL;
|
||||
return v->text + v->name_len + 1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -398,24 +373,21 @@ lookupvar(char *name)
|
|||
*/
|
||||
|
||||
char *
|
||||
bltinlookup(char *name, int doall)
|
||||
bltinlookup(const char *name, int doall)
|
||||
{
|
||||
struct strlist *sp;
|
||||
struct var *v;
|
||||
|
||||
for (sp = cmdenviron ; sp ; sp = sp->next) {
|
||||
if (varequal(sp->text, name))
|
||||
if (strequal(sp->text, name))
|
||||
return strchr(sp->text, '=') + 1;
|
||||
}
|
||||
for (v = *hashvar(name) ; v ; v = v->next) {
|
||||
if (varequal(v->text, name)) {
|
||||
if ((v->flags & VUNSET)
|
||||
|| (!doall && (v->flags & VEXPORT) == 0))
|
||||
return NULL;
|
||||
return strchr(v->text, '=') + 1;
|
||||
}
|
||||
}
|
||||
|
||||
v = find_var(name, NULL, NULL);
|
||||
|
||||
if (v == NULL || v->flags & VUNSET || (!doall && !(v->flags & VEXPORT)))
|
||||
return NULL;
|
||||
return v->text + v->name_len + 1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -431,7 +403,8 @@ environment(void)
|
|||
int nenv;
|
||||
struct var **vpp;
|
||||
struct var *vp;
|
||||
char **env, **ep;
|
||||
char **env;
|
||||
char **ep;
|
||||
|
||||
nenv = 0;
|
||||
for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
|
||||
|
@ -457,6 +430,8 @@ environment(void)
|
|||
*/
|
||||
|
||||
#ifdef mkinit
|
||||
void shprocvar(void);
|
||||
|
||||
SHELLPROC {
|
||||
shprocvar();
|
||||
}
|
||||
|
@ -496,23 +471,93 @@ shprocvar(void)
|
|||
* any variables.
|
||||
*/
|
||||
|
||||
void
|
||||
print_quoted(const char *p)
|
||||
{
|
||||
const char *q;
|
||||
|
||||
if (strcspn(p, "|&;<>()$`\\\"' \t\n*?[]#~=%") == strlen(p)) {
|
||||
out1fmt("%s", p);
|
||||
return;
|
||||
}
|
||||
while (*p) {
|
||||
if (*p == '\'') {
|
||||
out1fmt("\\'");
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
q = strchr(p, '\'');
|
||||
if (!q) {
|
||||
out1fmt("'%s'", p );
|
||||
return;
|
||||
}
|
||||
out1fmt("'%.*s'", (int)(q - p), p );
|
||||
p = q;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
sort_var(const void *v_v1, const void *v_v2)
|
||||
{
|
||||
const struct var * const *v1 = v_v1;
|
||||
const struct var * const *v2 = v_v2;
|
||||
|
||||
/* XXX Will anyone notice we include the '=' of the shorter name? */
|
||||
return strcoll((*v1)->text, (*v2)->text);
|
||||
}
|
||||
|
||||
/*
|
||||
* POSIX requires that 'set' (but not export or readonly) output the
|
||||
* variables in lexicographic order - by the locale's collating order (sigh).
|
||||
* Maybe we could keep them in an ordered balanced binary tree
|
||||
* instead of hashed lists.
|
||||
* For now just roll 'em through qsort for printing...
|
||||
*/
|
||||
|
||||
int
|
||||
showvarscmd(int argc __unused, char **argv __unused)
|
||||
showvars(const char *name, int flag, int show_value)
|
||||
{
|
||||
struct var **vpp;
|
||||
struct var *vp;
|
||||
const char *s;
|
||||
const char *p;
|
||||
|
||||
static struct var **list; /* static in case we are interrupted */
|
||||
static int list_len;
|
||||
int count = 0;
|
||||
|
||||
if (!list) {
|
||||
list_len = 32;
|
||||
list = ckmalloc(list_len * sizeof *list);
|
||||
}
|
||||
|
||||
for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
|
||||
for (vp = *vpp ; vp ; vp = vp->next) {
|
||||
if (vp->flags & VUNSET)
|
||||
if (flag && !(vp->flags & flag))
|
||||
continue;
|
||||
for (s = vp->text; *s != '='; s++)
|
||||
out1c(*s);
|
||||
out1c('=');
|
||||
out1qstr(s + 1);
|
||||
out1c('\n');
|
||||
if (vp->flags & VUNSET && !(show_value & 2))
|
||||
continue;
|
||||
if (count >= list_len) {
|
||||
list = ckrealloc(list,
|
||||
(list_len << 1) * sizeof *list);
|
||||
list_len <<= 1;
|
||||
}
|
||||
list[count++] = vp;
|
||||
}
|
||||
}
|
||||
|
||||
qsort(list, count, sizeof *list, sort_var);
|
||||
|
||||
for (vpp = list; count--; vpp++) {
|
||||
vp = *vpp;
|
||||
if (name)
|
||||
out1fmt("%s ", name);
|
||||
for (p = vp->text ; *p != '=' ; p++)
|
||||
out1c(*p);
|
||||
if (!(vp->flags & VUNSET) && show_value) {
|
||||
out1fmt("=");
|
||||
print_quoted(++p);
|
||||
}
|
||||
out1c('\n');
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -526,71 +571,29 @@ showvarscmd(int argc __unused, char **argv __unused)
|
|||
int
|
||||
exportcmd(int argc, char **argv)
|
||||
{
|
||||
struct var **vpp;
|
||||
struct var *vp;
|
||||
char *name;
|
||||
char *p;
|
||||
char *cmdname;
|
||||
int ch, values;
|
||||
const char *p;
|
||||
int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
|
||||
int pflag;
|
||||
|
||||
cmdname = argv[0];
|
||||
optreset = optind = 1;
|
||||
opterr = 0;
|
||||
values = 0;
|
||||
while ((ch = getopt(argc, argv, "p")) != -1) {
|
||||
switch (ch) {
|
||||
case 'p':
|
||||
values = 1;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
error("unknown option: -%c", optopt);
|
||||
pflag = nextopt("p") == 'p' ? 3 : 0;
|
||||
if (argc <= 1 || pflag) {
|
||||
showvars( pflag ? argv[0] : 0, flag, pflag );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
listsetvar(cmdenviron);
|
||||
if (argc != 0) {
|
||||
while ((name = *argptr++) != NULL) {
|
||||
if ((p = strchr(name, '=')) != NULL) {
|
||||
p++;
|
||||
} else {
|
||||
vpp = hashvar(name);
|
||||
for (vp = *vpp ; vp ; vp = vp->next) {
|
||||
if (varequal(vp->text, name)) {
|
||||
|
||||
vp = find_var(name, NULL, NULL);
|
||||
if (vp != NULL) {
|
||||
vp->flags |= flag;
|
||||
if ((vp->flags & VEXPORT) && localevar(vp->text)) {
|
||||
putenv(vp->text);
|
||||
(void) setlocale(LC_ALL, "");
|
||||
}
|
||||
goto found;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
setvar(name, p, flag);
|
||||
found:;
|
||||
}
|
||||
} else {
|
||||
for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
|
||||
for (vp = *vpp ; vp ; vp = vp->next) {
|
||||
if (vp->flags & flag) {
|
||||
if (values) {
|
||||
out1str(cmdname);
|
||||
out1c(' ');
|
||||
}
|
||||
for (p = vp->text ; *p != '=' ; p++)
|
||||
out1c(*p);
|
||||
if (values && !(vp->flags & VUNSET)) {
|
||||
out1c('=');
|
||||
out1qstr(p + 1);
|
||||
}
|
||||
out1c('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -601,28 +604,28 @@ found:;
|
|||
*/
|
||||
|
||||
int
|
||||
localcmd(int argc __unused, char **argv __unused)
|
||||
localcmd(int argc, char **argv)
|
||||
{
|
||||
char *name;
|
||||
|
||||
if (! in_function())
|
||||
error("Not in a function");
|
||||
while ((name = *argptr++) != NULL) {
|
||||
mklocal(name);
|
||||
mklocal(name, 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Make a variable a local variable. When a variable is made local, it's
|
||||
* Make a variable a local variable. When a variable is made local, its
|
||||
* value and flags are saved in a localvar structure. The saved values
|
||||
* will be restored when the shell function returns. We handle the name
|
||||
* "-" as a special case.
|
||||
*/
|
||||
|
||||
void
|
||||
mklocal(char *name)
|
||||
mklocal(const char *name, int flags)
|
||||
{
|
||||
struct localvar *lvp;
|
||||
struct var **vpp;
|
||||
|
@ -631,17 +634,17 @@ mklocal(char *name)
|
|||
INTOFF;
|
||||
lvp = ckmalloc(sizeof (struct localvar));
|
||||
if (name[0] == '-' && name[1] == '\0') {
|
||||
lvp->text = ckmalloc(sizeof optlist);
|
||||
memcpy(lvp->text, optlist, sizeof optlist);
|
||||
char *p;
|
||||
p = ckmalloc(sizeof_optlist);
|
||||
lvp->text = memcpy(p, optlist, sizeof_optlist);
|
||||
vp = NULL;
|
||||
} else {
|
||||
vpp = hashvar(name);
|
||||
for (vp = *vpp ; vp && ! varequal(vp->text, name) ; vp = vp->next);
|
||||
vp = find_var(name, &vpp, NULL);
|
||||
if (vp == NULL) {
|
||||
if (strchr(name, '='))
|
||||
setvareq(savestr(name), VSTRFIXED);
|
||||
setvareq(savestr(name), VSTRFIXED|flags);
|
||||
else
|
||||
setvar(name, NULL, VSTRFIXED);
|
||||
setvar(name, NULL, VSTRFIXED|flags);
|
||||
vp = *vpp; /* the new variable */
|
||||
lvp->text = NULL;
|
||||
lvp->flags = VUNSET;
|
||||
|
@ -649,8 +652,8 @@ mklocal(char *name)
|
|||
lvp->text = vp->text;
|
||||
lvp->flags = vp->flags;
|
||||
vp->flags |= VSTRFIXED|VTEXTFIXED;
|
||||
if (strchr(name, '='))
|
||||
setvareq(savestr(name), 0);
|
||||
if (name[vp->name_len] == '=')
|
||||
setvareq(savestr(name), flags);
|
||||
}
|
||||
}
|
||||
lvp->vp = vp;
|
||||
|
@ -673,12 +676,15 @@ poplocalvars(void)
|
|||
while ((lvp = localvars) != NULL) {
|
||||
localvars = lvp->next;
|
||||
vp = lvp->vp;
|
||||
TRACE(("poplocalvar %s", vp ? vp->text : "-"));
|
||||
if (vp == NULL) { /* $- saved */
|
||||
memcpy(optlist, lvp->text, sizeof optlist);
|
||||
memcpy(optlist, lvp->text, sizeof_optlist);
|
||||
ckfree(lvp->text);
|
||||
} else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
|
||||
(void)unsetvar(vp->text);
|
||||
(void)unsetvar(vp->text, 0);
|
||||
} else {
|
||||
if (vp->func && (vp->flags & VNOFUNC) == 0)
|
||||
(*vp->func)(lvp->text + vp->name_len + 1);
|
||||
if ((vp->flags & VTEXTFIXED) == 0)
|
||||
ckfree(vp->text);
|
||||
vp->flags = lvp->flags;
|
||||
|
@ -709,7 +715,7 @@ setvarcmd(int argc, char **argv)
|
|||
*/
|
||||
|
||||
int
|
||||
unsetcmd(int argc __unused, char **argv __unused)
|
||||
unsetcmd(int argc, char **argv)
|
||||
{
|
||||
char **ap;
|
||||
int i;
|
||||
|
@ -717,11 +723,11 @@ unsetcmd(int argc __unused, char **argv __unused)
|
|||
int flg_var = 0;
|
||||
int ret = 0;
|
||||
|
||||
while ((i = nextopt("vf")) != '\0') {
|
||||
while ((i = nextopt("evf")) != '\0') {
|
||||
if (i == 'f')
|
||||
flg_func = 1;
|
||||
else
|
||||
flg_var = 1;
|
||||
flg_var = i;
|
||||
}
|
||||
if (flg_func == 0 && flg_var == 0)
|
||||
flg_var = 1;
|
||||
|
@ -730,7 +736,7 @@ unsetcmd(int argc __unused, char **argv __unused)
|
|||
if (flg_func)
|
||||
ret |= unsetfunc(*ap);
|
||||
if (flg_var)
|
||||
ret |= unsetvar(*ap);
|
||||
ret |= unsetvar(*ap, flg_var == 'e');
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -741,23 +747,24 @@ unsetcmd(int argc __unused, char **argv __unused)
|
|||
*/
|
||||
|
||||
int
|
||||
unsetvar(char *s)
|
||||
unsetvar(const char *s, int unexport)
|
||||
{
|
||||
struct var **vpp;
|
||||
struct var *vp;
|
||||
|
||||
vpp = hashvar(s);
|
||||
for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) {
|
||||
if (varequal(vp->text, s)) {
|
||||
vp = find_var(s, &vpp, NULL);
|
||||
if (vp == NULL)
|
||||
return 0;
|
||||
|
||||
if (vp->flags & VREADONLY)
|
||||
return (1);
|
||||
return 1;
|
||||
|
||||
INTOFF;
|
||||
if (*(strchr(vp->text, '=') + 1) != '\0')
|
||||
if (unexport) {
|
||||
vp->flags &= ~VEXPORT;
|
||||
} else {
|
||||
if (vp->text[vp->name_len + 1] != '\0')
|
||||
setvar(s, nullstr, 0);
|
||||
if ((vp->flags & VEXPORT) && localevar(vp->text)) {
|
||||
unsetenv(s);
|
||||
setlocale(LC_ALL, "");
|
||||
}
|
||||
vp->flags &= ~VEXPORT;
|
||||
vp->flags |= VUNSET;
|
||||
if ((vp->flags & VSTRFIXED) == 0) {
|
||||
|
@ -766,31 +773,10 @@ unsetvar(char *s)
|
|||
*vpp = vp->next;
|
||||
ckfree(vp);
|
||||
}
|
||||
}
|
||||
INTON;
|
||||
return (0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Find the appropriate entry in the hash table from the name.
|
||||
*/
|
||||
|
||||
STATIC struct var **
|
||||
hashvar(char *p)
|
||||
{
|
||||
unsigned int hashval;
|
||||
|
||||
hashval = ((unsigned char) *p) << 4;
|
||||
while (*p && *p != '=')
|
||||
hashval += (unsigned char) *p++;
|
||||
return &vartab[hashval % VTABSIZE];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
@ -800,7 +786,7 @@ hashvar(char *p)
|
|||
*/
|
||||
|
||||
STATIC int
|
||||
varequal(char *p, char *q)
|
||||
strequal(const char *p, const char *q)
|
||||
{
|
||||
while (*p == *q++) {
|
||||
if (*p++ == '=')
|
||||
|
@ -812,5 +798,39 @@ varequal(char *p, char *q)
|
|||
}
|
||||
|
||||
/*
|
||||
* $PchId: var.c,v 1.5 2006/05/22 12:28:49 philip Exp $
|
||||
* Search for a variable.
|
||||
* 'name' may be terminated by '=' or a NUL.
|
||||
* vppp is set to the pointer to vp, or the list head if vp isn't found
|
||||
* lenp is set to the number of charactets in 'name'
|
||||
*/
|
||||
|
||||
STATIC struct var *
|
||||
find_var(const char *name, struct var ***vppp, int *lenp)
|
||||
{
|
||||
unsigned int hashval;
|
||||
int len;
|
||||
struct var *vp, **vpp;
|
||||
const char *p = name;
|
||||
|
||||
hashval = 0;
|
||||
while (*p && *p != '=')
|
||||
hashval = 2 * hashval + (unsigned char)*p++;
|
||||
len = p - name;
|
||||
|
||||
if (lenp)
|
||||
*lenp = len;
|
||||
vpp = &vartab[hashval % VTABSIZE];
|
||||
if (vppp)
|
||||
*vppp = vpp;
|
||||
|
||||
for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) {
|
||||
if (vp->name_len != len)
|
||||
continue;
|
||||
if (memcmp(vp->text, name, len) != 0)
|
||||
continue;
|
||||
if (vppp)
|
||||
*vppp = vpp;
|
||||
return vp;
|
||||
}
|
||||
return NULL;
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
/* $NetBSD: var.h,v 1.25 2011/06/18 21:18:46 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -13,7 +15,7 @@
|
|||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
|
@ -30,7 +32,6 @@
|
|||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)var.h 8.2 (Berkeley) 5/4/95
|
||||
* $FreeBSD: src/bin/sh/var.h,v 1.12 2004/04/06 20:06:51 markm Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -40,17 +41,19 @@
|
|||
/* flags */
|
||||
#define VEXPORT 0x01 /* variable is exported */
|
||||
#define VREADONLY 0x02 /* variable cannot be modified */
|
||||
#define VSTRFIXED 0x04 /* variable struct is staticly allocated */
|
||||
#define VTEXTFIXED 0x08 /* text is staticly allocated */
|
||||
#define VSTRFIXED 0x04 /* variable struct is statically allocated */
|
||||
#define VTEXTFIXED 0x08 /* text is statically allocated */
|
||||
#define VSTACK 0x10 /* text is allocated on the stack */
|
||||
#define VUNSET 0x20 /* the variable is not set */
|
||||
#define VNOFUNC 0x40 /* don't call the callback function */
|
||||
#define VNOSET 0x80 /* do not set variable - just readonly test */
|
||||
|
||||
|
||||
struct var {
|
||||
struct var *next; /* next entry in hash list */
|
||||
int flags; /* flags are defined above */
|
||||
char *text; /* name=value */
|
||||
int name_len; /* length of name */
|
||||
void (*func)(const char *);
|
||||
/* function to be called when */
|
||||
/* the variable gets set/unset */
|
||||
|
@ -65,17 +68,21 @@ struct localvar {
|
|||
};
|
||||
|
||||
|
||||
struct localvar *localvars;
|
||||
extern struct localvar *localvars;
|
||||
|
||||
#if ATTY
|
||||
extern struct var vatty;
|
||||
#endif
|
||||
extern struct var vifs;
|
||||
extern struct var vmail;
|
||||
extern struct var vmpath;
|
||||
extern struct var vpath;
|
||||
extern struct var vppid;
|
||||
extern struct var vps1;
|
||||
extern struct var vps2;
|
||||
extern struct var vpse;
|
||||
#ifndef NO_HISTORY
|
||||
extern struct var vps4;
|
||||
#ifndef SMALL
|
||||
extern struct var vterm;
|
||||
extern struct var vtermcap;
|
||||
extern struct var vhistsize;
|
||||
#endif
|
||||
|
||||
|
@ -92,33 +99,31 @@ extern struct var vhistsize;
|
|||
#define pathval() (vpath.text + 5)
|
||||
#define ps1val() (vps1.text + 4)
|
||||
#define ps2val() (vps2.text + 4)
|
||||
#define pseval() (vpse.text + 4)
|
||||
#define ps4val() (vps4.text + 4)
|
||||
#define optindval() (voptind.text + 7)
|
||||
#ifndef NO_HISTORY
|
||||
#ifndef SMALL
|
||||
#define histsizeval() (vhistsize.text + 9)
|
||||
#define termval() (vterm.text + 5)
|
||||
#endif
|
||||
|
||||
#if ATTY
|
||||
#define attyset() ((vatty.flags & VUNSET) == 0)
|
||||
#endif
|
||||
#define mpathset() ((vmpath.flags & VUNSET) == 0)
|
||||
|
||||
void initvar(void);
|
||||
void setvar(char *, char *, int);
|
||||
void setvar(const char *, const char *, int);
|
||||
void setvareq(char *, int);
|
||||
struct strlist;
|
||||
void listsetvar(struct strlist *);
|
||||
char *lookupvar(char *);
|
||||
char *bltinlookup(char *, int);
|
||||
void listsetvar(struct strlist *, int);
|
||||
char *lookupvar(const char *);
|
||||
char *bltinlookup(const char *, int);
|
||||
char **environment(void);
|
||||
void shprocvar(void);
|
||||
int showvarscmd(int, char **);
|
||||
int exportcmd(int, char **);
|
||||
int localcmd(int, char **);
|
||||
void mklocal(char *);
|
||||
int showvars(const char *, int, int);
|
||||
void mklocal(const char *, int);
|
||||
void listmklocal(struct strlist *, int);
|
||||
void poplocalvars(void);
|
||||
int setvarcmd(int, char **);
|
||||
int unsetcmd(int, char **);
|
||||
int unsetvar(char *);
|
||||
int setvarsafe(char *, char *, int);
|
||||
|
||||
/*
|
||||
* $PchId: var.h,v 1.4 2006/03/29 12:04:45 philip Exp $
|
||||
*/
|
||||
int unsetvar(const char *, int);
|
||||
int setvarsafe(const char *, const char *, int);
|
||||
void print_quoted(const char *);
|
|
@ -2214,14 +2214,14 @@
|
|||
./usr/Makefile minix-sys
|
||||
./usr/man minix-sys
|
||||
./usr/man/man1 minix-sys
|
||||
./usr/man/man1/..1 minix-sys
|
||||
./usr/man/man1/..1 minix-sys obsolete
|
||||
./usr/man/man1/[.1 minix-sys
|
||||
./usr/man/man1/addr2line.1 minix-sys binutils
|
||||
./usr/man/man1/apropos.1 minix-sys
|
||||
./usr/man/man1/ar.1 minix-sys binutils
|
||||
./usr/man/man1/as.1 minix-sys binutils
|
||||
./usr/man/man1/asa.1 minix-sys
|
||||
./usr/man/man1/ash.1 minix-sys
|
||||
./usr/man/man1/ash.1 minix-sys obsolete
|
||||
./usr/man/man1/at.1 minix-sys
|
||||
./usr/man/man1/atf2kyua.1 minix-sys kyua
|
||||
./usr/man/man1/atf-check.1 minix-sys atf
|
||||
|
@ -2235,7 +2235,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/break.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
|
||||
./usr/man/man1/bunzip2.1 minix-sys
|
||||
|
@ -2245,12 +2245,12 @@
|
|||
./usr/man/man1/c++.1 minix-sys gcccmds
|
||||
./usr/man/man1/cal.1 minix-sys
|
||||
./usr/man/man1/calendar.1 minix-sys
|
||||
./usr/man/man1/case.1 minix-sys
|
||||
./usr/man/man1/case.1 minix-sys obsolete
|
||||
./usr/man/man1/cat.1 minix-sys
|
||||
./usr/man/man1/cawf.1 minix-sys
|
||||
./usr/man/man1/cc.1 minix-sys gcccmds
|
||||
./usr/man/man1/cccp.1 minix-sys gcccmds
|
||||
./usr/man/man1/cd.1 minix-sys
|
||||
./usr/man/man1/cd.1 minix-sys obsolete
|
||||
./usr/man/man1/c++filt.1 minix-sys binutils
|
||||
./usr/man/man1/checknr.1 minix-sys
|
||||
./usr/man/man1/chfn.1 minix-sys
|
||||
|
@ -2268,9 +2268,9 @@
|
|||
./usr/man/man1/colrm.1 minix-sys
|
||||
./usr/man/man1/column.1 minix-sys
|
||||
./usr/man/man1/comm.1 minix-sys
|
||||
./usr/man/man1/command.1 minix-sys
|
||||
./usr/man/man1/command.1 minix-sys obsolete
|
||||
./usr/man/man1/compress.1 minix-sys
|
||||
./usr/man/man1/continue.1 minix-sys
|
||||
./usr/man/man1/continue.1 minix-sys obsolete
|
||||
./usr/man/man1/cp.1 minix-sys
|
||||
./usr/man/man1/cpio.1 minix-sys
|
||||
./usr/man/man1/cpp.1 minix-sys gcccmds
|
||||
|
@ -2296,12 +2296,12 @@
|
|||
./usr/man/man1/eject.1 minix-sys
|
||||
./usr/man/man1/elfedit.1 minix-sys binutils
|
||||
./usr/man/man1/env.1 minix-sys
|
||||
./usr/man/man1/eval.1 minix-sys
|
||||
./usr/man/man1/eval.1 minix-sys obsolete
|
||||
./usr/man/man1/ex.1 minix-sys
|
||||
./usr/man/man1/exec.1 minix-sys
|
||||
./usr/man/man1/exit.1 minix-sys
|
||||
./usr/man/man1/exec.1 minix-sys obsolete
|
||||
./usr/man/man1/exit.1 minix-sys obsolete
|
||||
./usr/man/man1/expand.1 minix-sys
|
||||
./usr/man/man1/export.1 minix-sys
|
||||
./usr/man/man1/export.1 minix-sys obsolete
|
||||
./usr/man/man1/expr.1 minix-sys
|
||||
./usr/man/man1/false.1 minix-sys
|
||||
./usr/man/man1/fetch.1 minix-sys
|
||||
|
@ -2312,7 +2312,7 @@
|
|||
./usr/man/man1/flex.1 minix-sys
|
||||
./usr/man/man1/flexdoc.1 minix-sys
|
||||
./usr/man/man1/fold.1 minix-sys
|
||||
./usr/man/man1/for.1 minix-sys
|
||||
./usr/man/man1/for.1 minix-sys obsolete
|
||||
./usr/man/man1/format.1 minix-sys
|
||||
./usr/man/man1/fpr.1 minix-sys
|
||||
./usr/man/man1/from.1 minix-sys
|
||||
|
@ -2325,7 +2325,7 @@
|
|||
./usr/man/man1/gcpp.1 minix-sys gcccmds
|
||||
./usr/man/man1/genassym.1 minix-sys
|
||||
./usr/man/man1/getopt.1 minix-sys
|
||||
./usr/man/man1/getopts.1 minix-sys
|
||||
./usr/man/man1/getopts.1 minix-sys obsolete
|
||||
./usr/man/man1/gprof.1 minix-sys binutils
|
||||
./usr/man/man1/grep.1 minix-sys
|
||||
./usr/man/man1/groups.1 minix-sys
|
||||
|
@ -2333,14 +2333,14 @@
|
|||
./usr/man/man1/gzcat.1 minix-sys
|
||||
./usr/man/man1/gzexe.1 minix-sys
|
||||
./usr/man/man1/gzip.1 minix-sys
|
||||
./usr/man/man1/hash.1 minix-sys
|
||||
./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/host.1 minix-sys
|
||||
./usr/man/man1/hostaddr.1 minix-sys
|
||||
./usr/man/man1/hostname.1 minix-sys
|
||||
./usr/man/man1/id.1 minix-sys
|
||||
./usr/man/man1/if.1 minix-sys
|
||||
./usr/man/man1/if.1 minix-sys obsolete
|
||||
./usr/man/man1/ifdef.1 minix-sys
|
||||
./usr/man/man1/indent.1 minix-sys
|
||||
./usr/man/man1/info.1 minix-sys
|
||||
|
@ -2351,7 +2351,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
|
||||
./usr/man/man1/jobs.1 minix-sys obsolete
|
||||
./usr/man/man1/join.1 minix-sys
|
||||
./usr/man/man1/jot.1 minix-sys
|
||||
./usr/man/man1/kill.1 minix-sys
|
||||
|
@ -2384,7 +2384,7 @@
|
|||
./usr/man/man1/ln.1 minix-sys
|
||||
./usr/man/man1/loadfont.1 minix-sys
|
||||
./usr/man/man1/loadkeys.1 minix-sys
|
||||
./usr/man/man1/local.1 minix-sys
|
||||
./usr/man/man1/local.1 minix-sys obsolete
|
||||
./usr/man/man1/lock.1 minix-sys
|
||||
./usr/man/man1/logger.1 minix-sys
|
||||
./usr/man/man1/login.1 minix-sys
|
||||
|
@ -2454,13 +2454,13 @@
|
|||
./usr/man/man1/pwhash.1 minix-sys
|
||||
./usr/man/man1/ranlib.1 minix-sys binutils
|
||||
./usr/man/man1/rcp.1 minix-sys
|
||||
./usr/man/man1/read.1 minix-sys
|
||||
./usr/man/man1/read.1 minix-sys obsolete
|
||||
./usr/man/man1/readelf.1 minix-sys binutils
|
||||
./usr/man/man1/readlink.1 minix-sys
|
||||
./usr/man/man1/readonly.1 minix-sys
|
||||
./usr/man/man1/readonly.1 minix-sys obsolete
|
||||
./usr/man/man1/recwave.1 minix-sys
|
||||
./usr/man/man1/remsync.1 minix-sys
|
||||
./usr/man/man1/return.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
|
||||
./usr/man/man1/rlogin.1 minix-sys
|
||||
|
@ -2472,12 +2472,12 @@
|
|||
./usr/man/man1/sdiff.1 minix-sys
|
||||
./usr/man/man1/sed.1 minix-sys
|
||||
./usr/man/man1/seq.1 minix-sys
|
||||
./usr/man/man1/set.1 minix-sys
|
||||
./usr/man/man1/setvar.1 minix-sys
|
||||
./usr/man/man1/set.1 minix-sys obsolete
|
||||
./usr/man/man1/setvar.1 minix-sys obsolete
|
||||
./usr/man/man1/sh.1 minix-sys
|
||||
./usr/man/man1/sha1.1 minix-sys
|
||||
./usr/man/man1/shar.1 minix-sys
|
||||
./usr/man/man1/shift.1 minix-sys
|
||||
./usr/man/man1/shift.1 minix-sys obsolete
|
||||
./usr/man/man1/shlock.1 minix-sys
|
||||
./usr/man/man1/shuffle.1 minix-sys
|
||||
./usr/man/man1/size.1 minix-sys binutils
|
||||
|
@ -2514,13 +2514,13 @@
|
|||
./usr/man/man1/touch.1 minix-sys
|
||||
./usr/man/man1/tput.1 minix-sys
|
||||
./usr/man/man1/tr.1 minix-sys
|
||||
./usr/man/man1/trap.1 minix-sys
|
||||
./usr/man/man1/trap.1 minix-sys obsolete
|
||||
./usr/man/man1/true.1 minix-sys
|
||||
./usr/man/man1/truncate.1 minix-sys
|
||||
./usr/man/man1/tsort.1 minix-sys
|
||||
./usr/man/man1/tty.1 minix-sys
|
||||
./usr/man/man1/ul.1 minix-sys
|
||||
./usr/man/man1/umask.1 minix-sys
|
||||
./usr/man/man1/umask.1 minix-sys obsolete
|
||||
./usr/man/man1/umount.1 minix-sys
|
||||
./usr/man/man1/uname.1 minix-sys
|
||||
./usr/man/man1/uncompress.1 minix-sys
|
||||
|
@ -2530,7 +2530,7 @@
|
|||
./usr/man/man1/uniq.1 minix-sys
|
||||
./usr/man/man1/units.1 minix-sys
|
||||
./usr/man/man1/unlzma.1 minix-sys
|
||||
./usr/man/man1/unset.1 minix-sys
|
||||
./usr/man/man1/unset.1 minix-sys obsolete
|
||||
./usr/man/man1/unvis.1 minix-sys
|
||||
./usr/man/man1/unxz.1 minix-sys
|
||||
./usr/man/man1/unzip.1 minix-sys
|
||||
|
@ -2544,7 +2544,7 @@
|
|||
./usr/man/man1/vis.1 minix-sys
|
||||
./usr/man/man1/vol.1 minix-sys
|
||||
./usr/man/man1/w.1 minix-sys
|
||||
./usr/man/man1/wait.1 minix-sys
|
||||
./usr/man/man1/wait.1 minix-sys obsolete
|
||||
./usr/man/man1/wall.1 minix-sys
|
||||
./usr/man/man1/wc.1 minix-sys
|
||||
./usr/man/man1/what.1 minix-sys
|
||||
|
@ -5249,6 +5249,15 @@
|
|||
./usr/share/doc/psd/19.curses/twinkle1.c minix-sys
|
||||
./usr/share/doc/psd/19.curses/twinkle2.c minix-sys
|
||||
./usr/share/doc/psd/19.curses/win_st.c minix-sys
|
||||
./usr/share/doc/usd minix-sys
|
||||
./usr/share/doc/usd/03.shell minix-sys
|
||||
./usr/share/doc/usd/03.shell/Makefile minix-sys
|
||||
./usr/share/doc/usd/03.shell/Rv7man minix-sys
|
||||
./usr/share/doc/usd/03.shell/t1 minix-sys
|
||||
./usr/share/doc/usd/03.shell/t2 minix-sys
|
||||
./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/examples minix-sys atf
|
||||
./usr/share/examples/atf minix-sys atf
|
||||
./usr/share/examples/atf/atf-run.hooks minix-sys atf,!kyua
|
||||
|
|
|
@ -114,6 +114,8 @@
|
|||
./usr/share/doc/html/bzip2
|
||||
./usr/share/doc/psd
|
||||
./usr/share/doc/psd/19.curses
|
||||
./usr/share/doc/usd
|
||||
./usr/share/doc/usd/03.shell
|
||||
./usr/share/info
|
||||
./usr/share/games
|
||||
./usr/share/games/fortune
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
# Activate emacs keybindings and command line history support
|
||||
set -o emacs
|
||||
set -o tabcomplete
|
||||
|
||||
# Set the default path
|
||||
PATH=/usr/local/bin:/usr/pkg/bin:/usr/bin:/bin:/usr/games
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
SUBDIR= add_route arp ash at backup btrace \
|
||||
SUBDIR= add_route arp at backup btrace \
|
||||
cawf cdprobe \
|
||||
ci cleantmp cmp co \
|
||||
compress crc cron crontab \
|
||||
|
|
|
@ -1,101 +0,0 @@
|
|||
# Makefile for ash.
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
PROG= sh
|
||||
BINDIR= /bin
|
||||
MAN=
|
||||
|
||||
# Enable this line to disable command line editing
|
||||
#EDIT=-DNO_HISTORY
|
||||
|
||||
# Enable this line if your system does not have a <paths.h>
|
||||
#NO_PATHS_H=-DNO_PATHS_H
|
||||
|
||||
# Enable this if you don't want job control
|
||||
NO_JOBS=-DJOBS=0
|
||||
MKB_NO_JOBS=-j
|
||||
|
||||
SRCS= alias.c arith.y arith_lex.l cd.c complete.c eval.c exec.c expand.c \
|
||||
histedit.c input.c jobs.c mail.c main.c memalloc.c miscbltin.c \
|
||||
mystring.c options.c output.c parser.c redir.c show.c \
|
||||
trap.c var.c setmode.c
|
||||
|
||||
.include "${.CURDIR}/bltin/Makefile.inc"
|
||||
|
||||
GENSRCS= builtins.c init.c nodes.c syntax.c operators.c signames.c
|
||||
GENHDRS= builtins.h nodes.h syntax.h token.h operators.h signames.h
|
||||
|
||||
SRCS+= ${GENSRCS}
|
||||
|
||||
CLEANFILES+=${GENSRCS} ${GENHDRS}
|
||||
|
||||
DPADD+= ${LIBL} ${LIBEDIT}
|
||||
LDADD+= -ll -ledit
|
||||
|
||||
CPPFLAGS+= -DSHELL
|
||||
CPPFLAGS+=${EDIT} ${NO_PATHS_H} ${NO_JOBS}
|
||||
|
||||
CPPFLAGS+= -I. -I${.CURDIR}
|
||||
|
||||
# A. Generate C tools used to build ash
|
||||
.for tool in init nodes signames syntax
|
||||
${.OBJDIR}/mk${tool}: ${.CURDIR}/mk${tool}.c
|
||||
${HOST_CC} ${HOST_CFLAGS} ${HOST_CPPFLAGS} ${.ALLSRC} -o ${.TARGET}
|
||||
|
||||
CLEANFILES+= ${.OBJDIR}/mk${tool}
|
||||
.endfor
|
||||
|
||||
# B. Generates C sources from C tools
|
||||
NODES_ARGS:= ${.CURDIR}/nodetypes ${.CURDIR}/nodes.c.pat
|
||||
INIT_ARGS:= alias.c eval.c exec.c input.c jobs.c options.c parser.c \
|
||||
redir.c trap.c var.c
|
||||
|
||||
.for tool in nodes signames syntax
|
||||
${tool}.c ${tool}.h: ${.OBJDIR}/mk${tool}
|
||||
${.OBJDIR}/mk${tool} ${${tool:tu}_ARGS}
|
||||
.endfor
|
||||
|
||||
init.c: ${.OBJDIR}/mkinit \
|
||||
alias.c eval.c exec.c input.c jobs.c options.c parser.c \
|
||||
redir.c trap.c var.c
|
||||
${.OBJDIR}/mkinit ${.ALLSRC:S,^${.OBJDIR}/mkinit$,,}
|
||||
|
||||
# C. Generates C sources from shell scripts
|
||||
token.h:
|
||||
${.CURDIR}/mktokens.sh
|
||||
|
||||
builtins.c builtins.h:
|
||||
${.CURDIR}/mkbuiltins.sh ${MKB_NO_JOBS} . ${.CURDIR}/shell.h ${.CURDIR}/builtins.def
|
||||
|
||||
operators.c operators.h:
|
||||
${.CURDIR}/bltin/mkexpr.sh ${.CURDIR}/bltin/unary_op ${.CURDIR}/bltin/binary_op
|
||||
|
||||
# D. Generates sources from yacc/lex
|
||||
LFLAGS= -8 # 8-bit lex scanner for arithmetic
|
||||
|
||||
YFLAGS:= -d
|
||||
CLEANFILES+= arith.h arith.y.o
|
||||
|
||||
parser.c: token.h
|
||||
y.tab.h: arith.y
|
||||
arith.h: y.tab.h
|
||||
arith_lex.l: arith.h
|
||||
|
||||
# Explicit dependencies to ensure creation when needed
|
||||
# LSC FIXME Under MINIX, the build system curiously needs more help.
|
||||
# is it because of the missing order tools?
|
||||
expand.c: arith.h
|
||||
trap.c: signames.h
|
||||
cd.c complete.c eval.c exec.c expand.c jobs.c main.c options.c parser.c redir.c show.c trap.c var.c: nodes.h
|
||||
eval.c exec.c expand.c input.c input.h jobs.c mystring.c output.c parser.c trap.c var.c: syntax.h
|
||||
cd.c eval.c exec.c histedit.cjobs.c main.c miscbltin.c options.c trap.c var.c: builtins.h
|
||||
|
||||
# LSC: Seems that this file is implicitly taken into account by NetBSD's make,
|
||||
# still seems to be ignored / not found currently.
|
||||
# It's a sad story, as it has default rules to manage yacc / lex files. So for
|
||||
# a happy ending here it is explicitly included:
|
||||
.include <sys.mk>
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
|
@ -1,360 +0,0 @@
|
|||
%{
|
||||
/*-
|
||||
* Copyright (c) 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Kenneth Almquist.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#if 0
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)arith.y 8.3 (Berkeley) 5/4/95";
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
/*
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/bin/sh/arith.y,v 1.19 2004/05/24 10:11:31 stefanf Exp $");
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
#include "shell.h"
|
||||
#include "expand.h"
|
||||
#include "var.h"
|
||||
%}
|
||||
%union {
|
||||
arith_t l_value;
|
||||
char* s_value;
|
||||
}
|
||||
%token <l_value> ARITH_NUM ARITH_LPAREN ARITH_RPAREN
|
||||
%token <s_value> ARITH_VAR
|
||||
|
||||
%type <l_value> expr
|
||||
%right ARITH_ASSIGN
|
||||
%right ARITH_ADDASSIGN ARITH_SUBASSIGN
|
||||
%right ARITH_MULASSIGN ARITH_DIVASSIGN ARITH_REMASSIGN
|
||||
%right ARITH_RSHASSIGN ARITH_LSHASSIGN
|
||||
%right ARITH_BANDASSIGN ARITH_BXORASSIGN ARITH_BORASSIGN
|
||||
%left ARITH_OR
|
||||
%left ARITH_AND
|
||||
%left ARITH_BOR
|
||||
%left ARITH_BXOR
|
||||
%left ARITH_BAND
|
||||
%left ARITH_EQ ARITH_NE
|
||||
%left ARITH_LT ARITH_GT ARITH_GE ARITH_LE
|
||||
%left ARITH_LSHIFT ARITH_RSHIFT
|
||||
%left ARITH_ADD ARITH_SUB
|
||||
%left ARITH_MUL ARITH_DIV ARITH_REM
|
||||
%left ARITH_UNARYMINUS ARITH_UNARYPLUS ARITH_NOT ARITH_BNOT
|
||||
%%
|
||||
|
||||
exp:
|
||||
expr
|
||||
{ return ($1); }
|
||||
;
|
||||
|
||||
expr:
|
||||
ARITH_LPAREN expr ARITH_RPAREN
|
||||
{ $$ = $2; } |
|
||||
expr ARITH_OR expr
|
||||
{ $$ = $1 ? $1 : $3 ? $3 : 0; } |
|
||||
expr ARITH_AND expr
|
||||
{ $$ = $1 ? ( $3 ? $3 : 0 ) : 0; } |
|
||||
expr ARITH_BOR expr
|
||||
{ $$ = $1 | $3; } |
|
||||
expr ARITH_BXOR expr
|
||||
{ $$ = $1 ^ $3; } |
|
||||
expr ARITH_BAND expr
|
||||
{ $$ = $1 & $3; } |
|
||||
expr ARITH_EQ expr
|
||||
{ $$ = $1 == $3; } |
|
||||
expr ARITH_GT expr
|
||||
{ $$ = $1 > $3; } |
|
||||
expr ARITH_GE expr
|
||||
{ $$ = $1 >= $3; } |
|
||||
expr ARITH_LT expr
|
||||
{ $$ = $1 < $3; } |
|
||||
expr ARITH_LE expr
|
||||
{ $$ = $1 <= $3; } |
|
||||
expr ARITH_NE expr
|
||||
{ $$ = $1 != $3; } |
|
||||
expr ARITH_LSHIFT expr
|
||||
{ $$ = $1 << $3; } |
|
||||
expr ARITH_RSHIFT expr
|
||||
{ $$ = $1 >> $3; } |
|
||||
expr ARITH_ADD expr
|
||||
{ $$ = $1 + $3; } |
|
||||
expr ARITH_SUB expr
|
||||
{ $$ = $1 - $3; } |
|
||||
expr ARITH_MUL expr
|
||||
{ $$ = $1 * $3; } |
|
||||
expr ARITH_DIV expr
|
||||
{
|
||||
if ($3 == 0)
|
||||
yyerror("division by zero");
|
||||
$$ = $1 / $3;
|
||||
} |
|
||||
expr ARITH_REM expr
|
||||
{
|
||||
if ($3 == 0)
|
||||
yyerror("division by zero");
|
||||
$$ = $1 % $3;
|
||||
} |
|
||||
ARITH_NOT expr
|
||||
{ $$ = !($2); } |
|
||||
ARITH_BNOT expr
|
||||
{ $$ = ~($2); } |
|
||||
ARITH_SUB expr %prec ARITH_UNARYMINUS
|
||||
{ $$ = -($2); } |
|
||||
ARITH_ADD expr %prec ARITH_UNARYPLUS
|
||||
{ $$ = $2; } |
|
||||
ARITH_NUM |
|
||||
ARITH_VAR
|
||||
{
|
||||
char *p;
|
||||
arith_t arith_val;
|
||||
char *str_val;
|
||||
|
||||
if (lookupvar($1) == NULL)
|
||||
setvarsafe($1, "0", 0);
|
||||
str_val = lookupvar($1);
|
||||
arith_val = strtoarith_t(str_val, &p, 0);
|
||||
/*
|
||||
* Conversion is successful only in case
|
||||
* we've converted _all_ characters.
|
||||
*/
|
||||
if (*p != '\0')
|
||||
yyerror("variable conversion error");
|
||||
$$ = arith_val;
|
||||
} |
|
||||
ARITH_VAR ARITH_ASSIGN expr
|
||||
{
|
||||
if (arith_assign($1, $3) != 0)
|
||||
yyerror("variable assignment error");
|
||||
$$ = $3;
|
||||
} |
|
||||
ARITH_VAR ARITH_ADDASSIGN expr
|
||||
{
|
||||
arith_t value;
|
||||
|
||||
value = atoarith_t(lookupvar($1)) + $3;
|
||||
if (arith_assign($1, value) != 0)
|
||||
yyerror("variable assignment error");
|
||||
$$ = value;
|
||||
} |
|
||||
ARITH_VAR ARITH_SUBASSIGN expr
|
||||
{
|
||||
arith_t value;
|
||||
|
||||
value = atoarith_t(lookupvar($1)) - $3;
|
||||
if (arith_assign($1, value) != 0)
|
||||
yyerror("variable assignment error");
|
||||
$$ = value;
|
||||
} |
|
||||
ARITH_VAR ARITH_MULASSIGN expr
|
||||
{
|
||||
arith_t value;
|
||||
|
||||
value = atoarith_t(lookupvar($1)) * $3;
|
||||
if (arith_assign($1, value) != 0)
|
||||
yyerror("variable assignment error");
|
||||
$$ = value;
|
||||
} |
|
||||
ARITH_VAR ARITH_DIVASSIGN expr
|
||||
{
|
||||
arith_t value;
|
||||
|
||||
if ($3 == 0)
|
||||
yyerror("division by zero");
|
||||
|
||||
value = atoarith_t(lookupvar($1)) / $3;
|
||||
if (arith_assign($1, value) != 0)
|
||||
yyerror("variable assignment error");
|
||||
$$ = value;
|
||||
} |
|
||||
ARITH_VAR ARITH_REMASSIGN expr
|
||||
{
|
||||
arith_t value;
|
||||
|
||||
if ($3 == 0)
|
||||
yyerror("division by zero");
|
||||
|
||||
value = atoarith_t(lookupvar($1)) % $3;
|
||||
if (arith_assign($1, value) != 0)
|
||||
yyerror("variable assignment error");
|
||||
$$ = value;
|
||||
} |
|
||||
ARITH_VAR ARITH_RSHASSIGN expr
|
||||
{
|
||||
arith_t value;
|
||||
|
||||
value = atoarith_t(lookupvar($1)) >> $3;
|
||||
if (arith_assign($1, value) != 0)
|
||||
yyerror("variable assignment error");
|
||||
$$ = value;
|
||||
} |
|
||||
ARITH_VAR ARITH_LSHASSIGN expr
|
||||
{
|
||||
arith_t value;
|
||||
|
||||
value = atoarith_t(lookupvar($1)) << $3;
|
||||
if (arith_assign($1, value) != 0)
|
||||
yyerror("variable assignment error");
|
||||
$$ = value;
|
||||
} |
|
||||
ARITH_VAR ARITH_BANDASSIGN expr
|
||||
{
|
||||
arith_t value;
|
||||
|
||||
value = atoarith_t(lookupvar($1)) & $3;
|
||||
if (arith_assign($1, value) != 0)
|
||||
yyerror("variable assignment error");
|
||||
$$ = value;
|
||||
} |
|
||||
ARITH_VAR ARITH_BXORASSIGN expr
|
||||
{
|
||||
arith_t value;
|
||||
|
||||
value = atoarith_t(lookupvar($1)) ^ $3;
|
||||
if (arith_assign($1, value) != 0)
|
||||
yyerror("variable assignment error");
|
||||
$$ = value;
|
||||
} |
|
||||
ARITH_VAR ARITH_BORASSIGN expr
|
||||
{
|
||||
arith_t value;
|
||||
|
||||
value = atoarith_t(lookupvar($1)) | $3;
|
||||
if (arith_assign($1, value) != 0)
|
||||
yyerror("variable assignment error");
|
||||
$$ = value;
|
||||
} ;
|
||||
%%
|
||||
#include "error.h"
|
||||
#include "output.h"
|
||||
#include "memalloc.h"
|
||||
|
||||
#define lstrlen(var) (3 + (2 + CHAR_BIT * sizeof((var))) / 3)
|
||||
|
||||
char *arith_buf, *arith_startbuf;
|
||||
|
||||
int yylex(void);
|
||||
int yyparse(void);
|
||||
|
||||
int
|
||||
arith_assign(char *name, arith_t value)
|
||||
{
|
||||
char *str;
|
||||
int ret;
|
||||
|
||||
str = (char *)ckmalloc(lstrlen(value));
|
||||
sprintf(str, ARITH_FORMAT_STR, value);
|
||||
ret = setvarsafe(name, str, 0);
|
||||
free(str);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
arith(char *s)
|
||||
{
|
||||
long result;
|
||||
|
||||
arith_buf = arith_startbuf = s;
|
||||
|
||||
INTOFF;
|
||||
result = yyparse();
|
||||
arith_lex_reset(); /* Reprime lex. */
|
||||
INTON;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
yyerror(char *s)
|
||||
{
|
||||
|
||||
yyerrok;
|
||||
yyclearin;
|
||||
arith_lex_reset(); /* Reprime lex. */
|
||||
error("arithmetic expression: %s: \"%s\"", s, arith_startbuf);
|
||||
}
|
||||
|
||||
/*
|
||||
* The exp(1) builtin.
|
||||
*/
|
||||
int
|
||||
expcmd(int argc, char **argv)
|
||||
{
|
||||
char *p;
|
||||
char *concat;
|
||||
char **ap;
|
||||
long i;
|
||||
|
||||
if (argc > 1) {
|
||||
p = argv[1];
|
||||
if (argc > 2) {
|
||||
/*
|
||||
* Concatenate arguments.
|
||||
*/
|
||||
STARTSTACKSTR(concat);
|
||||
ap = argv + 2;
|
||||
for (;;) {
|
||||
while (*p)
|
||||
STPUTC(*p++, concat);
|
||||
if ((p = *ap++) == NULL)
|
||||
break;
|
||||
STPUTC(' ', concat);
|
||||
}
|
||||
STPUTC('\0', concat);
|
||||
p = grabstackstr(concat);
|
||||
}
|
||||
} else
|
||||
p = "";
|
||||
|
||||
i = arith(p);
|
||||
|
||||
out1fmt("%ld\n", i);
|
||||
return !i;
|
||||
}
|
||||
|
||||
/*************************/
|
||||
#ifdef TEST_ARITH
|
||||
#include <stdio.h>
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
printf("%d\n", exp(argv[1]));
|
||||
}
|
||||
|
||||
error(char *s)
|
||||
{
|
||||
fprintf(stderr, "exp: %s\n", s);
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
|
@ -1,12 +0,0 @@
|
|||
/*
|
||||
arith_lex.h
|
||||
|
||||
Created: July 1995 by Philip Homburg <philip@cs.vu.nl>
|
||||
*/
|
||||
|
||||
int yylex(void);
|
||||
void arith_lex_reset(void);
|
||||
|
||||
/*
|
||||
* $PchId: arith_lex.h,v 1.1 2001/05/18 19:57:55 philip Exp $
|
||||
*/
|
|
@ -1,40 +0,0 @@
|
|||
ASH GENERAL PUBLIC LICENSE
|
||||
|
||||
1. You may copy and distribute ash code or code derived from it in
|
||||
source or object form, provided that you conspicuously and appropriately
|
||||
publish on each copy a valid copyright notice "Copyright 1989 by Kenneth
|
||||
Almquist." (or with whatever year is appropriate); keep intact the
|
||||
notices on all files that refer to this License Agreement and to the
|
||||
absence of any warranty; and give any other recipients of the ash program
|
||||
a copy of this License Agreement along with the program.
|
||||
|
||||
2. You may not copy, sublicense, distribute or transfer ash except as
|
||||
expressly provided under this License Agreement. Any attempt otherwise
|
||||
to copy, sublicense, distribute or transfer ash is void and your rights
|
||||
to use ash under this License agreement shall be automatically terminated.
|
||||
However, parties who have received computer software programs from you
|
||||
with this License Agreement will not have their licenses terminated so
|
||||
long as such parties remain in full compliance.
|
||||
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
Because ash is licensed free of charge, I provide absolutely no
|
||||
warranty, to the extent permitted by applicable state law. Except
|
||||
when otherwise stated in writing, Kenneth Almquist and/or other
|
||||
parties provide ash "as is" without warranty of any kind, either
|
||||
expressed or implied, including, but not limited to, the implied
|
||||
warranties of merchantability and fitness for a particular purpose.
|
||||
The entire risk as to the quality and performance of the program is
|
||||
with you. Should the ash program prove defective, you assume the cost
|
||||
of all necessary servicing, repair or correction.
|
||||
|
||||
In no event unless required by applicable law will Kenneth Almquist
|
||||
and/or any other party who may modify and redistribute ash as permitted
|
||||
above, be liable to you for damages, including any lost profits, lost
|
||||
monies, or other special, incidental or consequential damages arising
|
||||
out of the use or inability to use (including but not limited to loss
|
||||
of data or data being rendered inaccurate or losses sustained by third
|
||||
parties or a failure of the program to operate with programs provided
|
||||
by other parties) the program, even if you have been advised of the
|
||||
possibility of such damages, or for any claim by any other party.
|
|
@ -1,7 +0,0 @@
|
|||
|
||||
.PATH: ${.CURDIR}/bltin
|
||||
|
||||
SRCS+= echo.c error.c expr.c regexp.c
|
||||
|
||||
# LSC Again nbmake seems dumber on MINIX...
|
||||
expr.c: operators.h
|
|
@ -1,27 +0,0 @@
|
|||
# List of binary operators used by test/expr.
|
||||
#
|
||||
# Copyright 1989 by Kenneth Almquist. All rights reserved.
|
||||
# This file is part of ash, which is distributed under the terms specified
|
||||
# by the Ash General Public License. See the file named LICENSE.
|
||||
|
||||
OR1 -o 1
|
||||
OR2 | 1
|
||||
AND1 -a 2
|
||||
AND2 & 2
|
||||
STREQ = 4 OP_STRING
|
||||
STRNE != 4 OP_STRING
|
||||
NEWER -newer 4 OP_STRING
|
||||
NEWER -nt 4 OP_STRING
|
||||
OLDER -ot 4 OP_STRING
|
||||
EQ -eq 4 OP_INT
|
||||
NE -ne 4 OP_INT
|
||||
GT -gt 4 OP_INT
|
||||
LT -lt 4 OP_INT
|
||||
LE -le 4 OP_INT
|
||||
GE -ge 4 OP_INT
|
||||
PLUS + 5 OP_INT
|
||||
MINUS - 5 OP_INT
|
||||
TIMES * 6 OP_INT
|
||||
DIVIDE / 6 OP_INT
|
||||
REM % 6 OP_INT
|
||||
MATCHPAT : 7 OP_STRING
|
|
@ -1,88 +0,0 @@
|
|||
/*
|
||||
* Copy the files given as arguments to the standard output. The file
|
||||
* name "-" refers to the standard input.
|
||||
*
|
||||
* Copyright (C) 1989 by Kenneth Almquist. All rights reserved.
|
||||
* This file is part of ash, which is distributed under the terms specified
|
||||
* by the Ash General Public License. See the file named LICENSE.
|
||||
*/
|
||||
|
||||
#define main catfcmd
|
||||
|
||||
#include "bltin.h"
|
||||
#include "../error.h"
|
||||
#include <sys/param.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
|
||||
#ifdef SBUFSIZE
|
||||
#define BUFSIZE() SBUFSIZE
|
||||
#else
|
||||
#ifdef MAXBSIZE
|
||||
#define BUFSIZE() MAXBSIZE
|
||||
#else
|
||||
#define BUFSIZE() BSIZE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
main(argc, argv) char **argv; {
|
||||
char *filename;
|
||||
char *buf = stalloc(BUFSIZE());
|
||||
int fd;
|
||||
int i;
|
||||
#ifdef SHELL
|
||||
volatile int input;
|
||||
struct jmploc jmploc;
|
||||
struct jmploc *volatile savehandler;
|
||||
#endif
|
||||
|
||||
INITARGS(argv);
|
||||
#ifdef SHELL
|
||||
input = -1;
|
||||
if (setjmp(jmploc.loc)) {
|
||||
close(input);
|
||||
handler = savehandler;
|
||||
longjmp(handler, 1);
|
||||
}
|
||||
savehandler = handler;
|
||||
handler = &jmploc;
|
||||
#endif
|
||||
while ((filename = *++argv) != NULL) {
|
||||
if (filename[0] == '-' && filename[1] == '\0') {
|
||||
fd = 0;
|
||||
} else {
|
||||
#ifdef SHELL
|
||||
INTOFF;
|
||||
if ((fd = open(filename, O_RDONLY)) < 0)
|
||||
error("Can't open %s", filename);
|
||||
input = fd;
|
||||
INTON;
|
||||
#else
|
||||
if ((fd = open(filename, O_RDONLY)) < 0) {
|
||||
fprintf(stderr, "catf: Can't open %s\n", filename);
|
||||
exit(2);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
while ((i = read(fd, buf, BUFSIZE())) > 0) {
|
||||
#ifdef SHELL
|
||||
if (out1 == &memout) {
|
||||
register char *p;
|
||||
for (p = buf ; --i >= 0 ; p++) {
|
||||
outc(*p, &memout);
|
||||
}
|
||||
} else {
|
||||
write(1, buf, i);
|
||||
}
|
||||
#else
|
||||
write(1, buf, i);
|
||||
#endif
|
||||
}
|
||||
if (fd != 0)
|
||||
close(fd);
|
||||
}
|
||||
#ifdef SHELL
|
||||
handler = savehandler;
|
||||
#endif
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 1989 by Kenneth Almquist. All rights reserved.
|
||||
* This file is part of ash, which is distributed under the terms specified
|
||||
* by the Ash General Public License. See the file named LICENSE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
char *commandname;
|
||||
|
||||
|
||||
void
|
||||
#ifdef __STDC__
|
||||
error(char *msg, ...) {
|
||||
#else
|
||||
error(msg)
|
||||
char *msg;
|
||||
{
|
||||
#endif
|
||||
|
||||
fprintf(stderr, "%s: %s\n", commandname, msg);
|
||||
exit(2);
|
||||
}
|
|
@ -1,482 +0,0 @@
|
|||
/*
|
||||
* The expr and test commands.
|
||||
*
|
||||
* Copyright (C) 1989 by Kenneth Almquist. All rights reserved.
|
||||
* This file is part of ash, which is distributed under the terms specified
|
||||
* by the Ash General Public License. See the file named LICENSE.
|
||||
*/
|
||||
|
||||
|
||||
#include "bltin.h"
|
||||
#include "operators.h"
|
||||
#include <regex.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
#define STACKSIZE 12
|
||||
#define NESTINCR 16
|
||||
|
||||
/* data types */
|
||||
#define STRING 0
|
||||
#define INTEGER 1
|
||||
#define BOOLEAN 2
|
||||
|
||||
|
||||
/*
|
||||
* This structure hold a value. The type keyword specifies the type of
|
||||
* the value, and the union u holds the value. The value of a boolean
|
||||
* is stored in u.num (1 = TRUE, 0 = FALSE).
|
||||
*/
|
||||
|
||||
struct value {
|
||||
int type;
|
||||
union {
|
||||
char *string;
|
||||
long num;
|
||||
} u;
|
||||
};
|
||||
|
||||
|
||||
struct operator {
|
||||
short op; /* which operator */
|
||||
short pri; /* priority of operator */
|
||||
};
|
||||
|
||||
|
||||
struct filestat {
|
||||
char *name; /* name of file */
|
||||
int rcode; /* return code from stat */
|
||||
struct stat stat; /* status info on file */
|
||||
};
|
||||
|
||||
|
||||
extern char *match_begin[10]; /* matched string */
|
||||
extern short match_length[10]; /* defined in regexp.c */
|
||||
extern short number_parens; /* number of \( \) pairs */
|
||||
|
||||
|
||||
#ifdef __STDC__
|
||||
static int expr_is_false(struct value *);
|
||||
static void expr_operator(int, struct value *, struct filestat *);
|
||||
static int lookup_op(char *, char *const*);
|
||||
#else
|
||||
static int expr_is_false();
|
||||
static void expr_operator();
|
||||
static int lookup_op();
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
int exprcmd(argc, argv) int argc; char **argv; {
|
||||
char **ap;
|
||||
char *opname;
|
||||
char c;
|
||||
char *p;
|
||||
int print;
|
||||
int nest; /* parenthises nesting */
|
||||
int op;
|
||||
int pri;
|
||||
int skipping;
|
||||
int binary;
|
||||
struct operator opstack[STACKSIZE];
|
||||
struct operator *opsp;
|
||||
struct value valstack[STACKSIZE + 1];
|
||||
struct value *valsp;
|
||||
struct filestat fs;
|
||||
|
||||
INITARGS(argv);
|
||||
c = **argv;
|
||||
print = 1;
|
||||
if (c == 't')
|
||||
print = 0;
|
||||
else if (c == '[') {
|
||||
if (! equal(argv[argc - 1], "]"))
|
||||
error("missing ]");
|
||||
argv[argc - 1] = NULL;
|
||||
print = 0;
|
||||
}
|
||||
ap = argv + 1;
|
||||
fs.name = NULL;
|
||||
|
||||
/*
|
||||
* We use operator precedence parsing, evaluating the expression
|
||||
* as we parse it. Parentheses are handled by bumping up the
|
||||
* priority of operators using the variable "nest." We use the
|
||||
* variable "skipping" to turn off evaluation temporarily for the
|
||||
* short circuit boolean operators. (It is important do the short
|
||||
* circuit evaluation because under NFS a stat operation can take
|
||||
* infinitely long.)
|
||||
*/
|
||||
|
||||
nest = 0;
|
||||
skipping = 0;
|
||||
opsp = opstack + STACKSIZE;
|
||||
valsp = valstack;
|
||||
if (*ap == NULL) {
|
||||
valstack[0].type = BOOLEAN;
|
||||
valstack[0].u.num = 0;
|
||||
goto done;
|
||||
}
|
||||
for (;;) {
|
||||
opname = *ap++;
|
||||
if (opname == NULL)
|
||||
syntax: error("syntax error");
|
||||
if (opname[0] == '(' && opname[1] == '\0') {
|
||||
nest += NESTINCR;
|
||||
continue;
|
||||
} else if (*ap && (op = lookup_op(opname, unary_op)) >= 0) {
|
||||
if (opsp == &opstack[0])
|
||||
overflow: error("Expression too complex");
|
||||
--opsp;
|
||||
opsp->op = op;
|
||||
opsp->pri = op_priority[op] + nest;
|
||||
continue;
|
||||
|
||||
} else {
|
||||
if (opname[0] == '\'') {
|
||||
for (p = opname ; *++p != '\0' ; );
|
||||
if (--p > opname && *p == '\'') {
|
||||
*p = '\0';
|
||||
opname++;
|
||||
}
|
||||
}
|
||||
valsp->type = STRING;
|
||||
valsp->u.string = opname;
|
||||
valsp++;
|
||||
}
|
||||
for (;;) {
|
||||
opname = *ap++;
|
||||
if (opname == NULL) {
|
||||
if (nest != 0)
|
||||
goto syntax;
|
||||
pri = 0;
|
||||
break;
|
||||
}
|
||||
if (opname[0] != ')' || opname[1] != '\0') {
|
||||
if ((op = lookup_op(opname, binary_op)) < 0)
|
||||
goto syntax;
|
||||
op += FIRST_BINARY_OP;
|
||||
pri = op_priority[op] + nest;
|
||||
break;
|
||||
}
|
||||
if ((nest -= NESTINCR) < 0)
|
||||
goto syntax;
|
||||
}
|
||||
while (opsp < &opstack[STACKSIZE] && opsp->pri >= pri) {
|
||||
binary = opsp->op;
|
||||
for (;;) {
|
||||
valsp--;
|
||||
c = op_argflag[opsp->op];
|
||||
if (c == OP_INT) {
|
||||
if (valsp->type == STRING)
|
||||
valsp->u.num = atol(valsp->u.string);
|
||||
valsp->type = INTEGER;
|
||||
} else if (c >= OP_STRING) { /* OP_STRING or OP_FILE */
|
||||
if (valsp->type == INTEGER) {
|
||||
p = stalloc(32);
|
||||
#ifdef SHELL
|
||||
fmtstr(p, 32, "%ld", valsp->u.num);
|
||||
#else
|
||||
sprintf(p, "%d", valsp->u.num);
|
||||
#endif
|
||||
valsp->u.string = p;
|
||||
} else if (valsp->type == BOOLEAN) {
|
||||
if (valsp->u.num)
|
||||
valsp->u.string = "true";
|
||||
else
|
||||
valsp->u.string = "";
|
||||
}
|
||||
valsp->type = STRING;
|
||||
if (c == OP_FILE
|
||||
&& (fs.name == NULL
|
||||
|| ! equal(fs.name, valsp->u.string))) {
|
||||
fs.name = valsp->u.string;
|
||||
fs.rcode = stat(valsp->u.string, &fs.stat);
|
||||
}
|
||||
}
|
||||
if (binary < FIRST_BINARY_OP)
|
||||
break;
|
||||
binary = 0;
|
||||
}
|
||||
if (! skipping)
|
||||
expr_operator(opsp->op, valsp, &fs);
|
||||
else if (opsp->op == AND1 || opsp->op == OR1)
|
||||
skipping--;
|
||||
valsp++; /* push value */
|
||||
opsp++; /* pop operator */
|
||||
}
|
||||
if (opname == NULL)
|
||||
break;
|
||||
if (opsp == &opstack[0])
|
||||
goto overflow;
|
||||
if (op == AND1 || op == AND2) {
|
||||
op = AND1;
|
||||
if (skipping || expr_is_false(valsp - 1))
|
||||
skipping++;
|
||||
}
|
||||
if (op == OR1 || op == OR2) {
|
||||
op = OR1;
|
||||
if (skipping || ! expr_is_false(valsp - 1))
|
||||
skipping++;
|
||||
}
|
||||
opsp--;
|
||||
opsp->op = op;
|
||||
opsp->pri = pri;
|
||||
}
|
||||
done:
|
||||
if (print) {
|
||||
if (valstack[0].type == STRING)
|
||||
printf("%s\n", valstack[0].u.string);
|
||||
else if (valstack[0].type == INTEGER)
|
||||
printf("%ld\n", valstack[0].u.num);
|
||||
else if (valstack[0].u.num != 0)
|
||||
printf("true\n");
|
||||
}
|
||||
return expr_is_false(&valstack[0]);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
expr_is_false(val)
|
||||
struct value *val;
|
||||
{
|
||||
if (val->type == STRING) {
|
||||
if (val->u.string[0] == '\0')
|
||||
return 1;
|
||||
} else { /* INTEGER or BOOLEAN */
|
||||
if (val->u.num == 0)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Execute an operator. Op is the operator. Sp is the stack pointer;
|
||||
* sp[0] refers to the first operand, sp[1] refers to the second operand
|
||||
* (if any), and the result is placed in sp[0]. The operands are converted
|
||||
* to the type expected by the operator before expr_operator is called.
|
||||
* Fs is a pointer to a structure which holds the value of the last call
|
||||
* to stat, to avoid repeated stat calls on the same file.
|
||||
*/
|
||||
|
||||
static void
|
||||
expr_operator(op, sp, fs)
|
||||
int op;
|
||||
struct value *sp;
|
||||
struct filestat *fs;
|
||||
{
|
||||
int i, r;
|
||||
struct stat st1, st2;
|
||||
regex_t pat;
|
||||
regmatch_t rm[2];
|
||||
|
||||
switch (op) {
|
||||
case NOT:
|
||||
sp->u.num = expr_is_false(sp);
|
||||
sp->type = BOOLEAN;
|
||||
break;
|
||||
case EXISTS:
|
||||
if (fs->rcode >= 0) goto true;
|
||||
goto false;
|
||||
case ISREAD:
|
||||
i = 04;
|
||||
goto permission;
|
||||
case ISWRITE:
|
||||
i = 02;
|
||||
goto permission;
|
||||
case ISEXEC:
|
||||
i = 01;
|
||||
permission:
|
||||
if (fs->stat.st_uid == geteuid())
|
||||
i <<= 6;
|
||||
else if (fs->stat.st_gid == getegid())
|
||||
i <<= 3;
|
||||
goto filebit; /* true if (stat.st_mode & i) != 0 */
|
||||
case ISFILE:
|
||||
i = S_IFREG;
|
||||
goto filetype;
|
||||
case ISDIR:
|
||||
i = S_IFDIR;
|
||||
goto filetype;
|
||||
case ISCHAR:
|
||||
i = S_IFCHR;
|
||||
goto filetype;
|
||||
case ISBLOCK:
|
||||
i = S_IFBLK;
|
||||
goto filetype;
|
||||
case ISFIFO:
|
||||
#ifdef S_IFIFO
|
||||
i = S_IFIFO;
|
||||
goto filetype;
|
||||
#else
|
||||
goto false;
|
||||
#endif
|
||||
filetype:
|
||||
if ((fs->stat.st_mode & S_IFMT) == i && fs->rcode >= 0) {
|
||||
true:
|
||||
sp->u.num = 1;
|
||||
} else {
|
||||
false:
|
||||
sp->u.num = 0;
|
||||
}
|
||||
sp->type = BOOLEAN;
|
||||
break;
|
||||
case ISSETUID:
|
||||
i = S_ISUID;
|
||||
goto filebit;
|
||||
case ISSETGID:
|
||||
i = S_ISGID;
|
||||
goto filebit;
|
||||
case ISSTICKY:
|
||||
i = S_ISVTX;
|
||||
filebit:
|
||||
if (fs->stat.st_mode & i && fs->rcode >= 0)
|
||||
goto true;
|
||||
goto false;
|
||||
case ISSLINK:
|
||||
if (lstat(fs->name, &st1) == -1)
|
||||
goto false;
|
||||
if (S_ISLNK(st1.st_mode))
|
||||
goto true;
|
||||
goto false;
|
||||
case ISSIZE:
|
||||
sp->u.num = fs->rcode >= 0? fs->stat.st_size : 0L;
|
||||
sp->type = INTEGER;
|
||||
break;
|
||||
case OLDER:
|
||||
case NEWER:
|
||||
if (stat(sp->u.string, &st1) != 0) {
|
||||
sp->u.num = 0;
|
||||
} else if (stat((sp + 1)->u.string, &st2) != 0) {
|
||||
sp->u.num = 1;
|
||||
} else {
|
||||
int isnewer = st1.st_mtime >= st2.st_mtime;
|
||||
if(op == NEWER)
|
||||
sp->u.num = isnewer;
|
||||
else
|
||||
sp->u.num = !isnewer;
|
||||
}
|
||||
sp->type = INTEGER;
|
||||
break;
|
||||
case ISTTY:
|
||||
sp->u.num = isatty(sp->u.num);
|
||||
sp->type = BOOLEAN;
|
||||
break;
|
||||
case NULSTR:
|
||||
if (sp->u.string[0] == '\0')
|
||||
goto true;
|
||||
goto false;
|
||||
case STRLEN:
|
||||
sp->u.num = strlen(sp->u.string);
|
||||
sp->type = INTEGER;
|
||||
break;
|
||||
case OR1:
|
||||
case AND1:
|
||||
/*
|
||||
* These operators are mostly handled by the parser. If we
|
||||
* get here it means that both operands were evaluated, so
|
||||
* the value is the value of the second operand.
|
||||
*/
|
||||
*sp = *(sp + 1);
|
||||
break;
|
||||
case STREQ:
|
||||
case STRNE:
|
||||
i = 0;
|
||||
if (equal(sp->u.string, (sp + 1)->u.string))
|
||||
i++;
|
||||
if (op == STRNE)
|
||||
i = 1 - i;
|
||||
sp->u.num = i;
|
||||
sp->type = BOOLEAN;
|
||||
break;
|
||||
case EQ:
|
||||
if (sp->u.num == (sp + 1)->u.num)
|
||||
goto true;
|
||||
goto false;
|
||||
case NE:
|
||||
if (sp->u.num != (sp + 1)->u.num)
|
||||
goto true;
|
||||
goto false;
|
||||
case GT:
|
||||
if (sp->u.num > (sp + 1)->u.num)
|
||||
goto true;
|
||||
goto false;
|
||||
case LT:
|
||||
if (sp->u.num < (sp + 1)->u.num)
|
||||
goto true;
|
||||
goto false;
|
||||
case LE:
|
||||
if (sp->u.num <= (sp + 1)->u.num)
|
||||
goto true;
|
||||
goto false;
|
||||
case GE:
|
||||
if (sp->u.num >= (sp + 1)->u.num)
|
||||
goto true;
|
||||
goto false;
|
||||
case PLUS:
|
||||
sp->u.num += (sp + 1)->u.num;
|
||||
break;
|
||||
case MINUS:
|
||||
sp->u.num -= (sp + 1)->u.num;
|
||||
break;
|
||||
case TIMES:
|
||||
sp->u.num *= (sp + 1)->u.num;
|
||||
break;
|
||||
case DIVIDE:
|
||||
if ((sp + 1)->u.num == 0)
|
||||
error("Division by zero");
|
||||
sp->u.num /= (sp + 1)->u.num;
|
||||
break;
|
||||
case REM:
|
||||
if ((sp + 1)->u.num == 0)
|
||||
error("Division by zero");
|
||||
sp->u.num %= (sp + 1)->u.num;
|
||||
break;
|
||||
case MATCHPAT:
|
||||
{
|
||||
r = regcomp(&pat, (sp + 1)->u.string, 0);
|
||||
if (r)
|
||||
error("Bad regular expression");
|
||||
if (regexec(&pat, sp->u.string, 2, rm, 0) == 0 &&
|
||||
rm[0].rm_so == 0)
|
||||
{
|
||||
if (pat.re_nsub > 0) {
|
||||
sp->u.string[rm[1].rm_eo] = '\0';
|
||||
sp->u.string = sp->u.string+rm[1].rm_so;
|
||||
} else {
|
||||
sp->u.num = rm[0].rm_eo;
|
||||
sp->type = INTEGER;
|
||||
}
|
||||
} else {
|
||||
if (pat.re_nsub > 0) {
|
||||
sp->u.string[0] = '\0';
|
||||
} else {
|
||||
sp->u.num = 0;
|
||||
sp->type = INTEGER;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
lookup_op(name, table)
|
||||
char *name;
|
||||
char *const*table;
|
||||
{
|
||||
register char *const*tp;
|
||||
register char const *p;
|
||||
char c = name[1];
|
||||
|
||||
for (tp = table ; (p = *tp) != NULL ; tp++) {
|
||||
if (p[1] == c && equal(p, name))
|
||||
return tp - table;
|
||||
}
|
||||
return -1;
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
* The line command. Reads one line from the standard input and writes it
|
||||
* to the standard output.
|
||||
*
|
||||
* Copyright (C) 1989 by Kenneth Almquist. All rights reserved.
|
||||
* This file is part of ash, which is distributed under the terms specified
|
||||
* by the Ash General Public License. See the file named LICENSE.
|
||||
*/
|
||||
|
||||
#define main linecmd
|
||||
|
||||
#include "bltin.h"
|
||||
|
||||
|
||||
main(argc, argv) char **argv; {
|
||||
char c;
|
||||
|
||||
for (;;) {
|
||||
if (read(0, &c, 1) != 1) {
|
||||
putchar('\n');
|
||||
return 1;
|
||||
}
|
||||
putchar(c);
|
||||
if (c == '\n')
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
# Copyright (C) 1989 by Kenneth Almquist. All rights reserved.
|
||||
# This file is part of ash, which is distributed under the terms specified
|
||||
# by the Ash General Public License. See the file named LICENSE.
|
||||
|
||||
LIBFILES=catfcmd.o echocmd.o exprcmd.o linecmd.o nlechocmd.o\
|
||||
operators.o regexp.o
|
||||
DEBUG=-g
|
||||
CFLAGS=$(DEBUG)
|
||||
#CC=gcc
|
||||
|
||||
all:$P bltinlib.a catf echo expr line nlecho true umask
|
||||
|
||||
bltinlib.a:$P $(LIBFILES)
|
||||
ar rc $@ $(LIBFILES)
|
||||
|
||||
catf: catf.c bltin.h ../shell.h ../error.h error.o stalloc.o
|
||||
$(CC) $(CFLAGS) -o $@ catf.c error.o stalloc.o
|
||||
|
||||
catfcmd.o: catf.c bltin.h ../shell.h ../error.h
|
||||
$(CC) -DSHELL $(CFLAGS) -c catf.c
|
||||
mv catf.o $@
|
||||
|
||||
expr: expr.c bltin.h ../shell.h operators.h operators.o regexp.o error.o stalloc.o
|
||||
$(CC) $(CFLAGS) -o $@ expr.c operators.o regexp.o error.o stalloc.o
|
||||
-rm -f test '['
|
||||
ln expr test
|
||||
ln expr '['
|
||||
|
||||
exprcmd.o: expr.c bltin.h ../shell.h operators.h
|
||||
$(CC) -DSHELL $(CFLAGS) -c expr.c
|
||||
mv expr.o $@
|
||||
|
||||
operators.c operators.h: unary_op binary_op mkexpr
|
||||
./mkexpr
|
||||
|
||||
operators.o: ../shell.h operators.h
|
||||
|
||||
regexp.o: bltin.h ../shell.h
|
||||
|
||||
echo: echo.c bltin.h ../shell.h
|
||||
$(CC) $(CFLAGS) -o $@ echo.c
|
||||
|
||||
echocmd.o: echo.c bltin.h ../shell.h
|
||||
$(CC) -DSHELL $(CFLAGS) -c echo.c
|
||||
mv echo.o $@
|
||||
|
||||
line: line.c bltin.h ../shell.h
|
||||
$(CC) $(CFLAGS) -o $@ line.c
|
||||
|
||||
linecmd.o: line.c bltin.h ../shell.h
|
||||
$(CC) -DSHELL $(CFLAGS) -c line.c
|
||||
mv line.o $@
|
||||
|
||||
nlecho: nlecho.c bltin.h ../shell.h
|
||||
$(CC) $(CFLAGS) -o $@ nlecho.c
|
||||
|
||||
nlechocmd.o: nlecho.c bltin.h ../shell.h
|
||||
$(CC) -DSHELL $(CFLAGS) -c nlecho.c
|
||||
mv nlecho.o $@
|
||||
|
||||
umask: umask.c bltin.h
|
||||
$(CC) $(CFLAGS) -o $@ umask.c
|
||||
|
||||
true:
|
||||
> :
|
||||
chmod 755 :
|
||||
rm -f true
|
||||
ln : true
|
||||
|
||||
stalloc.o: ../shell.h
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
#!/bin/sh
|
||||
# Copyright 1989 by Kenneth Almquist. All rights reserved.
|
||||
#
|
||||
# This file is part of ash. Ash is distributed under the terms specified
|
||||
# by the Ash General Public License. See the file named LICENSE.
|
||||
|
||||
# All calls to awk removed, because Minix bawk is deficient. (kjb)
|
||||
|
||||
if [ $# -ne 2 ]
|
||||
then
|
||||
echo "Usage: $0 <unary_op> <binary_op>" >&2
|
||||
exit 1
|
||||
fi
|
||||
unary_op="$1"
|
||||
binary_op="$2"
|
||||
|
||||
exec > operators.h
|
||||
i=0
|
||||
sed -e '/^[^#]/!d' "$unary_op" "$binary_op" | while read line
|
||||
do
|
||||
set -$- $line
|
||||
echo "#define $1 $i"
|
||||
i=`expr $i + 1`
|
||||
done
|
||||
echo
|
||||
echo "#define FIRST_BINARY_OP" `sed -e '/^[^#]/!d' "$unary_op" | wc -l`
|
||||
echo '
|
||||
#define OP_INT 1 /* arguments to operator are integer */
|
||||
#define OP_STRING 2 /* arguments to operator are string */
|
||||
#define OP_FILE 3 /* argument is a file name */
|
||||
|
||||
extern char *const unary_op[];
|
||||
extern char *const binary_op[];
|
||||
extern const char op_priority[];
|
||||
extern const char op_argflag[];'
|
||||
|
||||
exec > operators.c
|
||||
echo '/*
|
||||
* Operators used in the expr/test command.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include "shell.h"
|
||||
#include "operators.h"
|
||||
|
||||
char *const unary_op[] = {'
|
||||
sed -e '/^[^#]/!d
|
||||
s/[ ][ ]*/ /g
|
||||
s/^[^ ][^ ]* \([^ ][^ ]*\).*/ "\1",/
|
||||
' "$unary_op"
|
||||
echo ' NULL
|
||||
};
|
||||
|
||||
char *const binary_op[] = {'
|
||||
sed -e '/^[^#]/!d
|
||||
s/[ ][ ]*/ /g
|
||||
s/^[^ ][^ ]* \([^ ][^ ]*\).*/ "\1",/
|
||||
' "$binary_op"
|
||||
echo ' NULL
|
||||
};
|
||||
|
||||
const char op_priority[] = {'
|
||||
sed -e '/^[^#]/!d
|
||||
s/[ ][ ]*/ /g
|
||||
s/^[^ ][^ ]* [^ ][^ ]* \([^ ][^ ]*\).*/ \1,/
|
||||
' "$unary_op" "$binary_op"
|
||||
echo '};
|
||||
|
||||
const char op_argflag[] = {'
|
||||
sed -e '/^[^#]/!d
|
||||
s/[ ][ ]*/ /g
|
||||
s/^[^ ][^ ]* [^ ][^ ]* [^ ][^ ]*$/& 0/
|
||||
s/^[^ ][^ ]* [^ ][^ ]* [^ ][^ ]* \([^ ][^ ]*\)/ \1,/
|
||||
' "$unary_op" "$binary_op"
|
||||
echo '};'
|
|
@ -1,8 +0,0 @@
|
|||
/*
|
||||
myregexp.h
|
||||
|
||||
Created: July 1995 by Philip Homburg <philip@cs.vu.nl>
|
||||
*/
|
||||
|
||||
char *re_compile(char *pattern);
|
||||
int re_match(char *pattern, char *string);
|
|
@ -1,25 +0,0 @@
|
|||
/*
|
||||
* Echo the command argument to the standard output, one line at a time.
|
||||
* This command is useful for debugging th shell and whenever you what
|
||||
* to output strings literally.
|
||||
*
|
||||
* Copyright (C) 1989 by Kenneth Almquist. All rights reserved.
|
||||
* This file is part of ash, which is distributed under the terms specified
|
||||
* by the Ash General Public License. See the file named LICENSE.
|
||||
*/
|
||||
|
||||
|
||||
#define main nlechocmd
|
||||
|
||||
#include "bltin.h"
|
||||
|
||||
|
||||
main(argc, argv) char **argv; {
|
||||
register char **ap;
|
||||
|
||||
for (ap = argv + 1 ; *ap ; ap++) {
|
||||
fputs(*ap, stdout);
|
||||
putchar('\n');
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -1,301 +0,0 @@
|
|||
/*
|
||||
* Regular expression matching for expr(1). Bugs: The upper bound of
|
||||
* a range specified by the \{ feature cannot be zero.
|
||||
*
|
||||
* Copyright (C) 1989 by Kenneth Almquist. All rights reserved.
|
||||
* This file is part of ash, which is distributed under the terms specified
|
||||
* by the Ash General Public License. See the file named LICENSE.
|
||||
*/
|
||||
|
||||
#include "bltin.h"
|
||||
#include "myregexp.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define RE_END 0 /* end of regular expression */
|
||||
#define RE_LITERAL 1 /* normal character follows */
|
||||
#define RE_DOT 2 /* "." */
|
||||
#define RE_CCL 3 /* "[...]" */
|
||||
#define RE_NCCL 4 /* "[^...]" */
|
||||
#define RE_LP 5 /* "\(" */
|
||||
#define RE_RP 6 /* "\)" */
|
||||
#define RE_MATCHED 7 /* "\digit" */
|
||||
#define RE_EOS 8 /* "$" matches end of string */
|
||||
#define RE_STAR 9 /* "*" */
|
||||
#define RE_RANGE 10 /* "\{num,num\}" */
|
||||
|
||||
|
||||
|
||||
char *match_begin[10];
|
||||
short match_length[10];
|
||||
short number_parens;
|
||||
static int match(char *pattern, char *string);
|
||||
|
||||
|
||||
|
||||
char *
|
||||
re_compile(pattern)
|
||||
char *pattern;
|
||||
{
|
||||
register char *p;
|
||||
register char c;
|
||||
char *comp;
|
||||
register char *q;
|
||||
char *begin;
|
||||
char *endp;
|
||||
register int len;
|
||||
int first;
|
||||
int type;
|
||||
char *stackp;
|
||||
char stack[10];
|
||||
int paren_num;
|
||||
int i;
|
||||
|
||||
p = pattern;
|
||||
if (*p == '^')
|
||||
p++;
|
||||
comp = q = malloc(2 * strlen(p) + 1);
|
||||
begin = q;
|
||||
stackp = stack;
|
||||
paren_num = 0;
|
||||
for (;;) {
|
||||
switch (c = *p++) {
|
||||
case '\0':
|
||||
*q = '\0';
|
||||
goto out;
|
||||
case '.':
|
||||
*q++ = RE_DOT;
|
||||
len = 1;
|
||||
break;
|
||||
case '[':
|
||||
begin = q;
|
||||
*q = RE_CCL;
|
||||
if (*p == '^') {
|
||||
*q = RE_NCCL;
|
||||
p++;
|
||||
}
|
||||
q++;
|
||||
first = 1;
|
||||
while (*p != ']' || first == 1) {
|
||||
if (p[1] == '-' && p[2] != ']') {
|
||||
*q++ = '-';
|
||||
*q++ = p[0];
|
||||
*q++ = p[2];
|
||||
p += 3;
|
||||
} else if (*p == '-') {
|
||||
*q++ = '-';
|
||||
*q++ = '-';
|
||||
*q++ = '-';
|
||||
p++;
|
||||
} else {
|
||||
*q++ = *p++;
|
||||
}
|
||||
first = 0;
|
||||
}
|
||||
p++;
|
||||
*q++ = '\0';
|
||||
len = q - begin;
|
||||
break;
|
||||
case '$':
|
||||
if (*p != '\0')
|
||||
goto dft;
|
||||
*q++ = RE_EOS;
|
||||
break;
|
||||
case '*':
|
||||
if (len == 0)
|
||||
goto dft;
|
||||
type = RE_STAR;
|
||||
range:
|
||||
i = (type == RE_RANGE)? 3 : 1;
|
||||
endp = q + i;
|
||||
begin = q - len;
|
||||
do {
|
||||
--q;
|
||||
*(q + i) = *q;
|
||||
} while (--len > 0);
|
||||
q = begin;
|
||||
*q++ = type;
|
||||
if (type == RE_RANGE) {
|
||||
i = 0;
|
||||
while ((unsigned)(*p - '0') <= 9)
|
||||
i = 10 * i + (*p++ - '0');
|
||||
*q++ = i;
|
||||
if (*p != ',') {
|
||||
*q++ = i;
|
||||
} else {
|
||||
p++;
|
||||
i = 0;
|
||||
while ((unsigned)(*p - '0') <= 9)
|
||||
i = 10 * i + (*p++ - '0');
|
||||
*q++ = i;
|
||||
}
|
||||
if (*p != '\\' || *++p != '}')
|
||||
error("RE error");
|
||||
p++;
|
||||
}
|
||||
q = endp;
|
||||
break;
|
||||
case '\\':
|
||||
if ((c = *p++) == '(') {
|
||||
if (++paren_num > 9)
|
||||
error("RE error");
|
||||
*q++ = RE_LP;
|
||||
*q++ = paren_num;
|
||||
*stackp++ = paren_num;
|
||||
len = 0;
|
||||
} else if (c == ')') {
|
||||
if (stackp == stack)
|
||||
error("RE error");
|
||||
*q++ = RE_RP;
|
||||
*q++ = *--stackp;
|
||||
len = 0;
|
||||
} else if (c == '{') {
|
||||
type = RE_RANGE;
|
||||
goto range;
|
||||
} else if ((unsigned)(c - '1') < 9) {
|
||||
/* should check validity here */
|
||||
*q++ = RE_MATCHED;
|
||||
*q++ = c - '0';
|
||||
len = 2;
|
||||
} else {
|
||||
goto dft;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
dft: *q++ = RE_LITERAL;
|
||||
*q++ = c;
|
||||
len = 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
out:
|
||||
if (stackp != stack)
|
||||
error("RE error");
|
||||
number_parens = paren_num;
|
||||
return comp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
re_match(pattern, string)
|
||||
char *pattern;
|
||||
char *string;
|
||||
{
|
||||
char **pp;
|
||||
|
||||
match_begin[0] = string;
|
||||
for (pp = &match_begin[1] ; pp <= &match_begin[9] ; pp++)
|
||||
*pp = 0;
|
||||
return match(pattern, string);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static
|
||||
match(pattern, string)
|
||||
char *pattern;
|
||||
char *string;
|
||||
{
|
||||
register char *p, *q;
|
||||
int counting;
|
||||
int low, high, count;
|
||||
char *curpat;
|
||||
char *start_count;
|
||||
int negate;
|
||||
int found;
|
||||
char *r;
|
||||
int len;
|
||||
char c;
|
||||
|
||||
p = pattern;
|
||||
q = string;
|
||||
counting = 0;
|
||||
for (;;) {
|
||||
if (counting) {
|
||||
if (++count > high)
|
||||
goto bad;
|
||||
p = curpat;
|
||||
}
|
||||
switch (*p++) {
|
||||
case RE_END:
|
||||
match_length[0] = q - match_begin[0];
|
||||
return 1;
|
||||
case RE_LITERAL:
|
||||
if (*q++ != *p++)
|
||||
goto bad;
|
||||
break;
|
||||
case RE_DOT:
|
||||
if (*q++ == '\0')
|
||||
goto bad;
|
||||
break;
|
||||
case RE_CCL:
|
||||
negate = 0;
|
||||
goto ccl;
|
||||
case RE_NCCL:
|
||||
negate = 1;
|
||||
ccl:
|
||||
found = 0;
|
||||
c = *q++;
|
||||
while (*p) {
|
||||
if (*p == '-') {
|
||||
if (c >= *++p && c <= *++p)
|
||||
found = 1;
|
||||
} else {
|
||||
if (c == *p)
|
||||
found = 1;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
p++;
|
||||
if (found == negate)
|
||||
goto bad;
|
||||
break;
|
||||
case RE_LP:
|
||||
match_begin[*p++] = q;
|
||||
break;
|
||||
case RE_RP:
|
||||
match_length[*p] = q - match_begin[*p];
|
||||
p++;
|
||||
break;
|
||||
case RE_MATCHED:
|
||||
r = match_begin[*p];
|
||||
len = match_length[*p++];
|
||||
while (--len >= 0) {
|
||||
if (*q++ != *r++)
|
||||
goto bad;
|
||||
}
|
||||
break;
|
||||
case RE_EOS:
|
||||
if (*q != '\0')
|
||||
goto bad;
|
||||
break;
|
||||
case RE_STAR:
|
||||
low = 0;
|
||||
high = 32767;
|
||||
goto range;
|
||||
case RE_RANGE:
|
||||
low = *p++;
|
||||
high = *p++;
|
||||
if (high == 0)
|
||||
high = 32767;
|
||||
range:
|
||||
curpat = p;
|
||||
start_count = q;
|
||||
count = 0;
|
||||
counting++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
bad:
|
||||
if (! counting)
|
||||
return 0;
|
||||
len = 1;
|
||||
if (*curpat == RE_MATCHED)
|
||||
len = match_length[curpat[1]];
|
||||
while (--count >= low) {
|
||||
if (match(p, start_count + count * len))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 1989 by Kenneth Almquist. All rights reserved.
|
||||
* This file is part of ash, which is distributed under the terms specified
|
||||
* by the Ash General Public License. See the file named LICENSE.
|
||||
*/
|
||||
|
||||
#include "../shell.h"
|
||||
|
||||
|
||||
void error();
|
||||
pointer malloc();
|
||||
|
||||
|
||||
pointer
|
||||
stalloc(nbytes) {
|
||||
register pointer p;
|
||||
|
||||
if ((p = malloc(nbytes)) == NULL)
|
||||
error("Out of space");
|
||||
return p;
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 1989 by Kenneth Almquist. All rights reserved.
|
||||
* This file is part of ash, which is distributed under the terms specified
|
||||
* by the Ash General Public License. See the file named LICENSE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
main(argc, argv) char **argv; {
|
||||
int mask;
|
||||
|
||||
if (argc > 1) {
|
||||
fprintf(stderr, "umask: only builtin version of umask can set value\n");
|
||||
exit(2);
|
||||
}
|
||||
printf("%.4o\n", umask(0));
|
||||
return 0;
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
# List of unary operators used by test/expr.
|
||||
#
|
||||
# Copyright (C) 1989 by Kenneth Almquist. All rights reserved.
|
||||
# This file is part of ash, which is distributed under the terms specified
|
||||
# by the Ash General Public License. See the file named LICENSE.
|
||||
|
||||
NOT ! 3
|
||||
EXISTS -e 12 OP_FILE
|
||||
ISREAD -r 12 OP_FILE
|
||||
ISWRITE -w 12 OP_FILE
|
||||
ISEXEC -x 12 OP_FILE
|
||||
ISFILE -f 12 OP_FILE
|
||||
ISDIR -d 12 OP_FILE
|
||||
ISCHAR -c 12 OP_FILE
|
||||
ISBLOCK -b 12 OP_FILE
|
||||
ISFIFO -p 12 OP_FILE
|
||||
ISSETUID -u 12 OP_FILE
|
||||
ISSETGID -g 12 OP_FILE
|
||||
ISSTICKY -k 12 OP_FILE
|
||||
ISSLINK -h 12 OP_FILE
|
||||
ISSIZE -s 12 OP_FILE
|
||||
ISTTY -t 12 OP_INT
|
||||
NULSTR -z 12 OP_STRING
|
||||
STRLEN -n 12 OP_STRING
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue