Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 2713 → Rev 2714

/trunk/uspace/app/ash/setmode.c
0,0 → 1,486
/* $NetBSD: setmode.c,v 1.28 2000/01/25 15:43:43 enami Exp $ */
 
/*
* Copyright (c) 1989, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Dave Borman at Cray Research, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
 
#include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
#if 0
static char sccsid[] = "@(#)setmode.c 8.2 (Berkeley) 3/25/94";
#else
__RCSID("$NetBSD: setmode.c,v 1.28 2000/01/25 15:43:43 enami Exp $");
#endif
#endif /* LIBC_SCCS and not lint */
 
#include <sys/types.h>
#include <sys/stat.h>
 
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
 
#ifdef SETMODE_DEBUG
#include <stdio.h>
#endif
 
#ifdef __weak_alias
__weak_alias(getmode,_getmode)
__weak_alias(setmode,_setmode)
#endif
 
#ifdef __GLIBC__
#define S_ISTXT __S_ISVTX
#endif
 
#define SET_LEN 6 /* initial # of bitcmd struct to malloc */
#define SET_LEN_INCR 4 /* # of bitcmd structs to add as needed */
 
typedef struct bitcmd {
char cmd;
char cmd2;
mode_t bits;
} BITCMD;
 
#define CMD2_CLR 0x01
#define CMD2_SET 0x02
#define CMD2_GBITS 0x04
#define CMD2_OBITS 0x08
#define CMD2_UBITS 0x10
 
static BITCMD *addcmd (BITCMD *, int, int, int, u_int);
static void compress_mode (BITCMD *);
#ifdef SETMODE_DEBUG
static void dumpmode (BITCMD *);
#endif
 
/*
* Given the old mode and an array of bitcmd structures, apply the operations
* described in the bitcmd structures to the old mode, and return the new mode.
* Note that there is no '=' command; a strict assignment is just a '-' (clear
* bits) followed by a '+' (set bits).
*/
mode_t
getmode(bbox, omode)
const void *bbox;
mode_t omode;
{
const BITCMD *set;
mode_t clrval, newmode, value;
 
_DIAGASSERT(bbox != NULL);
 
set = (const BITCMD *)bbox;
newmode = omode;
for (value = 0;; set++)
switch(set->cmd) {
/*
* When copying the user, group or other bits around, we "know"
* where the bits are in the mode so that we can do shifts to
* copy them around. If we don't use shifts, it gets real
* grundgy with lots of single bit checks and bit sets.
*/
case 'u':
value = (newmode & S_IRWXU) >> 6;
goto common;
 
case 'g':
value = (newmode & S_IRWXG) >> 3;
goto common;
 
case 'o':
value = newmode & S_IRWXO;
common: if (set->cmd2 & CMD2_CLR) {
clrval =
(set->cmd2 & CMD2_SET) ? S_IRWXO : value;
if (set->cmd2 & CMD2_UBITS)
newmode &= ~((clrval<<6) & set->bits);
if (set->cmd2 & CMD2_GBITS)
newmode &= ~((clrval<<3) & set->bits);
if (set->cmd2 & CMD2_OBITS)
newmode &= ~(clrval & set->bits);
}
if (set->cmd2 & CMD2_SET) {
if (set->cmd2 & CMD2_UBITS)
newmode |= (value<<6) & set->bits;
if (set->cmd2 & CMD2_GBITS)
newmode |= (value<<3) & set->bits;
if (set->cmd2 & CMD2_OBITS)
newmode |= value & set->bits;
}
break;
 
case '+':
newmode |= set->bits;
break;
 
case '-':
newmode &= ~set->bits;
break;
 
case 'X':
if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
newmode |= set->bits;
break;
 
case '\0':
default:
#ifdef SETMODE_DEBUG
(void)printf("getmode:%04o -> %04o\n", omode, newmode);
#endif
return (newmode);
}
}
 
#define ADDCMD(a, b, c, d) do { \
if (set >= endset) { \
BITCMD *newset; \
setlen += SET_LEN_INCR; \
newset = realloc(saveset, sizeof(BITCMD) * setlen); \
if (newset == NULL) { \
free(saveset); \
return (NULL); \
} \
set = newset + (set - saveset); \
saveset = newset; \
endset = newset + (setlen - 2); \
} \
set = addcmd(set, (a), (b), (c), (d)); \
} while (/*CONSTCOND*/0)
 
#define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
 
void *
setmode(p)
const char *p;
{
int perm, who;
char op, *ep;
BITCMD *set, *saveset, *endset;
sigset_t sigset, sigoset;
mode_t mask;
int equalopdone = 0; /* pacify gcc */
int permXbits, setlen;
 
if (!*p)
return (NULL);
 
/*
* Get a copy of the mask for the permissions that are mask relative.
* Flip the bits, we want what's not set. Since it's possible that
* the caller is opening files inside a signal handler, protect them
* as best we can.
*/
sigfillset(&sigset);
(void)sigprocmask(SIG_BLOCK, &sigset, &sigoset);
(void)umask(mask = umask(0));
mask = ~mask;
(void)sigprocmask(SIG_SETMASK, &sigoset, NULL);
 
setlen = SET_LEN + 2;
if ((set = malloc((u_int)(sizeof(BITCMD) * setlen))) == NULL)
return (NULL);
saveset = set;
endset = set + (setlen - 2);
 
/*
* If an absolute number, get it and return; disallow non-octal digits
* or illegal bits.
*/
if (isdigit((unsigned char)*p)) {
perm = (mode_t)strtol(p, &ep, 8);
if (*ep || perm & ~(STANDARD_BITS|S_ISTXT)) {
free(saveset);
return (NULL);
}
ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask);
set->cmd = 0;
return (saveset);
}
 
/*
* Build list of structures to set/clear/copy bits as described by
* each clause of the symbolic mode.
*/
for (;;) {
/* First, find out which bits might be modified. */
for (who = 0;; ++p) {
switch (*p) {
case 'a':
who |= STANDARD_BITS;
break;
case 'u':
who |= S_ISUID|S_IRWXU;
break;
case 'g':
who |= S_ISGID|S_IRWXG;
break;
case 'o':
who |= S_IRWXO;
break;
default:
goto getop;
}
}
 
getop: if ((op = *p++) != '+' && op != '-' && op != '=') {
free(saveset);
return (NULL);
}
if (op == '=')
equalopdone = 0;
 
who &= ~S_ISTXT;
for (perm = 0, permXbits = 0;; ++p) {
switch (*p) {
case 'r':
perm |= S_IRUSR|S_IRGRP|S_IROTH;
break;
case 's':
/*
* If specific bits where requested and
* only "other" bits ignore set-id.
*/
if (who == 0 || (who & ~S_IRWXO))
perm |= S_ISUID|S_ISGID;
break;
case 't':
/*
* If specific bits where requested and
* only "other" bits ignore set-id.
*/
if (who == 0 || (who & ~S_IRWXO)) {
who |= S_ISTXT;
perm |= S_ISTXT;
}
break;
case 'w':
perm |= S_IWUSR|S_IWGRP|S_IWOTH;
break;
case 'X':
permXbits = S_IXUSR|S_IXGRP|S_IXOTH;
break;
case 'x':
perm |= S_IXUSR|S_IXGRP|S_IXOTH;
break;
case 'u':
case 'g':
case 'o':
/*
* When ever we hit 'u', 'g', or 'o', we have
* to flush out any partial mode that we have,
* and then do the copying of the mode bits.
*/
if (perm) {
ADDCMD(op, who, perm, mask);
perm = 0;
}
if (op == '=')
equalopdone = 1;
if (op == '+' && permXbits) {
ADDCMD('X', who, permXbits, mask);
permXbits = 0;
}
ADDCMD(*p, who, op, mask);
break;
 
default:
/*
* Add any permissions that we haven't already
* done.
*/
if (perm || (op == '=' && !equalopdone)) {
if (op == '=')
equalopdone = 1;
ADDCMD(op, who, perm, mask);
perm = 0;
}
if (permXbits) {
ADDCMD('X', who, permXbits, mask);
permXbits = 0;
}
goto apply;
}
}
 
apply: if (!*p)
break;
if (*p != ',')
goto getop;
++p;
}
set->cmd = 0;
#ifdef SETMODE_DEBUG
(void)printf("Before compress_mode()\n");
dumpmode(saveset);
#endif
compress_mode(saveset);
#ifdef SETMODE_DEBUG
(void)printf("After compress_mode()\n");
dumpmode(saveset);
#endif
return (saveset);
}
 
static BITCMD *
addcmd(set, op, who, oparg, mask)
BITCMD *set;
int oparg, who;
int op;
u_int mask;
{
 
_DIAGASSERT(set != NULL);
 
switch (op) {
case '=':
set->cmd = '-';
set->bits = who ? who : STANDARD_BITS;
set++;
 
op = '+';
/* FALLTHROUGH */
case '+':
case '-':
case 'X':
set->cmd = op;
set->bits = (who ? who : mask) & oparg;
break;
 
case 'u':
case 'g':
case 'o':
set->cmd = op;
if (who) {
set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) |
((who & S_IRGRP) ? CMD2_GBITS : 0) |
((who & S_IROTH) ? CMD2_OBITS : 0);
set->bits = (mode_t)~0;
} else {
set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS;
set->bits = mask;
}
if (oparg == '+')
set->cmd2 |= CMD2_SET;
else if (oparg == '-')
set->cmd2 |= CMD2_CLR;
else if (oparg == '=')
set->cmd2 |= CMD2_SET|CMD2_CLR;
break;
}
return (set + 1);
}
 
#ifdef SETMODE_DEBUG
static void
dumpmode(set)
BITCMD *set;
{
 
_DIAGASSERT(set != NULL);
 
for (; set->cmd; ++set)
(void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n",
set->cmd, set->bits, set->cmd2 ? " cmd2:" : "",
set->cmd2 & CMD2_CLR ? " CLR" : "",
set->cmd2 & CMD2_SET ? " SET" : "",
set->cmd2 & CMD2_UBITS ? " UBITS" : "",
set->cmd2 & CMD2_GBITS ? " GBITS" : "",
set->cmd2 & CMD2_OBITS ? " OBITS" : "");
}
#endif
 
/*
* Given an array of bitcmd structures, compress by compacting consecutive
* '+', '-' and 'X' commands into at most 3 commands, one of each. The 'u',
* 'g' and 'o' commands continue to be separate. They could probably be
* compacted, but it's not worth the effort.
*/
static void
compress_mode(set)
BITCMD *set;
{
BITCMD *nset;
int setbits, clrbits, Xbits, op;
 
_DIAGASSERT(set != NULL);
 
for (nset = set;;) {
/* Copy over any 'u', 'g' and 'o' commands. */
while ((op = nset->cmd) != '+' && op != '-' && op != 'X') {
*set++ = *nset++;
if (!op)
return;
}
 
for (setbits = clrbits = Xbits = 0;; nset++) {
if ((op = nset->cmd) == '-') {
clrbits |= nset->bits;
setbits &= ~nset->bits;
Xbits &= ~nset->bits;
} else if (op == '+') {
setbits |= nset->bits;
clrbits &= ~nset->bits;
Xbits &= ~nset->bits;
} else if (op == 'X')
Xbits |= nset->bits & ~setbits;
else
break;
}
if (clrbits) {
set->cmd = '-';
set->cmd2 = 0;
set->bits = clrbits;
set++;
}
if (setbits) {
set->cmd = '+';
set->cmd2 = 0;
set->bits = setbits;
set++;
}
if (Xbits) {
set->cmd = 'X';
set->cmd2 = 0;
set->bits = Xbits;
set++;
}
}
}
/trunk/uspace/app/ash/options.h
0,0 → 1,115
/* $NetBSD: options.h,v 1.13 1999/07/09 03:05:50 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)options.h 8.2 (Berkeley) 5/4/95
*/
 
struct shparam {
int nparam; /* # of positional parameters (without $0) */
unsigned char malloc; /* if parameter list dynamically allocated */
char **p; /* parameter list */
int optind; /* next parameter to be processed by getopts */
int optoff; /* used by getopts */
};
 
 
 
#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 qflag optlist[15].val
 
#define NOPTS 16
 
struct optent {
const char *name;
const char letter;
char val;
};
 
#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 },
{ "quietprofile", 'q', 0 },
};
#else
extern struct optent optlist[NOPTS];
#endif
 
 
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 *optarg; /* set by nextopt */
extern char *optptr; /* used by nextopt */
 
void procargs (int, char **);
void optschanged (void);
void setparam (char **);
void freeparam (volatile struct shparam *);
int shiftcmd (int, char **);
int setcmd (int, char **);
int getoptscmd (int, char **);
int nextopt (const char *);
void getoptsreset (const char *);
/trunk/uspace/app/ash/mkbuiltins
0,0 → 1,100
#!/bin/sh -
# $NetBSD: mkbuiltins,v 1.15 1999/07/09 03:05:50 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. All advertising materials mentioning features or use of this software
# must display the following acknowledgement:
# This product includes software developed by the University of
# California, Berkeley and its contributors.
# 4. Neither the name of the University nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# @(#)mkbuiltins 8.2 (Berkeley) 5/4/95
 
temp=/tmp/ka$$
 
havehist=1
if [ "X$1" = "X-h" ]; then
havehist=0
shift
fi
shell=$1
builtins=$2
objdir=$3
 
havejobs=0
if grep '^#define JOBS[ ]*1' ${shell} > /dev/null
then
havejobs=1
fi
 
exec > ${objdir}/builtins.c
cat <<\!
/*
* This file was generated by the mkbuiltins program.
*/
 
#include "shell.h"
#include "builtins.h"
 
!
awk '/^[^#]/ {if(('$havejobs' || $2 != "-j") && ('$havehist' || $2 != "-h")) \
print $0}' ${builtins} | sed 's/-j//' > $temp
awk '{ printf "int %s (int, char **);\n", $1}' $temp
echo '
int (*const builtinfunc[]) (int, char **) = {'
awk '/^[^#]/ { printf "\t%s,\n", $1}' $temp
echo '};
 
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 <<\!
/*
* This file was generated by the mkbuiltins program.
*/
 
#include <sys/cdefs.h>
!
tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ < $temp |
awk '{ printf "#define %s %d\n", $1, NR-1}'
echo '
struct builtincmd {
const char *name;
int code;
};
 
extern int (*const builtinfunc[]) (int, char **);
extern const struct builtincmd builtincmd[];'
rm -f $temp
/trunk/uspace/app/ash/fake.c
0,0 → 1,50
/*
* Copyright (c) 2008 Josef Cejka
* 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 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.
* - 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.
*/
 
#include "fake.h"
 
uid_t getuid(void)
{
return 0;
}
 
uid_t geteuid(void)
{
return 0;
}
 
uid_t getgid(void)
{
return 0;
}
 
uid_t getegid(void)
{
return 0;
}
 
/trunk/uspace/app/ash/init.h
0,0 → 1,43
/* $NetBSD: init.h,v 1.8 1995/05/11 21:29:14 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)init.h 8.2 (Berkeley) 5/4/95
*/
 
void init (void);
void reset (void);
void initshellproc (void);
/trunk/uspace/app/ash/fake.h
0,0 → 1,43
/*
* Copyright (c) 2008 Josef Cejka
* 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 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.
* - 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.
*/
 
#ifndef fake_h
#define fake_h
 
typedef int uid_t;
 
uid_t getuid(void);
uid_t geteuid(void);
uid_t getgid(void);
uid_t getegid(void);
 
/* setjmp.h */
typedef int jmp_buf[6];
 
#endif
 
/trunk/uspace/app/ash/tools/mksignames.c
0,0 → 1,400
/* signames.c -- Create and write `signames.c', which contains an array of
signal names. */
 
/* Copyright (C) 1992 Free Software Foundation, Inc.
 
This file is part of GNU Bash, the Bourne Again SHell.
 
Bash is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
 
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
 
You should have received a copy of the GNU General Public License along
with Bash; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
 
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <stdlib.h>
 
#if !defined (NSIG)
# define NSIG 64
#endif
 
char *signal_names[2 * NSIG];
 
char *progname;
 
#if defined (SIGRTMAX) || defined (SIGRTMIN)
# define RTLEN 14
# define RTLIM 256
#endif
 
void
initialize_signames ()
{
register int i;
#if defined (SIGRTMAX) || defined (SIGRTMIN)
int rtmin, rtmax, rtcnt;
#endif
 
for (i = 1; i < sizeof(signal_names)/sizeof(signal_names[0]); i++)
signal_names[i] = (char *)NULL;
 
/* `signal' 0 is what we do on exit. */
signal_names[0] = "EXIT";
 
/* Place signal names which can be aliases for more common signal
names first. This allows (for example) SIGABRT to overwrite SIGLOST. */
 
/* POSIX 1003.1b-1993 real time signals, but take care of incomplete
implementations. Acoording to the standard, both, SIGRTMIN and
SIGRTMAX must be defined, SIGRTMIN must be stricly less than
SIGRTMAX, and the difference must be at least 7, that is, there
must be at least eight distinct real time signals. */
 
/* The generated signal names are SIGRTMIN, SIGRTMIN+1, ...,
SIGRTMIN+x, SIGRTMAX-x, ..., SIGRTMAX-1, SIGRTMAX. If the number
of RT signals is odd, there is an extra SIGRTMIN+(x+1).
These names are the ones used by ksh and /usr/xpg4/bin/sh on SunOS5. */
 
#if defined (SIGRTMIN)
rtmin = SIGRTMIN;
signal_names[rtmin] = "SIGRTMIN";
#endif
 
#if defined (SIGRTMAX)
rtmax = SIGRTMAX;
signal_names[rtmax] = "SIGRTMAX";
#endif
 
#if defined (SIGRTMAX) && defined (SIGRTMIN)
if (rtmax > rtmin)
{
rtcnt = (rtmax - rtmin - 1) / 2;
/* croak if there are too many RT signals */
if (rtcnt >= RTLIM/2)
{
rtcnt = RTLIM/2-1;
fprintf(stderr, "%s: error: more than %i real time signals, fix `%s'\n",
progname, RTLIM, progname);
}
 
for (i = 1; i <= rtcnt; i++)
{
signal_names[rtmin+i] = (char *)malloc(RTLEN);
sprintf (signal_names[rtmin+i], "SIGRTMIN+%d", i);
signal_names[rtmax-i] = (char *)malloc(RTLEN);
sprintf (signal_names[rtmax-i], "SIGRTMAX-%d", i);
}
 
if (rtcnt < RTLIM/2-1 && rtcnt != (rtmax-rtmin)/2)
{
/* Need an extra RTMIN signal */
signal_names[rtmin+rtcnt+1] = (char *)malloc(RTLEN);
sprintf (signal_names[rtmin+rtcnt+1], "SIGRTMIN+%d", rtcnt+1);
}
}
#endif /* SIGRTMIN && SIGRTMAX */
 
/* AIX */
#if defined (SIGLOST) /* resource lost (eg, record-lock lost) */
signal_names[SIGLOST] = "SIGLOST";
#endif
 
#if defined (SIGMSG) /* HFT input data pending */
signal_names[SIGMSG] = "SIGMSG";
#endif
 
#if defined (SIGDANGER) /* system crash imminent */
signal_names[SIGDANGER] = "SIGDANGER";
#endif
 
#if defined (SIGMIGRATE) /* migrate process to another CPU */
signal_names[SIGMIGRATE] = "SIGMIGRATE";
#endif
 
#if defined (SIGPRE) /* programming error */
signal_names[SIGPRE] = "SIGPRE";
#endif
 
#if defined (SIGVIRT) /* AIX virtual time alarm */
signal_names[SIGVIRT] = "SIGVIRT";
#endif
 
#if defined (SIGALRM1) /* m:n condition variables */
signal_names[SIGALRM1] = "SIGALRM1";
#endif
 
#if defined (SIGWAITING) /* m:n scheduling */
signal_names[SIGWAITING] = "SIGWAITING";
#endif
 
#if defined (SIGGRANT) /* HFT monitor mode granted */
signal_names[SIGGRANT] = "SIGGRANT";
#endif
 
#if defined (SIGKAP) /* keep alive poll from native keyboard */
signal_names[SIGKAP] = "SIGKAP";
#endif
 
#if defined (SIGRETRACT) /* HFT monitor mode retracted */
signal_names[SIGRETRACT] = "SIGRETRACT";
#endif
 
#if defined (SIGSOUND) /* HFT sound sequence has completed */
signal_names[SIGSOUND] = "SIGSOUND";
#endif
 
#if defined (SIGSAK) /* Secure Attention Key */
signal_names[SIGSAK] = "SIGSAK";
#endif
 
/* SunOS5 */
#if defined (SIGLWP) /* special signal used by thread library */
signal_names[SIGLWP] = "SIGLWP";
#endif
 
#if defined (SIGFREEZE) /* special signal used by CPR */
signal_names[SIGFREEZE] = "SIGFREEZE";
#endif
 
#if defined (SIGTHAW) /* special signal used by CPR */
signal_names[SIGTHAW] = "SIGTHAW";
#endif
 
#if defined (SIGCANCEL) /* thread cancellation signal used by libthread */
signal_names[SIGCANCEL] = "SIGCANCEL";
#endif
 
/* HP-UX */
#if defined (SIGDIL) /* DIL signal (?) */
signal_names[SIGDIL] = "SIGDIL";
#endif
 
/* System V */
#if defined (SIGCLD) /* Like SIGCHLD. */
signal_names[SIGCLD] = "SIGCLD";
#endif
 
#if defined (SIGPWR) /* power state indication */
signal_names[SIGPWR] = "SIGPWR";
#endif
 
#if defined (SIGPOLL) /* Pollable event (for streams) */
signal_names[SIGPOLL] = "SIGPOLL";
#endif
 
/* Unknown */
#if defined (SIGWINDOW)
signal_names[SIGWINDOW] = "SIGWINDOW";
#endif
 
/* Common */
#if defined (SIGHUP) /* hangup */
signal_names[SIGHUP] = "SIGHUP";
#endif
 
#if defined (SIGINT) /* interrupt */
signal_names[SIGINT] = "SIGINT";
#endif
 
#if defined (SIGQUIT) /* quit */
signal_names[SIGQUIT] = "SIGQUIT";
#endif
 
#if defined (SIGILL) /* illegal instruction (not reset when caught) */
signal_names[SIGILL] = "SIGILL";
#endif
 
#if defined (SIGTRAP) /* trace trap (not reset when caught) */
signal_names[SIGTRAP] = "SIGTRAP";
#endif
 
#if defined (SIGIOT) /* IOT instruction */
signal_names[SIGIOT] = "SIGIOT";
#endif
 
#if defined (SIGABRT) /* Cause current process to dump core. */
signal_names[SIGABRT] = "SIGABRT";
#endif
 
#if defined (SIGEMT) /* EMT instruction */
signal_names[SIGEMT] = "SIGEMT";
#endif
 
#if defined (SIGFPE) /* floating point exception */
signal_names[SIGFPE] = "SIGFPE";
#endif
 
#if defined (SIGKILL) /* kill (cannot be caught or ignored) */
signal_names[SIGKILL] = "SIGKILL";
#endif
 
#if defined (SIGBUS) /* bus error */
signal_names[SIGBUS] = "SIGBUS";
#endif
 
#if defined (SIGSEGV) /* segmentation violation */
signal_names[SIGSEGV] = "SIGSEGV";
#endif
 
#if defined (SIGSYS) /* bad argument to system call */
signal_names[SIGSYS] = "SIGSYS";
#endif
 
#if defined (SIGPIPE) /* write on a pipe with no one to read it */
signal_names[SIGPIPE] = "SIGPIPE";
#endif
 
#if defined (SIGALRM) /* alarm clock */
signal_names[SIGALRM] = "SIGALRM";
#endif
 
#if defined (SIGTERM) /* software termination signal from kill */
signal_names[SIGTERM] = "SIGTERM";
#endif
 
#if defined (SIGURG) /* urgent condition on IO channel */
signal_names[SIGURG] = "SIGURG";
#endif
 
#if defined (SIGSTOP) /* sendable stop signal not from tty */
signal_names[SIGSTOP] = "SIGSTOP";
#endif
 
#if defined (SIGTSTP) /* stop signal from tty */
signal_names[SIGTSTP] = "SIGTSTP";
#endif
 
#if defined (SIGCONT) /* continue a stopped process */
signal_names[SIGCONT] = "SIGCONT";
#endif
 
#if defined (SIGCHLD) /* to parent on child stop or exit */
signal_names[SIGCHLD] = "SIGCHLD";
#endif
 
#if defined (SIGTTIN) /* to readers pgrp upon background tty read */
signal_names[SIGTTIN] = "SIGTTIN";
#endif
 
#if defined (SIGTTOU) /* like TTIN for output if (tp->t_local&LTOSTOP) */
signal_names[SIGTTOU] = "SIGTTOU";
#endif
 
#if defined (SIGIO) /* input/output possible signal */
signal_names[SIGIO] = "SIGIO";
#endif
 
#if defined (SIGXCPU) /* exceeded CPU time limit */
signal_names[SIGXCPU] = "SIGXCPU";
#endif
 
#if defined (SIGXFSZ) /* exceeded file size limit */
signal_names[SIGXFSZ] = "SIGXFSZ";
#endif
 
#if defined (SIGVTALRM) /* virtual time alarm */
signal_names[SIGVTALRM] = "SIGVTALRM";
#endif
 
#if defined (SIGPROF) /* profiling time alarm */
signal_names[SIGPROF] = "SIGPROF";
#endif
 
#if defined (SIGWINCH) /* window changed */
signal_names[SIGWINCH] = "SIGWINCH";
#endif
 
/* 4.4 BSD */
#if defined (SIGINFO) && !defined (_SEQUENT_) /* information request */
signal_names[SIGINFO] = "SIGINFO";
#endif
 
#if defined (SIGUSR1) /* user defined signal 1 */
signal_names[SIGUSR1] = "SIGUSR1";
#endif
 
#if defined (SIGUSR2) /* user defined signal 2 */
signal_names[SIGUSR2] = "SIGUSR2";
#endif
 
#if defined (SIGKILLTHR) /* BeOS: Kill Thread */
signal_names[SIGKILLTHR] = "SIGKILLTHR";
#endif
 
for (i = 0; i < NSIG; i++)
if (signal_names[i] == (char *)NULL)
{
signal_names[i] = (char *)malloc (18);
sprintf (signal_names[i], "SIGJUNK(%d)", i);
}
 
signal_names[NSIG] = "DEBUG";
}
 
void
write_signames (stream)
FILE *stream;
{
register int i;
 
fprintf (stream, "/* This file was automatically created by %s.\n",
progname);
fprintf (stream, " Do not edit. Edit support/mksignames.c instead. */\n\n");
fprintf (stream, "#include <signal.h>\n\n");
fprintf (stream,
"/* A translation list so we can be polite to our users. */\n");
fprintf (stream, "char *signal_names[NSIG + 2] = {\n");
 
for (i = 0; i <= NSIG; i++)
fprintf (stream, " \"%s\",\n", signal_names[i]);
 
fprintf (stream, " (char *)0x0,\n");
fprintf (stream, "};\n");
}
 
int
main (argc, argv)
int argc;
char **argv;
{
char *stream_name;
FILE *stream;
 
progname = argv[0];
 
if (argc == 1)
{
stream_name = "signames.c";
}
else if (argc == 2)
{
stream_name = argv[1];
}
else
{
fprintf (stderr, "Usage: %s [output-file]\n", progname);
exit (1);
}
 
stream = fopen (stream_name, "w");
if (!stream)
{
fprintf (stderr, "%s: %s: cannot open for writing\n",
progname, stream_name);
exit (2);
}
 
initialize_signames ();
write_signames (stream);
exit (0);
}
/trunk/uspace/app/ash/tools/mksyntax.c
0,0 → 1,427
/* $NetBSD: mksyntax.c,v 1.23 2000/07/18 19:13:21 cgd 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
 
#ifndef lint
static const char copyright[] =
"@(#) Copyright (c) 1991, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
 
#ifndef lint
#if 0
static char sccsid[] = "@(#)mksyntax.c 8.2 (Berkeley) 5/4/95";
#else
static const char rcsid[] =
"$NetBSD: mksyntax.c,v 1.23 2000/07/18 19:13:21 cgd Exp $";
#endif
#endif /* not lint */
 
/*
* This program creates syntax.h and syntax.c.
*/
 
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include "../parser.h"
 
 
struct synclass {
char *name;
char *comment;
};
 
/* Syntax classes */
struct synclass synclass[] = {
{ "CWORD", "character is nothing special" },
{ "CNL", "newline character" },
{ "CBACK", "a backslash character" },
{ "CSQUOTE", "single quote" },
{ "CDQUOTE", "double quote" },
{ "CENDQUOTE", "a terminating quote" },
{ "CBQUOTE", "backwards single quote" },
{ "CVAR", "a dollar sign" },
{ "CENDVAR", "a '}' character" },
{ "CLP", "a left paren in arithmetic" },
{ "CRP", "a right paren in arithmetic" },
{ "CEOF", "end of file" },
{ "CCTL", "like CWORD, except it must be escaped" },
{ "CSPCL", "these terminate a word" },
{ NULL, NULL }
};
 
 
/*
* Syntax classes for is_ functions. Warning: if you add new classes
* you may have to change the definition of the is_in_name macro.
*/
struct synclass is_entry[] = {
{ "ISDIGIT", "a digit" },
{ "ISUPPER", "an upper case letter" },
{ "ISLOWER", "a lower case letter" },
{ "ISUNDER", "an underscore" },
{ "ISSPECL", "the name of a special parameter" },
{ NULL, NULL }
};
 
static char writer[] = "\
/*\n\
* This file was generated by the mksyntax program.\n\
*/\n\
\n";
 
 
static FILE *cfile;
static FILE *hfile;
static char *syntax[513];
static int base;
static int size; /* number of values which a char variable can have */
static int nbits; /* number of bits in a character */
static int digit_contig;/* true if digits are contiguous */
 
static void filltable(char *);
static void init(void);
static void add(char *, char *);
static void print(char *);
static void output_type_macros(void);
static void digit_convert(void);
int main(int, char **);
 
int
main(argc, argv)
int argc;
char **argv;
{
#ifdef TARGET_CHAR
TARGET_CHAR c;
TARGET_CHAR d;
#else
char c;
char d;
#endif
int sign;
int i;
char buf[80];
int pos;
static char digit[] = "0123456789";
 
/* Create output files */
if ((cfile = fopen("syntax.c", "w")) == NULL) {
perror("syntax.c");
exit(2);
}
if ((hfile = fopen("syntax.h", "w")) == NULL) {
perror("syntax.h");
exit(2);
}
fputs(writer, hfile);
fputs(writer, cfile);
 
/* Determine the characteristics of chars. */
c = -1;
if (c <= 0)
sign = 1;
else
sign = 0;
for (nbits = 1 ; ; nbits++) {
d = (1 << nbits) - 1;
if (d == c)
break;
}
printf("%s %d bit chars\n", sign? "signed" : "unsigned", nbits);
if (nbits > 9) {
fputs("Characters can't have more than 9 bits\n", stderr);
exit(2);
}
size = (1 << nbits) + 1;
base = 1;
if (sign)
base += 1 << (nbits - 1);
digit_contig = 1;
for (i = 0 ; i < 10 ; i++) {
if (digit[i] != '0' + i)
digit_contig = 0;
}
 
fputs("#include <sys/cdefs.h>\n", hfile);
fputs("#include <ctype.h>\n", hfile);
 
/* Generate the #define statements in the header file */
fputs("/* Syntax classes */\n", hfile);
for (i = 0 ; synclass[i].name ; i++) {
sprintf(buf, "#define %s %d", synclass[i].name, i);
fputs(buf, hfile);
for (pos = strlen(buf) ; pos < 32 ; pos = (pos + 8) & ~07)
putc('\t', hfile);
fprintf(hfile, "/* %s */\n", synclass[i].comment);
}
putc('\n', hfile);
fputs("/* Syntax classes for is_ functions */\n", hfile);
for (i = 0 ; is_entry[i].name ; i++) {
sprintf(buf, "#define %s %#o", is_entry[i].name, 1 << i);
fputs(buf, hfile);
for (pos = strlen(buf) ; pos < 32 ; pos = (pos + 8) & ~07)
putc('\t', hfile);
fprintf(hfile, "/* %s */\n", is_entry[i].comment);
}
putc('\n', hfile);
fprintf(hfile, "#define SYNBASE %d\n", base);
fprintf(hfile, "#define PEOF %d\n\n", -base);
if (sign)
fprintf(hfile, "#define UPEOF %d\n\n", -base);
else
fprintf(hfile, "#define UPEOF ((unsigned char) %d)\n\n", -base);
putc('\n', hfile);
fputs("#define BASESYNTAX (basesyntax + SYNBASE)\n", hfile);
fputs("#define DQSYNTAX (dqsyntax + SYNBASE)\n", hfile);
fputs("#define SQSYNTAX (sqsyntax + SYNBASE)\n", hfile);
fputs("#define ARISYNTAX (arisyntax + SYNBASE)\n", hfile);
putc('\n', hfile);
output_type_macros(); /* is_digit, etc. */
putc('\n', hfile);
 
/* Generate the syntax tables. */
fputs("#include \"shell.h\"\n", cfile);
fputs("#include \"syntax.h\"\n\n", cfile);
init();
fputs("/* syntax table used when not in quotes */\n", cfile);
add("\n", "CNL");
add("\\", "CBACK");
add("'", "CSQUOTE");
add("\"", "CDQUOTE");
add("`", "CBQUOTE");
add("$", "CVAR");
add("}", "CENDVAR");
add("<>();&| \t", "CSPCL");
print("basesyntax");
init();
fputs("\n/* syntax table used when in double quotes */\n", cfile);
add("\n", "CNL");
add("\\", "CBACK");
add("\"", "CENDQUOTE");
add("`", "CBQUOTE");
add("$", "CVAR");
add("}", "CENDVAR");
/* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
add("!*?[=~:/-]", "CCTL");
print("dqsyntax");
init();
fputs("\n/* syntax table used when in single quotes */\n", cfile);
add("\n", "CNL");
add("'", "CENDQUOTE");
/* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
add("!*?[=~:/-]\\", "CCTL");
print("sqsyntax");
init();
fputs("\n/* syntax table used when in arithmetic */\n", cfile);
add("\n", "CNL");
add("\\", "CBACK");
add("`", "CBQUOTE");
add("'", "CSQUOTE");
add("\"", "CDQUOTE");
add("$", "CVAR");
add("}", "CENDVAR");
add("(", "CLP");
add(")", "CRP");
print("arisyntax");
filltable("0");
fputs("\n/* character classification table */\n", cfile);
add("0123456789", "ISDIGIT");
add("abcdefghijklmnopqrstucvwxyz", "ISLOWER");
add("ABCDEFGHIJKLMNOPQRSTUCVWXYZ", "ISUPPER");
add("_", "ISUNDER");
add("#?$!-*@", "ISSPECL");
print("is_type");
if (! digit_contig)
digit_convert();
exit(0);
/* NOTREACHED */
}
 
 
 
/*
* Clear the syntax table.
*/
 
static void
filltable(dftval)
char *dftval;
{
int i;
 
for (i = 0 ; i < size ; i++)
syntax[i] = dftval;
}
 
 
/*
* Initialize the syntax table with default values.
*/
 
static void
init()
{
filltable("CWORD");
syntax[0] = "CEOF";
#ifdef TARGET_CHAR
syntax[base + (TARGET_CHAR)CTLESC] = "CCTL";
syntax[base + (TARGET_CHAR)CTLVAR] = "CCTL";
syntax[base + (TARGET_CHAR)CTLENDVAR] = "CCTL";
syntax[base + (TARGET_CHAR)CTLBACKQ] = "CCTL";
syntax[base + (TARGET_CHAR)CTLBACKQ + (TARGET_CHAR)CTLQUOTE] = "CCTL";
syntax[base + (TARGET_CHAR)CTLARI] = "CCTL";
syntax[base + (TARGET_CHAR)CTLENDARI] = "CCTL";
syntax[base + (TARGET_CHAR)CTLQUOTEMARK] = "CCTL";
#else
syntax[base + CTLESC] = "CCTL";
syntax[base + CTLVAR] = "CCTL";
syntax[base + CTLENDVAR] = "CCTL";
syntax[base + CTLBACKQ] = "CCTL";
syntax[base + CTLBACKQ + CTLQUOTE] = "CCTL";
syntax[base + CTLARI] = "CCTL";
syntax[base + CTLENDARI] = "CCTL";
syntax[base + CTLQUOTEMARK] = "CCTL";
#endif /* TARGET_CHAR */
}
 
 
/*
* Add entries to the syntax table.
*/
 
static void
add(p, type)
char *p, *type;
{
while (*p)
syntax[*p++ + base] = type;
}
 
 
 
/*
* Output the syntax table.
*/
 
static void
print(name)
char *name;
{
int i;
int col;
 
fprintf(hfile, "extern const char %s[];\n", name);
fprintf(cfile, "const char %s[%d] = {\n", name, size);
col = 0;
for (i = 0 ; i < size ; i++) {
if (i == 0) {
fputs(" ", cfile);
} else if ((i & 03) == 0) {
fputs(",\n ", cfile);
col = 0;
} else {
putc(',', cfile);
while (++col < 9 * (i & 03))
putc(' ', cfile);
}
fputs(syntax[i], cfile);
col += strlen(syntax[i]);
}
fputs("\n};\n", cfile);
}
 
 
 
/*
* Output character classification macros (e.g. is_digit). If digits are
* contiguous, we can test for them quickly.
*/
 
static char *macro[] = {
"#define is_digit(c)\t((is_type+SYNBASE)[c] & ISDIGIT)",
"#define is_alpha(c)\t((c) != UPEOF && ((c) < CTLESC || (c) > CTLENDARI) && isalpha((unsigned char) (c)))",
"#define is_name(c)\t((c) != UPEOF && ((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalpha((unsigned char) (c))))",
"#define is_in_name(c)\t((c) != UPEOF && ((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalnum((unsigned char) (c))))",
"#define is_special(c)\t((is_type+SYNBASE)[c] & (ISSPECL|ISDIGIT))",
NULL
};
 
static void
output_type_macros()
{
char **pp;
 
if (digit_contig)
macro[0] = "#define is_digit(c)\t((unsigned)((c) - '0') <= 9)";
for (pp = macro ; *pp ; pp++)
fprintf(hfile, "%s\n", *pp);
if (digit_contig)
fputs("#define digit_val(c)\t((c) - '0')\n", hfile);
else
fputs("#define digit_val(c)\t(digit_value[c])\n", hfile);
}
 
 
 
/*
* Output digit conversion table (if digits are not contiguous).
*/
 
static void
digit_convert()
{
int maxdigit;
static char digit[] = "0123456789";
char *p;
int i;
 
maxdigit = 0;
for (p = digit ; *p ; p++)
if (*p > maxdigit)
maxdigit = *p;
fputs("extern const char digit_value[];\n", hfile);
fputs("\n\nconst char digit_value[] = {\n", cfile);
for (i = 0 ; i <= maxdigit ; i++) {
for (p = digit ; *p && *p != i ; p++);
if (*p == '\0')
p = digit;
fprintf(cfile, " %ld,\n", (long)(p - digit));
}
fputs("};\n", cfile);
}
/trunk/uspace/app/ash/tools/mknodes.c
0,0 → 1,492
/* $NetBSD: mknodes.c,v 1.18 2000/07/27 04:06:49 cgd 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
 
#ifndef lint
static const char copyright[] =
"@(#) Copyright (c) 1991, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
 
#ifndef lint
#if 0
static char sccsid[] = "@(#)mknodes.c 8.2 (Berkeley) 5/4/95";
#else
static const char rcsid[] =
"$NetBSD: mknodes.c,v 1.18 2000/07/27 04:06:49 cgd Exp $";
#endif
#endif /* not lint */
 
/*
* This program reads the nodetypes file and nodes.c.pat file. It generates
* the files nodes.h and nodes.c.
*/
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
 
 
#define MAXTYPES 50 /* max number of node types */
#define MAXFIELDS 20 /* max fields in a structure */
#define BUFLEN 100 /* size of character buffers */
 
/* field types */
#define T_NODE 1 /* union node *field */
#define T_NODELIST 2 /* struct nodelist *field */
#define T_STRING 3
#define T_INT 4 /* int field */
#define T_OTHER 5 /* other */
#define T_TEMP 6 /* don't copy this field */
 
 
struct field { /* a structure field */
char *name; /* name of field */
int type; /* type of field */
char *decl; /* declaration of field */
};
 
 
struct str { /* struct representing a node structure */
char *tag; /* structure tag */
int nfields; /* number of fields in the structure */
struct field field[MAXFIELDS]; /* the fields of the structure */
int done; /* set if fully parsed */
};
 
 
static int ntypes; /* number of node types */
static char *nodename[MAXTYPES]; /* names of the nodes */
static struct str *nodestr[MAXTYPES]; /* type of structure used by the node */
static int nstr; /* number of structures */
static struct str str[MAXTYPES]; /* the structures */
static struct str *curstr; /* current structure */
static FILE *infp;
static char line[1024];
static int linno;
static char *linep;
 
static void parsenode(void);
static void parsefield(void);
static void output(char *);
static void outsizes(FILE *);
static void outfunc(FILE *, int);
static void indent(int, FILE *);
static int nextfield(char *);
static void skipbl(void);
static int readline(void);
static void error(const char *, ...);
static char *savestr(const char *);
int main(int, char **);
 
 
int
main(argc, argv)
int argc;
char **argv;
{
 
/*
* some versions of linux complain: initializer element is not
* constant if this is done at compile time.
*/
infp = stdin;
 
if (argc != 3)
error("usage: mknodes file");
if ((infp = fopen(argv[1], "r")) == NULL)
error("Can't open %s", argv[1]);
while (readline()) {
if (line[0] == ' ' || line[0] == '\t')
parsefield();
else if (line[0] != '\0')
parsenode();
}
output(argv[2]);
exit(0);
/* NOTREACHED */
}
 
 
 
static void
parsenode()
{
char name[BUFLEN];
char tag[BUFLEN];
struct str *sp;
 
if (curstr && curstr->nfields > 0)
curstr->done = 1;
nextfield(name);
if (! nextfield(tag))
error("Tag expected");
if (*linep != '\0')
error("Garbage at end of line");
nodename[ntypes] = savestr(name);
for (sp = str ; sp < str + nstr ; sp++) {
if (strcmp(sp->tag, tag) == 0)
break;
}
if (sp >= str + nstr) {
sp->tag = savestr(tag);
sp->nfields = 0;
curstr = sp;
nstr++;
}
nodestr[ntypes] = sp;
ntypes++;
}
 
 
static void
parsefield()
{
char name[BUFLEN];
char type[BUFLEN];
char decl[2 * BUFLEN];
struct field *fp;
 
if (curstr == NULL || curstr->done)
error("No current structure to add field to");
if (! nextfield(name))
error("No field name");
if (! nextfield(type))
error("No field type");
fp = &curstr->field[curstr->nfields];
fp->name = savestr(name);
if (strcmp(type, "nodeptr") == 0) {
fp->type = T_NODE;
sprintf(decl, "union node *%s", name);
} else if (strcmp(type, "nodelist") == 0) {
fp->type = T_NODELIST;
sprintf(decl, "struct nodelist *%s", name);
} else if (strcmp(type, "string") == 0) {
fp->type = T_STRING;
sprintf(decl, "char *%s", name);
} else if (strcmp(type, "int") == 0) {
fp->type = T_INT;
sprintf(decl, "int %s", name);
} else if (strcmp(type, "other") == 0) {
fp->type = T_OTHER;
} else if (strcmp(type, "temp") == 0) {
fp->type = T_TEMP;
} else {
error("Unknown type %s", type);
}
if (fp->type == T_OTHER || fp->type == T_TEMP) {
skipbl();
fp->decl = savestr(linep);
} else {
if (*linep)
error("Garbage at end of line");
fp->decl = savestr(decl);
}
curstr->nfields++;
}
 
 
char writer[] = "\
/*\n\
* This file was generated by the mknodes program.\n\
*/\n\
\n";
 
static void
output(file)
char *file;
{
FILE *hfile;
FILE *cfile;
FILE *patfile;
int i;
struct str *sp;
struct field *fp;
char *p;
 
if ((patfile = fopen(file, "r")) == NULL)
error("Can't open %s", file);
if ((hfile = fopen("nodes.h", "w")) == NULL)
error("Can't create nodes.h");
if ((cfile = fopen("nodes.c", "w")) == NULL)
error("Can't create nodes.c");
fputs(writer, hfile);
for (i = 0 ; i < ntypes ; i++)
fprintf(hfile, "#define %s %d\n", nodename[i], i);
fputs("\n\n\n", hfile);
for (sp = str ; sp < &str[nstr] ; sp++) {
fprintf(hfile, "struct %s {\n", sp->tag);
for (i = sp->nfields, fp = sp->field ; --i >= 0 ; fp++) {
fprintf(hfile, " %s;\n", fp->decl);
}
fputs("};\n\n\n", hfile);
}
fputs("union node {\n", hfile);
fprintf(hfile, " int type;\n");
for (sp = str ; sp < &str[nstr] ; sp++) {
fprintf(hfile, " struct %s %s;\n", sp->tag, sp->tag);
}
fputs("};\n\n\n", hfile);
fputs("struct nodelist {\n", hfile);
fputs("\tstruct nodelist *next;\n", hfile);
fputs("\tunion node *n;\n", hfile);
fputs("};\n\n\n", hfile);
fputs("#ifdef __STDC__\n", hfile);
fputs("union node *copyfunc(union node *);\n", hfile);
fputs("void freefunc(union node *);\n", hfile);
fputs("#else\n", hfile);
fputs("union node *copyfunc();\n", hfile);
fputs("void freefunc();\n", hfile);
fputs("#endif\n", hfile);
 
fputs(writer, cfile);
while (fgets(line, sizeof line, patfile) != NULL) {
for (p = line ; *p == ' ' || *p == '\t' ; p++);
if (strcmp(p, "%SIZES\n") == 0)
outsizes(cfile);
else if (strcmp(p, "%CALCSIZE\n") == 0)
outfunc(cfile, 1);
else if (strcmp(p, "%COPY\n") == 0)
outfunc(cfile, 0);
else
fputs(line, cfile);
}
}
 
 
 
static void
outsizes(cfile)
FILE *cfile;
{
int i;
 
fprintf(cfile, "static const short nodesize[%d] = {\n", ntypes);
for (i = 0 ; i < ntypes ; i++) {
fprintf(cfile, " ALIGN(sizeof (struct %s)),\n", nodestr[i]->tag);
}
fprintf(cfile, "};\n");
}
 
 
static void
outfunc(cfile, calcsize)
FILE *cfile;
int calcsize;
{
struct str *sp;
struct field *fp;
int i;
 
fputs(" if (n == NULL)\n", cfile);
if (calcsize)
fputs(" return;\n", cfile);
else
fputs(" return NULL;\n", cfile);
if (calcsize)
fputs(" funcblocksize += nodesize[n->type];\n", cfile);
else {
fputs(" new = funcblock;\n", cfile);
fputs(" funcblock = (char *) funcblock + nodesize[n->type];\n", cfile);
}
fputs(" switch (n->type) {\n", cfile);
for (sp = str ; sp < &str[nstr] ; sp++) {
for (i = 0 ; i < ntypes ; i++) {
if (nodestr[i] == sp)
fprintf(cfile, " case %s:\n", nodename[i]);
}
for (i = sp->nfields ; --i >= 1 ; ) {
fp = &sp->field[i];
switch (fp->type) {
case T_NODE:
if (calcsize) {
indent(12, cfile);
fprintf(cfile, "calcsize(n->%s.%s);\n",
sp->tag, fp->name);
} else {
indent(12, cfile);
fprintf(cfile, "new->%s.%s = copynode(n->%s.%s);\n",
sp->tag, fp->name, sp->tag, fp->name);
}
break;
case T_NODELIST:
if (calcsize) {
indent(12, cfile);
fprintf(cfile, "sizenodelist(n->%s.%s);\n",
sp->tag, fp->name);
} else {
indent(12, cfile);
fprintf(cfile, "new->%s.%s = copynodelist(n->%s.%s);\n",
sp->tag, fp->name, sp->tag, fp->name);
}
break;
case T_STRING:
if (calcsize) {
indent(12, cfile);
fprintf(cfile, "funcstringsize += strlen(n->%s.%s) + 1;\n",
sp->tag, fp->name);
} else {
indent(12, cfile);
fprintf(cfile, "new->%s.%s = nodesavestr(n->%s.%s);\n",
sp->tag, fp->name, sp->tag, fp->name);
}
break;
case T_INT:
case T_OTHER:
if (! calcsize) {
indent(12, cfile);
fprintf(cfile, "new->%s.%s = n->%s.%s;\n",
sp->tag, fp->name, sp->tag, fp->name);
}
break;
}
}
indent(12, cfile);
fputs("break;\n", cfile);
}
fputs(" };\n", cfile);
if (! calcsize)
fputs(" new->type = n->type;\n", cfile);
}
 
 
static void
indent(amount, fp)
int amount;
FILE *fp;
{
while (amount >= 8) {
putc('\t', fp);
amount -= 8;
}
while (--amount >= 0) {
putc(' ', fp);
}
}
 
 
static int
nextfield(buf)
char *buf;
{
char *p, *q;
 
p = linep;
while (*p == ' ' || *p == '\t')
p++;
q = buf;
while (*p != ' ' && *p != '\t' && *p != '\0')
*q++ = *p++;
*q = '\0';
linep = p;
return (q > buf);
}
 
 
static void
skipbl()
{
while (*linep == ' ' || *linep == '\t')
linep++;
}
 
 
static int
readline()
{
char *p;
 
if (fgets(line, 1024, infp) == NULL)
return 0;
for (p = line ; *p != '#' && *p != '\n' && *p != '\0' ; p++);
while (p > line && (p[-1] == ' ' || p[-1] == '\t'))
p--;
*p = '\0';
linep = line;
linno++;
if (p - line > BUFLEN)
error("Line too long");
return 1;
}
 
 
 
static void
#ifdef __STDC__
error(const char *msg, ...)
#else
error(va_alist)
va_dcl
#endif
{
va_list va;
#ifdef __STDC__
va_start(va, msg);
#else
char *msg;
va_start(va);
msg = va_arg(va, char *);
#endif
 
(void) fprintf(stderr, "line %d: ", linno);
(void) vfprintf(stderr, msg, va);
(void) fputc('\n', stderr);
 
va_end(va);
 
exit(2);
/* NOTREACHED */
}
 
 
 
static char *
savestr(s)
const char *s;
{
char *p;
 
if ((p = malloc(strlen(s) + 1)) == NULL)
error("Out of space");
(void) strcpy(p, s);
return p;
}
/trunk/uspace/app/ash/tools/mkinit.map
0,0 → 1,228
 
Allocating common symbols
Common symbol size file
 
header_files 0x320 mkinit.o
curfile 0x10 mkinit.o
amiddecls 0x10 mkinit.o
decls 0x10 mkinit.o
linno 0x10 mkinit.o
defines 0x10 mkinit.o
 
Memory Configuration
 
Name Origin Length Attributes
*default* 0x00000000 0xffffffff
 
Linker script and memory map
 
0x00400000 __image_base__ = 0x400000
0x00000000 __dll__ = 0x0
0x00001000 __section_alignment__ = 0x1000
0x00000200 __file_alignment__ = 0x200
0x00000004 __major_os_version__ = 0x4
0x00000000 __minor_os_version__ = 0x0
0x00000001 __major_image_version__ = 0x1
0x00000000 __minor_image_version__ = 0x0
0x00000004 __major_subsystem_version__ = 0x4
0x00000000 __minor_subsystem_version__ = 0x0
0x00000003 __subsystem__ = 0x3
0x00200000 __size_of_stack_reserve__ = 0x200000
0x00001000 __size_of_stack_commit__ = 0x1000
0x00100000 __size_of_heap_reserve__ = 0x100000
0x00001000 __size_of_heap_commit__ = 0x1000
0x00000000 __loader_flags__ = 0x0
LOAD mkinit.o
0x00000240 . = SIZEOF_HEADERS
0x00001000 . = ALIGN (__section_alignment__)
 
.text 0x00401000 0xe00
*(.init)
*(.text)
.text 0x00401000 0xc00 mkinit.o
0x00401b66 savestr
0x00401325 match
0x0040143d doevent
0x004015de doinclude
0x00401093 readfile
0x004019af addstr
0x00401b3a ckmalloc
0x00401ae9 ckfopen
0x00401398 gooddefine
0x00401b9a error
0x0040186f output
0x004016b1 dodecl
0x00401a69 writetext
0x00401000 main
0x004019fb addchar
*(SORT(.text$*))
*(.glue_7t)
*(.glue_7)
0x00401c00 ___CTOR_LIST__ = .
0x00401c00 __CTOR_LIST__ = .
0x00401c00 0x4 LONG 0xffffffff
*(.ctors)
*(.ctor)
*(SORT(.ctors.*))
0x00401c04 0x4 LONG 0x0
0x00401c08 ___DTOR_LIST__ = .
0x00401c08 __DTOR_LIST__ = .
0x00401c08 0x4 LONG 0xffffffff
*(.dtors)
*(.dtor)
*(SORT(.dtors.*))
0x00401c0c 0x4 LONG 0x0
*(.fini)
*(.gcc_exc)
0x00401c10 PROVIDE (etext, .)
*(.gcc_except_table)
 
.data 0x00402000 0x200
0x00402000 __data_start__ = .
*(.data)
.data 0x00402000 0x1e0 mkinit.o
0x00402000 writer
0x00402040 init
0x00402160 event
0x00402100 shellproc
0x00402060 reset
*(.data2)
*(SORT(.data$*))
*(.jcr)
0x004021e0 __data_end__ = .
*(.data_cygwin_nocopy)
 
.rdata 0x00403000 0x400
*(.rdata)
.rdata 0x00403000 0x220 mkinit.o
*(SORT(.rdata$*))
*(.eh_frame)
0x00403220 ___RUNTIME_PSEUDO_RELOC_LIST__ = .
0x00403220 __RUNTIME_PSEUDO_RELOC_LIST__ = .
*(.rdata_runtime_pseudo_reloc)
0x00403220 ___RUNTIME_PSEUDO_RELOC_LIST_END__ = .
0x00403220 __RUNTIME_PSEUDO_RELOC_LIST_END__ = .
 
.pdata
*(.pdata)
 
.bss 0x00404000 0x370
0x00404000 __bss_start__ = .
*(.bss)
.bss 0x00404000 0x0 mkinit.o
*(COMMON)
COMMON 0x00404000 0x370 mkinit.o
0x00404000 header_files
0x00404320 curfile
0x00404330 amiddecls
0x00404340 decls
0x00404350 linno
0x00404360 defines
0x00404370 __bss_end__ = .
 
.edata
*(.edata)
 
/DISCARD/
*(.debug$S)
*(.debug$T)
*(.debug$F)
*(.drectve)
 
.idata 0x00405000 0x200
SORT(*)(.idata$2)
SORT(*)(.idata$3)
0x00405000 0x4 LONG 0x0
0x00405004 0x4 LONG 0x0
0x00405008 0x4 LONG 0x0
0x0040500c 0x4 LONG 0x0
0x00405010 0x4 LONG 0x0
SORT(*)(.idata$4)
SORT(*)(.idata$5)
SORT(*)(.idata$6)
SORT(*)(.idata$7)
 
.CRT 0x00406000 0x0
0x00406000 ___crt_xc_start__ = .
*(SORT(.CRT$XC*))
0x00406000 ___crt_xc_end__ = .
0x00406000 ___crt_xi_start__ = .
*(SORT(.CRT$XI*))
0x00406000 ___crt_xi_end__ = .
0x00406000 ___crt_xl_start__ = .
*(SORT(.CRT$XL*))
0x00406000 ___crt_xp_start__ = .
*(SORT(.CRT$XP*))
0x00406000 ___crt_xp_end__ = .
0x00406000 ___crt_xt_start__ = .
*(SORT(.CRT$XT*))
0x00406000 ___crt_xt_end__ = .
 
.tls 0x00406000 0x0
0x00406000 ___tls_start__ = .
*(.tls)
*(.tls$)
*(SORT(.tls$*))
0x00406000 ___tls_end__ = .
 
.endjunk 0x00406000 0x0
0x00406000 PROVIDE (end, .)
0x00406000 PROVIDE (_end, .)
0x00406000 __end__ = .
 
.rsrc
*(.rsrc)
*(SORT(.rsrc$*))
 
.reloc
*(.reloc)
 
.stab
*(.stab)
 
.stabstr
*(.stabstr)
 
.debug_aranges
*(.debug_aranges)
 
.debug_pubnames
*(.debug_pubnames)
 
.debug_info
*(.debug_info)
*(.gnu.linkonce.wi.*)
 
.debug_abbrev
*(.debug_abbrev)
 
.debug_line
*(.debug_line)
 
.debug_frame
*(.debug_frame)
 
.debug_str
*(.debug_str)
 
.debug_loc
*(.debug_loc)
 
.debug_macinfo
*(.debug_macinfo)
 
.debug_weaknames
*(.debug_weaknames)
 
.debug_funcnames
*(.debug_funcnames)
 
.debug_typenames
*(.debug_typenames)
 
.debug_varnames
*(.debug_varnames)
 
.debug_ranges
*(.debug_ranges)
OUTPUT(mkinit pei-i386)
/trunk/uspace/app/ash/tools/mkinit.c
0,0 → 1,525
/* $NetBSD: mkinit.c,v 1.20 2000/07/18 19:13:20 cgd 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
 
 
#ifndef lint
static const char copyright[] =
"@(#) Copyright (c) 1991, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
 
#ifndef lint
#if 0
static char sccsid[] = "@(#)mkinit.c 8.2 (Berkeley) 5/4/95";
#else
static const char rcsid[] =
"$NetBSD: mkinit.c,v 1.20 2000/07/18 19:13:20 cgd Exp $";
#endif
#endif /* not lint */
 
/*
* This program scans all the source files for code to handle various
* special events and combines this code into one file. This (allegedly)
* improves the structure of the program since there is no need for
* anyone outside of a module to know that that module performs special
* operations on particular events.
*
* Usage: mkinit sourcefile...
*/
 
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
 
 
/*
* OUTFILE is the name of the output file. Output is initially written
* to the file OUTTEMP, which is then moved to OUTFILE.
*/
 
#define OUTFILE "init.c"
#define OUTTEMP "init.c.new"
 
 
/*
* A text structure is basicly just a string that grows as more characters
* are added onto the end of it. It is implemented as a linked list of
* blocks of characters. The routines addstr and addchar append a string
* or a single character, respectively, to a text structure. Writetext
* writes the contents of a text structure to a file.
*/
 
#define BLOCKSIZE 512
 
struct text {
char *nextc;
int nleft;
struct block *start;
struct block *last;
};
 
struct block {
struct block *next;
char text[BLOCKSIZE];
};
 
 
/*
* There is one event structure for each event that mkinit handles.
*/
 
struct event {
char *name; /* name of event (e.g. INIT) */
char *routine; /* name of routine called on event */
char *comment; /* comment describing routine */
struct text code; /* code for handling event */
};
 
 
char writer[] = "\
/*\n\
* This file was generated by the mkinit program.\n\
*/\n\
\n";
 
char init[] = "\
/*\n\
* Initialization code.\n\
*/\n";
 
char reset[] = "\
/*\n\
* This routine is called when an error or an interrupt occurs in an\n\
* interactive shell and control is returned to the main command loop.\n\
*/\n";
 
char shellproc[] = "\
/*\n\
* This routine is called to initialize the shell to run a shell procedure.\n\
*/\n";
 
 
struct event event[] = {
{"INIT", "init", init},
{"RESET", "reset", reset},
{"SHELLPROC", "initshellproc", shellproc},
{NULL, NULL}
};
 
 
char *curfile; /* current file */
int linno; /* current line */
char *header_files[200]; /* list of header files */
struct text defines; /* #define statements */
struct text decls; /* declarations */
int amiddecls; /* for formatting */
 
 
void readfile(char *);
int match(char *, char *);
int gooddefine(char *);
void doevent(struct event *, FILE *, char *);
void doinclude(char *);
void dodecl(char *, FILE *);
void output(void);
void addstr(char *, struct text *);
void addchar(int, struct text *);
void writetext(struct text *, FILE *);
FILE *ckfopen(char *, char *);
void *ckmalloc(int);
char *savestr(char *);
void error(char *);
int main(int, char **);
 
#define equal(s1, s2) (strcmp(s1, s2) == 0)
 
int
main(argc, argv)
int argc;
char **argv;
{
char **ap;
 
header_files[0] = "\"shell.h\"";
header_files[1] = "\"mystring.h\"";
header_files[2] = "\"init.h\"";
for (ap = argv + 1 ; *ap ; ap++)
readfile(*ap);
output();
rename(OUTTEMP, OUTFILE);
exit(0);
/* NOTREACHED */
}
 
 
/*
* Parse an input file.
*/
 
void
readfile(fname)
char *fname;
{
FILE *fp;
char line[1024];
struct event *ep;
 
fp = ckfopen(fname, "r");
curfile = fname;
linno = 0;
amiddecls = 0;
while (fgets(line, sizeof line, fp) != NULL) {
linno++;
for (ep = event ; ep->name ; ep++) {
if (line[0] == ep->name[0] && match(ep->name, line)) {
doevent(ep, fp, fname);
break;
}
}
if (line[0] == 'I' && match("INCLUDE", line))
doinclude(line);
if (line[0] == 'M' && match("MKINIT", line))
dodecl(line, fp);
if (line[0] == '#' && gooddefine(line))
addstr(line, &defines);
if (line[0] == '#' && gooddefine(line)) {
char *cp;
char line2[1024];
static const char undef[] = "#undef ";
 
strcpy(line2, line);
memcpy(line2, undef, sizeof(undef) - 1);
cp = line2 + sizeof(undef) - 1;
while(*cp && (*cp == ' ' || *cp == '\t'))
cp++;
while(*cp && *cp != ' ' && *cp != '\t' && *cp != '\n')
cp++;
*cp++ = '\n'; *cp = '\0';
addstr(line2, &defines);
addstr(line, &defines);
}
}
fclose(fp);
}
 
 
int
match(name, line)
char *name;
char *line;
{
char *p, *q;
 
p = name, q = line;
while (*p) {
if (*p++ != *q++)
return 0;
}
if (*q != '{' && *q != ' ' && *q != '\t' && *q != '\n')
return 0;
return 1;
}
 
 
int
gooddefine(line)
char *line;
{
char *p;
 
if (! match("#define", line))
return 0; /* not a define */
p = line + 7;
while (*p == ' ' || *p == '\t')
p++;
while (*p != ' ' && *p != '\t') {
if (*p == '(')
return 0; /* macro definition */
p++;
}
while (*p != '\n' && *p != '\0')
p++;
if (p[-1] == '\\')
return 0; /* multi-line definition */
return 1;
}
 
 
void
doevent(ep, fp, fname)
struct event *ep;
FILE *fp;
char *fname;
{
char line[1024];
int indent;
char *p;
 
sprintf(line, "\n /* from %s: */\n", fname);
addstr(line, &ep->code);
addstr(" {\n", &ep->code);
for (;;) {
linno++;
if (fgets(line, sizeof line, fp) == NULL)
error("Unexpected EOF");
if (equal(line, "}\n"))
break;
indent = 6;
for (p = line ; *p == '\t' ; p++)
indent += 8;
for ( ; *p == ' ' ; p++)
indent++;
if (*p == '\n' || *p == '#')
indent = 0;
while (indent >= 8) {
addchar('\t', &ep->code);
indent -= 8;
}
while (indent > 0) {
addchar(' ', &ep->code);
indent--;
}
addstr(p, &ep->code);
}
addstr(" }\n", &ep->code);
}
 
 
void
doinclude(line)
char *line;
{
char *p;
char *name;
char **pp;
 
for (p = line ; *p != '"' && *p != '<' && *p != '\0' ; p++);
if (*p == '\0')
error("Expecting '\"' or '<'");
name = p;
while (*p != ' ' && *p != '\t' && *p != '\n')
p++;
if (p[-1] != '"' && p[-1] != '>')
error("Missing terminator");
*p = '\0';
 
/* name now contains the name of the include file */
for (pp = header_files ; *pp && ! equal(*pp, name) ; pp++);
if (*pp == NULL)
*pp = savestr(name);
}
 
 
void
dodecl(line1, fp)
char *line1;
FILE *fp;
{
char line[1024];
char *p, *q;
 
if (strcmp(line1, "MKINIT\n") == 0) { /* start of struct/union decl */
addchar('\n', &decls);
do {
linno++;
if (fgets(line, sizeof line, fp) == NULL)
error("Unterminated structure declaration");
addstr(line, &decls);
} while (line[0] != '}');
amiddecls = 0;
} else {
if (! amiddecls)
addchar('\n', &decls);
q = NULL;
for (p = line1 + 6 ; *p && strchr("=/\n", *p) == NULL; p++)
continue;
if (*p == '=') { /* eliminate initialization */
for (q = p ; *q && *q != ';' ; q++);
if (*q == '\0')
q = NULL;
else {
while (p[-1] == ' ')
p--;
*p = '\0';
}
}
addstr("extern", &decls);
addstr(line1 + 6, &decls);
if (q != NULL)
addstr(q, &decls);
amiddecls = 1;
}
}
 
 
 
/*
* Write the output to the file OUTTEMP.
*/
 
void
output() {
FILE *fp;
char **pp;
struct event *ep;
 
fp = ckfopen(OUTTEMP, "w");
fputs(writer, fp);
for (pp = header_files ; *pp ; pp++)
fprintf(fp, "#include %s\n", *pp);
fputs("\n\n\n", fp);
writetext(&defines, fp);
fputs("\n\n", fp);
writetext(&decls, fp);
for (ep = event ; ep->name ; ep++) {
fputs("\n\n\n", fp);
fputs(ep->comment, fp);
fprintf(fp, "\nvoid\n%s() {\n", ep->routine);
writetext(&ep->code, fp);
fprintf(fp, "}\n");
}
fclose(fp);
}
 
 
/*
* A text structure is simply a block of text that is kept in memory.
* Addstr appends a string to the text struct, and addchar appends a single
* character.
*/
 
void
addstr(s, text)
char *s;
struct text *text;
{
while (*s) {
if (--text->nleft < 0)
addchar(*s++, text);
else
*text->nextc++ = *s++;
}
}
 
 
void
addchar(c, text)
int c;
struct text *text;
{
struct block *bp;
 
if (--text->nleft < 0) {
bp = ckmalloc(sizeof *bp);
if (text->start == NULL)
text->start = bp;
else
text->last->next = bp;
text->last = bp;
text->nextc = bp->text;
text->nleft = BLOCKSIZE - 1;
}
*text->nextc++ = c;
}
 
/*
* Write the contents of a text structure to a file.
*/
void
writetext(text, fp)
struct text *text;
FILE *fp;
{
struct block *bp;
 
if (text->start != NULL) {
for (bp = text->start ; bp != text->last ; bp = bp->next)
fwrite(bp->text, sizeof (char), BLOCKSIZE, fp);
fwrite(bp->text, sizeof (char), BLOCKSIZE - text->nleft, fp);
}
}
 
FILE *
ckfopen(file, mode)
char *file;
char *mode;
{
FILE *fp;
 
if ((fp = fopen(file, mode)) == NULL) {
fprintf(stderr, "Can't open %s\n", file);
exit(2);
}
return fp;
}
 
void *
ckmalloc(nbytes)
int nbytes;
{
char *p;
 
if ((p = malloc(nbytes)) == NULL)
error("Out of space");
return p;
}
 
char *
savestr(s)
char *s;
{
char *p;
 
p = ckmalloc(strlen(s) + 1);
strcpy(p, s);
return p;
}
 
void
error(msg)
char *msg;
{
if (curfile != NULL)
fprintf(stderr, "%s:%d: ", curfile, linno);
fprintf(stderr, "%s\n", msg);
exit(2);
/* NOTREACHED */
}
/trunk/uspace/app/ash/tools/Makefile
0,0 → 1,60
#
# Copyright (c) 2005 Martin Decky
# 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 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.
# - 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.
#
 
SOURCES = \
mkinit.c \
mknodes.c \
mksyntax.c \
mksignames.c
 
OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
OUTPUT := $(basename $(SOURCES))
 
.PHONY: all clean move-output
 
all: $(OUTPUT) move-output
 
#$(OUTPUT): $(OBJECTS)
# $(LD) $< $(LFLAGS) -o $@
 
move-output:
mv $(OUTPUT) ../
 
clean:
-rm -f $(OUTPUT) $(OBJECTS)
( cd ..; rm -f $(OUTPUT); )
 
%.o: %.S
$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@
 
%.o: %.s
$(AS) $(AFLAGS) $< -o $@
 
%.o: %.c
$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
 
/trunk/uspace/app/ash/sh.1
0,0 → 1,1614
.\" $NetBSD: sh.1,v 1.40 2000/11/20 17:48:05 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. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by the University of
.\" California, Berkeley and its contributors.
.\" 4. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" @(#)sh.1 8.6 (Berkeley) 5/4/95
.\"
.Dd January 9, 1999
.Os
.Dt SH 1
.Sh NAME
sh \- command interpreter (shell)
.Sh SYNOPSIS
.Nm sh
.Op Fl /+aCefnuvxIimqsVEbc
.Op Fl o Ar longname
.Bk -words
.Op Ar target ...
.Ek
.Sh DESCRIPTION
Sh is the standard command interpreter for the system. The current version
of
.Nm
is in the process of being changed to conform with the
.Tn POSIX
1003.2 and 1003.2a specifications for the shell. This version has many
features which make it appear similar in some respects to the Korn shell,
but it is not a Korn shell clone (see
.Xr ksh 1 ) .
Only features designated by
.Tn POSIX ,
plus a few Berkeley extensions, are being incorporated into this shell.
We expect
.Tn POSIX
conformance by the time 4.4 BSD is released. This man page is not intended
to be a tutorial or a complete specification of the shell.
.Ss Overview
The shell is a command that reads lines from either a file or the
terminal, interprets them, and generally executes other commands. It is
the program that is running when a user logs into the system (although a
user can select a different shell with the
.Xr chsh 1
command). The shell implements a language that has flow control
constructs, a macro facility that provides a variety of features in
addition to data storage, along with built in history and line editing
capabilities. It incorporates many features to aid interactive use and
has the advantage that the interpretative language is common to both
interactive and non-interactive use (shell scripts). That is, commands
can be typed directly to the running shell or can be put into a file and
the file can be executed directly by the shell.
.Ss Invocation
If no args are present and if the standard input of the shell
is connected to a terminal (or if the
.Fl i
flag is set),
and the
.Fl c
option is not present, the shell is considered an interactive shell. An
interactive shell generally prompts before each command and handles
programming and command errors differently (as described below). When
first starting, the shell inspects argument 0, and if it begins with a
dash
.Sq - ,
the shell is also considered
a login shell. This is normally done automatically by the system
when the user first logs in. A login shell first reads commands
from the files
.Pa /etc/profile
and
.Pa .profile
if they exist.
If the environment variable
.Ev ENV
is set on entry to a shell, or is set in the
.Pa .profile
of a login shell, the shell next reads
commands from the file named in
.Ev ENV .
Therefore, a user should place commands that are to be executed only at
login time in the
.Pa .profile
file, and commands that are executed for every shell inside the
.Ev ENV
file. To set the
.Ev ENV
variable to some file, place the following line in your
.Pa .profile
of your home directory
.Pp
.Dl ENV=$HOME/.shinit; export ENV
.Pp
substituting for
.Dq .shinit
any filename you wish. Since the
.Ev ENV
file is read for every invocation of the shell, including shell scripts
and non-interactive shells, the following paradigm is useful for
restricting commands in the
.Ev ENV
file to interactive invocations. Place commands within the
.Dq case
and
.Dq esac
below (these commands are described later):
.Pp
.Bl -item -compact -offset indent
.It
.Li case $- in *i*)
.Bl -item -compact -offset indent
.It
.Li # commands for interactive use only
.It
.Li ...
.El
.It
.Li esac
.El
.Pp
If command line arguments besides the options have been specified, then
the shell treats the first argument as the name of a file from which to
read commands (a shell script), and the remaining arguments are set as the
positional parameters of the shell ($1, $2, etc). Otherwise, the shell
reads commands from its standard input.
.Ss Argument List Processing
All of the single letter options have a corresponding name that can be
used as an argument to the
.Fl o
option. The set
.Fl o
name is provided next to the single letter option in
the description below. Specifying a dash
.Dq -
turns the option on, while using a plus
.Dq +
disables the option.
The following options can be set from the command line or
with the
.Xr set 1
builtin (described later).
.Bl -tag -width aaaallexportfoo -offset indent
.It Fl a Em allexport
Export all variables assigned to. (UNIMPLEMENTED for 4.4alpha)
.It Fl c
Read commands from the command line.
No commands will be read from the standard input.
.It Fl C Em noclobber
Don't overwrite existing files with
.Dq > .
(UNIMPLEMENTED for 4.4alpha)
.It Fl e Em errexit
If not interactive, exit immediately if any untested command fails.
The exit status of a command is considered to be
explicitly tested if the command is used to control
an
.Ic if ,
.Ic elif ,
.Ic while ,
or
.Ic until ;
or if the command is the left hand operand of an
.Dq &&
or
.Dq ||
operator.
.It Fl f Em noglob
Disable pathname expansion.
.It Fl n Em noexec
If not interactive, read commands but do not execute them. This is useful
for checking the syntax of shell scripts.
.It Fl u Em nounset
Write a message to standard error when attempting to expand a variable
that is not set, and if the shell is not interactive, exit immediately.
(UNIMPLEMENTED for 4.4alpha)
.It Fl v Em verbose
The shell writes its input to standard error as it is read. Useful for
debugging.
.It Fl x Em xtrace
Write each command to standard error (preceded
by a
.Sq +\ )
before it is executed. Useful for debugging.
.It Fl q Em quietprofile
If the
.Fl v
or
.Fl x
options have been set, do not apply them when reading
initialization files, these being
.Pa /etc/profile ,
.Pa .profile ,
and the file specified by the
.Ev ENV
environment variable.
.It Fl I Em ignoreeof
Ignore EOF's from input when interactive.
.It Fl i Em interactive
Force the shell to behave interactively.
.It Fl m Em monitor
Turn on job control (set automatically when interactive).
.It Fl s Em stdin
Read commands from standard input (set automatically if no file arguments
are present). This option has no effect when set after the shell has
already started running (i.e. with
.Xr set 1 ) .
.It Fl V Em vi
Enable the built-in
.Xr vi 1
command line editor (disables
.Fl E
if it has been set).
.It Fl E Em emacs
Enable the built-in
.Xr emacs 1
command line editor (disables
.Fl V
if it has been set).
.It Fl b Em notify
Enable asynchronous notification of background job completion.
(UNIMPLEMENTED for 4.4alpha)
.El
.Ss Lexical Structure
The shell reads input in terms of lines from a file and breaks it up into
words at whitespace (blanks and tabs), and at certain sequences of
characters that are special to the shell called
.Dq operators .
There are two types of operators: control operators and redirection
operators (their meaning is discussed later). Following is a list of operators:
.Bl -ohang -offset indent
.It "Control operators:"
.Dl & && ( ) ; ;; | || <newline>
.It "Redirection operator:"
.Dl < > >| << >> <& >& <<- <>
.El
.Ss Quoting
Quoting is used to remove the special meaning of certain characters or
words to the shell, such as operators, whitespace, or keywords. There are
three types of quoting: matched single quotes, matched double quotes, and
backslash.
.Ss Backslash
A backslash preserves the literal meaning of the following
character, with the exception of
.Aq newline .
A backslash preceding a
.Aq newline
is treated as a line continuation.
.Ss Single Quotes
Enclosing characters in single quotes preserves the literal meaning of all
the characters (except single quotes, making it impossible to put
single-quotes in a single-quoted string).
.Ss Double Quotes
Enclosing characters within double quotes preserves the literal
meaning of all characters except dollarsign
.Pq $ ,
backquote
.Pq ` ,
and backslash
.Pq \e .
The backslash inside double quotes is historically weird, and serves to
quote only the following characters:
.Dl $ ` \*q \e <newline> .
Otherwise it remains literal.
.Ss Reserved Words
Reserved words are words that have special meaning to the
shell and are recognized at the beginning of a line and
after a control operator. The following are reserved words:
.Bl -column while while while while while -offset indent
.It ! Ta elif Ta fi Ta while Ta case
.It else Ta for Ta then Ta { Ta }
.It do Ta done Ta until Ta if Ta esac
.El
.Pp
Their meaning is discussed later.
.Ss Aliases
An alias is a name and corresponding value set using the
.Xr alias 1
builtin command. Whenever a reserved word may occur (see above),
and after checking for reserved words, the shell
checks the word to see if it matches an alias. If it does,
it replaces it in the input stream with its value. For example,
if there is an alias called
.Dq lf
with the value
.Dq "ls -F" ,
then the input:
.Pp
.Dl lf foobar <return>
.Pp
would become
.Pp
.Dl ls -F foobar <return>
.Pp
Aliases provide a convenient way for naive users to create shorthands for
commands without having to learn how to create functions with arguments.
They can also be used to create lexically obscure code. This use is
discouraged.
.Ss Commands
The shell interprets the words it reads according to a language, the
specification of which is outside the scope of this man page (refer to the
BNF in the
.Tn POSIX
1003.2 document). Essentially though, a line is read and if the first
word of the line (or after a control operator) is not a reserved word,
then the shell has recognized a simple command. Otherwise, a complex
command or some other special construct may have been recognized.
.Ss Simple Commands
If a simple command has been recognized, the shell performs
the following actions:
.Bl -enum -offset indent
.It
Leading words of the form
.Dq name=value
are stripped off and assigned to the environment of the simple command.
Redirection operators and their arguments (as described below) are
stripped off and saved for processing.
.It
The remaining words are expanded as described in
the section called
.Dq Expansions ,
and the first remaining word is considered the command name and the
command is located. The remaining words are considered the arguments of
the command. If no command name resulted, then the
.Dq name=value
variable assignments recognized in item 1 affect the current shell.
.It
Redirections are performed as described in the next section.
.El
.Ss Redirections
Redirections are used to change where a command reads its input or sends
its output. In general, redirections open, close, or duplicate an
existing reference to a file. The overall format used for redirection is:
.Pp
.Dl [n] Va redir-op Ar file
.Pp
where
.Va redir-op
is one of the redirection operators mentioned previously. Following is a
list of the possible redirections. The
.Bq n
is an optional number, as in
.Sq 3
(not
.Sq Bq 3 ,
that refers to a file descriptor.
.Bl -tag -width aaabsfiles -offset indent
.It [n] Ns > file
Redirect standard output (or n) to file.
.It [n] Ns >| file
Same, but override the
.Fl C
option.
.It [n] Ns >> file
Append standard output (or n) to file.
.It [n] Ns < file
Redirect standard input (or n) from file.
.It [n1] Ns <& Ns n2
Duplicate standard input (or n1) from file descriptor n2.
.It [n] Ns <&-
Close standard input (or n).
.It [n1] Ns >& Ns n2
Duplicate standard output (or n1) from n2.
.It [n] Ns >&-
Close standard output (or n).
.It [n] Ns <> file
Open file for reading and writing on standard input (or n).
.El
.Pp
The following redirection is often called a
.Dq here-document .
.Bl -item -offset indent
.It
.Li [n]<< delimiter
.Dl here-doc-text...
.Li delimiter
.El
.Pp
All the text on successive lines up to the delimiter is saved away and
made available to the command on standard input, or file descriptor n if
it is specified. If the delimiter as specified on the initial line is
quoted, then the here-doc-text is treated literally, otherwise the text is
subjected to parameter expansion, command substitution, and arithmetic
expansion (as described in the section on
.Dq Expansions ) .
If the operator is
.Dq <<-
instead of
.Dq << ,
then leading tabs in the here-doc-text are stripped.
.Ss Search and Execution
There are three types of commands: shell functions, builtin commands, and
normal programs -- and the command is searched for (by name) in that
order. They each are executed in a different way.
.Pp
When a shell function is executed, all of the shell positional parameters
(except $0, which remains unchanged) are set to the arguments of the shell
function. The variables which are explicitly placed in the environment of
the command (by placing assignments to them before the function name) are
made local to the function and are set to the values given. Then the
command given in the function definition is executed. The positional
parameters are restored to their original values when the command
completes. This all occurs within the current shell.
.Pp
Shell builtins are executed internally to the shell, without spawning a
new process.
.Pp
Otherwise, if the command name doesn't match a function or builtin, the
command is searched for as a normal program in the filesystem (as
described in the next section). When a normal program is executed, the
shell runs the program, passing the arguments and the environment to the
program. If the program is not a normal executable file (i.e., if it does
not begin with the "magic number" whose
.Tn ASCII
representation is "#!", so
.Xr execve 2
returns
.Er ENOEXEC
then) the shell will interpret the program in a subshell. The child shell
will reinitialize itself in this case, so that the effect will be as if a
new shell had been invoked to handle the ad-hoc shell script, except that
the location of hashed commands located in the parent shell will be
remembered by the child.
.Pp
Note that previous versions of this document and the source code itself
misleadingly and sporadically refer to a shell script without a magic
number as a "shell procedure".
.Ss Path Search
.Pp
When locating a command, the shell first looks to see if it has a shell
function by that name. Then it looks for a builtin command by that name.
If a builtin command is not found, one of two things happen:
.Bl -enum
.It
Command names containing a slash are simply executed without performing
any searches.
.It
The shell searches each entry in
.Ev PATH
in turn for the command. The value of the
.Ev PATH
variable should be a series of entries separated by colons. Each entry
consists of a directory name. The current directory may be indicated
implicitly by an empty directory name, or explicitly by a single period.
.El
.Ss Command Exit Status
Each command has an exit status that can influence the behavior
of other shell commands. The paradigm is that a command exits
with zero for normal or success, and non-zero for failure,
error, or a false indication. The man page for each command
should indicate the various exit codes and what they mean.
Additionally, the builtin commands return exit codes, as does
an executed shell function.
.Ss Complex Commands
Complex commands are combinations of simple commands with control
operators or reserved words, together creating a larger complex command.
More generally, a command is one of the following:
.Bl -bullet
.It
simple command
.It
pipeline
.It
list or compound-list
.It
compound command
.It
function definition
.El
.Pp
Unless otherwise stated, the exit status of a command is that of the last
simple command executed by the command.
.Ss Pipelines
.Pp
A pipeline is a sequence of one or more commands separated
by the control operator |. The standard output of all but
the last command is connected to the standard input
of the next command. The standard output of the last
command is inherited from the shell, as usual.
.Pp
The format for a pipeline is:
.Pp
.Dl [!] command1 [ | command2 ...]
.Pp
The standard output of command1 is connected to the standard input of
command2. The standard input, standard output, or both of a command is
considered to be assigned by the pipeline before any redirection specified
by redirection operators that are part of the command.
.Pp
If the pipeline is not in the background (discussed later), the shell
waits for all commands to complete.
.Pp
If the reserved word ! does not precede the pipeline, the exit status is
the exit status of the last command specified in the pipeline.
Otherwise, the exit status is the logical NOT of the exit status of the
last command. That is, if the last command returns zero, the exit status
is 1; if the last command returns greater than zero, the exit status is
zero.
.Pp
Because pipeline assignment of standard input or standard output or both
takes place before redirection, it can be modified by redirection. For
example:
.Pp
.Dl $ command1 2>&1 | command2
.Pp
sends both the standard output and standard error of command1
to the standard input of command2.
.Pp
A ; or <newline> terminator causes the preceding AND-OR-list (described
next) to be executed sequentially; a & causes asynchronous execution of
the preceding AND-OR-list.
.Pp
Note that unlike some other shells, each process in the pipeline is a
child of the invoking shell (unless it is a shell builtin, in which case
it executes in the current shell -- but any effect it has on the
environment is wiped).
.Ss Background Commands -- &
If a command is terminated by the control operator ampersand (&), the
shell executes the command asynchronously -- that is, the shell does not
wait for the command to finish before executing the next command.
.Pp
The format for running a command in background is:
.Pp
.Dl command1 & [command2 & ...]
.Pp
If the shell is not interactive, the standard input of an asynchronous
command is set to
.Pa /dev/null .
.Ss Lists -- Generally Speaking
A list is a sequence of zero or more commands separated by newlines,
semicolons, or ampersands, and optionally terminated by one of these three
characters. The commands in a list are executed in the order they are
written. If command is followed by an ampersand, the shell starts the
command and immediately proceed onto the next command; otherwise it waits
for the command to terminate before proceeding to the next one.
.Ss Short-Circuit List Operators
.Dq &&
and
.Dq ||
are AND-OR list operators.
.Dq &&
executes the first command, and then executes the second command iff the
exit status of the first command is zero.
.Dq ||
is similar, but executes the second command iff the exit status of the first
command is nonzero.
.Dq &&
and
.Dq ||
both have the same priority.
.Ss Flow-Control Constructs -- if, while, for, case
The syntax of the if command is
.Bd -literal -offset indent
if list
then list
[ elif list
then list ] ...
[ else list ]
fi
.Ed
.Pp
The syntax of the while command is
.Bd -literal -offset indent
while list
do list
done
.Ed
.Pp
The two lists are executed repeatedly while the exit status of the
first list is zero. The until command is similar, but has the word
until in place of while, which causes it to
repeat until the exit status of the first list is zero.
.Pp
The syntax of the for command is
.Bd -literal -offset indent
for variable in word...
do list
done
.Ed
.Pp
The words are expanded, and then the list is executed repeatedly with the
variable set to each word in turn. do and done may be replaced with
.Dq {
and
.Dq } .
.Pp
The syntax of the break and continue command is
.Bd -literal -offset indent
break [ num ]
continue [ num ]
.Ed
.Pp
Break terminates the num innermost for or while loops.
Continue continues with the next iteration of the innermost loop.
These are implemented as builtin commands.
.Pp
The syntax of the case command is
.Bd -literal -offset indent
case word in
pattern) list ;;
\&...
esac
.Ed
.Pp
The pattern can actually be one or more patterns (see Shell
Patterns described later), separated by
.Dq \*(Ba
characters.
.Ss Grouping Commands Together
Commands may be grouped by writing either
.Pp
.Dl (list)
.Pp
or
.Pp
.Dl { list; }
.Pp
The first of these executes the commands in a subshell. Builtin commands
grouped into a (list) will not affect the current shell. The second form
does not fork another shell so is slightly more efficient. Grouping
commands together this way allows you to redirect their output as though
they were one program:
.Pp
.Bd -literal -offset indent
{ echo \*q hello \\c\*q ; echo \*q world" } > greeting
.Ed
.Pp
.Ss Functions
The syntax of a function definition is
.Pp
.Dl name ( ) command
.Pp
A function definition is an executable statement; when executed it
installs a function named name and returns an exit status of zero. The
command is normally a list enclosed between
.Dq {
and
.Dq } .
.Pp
Variables may be declared to be local to a function by using a local
command. This should appear as the first statement of a function, and the
syntax is
.Pp
.Dl local [ variable | - ] ...
.Pp
Local is implemented as a builtin command.
.Pp
When a variable is made local, it inherits the initial value and exported
and readonly flags from the variable with the same name in the surrounding
scope, if there is one. Otherwise, the variable is initially unset. The
shell uses dynamic scoping, so that if you make the variable x local to
function f, which then calls function g, references to the variable x made
inside g will refer to the variable x declared inside f, not to the global
variable named x.
.Pp
The only special parameter than can be made local is
.Dq - .
Making
.Dq -
local any shell options that are changed via the set command inside the
function to be restored to their original values when the function
returns.
.Pp
The syntax of the return command is
.Pp
.Dl return [ exitstatus ]
.Pp
It terminates the currently executing function. Return is
implemented as a builtin command.
.Ss Variables and Parameters
The shell maintains a set of parameters. A parameter denoted by a name is
called a variable. When starting up, the shell turns all the environment
variables into shell variables. New variables can be set using the form
.Pp
.Dl name=value
.Pp
Variables set by the user must have a name consisting solely of
alphabetics, numerics, and underscores - the first of which must not be
numeric. A parameter can also be denoted by a number or a special
character as explained below.
.Ss Positional Parameters
A positional parameter is a parameter denoted by a number (n > 0). The
shell sets these initially to the values of its command line arguments
that follow the name of the shell script. The
.Xr set 1
builtin can also be used to set or reset them.
.Ss Special Parameters
A special parameter is a parameter denoted by one of the following special
characters. The value of the parameter is listed next to its character.
.Bl -tag -width thinhyphena
.It *
Expands to the positional parameters, starting from one. When the
expansion occurs within a double-quoted string it expands to a single
field with the value of each parameter separated by the first character of
the
.Ev IFS
variable, or by a <space> if
.Ev IFS
is unset.
.It @
Expands to the positional parameters, starting from one. When
the expansion occurs within double-quotes, each positional
parameter expands as a separate argument.
If there are no positional parameters, the
expansion of @ generates zero arguments, even when @ is
double-quoted. What this basically means, for example, is
if $1 is
.Dq abc
and $2 is
.Dq def ghi ,
then
.Qq $@
expands to
the two arguments:
.Pp
.Sm off
.Dl \*q abc \*q \ \*q def\ ghi \*q
.Sm on
.It #
Expands to the number of positional parameters.
.It ?
Expands to the exit status of the most recent pipeline.
.It - (Hyphen.)
Expands to the current option flags (the single-letter
option names concatenated into a string) as specified on
invocation, by the set builtin command, or implicitly
by the shell.
.It $
Expands to the process ID of the invoked shell. A subshell
retains the same value of $ as its parent.
.It !
Expands to the process ID of the most recent background
command executed from the current shell. For a
pipeline, the process ID is that of the last command in the
pipeline.
.It 0 (Zero.)
Expands to the name of the shell or shell script.
.El
.Ss Word Expansions
This clause describes the various expansions that are performed on words.
Not all expansions are performed on every word, as explained later.
.Pp
Tilde expansions, parameter expansions, command substitutions, arithmetic
expansions, and quote removals that occur within a single word expand to a
single field. It is only field splitting or pathname expansion that can
create multiple fields from a single word. The single exception to this
rule is the expansion of the special parameter @ within double-quotes, as
was described above.
.Pp
The order of word expansion is:
.Bl -enum
.It
Tilde Expansion, Parameter Expansion, Command Substitution,
Arithmetic Expansion (these all occur at the same time).
.It
Field Splitting is performed on fields
generated by step (1) unless the
.Ev IFS
variable is null.
.It
Pathname Expansion (unless set
.Fl f
is in effect).
.It
Quote Removal.
.El
.Pp
The $ character is used to introduce parameter expansion, command
substitution, or arithmetic evaluation.
.Ss Tilde Expansion (substituting a user's home directory)
A word beginning with an unquoted tilde character (~) is
subjected to tilde expansion. All the characters up to
a slash (/) or the end of the word are treated as a username
and are replaced with the user's home directory. If the
username is missing (as in
.Pa ~/foobar ) ,
the tilde is replaced with the value of the
.Va HOME
variable (the current user's home directory).
.Ss Parameter Expansion
The format for parameter expansion is as follows:
.Pp
.Dl ${expression}
.Pp
where expression consists of all characters until the matching
.Dq } .
Any
.Dq }
escaped by a backslash or within a quoted string, and characters in
embedded arithmetic expansions, command substitutions, and variable
expansions, are not examined in determining the matching
.Dq } .
.Pp
The simplest form for parameter expansion is:
.Pp
.Dl ${parameter}
.Pp
The value, if any, of parameter is substituted.
.Pp
The parameter name or symbol can be enclosed in braces, which are
optional except for positional parameters with more than one digit or
when parameter is followed by a character that could be interpreted as
part of the name.
If a parameter expansion occurs inside
double-quotes:
.Bl -enum
.It
Pathname expansion is not performed on the results of the
expansion.
.It
Field splitting is not performed on the results of the
expansion, with the exception of @.
.El
.Pp
In addition, a parameter expansion can be modified by using one of the
following formats.
.Bl -tag -width aaparameterwordaaaaa
.It ${parameter:-word}
Use Default Values. If parameter is unset or null, the expansion of word
is substituted; otherwise, the value of parameter is substituted.
.It ${parameter:=word}
Assign Default Values. If parameter is unset or null, the expansion of
word is assigned to parameter. In all cases, the final value of parameter
is substituted. Only variables, not positional parameters or special
parameters, can be assigned in this way.
.It ${parameter:?[word]}
Indicate Error if Null or Unset. If parameter is unset or null, the
expansion of word (or a message indicating it is unset if word is omitted)
is written to standard error and the shell exits with a nonzero exit
status. Otherwise, the value of parameter is substituted. An interactive
shell need not exit.
.It ${parameter:+word}
Use Alternative Value. If parameter is unset or null, null is
substituted; otherwise, the expansion of word is substituted.
.El
.Pp
In the parameter expansions shown previously, use of the colon in the
format results in a test for a parameter that is unset or null; omission
of the colon results in a test for a parameter that is only unset.
.Bl -tag -width aaparameterwordaaaaa
.It ${#parameter}
String Length. The length in characters of
the value of parameter.
.El
.Pp
The following four varieties of parameter expansion provide for substring
processing. In each case, pattern matching notation (see Shell Patterns),
rather than regular expression notation, is used to evaluate the patterns.
If parameter is * or @, the result of the expansion is unspecified.
Enclosing the full parameter expansion string in double-quotes does not
cause the following four varieties of pattern characters to be quoted,
whereas quoting characters within the braces has this effect.
.Bl -tag -width aaparameterwordaaaaa
.It ${parameter%word}
Remove Smallest Suffix Pattern. The word is expanded to produce a
pattern. The parameter expansion then results in parameter, with the
smallest portion of the suffix matched by the pattern deleted.
.It ${parameter%%word}
Remove Largest Suffix Pattern. The word is expanded to produce a pattern.
The parameter expansion then results in parameter, with the largest
portion of the suffix matched by the pattern deleted.
.It ${parameter#word}
Remove Smallest Prefix Pattern. The word is expanded to produce a
pattern. The parameter expansion then results in parameter, with the
smallest portion of the prefix matched by the pattern deleted.
.It ${parameter##word}
Remove Largest Prefix Pattern. The word is expanded to produce a pattern.
The parameter expansion then results in parameter, with the largest
portion of the prefix matched by the pattern deleted.
.El
.Ss Command Substitution
Command substitution allows the output of a command to be substituted in
place of the command name itself. Command substitution occurs when
the command is enclosed as follows:
.Pp
.Dl $(command)
.Pp
or
.Po
.Dq backquoted
version
.Pc :
.Pp
.Dl `command`
.Pp
The shell expands the command substitution by executing command in a
subshell environment and replacing the command substitution with the
standard output of the command, removing sequences of one or more
<newline>s at the end of the substitution. (Embedded <newline>s before
the end of the output are not removed; however, during field splitting,
they may be translated into <space>s, depending on the value of
.Ev IFS
and quoting that is in effect.)
.Ss Arithmetic Expansion
.Pp
Arithmetic expansion provides a mechanism for evaluating an arithmetic
expression and substituting its value. The format for arithmetic
expansion is as follows:
.Pp
.Dl $((expression))
.Pp
The expression is treated as if it were in double-quotes, except
that a double-quote inside the expression is not treated specially. The
shell expands all tokens in the expression for parameter expansion,
command substitution, and quote removal.
.Pp
Next, the shell treats this as an arithmetic expression and
substitutes the value of the expression.
.Ss White Space Splitting (Field Splitting)
After parameter expansion, command substitution, and
arithmetic expansion the shell scans the results of
expansions and substitutions that did not occur in double-quotes for
field splitting and multiple fields can result.
.Pp
The shell treats each character of the
.Ev IFS
as a delimiter and use the delimiters to split the results of parameter
expansion and command substitution into fields.
.Ss Pathname Expansion (File Name Generation)
Unless the
.Fl f
flag is set, file name generation is performed after word splitting is
complete. Each word is viewed as a series of patterns, separated by
slashes. The process of expansion replaces the word with the names of all
existing files whose names can be formed by replacing each pattern with a
string that matches the specified pattern. There are two restrictions on
this: first, a pattern cannot match a string containing a slash, and
second, a pattern cannot match a string starting with a period unless the
first character of the pattern is a period. The next section describes the
patterns used for both Pathname Expansion and the
.Xr case 1
command.
.Ss Shell Patterns
A pattern consists of normal characters, which match themselves,
and meta-characters. The meta-characters are
.Dq ! ,
.Dq * ,
.Dq ? ,
and
.Dq [ .
These characters lose their special meanings if they are quoted. When
command or variable substitution is performed and the dollar sign or back
quotes are not double quoted, the value of the variable or the output of
the command is scanned for these characters and they are turned into
meta-characters.
.Pp
An asterisk
.Pq Dq *
matches any string of characters. A question mark matches any single
character. A left bracket
.Pq Dq \&[
introduces a character class. The end of
the character class is indicated by a
.Pq Dq \&] ;
if the
.Dq \&]
is missing then the
.Dq \&[
matches a
.Dq \&[
rather than introducing a character class. A character class matches any
of the characters between the square brackets. A range of characters may
be specified using a minus sign. The character class may be complemented
by making an exclamation point the first character of the character class.
.Pp
To include a
.Dq \&]
in a character class, make it the first character listed (after the
.Dq \&! ,
if any). To include a minus sign, make it the first or last character listed
.Ss Builtins
.Pp
This section lists the builtin commands which are builtin because they
need to perform some operation that can't be performed by a separate
process. In addition to these, there are several other commands that may
be builtin for efficiency (e.g.
.Xr printf 1 ,
.Xr echo 1 ,
.Xr test 1 ,
etc).
.Bl -tag -width 5n
.It :
A null command that returns a 0 (true) exit value.
.It \&. file
The commands in the specified file are read and executed by the shell.
.It alias Op Ar name Ns Op Ar "=string ..."
If
.Ar name=string
is specified, the shell defines the alias
.Ar name
with value
.Ar string .
If just
.Ar name
is specified, the value of the alias
.Ar name
is printed. With no arguments, the
.Ic alias
builtin prints the
names and values of all defined aliases (see
.Ic unalias ) .
.It bg [ Ar job ] ...
Continue the specified jobs (or the current job if no
jobs are given) in the background.
.It command Ar command Ar arg...
Execute the specified builtin command. (This is useful when you
have a shell function with the same name as a builtin command.)
.It cd Op Ar directory
Switch to the specified directory (default
.Ev $HOME ) .
If an entry for
.Ev CDPATH
appears in the environment of the
.Ic cd
command or the shell variable
.Ev CDPATH
is set and the directory name does not begin with a slash, then the
directories listed in
.Ev CDPATH
will be searched for the specified directory. The format of
.Ev CDPATH
is the same as that of
.Ev PATH .
In an interactive shell, the
.Ic cd
command will print out the name of the
directory that it actually switched to if this is different from the name
that the user gave. These may be different either because the
.Ev CDPATH
mechanism was used or because a symbolic link was crossed.
.It eval Ar string...
Concatenate all the arguments with spaces. Then re-parse and execute
the command.
.It exec Op Ar command arg...
Unless command is omitted, the shell process is replaced with the
specified program (which must be a real program, not a shell builtin or
function). Any redirections on the
.Ic exec
command are marked as permanent, so that they are not undone when the
.Ic exec
command finishes.
.It exit Op Ar exitstatus
Terminate the shell process. If
.Ar exitstatus
is given it is used as the exit status of the shell; otherwise the
exit status of the preceding command is used.
.It export Ar name...
.It export Fl p
The specified names are exported so that they will appear in the
environment of subsequent commands. The only way to un-export a variable
is to unset it. The shell allows the value of a variable to be set at the
same time it is exported by writing
.Pp
.Dl export name=value
.Pp
With no arguments the export command lists the names of all exported variables.
With the
.Fl p
option specified the output will be formatted suitably for non-interactive use.
.It Xo fc Op Fl e Ar editor
.Op Ar first Op Ar last
.Xc
.It Xo fc Fl l
.Op Fl nr
.Op Ar first Op Ar last
.Xc
.It Xo fc Fl s Op Ar old=new
.Op Ar first
.Xc
The
.Ic fc
builtin lists, or edits and re-executes, commands previously entered
to an interactive shell.
.Bl -tag -width 5n
.It Fl e No editor
Use the editor named by editor to edit the commands. The
editor string is a command name, subject to search via the
.Ev PATH
variable. The value in the
.Ev FCEDIT
variable is used as a default when
.Fl e
is not specified. If
.Ev FCEDIT
is null or unset, the value of the
.Ev EDITOR
variable is used. If
.Ev EDITOR
is null or unset,
.Xr ed 1
is used as the editor.
.It Fl l No (ell)
List the commands rather than invoking an editor on them. The commands
are written in the sequence indicated by the first and last operands, as
affected by
.Fl r ,
with each command preceded by the command number.
.It Fl n
Suppress command numbers when listing with -l.
.It Fl r
Reverse the order of the commands listed (with
.Fl l )
or edited (with neither
.Fl l
nor
.Fl s ) .
.It Fl s
Re-execute the command without invoking an editor.
.It first
.It last
Select the commands to list or edit. The number of previous commands that
can be accessed are determined by the value of the
.Ev HISTSIZE
variable. The value of first or last or both are one of the following:
.Bl -tag -width 5n
.It [+]number
A positive number representing a command number; command numbers can be
displayed with the
.Fl l
option.
.It Fl number
A negative decimal number representing the command that was executed
number of commands previously. For example, -1 is the immediately
previous command.
.El
.It string
A string indicating the most recently entered command that begins with
that string. If the old=new operand is not also specified with
.Fl s ,
the string form of the first operand cannot contain an embedded equal sign.
.El
.Pp
The following environment variables affect the execution of fc:
.Bl -tag -width HISTSIZE
.It Ev FCEDIT
Name of the editor to use.
.It Ev HISTSIZE
The number of previous commands that are accessible.
.El
.It fg Op Ar job
Move the specified job or the current job to the foreground.
.It getopts Ar optstring var
The
.Tn POSIX
.Ic getopts
command, not to be confused with the
.Em Bell Labs
-derived
.Xr getopt 1 .
.Pp
The first argument should be a series of letters, each of which may be
optionally followed by a colon to indicate that the option requires an
argument. The variable specified is set to the parsed option.
.Pp
The
.Ic getopts
command deprecates the older
.Xr getopt 1
utility due to its handling of arguments containing whitespace.
.Pp
The
.Ic getopts
builtin may be used to obtain options and their arguments
from a list of parameters. When invoked,
.Ic getopts
places the value of the next option from the option string in the list in
the shell variable specified by
.Va var
and it's index in the shell variable
.Ev OPTIND .
When the shell is invoked,
.Ev OPTIND
is initialized to 1. For each option that requires an argument, the
.Ic getopts
builtin will place it in the shell variable
.Ev OPTARG .
If an option is not allowed for in the
.Va optstring ,
then
.Ev OPTARG
will be unset.
.Pp
.Va optstring
is a string of recognized option letters (see
.Xr getopt 3 ) .
If a letter is followed by a colon, the option is expected to have an
argument which may or may not be separated from it by white space. If an
option character is not found where expected,
.Ic getopts
will set the variable
.Va var
to a
.Dq ? ;
.Ic getopts
will then unset
.Ev OPTARG
and write output to standard error. By specifying a colon as the
first character of
.Va optstring
all errors will be ignored.
.Pp
A nonzero value is returned when the last option is reached.
If there are no remaining arguments,
.Ic getopts
will set
.Va var
to the special option,
.Dq -- ,
otherwise, it will set
.Va var
to
.Dq ? .
.Pp
The following code fragment shows how one might process the arguments
for a command that can take the options
.Op a
and
.Op b ,
and the option
.Op c ,
which requires an argument.
.Pp
.Bd -literal -offset indent
while getopts abc: f
do
case $f in
a | b) flag=$f;;
c) carg=$OPTARG;;
\\?) echo $USAGE; exit 1;;
esac
done
shift `expr $OPTIND - 1`
.Ed
.Pp
This code will accept any of the following as equivalent:
.Pp
.Bd -literal -offset indent
cmd \-acarg file file
cmd \-a \-c arg file file
cmd \-carg -a file file
cmd \-a \-carg \-\- file file
.Ed
.It hash Fl rv Ar command...
The shell maintains a hash table which remembers the
locations of commands. With no arguments whatsoever,
the
.Ic hash
command prints out the contents of this table. Entries which have not
been looked at since the last
.Ic cd
command are marked with an asterisk; it is possible for these entries
to be invalid.
.Pp
With arguments, the
.Ic hash
command removes the specified commands from the hash table (unless
they are functions) and then locates them. With the
.Fl v
option, hash prints the locations of the commands as it finds them. The
.Fl r
option causes the hash command to delete all the entries in the hash table
except for functions.
.It jobid Op Ar job
Print the process id's of the processes in the job.
If the
.Ar job
argument is omitted, the current job is used.
.It jobs
This command lists out all the background processes
which are children of the current shell process.
.It pwd
Print the current directory. The builtin command may
differ from the program of the same name because the
builtin command remembers what the current directory
is rather than recomputing it each time. This makes
it faster. However, if the current directory is
renamed, the builtin version of
.Ic pwd
will continue to print the old name for the directory.
.It Xo read Op Fl p Ar prompt
.Op Fl r
.Ar variable...
.Xc
The prompt is printed if the
.Fl p
option is specified and the standard input is a terminal. Then a line is
read from the standard input. The trailing newline is deleted from the
line and the line is split as described in the section on word splitting
above, and the pieces are assigned to the variables in order.
At least one variable must be specified.
If there are
more pieces than variables, the remaining pieces (along with the
characters in
.Ev IFS
that separated them) are assigned to the last variable. If there are more
variables than pieces, the remaining variables are assigned the null
string. The
.Ic read
builtin will indicate success unless EOF is encountered on input, in
which case failure is returned.
.Pp
By default, unless the
.Fl r
option is specified, the backslash
.Dq \e
acts as an escape character, causing the following character to be treated
literally. If a backslash is followed by a newline, the backslash and the
newline will be deleted.
.It readonly Ar name...
.It readonly Fl p
The specified names are marked as read only, so that they cannot be
subsequently modified or unset. The shell allows the value of a variable
to be set at the same time it is marked read only by writing
.Pp
.Dl readonly name=value
.Pp
With no arguments the readonly command lists the names of all read only
variables.
With the
.Fl p
option specified the output will be formatted suitably for non-interactive use.
.Pp
.It Xo set
.Oo {
.Fl options | Cm +options | Cm -- }
.Oc Ar arg...
.Xc
The
.Ic set
command performs three different functions.
.Pp
With no arguments, it lists the values of all shell
variables.
.Pp
If options are given, it sets the specified option
flags, or clears them as described in the section
called
.Sx Argument List Processing .
.Pp
The third use of the set command is to set the values of the shell's
positional parameters to the specified args. To change the positional
parameters without changing any options, use
.Dq --
as the first argument to set. If no args are present, the set command
will clear all the positional parameters (equivalent to executing
.Dq shift $# . )
.It setvar Ar variable Ar value
Assigns value to variable. (In general it is better to write
variable=value rather than using
.Ic setvar .
.Ic setvar
is intended to be used in
functions that assign values to variables whose names are passed as
parameters.)
.It shift Op Ar n
Shift the positional parameters n times. A
.Ic shift
sets the value of
.Va $1
to the value of
.Va $2 ,
the value of
.Va $2
to the value of
.Va $3 ,
and so on, decreasing
the value of
.Va $#
by one. If there are zero positional parameters,
.Ic shift
does nothing.
.It times
Print the accumulated user and system times for the shell and for processes
run from the shell. The return status is 0.
.It Xo trap
.Op Ar action
.Ar signal...
.Xc
Cause the shell to parse and execute action when any of the specified
signals are received. The signals are specified by signal number. If
.Ar signal
is
.Li 0 ,
the action is executed when the shell exits.
.Ar action
may be null or omitted; the former causes the specified signal to be
ignored and the latter causes the default action to be taken. When the
shell forks off a subshell, it resets trapped (but not ignored) signals to
the default action. The
.Ic trap
command has no effect on signals that were
ignored on entry to the shell.
.It type Op Ar name ...
Interpret each name as a command and print the resolution of the command
search. Possible resolutions are:
shell keyword, alias, shell builtin,
command, tracked alias and not found. For aliases the alias expansion is
printed; for commands and tracked aliases the complete pathname of the
command is printed.
.It ulimit Xo
.Op Fl H \*(Ba Fl S
.Op Fl a \*(Ba Fl tfdscmlpn Op Ar value
.Xc
Inquire about or set the hard or soft limits on processes or set new
limits. The choice between hard limit (which no process is allowed to
violate, and which may not be raised once it has been lowered) and soft
limit (which causes processes to be signaled but not necessarily killed,
and which may be raised) is made with these flags:
.Bl -tag -width Fl
.It Fl H
set or inquire about hard limits
.It Fl S
set or inquire about soft limits. If neither
.Fl H
nor
.Fl S
is specified, the soft limit is displayed or both limits are set. If both
are specified, the last one wins.
.El
.Pp
.Bl -tag -width Fl
The limit to be interrogated or set, then, is chosen by specifying
any one of these flags:
.It Fl a
show all the current limits
.It Fl t
show or set the limit on CPU time (in seconds)
.It Fl f
show or set the limit on the largest file that can be created
(in 512-byte blocks)
.It Fl d
show or set the limit on the data segment size of a process (in kilobytes)
.It Fl s
show or set the limit on the stack size of a process (in kilobytes)
.It Fl c
show or set the limit on the largest core dump size that can be produced
(in 512-byte blocks)
.It Fl m
show or set the limit on the total physical memory that can be
in use by a process (in kilobytes)
.It Fl l
show or set the limit on how much memory a process can lock with
.Xr mlock 2
(in kilobytes)
.It Fl p
show or set the limit on the number of processes this user can
have at one time
.It Fl n
show or set the limit on the number files a process can have open at once
.El
.Pp
If none of these is specified, it is the limit on file size that is shown
or set. If value is specified, the limit is set to that number; otherwise
the current limit is displayed.
.Pp
Limits of an arbitrary process can be displayed or set using the
.Xr sysctl 8
utility.
.Pp
.It umask Op Ar mask
Set the value of umask (see
.Xr umask 2 )
to the specified octal value. If the argument is omitted, the umask value
is printed.
.It unalias Xo
.Op Fl a
.Op Ar name
.Xc
If
.Ar name
is specified, the shell removes that alias. If
.Fl a
is specified, all aliases are removed.
.It unset Ar name...
The specified variables and functions are unset and unexported. If a given
name corresponds to both a variable and a function, both the variable and
the function are unset.
.It wait Op Ar job
Wait for the specified job to complete and return the exit status of the
last process in the job. If the argument is omitted, wait for all jobs to
complete and the return an exit status of zero.
.El
.Ss Command Line Editing
When
.Nm
is being used interactively from a terminal, the current command
and the command history (see
.Ic fc
in
.Sx Builtins )
can be edited using vi-mode command-line editing. This mode uses commands,
described below, similar to a subset of those described in the vi man
page. The command
.Ql set -o vi
enables vi-mode editing and place sh into vi insert mode. With vi-mode
enabled, sh can be switched between insert mode and command mode. The
editor is not described in full here, but will be in a later document.
It's similar to vi: typing
.Aq ESC
will throw you into command VI command mode. Hitting
.Aq return
while in command mode will pass the line to the shell.
.Sh ENVIRONMENT
.Bl -tag -width MAILCHECK
.It Ev HOME
Set automaticly by
.Xr login 1
from the user's login directory in the password file
.Pq Xr passwd 4 .
This environment variable also functions as the default argument for the
cd builtin.
.It Ev PATH
The default search path for executables. See the above section
.Sx Path Search .
.It Ev CDPATH
The search path used with the cd builtin.
.It Ev MAIL
The name of a mail file, that will be checked for the arrival of new mail.
Overridden by
.Ev MAILPATH .
.It Ev MAILCHECK
The frequency in seconds that the shell checks for the arrival of mail
in the files specified by the
.Ev MAILPATH
or the
.Ev MAIL
file. If set to 0, the check will occur at each prompt.
.It Ev MAILPATH
A colon
.Dq \&:
separated list of file names, for the shell to check for incoming mail.
This environment setting overrides the
.Ev MAIL
setting. There is a maximum of 10 mailboxes that can be monitored at once.
.It Ev PS1
The primary prompt string, which defaults to
.Dq $ \ ,
unless you are the superuser, in which case it defaults to
.Dq # \ .
.It Ev PS2
The secondary prompt string, which defaults to
.Dq > \ .
.It Ev IFS
Input Field Separators. This is normally set to <space> <tab> and
<newline>. See the
.Sx White Space Splitting
section for more details.
.It Ev TERM
The default terminal setting for the shell. This is inherited by
children of the shell, and is used in the history editing modes.
.It Ev HISTSIZE
The number of lines in the history buffer for the shell.
.El
.Sh FILES
.Bl -item -width HOMEprofilexxxx
.It
.Pa $HOME/.profile
.It
.Pa /etc/profile
.El
.Sh SEE ALSO
.Xr csh 1 ,
.Xr getopt 1 ,
.Xr ksh 1 ,
.Xr login 1 ,
.Xr test 1 ,
.Xr getopt 3 ,
.Xr passwd 4 ,
.Xr profile 4 ,
.Xr environ 5
.Xr sysctl 8
.Sh HISTORY
A
.Nm
command appeared in
.At v1 .
It was, however, unmaintainable so we wrote this one.
.Sh EXIT STATUS
Errors that are detected by the shell, such as a syntax error, will cause the
shell to exit with a non-zero exit status. If the shell is not an
interactive shell, the execution of the shell file will be aborted. Otherwise
the shell will return the exit status of the last command executed, or
if the exit builtin is used with a numeric argument, it will return the
argument.
.Sh BUGS
Setuid shell scripts should be avoided at all costs, as they are a
significant security risk.
/trunk/uspace/app/ash/lex.yy.c
0,0 → 1,1904
 
#line 3 "lex.yy.c"
 
#define YY_INT_ALIGNED short int
 
/* A lexical scanner generated by flex */
 
#define FLEX_SCANNER
#define YY_FLEX_MAJOR_VERSION 2
#define YY_FLEX_MINOR_VERSION 5
#define YY_FLEX_SUBMINOR_VERSION 33
#if YY_FLEX_SUBMINOR_VERSION > 0
#define FLEX_BETA
#endif
 
/* First, we deal with platform-specific or compiler-specific issues. */
 
/* begin standard C headers. */
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
 
/* end standard C headers. */
 
/* flex integer type definitions */
 
#ifndef FLEXINT_H
#define FLEXINT_H
 
/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
 
#if __STDC_VERSION__ >= 199901L
 
/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
* if you want the limit (max/min) macros for int types.
*/
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS 1
#endif
 
#include <inttypes.h>
typedef int8_t flex_int8_t;
typedef uint8_t flex_uint8_t;
typedef int16_t flex_int16_t;
typedef uint16_t flex_uint16_t;
typedef int32_t flex_int32_t;
typedef uint32_t flex_uint32_t;
#else
typedef signed char flex_int8_t;
typedef short int flex_int16_t;
typedef int flex_int32_t;
typedef unsigned char flex_uint8_t;
typedef unsigned short int flex_uint16_t;
typedef unsigned int flex_uint32_t;
#endif /* ! C99 */
 
/* Limits of integral types. */
#ifndef INT8_MIN
#define INT8_MIN (-128)
#endif
#ifndef INT16_MIN
#define INT16_MIN (-32767-1)
#endif
#ifndef INT32_MIN
#define INT32_MIN (-2147483647-1)
#endif
#ifndef INT8_MAX
#define INT8_MAX (127)
#endif
#ifndef INT16_MAX
#define INT16_MAX (32767)
#endif
#ifndef INT32_MAX
#define INT32_MAX (2147483647)
#endif
#ifndef UINT8_MAX
#define UINT8_MAX (255U)
#endif
#ifndef UINT16_MAX
#define UINT16_MAX (65535U)
#endif
#ifndef UINT32_MAX
#define UINT32_MAX (4294967295U)
#endif
 
#endif /* ! FLEXINT_H */
 
#ifdef __cplusplus
 
/* The "const" storage-class-modifier is valid. */
#define YY_USE_CONST
 
#else /* ! __cplusplus */
 
#if __STDC__
 
#define YY_USE_CONST
 
#endif /* __STDC__ */
#endif /* ! __cplusplus */
 
#ifdef YY_USE_CONST
#define yyconst const
#else
#define yyconst
#endif
 
/* Returned upon end-of-file. */
#define YY_NULL 0
 
/* Promotes a possibly negative, possibly signed char to an unsigned
* integer for use as an array index. If the signed char is negative,
* we want to instead treat it as an 8-bit unsigned char, hence the
* double cast.
*/
#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
 
/* Enter a start condition. This macro really ought to take a parameter,
* but we do it the disgusting crufty way forced on us by the ()-less
* definition of BEGIN.
*/
#define BEGIN (yy_start) = 1 + 2 *
 
/* Translate the current start state into a value that can be later handed
* to BEGIN to return to the state. The YYSTATE alias is for lex
* compatibility.
*/
#define YY_START (((yy_start) - 1) / 2)
#define YYSTATE YY_START
 
/* Action number for EOF rule of a given start state. */
#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
 
/* Special action meaning "start processing a new file". */
#define YY_NEW_FILE yyrestart(yyin )
 
#define YY_END_OF_BUFFER_CHAR 0
 
/* Size of default input buffer. */
#ifndef YY_BUF_SIZE
#define YY_BUF_SIZE 16384
#endif
 
/* The state buf must be large enough to hold one state per character in the main buffer.
*/
#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
 
#ifndef YY_TYPEDEF_YY_BUFFER_STATE
#define YY_TYPEDEF_YY_BUFFER_STATE
typedef struct yy_buffer_state *YY_BUFFER_STATE;
#endif
 
extern int yyleng;
 
extern FILE *yyin, *yyout;
 
#define EOB_ACT_CONTINUE_SCAN 0
#define EOB_ACT_END_OF_FILE 1
#define EOB_ACT_LAST_MATCH 2
 
#define YY_LESS_LINENO(n)
/* Return all but the first "n" matched characters back to the input stream. */
#define yyless(n) \
do \
{ \
/* Undo effects of setting up yytext. */ \
int yyless_macro_arg = (n); \
YY_LESS_LINENO(yyless_macro_arg);\
*yy_cp = (yy_hold_char); \
YY_RESTORE_YY_MORE_OFFSET \
(yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
YY_DO_BEFORE_ACTION; /* set up yytext again */ \
} \
while ( 0 )
 
#define unput(c) yyunput( c, (yytext_ptr) )
 
/* The following is because we cannot portably get our hands on size_t
* (without autoconf's help, which isn't available because we want
* flex-generated scanners to compile on their own).
*/
 
#ifndef YY_TYPEDEF_YY_SIZE_T
#define YY_TYPEDEF_YY_SIZE_T
typedef unsigned int yy_size_t;
#endif
 
#ifndef YY_STRUCT_YY_BUFFER_STATE
#define YY_STRUCT_YY_BUFFER_STATE
struct yy_buffer_state
{
FILE *yy_input_file;
 
char *yy_ch_buf; /* input buffer */
char *yy_buf_pos; /* current position in input buffer */
 
/* Size of input buffer in bytes, not including room for EOB
* characters.
*/
yy_size_t yy_buf_size;
 
/* Number of characters read into yy_ch_buf, not including EOB
* characters.
*/
int yy_n_chars;
 
/* Whether we "own" the buffer - i.e., we know we created it,
* and can realloc() it to grow it, and should free() it to
* delete it.
*/
int yy_is_our_buffer;
 
/* Whether this is an "interactive" input source; if so, and
* if we're using stdio for input, then we want to use getc()
* instead of fread(), to make sure we stop fetching input after
* each newline.
*/
int yy_is_interactive;
 
/* Whether we're considered to be at the beginning of a line.
* If so, '^' rules will be active on the next match, otherwise
* not.
*/
int yy_at_bol;
 
int yy_bs_lineno; /**< The line count. */
int yy_bs_column; /**< The column count. */
/* Whether to try to fill the input buffer when we reach the
* end of it.
*/
int yy_fill_buffer;
 
int yy_buffer_status;
 
#define YY_BUFFER_NEW 0
#define YY_BUFFER_NORMAL 1
/* When an EOF's been seen but there's still some text to process
* then we mark the buffer as YY_EOF_PENDING, to indicate that we
* shouldn't try reading from the input source any more. We might
* still have a bunch of tokens to match, though, because of
* possible backing-up.
*
* When we actually see the EOF, we change the status to "new"
* (via yyrestart()), so that the user can continue scanning by
* just pointing yyin at a new input file.
*/
#define YY_BUFFER_EOF_PENDING 2
 
};
#endif /* !YY_STRUCT_YY_BUFFER_STATE */
 
/* Stack of input buffers. */
static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
 
/* We provide macros for accessing buffer states in case in the
* future we want to put the buffer states in a more general
* "scanner state".
*
* Returns the top of the stack, or NULL.
*/
#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
? (yy_buffer_stack)[(yy_buffer_stack_top)] \
: NULL)
 
/* Same as previous macro, but useful when we know that the buffer stack is not
* NULL or when we need an lvalue. For internal use only.
*/
#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
 
/* yy_hold_char holds the character lost when yytext is formed. */
static char yy_hold_char;
static int yy_n_chars; /* number of characters read into yy_ch_buf */
int yyleng;
 
/* Points to current character in buffer. */
static char *yy_c_buf_p = (char *) 0;
static int yy_init = 0; /* whether we need to initialize */
static int yy_start = 0; /* start state number */
 
/* Flag which is used to allow yywrap()'s to do buffer switches
* instead of setting up a fresh yyin. A bit of a hack ...
*/
static int yy_did_buffer_switch_on_eof;
 
void yyrestart (FILE *input_file );
void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer );
YY_BUFFER_STATE yy_create_buffer (FILE *file,int size );
void yy_delete_buffer (YY_BUFFER_STATE b );
void yy_flush_buffer (YY_BUFFER_STATE b );
void yypush_buffer_state (YY_BUFFER_STATE new_buffer );
void yypop_buffer_state (void );
 
static void yyensure_buffer_stack (void );
static void yy_load_buffer_state (void );
static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file );
 
#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER )
 
YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size );
YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str );
YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len );
 
void *yyalloc (yy_size_t );
void *yyrealloc (void *,yy_size_t );
void yyfree (void * );
 
#define yy_new_buffer yy_create_buffer
 
#define yy_set_interactive(is_interactive) \
{ \
if ( ! YY_CURRENT_BUFFER ){ \
yyensure_buffer_stack (); \
YY_CURRENT_BUFFER_LVALUE = \
yy_create_buffer(yyin,YY_BUF_SIZE ); \
} \
YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
}
 
#define yy_set_bol(at_bol) \
{ \
if ( ! YY_CURRENT_BUFFER ){\
yyensure_buffer_stack (); \
YY_CURRENT_BUFFER_LVALUE = \
yy_create_buffer(yyin,YY_BUF_SIZE ); \
} \
YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
}
 
#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
 
/* Begin user sect3 */
 
typedef unsigned char YY_CHAR;
 
FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
 
typedef int yy_state_type;
 
extern int yylineno;
 
int yylineno = 1;
 
extern char *yytext;
#define yytext_ptr yytext
 
static yy_state_type yy_get_previous_state (void );
static yy_state_type yy_try_NUL_trans (yy_state_type current_state );
static int yy_get_next_buffer (void );
static void yy_fatal_error (yyconst char msg[] );
 
/* Done after the current pattern has been matched and before the
* corresponding action - sets up yytext.
*/
#define YY_DO_BEFORE_ACTION \
(yytext_ptr) = yy_bp; \
yyleng = (size_t) (yy_cp - yy_bp); \
(yy_hold_char) = *yy_cp; \
*yy_cp = '\0'; \
(yy_c_buf_p) = yy_cp;
 
#define YY_NUM_RULES 26
#define YY_END_OF_BUFFER 27
/* This struct is not used in this scanner,
but its presence is necessary. */
struct yy_trans_info
{
flex_int32_t yy_verify;
flex_int32_t yy_nxt;
};
static yyconst flex_int16_t yy_accept[33] =
{ 0,
0, 0, 27, 25, 1, 1, 24, 20, 9, 3,
4, 18, 21, 22, 19, 2, 14, 25, 12, 8,
7, 23, 11, 6, 2, 16, 15, 10, 13, 17,
5, 0
} ;
 
static yyconst flex_int32_t yy_ec[256] =
{ 0,
1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 2, 4, 1, 1, 1, 5, 6, 1, 7,
8, 9, 10, 1, 11, 1, 12, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 1, 1, 14,
15, 16, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 17, 1, 1, 1, 1, 1, 1,
 
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 18, 1, 19, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
 
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1
} ;
 
static yyconst flex_int32_t yy_meta[20] =
{ 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1
} ;
 
static yyconst flex_int16_t yy_base[33] =
{ 0,
0, 0, 30, 31, 31, 31, 14, 31, 22, 31,
31, 31, 31, 31, 31, 14, 6, 11, 7, 31,
7, 31, 31, 31, 11, 31, 31, 31, 31, 31,
31, 31
} ;
 
static yyconst flex_int16_t yy_def[33] =
{ 0,
32, 1, 32, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
32, 0
} ;
 
static yyconst flex_int16_t yy_nxt[51] =
{ 0,
4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19, 20, 21, 22, 26,
27, 29, 30, 25, 31, 28, 25, 24, 23, 32,
3, 32, 32, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32, 32, 32, 32, 32, 32, 32
} ;
 
static yyconst flex_int16_t yy_chk[51] =
{ 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 17,
17, 19, 19, 25, 21, 18, 16, 9, 7, 3,
32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32, 32, 32, 32, 32, 32, 32
} ;
 
static yy_state_type yy_last_accepting_state;
static char *yy_last_accepting_cpos;
 
extern int yy_flex_debug;
int yy_flex_debug = 0;
 
/* The intent behind this definition is that it'll catch
* any uses of REJECT which flex missed.
*/
#define REJECT reject_used_but_not_detected
#define yymore() yymore_used_but_not_detected
#define YY_MORE_ADJ 0
#define YY_RESTORE_YY_MORE_OFFSET
char *yytext;
#line 1 "arith_lex.l"
#line 2 "arith_lex.l"
/* $NetBSD: arith_lex.l,v 1.10 1999/02/05 07:52:52 christos 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
 
#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.10 1999/02/05 07:52:52 christos Exp $");
#endif
#endif /* not lint */
 
#include <unistd.h>
#include "arith.h"
#include "error.h"
#include "expand.h"
 
extern int yylval;
extern 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
#line 530 "lex.yy.c"
 
#define INITIAL 0
 
#ifndef YY_NO_UNISTD_H
/* Special case for "unistd.h", since it is non-ANSI. We include it way
* down here because we want the user's section 1 to have been scanned first.
* The user has a chance to override it with an option.
*/
#include <unistd.h>
#endif
 
#ifndef YY_EXTRA_TYPE
#define YY_EXTRA_TYPE void *
#endif
 
static int yy_init_globals (void );
 
/* Macros after this point can all be overridden by user definitions in
* section 1.
*/
 
#ifndef YY_SKIP_YYWRAP
#ifdef __cplusplus
extern "C" int yywrap (void );
#else
extern int yywrap (void );
#endif
#endif
 
static void yyunput (int c,char *buf_ptr );
#ifndef yytext_ptr
static void yy_flex_strncpy (char *,yyconst char *,int );
#endif
 
#ifdef YY_NEED_STRLEN
static int yy_flex_strlen (yyconst char * );
#endif
 
#ifndef YY_NO_INPUT
 
#ifdef __cplusplus
static int yyinput (void );
#else
static int input (void );
#endif
 
#endif
 
/* Amount of stuff to slurp up with each read. */
#ifndef YY_READ_BUF_SIZE
#define YY_READ_BUF_SIZE 8192
#endif
 
/* Copy whatever the last rule matched to the standard output. */
#ifndef ECHO
/* This used to be an fputs(), but since the string might contain NUL's,
* we now use fwrite().
*/
#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
#endif
 
/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
* is returned in "result".
*/
#ifndef YY_INPUT
#define YY_INPUT(buf,result,max_size) \
if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
{ \
int c = '*'; \
size_t n; \
for ( n = 0; n < max_size && \
(c = getc( yyin )) != EOF && c != '\n'; ++n ) \
buf[n] = (char) c; \
if ( c == '\n' ) \
buf[n++] = (char) c; \
if ( c == EOF && ferror( yyin ) ) \
YY_FATAL_ERROR( "input in flex scanner failed" ); \
result = n; \
} \
else \
{ \
errno=0; \
while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
{ \
if( errno != EINTR) \
{ \
YY_FATAL_ERROR( "input in flex scanner failed" ); \
break; \
} \
errno=0; \
clearerr(yyin); \
} \
}\
\
 
#endif
 
/* No semi-colon after return; correct usage is to write "yyterminate();" -
* we don't want an extra ';' after the "return" because that will cause
* some compilers to complain about unreachable statements.
*/
#ifndef yyterminate
#define yyterminate() return YY_NULL
#endif
 
/* Number of entries by which start-condition stack grows. */
#ifndef YY_START_STACK_INCR
#define YY_START_STACK_INCR 25
#endif
 
/* Report a fatal error. */
#ifndef YY_FATAL_ERROR
#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
#endif
 
/* end tables serialization structures and prototypes */
 
/* Default declaration of generated scanner - a define so the user can
* easily add parameters.
*/
#ifndef YY_DECL
#define YY_DECL_IS_OURS 1
 
extern int yylex (void);
 
#define YY_DECL int yylex (void)
#endif /* !YY_DECL */
 
/* Code executed at the beginning of each rule, after yytext and yyleng
* have been set up.
*/
#ifndef YY_USER_ACTION
#define YY_USER_ACTION
#endif
 
/* Code executed at the end of each rule. */
#ifndef YY_BREAK
#define YY_BREAK break;
#endif
 
#define YY_RULE_SETUP \
YY_USER_ACTION
 
/** The main scanner function which does all the work.
*/
YY_DECL
{
register yy_state_type yy_current_state;
register char *yy_cp, *yy_bp;
register int yy_act;
#line 62 "arith_lex.l"
 
#line 685 "lex.yy.c"
 
if ( !(yy_init) )
{
(yy_init) = 1;
 
#ifdef YY_USER_INIT
YY_USER_INIT;
#endif
 
if ( ! (yy_start) )
(yy_start) = 1; /* first start state */
 
if ( ! yyin )
yyin = stdin;
 
if ( ! yyout )
yyout = stdout;
 
if ( ! YY_CURRENT_BUFFER ) {
yyensure_buffer_stack ();
YY_CURRENT_BUFFER_LVALUE =
yy_create_buffer(yyin,YY_BUF_SIZE );
}
 
yy_load_buffer_state( );
}
 
while ( 1 ) /* loops until end-of-file is reached */
{
yy_cp = (yy_c_buf_p);
 
/* Support of yytext. */
*yy_cp = (yy_hold_char);
 
/* yy_bp points to the position in yy_ch_buf of the start of
* the current run.
*/
yy_bp = yy_cp;
 
yy_current_state = (yy_start);
yy_match:
do
{
register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
if ( yy_accept[yy_current_state] )
{
(yy_last_accepting_state) = yy_current_state;
(yy_last_accepting_cpos) = yy_cp;
}
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
if ( yy_current_state >= 33 )
yy_c = yy_meta[(unsigned int) yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
++yy_cp;
}
while ( yy_base[yy_current_state] != 31 );
 
yy_find_action:
yy_act = yy_accept[yy_current_state];
if ( yy_act == 0 )
{ /* have to back up */
yy_cp = (yy_last_accepting_cpos);
yy_current_state = (yy_last_accepting_state);
yy_act = yy_accept[yy_current_state];
}
 
YY_DO_BEFORE_ACTION;
 
do_action: /* This label is used only to access EOF actions. */
 
switch ( yy_act )
{ /* beginning of action switch */
case 0: /* must back up */
/* undo the effects of YY_DO_BEFORE_ACTION */
*yy_cp = (yy_hold_char);
yy_cp = (yy_last_accepting_cpos);
yy_current_state = (yy_last_accepting_state);
goto yy_find_action;
 
case 1:
/* rule 1 can match eol */
YY_RULE_SETUP
#line 63 "arith_lex.l"
{ ; }
YY_BREAK
case 2:
YY_RULE_SETUP
#line 64 "arith_lex.l"
{ yylval = atol(yytext); return(ARITH_NUM); }
YY_BREAK
case 3:
YY_RULE_SETUP
#line 65 "arith_lex.l"
{ return(ARITH_LPAREN); }
YY_BREAK
case 4:
YY_RULE_SETUP
#line 66 "arith_lex.l"
{ return(ARITH_RPAREN); }
YY_BREAK
case 5:
YY_RULE_SETUP
#line 67 "arith_lex.l"
{ return(ARITH_OR); }
YY_BREAK
case 6:
YY_RULE_SETUP
#line 68 "arith_lex.l"
{ return(ARITH_AND); }
YY_BREAK
case 7:
YY_RULE_SETUP
#line 69 "arith_lex.l"
{ return(ARITH_BOR); }
YY_BREAK
case 8:
YY_RULE_SETUP
#line 70 "arith_lex.l"
{ return(ARITH_BXOR); }
YY_BREAK
case 9:
YY_RULE_SETUP
#line 71 "arith_lex.l"
{ return(ARITH_BAND); }
YY_BREAK
case 10:
YY_RULE_SETUP
#line 72 "arith_lex.l"
{ return(ARITH_EQ); }
YY_BREAK
case 11:
YY_RULE_SETUP
#line 73 "arith_lex.l"
{ return(ARITH_NE); }
YY_BREAK
case 12:
YY_RULE_SETUP
#line 74 "arith_lex.l"
{ return(ARITH_GT); }
YY_BREAK
case 13:
YY_RULE_SETUP
#line 75 "arith_lex.l"
{ return(ARITH_GE); }
YY_BREAK
case 14:
YY_RULE_SETUP
#line 76 "arith_lex.l"
{ return(ARITH_LT); }
YY_BREAK
case 15:
YY_RULE_SETUP
#line 77 "arith_lex.l"
{ return(ARITH_LE); }
YY_BREAK
case 16:
YY_RULE_SETUP
#line 78 "arith_lex.l"
{ return(ARITH_LSHIFT); }
YY_BREAK
case 17:
YY_RULE_SETUP
#line 79 "arith_lex.l"
{ return(ARITH_RSHIFT); }
YY_BREAK
case 18:
YY_RULE_SETUP
#line 80 "arith_lex.l"
{ return(ARITH_MUL); }
YY_BREAK
case 19:
YY_RULE_SETUP
#line 81 "arith_lex.l"
{ return(ARITH_DIV); }
YY_BREAK
case 20:
YY_RULE_SETUP
#line 82 "arith_lex.l"
{ return(ARITH_REM); }
YY_BREAK
case 21:
YY_RULE_SETUP
#line 83 "arith_lex.l"
{ return(ARITH_ADD); }
YY_BREAK
case 22:
YY_RULE_SETUP
#line 84 "arith_lex.l"
{ return(ARITH_SUB); }
YY_BREAK
case 23:
YY_RULE_SETUP
#line 85 "arith_lex.l"
{ return(ARITH_BNOT); }
YY_BREAK
case 24:
YY_RULE_SETUP
#line 86 "arith_lex.l"
{ return(ARITH_NOT); }
YY_BREAK
case 25:
YY_RULE_SETUP
#line 87 "arith_lex.l"
{ error("arith: syntax error: \"%s\"\n", arith_startbuf); }
YY_BREAK
case 26:
YY_RULE_SETUP
#line 88 "arith_lex.l"
ECHO;
YY_BREAK
#line 899 "lex.yy.c"
case YY_STATE_EOF(INITIAL):
yyterminate();
 
case YY_END_OF_BUFFER:
{
/* Amount of text matched not including the EOB char. */
int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
 
/* Undo the effects of YY_DO_BEFORE_ACTION. */
*yy_cp = (yy_hold_char);
YY_RESTORE_YY_MORE_OFFSET
 
if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
{
/* We're scanning a new file or input source. It's
* possible that this happened because the user
* just pointed yyin at a new source and called
* yylex(). If so, then we have to assure
* consistency between YY_CURRENT_BUFFER and our
* globals. Here is the right place to do so, because
* this is the first action (other than possibly a
* back-up) that will match for the new input source.
*/
(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
}
 
/* Note that here we test for yy_c_buf_p "<=" to the position
* of the first EOB in the buffer, since yy_c_buf_p will
* already have been incremented past the NUL character
* (since all states make transitions on EOB to the
* end-of-buffer state). Contrast this with the test
* in input().
*/
if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
{ /* This was really a NUL. */
yy_state_type yy_next_state;
 
(yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
 
yy_current_state = yy_get_previous_state( );
 
/* Okay, we're now positioned to make the NUL
* transition. We couldn't have
* yy_get_previous_state() go ahead and do it
* for us because it doesn't know how to deal
* with the possibility of jamming (and we don't
* want to build jamming into it because then it
* will run more slowly).
*/
 
yy_next_state = yy_try_NUL_trans( yy_current_state );
 
yy_bp = (yytext_ptr) + YY_MORE_ADJ;
 
if ( yy_next_state )
{
/* Consume the NUL. */
yy_cp = ++(yy_c_buf_p);
yy_current_state = yy_next_state;
goto yy_match;
}
 
else
{
yy_cp = (yy_c_buf_p);
goto yy_find_action;
}
}
 
else switch ( yy_get_next_buffer( ) )
{
case EOB_ACT_END_OF_FILE:
{
(yy_did_buffer_switch_on_eof) = 0;
 
if ( yywrap( ) )
{
/* Note: because we've taken care in
* yy_get_next_buffer() to have set up
* yytext, we can now set up
* yy_c_buf_p so that if some total
* hoser (like flex itself) wants to
* call the scanner after we return the
* YY_NULL, it'll still work - another
* YY_NULL will get returned.
*/
(yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
 
yy_act = YY_STATE_EOF(YY_START);
goto do_action;
}
 
else
{
if ( ! (yy_did_buffer_switch_on_eof) )
YY_NEW_FILE;
}
break;
}
 
case EOB_ACT_CONTINUE_SCAN:
(yy_c_buf_p) =
(yytext_ptr) + yy_amount_of_matched_text;
 
yy_current_state = yy_get_previous_state( );
 
yy_cp = (yy_c_buf_p);
yy_bp = (yytext_ptr) + YY_MORE_ADJ;
goto yy_match;
 
case EOB_ACT_LAST_MATCH:
(yy_c_buf_p) =
&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
 
yy_current_state = yy_get_previous_state( );
 
yy_cp = (yy_c_buf_p);
yy_bp = (yytext_ptr) + YY_MORE_ADJ;
goto yy_find_action;
}
break;
}
 
default:
YY_FATAL_ERROR(
"fatal flex scanner internal error--no action found" );
} /* end of action switch */
} /* end of scanning one token */
} /* end of yylex */
 
/* yy_get_next_buffer - try to read in a new buffer
*
* Returns a code representing an action:
* EOB_ACT_LAST_MATCH -
* EOB_ACT_CONTINUE_SCAN - continue scanning from current position
* EOB_ACT_END_OF_FILE - end of file
*/
static int yy_get_next_buffer (void)
{
register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
register char *source = (yytext_ptr);
register int number_to_move, i;
int ret_val;
 
if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
YY_FATAL_ERROR(
"fatal flex scanner internal error--end of buffer missed" );
 
if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
{ /* Don't try to fill the buffer, so this is an EOF. */
if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
{
/* We matched a single character, the EOB, so
* treat this as a final EOF.
*/
return EOB_ACT_END_OF_FILE;
}
 
else
{
/* We matched some text prior to the EOB, first
* process it.
*/
return EOB_ACT_LAST_MATCH;
}
}
 
/* Try to read more data. */
 
/* First move last chars to start of buffer. */
number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
 
for ( i = 0; i < number_to_move; ++i )
*(dest++) = *(source++);
 
if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
/* don't do the read, it's not guaranteed to return an EOF,
* just force an EOF
*/
YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
 
else
{
int num_to_read =
YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
 
while ( num_to_read <= 0 )
{ /* Not enough room in the buffer - grow it. */
 
/* just a shorter name for the current buffer */
YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
 
int yy_c_buf_p_offset =
(int) ((yy_c_buf_p) - b->yy_ch_buf);
 
if ( b->yy_is_our_buffer )
{
int new_size = b->yy_buf_size * 2;
 
if ( new_size <= 0 )
b->yy_buf_size += b->yy_buf_size / 8;
else
b->yy_buf_size *= 2;
 
b->yy_ch_buf = (char *)
/* Include room in for 2 EOB chars. */
yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 );
}
else
/* Can't grow it, we don't own it. */
b->yy_ch_buf = 0;
 
if ( ! b->yy_ch_buf )
YY_FATAL_ERROR(
"fatal error - scanner input buffer overflow" );
 
(yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
 
num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
number_to_move - 1;
 
}
 
if ( num_to_read > YY_READ_BUF_SIZE )
num_to_read = YY_READ_BUF_SIZE;
 
/* Read in more data. */
YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
(yy_n_chars), num_to_read );
 
YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
}
 
if ( (yy_n_chars) == 0 )
{
if ( number_to_move == YY_MORE_ADJ )
{
ret_val = EOB_ACT_END_OF_FILE;
yyrestart(yyin );
}
 
else
{
ret_val = EOB_ACT_LAST_MATCH;
YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
YY_BUFFER_EOF_PENDING;
}
}
 
else
ret_val = EOB_ACT_CONTINUE_SCAN;
 
(yy_n_chars) += number_to_move;
YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
 
(yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
 
return ret_val;
}
 
/* yy_get_previous_state - get the state just before the EOB char was reached */
 
static yy_state_type yy_get_previous_state (void)
{
register yy_state_type yy_current_state;
register char *yy_cp;
yy_current_state = (yy_start);
 
for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
{
register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
if ( yy_accept[yy_current_state] )
{
(yy_last_accepting_state) = yy_current_state;
(yy_last_accepting_cpos) = yy_cp;
}
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
if ( yy_current_state >= 33 )
yy_c = yy_meta[(unsigned int) yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
}
 
return yy_current_state;
}
 
/* yy_try_NUL_trans - try to make a transition on the NUL character
*
* synopsis
* next_state = yy_try_NUL_trans( current_state );
*/
static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state )
{
register int yy_is_jam;
register char *yy_cp = (yy_c_buf_p);
 
register YY_CHAR yy_c = 1;
if ( yy_accept[yy_current_state] )
{
(yy_last_accepting_state) = yy_current_state;
(yy_last_accepting_cpos) = yy_cp;
}
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
if ( yy_current_state >= 33 )
yy_c = yy_meta[(unsigned int) yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
yy_is_jam = (yy_current_state == 32);
 
return yy_is_jam ? 0 : yy_current_state;
}
 
static void yyunput (int c, register char * yy_bp )
{
register char *yy_cp;
yy_cp = (yy_c_buf_p);
 
/* undo effects of setting up yytext */
*yy_cp = (yy_hold_char);
 
if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
{ /* need to shift things up to make room */
/* +2 for EOB chars. */
register int number_to_move = (yy_n_chars) + 2;
register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
register char *source =
&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
 
while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
*--dest = *--source;
 
yy_cp += (int) (dest - source);
yy_bp += (int) (dest - source);
YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
 
if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
YY_FATAL_ERROR( "flex scanner push-back overflow" );
}
 
*--yy_cp = (char) c;
 
(yytext_ptr) = yy_bp;
(yy_hold_char) = *yy_cp;
(yy_c_buf_p) = yy_cp;
}
 
#ifndef YY_NO_INPUT
#ifdef __cplusplus
static int yyinput (void)
#else
static int input (void)
#endif
 
{
int c;
*(yy_c_buf_p) = (yy_hold_char);
 
if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
{
/* yy_c_buf_p now points to the character we want to return.
* If this occurs *before* the EOB characters, then it's a
* valid NUL; if not, then we've hit the end of the buffer.
*/
if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
/* This was really a NUL. */
*(yy_c_buf_p) = '\0';
 
else
{ /* need more input */
int offset = (yy_c_buf_p) - (yytext_ptr);
++(yy_c_buf_p);
 
switch ( yy_get_next_buffer( ) )
{
case EOB_ACT_LAST_MATCH:
/* This happens because yy_g_n_b()
* sees that we've accumulated a
* token and flags that we need to
* try matching the token before
* proceeding. But for input(),
* there's no matching to consider.
* So convert the EOB_ACT_LAST_MATCH
* to EOB_ACT_END_OF_FILE.
*/
 
/* Reset buffer status. */
yyrestart(yyin );
 
/*FALLTHROUGH*/
 
case EOB_ACT_END_OF_FILE:
{
if ( yywrap( ) )
return EOF;
 
if ( ! (yy_did_buffer_switch_on_eof) )
YY_NEW_FILE;
#ifdef __cplusplus
return yyinput();
#else
return input();
#endif
}
 
case EOB_ACT_CONTINUE_SCAN:
(yy_c_buf_p) = (yytext_ptr) + offset;
break;
}
}
}
 
c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */
*(yy_c_buf_p) = '\0'; /* preserve yytext */
(yy_hold_char) = *++(yy_c_buf_p);
 
return c;
}
#endif /* ifndef YY_NO_INPUT */
 
/** Immediately switch to a different input stream.
* @param input_file A readable stream.
*
* @note This function does not reset the start condition to @c INITIAL .
*/
void yyrestart (FILE * input_file )
{
if ( ! YY_CURRENT_BUFFER ){
yyensure_buffer_stack ();
YY_CURRENT_BUFFER_LVALUE =
yy_create_buffer(yyin,YY_BUF_SIZE );
}
 
yy_init_buffer(YY_CURRENT_BUFFER,input_file );
yy_load_buffer_state( );
}
 
/** Switch to a different input buffer.
* @param new_buffer The new input buffer.
*
*/
void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer )
{
/* TODO. We should be able to replace this entire function body
* with
* yypop_buffer_state();
* yypush_buffer_state(new_buffer);
*/
yyensure_buffer_stack ();
if ( YY_CURRENT_BUFFER == new_buffer )
return;
 
if ( YY_CURRENT_BUFFER )
{
/* Flush out information for old buffer. */
*(yy_c_buf_p) = (yy_hold_char);
YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
}
 
YY_CURRENT_BUFFER_LVALUE = new_buffer;
yy_load_buffer_state( );
 
/* We don't actually know whether we did this switch during
* EOF (yywrap()) processing, but the only time this flag
* is looked at is after yywrap() is called, so it's safe
* to go ahead and always set it.
*/
(yy_did_buffer_switch_on_eof) = 1;
}
 
static void yy_load_buffer_state (void)
{
(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
(yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
(yy_hold_char) = *(yy_c_buf_p);
}
 
/** Allocate and initialize an input buffer state.
* @param file A readable stream.
* @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
*
* @return the allocated buffer state.
*/
YY_BUFFER_STATE yy_create_buffer (FILE * file, int size )
{
YY_BUFFER_STATE b;
b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) );
if ( ! b )
YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
 
b->yy_buf_size = size;
 
/* yy_ch_buf has to be 2 characters longer than the size given because
* we need to put in 2 end-of-buffer characters.
*/
b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 );
if ( ! b->yy_ch_buf )
YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
 
b->yy_is_our_buffer = 1;
 
yy_init_buffer(b,file );
 
return b;
}
 
/** Destroy the buffer.
* @param b a buffer created with yy_create_buffer()
*
*/
void yy_delete_buffer (YY_BUFFER_STATE b )
{
if ( ! b )
return;
 
if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
 
if ( b->yy_is_our_buffer )
yyfree((void *) b->yy_ch_buf );
 
yyfree((void *) b );
}
 
#ifndef _UNISTD_H /* assume unistd.h has isatty() for us */
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __THROW /* this is a gnuism */
extern int isatty (int ) __THROW;
#else
extern int isatty (int );
#endif
#ifdef __cplusplus
}
#endif
#endif
/* Initializes or reinitializes a buffer.
* This function is sometimes called more than once on the same buffer,
* such as during a yyrestart() or at EOF.
*/
static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file )
 
{
int oerrno = errno;
yy_flush_buffer(b );
 
b->yy_input_file = file;
b->yy_fill_buffer = 1;
 
/* If b is the current buffer, then yy_init_buffer was _probably_
* called from yyrestart() or through yy_get_next_buffer.
* In that case, we don't want to reset the lineno or column.
*/
if (b != YY_CURRENT_BUFFER){
b->yy_bs_lineno = 1;
b->yy_bs_column = 0;
}
 
b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
errno = oerrno;
}
 
/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
* @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
*
*/
void yy_flush_buffer (YY_BUFFER_STATE b )
{
if ( ! b )
return;
 
b->yy_n_chars = 0;
 
/* We always need two end-of-buffer characters. The first causes
* a transition to the end-of-buffer state. The second causes
* a jam in that state.
*/
b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
 
b->yy_buf_pos = &b->yy_ch_buf[0];
 
b->yy_at_bol = 1;
b->yy_buffer_status = YY_BUFFER_NEW;
 
if ( b == YY_CURRENT_BUFFER )
yy_load_buffer_state( );
}
 
/** Pushes the new state onto the stack. The new state becomes
* the current state. This function will allocate the stack
* if necessary.
* @param new_buffer The new state.
*
*/
void yypush_buffer_state (YY_BUFFER_STATE new_buffer )
{
if (new_buffer == NULL)
return;
 
yyensure_buffer_stack();
 
/* This block is copied from yy_switch_to_buffer. */
if ( YY_CURRENT_BUFFER )
{
/* Flush out information for old buffer. */
*(yy_c_buf_p) = (yy_hold_char);
YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
}
 
/* Only push if top exists. Otherwise, replace top. */
if (YY_CURRENT_BUFFER)
(yy_buffer_stack_top)++;
YY_CURRENT_BUFFER_LVALUE = new_buffer;
 
/* copied from yy_switch_to_buffer. */
yy_load_buffer_state( );
(yy_did_buffer_switch_on_eof) = 1;
}
 
/** Removes and deletes the top of the stack, if present.
* The next element becomes the new top.
*
*/
void yypop_buffer_state (void)
{
if (!YY_CURRENT_BUFFER)
return;
 
yy_delete_buffer(YY_CURRENT_BUFFER );
YY_CURRENT_BUFFER_LVALUE = NULL;
if ((yy_buffer_stack_top) > 0)
--(yy_buffer_stack_top);
 
if (YY_CURRENT_BUFFER) {
yy_load_buffer_state( );
(yy_did_buffer_switch_on_eof) = 1;
}
}
 
/* Allocates the stack if it does not exist.
* Guarantees space for at least one push.
*/
static void yyensure_buffer_stack (void)
{
int num_to_alloc;
if (!(yy_buffer_stack)) {
 
/* First allocation is just for 2 elements, since we don't know if this
* scanner will even need a stack. We use 2 instead of 1 to avoid an
* immediate realloc on the next call.
*/
num_to_alloc = 1;
(yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
(num_to_alloc * sizeof(struct yy_buffer_state*)
);
memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
(yy_buffer_stack_max) = num_to_alloc;
(yy_buffer_stack_top) = 0;
return;
}
 
if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
 
/* Increase the buffer to prepare for a possible push. */
int grow_size = 8 /* arbitrary grow size */;
 
num_to_alloc = (yy_buffer_stack_max) + grow_size;
(yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
((yy_buffer_stack),
num_to_alloc * sizeof(struct yy_buffer_state*)
);
 
/* zero only the new slots.*/
memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
(yy_buffer_stack_max) = num_to_alloc;
}
}
 
/** Setup the input buffer state to scan directly from a user-specified character buffer.
* @param base the character buffer
* @param size the size in bytes of the character buffer
*
* @return the newly allocated buffer state object.
*/
YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size )
{
YY_BUFFER_STATE b;
if ( size < 2 ||
base[size-2] != YY_END_OF_BUFFER_CHAR ||
base[size-1] != YY_END_OF_BUFFER_CHAR )
/* They forgot to leave room for the EOB's. */
return 0;
 
b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) );
if ( ! b )
YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
 
b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
b->yy_buf_pos = b->yy_ch_buf = base;
b->yy_is_our_buffer = 0;
b->yy_input_file = 0;
b->yy_n_chars = b->yy_buf_size;
b->yy_is_interactive = 0;
b->yy_at_bol = 1;
b->yy_fill_buffer = 0;
b->yy_buffer_status = YY_BUFFER_NEW;
 
yy_switch_to_buffer(b );
 
return b;
}
 
/** Setup the input buffer state to scan a string. The next call to yylex() will
* scan from a @e copy of @a str.
* @param str a NUL-terminated string to scan
*
* @return the newly allocated buffer state object.
* @note If you want to scan bytes that may contain NUL values, then use
* yy_scan_bytes() instead.
*/
YY_BUFFER_STATE yy_scan_string (yyconst char * yystr )
{
return yy_scan_bytes(yystr,strlen(yystr) );
}
 
/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
* scan from a @e copy of @a bytes.
* @param bytes the byte buffer to scan
* @param len the number of bytes in the buffer pointed to by @a bytes.
*
* @return the newly allocated buffer state object.
*/
YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len )
{
YY_BUFFER_STATE b;
char *buf;
yy_size_t n;
int i;
/* Get memory for full buffer, including space for trailing EOB's. */
n = _yybytes_len + 2;
buf = (char *) yyalloc(n );
if ( ! buf )
YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
 
for ( i = 0; i < _yybytes_len; ++i )
buf[i] = yybytes[i];
 
buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
 
b = yy_scan_buffer(buf,n );
if ( ! b )
YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
 
/* It's okay to grow etc. this buffer, and we should throw it
* away when we're done.
*/
b->yy_is_our_buffer = 1;
 
return b;
}
 
#ifndef YY_EXIT_FAILURE
#define YY_EXIT_FAILURE 2
#endif
 
static void yy_fatal_error (yyconst char* msg )
{
(void) fprintf( stderr, "%s\n", msg );
exit( YY_EXIT_FAILURE );
}
 
/* Redefine yyless() so it works in section 3 code. */
 
#undef yyless
#define yyless(n) \
do \
{ \
/* Undo effects of setting up yytext. */ \
int yyless_macro_arg = (n); \
YY_LESS_LINENO(yyless_macro_arg);\
yytext[yyleng] = (yy_hold_char); \
(yy_c_buf_p) = yytext + yyless_macro_arg; \
(yy_hold_char) = *(yy_c_buf_p); \
*(yy_c_buf_p) = '\0'; \
yyleng = yyless_macro_arg; \
} \
while ( 0 )
 
/* Accessor methods (get/set functions) to struct members. */
 
/** Get the current line number.
*
*/
int yyget_lineno (void)
{
return yylineno;
}
 
/** Get the input stream.
*
*/
FILE *yyget_in (void)
{
return yyin;
}
 
/** Get the output stream.
*
*/
FILE *yyget_out (void)
{
return yyout;
}
 
/** Get the length of the current token.
*
*/
int yyget_leng (void)
{
return yyleng;
}
 
/** Get the current token.
*
*/
 
char *yyget_text (void)
{
return yytext;
}
 
/** Set the current line number.
* @param line_number
*
*/
void yyset_lineno (int line_number )
{
yylineno = line_number;
}
 
/** Set the input stream. This does not discard the current
* input buffer.
* @param in_str A readable stream.
*
* @see yy_switch_to_buffer
*/
void yyset_in (FILE * in_str )
{
yyin = in_str ;
}
 
void yyset_out (FILE * out_str )
{
yyout = out_str ;
}
 
int yyget_debug (void)
{
return yy_flex_debug;
}
 
void yyset_debug (int bdebug )
{
yy_flex_debug = bdebug ;
}
 
static int yy_init_globals (void)
{
/* Initialization is the same as for the non-reentrant scanner.
* This function is called from yylex_destroy(), so don't allocate here.
*/
 
(yy_buffer_stack) = 0;
(yy_buffer_stack_top) = 0;
(yy_buffer_stack_max) = 0;
(yy_c_buf_p) = (char *) 0;
(yy_init) = 0;
(yy_start) = 0;
 
/* Defined in main.c */
#ifdef YY_STDINIT
yyin = stdin;
yyout = stdout;
#else
yyin = (FILE *) 0;
yyout = (FILE *) 0;
#endif
 
/* For future reference: Set errno on error, since we are called by
* yylex_init()
*/
return 0;
}
 
/* yylex_destroy is for both reentrant and non-reentrant scanners. */
int yylex_destroy (void)
{
/* Pop the buffer stack, destroying each element. */
while(YY_CURRENT_BUFFER){
yy_delete_buffer(YY_CURRENT_BUFFER );
YY_CURRENT_BUFFER_LVALUE = NULL;
yypop_buffer_state();
}
 
/* Destroy the stack itself. */
yyfree((yy_buffer_stack) );
(yy_buffer_stack) = NULL;
 
/* Reset the globals. This is important in a non-reentrant scanner so the next time
* yylex() is called, initialization will occur. */
yy_init_globals( );
 
return 0;
}
 
/*
* Internal utility routines.
*/
 
#ifndef yytext_ptr
static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
{
register int i;
for ( i = 0; i < n; ++i )
s1[i] = s2[i];
}
#endif
 
#ifdef YY_NEED_STRLEN
static int yy_flex_strlen (yyconst char * s )
{
register int n;
for ( n = 0; s[n]; ++n )
;
 
return n;
}
#endif
 
void *yyalloc (yy_size_t size )
{
return (void *) malloc( size );
}
 
void *yyrealloc (void * ptr, yy_size_t size )
{
/* The cast to (char *) in the following accommodates both
* implementations that use char* generic pointers, and those
* that use void* generic pointers. It works with the latter
* because both ANSI C and C++ allow castless assignment from
* any pointer type to void*, and deal with argument conversions
* as though doing an assignment.
*/
return (void *) realloc( (char *) ptr, size );
}
 
void yyfree (void * ptr )
{
free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
}
 
#define YYTABLES_NAME "yytables"
 
#line 88 "arith_lex.l"
 
 
 
void
arith_lex_reset() {
#ifdef YY_NEW_FILE
YY_NEW_FILE;
#endif
}
 
/trunk/uspace/app/ash/nodetypes
0,0 → 1,147
# $NetBSD: nodetypes,v 1.9 1999/02/04 16:17:39 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. All advertising materials mentioning features or use of this software
# must display the following acknowledgement:
# This product includes software developed by the University of
# California, Berkeley and its contributors.
# 4. Neither the name of the University nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# @(#)nodetypes 8.2 (Berkeley) 5/4/95
 
# This file describes the nodes used in parse trees. Unindented lines
# contain a node type followed by a structure tag. Subsequent indented
# lines specify the fields of the structure. Several node types can share
# the same structure, in which case the fields of the structure should be
# specified only once.
#
# A field of a structure is described by the name of the field followed
# by a type. The currently implemented types are:
# nodeptr - a pointer to a node
# nodelist - a pointer to a list of nodes
# string - a pointer to a nul terminated string
# int - an integer
# other - any type that can be copied by assignment
# temp - a field that doesn't have to be copied when the node is copied
# The last two types should be followed by the text of a C declaration for
# the field.
 
NSEMI nbinary # two commands separated by a semicolon
type int
ch1 nodeptr # the first child
ch2 nodeptr # the second child
 
NCMD ncmd # a simple command
type int
backgnd int # set to run command in background
args nodeptr # the arguments
redirect nodeptr # list of file redirections
 
NPIPE npipe # a pipeline
type int
backgnd int # set to run pipeline in background
cmdlist nodelist # the commands in the pipeline
 
NREDIR nredir # redirection (of a compex command)
type int
n nodeptr # the command
redirect nodeptr # list of file redirections
 
NBACKGND nredir # run command in background
NSUBSHELL nredir # run command in a subshell
 
NAND nbinary # the && operator
NOR nbinary # the || operator
 
NIF nif # the if statement. Elif clauses are handled
type int # using multiple if nodes.
test nodeptr # if test
ifpart nodeptr # then ifpart
elsepart nodeptr # else elsepart
 
NWHILE nbinary # the while statement. First child is the test
NUNTIL nbinary # the until statement
 
NFOR nfor # the for statement
type int
args nodeptr # for var in args
body nodeptr # do body; done
var string # the for variable
 
NCASE ncase # a case statement
type int
expr nodeptr # the word to switch on
cases nodeptr # the list of cases (NCLIST nodes)
 
NCLIST nclist # a case
type int
next nodeptr # the next case in list
pattern nodeptr # list of patterns for this case
body nodeptr # code to execute for this case
 
 
NDEFUN narg # define a function. The "next" field contains
# the body of the function.
 
NARG narg # represents a word
type int
next nodeptr # next word in list
text string # the text of the word
backquote nodelist # list of commands in back quotes
 
NTO nfile # fd> fname
NFROM nfile # fd< fname
NFROMTO nfile # fd<> fname
NAPPEND nfile # fd>> fname
NTOOV nfile # fd>| fname
type int
next nodeptr # next redirection in list
fd int # file descriptor being redirected
fname nodeptr # file name, in a NARG node
expfname temp char *expfname # actual file name
 
NTOFD ndup # fd<&dupfd
NFROMFD ndup # fd>&dupfd
type int
next nodeptr # next redirection in list
fd int # file descriptor being redirected
dupfd int # file descriptor to duplicate
vname nodeptr # file name if fd>&$var
 
 
NHERE nhere # fd<<\!
NXHERE nhere # fd<<!
type int
next nodeptr # next redirection in list
fd int # file descriptor being redirected
doc nodeptr # input to command (NARG node)
 
NNOT nnot # ! command (actually pipeline)
type int
com nodeptr
/trunk/uspace/app/ash/error.c
0,0 → 1,301
/* $NetBSD: error.c,v 1.23 2000/07/03 03:26:19 matt 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
 
#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.23 2000/07/03 03:26:19 matt Exp $");
#endif
#endif /* not lint */
 
/*
* Errors and exceptions.
*/
 
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
 
#include "shell.h"
#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;
char *commandname;
 
 
static void exverror (int, const char *, va_list)
__attribute__((__noreturn__));
 
/*
* 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(e)
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() {
sigset_t sigset;
 
if (suppressint) {
intpending++;
return;
}
intpending = 0;
sigemptyset(&sigset);
sigprocmask(SIG_SETMASK, &sigset, NULL);
if (rootshell && iflag)
exraise(EXINT);
else {
signal(SIGINT, SIG_DFL);
raise(SIGINT);
}
/* NOTREACHED */
}
 
 
/*
* Exverror is called to raise the error exception. If the first argument
* is not NULL then error prints an error message using printf style
* formatting. It then raises the error exception.
*/
static void
exverror(cond, msg, ap)
int cond;
const char *msg;
va_list ap;
{
CLEAR_PENDING_INT;
INTOFF;
 
#ifdef DEBUG
if (msg)
TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
else
TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
#endif
if (msg) {
if (commandname)
outfmt(&errout, "%s: ", commandname);
doformat(&errout, msg, ap);
out2c('\n');
}
flushall();
exraise(cond);
/* NOTREACHED */
}
 
 
#ifdef __STDC__
void
error(const char *msg, ...)
#else
void
error(va_alist)
va_dcl
#endif
{
#ifndef __STDC__
const char *msg;
#endif
va_list ap;
#ifdef __STDC__
va_start(ap, msg);
#else
va_start(ap);
msg = va_arg(ap, const char *);
#endif
exverror(EXERROR, msg, ap);
/* NOTREACHED */
va_end(ap);
}
 
 
#ifdef __STDC__
void
exerror(int cond, const char *msg, ...)
#else
void
exerror(va_alist)
va_dcl
#endif
{
#ifndef __STDC__
int cond;
const char *msg;
#endif
va_list ap;
#ifdef __STDC__
va_start(ap, msg);
#else
va_start(ap);
cond = va_arg(ap, int);
msg = va_arg(ap, const char *);
#endif
exverror(cond, msg, ap);
/* NOTREACHED */
va_end(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" },
{ 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" },
{ EEXIST, E_CREAT,"file exists" },
#ifdef notdef
{ 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 SYSV
{ 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
{ 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(e, action)
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;
}
/trunk/uspace/app/ash/Makefile
0,0 → 1,177
#
# Copyright (c) 2005 Martin Decky
# 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 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.
# - 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.
#
 
include ../../../version
include ../../Makefile.config
 
## Setup toolchain
#
 
LIBC_PREFIX = ../../lib/libc
SOFTINT_PREFIX = ../../lib/softint
include $(LIBC_PREFIX)/Makefile.toolchain
 
CFLAGS += \
-DSHELL \
-I. \
-DNO_HISTORY \
-DBSD=1 \
-DSMALL \
-D_GNU_SOURCE \
-DGLOB_BROKEN \
-D__COPYRIGHT\(x\)= \
-D__RCSID\(x\)=
# -D_DIAGASSERT\(x\)= \
# -DHETIO
 
LIBS = $(LIBC_PREFIX)/libc.a
DEFS += -DRELEASE=\"$(RELEASE)\"
 
ifdef REVISION
DEFS += "-DREVISION=\"$(REVISION)\""
endif
 
ifdef TIMESTAMP
DEFS += "-DTIMESTAMP=\"$(TIMESTAMP)\""
endif
 
## Sources
#
 
OUTPUT = sh
SHSRCS = \
fake.c \
alias.c \
cd.c \
bltin/echo.c \
error.c \
eval.c \
exec.c \
expand.c \
hetio.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 \
setmode.c \
bltin/test.c \
bltin/times.c \
trap.c \
var.c
 
GENSRCS = \
builtins.c \
init.c \
nodes.c \
syntax.c \
signames.c
# lex.yy.c \
# arith.c \
# arith.h \
 
GENHEADERS = \
token.h \
nodes.h \
syntax.h \
builtins.h
 
SOURCES = ${SHSRCS} ${GENSRCS}
 
OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
 
.PHONY: all clean depend disasm
 
all: $(OUTPUT) disasm
 
-include Makefile.depend
 
BUILD_TOOLS = \
mkinit \
mknodes \
mksyntax
 
build-tools: $(BUILD_TOOLS)
$(CC) -c $< -o $@
 
.ORDER: builtins.c builtins.h
builtins.c builtins.h: mkbuiltins builtins.def
sh mkbuiltins shell.h builtins.def `pwd`
 
INIT_DEPS = alias.c eval.c exec.c input.c jobs.c options.c parser.c \
redir.c trap.c var.c output.c
init.c: mkinit $(INIT_DEPS)
./mkinit $(INIT_DEPS)
 
signames.c: mksignames
./mksignames
 
nodes.c nodes.h: mknodes nodetypes nodes.c.pat
./mknodes ./nodetypes ./nodes.c.pat
 
syntax.c syntax.h: mksyntax
./mksyntax
 
#arith.c arith.h: arith.y
# yacc -d arith.y
# mv y.tab.h arith.h
# mv y.tab.c arith.c
 
token.h: mktokens
sh ./mktokens
 
clean:
-rm -f $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm Makefile.depend
-rm -f $(GENSRCS) $(GENHEADERS) $(OBJECTS) $(BUILD_TOOLS)
 
depend:
$(CC) $(DEFS) $(CFLAGS) -M $(SOURCES) $(GENHEADERS) > Makefile.depend
 
$(OUTPUT): $(GENSRCS) $(GENHEADERS) $(OBJECTS) $(LIBS)
$(LD) -T $(LIBC_PREFIX)/arch/$(ARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
 
disasm:
$(OBJDUMP) -d $(OUTPUT) >$(OUTPUT).disasm
 
%.o: %.S
$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@
 
%.o: %.s
$(AS) $(AFLAGS) $< -o $@
 
%.o: %.c
$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
/trunk/uspace/app/ash/error.h
0,0 → 1,109
/* $NetBSD: error.h,v 1.13 1999/07/09 03:05:49 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)error.h 8.2 (Berkeley) 5/4/95
*/
 
/*
* Types of operations (passed to the errmsg routine).
*/
 
#define E_OPEN 01 /* opening a file */
#define E_CREAT 02 /* creating a file */
#define E_EXEC 04 /* executing a program */
 
 
/*
* We enclose jmp_buf in a structure so that we can declare pointers to
* jump locations. The global variable handler contains the location to
* jump to when an exception occurs, and the global variable exception
* contains a code identifying the exeception. To implement nested
* exception handlers, the user should save the value of handler on entry
* to an inner scope, set handler to point to a jmploc structure for the
* inner scope, and restore handler on exit from the scope.
*/
 
#include <setjmp.h>
#include "fake.h"
 
struct jmploc {
jmp_buf loc;
};
 
extern struct jmploc *handler;
extern int exception;
 
/* exceptions */
#define EXINT 0 /* SIGINT received */
#define EXERROR 1 /* a generic error */
#define EXSHELLPROC 2 /* execute a shell procedure */
#define EXEXEC 3 /* command execution failed */
 
 
/*
* These macros allow the user to suspend the handling of interrupt signals
* over a period of time. This is similar to SIGHOLD to or sigblock, but
* much more efficient and portable. (But hacking the kernel is so much
* more fun than worrying about efficiency and portability. :-))
*/
 
extern volatile int suppressint;
extern volatile int intpending;
extern char *commandname; /* name of command--printed on error */
 
#define INTOFF suppressint++
#define INTON { if (--suppressint == 0 && intpending) onint(); }
#define FORCEINTON {suppressint = 0; if (intpending) onint();}
#define CLEAR_PENDING_INT intpending = 0
#define int_pending() intpending
 
void exraise (int) __attribute__((__noreturn__));
void onint (void);
void error (const char *, ...) __attribute__((__noreturn__));
void exerror (int, const char *, ...) __attribute__((__noreturn__));
const char *errmsg (int, int);
 
 
/*
* BSD setjmp saves the signal mask, which violates ANSI C and takes time,
* so we use _setjmp instead.
*/
 
#if defined(BSD) && !defined(__SVR4) && !defined(__GLIBC__)
#define setjmp(jmploc) _setjmp(jmploc)
#define longjmp(jmploc, val) _longjmp(jmploc, val)
#endif
/trunk/uspace/app/ash/machdep.h
0,0 → 1,53
/* $NetBSD: machdep.h,v 1.8 1995/05/11 21:29:21 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)machdep.h 8.2 (Berkeley) 5/4/95
*/
 
/*
* Most machines require the value returned from malloc to be aligned
* in some way. The following macro will get this right on many machines.
*/
 
#ifndef ALIGN
union align {
int i;
char *cp;
};
 
#define ALIGN(nbytes) (((nbytes) + sizeof(union align) - 1) & ~(sizeof(union align) - 1))
#endif
/trunk/uspace/app/ash/TOUR
0,0 → 1,357
# $NetBSD: TOUR,v 1.8 1996/10/16 14:24:56 christos Exp $
# @(#)TOUR 8.1 (Berkeley) 5/31/93
 
NOTE -- This is the original TOUR paper distributed with ash and
does not represent the current state of the shell. It is provided anyway
since it provides helpful information for how the shell is structured,
but be warned that things have changed -- the current shell is
still under development.
 
================================================================
 
A Tour through Ash
 
Copyright 1989 by Kenneth Almquist.
 
 
DIRECTORIES: The subdirectory bltin contains commands which can
be compiled stand-alone. The rest of the source is in the main
ash directory.
 
SOURCE CODE GENERATORS: Files whose names begin with "mk" are
programs that generate source code. A complete list of these
programs is:
 
program intput files generates
------- ------------ ---------
mkbuiltins builtins builtins.h builtins.c
mkinit *.c init.c
mknodes nodetypes nodes.h nodes.c
mksignames - signames.h signames.c
mksyntax - syntax.h syntax.c
mktokens - token.h
bltin/mkexpr unary_op binary_op operators.h operators.c
 
There are undoubtedly too many of these. Mkinit searches all the
C source files for entries looking like:
 
INIT {
x = 1; /* executed during initialization */
}
 
RESET {
x = 2; /* executed when the shell does a longjmp
back to the main command loop */
}
 
SHELLPROC {
x = 3; /* executed when the shell runs a shell procedure */
}
 
It pulls this code out into routines which are when particular
events occur. The intent is to improve modularity by isolating
the information about which modules need to be explicitly
initialized/reset within the modules themselves.
 
Mkinit recognizes several constructs for placing declarations in
the init.c file.
INCLUDE "file.h"
includes a file. The storage class MKINIT makes a declaration
available in the init.c file, for example:
MKINIT int funcnest; /* depth of function calls */
MKINIT alone on a line introduces a structure or union declara-
tion:
MKINIT
struct redirtab {
short renamed[10];
};
Preprocessor #define statements are copied to init.c without any
special action to request this.
 
INDENTATION: The ash source is indented in multiples of six
spaces. The only study that I have heard of on the subject con-
cluded that the optimal amount to indent is in the range of four
to six spaces. I use six spaces since it is not too big a jump
from the widely used eight spaces. If you really hate six space
indentation, use the adjind (source included) program to change
it to something else.
 
EXCEPTIONS: Code for dealing with exceptions appears in
exceptions.c. The C language doesn't include exception handling,
so I implement it using setjmp and longjmp. The global variable
exception contains the type of exception. EXERROR is raised by
calling error. EXINT is an interrupt. EXSHELLPROC is an excep-
tion which is raised when a shell procedure is invoked. The pur-
pose of EXSHELLPROC is to perform the cleanup actions associated
with other exceptions. After these cleanup actions, the shell
can interpret a shell procedure itself without exec'ing a new
copy of the shell.
 
INTERRUPTS: In an interactive shell, an interrupt will cause an
EXINT exception to return to the main command loop. (Exception:
EXINT is not raised if the user traps interrupts using the trap
command.) The INTOFF and INTON macros (defined in exception.h)
provide uninterruptable critical sections. Between the execution
of INTOFF and the execution of INTON, interrupt signals will be
held for later delivery. INTOFF and INTON can be nested.
 
MEMALLOC.C: Memalloc.c defines versions of malloc and realloc
which call error when there is no memory left. It also defines a
stack oriented memory allocation scheme. Allocating off a stack
is probably more efficient than allocation using malloc, but the
big advantage is that when an exception occurs all we have to do
to free up the memory in use at the time of the exception is to
restore the stack pointer. The stack is implemented using a
linked list of blocks.
 
STPUTC: If the stack were contiguous, it would be easy to store
strings on the stack without knowing in advance how long the
string was going to be:
p = stackptr;
*p++ = c; /* repeated as many times as needed */
stackptr = p;
The folloing three macros (defined in memalloc.h) perform these
operations, but grow the stack if you run off the end:
STARTSTACKSTR(p);
STPUTC(c, p); /* repeated as many times as needed */
grabstackstr(p);
 
We now start a top-down look at the code:
 
MAIN.C: The main routine performs some initialization, executes
the user's profile if necessary, and calls cmdloop. Cmdloop is
repeatedly parses and executes commands.
 
OPTIONS.C: This file contains the option processing code. It is
called from main to parse the shell arguments when the shell is
invoked, and it also contains the set builtin. The -i and -j op-
tions (the latter turns on job control) require changes in signal
handling. The routines setjobctl (in jobs.c) and setinteractive
(in trap.c) are called to handle changes to these options.
 
PARSING: The parser code is all in parser.c. A recursive des-
cent parser is used. Syntax tables (generated by mksyntax) are
used to classify characters during lexical analysis. There are
three tables: one for normal use, one for use when inside single
quotes, and one for use when inside double quotes. The tables
are machine dependent because they are indexed by character vari-
ables and the range of a char varies from machine to machine.
 
PARSE OUTPUT: The output of the parser consists of a tree of
nodes. The various types of nodes are defined in the file node-
types.
 
Nodes of type NARG are used to represent both words and the con-
tents of here documents. An early version of ash kept the con-
tents of here documents in temporary files, but keeping here do-
cuments in memory typically results in significantly better per-
formance. It would have been nice to make it an option to use
temporary files for here documents, for the benefit of small
machines, but the code to keep track of when to delete the tem-
porary files was complex and I never fixed all the bugs in it.
(AT&T has been maintaining the Bourne shell for more than ten
years, and to the best of my knowledge they still haven't gotten
it to handle temporary files correctly in obscure cases.)
 
The text field of a NARG structure points to the text of the
word. The text consists of ordinary characters and a number of
special codes defined in parser.h. The special codes are:
 
CTLVAR Variable substitution
CTLENDVAR End of variable substitution
CTLBACKQ Command substitution
CTLBACKQ|CTLQUOTE Command substitution inside double quotes
CTLESC Escape next character
 
A variable substitution contains the following elements:
 
CTLVAR type name '=' [ alternative-text CTLENDVAR ]
 
The type field is a single character specifying the type of sub-
stitution. The possible types are:
 
VSNORMAL $var
VSMINUS ${var-text}
VSMINUS|VSNUL ${var:-text}
VSPLUS ${var+text}
VSPLUS|VSNUL ${var:+text}
VSQUESTION ${var?text}
VSQUESTION|VSNUL ${var:?text}
VSASSIGN ${var=text}
VSASSIGN|VSNUL ${var=text}
 
In addition, the type field will have the VSQUOTE flag set if the
variable is enclosed in double quotes. The name of the variable
comes next, terminated by an equals sign. If the type is not
VSNORMAL, then the text field in the substitution follows, ter-
minated by a CTLENDVAR byte.
 
Commands in back quotes are parsed and stored in a linked list.
The locations of these commands in the string are indicated by
CTLBACKQ and CTLBACKQ+CTLQUOTE characters, depending upon whether
the back quotes were enclosed in double quotes.
 
The character CTLESC escapes the next character, so that in case
any of the CTL characters mentioned above appear in the input,
they can be passed through transparently. CTLESC is also used to
escape '*', '?', '[', and '!' characters which were quoted by the
user and thus should not be used for file name generation.
 
CTLESC characters have proved to be particularly tricky to get
right. In the case of here documents which are not subject to
variable and command substitution, the parser doesn't insert any
CTLESC characters to begin with (so the contents of the text
field can be written without any processing). Other here docu-
ments, and words which are not subject to splitting and file name
generation, have the CTLESC characters removed during the vari-
able and command substitution phase. Words which are subject
splitting and file name generation have the CTLESC characters re-
moved as part of the file name phase.
 
EXECUTION: Command execution is handled by the following files:
eval.c The top level routines.
redir.c Code to handle redirection of input and output.
jobs.c Code to handle forking, waiting, and job control.
exec.c Code to to path searches and the actual exec sys call.
expand.c Code to evaluate arguments.
var.c Maintains the variable symbol table. Called from expand.c.
 
EVAL.C: Evaltree recursively executes a parse tree. The exit
status is returned in the global variable exitstatus. The alter-
native entry evalbackcmd is called to evaluate commands in back
quotes. It saves the result in memory if the command is a buil-
tin; otherwise it forks off a child to execute the command and
connects the standard output of the child to a pipe.
 
JOBS.C: To create a process, you call makejob to return a job
structure, and then call forkshell (passing the job structure as
an argument) to create the process. Waitforjob waits for a job
to complete. These routines take care of process groups if job
control is defined.
 
REDIR.C: Ash allows file descriptors to be redirected and then
restored without forking off a child process. This is accom-
plished by duplicating the original file descriptors. The redir-
tab structure records where the file descriptors have be dupli-
cated to.
 
EXEC.C: The routine find_command locates a command, and enters
the command in the hash table if it is not already there. The
third argument specifies whether it is to print an error message
if the command is not found. (When a pipeline is set up,
find_command is called for all the commands in the pipeline be-
fore any forking is done, so to get the commands into the hash
table of the parent process. But to make command hashing as
transparent as possible, we silently ignore errors at that point
and only print error messages if the command cannot be found
later.)
 
The routine shellexec is the interface to the exec system call.
 
EXPAND.C: Arguments are processed in three passes. The first
(performed by the routine argstr) performs variable and command
substitution. The second (ifsbreakup) performs word splitting
and the third (expandmeta) performs file name generation. If the
"/u" directory is simulated, then when "/u/username" is replaced
by the user's home directory, the flag "didudir" is set. This
tells the cd command that it should print out the directory name,
just as it would if the "/u" directory were implemented using
symbolic links.
 
VAR.C: Variables are stored in a hash table. Probably we should
switch to extensible hashing. The variable name is stored in the
same string as the value (using the format "name=value") so that
no string copying is needed to create the environment of a com-
mand. Variables which the shell references internally are preal-
located so that the shell can reference the values of these vari-
ables without doing a lookup.
 
When a program is run, the code in eval.c sticks any environment
variables which precede the command (as in "PATH=xxx command") in
the variable table as the simplest way to strip duplicates, and
then calls "environment" to get the value of the environment.
There are two consequences of this. First, if an assignment to
PATH precedes the command, the value of PATH before the assign-
ment must be remembered and passed to shellexec. Second, if the
program turns out to be a shell procedure, the strings from the
environment variables which preceded the command must be pulled
out of the table and replaced with strings obtained from malloc,
since the former will automatically be freed when the stack (see
the entry on memalloc.c) is emptied.
 
BUILTIN COMMANDS: The procedures for handling these are scat-
tered throughout the code, depending on which location appears
most appropriate. They can be recognized because their names al-
ways end in "cmd". The mapping from names to procedures is
specified in the file builtins, which is processed by the mkbuil-
tins command.
 
A builtin command is invoked with argc and argv set up like a
normal program. A builtin command is allowed to overwrite its
arguments. Builtin routines can call nextopt to do option pars-
ing. This is kind of like getopt, but you don't pass argc and
argv to it. Builtin routines can also call error. This routine
normally terminates the shell (or returns to the main command
loop if the shell is interactive), but when called from a builtin
command it causes the builtin command to terminate with an exit
status of 2.
 
The directory bltins contains commands which can be compiled in-
dependently but can also be built into the shell for efficiency
reasons. The makefile in this directory compiles these programs
in the normal fashion (so that they can be run regardless of
whether the invoker is ash), but also creates a library named
bltinlib.a which can be linked with ash. The header file bltin.h
takes care of most of the differences between the ash and the
stand-alone environment. The user should call the main routine
"main", and #define main to be the name of the routine to use
when the program is linked into ash. This #define should appear
before bltin.h is included; bltin.h will #undef main if the pro-
gram is to be compiled stand-alone.
 
CD.C: This file defines the cd and pwd builtins. The pwd com-
mand runs /bin/pwd the first time it is invoked (unless the user
has already done a cd to an absolute pathname), but then
remembers the current directory and updates it when the cd com-
mand is run, so subsequent pwd commands run very fast. The main
complication in the cd command is in the docd command, which
resolves symbolic links into actual names and informs the user
where the user ended up if he crossed a symbolic link.
 
SIGNALS: Trap.c implements the trap command. The routine set-
signal figures out what action should be taken when a signal is
received and invokes the signal system call to set the signal ac-
tion appropriately. When a signal that a user has set a trap for
is caught, the routine "onsig" sets a flag. The routine dotrap
is called at appropriate points to actually handle the signal.
When an interrupt is caught and no trap has been set for that
signal, the routine "onint" in error.c is called.
 
OUTPUT: Ash uses it's own output routines. There are three out-
put structures allocated. "Output" represents the standard out-
put, "errout" the standard error, and "memout" contains output
which is to be stored in memory. This last is used when a buil-
tin command appears in backquotes, to allow its output to be col-
lected without doing any I/O through the UNIX operating system.
The variables out1 and out2 normally point to output and errout,
respectively, but they are set to point to memout when appropri-
ate inside backquotes.
 
INPUT: The basic input routine is pgetc, which reads from the
current input file. There is a stack of input files; the current
input file is the top file on this stack. The code allows the
input to come from a string rather than a file. (This is for the
-c option and the "." and eval builtin commands.) The global
variable plinno is saved and restored when files are pushed and
popped from the stack. The parser routines store the number of
the current line in this variable.
 
DEBUGGING: If DEBUG is defined in shell.h, then the shell will
write debugging information to the file $HOME/trace. Most of
this is done using the TRACE macro, which takes a set of printf
arguments inside two sets of parenthesis. Example:
"TRACE(("n=%d0, n))". The double parenthesis are necessary be-
cause the preprocessor can't handle functions with a variable
number of arguments. Defining DEBUG also causes the shell to
generate a core dump if it is sent a quit signal. The tracing
code is in show.c.
/trunk/uspace/app/ash/hetio.c
0,0 → 1,378
/*
* Termios command line History and Editting for NetBSD sh (ash)
* Copyright (c) 1999
* Main code: Adam Rogoyski <rogoyski@cs.utexas.edu>
* Etc: Dave Cinege <dcinege@psychosis.com>
*
* You may use this code as you wish, so long as the original author(s)
* are attributed in any redistributions of the source code.
* This code is 'as is' with no warranty.
* This code may safely be consumed by a BSD or GPL license.
*
* v 0.5 19990328 Initial release
*
* Future plans: Simple file and path name completion. (like BASH)
*
*/
 
/*
Usage and Known bugs:
Terminal key codes are not extensive, and more will probably
need to be added. This version was created on Debian GNU/Linux 2.x.
Delete, Backspace, Home, End, and the arrow keys were tested
to work in an Xterm and console. Ctrl-A also works as Home.
Ctrl-E also works as End. The binary size increase is <3K.
Editting will not display correctly for lines greater then the
terminal width. (more then one line.) However, history will.
*/
 
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <ctype.h>
#include <sys/ioctl.h>
 
#include "input.h"
#include "output.h"
 
#ifdef HETIO
 
#include "hetio.h"
 
#define MAX_HISTORY 15 /* Maximum length of the linked list for the command line history */
 
#define ESC 27
#define DEL 127
 
static struct history *his_front = NULL; /* First element in command line list */
static struct history *his_end = NULL; /* Last element in command line list */
static struct termios old_term, new_term; /* Current termio and the previous termio before starting ash */
 
static int history_counter = 0; /* Number of commands in history list */
static int reset_term = 0; /* Set to true if the terminal needs to be reset upon exit */
//static int hetio_inter = 0;
int hetio_inter = 0;
 
struct history
{
char *s;
struct history *p;
struct history *n;
};
 
 
void input_delete (int);
void input_home (int *);
void input_end (int *, int);
void input_backspace (int *, int *);
 
 
 
void hetio_init(void)
{
hetio_inter = 1;
}
 
 
void hetio_reset_term(void)
{
if (reset_term)
tcsetattr(1, TCSANOW, &old_term);
}
 
 
void setIO(struct termios *new, struct termios *old) /* Set terminal IO to canonical mode, and save old term settings. */
{
tcgetattr(0, old);
memcpy(new, old, sizeof(*new));
new->c_cc[VMIN] = 1;
new->c_cc[VTIME] = 0;
new->c_lflag &= ~ICANON; /* unbuffered input */
new->c_lflag &= ~ECHO;
tcsetattr(0, TCSANOW, new);
}
 
void input_home(int *cursor) /* Command line input routines */
{
while (*cursor > 0) {
out1c('\b');
--*cursor;
}
flushout(&output);
}
 
 
void input_delete(int cursor)
{
int j = 0;
 
memmove(parsenextc + cursor, parsenextc + cursor + 1,
BUFSIZ - cursor - 1);
for (j = cursor; j < (BUFSIZ - 1); j++) {
if (!*(parsenextc + j))
break;
else
out1c(*(parsenextc + j));
}
 
out1str(" \b");
while (j-- > cursor)
out1c('\b');
flushout(&output);
}
 
 
void input_end(int *cursor, int len)
{
while (*cursor < len) {
out1str("\033[C");
++*cursor;
}
flushout(&output);
}
 
 
void
input_backspace(int *cursor, int *len)
{
int j = 0;
 
if (*cursor > 0) {
out1str("\b \b");
--*cursor;
memmove(parsenextc + *cursor, parsenextc + *cursor + 1,
BUFSIZ - *cursor + 1);
for (j = *cursor; j < (BUFSIZ - 1); j++) {
if (!*(parsenextc + j))
break;
else
out1c(*(parsenextc + j));
}
out1str(" \b");
while (j-- > *cursor)
out1c('\b');
--*len;
flushout(&output);
}
}
 
int hetio_read_input(int fd)
{
int nr = 0;
 
if (!hetio_inter) { /* Are we an interactive shell? */
return -255;
} else {
int len = 0;
int j = 0;
int cursor = 0;
int break_out = 0;
int ret = 0;
char c = 0;
struct history *hp = his_end;
 
if (!reset_term) {
setIO(&new_term, &old_term);
reset_term = 1;
} else {
tcsetattr(0, TCSANOW, &new_term);
}
memset(parsenextc, 0, BUFSIZ);
while (1) {
if ((ret = read(fd, &c, 1)) < 1)
return ret;
switch (c) {
case 1: /* Control-A Beginning of line */
input_home(&cursor);
break;
case 5: /* Control-E EOL */
input_end(&cursor, len);
break;
case 4: /* Control-D */
#ifndef CTRL_D_DELETE
return 0;
#else
if (cursor != len) {
input_delete(cursor);
len--;
}
break;
#endif
case '\b': /* Backspace */
case DEL:
input_backspace(&cursor, &len);
break;
case '\n': /* Enter */
*(parsenextc + len++ + 1) = c;
out1c(c);
flushout(&output);
break_out = 1;
break;
case ESC: /* escape sequence follows */
if ((ret = read(fd, &c, 1)) < 1)
return ret;
if (c == '[' || c == 'O' ) { /* 91 */
if ((ret = read(fd, &c, 1)) < 1)
return ret;
switch (c) {
case 'A':
if (hp && hp->p) { /* Up */
hp = hp->p;
goto hop;
}
break;
case 'B':
if (hp && hp->n && hp->n->s) { /* Down */
hp = hp->n;
goto hop;
}
break;
 
hop: /* hop */
len = strlen(parsenextc);
 
for (; cursor > 0; cursor--) /* return to begining of line */
out1c('\b');
 
for (j = 0; j < len; j++) /* erase old command */
out1c(' ');
 
for (j = len; j > 0; j--) /* return to begining of line */
out1c('\b');
 
strcpy (parsenextc, hp->s); /* write new command */
len = strlen (hp->s);
out1str(parsenextc);
flushout(&output);
cursor = len;
break;
case 'C': /* Right */
if (cursor < len) {
out1str("\033[C");
cursor++;
flushout(&output);
}
break;
case 'D': /* Left */
if (cursor > 0) {
out1str("\033[D");
cursor--;
flushout(&output);
}
break;
case '3': /* Delete */
if (cursor != len) {
input_delete(cursor);
len--;
}
break;
case 'H': /* Home (xterm) */
case '1': /* Home (Ctrl-A) */
input_home(&cursor);
break;
case 'F': /* End (xterm_ */
case '4': /* End (Ctrl-E) */
input_end(&cursor, len);
break;
}
if (c == '1' || c == '3' || c == '4')
if ((ret = read(fd, &c, 1)) < 1)
return ret; /* read 126 (~) */
}
c = 0;
break;
default: /* If it's regular input, do the normal thing */
if (!isprint(c)) /* Skip non-printable characters */
break;
if (len >= (BUFSIZ - 2)) /* Need to leave space for enter */
break;
len++;
if (cursor == (len - 1)) { /* Append if at the end of the line */
*(parsenextc + cursor) = c;
} else { /* Insert otherwise */
memmove(parsenextc + cursor + 1, parsenextc + cursor,
len - cursor - 1);
*(parsenextc + cursor) = c;
for (j = cursor; j < len; j++)
out1c(*(parsenextc + j));
for (; j > cursor; j--)
out1str("\033[D");
}
cursor++;
out1c(c);
flushout(&output);
break;
}
if (break_out) /* Enter is the command terminator, no more input. */
break;
}
nr = len + 1;
tcsetattr(0, TCSANOW, &old_term);
if (*(parsenextc)) { /* Handle command history log */
struct history *h = his_end;
if (!h) { /* No previous history */
h = his_front = malloc(sizeof (struct history));
h->n = malloc(sizeof (struct history));
h->p = NULL;
h->s = strdup(parsenextc);
 
h->n->p = h;
h->n->n = NULL;
h->n->s = NULL;
his_end = h->n;
history_counter++;
} else { /* Add a new history command */
h->n = malloc(sizeof (struct history));
 
h->n->p = h;
h->n->n = NULL;
h->n->s = NULL;
h->s = strdup(parsenextc);
his_end = h->n;
 
if (history_counter >= MAX_HISTORY) { /* After max history, remove the last known command */
struct history *p = his_front->n;
p->p = NULL;
free(his_front->s);
free(his_front);
his_front = p;
} else {
history_counter++;
}
}
}
}
 
return nr;
}
#endif
/trunk/uspace/app/ash/mktokens
0,0 → 1,96
#!/bin/sh -
# $NetBSD: mktokens,v 1.9 1999/07/09 03:05:50 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. All advertising materials mentioning features or use of this software
# must display the following acknowledgement:
# This product includes software developed by the University of
# California, Berkeley and its contributors.
# 4. Neither the name of the University nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# @(#)mktokens 8.1 (Berkeley) 5/31/93
 
# 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.
 
cat > /tmp/ka$$ <<\!
TEOF 1 end of file
TNL 0 newline
TSEMI 0 ";"
TBACKGND 0 "&"
TAND 0 "&&"
TOR 0 "||"
TPIPE 0 "|"
TLP 0 "("
TRP 1 ")"
TENDCASE 1 ";;"
TENDBQUOTE 1 "`"
TREDIR 0 redirection
TWORD 0 word
TIF 0 "if"
TTHEN 1 "then"
TELSE 1 "else"
TELIF 1 "elif"
TFI 1 "fi"
TWHILE 0 "while"
TUNTIL 0 "until"
TFOR 0 "for"
TDO 1 "do"
TDONE 1 "done"
TBEGIN 0 "{"
TEND 1 "}"
TCASE 0 "case"
TESAC 1 "esac"
TNOT 0 "!"
!
nl=`wc -l /tmp/ka$$`
exec > token.h
awk '{print "#define " $1 " " NR-1}' /tmp/ka$$
echo '
/* Array indicating which tokens mark the end of a list */
const char tokendlist[] = {'
awk '{print "\t" $2 ","}' /tmp/ka$$
echo '};
 
const char *const tokname[] = {'
sed -e 's/"/\\"/g' \
-e 's/[^ ]*[ ][ ]*[^ ]*[ ][ ]*\(.*\)/ "\1",/' \
/tmp/ka$$
echo '};
'
sed 's/"//g' /tmp/ka$$ | awk '
/TIF/{print "#define KWDOFFSET " NR-1; print "";
print "const char *const parsekwd[] = {"}
/TIF/,/neverfound/{print " \"" $3 "\","}'
echo ' 0
};'
 
rm /tmp/ka$$
/trunk/uspace/app/ash/shell.h
0,0 → 1,86
/* $NetBSD: shell.h,v 1.13 2000/05/22 10:18:47 elric 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)shell.h 8.2 (Berkeley) 5/4/95
*/
 
/*
* The follow should be set to reflect the type of system you have:
* JOBS -> 1 if you have Berkeley job control, 0 otherwise.
* 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=2 to compile in and turn on debugging.
*
* When debugging is on, debugging info will be written to $HOME/trace and
* a quit signal will generate a core dump.
*/
 
 
#define JOBS 0
#ifndef BSD
#define BSD 1
#endif
 
//#include "fake.h"
 
#ifdef __STDC__
typedef void *pointer;
#ifndef NULL
#define NULL (void *)0
#endif
#else /* not __STDC__ */
typedef char *pointer;
#ifndef NULL
#define NULL 0
#endif
#endif /* not __STDC__ */
#define STATIC /* empty */
#define MKINIT /* empty */
 
#include <sys/cdefs.h>
 
extern char nullstr[1]; /* null string */
 
 
#ifdef DEBUG
#define TRACE(param) trace param
#else
#define TRACE(param)
#endif
 
/trunk/uspace/app/ash/hetio.h
0,0 → 1,22
/*
* Termios command line History and Editting for NetBSD sh (ash)
* Copyright (c) 1999
* Main code: Adam Rogoyski <rogoyski@cs.utexas.edu>
* Etc: Dave Cinege <dcinege@psychosis.com>
*
* You may use this code as you wish, so long as the original author(s)
* are attributed in any redistributions of the source code.
* This code is 'as is' with no warranty.
* This code may safely be consumed by a BSD or GPL license.
*
* v 0.5 19990328 Initial release
*
* Future plans: Simple file and path name completion. (like BASH)
*
*/
 
void hetio_init(void);
int hetio_read_input(int fd);
void hetio_reset_term(void);
 
extern int hetio_inter;
/trunk/uspace/app/ash/exec.c
0,0 → 1,1181
/* $NetBSD: exec.c,v 1.31 2000/11/01 19:21:41 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
 
#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.31 2000/11/01 19:21:41 christos Exp $");
#endif
#endif /* not lint */
 
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <sysexits.h>
 
/*
* When commands are first encountered, they are entered in a hash table.
* This ensures that a full path search will not have to be done for them
* on each invocation.
*
* We should investigate converting to a linear search, even though that
* would make the command name "hash" a misnomer.
*/
 
#include "shell.h"
#include "main.h"
#include "nodes.h"
#include "parser.h"
#include "redir.h"
#include "eval.h"
#include "exec.h"
#include "builtins.h"
#include "var.h"
#include "options.h"
#include "input.h"
#include "output.h"
#include "syntax.h"
#include "memalloc.h"
#include "error.h"
#include "init.h"
#include "mystring.h"
#include "show.h"
#include "jobs.h"
#include "alias.h"
 
 
#define CMDTABLESIZE 31 /* should be prime */
#define ARB 1 /* actual size determined at run time */
 
 
 
struct tblentry {
struct tblentry *next; /* next entry in hash chain */
union param param; /* definition of builtin function */
short cmdtype; /* index identifying command */
char rehash; /* if set, cd done since entry created */
char cmdname[ARB]; /* name of command */
};
 
 
STATIC struct tblentry *cmdtable[CMDTABLESIZE];
STATIC int builtinloc = -1; /* index in path of %builtin, or -1 */
int exerrno = 0; /* Last exec error */
 
 
STATIC void tryexec (char *, char **, char **);
STATIC void execinterp (char **, char **);
STATIC void printentry (struct tblentry *, int);
STATIC void clearcmdentry (int);
STATIC struct tblentry *cmdlookup (char *, int);
STATIC void delete_cmd_entry (void);
STATIC int describe_command (char *, int);
STATIC int path_change (const char *, int *);
STATIC int is_regular_builtin (const char *);
 
 
 
/*
* Exec a program. Never returns. If you change this routine, you may
* have to change the find_command routine as well.
*/
 
void
shellexec(argv, envp, path, idx)
char **argv, **envp;
const char *path;
int idx;
{
char *cmdname;
int e;
 
if (fd2 >= 0 && fd2 != 2) {
close(fd2);
}
 
if (strchr(argv[0], '/') != NULL) {
tryexec(argv[0], argv, envp);
e = errno;
} else {
e = ENOENT;
while ((cmdname = padvance(&path, argv[0])) != NULL) {
if (--idx < 0 && pathopt == NULL) {
tryexec(cmdname, argv, envp);
if (errno != ENOENT && errno != ENOTDIR)
e = errno;
}
stunalloc(cmdname);
}
}
 
/* Map to POSIX errors */
switch (e) {
case EACCES:
exerrno = 126;
break;
case ENOENT:
exerrno = 127;
break;
default:
exerrno = 2;
break;
}
exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
/* NOTREACHED */
}
 
 
STATIC void
tryexec(cmd, argv, envp)
char *cmd;
char **argv;
char **envp;
{
int e;
#if !defined(BSD) && !defined(linux)
char *p;
#endif
 
#ifdef SYSV
do {
execve(cmd, argv, envp);
} while (errno == EINTR);
#else
execve(cmd, argv, envp);
#endif
e = errno;
if (e == ENOEXEC) {
initshellproc();
setinputfile(cmd, 0);
commandname = arg0 = savestr(argv[0]);
#if !defined(BSD) && !defined(linux)
pgetc(); pungetc(); /* fill up input buffer */
p = parsenextc;
if (parsenleft > 2 && p[0] == '#' && p[1] == '!') {
argv[0] = cmd;
execinterp(argv, envp);
}
#endif
setparam(argv + 1);
exraise(EXSHELLPROC);
}
errno = e;
}
 
 
#if !defined(BSD) && !defined(linux)
/*
* 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(argv, envp)
char **argv, **envp;
{
int n;
char *inp;
char *outp;
char c;
char *p;
char **ap;
char *newargs[NEWARGS];
int i;
char **ap2;
char **new;
 
n = parsenleft - 2;
inp = parsenextc + 2;
ap = newargs;
for (;;) {
while (--n >= 0 && (*inp == ' ' || *inp == '\t'))
inp++;
if (n < 0)
goto bad;
if ((c = *inp++) == '\n')
break;
if (ap == &newargs[NEWARGS])
bad: error("Bad #! line");
STARTSTACKSTR(outp);
do {
STPUTC(c, outp);
} while (--n >= 0 && (c = *inp++) != ' ' && c != '\t' && c != '\n');
STPUTC('\0', outp);
n++, inp--;
*ap++ = grabstackstr(outp);
}
if (ap == newargs + 1) { /* if no args, maybe no exec is needed */
p = newargs[0];
for (;;) {
if (equal(p, "sh") || equal(p, "ash")) {
return;
}
while (*p != '/') {
if (*p == '\0')
goto break2;
p++;
}
p++;
}
break2:;
}
i = (char *)ap - (char *)newargs; /* size in bytes */
if (i == 0)
error("Bad #! line");
for (ap2 = argv ; *ap2++ != NULL ; );
new = ckmalloc(i + ((char *)ap2 - (char *)argv));
ap = newargs, ap2 = new;
while ((i -= sizeof (char **)) >= 0)
*ap2++ = *ap++;
ap = argv;
while (*ap2++ = *ap++);
shellexec(new, envp, pathval(), 0);
/* NOTREACHED */
}
#endif
 
 
 
/*
* Do a path search. The variable path (passed by reference) should be
* set to the start of the path before the first call; padvance will update
* this value as it proceeds. Successive calls to padvance will return
* the possible path expansions in sequence. If an option (indicated by
* a percent sign) appears in the path entry then the global variable
* pathopt will be set to point to it; otherwise pathopt will be set to
* NULL.
*/
 
const char *pathopt;
 
char *
padvance(path, name)
const char **path;
const char *name;
{
const char *p;
char *q;
const char *start;
int len;
 
if (*path == NULL)
return NULL;
start = *path;
for (p = start ; *p && *p != ':' && *p != '%' ; p++);
len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
while (stackblocksize() < len)
growstackblock();
q = stackblock();
if (p != start) {
memcpy(q, start, p - start);
q += p - start;
*q++ = '/';
}
strcpy(q, name);
pathopt = NULL;
if (*p == '%') {
pathopt = ++p;
while (*p && *p != ':') p++;
}
if (*p == ':')
*path = p + 1;
else
*path = NULL;
return stalloc(len);
}
 
 
 
/*** Command hashing code ***/
 
 
int
hashcmd(argc, argv)
int argc;
char **argv;
{
struct tblentry **pp;
struct tblentry *cmdp;
int c;
int verbose;
struct cmdentry entry;
char *name;
 
verbose = 0;
while ((c = nextopt("rv")) != '\0') {
if (c == 'r') {
clearcmdentry(0);
} else if (c == 'v') {
verbose++;
}
}
if (*argptr == NULL) {
for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
if (cmdp->cmdtype != CMDBUILTIN) {
printentry(cmdp, verbose);
}
}
}
return 0;
}
c = 0;
while ((name = *argptr) != NULL) {
if ((cmdp = cmdlookup(name, 0)) != NULL
&& (cmdp->cmdtype == CMDNORMAL
|| (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
delete_cmd_entry();
find_command(name, &entry, DO_ERR, pathval());
if (entry.cmdtype == CMDUNKNOWN) c = 1;
else if (verbose) {
cmdp = cmdlookup(name, 0);
if (cmdp) printentry(cmdp, verbose);
flushall();
}
argptr++;
}
return c;
}
 
 
STATIC void
printentry(cmdp, verbose)
struct tblentry *cmdp;
int verbose;
{
int idx;
const char *path;
char *name;
 
if (cmdp->cmdtype == CMDNORMAL) {
idx = cmdp->param.index;
path = pathval();
do {
name = padvance(&path, cmdp->cmdname);
stunalloc(name);
} while (--idx >= 0);
out1str(name);
} else if (cmdp->cmdtype == CMDBUILTIN) {
out1fmt("builtin %s", cmdp->cmdname);
} else if (cmdp->cmdtype == CMDFUNCTION) {
out1fmt("function %s", cmdp->cmdname);
if (verbose) {
INTOFF;
name = commandtext(cmdp->param.func);
out1c(' ');
out1str(name);
ckfree(name);
INTON;
}
#ifdef DEBUG
} else {
error("internal error: cmdtype %d", cmdp->cmdtype);
#endif
}
if (cmdp->rehash)
out1c('*');
out1c('\n');
}
 
 
 
/*
* Resolve a command name. If you change this routine, you may have to
* change the shellexec routine as well.
*/
 
void
find_command(name, entry, act, path)
char *name;
struct cmdentry *entry;
int act;
const char *path;
{
struct tblentry *cmdp;
int idx;
int prev;
char *fullname;
struct stat statb;
int e;
int i;
int bltin;
int firstchange;
int updatetbl;
int regular;
 
/* If name contains a slash, don't use the 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;
}
 
updatetbl = 1;
if (act & DO_BRUTE) {
firstchange = path_change(path, &bltin);
} else {
bltin = builtinloc;
firstchange = 9999;
}
 
/* If name is in the table, and not invalidated by cd, we're done */
if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
if (cmdp->cmdtype == CMDFUNCTION) {
if (act & DO_NOFUN) {
updatetbl = 0;
} else {
goto success;
}
} else if (act & DO_BRUTE) {
if ((cmdp->cmdtype == CMDNORMAL &&
cmdp->param.index >= firstchange) ||
(cmdp->cmdtype == CMDBUILTIN &&
((builtinloc < 0 && bltin >= 0) ?
bltin : builtinloc) >= firstchange)) {
/* need to recompute the entry */
} else {
goto success;
}
} else {
goto success;
}
}
 
if ((regular = is_regular_builtin(name))) {
if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) {
goto success;
}
} else if (act & DO_BRUTE) {
if (firstchange == 0) {
updatetbl = 0;
}
}
 
/* If %builtin not in path, check for builtin next */
if ((bltin < 0 || regular) && (i = find_builtin(name)) >= 0) {
if (!updatetbl) {
entry->cmdtype = CMDBUILTIN;
entry->u.index = i;
return;
}
INTOFF;
cmdp = cmdlookup(name, 1);
cmdp->cmdtype = CMDBUILTIN;
cmdp->param.index = i;
INTON;
goto success;
}
 
/* We have to search path. */
prev = -1; /* where to start */
if (cmdp && cmdp->rehash) { /* doing a rehash */
if (cmdp->cmdtype == CMDBUILTIN)
prev = builtinloc;
else
prev = cmdp->param.index;
}
 
e = ENOENT;
idx = -1;
loop:
while ((fullname = padvance(&path, name)) != NULL) {
stunalloc(fullname);
idx++;
if (idx >= firstchange) {
updatetbl = 0;
}
if (pathopt) {
if (prefix("builtin", pathopt)) {
if ((i = find_builtin(name)) >= 0) {
if (!updatetbl) {
entry->cmdtype = CMDBUILTIN;
entry->u.index = i;
return;
}
INTOFF;
cmdp = cmdlookup(name, 1);
cmdp->cmdtype = CMDBUILTIN;
cmdp->param.index = i;
INTON;
goto success;
} else {
continue;
}
} else if (!(act & DO_NOFUN) &&
prefix("func", pathopt)) {
/* handled below */
} else {
continue; /* ignore unimplemented options */
}
}
/* if rehash, don't redo absolute path names */
if (fullname[0] == '/' && idx <= prev &&
idx < firstchange) {
if (idx < prev)
continue;
TRACE(("searchexec \"%s\": no change\n", name));
goto success;
}
while (stat(fullname, &statb) < 0) {
#ifdef SYSV
if (errno == EINTR)
continue;
#endif
if (errno != ENOENT && errno != ENOTDIR)
e = errno;
goto loop;
}
e = EACCES; /* if we fail, this will be the error */
if (!S_ISREG(statb.st_mode))
continue;
if (pathopt) { /* this is a %func directory */
stalloc(strlen(fullname) + 1);
readcmdfile(fullname);
if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
error("%s not defined in %s", name, fullname);
stunalloc(fullname);
goto success;
}
#ifdef notdef
if (statb.st_uid == geteuid()) {
if ((statb.st_mode & 0100) == 0)
goto loop;
} else if (statb.st_gid == getegid()) {
if ((statb.st_mode & 010) == 0)
goto loop;
} else {
if ((statb.st_mode & 01) == 0)
goto loop;
}
#endif
TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
/* If we aren't called with DO_BRUTE and cmdp is set, it must
be a function and we're being called with DO_NOFUN */
if (!updatetbl) {
entry->cmdtype = CMDNORMAL;
entry->u.index = idx;
return;
}
INTOFF;
cmdp = cmdlookup(name, 1);
cmdp->cmdtype = CMDNORMAL;
cmdp->param.index = idx;
INTON;
goto success;
}
 
/* We failed. If there was an entry for this command, delete it */
if (cmdp && updatetbl)
delete_cmd_entry();
if (act & DO_ERR)
outfmt(out2, "%s: %s\n", name, errmsg(e, E_EXEC));
entry->cmdtype = CMDUNKNOWN;
return;
 
success:
cmdp->rehash = 0;
entry->cmdtype = cmdp->cmdtype;
entry->u = cmdp->param;
}
 
 
 
/*
* Search the table of builtin commands.
*/
 
int
find_builtin(name)
char *name;
{
const struct builtincmd *bp;
 
for (bp = builtincmd ; bp->name ; bp++) {
if (*bp->name == *name && equal(bp->name, name))
return bp->code;
}
return -1;
}
 
 
 
/*
* Called when a cd is done. Marks all commands so the next time they
* are executed they will be rehashed.
*/
 
void
hashcd() {
struct tblentry **pp;
struct tblentry *cmdp;
 
for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
if (cmdp->cmdtype == CMDNORMAL
|| (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
cmdp->rehash = 1;
}
}
}
 
 
 
/*
* Called before PATH is changed. The argument is the new value of PATH;
* pathval() still returns the old value at this point. Called with
* interrupts off.
*/
 
void
changepath(newval)
const char *newval;
{
int firstchange;
int bltin;
 
firstchange = path_change(newval, &bltin);
if (builtinloc < 0 && bltin >= 0)
builtinloc = bltin; /* zap builtins */
clearcmdentry(firstchange);
builtinloc = bltin;
}
 
 
/*
* Clear out command entries. The argument specifies the first entry in
* PATH which has changed.
*/
 
STATIC void
clearcmdentry(firstchange)
int firstchange;
{
struct tblentry **tblp;
struct tblentry **pp;
struct tblentry *cmdp;
 
INTOFF;
for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
pp = tblp;
while ((cmdp = *pp) != NULL) {
if ((cmdp->cmdtype == CMDNORMAL &&
cmdp->param.index >= firstchange)
|| (cmdp->cmdtype == CMDBUILTIN &&
builtinloc >= firstchange)) {
*pp = cmdp->next;
ckfree(cmdp);
} else {
pp = &cmdp->next;
}
}
}
INTON;
}
 
 
/*
* Delete all functions.
*/
 
#ifdef mkinit
MKINIT void deletefuncs (void);
 
SHELLPROC {
deletefuncs();
}
#endif
 
void
deletefuncs() {
struct tblentry **tblp;
struct tblentry **pp;
struct tblentry *cmdp;
 
INTOFF;
for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
pp = tblp;
while ((cmdp = *pp) != NULL) {
if (cmdp->cmdtype == CMDFUNCTION) {
*pp = cmdp->next;
freefunc(cmdp->param.func);
ckfree(cmdp);
} else {
pp = &cmdp->next;
}
}
}
INTON;
}
 
 
 
/*
* Locate a command in the command hash table. If "add" is nonzero,
* add the command to the table if it is not already present. The
* variable "lastcmdentry" is set to point to the address of the link
* pointing to the entry, so that delete_cmd_entry can delete the
* entry.
*/
 
struct tblentry **lastcmdentry;
 
 
STATIC struct tblentry *
cmdlookup(name, add)
char *name;
int add;
{
int hashval;
char *p;
struct tblentry *cmdp;
struct tblentry **pp;
 
p = name;
hashval = *p << 4;
while (*p)
hashval += *p++;
hashval &= 0x7FFF;
pp = &cmdtable[hashval % CMDTABLESIZE];
for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
if (equal(cmdp->cmdname, name))
break;
pp = &cmdp->next;
}
if (add && cmdp == NULL) {
INTOFF;
cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
+ strlen(name) + 1);
cmdp->next = NULL;
cmdp->cmdtype = CMDUNKNOWN;
cmdp->rehash = 0;
strcpy(cmdp->cmdname, name);
INTON;
}
lastcmdentry = pp;
return cmdp;
}
 
/*
* Delete the command entry returned on the last lookup.
*/
 
STATIC void
delete_cmd_entry() {
struct tblentry *cmdp;
 
INTOFF;
cmdp = *lastcmdentry;
*lastcmdentry = cmdp->next;
ckfree(cmdp);
INTON;
}
 
 
 
#ifdef notdef
void
getcmdentry(name, entry)
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.
*/
 
void
addcmdentry(name, entry)
char *name;
struct cmdentry *entry;
{
struct tblentry *cmdp;
 
INTOFF;
cmdp = cmdlookup(name, 1);
if (cmdp->cmdtype == CMDFUNCTION) {
freefunc(cmdp->param.func);
}
cmdp->cmdtype = entry->cmdtype;
cmdp->param = entry->u;
INTON;
}
 
 
/*
* Define a shell function.
*/
 
void
defun(name, func)
char *name;
union node *func;
{
struct cmdentry entry;
 
entry.cmdtype = CMDFUNCTION;
entry.u.func = copyfunc(func);
addcmdentry(name, &entry);
}
 
 
/*
* Delete a function if it exists.
*/
 
int
unsetfunc(name)
char *name;
{
struct tblentry *cmdp;
 
if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
freefunc(cmdp->param.func);
delete_cmd_entry();
return (0);
}
return (1);
}
 
/*
* Locate and print what a word is...
*/
 
int
typecmd(argc, argv)
int argc;
char **argv;
{
struct cmdentry entry;
struct tblentry *cmdp;
char * const *pp;
struct alias *ap;
int i;
int err = 0;
extern char *const parsekwd[];
 
for (i = 1; i < argc; i++) {
out1str(argv[i]);
/* First look at the keywords */
for (pp = parsekwd; *pp; pp++)
if (**pp == *argv[i] && equal(*pp, argv[i]))
break;
 
if (*pp) {
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);
continue;
}
 
/* Then check if it is a tracked alias */
if ((cmdp = cmdlookup(argv[i], 0)) != NULL) {
entry.cmdtype = cmdp->cmdtype;
entry.u = cmdp->param;
}
else {
/* Finally use brute force */
find_command(argv[i], &entry, DO_ABS, pathval());
}
 
switch (entry.cmdtype) {
case CMDNORMAL: {
if (strchr(argv[i], '/') == NULL) {
const char *path = pathval();
char *name;
int j = entry.u.index;
do {
name = padvance(&path, argv[i]);
stunalloc(name);
} while (--j >= 0);
out1fmt(" is%s %s\n",
cmdp ? " a tracked alias for" : "", name);
} else {
if (access(argv[i], X_OK) == 0)
out1fmt(" is %s\n", argv[i]);
else
out1fmt(": %s\n", strerror(errno));
}
break;
}
case CMDFUNCTION:
out1str(" is a shell function\n");
break;
 
case CMDBUILTIN:
out1str(" is a shell builtin\n");
break;
 
default:
out1str(": not found\n");
err |= 127;
break;
}
}
return err;
}
 
STATIC int
describe_command(command, verbose)
char *command;
int verbose;
{
struct cmdentry entry;
struct tblentry *cmdp;
char **pp;
struct alias *ap;
extern char *const parsekwd[];
 
for (pp = (char **)parsekwd; *pp; pp++)
if (**pp == *command && equal(*pp, command))
break;
 
if (*pp) {
if (verbose) {
out1fmt("%s is a reserved word\n", command);
} else {
out1fmt("%s\n", command);
}
return 0;
}
 
/* Then look at the aliases */
if ((ap = lookupalias(command, 1)) != NULL) {
if (verbose) {
out1fmt("%s is aliased to `%s'\n", command, ap->val);
} else {
out1fmt("alias %s='%s'\n", command, ap->val);
}
return 0;
}
 
/* Then check if it is a tracked alias */
if ((cmdp = cmdlookup(command, 0)) != NULL) {
entry.cmdtype = cmdp->cmdtype;
entry.u = cmdp->param;
}
else {
/* Finally use brute force */
find_command(command, &entry, DO_ABS, pathval());
}
 
switch (entry.cmdtype) {
case CMDNORMAL: {
int j = entry.u.index;
const char *path = pathval();
char *name;
if (j == -1)
name = command;
else {
do {
name = padvance(&path, command);
stunalloc(name);
} while (--j >= 0);
}
if (verbose) {
out1fmt("%s is %s\n", command, name);
} else {
out1fmt("%s\n", name);
}
break;
}
case CMDFUNCTION:
if (verbose) {
out1fmt("%s is a function\n", command);
} else {
out1fmt("%s\n", command);
}
break;
case CMDBUILTIN:
if (verbose) {
if (is_special_builtin(command)) {
out1fmt("%s is a special built-in utility\n", command);
} else {
out1fmt("%s is a built-in utility\n", command);
}
} else {
out1fmt("%s\n", command);
}
break;
default:
outfmt(out2, "%s not found\n", command);
return 127;
}
 
return 0;
}
 
int
commandcmd(argc, argv)
int argc;
char **argv;
{
int c;
int default_path = 0;
int verify_only = 0;
int verbose_verify_only = 0;
 
while ((c = nextopt("pvV")) != '\0')
switch (c) {
case 'p':
default_path = 1;
break;
case 'v':
verify_only = 1;
break;
case 'V':
verbose_verify_only = 1;
break;
default:
outfmt(out2,
"command: nextopt returned character code 0%o\n", c);
return EX_SOFTWARE;
}
 
if (default_path + verify_only + verbose_verify_only > 1 ||
!*argptr) {
outfmt(out2,
"command [-p] command [arg ...]\n");
outfmt(out2,
"command {-v|-V} command\n");
return EX_USAGE;
}
 
if (verify_only || verbose_verify_only) {
return describe_command(*argptr, verbose_verify_only);
}
 
return 0;
}
 
STATIC int
path_change(newval, bltin)
const char *newval;
int *bltin;
{
const char *old, *new;
int idx;
int firstchange;
 
old = pathval();
new = newval;
firstchange = 9999; /* assume no change */
idx = 0;
*bltin = -1;
for (;;) {
if (*old != *new) {
firstchange = idx;
if ((*old == '\0' && *new == ':')
|| (*old == ':' && *new == '\0'))
firstchange++;
old = new; /* ignore subsequent differences */
}
if (*new == '\0')
break;
if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1))
*bltin = idx;
if (*new == ':') {
idx++;
}
new++, old++;
}
if (builtinloc >= 0 && *bltin < 0)
firstchange = 0;
return firstchange;
}
 
STATIC int
is_regular_builtin(name)
const char *name;
{
static const char *regular_builtins[] = {
"alias", "bg", "cd", "command", "false", "fc", "fg",
"getopts", "jobs", "kill", "newgrp", "read", "true",
"umask", "unalias", "wait", (char *)NULL
};
int i;
 
if (!name) return 0;
for (i = 0; regular_builtins[i]; i++)
if (equal(name, regular_builtins[i])) return 1;
return 0;
}
/trunk/uspace/app/ash/cd.c
0,0 → 1,382
/* $NetBSD: cd.c,v 1.27 1999/07/09 03:05:49 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
 
#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.27 1999/07/09 03:05:49 christos Exp $");
#endif
#endif /* not lint */
 
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
 
/*
* The cd and pwd commands.
*/
 
#include "shell.h"
#include "var.h"
#include "nodes.h" /* for jobs.h */
#include "jobs.h"
#include "options.h"
#include "output.h"
#include "memalloc.h"
#include "error.h"
#include "exec.h"
#include "redir.h"
#include "mystring.h"
#include "show.h"
#include "cd.h"
 
STATIC int docd (char *, int);
STATIC char *getcomponent (void);
STATIC void updatepwd (char *);
 
char *curdir = NULL; /* current working directory */
char *prevdir; /* previous working directory */
STATIC char *cdcomppath;
 
int
cdcmd(argc, argv)
int argc;
char **argv;
{
const char *dest;
const char *path;
char *p;
struct stat statb;
int print = 0;
 
nextopt(nullstr);
if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME", 1)) == NULL)
error("HOME not set");
if (*dest == '\0')
dest = ".";
if (dest[0] == '-' && dest[1] == '\0') {
dest = prevdir ? prevdir : curdir;
print = 1;
if (dest)
print = 1;
else
dest = ".";
}
if (*dest == '/' || (path = bltinlookup("CDPATH", 1)) == NULL)
path = nullstr;
while ((p = padvance(&path, dest)) != NULL) {
if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
if (!print) {
/*
* XXX - rethink
*/
if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
p += 2;
print = strcmp(p, dest);
}
if (docd(p, print) >= 0)
return 0;
 
}
}
error("can't cd to %s", dest);
/* NOTREACHED */
}
 
 
/*
* Actually do the chdir. In an interactive shell, print the
* directory name if "print" is nonzero.
*/
 
STATIC int
docd(dest, print)
char *dest;
int print;
{
char *p;
char *q;
char *component;
struct stat statb;
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()
* next time we get the value of the current directory.
*/
badstat = 0;
cdcomppath = stalloc(strlen(dest) + 1);
scopy(dest, cdcomppath);
STARTSTACKSTR(p);
if (*dest == '/') {
STPUTC('/', p);
cdcomppath++;
}
first = 1;
while ((q = getcomponent()) != NULL) {
if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0'))
continue;
if (! first)
STPUTC('/', p);
first = 0;
component = q;
while (*q)
STPUTC(*q++, p);
if (equal(component, ".."))
continue;
STACKSTRNUL(p);
if ((lstat(stackblock(), &statb) < 0)
|| (S_ISLNK(statb.st_mode))) {
/* print = 1; */
badstat = 1;
break;
}
}
 
INTOFF;
if (chdir(dest) < 0) {
INTON;
return -1;
}
updatepwd(badstat ? NULL : dest);
INTON;
if (print && iflag && curdir)
out1fmt("%s\n", curdir);
return 0;
}
 
 
/*
* Get the next component of the path name pointed to by cdcomppath.
* This routine overwrites the string pointed to by cdcomppath.
*/
 
STATIC char *
getcomponent() {
char *p;
char *start;
 
if ((p = cdcomppath) == NULL)
return NULL;
start = cdcomppath;
while (*p != '/' && *p != '\0')
p++;
if (*p == '\0') {
cdcomppath = NULL;
} else {
*p++ = '\0';
cdcomppath = p;
}
return start;
}
 
 
 
/*
* Update curdir (the name of the current directory) in response to a
* cd command. We also call hashcd to let the routines in exec.c know
* that the current directory has changed.
*/
 
STATIC void
updatepwd(dir)
char *dir;
{
char *new;
char *p;
 
hashcd(); /* update command hash table */
 
/*
* If our argument is NULL, we don't know the current directory
* any more because we traversed a symbolic link or something
* we couldn't stat().
*/
if (dir == NULL || curdir == NULL) {
if (prevdir)
ckfree(prevdir);
INTOFF;
prevdir = curdir;
curdir = NULL;
getpwd();
setvar("PWD", curdir, VEXPORT|VTEXTFIXED);
setvar("OLDPWD", prevdir, VEXPORT|VTEXTFIXED);
INTON;
return;
}
cdcomppath = stalloc(strlen(dir) + 1);
scopy(dir, cdcomppath);
STARTSTACKSTR(new);
if (*dir != '/') {
p = curdir;
while (*p)
STPUTC(*p++, new);
if (p[-1] == '/')
STUNPUTC(new);
}
while ((p = getcomponent()) != NULL) {
if (equal(p, "..")) {
while (new > stackblock() && (STUNPUTC(new), *new) != '/');
} else if (*p != '\0' && ! equal(p, ".")) {
STPUTC('/', new);
while (*p)
STPUTC(*p++, new);
}
}
if (new == stackblock())
STPUTC('/', new);
STACKSTRNUL(new);
INTOFF;
if (prevdir)
ckfree(prevdir);
prevdir = curdir;
curdir = savestr(stackblock());
setvar("PWD", curdir, VEXPORT|VTEXTFIXED);
setvar("OLDPWD", prevdir, VEXPORT|VTEXTFIXED);
INTON;
}
 
 
 
int
pwdcmd(argc, argv)
int argc;
char **argv;
{
getpwd();
out1str(curdir);
out1c('\n');
return 0;
}
 
 
 
 
#define MAXPWD 256
 
/*
* Find out what the current directory is. If we already know the current
* directory, this routine returns immediately.
*/
void
getpwd()
{
char buf[MAXPWD];
 
if (curdir)
return;
/*
* 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(__GLIBC__)
if (getcwd(buf, sizeof(buf)) == NULL) {
char *pwd = getenv("PWD");
struct stat stdot, stpwd;
 
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;
}
error("getcwd() failed: %s", strerror(errno));
}
curdir = savestr(buf);
#else
{
char *p;
int i;
int status;
struct job *jp;
int pip[2];
 
INTOFF;
if (pipe(pip) < 0)
error("Pipe call failed");
jp = makejob((union node *)NULL, 1);
if (forkshell(jp, (union node *)NULL, FORK_NOJOB) == 0) {
(void) close(pip[0]);
if (pip[1] != 1) {
close(1);
copyfd(pip[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 = buf;
while ((i = read(pip[0], p, buf + 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 == buf || p[-1] != '\n')
error("pwd command failed");
p[-1] = '\0';
}
curdir = savestr(buf);
INTON;
#endif
}
/trunk/uspace/app/ash/bltin/echo.c
0,0 → 1,127
/* $NetBSD: echo.c,v 1.8 1996/11/02 18:26:06 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)echo.c 8.1 (Berkeley) 5/31/93
*/
 
/*
* Echo command.
*/
 
#define main echocmd
 
#ifdef _GNU_SOURCE
#include <stdio.h>
 
#include "../mystring.h"
#else
#include "bltin.h"
#endif
 
/* #define eflag 1 */
 
int
main(argc, argv) char **argv; {
register char **ap;
register char *p;
register char c;
int nflag = 0;
#ifndef eflag
int eflag = 0;
#endif
 
ap = argv;
if (argc)
ap++;
while ((p = *ap) != NULL && *p == '-') {
if (equal(p, "-n")) {
nflag = 1;
} else if (equal(p, "-e")) {
#ifndef eflag
eflag = 1;
#endif
} else if (equal(p, "-E")) {
#ifndef eflag
eflag = 0;
#endif
}
else break;
ap++;
}
while ((p = *ap++) != NULL) {
while ((c = *p++) != '\0') {
if (c == '\\' && eflag) {
switch (c = *p++) {
case 'a': c = '\007'; break;
case 'b': c = '\b'; break;
case 'c': return 0; /* exit */
case 'e': c = '\033'; break;
case 'f': c = '\f'; break;
case 'n': c = '\n'; break;
case 'r': c = '\r'; break;
case 't': c = '\t'; break;
case 'v': c = '\v'; break;
case '\\': break; /* c = '\\' */
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
c -= '0';
if (*p >= '0' && *p <= '7')
c = c * 8 + (*p++ - '0');
if (*p >= '0' && *p <= '7')
c = c * 8 + (*p++ - '0');
break;
default:
p--;
break;
}
}
putchar(c);
}
if (*ap)
putchar(' ');
}
if (! nflag)
putchar('\n');
#ifdef _GNU_SOURCE
fflush(stdout);
if (ferror(stdout)) {
clearerr(stdout);
return 1;
}
#endif
return 0;
}
/trunk/uspace/app/ash/bltin/test.c
0,0 → 1,583
/* $NetBSD: test.c,v 1.22 2000/04/09 23:24:59 christos Exp $ */
 
/*
* test(1); version 7-like -- author Erik Baalbergen
* modified by Eric Gisin to be used as built-in.
* modified by Arnold Robbins to add SVR3 compatibility
* (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket).
* modified by J.T. Conklin for NetBSD.
*
* This program is in the Public Domain.
*/
 
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: test.c,v 1.22 2000/04/09 23:24:59 christos Exp $");
#endif
 
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <err.h>
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
 
/* test(1) accepts the following grammar:
oexpr ::= aexpr | aexpr "-o" oexpr ;
aexpr ::= nexpr | nexpr "-a" aexpr ;
nexpr ::= primary | "!" primary
primary ::= unary-operator operand
| operand binary-operator operand
| operand
| "(" oexpr ")"
;
unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"|
"-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S";
 
binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
"-nt"|"-ot"|"-ef";
operand ::= <any legal UNIX file name>
*/
 
enum token {
EOI,
FILRD,
FILWR,
FILEX,
FILEXIST,
FILREG,
FILDIR,
FILCDEV,
FILBDEV,
FILFIFO,
FILSOCK,
FILSYM,
FILGZ,
FILTT,
FILSUID,
FILSGID,
FILSTCK,
FILNT,
FILOT,
FILEQ,
FILUID,
FILGID,
STREZ,
STRNZ,
STREQ,
STRNE,
STRLT,
STRGT,
INTEQ,
INTNE,
INTGE,
INTGT,
INTLE,
INTLT,
UNOT,
BAND,
BOR,
LPAREN,
RPAREN,
OPERAND
};
 
enum token_types {
UNOP,
BINOP,
BUNOP,
BBINOP,
PAREN
};
 
static struct t_op {
const char *op_text;
short op_num, op_type;
} const ops [] = {
{"-r", FILRD, UNOP},
{"-w", FILWR, UNOP},
{"-x", FILEX, UNOP},
{"-e", FILEXIST,UNOP},
{"-f", FILREG, UNOP},
{"-d", FILDIR, UNOP},
{"-c", FILCDEV,UNOP},
{"-b", FILBDEV,UNOP},
{"-p", FILFIFO,UNOP},
{"-u", FILSUID,UNOP},
{"-g", FILSGID,UNOP},
{"-k", FILSTCK,UNOP},
{"-s", FILGZ, UNOP},
{"-t", FILTT, UNOP},
{"-z", STREZ, UNOP},
{"-n", STRNZ, UNOP},
{"-h", FILSYM, UNOP}, /* for backwards compat */
{"-O", FILUID, UNOP},
{"-G", FILGID, UNOP},
{"-L", FILSYM, UNOP},
{"-S", FILSOCK,UNOP},
{"=", STREQ, BINOP},
{"!=", STRNE, BINOP},
{"<", STRLT, BINOP},
{">", STRGT, BINOP},
{"-eq", INTEQ, BINOP},
{"-ne", INTNE, BINOP},
{"-ge", INTGE, BINOP},
{"-gt", INTGT, BINOP},
{"-le", INTLE, BINOP},
{"-lt", INTLT, BINOP},
{"-nt", FILNT, BINOP},
{"-ot", FILOT, BINOP},
{"-ef", FILEQ, BINOP},
{"!", UNOT, BUNOP},
{"-a", BAND, BBINOP},
{"-o", BOR, BBINOP},
{"(", LPAREN, PAREN},
{")", RPAREN, PAREN},
{0, 0, 0}
};
 
static char **t_wp;
static struct t_op const *t_wp_op;
static gid_t *group_array = NULL;
static int ngroups;
 
static void syntax __P((const char *, const char *));
static int oexpr __P((enum token));
static int aexpr __P((enum token));
static int nexpr __P((enum token));
static int primary __P((enum token));
static int binop __P((void));
static int filstat __P((char *, enum token));
static enum token t_lex __P((char *));
static int isoperand __P((void));
static int getn __P((const char *));
static int newerf __P((const char *, const char *));
static int olderf __P((const char *, const char *));
static int equalf __P((const char *, const char *));
static int test_eaccess();
static int bash_group_member();
static void initialize_group_array();
 
#if defined(SHELL)
extern void error __P((const char *, ...)) __attribute__((__noreturn__));
#else
static void error __P((const char *, ...)) __attribute__((__noreturn__));
 
static void
#ifdef __STDC__
error(const char *msg, ...)
#else
error(va_alist)
va_dcl
#endif
{
va_list ap;
#ifndef __STDC__
const char *msg;
 
va_start(ap);
msg = va_arg(ap, const char *);
#else
va_start(ap, msg);
#endif
verrx(2, msg, ap);
/*NOTREACHED*/
va_end(ap);
}
#endif
 
#ifdef SHELL
int testcmd __P((int, char **));
 
int
testcmd(argc, argv)
int argc;
char **argv;
#else
int main __P((int, char **));
 
int
main(argc, argv)
int argc;
char **argv;
#endif
{
int res;
 
 
if (strcmp(argv[0], "[") == 0) {
if (strcmp(argv[--argc], "]"))
error("missing ]");
argv[argc] = NULL;
}
 
if (argc < 2)
return 1;
 
t_wp = &argv[1];
res = !oexpr(t_lex(*t_wp));
 
if (*t_wp != NULL && *++t_wp != NULL)
syntax(*t_wp, "unexpected operator");
 
return res;
}
 
static void
syntax(op, msg)
const char *op;
const char *msg;
{
if (op && *op)
error("%s: %s", op, msg);
else
error("%s", msg);
}
 
static int
oexpr(n)
enum token n;
{
int res;
 
res = aexpr(n);
if (t_lex(*++t_wp) == BOR)
return oexpr(t_lex(*++t_wp)) || res;
t_wp--;
return res;
}
 
static int
aexpr(n)
enum token n;
{
int res;
 
res = nexpr(n);
if (t_lex(*++t_wp) == BAND)
return aexpr(t_lex(*++t_wp)) && res;
t_wp--;
return res;
}
 
static int
nexpr(n)
enum token n; /* token */
{
if (n == UNOT)
return !nexpr(t_lex(*++t_wp));
return primary(n);
}
 
static int
primary(n)
enum token n;
{
enum token nn;
int res;
 
if (n == EOI)
return 0; /* missing expression */
if (n == LPAREN) {
if ((nn = t_lex(*++t_wp)) == RPAREN)
return 0; /* missing expression */
res = oexpr(nn);
if (t_lex(*++t_wp) != RPAREN)
syntax(NULL, "closing paren expected");
return res;
}
if (t_wp_op && t_wp_op->op_type == UNOP) {
/* unary expression */
if (*++t_wp == NULL)
syntax(t_wp_op->op_text, "argument expected");
switch (n) {
case STREZ:
return strlen(*t_wp) == 0;
case STRNZ:
return strlen(*t_wp) != 0;
case FILTT:
return isatty(getn(*t_wp));
default:
return filstat(*t_wp, n);
}
}
 
if (t_lex(t_wp[1]), t_wp_op && t_wp_op->op_type == BINOP) {
return binop();
}
 
return strlen(*t_wp) > 0;
}
 
static int
binop()
{
const char *opnd1, *opnd2;
struct t_op const *op;
 
opnd1 = *t_wp;
(void) t_lex(*++t_wp);
op = t_wp_op;
 
if ((opnd2 = *++t_wp) == (char *)0)
syntax(op->op_text, "argument expected");
switch (op->op_num) {
case STREQ:
return strcmp(opnd1, opnd2) == 0;
case STRNE:
return strcmp(opnd1, opnd2) != 0;
case STRLT:
return strcmp(opnd1, opnd2) < 0;
case STRGT:
return strcmp(opnd1, opnd2) > 0;
case INTEQ:
return getn(opnd1) == getn(opnd2);
case INTNE:
return getn(opnd1) != getn(opnd2);
case INTGE:
return getn(opnd1) >= getn(opnd2);
case INTGT:
return getn(opnd1) > getn(opnd2);
case INTLE:
return getn(opnd1) <= getn(opnd2);
case INTLT:
return getn(opnd1) < getn(opnd2);
case FILNT:
return newerf (opnd1, opnd2);
case FILOT:
return olderf (opnd1, opnd2);
case FILEQ:
return equalf (opnd1, opnd2);
default:
abort();
/* NOTREACHED */
}
}
 
static int
filstat(nm, mode)
char *nm;
enum token mode;
{
struct stat s;
 
if (mode == FILSYM ? lstat(nm, &s) : stat(nm, &s))
return 0;
 
switch (mode) {
case FILRD:
return test_eaccess(nm, R_OK) == 0;
case FILWR:
return test_eaccess(nm, W_OK) == 0;
case FILEX:
return test_eaccess(nm, X_OK) == 0;
case FILEXIST:
return 1;
case FILREG:
return S_ISREG(s.st_mode);
case FILDIR:
return S_ISDIR(s.st_mode);
case FILCDEV:
return S_ISCHR(s.st_mode);
case FILBDEV:
return S_ISBLK(s.st_mode);
case FILFIFO:
return S_ISFIFO(s.st_mode);
case FILSOCK:
return S_ISSOCK(s.st_mode);
case FILSYM:
return S_ISLNK(s.st_mode);
case FILSUID:
return (s.st_mode & S_ISUID) != 0;
case FILSGID:
return (s.st_mode & S_ISGID) != 0;
case FILSTCK:
return (s.st_mode & S_ISVTX) != 0;
case FILGZ:
return s.st_size > (off_t)0;
case FILUID:
return s.st_uid == geteuid();
case FILGID:
return s.st_gid == getegid();
default:
return 1;
}
}
 
static enum token
t_lex(s)
char *s;
{
struct t_op const *op = ops;
 
if (s == 0) {
t_wp_op = (struct t_op *)0;
return EOI;
}
while (op->op_text) {
if (strcmp(s, op->op_text) == 0) {
if ((op->op_type == UNOP && isoperand()) ||
(op->op_num == LPAREN && *(t_wp+1) == 0))
break;
t_wp_op = op;
return op->op_num;
}
op++;
}
t_wp_op = (struct t_op *)0;
return OPERAND;
}
 
static int
isoperand()
{
struct t_op const *op = ops;
char *s;
char *t;
 
if ((s = *(t_wp+1)) == 0)
return 1;
if ((t = *(t_wp+2)) == 0)
return 0;
while (op->op_text) {
if (strcmp(s, op->op_text) == 0)
return op->op_type == BINOP &&
(t[0] != ')' || t[1] != '\0');
op++;
}
return 0;
}
 
/* atoi with error detection */
static int
getn(s)
const char *s;
{
char *p;
long r;
 
errno = 0;
r = strtol(s, &p, 10);
 
if (errno != 0)
error("%s: out of range", s);
 
while (isspace((unsigned char)*p))
p++;
if (*p)
error("%s: bad number", s);
 
return (int) r;
}
 
static int
newerf (f1, f2)
const char *f1, *f2;
{
struct stat b1, b2;
 
return (stat (f1, &b1) == 0 &&
stat (f2, &b2) == 0 &&
b1.st_mtime > b2.st_mtime);
}
 
static int
olderf (f1, f2)
const char *f1, *f2;
{
struct stat b1, b2;
 
return (stat (f1, &b1) == 0 &&
stat (f2, &b2) == 0 &&
b1.st_mtime < b2.st_mtime);
}
 
static int
equalf (f1, f2)
const char *f1, *f2;
{
struct stat b1, b2;
 
return (stat (f1, &b1) == 0 &&
stat (f2, &b2) == 0 &&
b1.st_dev == b2.st_dev &&
b1.st_ino == b2.st_ino);
}
 
/* Do the same thing access(2) does, but use the effective uid and gid,
and don't make the mistake of telling root that any file is
executable. */
static int
test_eaccess (path, mode)
char *path;
int mode;
{
struct stat st;
int euid = geteuid();
 
if (stat (path, &st) < 0)
return (-1);
 
if (euid == 0) {
/* Root can read or write any file. */
if (mode != X_OK)
return (0);
 
/* Root can execute any file that has any one of the execute
bits set. */
if (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))
return (0);
}
 
if (st.st_uid == euid) /* owner */
mode <<= 6;
else if (bash_group_member (st.st_gid))
mode <<= 3;
 
if (st.st_mode & mode)
return (0);
 
return (-1);
}
 
static void
initialize_group_array ()
{
ngroups = getgroups(0, NULL);
group_array = malloc(ngroups * sizeof(gid_t));
if (!group_array)
error(strerror(ENOMEM));
getgroups(ngroups, group_array);
}
 
/* Return non-zero if GID is one that we have in our groups list. */
static int
bash_group_member (gid)
gid_t gid;
{
register int i;
 
/* Short-circuit if possible, maybe saving a call to getgroups(). */
if (gid == getgid() || gid == getegid())
return (1);
 
if (ngroups == 0)
initialize_group_array ();
 
/* Search through the list looking for GID. */
for (i = 0; i < ngroups; i++)
if (gid == group_array[i])
return (1);
 
return (0);
}
/trunk/uspace/app/ash/bltin/times.c
0,0 → 1,30
#ifdef _GNU_SOURCE
/*
* Copyright (c) 1999 Herbert Xu <herbert@debian.org>
* This file contains code for the times builtin.
* $Id: ash-0.4.0-cumulative_fixes-1.patch,v 1.1 2004/06/04 10:32:01 jim Exp $
*/
 
#include <stdio.h>
#include <sys/times.h>
#include <unistd.h>
 
#define main timescmd
 
int main() {
struct tms buf;
long int clk_tck = sysconf(_SC_CLK_TCK);
 
times(&buf);
printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
(int) (buf.tms_utime / clk_tck / 60),
((double) buf.tms_utime) / clk_tck,
(int) (buf.tms_stime / clk_tck / 60),
((double) buf.tms_stime) / clk_tck,
(int) (buf.tms_cutime / clk_tck / 60),
((double) buf.tms_cutime) / clk_tck,
(int) (buf.tms_cstime / clk_tck / 60),
((double) buf.tms_cstime) / clk_tck);
return 0;
}
#endif /* _GNU_SOURCE */
/trunk/uspace/app/ash/bltin/echo.1
0,0 → 1,113
.\" $NetBSD: echo.1,v 1.9 1999/03/22 18:30:47 garbled 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. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by the University of
.\" California, Berkeley and its contributors.
.\" 4. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" @(#)echo.1 8.1 (Berkeley) 5/31/93
.\"
.Dd May 31, 1993
.Dt ECHO 1
.Os
.Sh NAME
.Nm echo
.Nd produce message in a shell script
.Sh SYNOPSIS
.Nm
.Op Fl n | Fl e
.Ar args...
.Sh DESCRIPTION
.Nm
prints its arguments on the standard output, separated by spaces.
Unless the
.Fl n
option is present, a newline is output following the arguments.
The
.Fl e
option causes
.Nm
to treat the escape sequences specially, as described in the following
paragraph.
The
.Fl e
option is the default, and is provided solely for compatibility with
other systems.
Only one of the options
.Fl n
and
.Fl e
may be given.
.Pp
If any of the following sequences of characters is encountered during
output, the sequence is not output. Instead, the specified action is
performed:
.Bl -tag -width indent
.It Li \eb
A backspace character is output.
.It Li \ec
Subsequent output is suppressed. This is normally used at the end of the
last argument to suppress the trailing newline that
.Nm
would otherwise output.
.It Li \ef
Output a form feed.
.It Li \en
Output a newline character.
.It Li \er
Output a carriage return.
.It Li \et
Output a (horizontal) tab character.
.It Li \ev
Output a vertical tab.
.It Li \e0 Ns Ar digits
Output the character whose value is given by zero to three digits.
If there are zero digits, a nul character is output.
.It Li \e\e
Output a backslash.
.El
.Sh HINTS
Remember that backslash is special to the shell and needs to be escaped.
To output a message to standard error, say
.Pp
.D1 echo message >&2
.Sh BUGS
The octal character escape mechanism
.Pq Li \e0 Ns Ar digits
differs from the
C language mechanism.
.Pp
There is no way to force
.Nm
to treat its arguments literally, rather than interpreting them as
options and escape sequences.
/trunk/uspace/app/ash/bltin/bltin.h
0,0 → 1,81
/* $NetBSD: bltin.h,v 1.9 1997/07/04 21:02:29 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)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.
*/
 
#include "../shell.h"
#include "../mystring.h"
#include "../memalloc.h"
#ifdef SHELL
#include "../output.h"
#ifndef _GNU_SOURCE
#define stdout out1
#define stderr out2
#define printf out1fmt
#define putc(c, file) outc(c, file)
#define putchar(c) out1c(c)
#define fprintf outfmt
#define fputs outstr
#define fflush flushout
#define warnx(a, b, c) { \
char buf[64]; \
(void)snprintf(buf, sizeof(buf), a, b, c); \
error("%s", buf); \
}
#endif
#define INITARGS(argv)
 
#else
#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
 
pointer stalloc __P((int));
void error __P((char *, ...));
int echocmd __P((int, char **));
 
 
extern char *commandname;
/trunk/uspace/app/ash/memalloc.c
0,0 → 1,329
/* $NetBSD: memalloc.c,v 1.23 2000/11/01 19:56:01 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
 
#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.23 2000/11/01 19:56:01 christos Exp $");
#endif
#endif /* not lint */
 
#include <stdlib.h>
#include <unistd.h>
 
#include "shell.h"
#include "output.h"
#include "memalloc.h"
#include "error.h"
#include "machdep.h"
#include "mystring.h"
 
/*
* Like malloc, but returns an error when out of space.
*/
 
pointer
ckmalloc(nbytes)
int nbytes;
{
pointer p;
 
INTOFF;
p = malloc(nbytes);
INTON;
if (p == NULL)
error("Out of space");
return p;
}
 
 
/*
* Same for realloc.
*/
 
pointer
ckrealloc(p, nbytes)
pointer p;
int nbytes;
{
 
if ((p = realloc(p, nbytes)) == NULL)
error("Out of space");
return p;
}
 
 
/*
* Make a copy of a string in safe storage.
*/
 
char *
savestr(s)
char *s;
{
char *p;
 
p = ckmalloc(strlen(s) + 1);
scopy(s, p);
return p;
}
 
 
/*
* Parse trees for commands are allocated in lifo order, so we use a stack
* to make this more efficient, and also to avoid all sorts of exception
* handling code to handle interrupts in the middle of a parse.
*
* The size 504 was chosen because the Ultrix malloc handles that size
* well.
*/
 
#define MINSIZE 504 /* minimum size of a block */
 
 
struct stack_block {
struct stack_block *prev;
char space[MINSIZE];
};
 
struct stack_block stackbase;
struct stack_block *stackp = &stackbase;
struct stackmark *markp;
char *stacknxt = stackbase.space;
int stacknleft = MINSIZE;
int sstrnleft;
int herefd = -1;
 
 
 
pointer
stalloc(nbytes)
int nbytes;
{
char *p;
 
nbytes = ALIGN(nbytes);
if (nbytes > stacknleft) {
int blocksize;
struct stack_block *sp;
 
blocksize = nbytes;
if (blocksize < MINSIZE)
blocksize = MINSIZE;
INTOFF;
sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
sp->prev = stackp;
stacknxt = sp->space;
stacknleft = blocksize;
stackp = sp;
INTON;
}
p = stacknxt;
stacknxt += nbytes;
stacknleft -= nbytes;
return p;
}
 
 
void
stunalloc(p)
pointer p;
{
if (p == NULL) { /*DEBUG */
write(2, "stunalloc\n", 10);
abort();
}
stacknleft += stacknxt - (char *)p;
stacknxt = p;
}
 
 
 
void
setstackmark(mark)
struct stackmark *mark;
{
mark->stackp = stackp;
mark->stacknxt = stacknxt;
mark->stacknleft = stacknleft;
mark->marknext = markp;
markp = mark;
}
 
 
void
popstackmark(mark)
struct stackmark *mark;
{
struct stack_block *sp;
 
INTOFF;
markp = mark->marknext;
while (stackp != mark->stackp) {
sp = stackp;
stackp = sp->prev;
ckfree(sp);
}
stacknxt = mark->stacknxt;
stacknleft = mark->stacknleft;
INTON;
}
 
 
/*
* When the parser reads in a string, it wants to stick the string on the
* stack and only adjust the stack pointer when it knows how big the
* string is. Stackblock (defined in stack.h) returns a pointer to a block
* of space on top of the stack and stackblocklen returns the length of
* this block. Growstackblock will grow this space by at least one byte,
* possibly moving it (like realloc). Grabstackblock actually allocates the
* part of the block that has been used.
*/
 
void
growstackblock() {
char *p;
int newlen = ALIGN(stacknleft * 2 + 100);
char *oldspace = stacknxt;
int oldlen = stacknleft;
struct stack_block *sp;
struct stack_block *oldstackp;
 
if (stacknxt == stackp->space && stackp != &stackbase) {
INTOFF;
oldstackp = stackp;
sp = stackp;
stackp = sp->prev;
sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen);
sp->prev = stackp;
stackp = sp;
stacknxt = sp->space;
stacknleft = newlen;
{
/* Stack marks pointing to the start of the old block
* must be relocated to point to the new block
*/
struct stackmark *xmark;
xmark = markp;
while (xmark != NULL && xmark->stackp == oldstackp) {
xmark->stackp = stackp;
xmark->stacknxt = stacknxt;
xmark->stacknleft = stacknleft;
xmark = xmark->marknext;
}
}
INTON;
} else {
p = stalloc(newlen);
memcpy(p, oldspace, oldlen);
stacknxt = p; /* free the space */
stacknleft += newlen; /* we just allocated */
}
}
 
 
 
void
grabstackblock(len)
int len;
{
len = ALIGN(len);
stacknxt += len;
stacknleft -= len;
}
 
 
 
/*
* The following routines are somewhat easier to use that the above.
* The user declares a variable of type STACKSTR, which may be declared
* to be a register. The macro STARTSTACKSTR initializes things. Then
* the user uses the macro STPUTC to add characters to the string. In
* effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
* grown as necessary. When the user is done, she can just leave the
* string there and refer to it using stackblock(). Or she can allocate
* the space for it using grabstackstr(). If it is necessary to allow
* someone else to use the stack temporarily and then continue to grow
* the string, the user should use grabstack to allocate the space, and
* then call ungrabstr(p) to return to the previous mode of operation.
*
* USTPUTC is like STPUTC except that it doesn't check for overflow.
* CHECKSTACKSPACE can be called before USTPUTC to ensure that there
* is space for at least one character.
*/
 
 
char *
growstackstr() {
int len = stackblocksize();
if (herefd >= 0 && len >= 1024) {
xwrite(herefd, stackblock(), len);
sstrnleft = len - 1;
return stackblock();
}
growstackblock();
sstrnleft = stackblocksize() - len - 1;
return stackblock() + len;
}
 
 
/*
* Called from CHECKSTRSPACE.
*/
 
char *
makestrspace() {
int len = stackblocksize() - sstrnleft;
growstackblock();
sstrnleft = stackblocksize() - len;
return stackblock() + len;
}
 
 
 
void
ungrabstackstr(s, p)
char *s;
char *p;
{
stacknleft += stacknxt - s;
stacknxt = s;
sstrnleft = stacknleft - (p - s);
}
/trunk/uspace/app/ash/alias.c
0,0 → 1,267
/* $NetBSD: alias.c,v 1.10 1998/05/20 00:27:56 christos 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
 
//#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.10 1998/05/20 00:27:56 christos Exp $");
#endif
#endif /* not lint */
 
#include <stdlib.h>
#include "shell.h"
#include "input.h"
#include "output.h"
#include "error.h"
#include "memalloc.h"
#include "mystring.h"
#include "alias.h"
#include "options.h" /* XXX for argptr (should remove?) */
 
#define ATABSIZE 39
 
struct alias *atab[ATABSIZE];
 
STATIC void setalias (char *, char *);
STATIC int unalias (char *);
STATIC struct alias **hashalias (char *);
 
STATIC
void
setalias(char *name, char *val)
{
struct alias *ap, **app;
 
app = hashalias(name);
for (ap = *app; ap; ap = ap->next) {
if (equal(name, ap->name)) {
INTOFF;
ckfree(ap->val);
ap->val = savestr(val);
INTON;
return;
}
}
/* not found */
INTOFF;
ap = ckmalloc(sizeof (struct alias));
ap->name = savestr(name);
/*
* XXX - HACK: in order that the parser will not finish reading the
* alias value off the input before processing the next alias, we
* dummy up an extra space at the end of the alias. This is a crock
* and should be re-thought. The idea (if you feel inclined to help)
* is to avoid alias recursions. The mechanism used is: when
* 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 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
* H A C K is that we add a little fluff after the alias value
* so that the string will not be exhausted. This is a good
* idea ------- ***NOT***
*/
#ifdef notyet
ap->val = savestr(val);
#else /* hack */
{
int len = strlen(val);
ap->val = ckmalloc(len + 2);
memcpy(ap->val, val, len);
ap->val[len] = ' '; /* fluff */
ap->val[len+1] = '\0';
}
#endif
ap->next = *app;
*app = ap;
INTON;
}
 
STATIC int
unalias(name)
char *name;
{
struct alias *ap, **app;
 
app = hashalias(name);
 
for (ap = *app; ap; app = &(ap->next), ap = ap->next) {
if (equal(name, ap->name)) {
/*
* if the alias is currently in use (i.e. its
* buffer is being used by the input routine) we
* just null out the name instead of freeing it.
* We could clear it out later, but this situation
* is so rare that it hardly seems worth it.
*/
if (ap->flag & ALIASINUSE)
*ap->name = '\0';
else {
INTOFF;
*app = ap->next;
ckfree(ap->name);
ckfree(ap->val);
ckfree(ap);
INTON;
}
return (0);
}
}
 
return (1);
}
 
#ifdef mkinit
MKINIT void rmaliases (void);
 
SHELLPROC {
rmaliases();
}
#endif
 
void
rmaliases() {
struct alias *ap, *tmp;
int i;
 
INTOFF;
for (i = 0; i < ATABSIZE; i++) {
ap = atab[i];
atab[i] = NULL;
while (ap) {
ckfree(ap->name);
ckfree(ap->val);
tmp = ap;
ap = ap->next;
ckfree(tmp);
}
}
INTON;
}
 
struct alias *
lookupalias(name, check)
char *name;
int check;
{
struct alias *ap = *hashalias(name);
 
for (; ap; ap = ap->next) {
if (equal(name, ap->name)) {
if (check && (ap->flag & ALIASINUSE))
return (NULL);
return (ap);
}
}
 
return (NULL);
}
 
/*
* TODO - sort output
*/
int
aliascmd(argc, argv)
int argc;
char **argv;
{
char *n, *v;
int ret = 0;
struct alias *ap;
 
if (argc == 1) {
int i;
 
for (i = 0; i < ATABSIZE; i++)
for (ap = atab[i]; ap; ap = ap->next) {
if (*ap->name != '\0')
out1fmt("alias %s=%s\n", ap->name, ap->val);
}
return (0);
}
while ((n = *++argv) != NULL) {
if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
if ((ap = lookupalias(n, 0)) == NULL) {
outfmt(out2, "alias: %s not found\n", n);
ret = 1;
} else
out1fmt("alias %s=%s\n", n, ap->val);
}
else {
*v++ = '\0';
setalias(n, v);
}
}
 
return (ret);
}
 
int
unaliascmd(argc, argv)
int argc;
char **argv;
{
int i;
 
while ((i = nextopt("a")) != '\0') {
if (i == 'a') {
rmaliases();
return (0);
}
}
for (i = 0; *argptr; argptr++)
i = unalias(*argptr);
 
return (i);
}
 
STATIC struct alias **
hashalias(p)
char *p;
{
unsigned int hashval;
 
hashval = *p << 4;
while (*p)
hashval+= *p++;
return &atab[hashval % ATABSIZE];
}
/trunk/uspace/app/ash/exec.h
0,0 → 1,79
/* $NetBSD: exec.h,v 1.17 2000/05/22 10:18:47 elric 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)exec.h 8.3 (Berkeley) 6/8/95
*/
 
/* values of cmdtype */
#define CMDUNKNOWN -1 /* no entry in table for command */
#define CMDNORMAL 0 /* command is an executable program */
#define CMDBUILTIN 1 /* command is a shell builtin */
#define CMDFUNCTION 2 /* command is a shell function */
 
 
struct cmdentry {
int cmdtype;
union param {
int index;
union node *func;
} u;
};
 
 
#define DO_ERR 1 /* find_command prints errors */
#define DO_ABS 2 /* find_command checks absolute paths */
#define DO_NOFUN 4 /* find_command ignores functions */
#define DO_BRUTE 8 /* find_command ignores hash table */
 
extern const char *pathopt; /* set by padvance */
extern int exerrno; /* last exec error */
 
void shellexec (char **, char **, const char *, int)
__attribute__((noreturn));
char *padvance (const char **, const char *);
int hashcmd (int, char **);
void find_command (char *, struct cmdentry *, int, const char *);
int find_builtin (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 **);
int commandcmd (int, char **);
/trunk/uspace/app/ash/nodes.c.pat
0,0 → 1,169
/* $NetBSD: nodes.c.pat,v 1.8 1997/04/11 23:03:09 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)nodes.c.pat 8.2 (Berkeley) 5/4/95
*/
 
#include <stdlib.h>
/*
* Routine for dealing with parsed shell commands.
*/
 
#include "shell.h"
#include "nodes.h"
#include "memalloc.h"
#include "machdep.h"
#include "mystring.h"
 
 
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
 
 
STATIC void calcsize (union node *);
STATIC void sizenodelist (struct nodelist *);
STATIC union node *copynode (union node *);
STATIC struct nodelist *copynodelist (struct nodelist *);
STATIC char *nodesavestr (char *);
 
 
 
/*
* Make a copy of a parse tree.
*/
 
union node *
copyfunc(n)
union node *n;
{
if (n == NULL)
return NULL;
funcblocksize = 0;
funcstringsize = 0;
calcsize(n);
funcblock = ckmalloc(funcblocksize + funcstringsize);
funcstring = (char *) funcblock + funcblocksize;
return copynode(n);
}
 
 
 
STATIC void
calcsize(n)
union node *n;
{
%CALCSIZE
}
 
 
 
STATIC void
sizenodelist(lp)
struct nodelist *lp;
{
while (lp) {
funcblocksize += ALIGN(sizeof(struct nodelist));
calcsize(lp->n);
lp = lp->next;
}
}
 
 
 
STATIC union node *
copynode(n)
union node *n;
{
union node *new;
 
%COPY
return new;
}
 
 
STATIC struct nodelist *
copynodelist(lp)
struct nodelist *lp;
{
struct nodelist *start;
struct nodelist **lpp;
 
lpp = &start;
while (lp) {
*lpp = funcblock;
funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist));
(*lpp)->n = copynode(lp->n);
lp = lp->next;
lpp = &(*lpp)->next;
}
*lpp = NULL;
return start;
}
 
 
 
STATIC char *
nodesavestr(s)
char *s;
{
register char *p = s;
register char *q = funcstring;
char *rtn = funcstring;
 
while ((*q++ = *p++) != '\0')
continue;
funcstring = q;
return rtn;
}
 
 
 
/*
* Free a parse tree.
*/
 
void
freefunc(n)
union node *n;
{
if (n)
ckfree(n);
}
/trunk/uspace/app/ash/cd.h
0,0 → 1,39
/* $NetBSD: cd.h,v 1.2 1997/07/04 21:01:52 christos Exp $ */
 
/*-
* Copyright (c) 1995
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
 
void getpwd (void);
int cdcmd (int, char **);
int pwdcmd (int, char **);
/trunk/uspace/app/ash/parser.c
0,0 → 1,1559
/* $NetBSD: parser.c,v 1.45 2000/07/27 04:09:27 cgd 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
 
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)parser.c 8.7 (Berkeley) 5/16/95";
#else
__RCSID("$NetBSD: parser.c,v 1.45 2000/07/27 04:09:27 cgd Exp $");
#endif
#endif /* not lint */
 
#include <stdlib.h>
 
#include "shell.h"
#include "parser.h"
#include "nodes.h"
#include "expand.h" /* defines rmescapes() */
#include "redir.h" /* defines copyfd() */
#include "syntax.h"
#include "options.h"
#include "input.h"
#include "output.h"
#include "var.h"
#include "error.h"
#include "memalloc.h"
#include "mystring.h"
#include "alias.h"
#include "show.h"
#ifndef SMALL
#include "myhistedit.h"
#endif
 
/*
* Shell command parser.
*/
 
#define EOFMARKLEN 79
 
/* values returned by readtoken */
#include "token.h"
 
 
 
struct heredoc {
struct heredoc *next; /* next here document in list */
union node *here; /* redirection node */
char *eofmark; /* string indicating end of input */
int striptabs; /* if set, strip leading tabs */
};
 
 
 
struct heredoc *heredoclist; /* list of here documents to read */
int parsebackquote; /* nonzero if we are inside backquotes */
int doprompt; /* if set, prompt the user */
int needprompt; /* true if interactive and at start of line */
int lasttoken; /* last token read */
MKINIT int tokpushback; /* last token pushed back */
char *wordtext; /* text of last word returned by readtoken */
MKINIT int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */
struct nodelist *backquotelist;
union node *redirnode;
struct heredoc *heredoc;
int quoteflag; /* set if (part of) last token was quoted */
int startlinno; /* line # where last token started */
 
 
STATIC union node *list (int);
STATIC union node *andor (void);
STATIC union node *pipeline (void);
STATIC union node *command (void);
STATIC union node *simplecmd (union node **, union node *);
STATIC union node *makename (void);
STATIC void parsefname (void);
STATIC void parseheredoc (void);
STATIC int peektoken (void);
STATIC int readtoken (void);
STATIC int xxreadtoken (void);
STATIC int readtoken1 (int, char const *, char *, int);
STATIC int noexpand (char *);
STATIC void synexpect (int) __attribute__((noreturn));
STATIC void synerror (const char *) __attribute__((noreturn));
STATIC void setprompt (int);
 
 
/*
* Read and parse a command. Returns NEOF on end of file. (NULL is a
* valid parse tree indicating a blank line.)
*/
 
union node *
parsecmd(int interact)
{
int t;
 
doprompt = interact;
if (doprompt)
setprompt(1);
else
setprompt(0);
needprompt = 0;
t = readtoken();
if (t == TEOF)
return NEOF;
if (t == TNL)
return NULL;
tokpushback++;
return list(1);
}
 
 
STATIC union node *
list(nlflag)
int nlflag;
{
union node *n1, *n2, *n3;
int tok;
 
checkkwd = 2;
if (nlflag == 0 && tokendlist[peektoken()])
return NULL;
n1 = NULL;
for (;;) {
n2 = andor();
tok = readtoken();
if (tok == TBACKGND) {
if (n2->type == NCMD || n2->type == NPIPE) {
n2->ncmd.backgnd = 1;
} else if (n2->type == NREDIR) {
n2->type = NBACKGND;
} else {
n3 = (union node *)stalloc(sizeof (struct nredir));
n3->type = NBACKGND;
n3->nredir.n = n2;
n3->nredir.redirect = NULL;
n2 = n3;
}
}
if (n1 == NULL) {
n1 = n2;
}
else {
n3 = (union node *)stalloc(sizeof (struct nbinary));
n3->type = NSEMI;
n3->nbinary.ch1 = n1;
n3->nbinary.ch2 = n2;
n1 = n3;
}
switch (tok) {
case TBACKGND:
case TSEMI:
tok = readtoken();
/* fall through */
case TNL:
if (tok == TNL) {
parseheredoc();
if (nlflag)
return n1;
} else {
tokpushback++;
}
checkkwd = 2;
if (tokendlist[peektoken()])
return n1;
break;
case TEOF:
if (heredoclist)
parseheredoc();
else
pungetc(); /* push back EOF on input */
return n1;
default:
if (nlflag)
synexpect(-1);
tokpushback++;
return n1;
}
}
}
 
 
 
STATIC union node *
andor() {
union node *n1, *n2, *n3;
int t;
 
checkkwd = 1;
n1 = pipeline();
for (;;) {
if ((t = readtoken()) == TAND) {
t = NAND;
} else if (t == TOR) {
t = NOR;
} else {
tokpushback++;
return n1;
}
checkkwd = 2;
n2 = pipeline();
n3 = (union node *)stalloc(sizeof (struct nbinary));
n3->type = t;
n3->nbinary.ch1 = n1;
n3->nbinary.ch2 = n2;
n1 = n3;
}
}
 
 
 
STATIC union node *
pipeline() {
union node *n1, *n2, *pipenode;
struct nodelist *lp, *prev;
int negate;
 
negate = 0;
TRACE(("pipeline: entered\n"));
if (readtoken() == TNOT) {
negate = !negate;
checkkwd = 1;
} else
tokpushback++;
n1 = command();
if (readtoken() == TPIPE) {
pipenode = (union node *)stalloc(sizeof (struct npipe));
pipenode->type = NPIPE;
pipenode->npipe.backgnd = 0;
lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
pipenode->npipe.cmdlist = lp;
lp->n = n1;
do {
prev = lp;
lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
checkkwd = 2;
lp->n = command();
prev->next = lp;
} while (readtoken() == TPIPE);
lp->next = NULL;
n1 = pipenode;
}
tokpushback++;
if (negate) {
n2 = (union node *)stalloc(sizeof (struct nnot));
n2->type = NNOT;
n2->nnot.com = n1;
return n2;
} else
return n1;
}
 
 
 
STATIC union node *
command() {
union node *n1, *n2;
union node *ap, **app;
union node *cp, **cpp;
union node *redir, **rpp;
int t;
 
redir = NULL;
n1 = NULL;
rpp = &redir;
 
/* Check for redirection which may precede command */
while (readtoken() == TREDIR) {
*rpp = n2 = redirnode;
rpp = &n2->nfile.next;
parsefname();
}
tokpushback++;
 
switch (readtoken()) {
case TIF:
n1 = (union node *)stalloc(sizeof (struct nif));
n1->type = NIF;
n1->nif.test = list(0);
if (readtoken() != TTHEN)
synexpect(TTHEN);
n1->nif.ifpart = list(0);
n2 = n1;
while (readtoken() == TELIF) {
n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
n2 = n2->nif.elsepart;
n2->type = NIF;
n2->nif.test = list(0);
if (readtoken() != TTHEN)
synexpect(TTHEN);
n2->nif.ifpart = list(0);
}
if (lasttoken == TELSE)
n2->nif.elsepart = list(0);
else {
n2->nif.elsepart = NULL;
tokpushback++;
}
if (readtoken() != TFI)
synexpect(TFI);
checkkwd = 1;
break;
case TWHILE:
case TUNTIL: {
int got;
n1 = (union node *)stalloc(sizeof (struct nbinary));
n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
n1->nbinary.ch1 = list(0);
if ((got=readtoken()) != TDO) {
TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
synexpect(TDO);
}
n1->nbinary.ch2 = list(0);
if (readtoken() != TDONE)
synexpect(TDONE);
checkkwd = 1;
break;
}
case TFOR:
if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
synerror("Bad for loop variable");
n1 = (union node *)stalloc(sizeof (struct nfor));
n1->type = NFOR;
n1->nfor.var = wordtext;
if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) {
app = &ap;
while (readtoken() == TWORD) {
n2 = (union node *)stalloc(sizeof (struct narg));
n2->type = NARG;
n2->narg.text = wordtext;
n2->narg.backquote = backquotelist;
*app = n2;
app = &n2->narg.next;
}
*app = NULL;
n1->nfor.args = ap;
if (lasttoken != TNL && lasttoken != TSEMI)
synexpect(-1);
} else {
static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
'@', '=', '\0'};
n2 = (union node *)stalloc(sizeof (struct narg));
n2->type = NARG;
n2->narg.text = argvars;
n2->narg.backquote = NULL;
n2->narg.next = NULL;
n1->nfor.args = n2;
/*
* Newline or semicolon here is optional (but note
* that the original Bourne shell only allowed NL).
*/
if (lasttoken != TNL && lasttoken != TSEMI)
tokpushback++;
}
checkkwd = 2;
if ((t = readtoken()) == TDO)
t = TDONE;
else if (t == TBEGIN)
t = TEND;
else
synexpect(-1);
n1->nfor.body = list(0);
if (readtoken() != t)
synexpect(t);
checkkwd = 1;
break;
case TCASE:
n1 = (union node *)stalloc(sizeof (struct ncase));
n1->type = NCASE;
if (readtoken() != TWORD)
synexpect(TWORD);
n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
n2->type = NARG;
n2->narg.text = wordtext;
n2->narg.backquote = backquotelist;
n2->narg.next = NULL;
while (readtoken() == TNL);
if (lasttoken != TWORD || ! equal(wordtext, "in"))
synerror("expecting \"in\"");
cpp = &n1->ncase.cases;
checkkwd = 2, readtoken();
do {
if (lasttoken == TLP)
readtoken();
*cpp = cp = (union node *)stalloc(sizeof (struct nclist));
cp->type = NCLIST;
app = &cp->nclist.pattern;
for (;;) {
*app = ap = (union node *)stalloc(sizeof (struct narg));
ap->type = NARG;
ap->narg.text = wordtext;
ap->narg.backquote = backquotelist;
if (checkkwd = 2, readtoken() != TPIPE)
break;
app = &ap->narg.next;
readtoken();
}
ap->narg.next = NULL;
if (lasttoken != TRP)
synexpect(TRP);
cp->nclist.body = list(0);
 
checkkwd = 2;
if ((t = readtoken()) != TESAC) {
if (t != TENDCASE)
synexpect(TENDCASE);
else
checkkwd = 2, readtoken();
}
cpp = &cp->nclist.next;
} while(lasttoken != TESAC);
*cpp = NULL;
checkkwd = 1;
break;
case TLP:
n1 = (union node *)stalloc(sizeof (struct nredir));
n1->type = NSUBSHELL;
n1->nredir.n = list(0);
n1->nredir.redirect = NULL;
if (readtoken() != TRP)
synexpect(TRP);
checkkwd = 1;
break;
case TBEGIN:
n1 = list(0);
if (readtoken() != TEND)
synexpect(TEND);
checkkwd = 1;
break;
/* Handle an empty command like other simple commands. */
case TSEMI:
case TAND:
case TOR:
case TNL:
case TEOF:
case TRP:
case TBACKGND:
/*
* An empty command before a ; doesn't make much sense, and
* should certainly be disallowed in the case of `if ;'.
*/
if (!redir)
synexpect(-1);
case TWORD:
tokpushback++;
n1 = simplecmd(rpp, redir);
return n1;
default:
synexpect(-1);
/* NOTREACHED */
}
 
/* Now check for redirection which may follow command */
while (readtoken() == TREDIR) {
*rpp = n2 = redirnode;
rpp = &n2->nfile.next;
parsefname();
}
tokpushback++;
*rpp = NULL;
if (redir) {
if (n1->type != NSUBSHELL) {
n2 = (union node *)stalloc(sizeof (struct nredir));
n2->type = NREDIR;
n2->nredir.n = n1;
n1 = n2;
}
n1->nredir.redirect = redir;
}
 
return n1;
}
 
 
STATIC union node *
simplecmd(rpp, redir)
union node **rpp, *redir;
{
union node *args, **app;
union node **orig_rpp = rpp;
union node *n = NULL;
 
/* If we don't have any redirections already, then we must reset */
/* rpp to be the address of the local redir variable. */
if (redir == 0)
rpp = &redir;
 
args = NULL;
app = &args;
/*
* We save the incoming value, because we need this for shell
* functions. There can not be a redirect or an argument between
* the function name and the open parenthesis.
*/
orig_rpp = rpp;
 
for (;;) {
if (readtoken() == TWORD) {
n = (union node *)stalloc(sizeof (struct narg));
n->type = NARG;
n->narg.text = wordtext;
n->narg.backquote = backquotelist;
*app = n;
app = &n->narg.next;
} else if (lasttoken == TREDIR) {
*rpp = n = redirnode;
rpp = &n->nfile.next;
parsefname(); /* read name of redirection file */
} else if (lasttoken == TLP && app == &args->narg.next
&& rpp == orig_rpp) {
/* We have a function */
if (readtoken() != TRP)
synexpect(TRP);
#ifdef notdef
if (! goodname(n->narg.text))
synerror("Bad function name");
#endif
n->type = NDEFUN;
checkkwd = 2;
n->narg.next = command();
return n;
} else {
tokpushback++;
break;
}
}
*app = NULL;
*rpp = NULL;
n = (union node *)stalloc(sizeof (struct ncmd));
n->type = NCMD;
n->ncmd.backgnd = 0;
n->ncmd.args = args;
n->ncmd.redirect = redir;
return n;
}
 
STATIC union node *
makename() {
union node *n;
 
n = (union node *)stalloc(sizeof (struct narg));
n->type = NARG;
n->narg.next = NULL;
n->narg.text = wordtext;
n->narg.backquote = backquotelist;
return n;
}
 
void fixredir(union node *n, const char *text, int err)
{
TRACE(("Fix redir %s %d\n", text, err));
if (!err)
n->ndup.vname = NULL;
 
if (is_digit(text[0]) && text[1] == '\0')
n->ndup.dupfd = digit_val(text[0]);
else if (text[0] == '-' && text[1] == '\0')
n->ndup.dupfd = -1;
else {
 
if (err)
synerror("Bad fd number");
else
n->ndup.vname = makename();
}
}
 
 
STATIC void
parsefname() {
union node *n = redirnode;
 
if (readtoken() != TWORD)
synexpect(-1);
if (n->type == NHERE) {
struct heredoc *here = heredoc;
struct heredoc *p;
int i;
 
if (quoteflag == 0)
n->type = NXHERE;
TRACE(("Here document %d\n", n->type));
if (here->striptabs) {
while (*wordtext == '\t')
wordtext++;
}
if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
synerror("Illegal eof marker for << redirection");
rmescapes(wordtext);
here->eofmark = wordtext;
here->next = NULL;
if (heredoclist == NULL)
heredoclist = here;
else {
for (p = heredoclist ; p->next ; p = p->next);
p->next = here;
}
} else if (n->type == NTOFD || n->type == NFROMFD) {
fixredir(n, wordtext, 0);
} else {
n->nfile.fname = makename();
}
}
 
 
/*
* Input any here documents.
*/
 
STATIC void
parseheredoc() {
struct heredoc *here;
union node *n;
 
while (heredoclist) {
here = heredoclist;
heredoclist = here->next;
if (needprompt) {
setprompt(2);
needprompt = 0;
}
readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
here->eofmark, here->striptabs);
n = (union node *)stalloc(sizeof (struct narg));
n->narg.type = NARG;
n->narg.next = NULL;
n->narg.text = wordtext;
n->narg.backquote = backquotelist;
here->here->nhere.doc = n;
}
}
 
STATIC int
peektoken() {
int t;
 
t = readtoken();
tokpushback++;
return (t);
}
 
STATIC int
readtoken() {
int t;
int savecheckkwd = checkkwd;
struct alias *ap;
#ifdef DEBUG
int alreadyseen = tokpushback;
#endif
 
top:
t = xxreadtoken();
 
if (checkkwd) {
/*
* eat newlines
*/
if (checkkwd == 2) {
checkkwd = 0;
while (t == TNL) {
parseheredoc();
t = xxreadtoken();
}
} else
checkkwd = 0;
/*
* check for keywords and aliases
*/
if (t == TWORD && !quoteflag)
{
const char *const *pp;
 
for (pp = parsekwd; *pp; pp++) {
if (**pp == *wordtext && equal(*pp, wordtext))
{
lasttoken = t = pp -
parsekwd + KWDOFFSET;
TRACE(("keyword %s recognized\n", tokname[t]));
goto out;
}
}
if ((ap = lookupalias(wordtext, 1)) != NULL) {
pushstring(ap->val, strlen(ap->val), ap);
checkkwd = savecheckkwd;
goto top;
}
}
out:
checkkwd = 0;
}
#ifdef DEBUG
if (!alreadyseen)
TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
else
TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
#endif
return (t);
}
 
 
/*
* Read the next input token.
* If the token is a word, we set backquotelist to the list of cmds in
* backquotes. We set quoteflag to true if any part of the word was
* quoted.
* If the token is TREDIR, then we set redirnode to a structure containing
* the redirection.
* In all cases, the variable startlinno is set to the number of the line
* on which the token starts.
*
* [Change comment: here documents and internal procedures]
* [Readtoken shouldn't have any arguments. Perhaps we should make the
* word parsing code into a separate routine. In this case, readtoken
* doesn't need to have any internal procedures, but parseword does.
* We could also make parseoperator in essence the main routine, and
* have parseword (readtoken1?) handle both words and redirection.]
*/
 
#define RETURN(token) return lasttoken = token
 
STATIC int
xxreadtoken() {
int c;
 
if (tokpushback) {
tokpushback = 0;
return lasttoken;
}
if (needprompt) {
setprompt(2);
needprompt = 0;
}
startlinno = plinno;
for (;;) { /* until token or start of word found */
c = pgetc_macro();
if (c == ' ' || c == '\t')
continue; /* quick check for white space first */
switch (c) {
case ' ': case '\t':
continue;
case '#':
while ((c = pgetc()) != '\n' && c != PEOF);
pungetc();
continue;
case '\\':
if (pgetc() == '\n') {
startlinno = ++plinno;
if (doprompt)
setprompt(2);
else
setprompt(0);
continue;
}
pungetc();
goto breakloop;
case '\n':
plinno++;
needprompt = doprompt;
RETURN(TNL);
case PEOF:
RETURN(TEOF);
case '&':
if (pgetc() == '&')
RETURN(TAND);
pungetc();
RETURN(TBACKGND);
case '|':
if (pgetc() == '|')
RETURN(TOR);
pungetc();
RETURN(TPIPE);
case ';':
if (pgetc() == ';')
RETURN(TENDCASE);
pungetc();
RETURN(TSEMI);
case '(':
RETURN(TLP);
case ')':
RETURN(TRP);
default:
goto breakloop;
}
}
breakloop:
return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
#undef RETURN
}
 
 
 
/*
* If eofmark is NULL, read a word or a redirection symbol. If eofmark
* is not NULL, read a here document. In the latter case, eofmark is the
* word which marks the end of the document and striptabs is true if
* leading tabs should be stripped from the document. The argument firstc
* is the first character of the input token or document.
*
* Because C does not have internal subroutines, I have simulated them
* using goto's to implement the subroutine linkage. The following macros
* will run code that appears at the end of readtoken1.
*/
 
#define CHECKEND() {goto checkend; checkend_return:;}
#define PARSEREDIR() {goto parseredir; parseredir_return:;}
#define PARSESUB() {goto parsesub; parsesub_return:;}
#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
#define PARSEARITH() {goto parsearith; parsearith_return:;}
 
STATIC int
readtoken1(firstc, syntax, eofmark, striptabs)
int firstc;
char const *syntax;
char *eofmark;
int striptabs;
{
int c = firstc;
char *out;
int len;
char line[EOFMARKLEN + 1];
struct nodelist *bqlist;
int quotef;
int dblquote;
int varnest; /* levels of variables expansion */
int arinest; /* levels of arithmetic expansion */
int parenlevel; /* levels of parens in arithmetic */
int dqvarnest; /* levels of variables expansion within double quotes */
int oldstyle;
char const *prevsyntax; /* syntax before arithmetic */
#if __GNUC__
/* Avoid longjmp clobbering */
(void) &out;
(void) &quotef;
(void) &dblquote;
(void) &varnest;
(void) &arinest;
(void) &parenlevel;
(void) &dqvarnest;
(void) &oldstyle;
(void) &prevsyntax;
(void) &syntax;
#endif
 
startlinno = plinno;
dblquote = 0;
if (syntax == DQSYNTAX)
dblquote = 1;
quotef = 0;
bqlist = NULL;
varnest = 0;
arinest = 0;
parenlevel = 0;
dqvarnest = 0;
 
STARTSTACKSTR(out);
loop: { /* for each line, until end of word */
#if ATTY
if (c == '\034' && doprompt
&& attyset() && ! equal(termval(), "emacs")) {
attyline();
if (syntax == BASESYNTAX)
return readtoken();
c = pgetc();
goto loop;
}
#endif
CHECKEND(); /* set c to PEOF if at end of here document */
for (;;) { /* until end of line or end of word */
CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
switch(syntax[c]) {
case CNL: /* '\n' */
if (syntax == BASESYNTAX)
goto endword; /* exit outer loop */
USTPUTC(c, out);
plinno++;
if (doprompt)
setprompt(2);
else
setprompt(0);
c = pgetc();
goto loop; /* continue outer loop */
case CWORD:
USTPUTC(c, out);
break;
case CCTL:
if ((eofmark == NULL || dblquote) &&
dqvarnest == 0)
USTPUTC(CTLESC, out);
USTPUTC(c, out);
break;
case CBACK: /* backslash */
c = pgetc();
if (c == PEOF) {
USTPUTC('\\', out);
pungetc();
} else if (c == '\n') {
if (doprompt)
setprompt(2);
else
setprompt(0);
} else {
if (dblquote && c != '\\' && c != '`' && c != '$'
&& (c != '"' || eofmark != NULL))
USTPUTC('\\', out);
if (SQSYNTAX[c] == CCTL)
USTPUTC(CTLESC, out);
else if (eofmark == NULL)
USTPUTC(CTLQUOTEMARK, out);
USTPUTC(c, out);
quotef++;
}
break;
case CSQUOTE:
if (eofmark == NULL)
USTPUTC(CTLQUOTEMARK, out);
syntax = SQSYNTAX;
break;
case CDQUOTE:
if (eofmark == NULL)
USTPUTC(CTLQUOTEMARK, out);
syntax = DQSYNTAX;
dblquote = 1;
break;
case CENDQUOTE:
if (eofmark != NULL && arinest == 0 &&
varnest == 0) {
USTPUTC(c, out);
} else {
if (arinest) {
syntax = ARISYNTAX;
dblquote = 0;
} else if (eofmark == NULL &&
dqvarnest == 0) {
syntax = BASESYNTAX;
dblquote = 0;
}
quotef++;
}
break;
case CVAR: /* '$' */
PARSESUB(); /* parse substitution */
break;
case CENDVAR: /* '}' */
if (varnest > 0) {
varnest--;
if (dqvarnest > 0) {
dqvarnest--;
}
USTPUTC(CTLENDVAR, out);
} else {
USTPUTC(c, out);
}
break;
case CLP: /* '(' in arithmetic */
parenlevel++;
USTPUTC(c, out);
break;
case CRP: /* ')' in arithmetic */
if (parenlevel > 0) {
USTPUTC(c, out);
--parenlevel;
} else {
if (pgetc() == ')') {
if (--arinest == 0) {
USTPUTC(CTLENDARI, out);
syntax = prevsyntax;
if (syntax == DQSYNTAX)
dblquote = 1;
else
dblquote = 0;
} else
USTPUTC(')', out);
} else {
/*
* unbalanced parens
* (don't 2nd guess - no error)
*/
pungetc();
USTPUTC(')', out);
}
}
break;
case CBQUOTE: /* '`' */
PARSEBACKQOLD();
break;
case CEOF:
goto endword; /* exit outer loop */
default:
if (varnest == 0)
goto endword; /* exit outer loop */
USTPUTC(c, out);
}
c = pgetc_macro();
}
}
endword:
if (syntax == ARISYNTAX)
synerror("Missing '))'");
if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
synerror("Unterminated quoted string");
if (varnest != 0) {
startlinno = plinno;
synerror("Missing '}'");
}
USTPUTC('\0', out);
len = out - stackblock();
out = stackblock();
if (eofmark == NULL) {
if ((c == '>' || c == '<')
&& quotef == 0
&& len <= 2
&& (*out == '\0' || is_digit(*out))) {
PARSEREDIR();
return lasttoken = TREDIR;
} else {
pungetc();
}
}
quoteflag = quotef;
backquotelist = bqlist;
grabstackblock(len);
wordtext = out;
return lasttoken = TWORD;
/* end of readtoken routine */
 
 
 
/*
* Check to see whether we are at the end of the here document. When this
* is called, c is set to the first character of the next input line. If
* we are at the end of the here document, this routine sets the c to PEOF.
*/
 
checkend: {
if (eofmark) {
if (striptabs) {
while (c == '\t')
c = pgetc();
}
if (c == *eofmark) {
if (pfgets(line, sizeof line) != NULL) {
char *p, *q;
 
p = line;
for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
if (*p == '\n' && *q == '\0') {
c = PEOF;
plinno++;
needprompt = doprompt;
} else {
pushstring(line, strlen(line), NULL);
}
}
}
}
goto checkend_return;
}
 
 
/*
* Parse a redirection operator. The variable "out" points to a string
* specifying the fd to be redirected. The variable "c" contains the
* first character of the redirection operator.
*/
 
parseredir: {
char fd = *out;
union node *np;
 
np = (union node *)stalloc(sizeof (struct nfile));
if (c == '>') {
np->nfile.fd = 1;
c = pgetc();
if (c == '>')
np->type = NAPPEND;
else if (c == '&')
np->type = NTOFD;
else if (c == '|')
np->type = NTOOV;
else {
np->type = NTO;
pungetc();
}
} else { /* c == '<' */
np->nfile.fd = 0;
switch (c = pgetc()) {
case '<':
if (sizeof (struct nfile) != sizeof (struct nhere)) {
np = (union node *)stalloc(sizeof (struct nhere));
np->nfile.fd = 0;
}
np->type = NHERE;
heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
heredoc->here = np;
if ((c = pgetc()) == '-') {
heredoc->striptabs = 1;
} else {
heredoc->striptabs = 0;
pungetc();
}
break;
 
case '&':
np->type = NFROMFD;
break;
 
case '>':
np->type = NFROMTO;
break;
 
default:
np->type = NFROM;
pungetc();
break;
}
}
if (fd != '\0')
np->nfile.fd = digit_val(fd);
redirnode = np;
goto parseredir_return;
}
 
 
/*
* Parse a substitution. At this point, we have read the dollar sign
* and nothing else.
*/
 
parsesub: {
int subtype;
int typeloc;
int flags;
char *p;
static const char types[] = "}-+?=";
 
c = pgetc();
if (c != '(' && c != '{' && !is_name(c) && !is_special(c)) {
USTPUTC('$', out);
pungetc();
} else if (c == '(') { /* $(command) or $((arith)) */
if (pgetc() == '(') {
PARSEARITH();
} else {
pungetc();
PARSEBACKQNEW();
}
} else {
USTPUTC(CTLVAR, out);
typeloc = out - stackblock();
USTPUTC(VSNORMAL, out);
subtype = VSNORMAL;
if (c == '{') {
c = pgetc();
if (c == '#') {
if ((c = pgetc()) == '}')
c = '#';
else
subtype = VSLENGTH;
}
else
subtype = 0;
}
if (is_name(c)) {
do {
STPUTC(c, out);
c = pgetc();
} while (is_in_name(c));
} else if (is_digit(c)) {
do {
USTPUTC(c, out);
c = pgetc();
} while (is_digit(c));
}
else if (is_special(c)) {
USTPUTC(c, out);
c = pgetc();
}
else
badsub: synerror("Bad substitution");
 
STPUTC('=', out);
flags = 0;
if (subtype == 0) {
switch (c) {
case ':':
flags = VSNUL;
c = pgetc();
/*FALLTHROUGH*/
default:
p = strchr(types, c);
if (p == NULL)
goto badsub;
subtype = p - types + VSNORMAL;
break;
case '%':
case '#':
{
int cc = c;
subtype = c == '#' ? VSTRIMLEFT :
VSTRIMRIGHT;
c = pgetc();
if (c == cc)
subtype++;
else
pungetc();
break;
}
}
} else {
pungetc();
}
if (dblquote || arinest)
flags |= VSQUOTE;
*(stackblock() + typeloc) = subtype | flags;
if (subtype != VSNORMAL) {
varnest++;
if (dblquote) {
dqvarnest++;
}
}
}
goto parsesub_return;
}
 
 
/*
* Called to parse command substitutions. Newstyle is set if the command
* is enclosed inside $(...); nlpp is a pointer to the head of the linked
* list of commands (passed by reference), and savelen is the number of
* characters on the top of the stack which must be preserved.
*/
 
parsebackq: {
struct nodelist **nlpp;
int savepbq;
union node *n;
char *volatile str;
struct jmploc jmploc;
struct jmploc *volatile savehandler;
int savelen;
int saveprompt;
#ifdef __GNUC__
(void) &saveprompt;
#endif
 
savepbq = parsebackquote;
if (setjmp(jmploc.loc)) {
if (str)
ckfree(str);
parsebackquote = 0;
handler = savehandler;
longjmp(handler->loc, 1);
}
INTOFF;
str = NULL;
savelen = out - stackblock();
if (savelen > 0) {
str = ckmalloc(savelen);
memcpy(str, stackblock(), savelen);
}
savehandler = handler;
handler = &jmploc;
INTON;
if (oldstyle) {
/* We must read until the closing backquote, giving special
treatment to some slashes, and then push the string and
reread it as input, interpreting it normally. */
char *pout;
int pc;
int psavelen;
char *pstr;
 
 
STARTSTACKSTR(pout);
for (;;) {
if (needprompt) {
setprompt(2);
needprompt = 0;
}
switch (pc = pgetc()) {
case '`':
goto done;
 
case '\\':
if ((pc = pgetc()) == '\n') {
plinno++;
if (doprompt)
setprompt(2);
else
setprompt(0);
/*
* If eating a newline, avoid putting
* the newline into the new character
* stream (via the STPUTC after the
* switch).
*/
continue;
}
if (pc != '\\' && pc != '`' && pc != '$'
&& (!dblquote || pc != '"'))
STPUTC('\\', pout);
break;
 
case '\n':
plinno++;
needprompt = doprompt;
break;
 
case PEOF:
startlinno = plinno;
synerror("EOF in backquote substitution");
break;
 
default:
break;
}
STPUTC(pc, pout);
}
done:
STPUTC('\0', pout);
psavelen = pout - stackblock();
if (psavelen > 0) {
pstr = grabstackstr(pout);
setinputstring(pstr, 1);
}
}
nlpp = &bqlist;
while (*nlpp)
nlpp = &(*nlpp)->next;
*nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
(*nlpp)->next = NULL;
parsebackquote = oldstyle;
 
if (oldstyle) {
saveprompt = doprompt;
doprompt = 0;
}
 
n = list(0);
 
if (oldstyle)
doprompt = saveprompt;
else {
if (readtoken() != TRP)
synexpect(TRP);
}
 
(*nlpp)->n = n;
if (oldstyle) {
/*
* Start reading from old file again, ignoring any pushed back
* tokens left from the backquote parsing
*/
popfile();
tokpushback = 0;
}
while (stackblocksize() <= savelen)
growstackblock();
STARTSTACKSTR(out);
if (str) {
memcpy(out, str, savelen);
STADJUST(savelen, out);
INTOFF;
ckfree(str);
str = NULL;
INTON;
}
parsebackquote = savepbq;
handler = savehandler;
if (arinest || dblquote)
USTPUTC(CTLBACKQ | CTLQUOTE, out);
else
USTPUTC(CTLBACKQ, out);
if (oldstyle)
goto parsebackq_oldreturn;
else
goto parsebackq_newreturn;
}
 
/*
* Parse an arithmetic expansion (indicate start of one and set state)
*/
parsearith: {
 
if (++arinest == 1) {
prevsyntax = syntax;
syntax = ARISYNTAX;
USTPUTC(CTLARI, out);
if (dblquote)
USTPUTC('"',out);
else
USTPUTC(' ',out);
} else {
/*
* we collapse embedded arithmetic expansion to
* parenthesis, which should be equivalent
*/
USTPUTC('(', out);
}
goto parsearith_return;
}
 
} /* end of readtoken */
 
 
 
#ifdef mkinit
RESET {
tokpushback = 0;
checkkwd = 0;
}
#endif
 
/*
* Returns true if the text contains nothing to expand (no dollar signs
* or backquotes).
*/
 
STATIC int
noexpand(text)
char *text;
{
char *p;
char c;
 
p = text;
while ((c = *p++) != '\0') {
if (c == CTLQUOTEMARK)
continue;
if (c == CTLESC)
p++;
else if (BASESYNTAX[(int)c] == CCTL)
return 0;
}
return 1;
}
 
 
/*
* Return true if the argument is a legal variable name (a letter or
* underscore followed by zero or more letters, underscores, and digits).
*/
 
int
goodname(char *name)
{
char *p;
 
p = name;
if (! is_name(*p))
return 0;
while (*++p) {
if (! is_in_name(*p))
return 0;
}
return 1;
}
 
 
/*
* Called when an unexpected token is read during the parse. The argument
* is the token that is expected, or -1 if more than one type of token can
* occur at this point.
*/
 
STATIC void
synexpect(token)
int token;
{
char msg[64];
 
if (token >= 0) {
fmtstr(msg, 64, "%s unexpected (expecting %s)",
tokname[lasttoken], tokname[token]);
} else {
fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]);
}
synerror(msg);
/* NOTREACHED */
}
 
 
STATIC void
synerror(msg)
const char *msg;
{
if (commandname)
outfmt(&errout, "%s: %d: ", commandname, startlinno);
outfmt(&errout, "Syntax error: %s\n", msg);
error((char *)NULL);
/* NOTREACHED */
}
 
STATIC void
setprompt(which)
int which;
{
whichprompt = which;
 
#ifndef SMALL
if (!el)
#endif
out2str(getprompt(NULL));
}
 
/*
* called by editline -- any expansions to the prompt
* should be added here.
*/
const char *
getprompt(void *unused)
{
switch (whichprompt) {
case 0:
return "";
case 1:
return ps1val();
case 2:
return ps2val();
default:
return "<internal prompt error>";
}
}
/trunk/uspace/app/ash/jobs.c
0,0 → 1,1263
/* $NetBSD: jobs.c,v 1.36 2000/05/22 10:18:47 elric 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
 
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)jobs.c 8.5 (Berkeley) 5/4/95";
#else
__RCSID("$NetBSD: jobs.c,v 1.36 2000/05/22 10:18:47 elric Exp $");
#endif
#endif /* not lint */
 
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <paths.h>
#include <sys/types.h>
#include <sys/param.h>
#ifdef BSD
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
#endif
#include <sys/ioctl.h>
 
#include "shell.h"
#if JOBS
#if OLD_TTY_DRIVER
#include "sgtty.h"
#else
#include <termios.h>
#endif
#undef CEOF /* syntax.h redefines this */
#endif
#include "redir.h"
#include "show.h"
#include "main.h"
#include "parser.h"
#include "nodes.h"
#include "jobs.h"
#include "options.h"
#include "trap.h"
#include "syntax.h"
#include "input.h"
#include "output.h"
#include "memalloc.h"
#include "error.h"
#include "mystring.h"
 
 
struct job *jobtab; /* array of jobs */
int njobs; /* size of array */
MKINIT short backgndpid = -1; /* pid of last background process */
#if JOBS
int initialpgrp; /* pgrp of shell on invocation */
short curjob; /* current job */
#endif
STATIC int intreceived;
 
STATIC void restartjob (struct job *);
STATIC void freejob (struct job *);
STATIC struct job *getjob (char *);
STATIC int dowait (int, struct job *);
STATIC int onsigchild (void);
STATIC int waitproc (int, int *);
STATIC void cmdtxt (union node *);
STATIC void cmdputs (const char *);
STATIC void waitonint(int);
 
 
#if JOBS
/*
* Turn job control on and off.
*
* Note: This code assumes that the third arg to ioctl is a character
* pointer, which is true on Berkeley systems but not System V. Since
* System V doesn't have job control yet, this isn't a problem now.
*/
 
MKINIT int jobctl;
 
void
setjobctl(on)
int on;
{
#ifdef OLD_TTY_DRIVER
int ldisc;
#endif
 
if (on == jobctl || rootshell == 0)
return;
if (on) {
do { /* while we are in the background */
#ifdef OLD_TTY_DRIVER
if (ioctl(fd2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
#else
initialpgrp = tcgetpgrp(fd2);
if (initialpgrp < 0) {
#endif
out2str("sh: can't access tty; job control turned off\n");
mflag = 0;
return;
}
if (initialpgrp == -1)
initialpgrp = getpgrp();
else if (initialpgrp != getpgrp()) {
killpg(initialpgrp, SIGTTIN);
continue;
}
} while (0);
#ifdef OLD_TTY_DRIVER
if (ioctl(fd2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
out2str("sh: need new tty driver to run job control; job control turned off\n");
mflag = 0;
return;
}
#endif
setsignal(SIGTSTP);
setsignal(SIGTTOU);
setsignal(SIGTTIN);
setpgid(0, rootpid);
#ifdef OLD_TTY_DRIVER
ioctl(fd2, TIOCSPGRP, (char *)&rootpid);
#else
tcsetpgrp(fd2, rootpid);
#endif
} else { /* turning job control off */
setpgid(0, initialpgrp);
#ifdef OLD_TTY_DRIVER
ioctl(fd2, TIOCSPGRP, (char *)&initialpgrp);
#else
tcsetpgrp(fd2, initialpgrp);
#endif
setsignal(SIGTSTP);
setsignal(SIGTTOU);
setsignal(SIGTTIN);
}
jobctl = on;
}
#endif
 
 
#ifdef mkinit
INCLUDE <stdlib.h>
 
SHELLPROC {
backgndpid = -1;
#if JOBS
jobctl = 0;
#endif
}
 
#endif
 
 
 
#if JOBS
int
killcmd(argc, argv)
int argc;
char **argv;
{
extern char *signal_names[];
int signo = -1;
int list = 0;
int i;
pid_t pid;
struct job *jp;
 
if (argc <= 1) {
error(
"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
"kill -l [exitstatus]"
);
}
 
if (*argv[1] == '-') {
signo = decode_signal(argv[1]+1);
if (signo < 0) {
int c;
 
while ((c = nextopt("ls:")) != '\0')
switch (c) {
case 'l':
list = 1;
break;
case 's':
signo = decode_signal(optarg);
break;
default:
error(
"nextopt returned character code 0%o", c);
}
} else
argptr++;
}
 
if (!list && signo < 0)
signo = SIGTERM;
 
if ((signo < 0 || !*argptr) ^ list) {
error(
"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
"kill -l [exitstatus]"
);
}
 
if (list) {
if (!*argptr) {
out1fmt("0\n");
for (i = 1; i < NSIG; i++) {
if (strncmp(signal_names[i], "SIGJUNK(", 8)
== 0)
continue;
out1fmt("%s\n", signal_names[i] + 3);
}
return 0;
}
signo = atoi(*argptr);
if (signo > 128)
signo -= 128;
if (0 < signo && signo < NSIG)
out1fmt("%s\n", signal_names[signo] + 3);
else
error("invalid signal number or exit status: %s",
*argptr);
return 0;
}
 
do {
if (**argptr == '%') {
jp = getjob(*argptr);
if (jp->jobctl == 0)
error("job %s not created under job control",
*argptr);
pid = -jp->ps[0].pid;
} else
pid = atoi(*argptr);
if (kill(pid, signo) != 0)
error("%s: %s", *argptr, strerror(errno));
} while (*++argptr);
 
return 0;
}
 
int
fgcmd(argc, argv)
int argc;
char **argv;
{
struct job *jp;
int pgrp;
int status;
 
jp = getjob(argv[1]);
if (jp->jobctl == 0)
error("job not created under job control");
pgrp = jp->ps[0].pid;
#ifdef OLD_TTY_DRIVER
ioctl(fd2, TIOCSPGRP, (char *)&pgrp);
#else
tcsetpgrp(fd2, pgrp);
#endif
restartjob(jp);
INTOFF;
status = waitforjob(jp);
INTON;
return status;
}
 
 
int
bgcmd(argc, argv)
int argc;
char **argv;
{
struct job *jp;
 
do {
jp = getjob(*++argv);
if (jp->jobctl == 0)
error("job not created under job control");
restartjob(jp);
} while (--argc > 1);
return 0;
}
 
 
STATIC void
restartjob(jp)
struct job *jp;
{
struct procstat *ps;
int i;
 
if (jp->state == JOBDONE)
return;
INTOFF;
killpg(jp->ps[0].pid, SIGCONT);
for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
if (WIFSTOPPED(ps->status)) {
ps->status = -1;
jp->state = 0;
}
}
INTON;
}
#endif
 
 
int
jobscmd(argc, argv)
int argc;
char **argv;
{
showjobs(0);
return 0;
}
 
 
/*
* Print a list of jobs. If "change" is nonzero, only print jobs whose
* statuses have changed since the last call to showjobs.
*
* If the shell is interrupted in the process of creating a job, the
* result may be a job structure containing zero processes. Such structures
* will be freed here.
*/
 
void
showjobs(change)
int change;
{
int jobno;
int procno;
int i;
struct job *jp;
struct procstat *ps;
int col;
char s[64];
 
TRACE(("showjobs(%d) called\n", change));
while (dowait(0, (struct job *)NULL) > 0);
for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
if (! jp->used)
continue;
if (jp->nprocs == 0) {
freejob(jp);
continue;
}
if (change && ! jp->changed)
continue;
procno = jp->nprocs;
for (ps = jp->ps ; ; ps++) { /* for each process */
if (ps == jp->ps)
fmtstr(s, 64, "[%d] %ld ", jobno,
(long)ps->pid);
else
fmtstr(s, 64, " %ld ",
(long)ps->pid);
out1str(s);
col = strlen(s);
s[0] = '\0';
if (ps->status == -1) {
/* don't print anything */
} else if (WIFEXITED(ps->status)) {
fmtstr(s, 64, "Exit %d",
WEXITSTATUS(ps->status));
} else {
#if JOBS
if (WIFSTOPPED(ps->status))
i = WSTOPSIG(ps->status);
else /* WIFSIGNALED(ps->status) */
#endif
i = WTERMSIG(ps->status);
if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
scopy(sys_siglist[i & 0x7F], s);
else
fmtstr(s, 64, "Signal %d", i & 0x7F);
if (WCOREDUMP(ps->status))
strcat(s, " (core dumped)");
}
out1str(s);
col += strlen(s);
do {
out1c(' ');
col++;
} while (col < 30);
out1str(ps->cmd);
out1c('\n');
if (--procno <= 0)
break;
}
jp->changed = 0;
if (jp->state == JOBDONE) {
freejob(jp);
}
}
}
 
 
/*
* Mark a job structure as unused.
*/
 
STATIC void
freejob(jp)
struct job *jp;
{
struct procstat *ps;
int i;
 
INTOFF;
for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
if (ps->cmd != nullstr)
ckfree(ps->cmd);
}
if (jp->ps != &jp->ps0)
ckfree(jp->ps);
jp->used = 0;
#if JOBS
if (curjob == jp - jobtab + 1)
curjob = 0;
#endif
INTON;
}
 
 
 
int
waitcmd(argc, argv)
int argc;
char **argv;
{
struct job *job;
int status, retval;
struct job *jp;
 
if (argc > 1) {
job = getjob(argv[1]);
} else {
job = NULL;
}
for (;;) { /* loop until process terminated or stopped */
if (job != NULL) {
if (job->state) {
status = job->ps[job->nprocs - 1].status;
if (WIFEXITED(status))
retval = WEXITSTATUS(status);
#if JOBS
else if (WIFSTOPPED(status))
retval = WSTOPSIG(status) + 128;
#endif
else {
/* XXX: limits number of signals */
retval = WTERMSIG(status) + 128;
}
if (! iflag)
freejob(job);
return retval;
}
} else {
for (jp = jobtab ; ; jp++) {
if (jp >= jobtab + njobs) { /* no running procs */
return 0;
}
if (jp->used && jp->state == 0)
break;
}
}
dowait(1, (struct job *)NULL);
}
}
 
 
 
int
jobidcmd(argc, argv)
int argc;
char **argv;
{
struct job *jp;
int i;
 
jp = getjob(argv[1]);
for (i = 0 ; i < jp->nprocs ; ) {
out1fmt("%ld", (long)jp->ps[i].pid);
out1c(++i < jp->nprocs? ' ' : '\n');
}
return 0;
}
 
 
 
/*
* Convert a job name to a job structure.
*/
 
STATIC struct job *
getjob(name)
char *name;
{
int jobno;
struct job *jp;
int pid;
int i;
 
if (name == NULL) {
#if JOBS
currentjob:
if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
error("No current job");
return &jobtab[jobno - 1];
#else
error("No current job");
#endif
} else if (name[0] == '%') {
if (is_digit(name[1])) {
jobno = number(name + 1);
if (jobno > 0 && jobno <= njobs
&& jobtab[jobno - 1].used != 0)
return &jobtab[jobno - 1];
#if JOBS
} else if (name[1] == '%' && name[2] == '\0') {
goto currentjob;
#endif
} else {
struct job *found = NULL;
for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
if (jp->used && jp->nprocs > 0
&& prefix(name + 1, jp->ps[0].cmd)) {
if (found)
error("%s: ambiguous", name);
found = jp;
}
}
if (found)
return found;
}
} else if (is_number(name)) {
pid = number(name);
for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
if (jp->used && jp->nprocs > 0
&& jp->ps[jp->nprocs - 1].pid == pid)
return jp;
}
}
error("No such job: %s", name);
/* NOTREACHED */
}
 
 
 
/*
* Return a new job structure,
*/
 
struct job *
makejob(node, nprocs)
union node *node;
int nprocs;
{
int i;
struct job *jp;
 
for (i = njobs, jp = jobtab ; ; jp++) {
if (--i < 0) {
INTOFF;
if (njobs == 0) {
jobtab = ckmalloc(4 * sizeof jobtab[0]);
} else {
jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
memcpy(jp, jobtab, njobs * sizeof jp[0]);
/* Relocate `ps' pointers */
for (i = 0; i < njobs; i++)
if (jp[i].ps == &jobtab[i].ps0)
jp[i].ps = &jp[i].ps0;
ckfree(jobtab);
jobtab = jp;
}
jp = jobtab + njobs;
for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
INTON;
break;
}
if (jp->used == 0)
break;
}
INTOFF;
jp->state = 0;
jp->used = 1;
jp->changed = 0;
jp->nprocs = 0;
#if JOBS
jp->jobctl = jobctl;
#endif
if (nprocs > 1) {
jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
} else {
jp->ps = &jp->ps0;
}
INTON;
TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
jp - jobtab + 1));
return jp;
}
 
 
/*
* Fork of a subshell. If we are doing job control, give the subshell its
* own process group. Jp is a job structure that the job is to be added to.
* N is the command that will be evaluated by the child. Both jp and n may
* be NULL. The mode parameter can be one of the following:
* FORK_FG - Fork off a foreground process.
* FORK_BG - Fork off a background process.
* FORK_NOJOB - Like FORK_FG, but don't give the process its own
* process group even if job control is on.
*
* When job control is turned off, background processes have their standard
* input redirected to /dev/null (except for the second and later processes
* in a pipeline).
*/
 
int
forkshell(jp, n, mode)
union node *n;
struct job *jp;
int mode;
{
int pid;
int pgrp;
const char *devnull = _PATH_DEVNULL;
const char *nullerr = "Can't open %s";
 
TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
mode));
INTOFF;
pid = fork();
if (pid == -1) {
TRACE(("Fork failed, errno=%d\n", errno));
INTON;
error("Cannot fork");
}
if (pid == 0) {
struct job *p;
int wasroot;
int i;
 
TRACE(("Child shell %d\n", getpid()));
wasroot = rootshell;
rootshell = 0;
closescript();
INTON;
clear_traps();
#if JOBS
jobctl = 0; /* do job control only in root shell */
if (wasroot && mode != FORK_NOJOB && mflag) {
if (jp == NULL || jp->nprocs == 0)
pgrp = getpid();
else
pgrp = jp->ps[0].pid;
setpgid(0, pgrp);
if (mode == FORK_FG) {
/*** this causes superfluous TIOCSPGRPS ***/
#ifdef OLD_TTY_DRIVER
if (ioctl(fd2, TIOCSPGRP, (char *)&pgrp) < 0)
error("TIOCSPGRP failed, errno=%d", errno);
#else
if (tcsetpgrp(fd2, pgrp) < 0)
error("tcsetpgrp failed, errno=%d", errno);
#endif
}
setsignal(SIGTSTP);
setsignal(SIGTTOU);
} else if (mode == FORK_BG) {
ignoresig(SIGINT);
ignoresig(SIGQUIT);
ignoresig(SIGHUP);
if ((jp == NULL || jp->nprocs == 0) &&
! fd0_redirected_p ()) {
close(0);
if (open(devnull, O_RDONLY) != 0)
error(nullerr, devnull);
}
}
#else
if (mode == FORK_BG) {
ignoresig(SIGINT);
ignoresig(SIGQUIT);
ignoresig(SIGHUP);
if ((jp == NULL || jp->nprocs == 0) &&
! fd0_redirected_p ()) {
close(0);
if (open(devnull, O_RDONLY) != 0)
error(nullerr, devnull);
}
}
#endif
for (i = njobs, p = jobtab ; --i >= 0 ; p++)
if (p->used)
freejob(p);
if (wasroot && iflag) {
setsignal(SIGINT);
setsignal(SIGQUIT);
setsignal(SIGTERM);
}
return pid;
}
if (rootshell && mode != FORK_NOJOB && mflag) {
if (jp == NULL || jp->nprocs == 0)
pgrp = pid;
else
pgrp = jp->ps[0].pid;
setpgid(pid, pgrp);
}
if (mode == FORK_BG)
backgndpid = pid; /* set $! */
if (jp) {
struct procstat *ps = &jp->ps[jp->nprocs++];
ps->pid = pid;
ps->status = -1;
ps->cmd = nullstr;
if (iflag && rootshell && n)
ps->cmd = commandtext(n);
}
INTON;
TRACE(("In parent shell: child = %d\n", pid));
return pid;
}
 
 
 
/*
* Wait for job to finish.
*
* Under job control we have the problem that while a child process is
* running interrupts generated by the user are sent to the child but not
* to the shell. This means that an infinite loop started by an inter-
* active user may be hard to kill. With job control turned off, an
* interactive user may place an interactive program inside a loop. If
* the interactive program catches interrupts, the user doesn't want
* these interrupts to also abort the loop. The approach we take here
* is to have the shell ignore interrupt signals while waiting for a
* forground process to terminate, and then send itself an interrupt
* signal if the child process was terminated by an interrupt signal.
* Unfortunately, some programs want to do a bit of cleanup and then
* exit on interrupt; unless these processes terminate themselves by
* sending a signal to themselves (instead of calling exit) they will
* confuse this approach.
*/
 
int
waitforjob(jp)
struct job *jp;
{
#if JOBS
int mypgrp = getpgrp();
#endif
int status;
int st;
struct sigaction act, oact;
 
INTOFF;
intreceived = 0;
#if JOBS
if (!jobctl) {
#else
if (!iflag) {
#endif
sigaction(SIGINT, 0, &act);
act.sa_handler = waitonint;
sigaction(SIGINT, &act, &oact);
}
TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
while (jp->state == 0) {
dowait(1, jp);
}
#if JOBS
if (!jobctl) {
#else
if (!iflag) {
#endif
extern char *trap[];
sigaction(SIGINT, &oact, 0);
if (intreceived && trap[SIGINT]) kill(getpid(), SIGINT);
}
#if JOBS
if (jp->jobctl) {
#ifdef OLD_TTY_DRIVER
if (ioctl(fd2, TIOCSPGRP, (char *)&mypgrp) < 0)
error("TIOCSPGRP failed, errno=%d\n", errno);
#else
if (tcsetpgrp(fd2, mypgrp) < 0)
error("tcsetpgrp failed, errno=%d\n", errno);
#endif
}
if (jp->state == JOBSTOPPED)
curjob = jp - jobtab + 1;
#endif
status = jp->ps[jp->nprocs - 1].status;
/* convert to 8 bits */
if (WIFEXITED(status))
st = WEXITSTATUS(status);
#if JOBS
else if (WIFSTOPPED(status))
st = WSTOPSIG(status) + 128;
#endif
else
st = WTERMSIG(status) + 128;
#if JOBS
if (jp->jobctl) {
/*
* This is truly gross.
* If we're doing job control, then we did a TIOCSPGRP which
* caused us (the shell) to no longer be in the controlling
* session -- so we wouldn't have seen any ^C/SIGINT. So, we
* intuit from the subprocess exit status whether a SIGINT
* occured, and if so interrupt ourselves. Yuck. - mycroft
*/
if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
raise(SIGINT);
}
#endif
if (! JOBS || jp->state == JOBDONE)
freejob(jp);
INTON;
return st;
}
 
 
 
/*
* Wait for a process to terminate.
*/
 
STATIC int
dowait(block, job)
int block;
struct job *job;
{
int pid;
int status;
struct procstat *sp;
struct job *jp;
struct job *thisjob;
int done;
int stopped;
int core;
int sig;
 
TRACE(("dowait(%d) called\n", block));
do {
pid = waitproc(block, &status);
TRACE(("wait returns %d, status=%d\n", pid, status));
} while (pid == -1 && errno == EINTR);
if (pid <= 0)
return pid;
INTOFF;
thisjob = NULL;
for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
if (jp->used) {
done = 1;
stopped = 1;
for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
if (sp->pid == -1)
continue;
if (sp->pid == pid) {
TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
sp->status = status;
thisjob = jp;
}
if (sp->status == -1)
stopped = 0;
else if (WIFSTOPPED(sp->status))
done = 0;
}
if (stopped) { /* stopped or done */
int state = done? JOBDONE : JOBSTOPPED;
if (jp->state != state) {
TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
jp->state = state;
#if JOBS
if (done && curjob == jp - jobtab + 1)
curjob = 0; /* no current job */
#endif
}
}
}
}
INTON;
if (! rootshell || ! iflag || (job && thisjob == job)) {
core = WCOREDUMP(status);
#if JOBS
if (WIFSTOPPED(status)) sig = WSTOPSIG(status);
else
#endif
if (WIFEXITED(status)) sig = 0;
else sig = WTERMSIG(status);
 
if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
if (thisjob != job)
outfmt(out2, "%d: ", pid);
#if JOBS
if (sig == SIGTSTP && rootshell && iflag)
outfmt(out2, "%%%ld ",
(long)(job - jobtab + 1));
#endif
if (sig < NSIG && sys_siglist[sig])
out2str(sys_siglist[sig]);
else
outfmt(out2, "Signal %d", sig);
if (core)
out2str(" - core dumped");
out2c('\n');
flushout(&errout);
} else {
TRACE(("Not printing status: status=%d, sig=%d\n",
status, sig));
}
} else {
TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
if (thisjob)
thisjob->changed = 1;
}
return pid;
}
 
 
 
/*
* Do a wait system call. If job control is compiled in, we accept
* stopped processes. If block is zero, we return a value of zero
* rather than blocking.
*
* System V doesn't have a non-blocking wait system call. It does
* have a SIGCLD signal that is sent to a process when one of it's
* children dies. The obvious way to use SIGCLD would be to install
* a handler for SIGCLD which simply bumped a counter when a SIGCLD
* was received, and have waitproc bump another counter when it got
* the status of a process. Waitproc would then know that a wait
* system call would not block if the two counters were different.
* This approach doesn't work because if a process has children that
* have not been waited for, System V will send it a SIGCLD when it
* installs a signal handler for SIGCLD. What this means is that when
* a child exits, the shell will be sent SIGCLD signals continuously
* until is runs out of stack space, unless it does a wait call before
* restoring the signal handler. The code below takes advantage of
* this (mis)feature by installing a signal handler for SIGCLD and
* then checking to see whether it was called. If there are any
* children to be waited for, it will be.
*
* If neither SYSV nor BSD is defined, we don't implement nonblocking
* waits at all. In this case, the user will not be informed when
* a background process until the next time she runs a real program
* (as opposed to running a builtin command or just typing return),
* and the jobs command may give out of date information.
*/
 
#ifdef SYSV
STATIC int gotsigchild;
 
STATIC int onsigchild() {
gotsigchild = 1;
}
#endif
 
 
STATIC int
waitproc(block, status)
int block;
int *status;
{
#ifdef BSD
int flags;
 
flags = 0;
#if JOBS
if (jobctl)
flags |= WUNTRACED;
#endif
if (block == 0)
flags |= WNOHANG;
return wait3(status, flags, (struct rusage *)NULL);
#else
#ifdef SYSV
int (*save)();
 
if (block == 0) {
gotsigchild = 0;
save = signal(SIGCLD, onsigchild);
signal(SIGCLD, save);
if (gotsigchild == 0)
return 0;
}
return wait(status);
#else
if (block == 0)
return 0;
return wait(status);
#endif
#endif
}
 
/*
* return 1 if there are stopped jobs, otherwise 0
*/
int job_warning = 0;
int
stoppedjobs()
{
int jobno;
struct job *jp;
 
if (job_warning)
return (0);
for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
if (jp->used == 0)
continue;
if (jp->state == JOBSTOPPED) {
out2str("You have stopped jobs.\n");
job_warning = 2;
return (1);
}
}
 
return (0);
}
 
/*
* Return a string identifying a command (to be printed by the
* jobs command.
*/
 
STATIC char *cmdnextc;
STATIC int cmdnleft;
#define MAXCMDTEXT 200
 
char *
commandtext(n)
union node *n;
{
char *name;
 
cmdnextc = name = ckmalloc(MAXCMDTEXT);
cmdnleft = MAXCMDTEXT - 4;
cmdtxt(n);
*cmdnextc = '\0';
return name;
}
 
 
STATIC void
cmdtxt(n)
union node *n;
{
union node *np;
struct nodelist *lp;
const char *p;
int i;
char s[2];
 
if (n == NULL)
return;
switch (n->type) {
case NSEMI:
cmdtxt(n->nbinary.ch1);
cmdputs("; ");
cmdtxt(n->nbinary.ch2);
break;
case NAND:
cmdtxt(n->nbinary.ch1);
cmdputs(" && ");
cmdtxt(n->nbinary.ch2);
break;
case NOR:
cmdtxt(n->nbinary.ch1);
cmdputs(" || ");
cmdtxt(n->nbinary.ch2);
break;
case NPIPE:
for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
cmdtxt(lp->n);
if (lp->next)
cmdputs(" | ");
}
break;
case NSUBSHELL:
cmdputs("(");
cmdtxt(n->nredir.n);
cmdputs(")");
break;
case NREDIR:
case NBACKGND:
cmdtxt(n->nredir.n);
break;
case NIF:
cmdputs("if ");
cmdtxt(n->nif.test);
cmdputs("; then ");
cmdtxt(n->nif.ifpart);
cmdputs("...");
break;
case NWHILE:
cmdputs("while ");
goto until;
case NUNTIL:
cmdputs("until ");
until:
cmdtxt(n->nbinary.ch1);
cmdputs("; do ");
cmdtxt(n->nbinary.ch2);
cmdputs("; done");
break;
case NFOR:
cmdputs("for ");
cmdputs(n->nfor.var);
cmdputs(" in ...");
break;
case NCASE:
cmdputs("case ");
cmdputs(n->ncase.expr->narg.text);
cmdputs(" in ...");
break;
case NDEFUN:
cmdputs(n->narg.text);
cmdputs("() ...");
break;
case NCMD:
for (np = n->ncmd.args ; np ; np = np->narg.next) {
cmdtxt(np);
if (np->narg.next)
cmdputs(" ");
}
for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
cmdputs(" ");
cmdtxt(np);
}
break;
case NARG:
cmdputs(n->narg.text);
break;
case NTO:
p = ">"; i = 1; goto redir;
case NAPPEND:
p = ">>"; i = 1; goto redir;
case NTOFD:
p = ">&"; i = 1; goto redir;
case NTOOV:
p = ">|"; i = 1; goto redir;
case NFROM:
p = "<"; i = 0; goto redir;
case NFROMFD:
p = "<&"; i = 0; goto redir;
case NFROMTO:
p = "<>"; i = 0; goto redir;
redir:
if (n->nfile.fd != i) {
s[0] = n->nfile.fd + '0';
s[1] = '\0';
cmdputs(s);
}
cmdputs(p);
if (n->type == NTOFD || n->type == NFROMFD) {
s[0] = n->ndup.dupfd + '0';
s[1] = '\0';
cmdputs(s);
} else {
cmdtxt(n->nfile.fname);
}
break;
case NHERE:
case NXHERE:
cmdputs("<<...");
break;
default:
cmdputs("???");
break;
}
}
 
 
 
STATIC void
cmdputs(s)
const char *s;
{
const char *p;
char *q;
char c;
int subtype = 0;
 
if (cmdnleft <= 0)
return;
p = s;
q = cmdnextc;
while ((c = *p++) != '\0') {
if (c == CTLESC)
*q++ = *p++;
else if (c == CTLVAR) {
*q++ = '$';
if (--cmdnleft > 0)
*q++ = '{';
subtype = *p++;
} else if (c == '=' && subtype != 0) {
*q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
subtype = 0;
} else if (c == CTLENDVAR) {
*q++ = '}';
} else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
cmdnleft++; /* ignore it */
else
*q++ = c;
if (--cmdnleft <= 0) {
*q++ = '.';
*q++ = '.';
*q++ = '.';
break;
}
}
cmdnextc = q;
}
 
STATIC void waitonint(int sig) {
intreceived = 1;
return;
}
/trunk/uspace/app/ash/memalloc.h
0,0 → 1,81
/* $NetBSD: memalloc.h,v 1.11 2000/11/01 19:56:01 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)memalloc.h 8.2 (Berkeley) 5/4/95
*/
 
struct stackmark {
struct stack_block *stackp;
char *stacknxt;
int stacknleft;
struct stackmark *marknext;
};
 
 
extern char *stacknxt;
extern int stacknleft;
extern int sstrnleft;
extern int herefd;
 
pointer ckmalloc (int);
pointer ckrealloc (pointer, int);
char *savestr (char *);
pointer stalloc (int);
void stunalloc (pointer);
void setstackmark (struct stackmark *);
void popstackmark (struct stackmark *);
void growstackblock (void);
void grabstackblock (int);
char *growstackstr (void);
char *makestrspace (void);
void ungrabstackstr (char *, char *);
 
 
 
#define stackblock() stacknxt
#define stackblocksize() stacknleft
#define STARTSTACKSTR(p) p = stackblock(), sstrnleft = stackblocksize()
#define STPUTC(c, p) (--sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(), *p++ = (c)))
#define CHECKSTRSPACE(n, p) { if (sstrnleft < n) p = makestrspace(); }
#define USTPUTC(c, p) (--sstrnleft, *p++ = (c))
#define STACKSTRNUL(p) (sstrnleft == 0? (p = growstackstr(), *p = '\0') : (*p = '\0'))
#define STUNPUTC(p) (++sstrnleft, --p)
#define STTOPC(p) p[-1]
#define STADJUST(amount, p) (p += (amount), sstrnleft -= (amount))
#define grabstackstr(p) stalloc(stackblocksize() - sstrnleft)
 
#define ckfree(p) free((pointer)(p))
/trunk/uspace/app/ash/alias.h
0,0 → 1,53
/* $NetBSD: alias.h,v 1.4 1995/05/11 21:28:42 christos 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)alias.h 8.2 (Berkeley) 5/4/95
*/
 
#define ALIASINUSE 1
 
struct alias {
struct alias *next;
char *name;
char *val;
int flag;
};
 
struct alias *lookupalias (char *, int);
int aliascmd (int, char **);
int unaliascmd (int, char **);
void rmaliases (void);
/trunk/uspace/app/ash/output.c
0,0 → 1,634
/* $NetBSD: output.c,v 1.23 2001/01/07 23:39:07 lukem 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
 
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)output.c 8.2 (Berkeley) 5/4/95";
#else
__RCSID("$NetBSD: output.c,v 1.23 2001/01/07 23:39:07 lukem Exp $");
#endif
#endif /* not lint */
 
/*
* Shell output routines. We use our own output routines because:
* When a builtin command is interrupted we have to discard
* any pending output.
* When a builtin command appears in back quotes, we want to
* save the output of the command in a region obtained
* via malloc, rather than doing a fork and reading the
* output of the command via a pipe.
* Our output routines may be smaller than the stdio routines.
*/
 
#include <sys/types.h> /* quad_t */
#include <sys/param.h> /* BSD4_4 */
#include <sys/ioctl.h>
 
#include <stdio.h> /* defines BUFSIZ */
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
#undef CEOF /* get rid of the redefine warning */
#include <fcntl.h>
#endif
 
#include "shell.h"
#include "syntax.h"
#include "output.h"
#include "memalloc.h"
#include "error.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 */
 
 
#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
struct output output = {NULL, NULL, 0, NULL, 0, 1, 0};
struct output errout = {NULL, NULL, 0, NULL, 0, 2, 0};
struct output memout = {NULL, NULL, 0, NULL, 0, MEM_OUT, 0};
#else
struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
struct output errout = {NULL, 0, NULL, 100, 2, 0};
struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};
#endif
struct output *out1 = &output;
struct output *out2 = &errout;
 
 
 
#ifdef mkinit
 
INCLUDE "output.h"
INCLUDE "memalloc.h"
 
INIT {
#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
initstreams();
#endif
}
 
RESET {
out1 = &output;
out2 = &errout;
#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
if (memout.stream != NULL)
closememout();
#endif
if (memout.buf != NULL) {
ckfree(memout.buf);
memout.buf = NULL;
}
}
 
#endif
 
 
#ifdef notdef /* no longer used */
/*
* Set up an output file to write to memory rather than a file.
*/
 
void
open_mem(block, length, file)
char *block;
int length;
struct output *file;
{
file->nextc = block;
file->nleft = --length;
file->fd = BLOCK_OUT;
file->flags = 0;
}
#endif
 
 
void
outstr(p, file)
const char *p;
struct output *file;
{
#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
fputs(p, file->stream);
#else
while (*p)
outc(*p++, file);
#endif
if (file == out2)
flushout(file);
}
 
 
#if !defined(_GNU_SOURCE) || defined(__UCLIBC__)
char out_junk[16];
 
 
void
emptyoutbuf(dest)
struct output *dest;
{
int offset;
 
if (dest->fd == BLOCK_OUT) {
dest->nextc = out_junk;
dest->nleft = sizeof out_junk;
dest->flags |= OUTPUT_ERR;
} else if (dest->buf == NULL) {
INTOFF;
dest->buf = ckmalloc(dest->bufsize);
dest->nextc = dest->buf;
dest->nleft = dest->bufsize;
INTON;
} else if (dest->fd == MEM_OUT) {
offset = dest->bufsize;
INTOFF;
dest->bufsize <<= 1;
dest->buf = ckrealloc(dest->buf, dest->bufsize);
dest->nleft = dest->bufsize - offset;
dest->nextc = dest->buf + offset;
INTON;
} else {
flushout(dest);
}
dest->nleft--;
}
#endif
 
 
void
flushall() {
flushout(&output);
flushout(&errout);
}
 
 
#if !defined(_GNU_SOURCE) || defined(__UCLIBC__)
void
flushout(dest)
struct output *dest;
{
if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0)
return;
if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0)
dest->flags |= OUTPUT_ERR;
dest->nextc = dest->buf;
dest->nleft = dest->bufsize;
}
#endif
 
 
void
freestdout() {
INTOFF;
if (output.buf) {
ckfree(output.buf);
output.buf = NULL;
output.nleft = 0;
}
INTON;
}
 
 
void
#ifdef __STDC__
outfmt(struct output *file, const char *fmt, ...)
#else
void
outfmt(va_alist)
va_dcl
#endif
{
va_list ap;
#ifndef __STDC__
struct output *file;
const char *fmt;
 
va_start(ap);
file = va_arg(ap, struct output *);
fmt = va_arg(ap, const char *);
#else
va_start(ap, fmt);
#endif
doformat(file, fmt, ap);
va_end(ap);
}
 
 
void
#ifdef __STDC__
out1fmt(const char *fmt, ...)
#else
out1fmt(va_alist)
va_dcl
#endif
{
va_list ap;
#ifndef __STDC__
const char *fmt;
 
va_start(ap);
fmt = va_arg(ap, const char *);
#else
va_start(ap, fmt);
#endif
doformat(out1, fmt, ap);
va_end(ap);
}
 
#if !defined(__GLIBC__) && !defined(__UCLIBC__)
void
#ifdef __STDC__
dprintf(const char *fmt, ...)
#else
dprintf(va_alist)
va_dcl
#endif
{
va_list ap;
#ifndef __STDC__
const char *fmt;
 
va_start(ap);
fmt = va_arg(ap, const char *);
#else
va_start(ap, fmt);
#endif
doformat(out2, fmt, ap);
va_end(ap);
flushout(out2);
}
#endif
 
void
#ifdef __STDC__
fmtstr(char *outbuf, size_t length, const char *fmt, ...)
#else
fmtstr(va_alist)
va_dcl
#endif
{
va_list ap;
#if !defined(_GNU_SOURCE) || defined(__UCLIBC__)
struct output strout;
#endif
#ifndef __STDC__
char *outbuf;
size_t length;
const char *fmt;
 
va_start(ap);
outbuf = va_arg(ap, char *);
length = va_arg(ap, size_t);
fmt = va_arg(ap, const char *);
#else
va_start(ap, fmt);
#endif
#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
vsnprintf(outbuf, length, fmt, ap);
#else
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
}
 
#if !defined(_GNU_SOURCE) || defined(__UCLIBC__)
/*
* Formatted output. This routine handles a subset of the printf formats:
* - Formats supported: d, u, o, p, X, s, and c.
* - The x format is also accepted but is treated like X.
* - The l, ll and q modifiers are accepted.
* - The - and # flags are accepted; # only works with the o format.
* - Width and precision may be specified with any format except c.
* - An * may be given for the width or precision.
* - The obsolete practice of preceding the width with a zero to get
* zero padding is not supported; use the precision field.
* - A % may be printed by writing %% in the format string.
*/
 
#define TEMPSIZE 24
 
static const char digit[] = "0123456789ABCDEF";
 
#ifdef BSD4_4
#define HAVE_VASPRINTF 1
#endif
 
 
void
doformat(dest, f, ap)
struct output *dest;
const char *f; /* format string */
va_list ap;
{
#if HAVE_VASPRINTF
char *s;
 
vasprintf(&s, f, ap);
outstr(s, dest);
free(s);
#else /* !HAVE_VASPRINTF */
char c;
char temp[TEMPSIZE];
int flushleft;
int sharp;
int width;
int prec;
int islong;
int isquad;
char *p;
int sign;
#ifdef BSD4_4
quad_t l;
u_quad_t num;
#else
long l;
u_long num;
#endif
unsigned base;
int len;
int size;
int pad;
 
while ((c = *f++) != '\0') {
if (c != '%') {
outc(c, dest);
continue;
}
flushleft = 0;
sharp = 0;
width = 0;
prec = -1;
islong = 0;
isquad = 0;
for (;;) {
if (*f == '-')
flushleft++;
else if (*f == '#')
sharp++;
else
break;
f++;
}
if (*f == '*') {
width = va_arg(ap, int);
f++;
} else {
while (is_digit(*f)) {
width = 10 * width + digit_val(*f++);
}
}
if (*f == '.') {
if (*++f == '*') {
prec = va_arg(ap, int);
f++;
} else {
prec = 0;
while (is_digit(*f)) {
prec = 10 * prec + digit_val(*f++);
}
}
}
if (*f == 'l') {
f++;
if (*f == 'l') {
isquad++;
f++;
} else
islong++;
} else if (*f == 'q') {
isquad++;
f++;
}
switch (*f) {
case 'd':
#ifdef BSD4_4
if (isquad)
l = va_arg(ap, quad_t);
else
#endif
if (islong)
l = va_arg(ap, long);
else
l = va_arg(ap, int);
sign = 0;
num = l;
if (l < 0) {
num = -l;
sign = 1;
}
base = 10;
goto number;
case 'u':
base = 10;
goto uns_number;
case 'o':
base = 8;
goto uns_number;
case 'p':
outc('0', dest);
outc('x', dest);
/*FALLTHROUGH*/
case 'x':
/* we don't implement 'x'; treat like 'X' */
case 'X':
base = 16;
uns_number: /* an unsigned number */
sign = 0;
#ifdef BSD4_4
if (isquad)
num = va_arg(ap, u_quad_t);
else
#endif
if (islong)
num = va_arg(ap, unsigned long);
else
num = va_arg(ap, unsigned int);
number: /* process a number */
p = temp + TEMPSIZE - 1;
*p = '\0';
while (num) {
*--p = digit[num % base];
num /= base;
}
len = (temp + TEMPSIZE - 1) - p;
if (prec < 0)
prec = 1;
if (sharp && *f == 'o' && prec <= len)
prec = len + 1;
pad = 0;
if (width) {
size = len;
if (size < prec)
size = prec;
size += sign;
pad = width - size;
if (flushleft == 0) {
while (--pad >= 0)
outc(' ', dest);
}
}
if (sign)
outc('-', dest);
prec -= len;
while (--prec >= 0)
outc('0', dest);
while (*p)
outc(*p++, dest);
while (--pad >= 0)
outc(' ', dest);
break;
case 's':
p = va_arg(ap, char *);
pad = 0;
if (width) {
len = strlen(p);
if (prec >= 0 && len > prec)
len = prec;
pad = width - len;
if (flushleft == 0) {
while (--pad >= 0)
outc(' ', dest);
}
}
prec++;
while (--prec != 0 && *p)
outc(*p++, dest);
while (--pad >= 0)
outc(' ', dest);
break;
case 'c':
c = va_arg(ap, int);
outc(c, dest);
break;
default:
outc(*f, dest);
break;
}
f++;
}
#endif /* !HAVE_VASPRINTF */
}
#endif
 
 
/*
* Version of write which resumes after a signal is caught.
*/
 
int
xwrite(fd, buf, nbytes)
int fd;
const char *buf;
int nbytes;
{
int ntry;
int i;
int n;
 
n = nbytes;
ntry = 0;
for (;;) {
i = write(fd, buf, n);
if (i > 0) {
if ((n -= i) <= 0)
return nbytes;
buf += i;
ntry = 0;
} else if (i == 0) {
if (++ntry > 10)
return nbytes - n;
} else if (errno != EINTR) {
return -1;
}
}
}
 
 
 
#ifdef notdef
/*
* Version of ioctl that retries after a signal is caught.
* XXX unused function
*/
 
int
xioctl(fd, request, arg)
int fd;
unsigned long request;
char * arg;
{
int i;
 
while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR);
return i;
}
#endif
 
 
#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
void initstreams() {
output.stream = stdout;
errout.stream = stderr;
}
 
 
void
openmemout() {
memout.stream = open_memstream(&memout.buf, &memout.bufsize);
}
 
 
void
closememout() {
INTOFF;
fclose(memout.stream);
memout.stream = NULL;
INTON;
}
#endif
/trunk/uspace/app/ash/parser.h
0,0 → 1,83
/* $NetBSD: parser.h,v 1.14 2000/07/27 04:09:28 cgd 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)parser.h 8.3 (Berkeley) 5/4/95
*/
 
/* control characters in argument strings */
#define CTLESC '\201'
#define CTLVAR '\202'
#define CTLENDVAR '\203'
#define CTLBACKQ '\204'
#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
/* CTLBACKQ | CTLQUOTE == '\205' */
#define CTLARI '\206'
#define CTLENDARI '\207'
#define CTLQUOTEMARK '\210'
 
/* variable substitution byte (follows CTLVAR) */
#define VSTYPE 0x0f /* type of variable substitution */
#define VSNUL 0x10 /* colon--treat the empty string as unset */
#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
 
/* values of VSTYPE field */
#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
#define VSMINUS 0x2 /* ${var-text} */
#define VSPLUS 0x3 /* ${var+text} */
#define VSQUESTION 0x4 /* ${var?message} */
#define VSASSIGN 0x5 /* ${var=text} */
#define VSTRIMLEFT 0x6 /* ${var#pattern} */
#define VSTRIMLEFTMAX 0x7 /* ${var##pattern} */
#define VSTRIMRIGHT 0x8 /* ${var%pattern} */
#define VSTRIMRIGHTMAX 0x9 /* ${var%%pattern} */
#define VSLENGTH 0xa /* ${#var} */
 
 
/*
* NEOF is returned by parsecmd when it encounters an end of file. It
* must be distinct from NULL, so we use the address of a variable that
* happens to be handy.
*/
extern int tokpushback;
#define NEOF ((union node *)&tokpushback)
extern int whichprompt; /* 1 == PS1, 2 == PS2 */
 
 
union node *parsecmd(int);
void fixredir(union node *, const char *, int);
int goodname(char *);
const char *getprompt(void *);
/trunk/uspace/app/ash/jobs.h
0,0 → 1,98
/* $NetBSD: jobs.h,v 1.12 2000/05/22 10:18:47 elric 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)jobs.h 8.2 (Berkeley) 5/4/95
*/
 
/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
#define FORK_FG 0
#define FORK_BG 1
#define FORK_NOJOB 2
 
 
/*
* A job structure contains information about a job. A job is either a
* single process or a set of processes contained in a pipeline. In the
* latter case, pidlist will be non-NULL, and will point to a -1 terminated
* array of pids.
*/
 
struct procstat {
pid_t pid; /* process id */
int status; /* status flags (defined above) */
char *cmd; /* 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 */
short pgrp; /* process group of this job */
char state; /* true if job is finished */
char used; /* true if this entry is in used */
char changed; /* true if status has changed */
#if JOBS
char jobctl; /* job running under job control */
#endif
};
 
extern short backgndpid; /* pid of last background process */
extern int job_warning; /* user was warned about stopped jobs */
 
void setjobctl (int);
int killcmd (int, char **);
int fgcmd (int, char **);
int bgcmd (int, char **);
int jobscmd (int, char **);
void showjobs (int);
int waitcmd (int, char **);
int jobidcmd (int, char **);
struct job *makejob (union node *, int);
int forkshell (struct job *, union node *, int);
int waitforjob (struct job *);
int stoppedjobs (void);
char *commandtext (union node *);
 
#if ! JOBS
#define setjobctl(on) /* do nothing */
#endif
/trunk/uspace/app/ash/output.h
0,0 → 1,110
/* $NetBSD: output.h,v 1.14 1998/01/31 12:37:55 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)output.h 8.2 (Berkeley) 5/4/95
*/
 
#ifndef OUTPUT_INCL
 
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
#include <stdio.h>
#endif
 
struct output {
#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
FILE *stream;
#endif
char *nextc;
int nleft;
char *buf;
int bufsize;
int fd;
short flags;
};
 
extern struct output output;
extern struct output errout;
extern struct output memout;
extern struct output *out1;
extern struct output *out2;
 
void outstr (const char *, struct output *);
#ifndef _GNU_SOURCE
void emptyoutbuf (struct output *);
#endif
void flushall (void);
#ifndef _GNU_SOURCE
void flushout (struct output *);
#endif
void freestdout (void);
void outfmt (struct output *, const char *, ...)
__attribute__((__format__(__printf__,2,3)));
void out1fmt (const char *, ...)
__attribute__((__format__(__printf__,1,2)));
#if !defined(__GLIBC__) && !defined(__UCLIBC__)
void dprintf (const char *, ...)
__attribute__((__format__(__printf__,1,2)));
#endif
void fmtstr (char *, size_t, const char *, ...)
__attribute__((__format__(__printf__,3,4)));
#ifndef _GNU_SOURCE
void doformat (struct output *, const char *, va_list);
#endif
int xwrite (int, const char *, int);
#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
void initstreams (void);
void openmemout (void);
void closememout (void);
 
#define outc(c, o) putc(c, (o)->stream)
#define flushout(o) fflush((o)->stream)
#define doformat(d, f, a) vfprintf((d)->stream, f, a)
#else
#define outc(c, file) (--(file)->nleft < 0? (emptyoutbuf(file), *(file)->nextc++ = (c)) : (*(file)->nextc++ = (c)))
#endif
#define out1c(c) outc(c, out1)
#define out2c(c) outc(c, out2)
#define out1str(s) outstr(s, out1)
#define out2str(s) outstr(s, out2)
 
#define OUTPUT_INCL
#endif
/trunk/uspace/app/ash/builtins.def
0,0 → 1,96
#!/bin/sh -
# $NetBSD: builtins.def,v 1.15 2000/04/09 23:27:03 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. All advertising materials mentioning features or use of this software
# must display the following acknowledgement:
# This product includes software developed by the University of
# California, Berkeley and its contributors.
# 4. Neither the name of the University nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# @(#)builtins.def 8.4 (Berkeley) 5/4/95
 
#
# This file lists all the builtin commands. The first column is the name
# of a C routine. The -j flag, 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 SMALL 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!
 
bltincmd builtin
#alloccmd alloc
bgcmd -j bg
breakcmd break continue
#catfcmd catf
cdcmd cd chdir
commandcmd command
dotcmd .
echocmd echo
evalcmd eval
execcmd exec
exitcmd exit
expcmd exp let
exportcmd export readonly
#exprcmd expr
falsecmd false
histcmd -h fc
fgcmd -j fg
getoptscmd getopts
hashcmd hash
jobidcmd jobid
jobscmd jobs
killcmd -j kill
#linecmd line
localcmd local
#nlechocmd nlecho
#printfcmd printf
pwdcmd pwd
readcmd read
returncmd return
setcmd set
setvarcmd setvar
shiftcmd shift
trapcmd trap
truecmd : true
typecmd type
umaskcmd umask
unaliascmd unalias
unsetcmd unset
waitcmd wait
#foocmd foo
aliascmd alias
ulimitcmd ulimit
testcmd test [
timescmd times
/trunk/uspace/app/ash/mystring.c
0,0 → 1,144
/* $NetBSD: mystring.c,v 1.14 1999/07/09 03:05:50 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
 
#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.14 1999/07/09 03:05:50 christos Exp $");
#endif
#endif /* not lint */
 
/*
* String functions.
*
* equal(s1, s2) Return true if strings are equal.
* scopy(from, to) Copy a string.
* scopyn(from, to, n) Like scopy, but checks for overflow.
* number(s) Convert a string of digits to an integer.
* is_number(s) Return true if s is a string of digits.
*/
 
#include <stdlib.h>
#include "shell.h"
#include "syntax.h"
#include "error.h"
#include "mystring.h"
 
 
char nullstr[1]; /* zero length string */
 
/*
* equal - #defined in mystring.h
*/
 
/*
* scopy - #defined in mystring.h
*/
 
 
/*
* scopyn - copy a string from "from" to "to", truncating the string
* if necessary. "To" is always nul terminated, even if
* truncation is performed. "Size" is the size of "to".
*/
 
void
scopyn(from, to, size)
char const *from;
char *to;
int size;
{
 
while (--size > 0) {
if ((*to++ = *from++) == '\0')
return;
}
*to = '\0';
}
 
 
/*
* prefix -- see if pfx is a prefix of string.
*/
 
int
prefix(pfx, string)
char const *pfx;
char const *string;
{
while (*pfx) {
if (*pfx++ != *string++)
return 0;
}
return 1;
}
 
 
/*
* Convert a string of digits to an integer, printing an error message on
* failure.
*/
 
int
number(s)
const char *s;
{
 
if (! is_number(s))
error("Illegal number: %s", s);
return atoi(s);
}
 
 
 
/*
* Check for a valid number. This should be elsewhere.
*/
 
int
is_number(p)
const char *p;
{
do {
if (! is_digit(*p))
return 0;
} while (*++p != '\0');
return 1;
}
/trunk/uspace/app/ash/tags
0,0 → 1,1207
!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
!_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/
!_TAG_PROGRAM_NAME Exuberant Ctags //
!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/
!_TAG_PROGRAM_VERSION 5.5.4 //
ADDCMD setmode.c 170;" d file:
ALIASINUSE alias.h 41;" d
ALIGN machdep.h 52;" d
ALL error.c 223;" d file:
ARB exec.c 88;" d file:
ARITH_ADD arith.c /^ ARITH_ADD = 275,$/;" e enum:yytokentype file:
ARITH_ADD arith.c 114;" d file:
ARITH_ADD arith.h /^ ARITH_ADD = 275,$/;" e enum:yytokentype
ARITH_ADD arith.h 87;" d
ARITH_AND arith.c /^ ARITH_AND = 262,$/;" e enum:yytokentype file:
ARITH_AND arith.c 101;" d file:
ARITH_AND arith.h /^ ARITH_AND = 262,$/;" e enum:yytokentype
ARITH_AND arith.h 74;" d
ARITH_BAND arith.c /^ ARITH_BAND = 265,$/;" e enum:yytokentype file:
ARITH_BAND arith.c 104;" d file:
ARITH_BAND arith.h /^ ARITH_BAND = 265,$/;" e enum:yytokentype
ARITH_BAND arith.h 77;" d
ARITH_BNOT arith.c /^ ARITH_BNOT = 279,$/;" e enum:yytokentype file:
ARITH_BNOT arith.c 118;" d file:
ARITH_BNOT arith.h /^ ARITH_BNOT = 279,$/;" e enum:yytokentype
ARITH_BNOT arith.h 91;" d
ARITH_BOR arith.c /^ ARITH_BOR = 263,$/;" e enum:yytokentype file:
ARITH_BOR arith.c 102;" d file:
ARITH_BOR arith.h /^ ARITH_BOR = 263,$/;" e enum:yytokentype
ARITH_BOR arith.h 75;" d
ARITH_BXOR arith.c /^ ARITH_BXOR = 264,$/;" e enum:yytokentype file:
ARITH_BXOR arith.c 103;" d file:
ARITH_BXOR arith.h /^ ARITH_BXOR = 264,$/;" e enum:yytokentype
ARITH_BXOR arith.h 76;" d
ARITH_DIV arith.c /^ ARITH_DIV = 277,$/;" e enum:yytokentype file:
ARITH_DIV arith.c 116;" d file:
ARITH_DIV arith.h /^ ARITH_DIV = 277,$/;" e enum:yytokentype
ARITH_DIV arith.h 89;" d
ARITH_EQ arith.c /^ ARITH_EQ = 267,$/;" e enum:yytokentype file:
ARITH_EQ arith.c 106;" d file:
ARITH_EQ arith.h /^ ARITH_EQ = 267,$/;" e enum:yytokentype
ARITH_EQ arith.h 79;" d
ARITH_GE arith.c /^ ARITH_GE = 269,$/;" e enum:yytokentype file:
ARITH_GE arith.c 108;" d file:
ARITH_GE arith.h /^ ARITH_GE = 269,$/;" e enum:yytokentype
ARITH_GE arith.h 81;" d
ARITH_GT arith.c /^ ARITH_GT = 270,$/;" e enum:yytokentype file:
ARITH_GT arith.c 109;" d file:
ARITH_GT arith.h /^ ARITH_GT = 270,$/;" e enum:yytokentype
ARITH_GT arith.h 82;" d
ARITH_LE arith.c /^ ARITH_LE = 268,$/;" e enum:yytokentype file:
ARITH_LE arith.c 107;" d file:
ARITH_LE arith.h /^ ARITH_LE = 268,$/;" e enum:yytokentype
ARITH_LE arith.h 80;" d
ARITH_LPAREN arith.c /^ ARITH_LPAREN = 259,$/;" e enum:yytokentype file:
ARITH_LPAREN arith.c 98;" d file:
ARITH_LPAREN arith.h /^ ARITH_LPAREN = 259,$/;" e enum:yytokentype
ARITH_LPAREN arith.h 71;" d
ARITH_LSHIFT arith.c /^ ARITH_LSHIFT = 273,$/;" e enum:yytokentype file:
ARITH_LSHIFT arith.c 112;" d file:
ARITH_LSHIFT arith.h /^ ARITH_LSHIFT = 273,$/;" e enum:yytokentype
ARITH_LSHIFT arith.h 85;" d
ARITH_LT arith.c /^ ARITH_LT = 271,$/;" e enum:yytokentype file:
ARITH_LT arith.c 110;" d file:
ARITH_LT arith.h /^ ARITH_LT = 271,$/;" e enum:yytokentype
ARITH_LT arith.h 83;" d
ARITH_MUL arith.c /^ ARITH_MUL = 278,$/;" e enum:yytokentype file:
ARITH_MUL arith.c 117;" d file:
ARITH_MUL arith.h /^ ARITH_MUL = 278,$/;" e enum:yytokentype
ARITH_MUL arith.h 90;" d
ARITH_NE arith.c /^ ARITH_NE = 266,$/;" e enum:yytokentype file:
ARITH_NE arith.c 105;" d file:
ARITH_NE arith.h /^ ARITH_NE = 266,$/;" e enum:yytokentype
ARITH_NE arith.h 78;" d
ARITH_NOT arith.c /^ ARITH_NOT = 280,$/;" e enum:yytokentype file:
ARITH_NOT arith.c 119;" d file:
ARITH_NOT arith.h /^ ARITH_NOT = 280,$/;" e enum:yytokentype
ARITH_NOT arith.h 92;" d
ARITH_NUM arith.c /^ ARITH_NUM = 258,$/;" e enum:yytokentype file:
ARITH_NUM arith.c 97;" d file:
ARITH_NUM arith.h /^ ARITH_NUM = 258,$/;" e enum:yytokentype
ARITH_NUM arith.h 70;" d
ARITH_OR arith.c /^ ARITH_OR = 261,$/;" e enum:yytokentype file:
ARITH_OR arith.c 100;" d file:
ARITH_OR arith.h /^ ARITH_OR = 261,$/;" e enum:yytokentype
ARITH_OR arith.h 73;" d
ARITH_REM arith.c /^ ARITH_REM = 276,$/;" e enum:yytokentype file:
ARITH_REM arith.c 115;" d file:
ARITH_REM arith.h /^ ARITH_REM = 276,$/;" e enum:yytokentype
ARITH_REM arith.h 88;" d
ARITH_RPAREN arith.c /^ ARITH_RPAREN = 260,$/;" e enum:yytokentype file:
ARITH_RPAREN arith.c 99;" d file:
ARITH_RPAREN arith.h /^ ARITH_RPAREN = 260,$/;" e enum:yytokentype
ARITH_RPAREN arith.h 72;" d
ARITH_RSHIFT arith.c /^ ARITH_RSHIFT = 272,$/;" e enum:yytokentype file:
ARITH_RSHIFT arith.c 111;" d file:
ARITH_RSHIFT arith.h /^ ARITH_RSHIFT = 272,$/;" e enum:yytokentype
ARITH_RSHIFT arith.h 84;" d
ARITH_SUB arith.c /^ ARITH_SUB = 274,$/;" e enum:yytokentype file:
ARITH_SUB arith.c 113;" d file:
ARITH_SUB arith.h /^ ARITH_SUB = 274,$/;" e enum:yytokentype
ARITH_SUB arith.h 86;" d
ARITH_UNARYMINUS arith.c /^ ARITH_UNARYMINUS = 282$/;" e enum:yytokentype file:
ARITH_UNARYMINUS arith.c 121;" d file:
ARITH_UNARYMINUS arith.h /^ ARITH_UNARYMINUS = 282$/;" e enum:yytokentype
ARITH_UNARYMINUS arith.h 94;" d
ARITH_UNARYPLUS arith.c /^ ARITH_UNARYPLUS = 281,$/;" e enum:yytokentype file:
ARITH_UNARYPLUS arith.c 120;" d file:
ARITH_UNARYPLUS arith.h /^ ARITH_UNARYPLUS = 281,$/;" e enum:yytokentype
ARITH_UNARYPLUS arith.h 93;" d
ATABSIZE alias.c 58;" d file:
BAND bltin/test.c /^ BAND,$/;" e enum:token file:
BBINOP bltin/test.c /^ BBINOP,$/;" e enum:token_types file:
BINOP bltin/test.c /^ BINOP,$/;" e enum:token_types file:
BITCMD setmode.c /^} BITCMD;$/;" t file:
BLOCKSIZE mkinit.c 90;" d file:
BLOCK_OUT output.c 81;" d file:
BOR bltin/test.c /^ BOR,$/;" e enum:token file:
BSD shell.h 57;" d
BUFLEN mknodes.c 71;" d file:
BUNOP bltin/test.c /^ BUNOP,$/;" e enum:token_types file:
CEOF jobs.c 70;" d file:
CEOF output.c 69;" d file:
CHECKEND parser.c 839;" d file:
CHECKSTRSPACE memalloc.h 73;" d
CLEAR_PENDING_INT error.h 90;" d
CMD2_CLR setmode.c 80;" d file:
CMD2_GBITS setmode.c 82;" d file:
CMD2_OBITS setmode.c 83;" d file:
CMD2_SET setmode.c 81;" d file:
CMD2_UBITS setmode.c 84;" d file:
CMDBUILTIN exec.h 44;" d
CMDFUNCTION exec.h 45;" d
CMDNORMAL exec.h 43;" d
CMDTABLESIZE exec.c 87;" d file:
CMDUNKNOWN exec.h 42;" d
CTLARI parser.h 48;" d
CTLBACKQ parser.h 45;" d
CTLENDARI parser.h 49;" d
CTLENDVAR parser.h 44;" d
CTLESC parser.h 42;" d
CTLQUOTE parser.h 46;" d
CTLQUOTEMARK parser.h 50;" d
CTLVAR parser.h 43;" d
Cflag options.h 62;" d
DEFEDITOR histedit.c 70;" d file:
DEFINE_OPTIONS options.c 53;" d file:
DEFINE_OPTIONS options.c 55;" d file:
DEL hetio.c 49;" d file:
DO_ABS exec.h 58;" d
DO_BRUTE exec.h 60;" d
DO_ERR exec.h 57;" d
DO_NOFUN exec.h 59;" d
EMPTY redir.c 73;" d file:
EOFMARKLEN parser.c 73;" d file:
EOF_NLEFT input.c 77;" d file:
EOI bltin/test.c /^ EOI,$/;" e enum:token file:
ESC hetio.c 48;" d file:
EV_BACKCMD eval.c 84;" d file:
EV_EXIT eval.c 82;" d file:
EV_TESTED eval.c 83;" d file:
EXERROR error.h 71;" d
EXEXEC error.h 73;" d
EXINT error.h 70;" d
EXP_CASE expand.h 59;" d
EXP_FULL expand.h 55;" d
EXP_RECORD expand.h 60;" d
EXP_REDIR expand.h 58;" d
EXP_TILDE expand.h 56;" d
EXP_VARTILDE expand.h 57;" d
EXSHELLPROC error.h 72;" d
E_CREAT error.h 46;" d
E_EXEC error.h 47;" d
E_OPEN error.h 45;" d
Eflag options.h 61;" d
FILBDEV bltin/test.c /^ FILBDEV,$/;" e enum:token file:
FILCDEV bltin/test.c /^ FILCDEV,$/;" e enum:token file:
FILDIR bltin/test.c /^ FILDIR,$/;" e enum:token file:
FILEQ bltin/test.c /^ FILEQ,$/;" e enum:token file:
FILEX bltin/test.c /^ FILEX,$/;" e enum:token file:
FILEXIST bltin/test.c /^ FILEXIST,$/;" e enum:token file:
FILFIFO bltin/test.c /^ FILFIFO,$/;" e enum:token file:
FILGID bltin/test.c /^ FILGID,$/;" e enum:token file:
FILGZ bltin/test.c /^ FILGZ,$/;" e enum:token file:
FILNT bltin/test.c /^ FILNT,$/;" e enum:token file:
FILOT bltin/test.c /^ FILOT,$/;" e enum:token file:
FILRD bltin/test.c /^ FILRD,$/;" e enum:token file:
FILREG bltin/test.c /^ FILREG,$/;" e enum:token file:
FILSGID bltin/test.c /^ FILSGID,$/;" e enum:token file:
FILSOCK bltin/test.c /^ FILSOCK,$/;" e enum:token file:
FILSTCK bltin/test.c /^ FILSTCK,$/;" e enum:token file:
FILSUID bltin/test.c /^ FILSUID,$/;" e enum:token file:
FILSYM bltin/test.c /^ FILSYM,$/;" e enum:token file:
FILTT bltin/test.c /^ FILTT,$/;" e enum:token file:
FILUID bltin/test.c /^ FILUID,$/;" e enum:token file:
FILWR bltin/test.c /^ FILWR,$/;" e enum:token file:
FORCEINTON error.h 89;" d
FORK_BG jobs.h 43;" d
FORK_FG jobs.h 42;" d
FORK_NOJOB jobs.h 44;" d
GENHEADERS Makefile /^GENHEADERS = \\$/;" m
GENSRCS Makefile /^GENSRCS = builtins.c \\$/;" m
HAVE_VASPRINTF output.c 359;" d file:
INITARGS bltin/bltin.h 67;" d
INITARGS bltin/bltin.h 73;" d
INIT_DEPS Makefile /^INIT_DEPS = alias.c eval.c exec.c input.c jobs.c options.c parser.c \\$/;" m
INTEQ bltin/test.c /^ INTEQ,$/;" e enum:token file:
INTGE bltin/test.c /^ INTGE,$/;" e enum:token file:
INTGT bltin/test.c /^ INTGT,$/;" e enum:token file:
INTLE bltin/test.c /^ INTLE,$/;" e enum:token file:
INTLT bltin/test.c /^ INTLT,$/;" e enum:token file:
INTNE bltin/test.c /^ INTNE,$/;" e enum:token file:
INTOFF error.h 87;" d
INTON error.h 88;" d
Iflag options.h 53;" d
JOBDONE jobs.h 63;" d
JOBS shell.h 55;" d
JOBSTOPPED jobs.h 62;" d
LIBC_PREFIX Makefile /^LIBC_PREFIX = ..\/..\/lib\/libc$/;" m
LIBS Makefile /^LIBS = $(LIBC_PREFIX)\/libc.a$/;" m
LPAREN bltin/test.c /^ LPAREN,$/;" e enum:token file:
MAXCMDTEXT jobs.c 1073;" d file:
MAXFIELDS mknodes.c 70;" d file:
MAXHISTLOOPS histedit.c 69;" d file:
MAXMBOXES mail.c 64;" d file:
MAXPWD cd.c 299;" d file:
MAXTYPES mknodes.c 69;" d file:
MAX_HISTORY hetio.c 46;" d file:
MEM_OUT output.c 82;" d file:
MINSIZE memalloc.c 118;" d file:
MKINIT shell.h 72;" d
NEOF parser.h 76;" d
NEWARGS exec.c 217;" d file:
NOPTS options.h 68;" d
NSIG mksignames.c 28;" d file:
NULL bltin/bltin.h 70;" d
NULL shell.h 63;" d
NULL shell.h 68;" d
OBJECTS Makefile /^OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))$/;" m
OPERAND bltin/test.c /^ OPERAND$/;" e enum:token file:
OUTBUFSIZ output.c 80;" d file:
OUTFILE mkinit.c 78;" d file:
OUTPUT Makefile /^OUTPUT = sh$/;" m
OUTPUT_ERR output.c 83;" d file:
OUTPUT_INCL output.h 109;" d
OUTTEMP mkinit.c 79;" d file:
PAREN bltin/test.c /^ PAREN$/;" e enum:token_types file:
PARSEARITH parser.c 844;" d file:
PARSEBACKQNEW parser.c 843;" d file:
PARSEBACKQOLD parser.c 842;" d file:
PARSEREDIR parser.c 840;" d file:
PARSESUB parser.c 841;" d file:
PIPESIZE redir.c 75;" d file:
PIPESIZE redir.c 77;" d file:
PROFILE main.c 86;" d file:
REDIR_BACKQ redir.h 43;" d
REDIR_PUSH redir.h 42;" d
RETURN parser.c 754;" d file:
RETURN parser.c 822;" d file:
RPAREN bltin/test.c /^ RPAREN,$/;" e enum:token file:
RTLEN mksignames.c 36;" d file:
RTLIM mksignames.c 37;" d file:
SET_LEN setmode.c 71;" d file:
SET_LEN_INCR setmode.c 72;" d file:
SHSRCS Makefile /^SHSRCS = alias.c \\$/;" m
SIGSSIZE main.c 217;" d file:
SKIPBREAK eval.h 72;" d
SKIPCONT eval.h 73;" d
SKIPFILE eval.h 75;" d
SKIPFUNC eval.h 74;" d
SOFTINT_PREFIX Makefile /^SOFTINT_PREFIX = ..\/..\/lib\/softint$/;" m
SOURCES Makefile /^SOURCES = ${SHSRCS} ${GENSRCS}$/;" m
STACKSTRNUL memalloc.h 75;" d
STADJUST memalloc.h 78;" d
STANDARD_BITS setmode.c 186;" d file:
STARTSTACKSTR memalloc.h 71;" d
STATIC shell.h 71;" d
STPUTC memalloc.h 72;" d
STREQ bltin/test.c /^ STREQ,$/;" e enum:token file:
STREZ bltin/test.c /^ STREZ,$/;" e enum:token file:
STRGT bltin/test.c /^ STRGT,$/;" e enum:token file:
STRLT bltin/test.c /^ STRLT,$/;" e enum:token file:
STRNE bltin/test.c /^ STRNE,$/;" e enum:token file:
STRNZ bltin/test.c /^ STRNZ,$/;" e enum:token file:
STTOPC memalloc.h 77;" d
STUNPUTC memalloc.h 76;" d
S_CATCH trap.c 78;" d file:
S_DFL trap.c 77;" d file:
S_HARD_IGN trap.c 80;" d file:
S_IGN trap.c 79;" d file:
S_ISTXT setmode.c 68;" d file:
S_RESET trap.c 81;" d file:
TEMPSIZE output.c 354;" d file:
TRACE shell.h 80;" d
TRACE shell.h 82;" d
T_INT mknodes.c 77;" d file:
T_NODE mknodes.c 74;" d file:
T_NODELIST mknodes.c 75;" d file:
T_OTHER mknodes.c 78;" d file:
T_STRING mknodes.c 76;" d file:
T_TEMP mknodes.c 79;" d file:
UNOP bltin/test.c /^ UNOP,$/;" e enum:token_types file:
UNOT bltin/test.c /^ UNOT,$/;" e enum:token file:
USTPUTC memalloc.h 74;" d
VEXPORT var.h 46;" d
VNOFUNC var.h 52;" d
VREADONLY var.h 47;" d
VSASSIGN parser.h 62;" d
VSLENGTH parser.h 67;" d
VSMINUS parser.h 59;" d
VSNORMAL parser.h 58;" d
VSNUL parser.h 54;" d
VSPLUS parser.h 60;" d
VSQUESTION parser.h 61;" d
VSQUOTE parser.h 55;" d
VSTACK var.h 50;" d
VSTRFIXED var.h 48;" d
VSTRIMLEFT parser.h 63;" d
VSTRIMLEFTMAX parser.h 64;" d
VSTRIMRIGHT parser.h 65;" d
VSTRIMRIGHTMAX parser.h 66;" d
VSTYPE parser.h 53;" d
VTABSIZE var.c 75;" d file:
VTEXTFIXED var.h 49;" d
VUNSET var.h 51;" d
Vflag options.h 60;" d
YYABORT arith.c 744;" d file:
YYACCEPT arith.c 743;" d file:
YYBACKUP arith.c 756;" d file:
YYBISON arith.c 47;" d file:
YYBISON_VERSION arith.c 50;" d file:
YYCOPY arith.c 477;" d file:
YYCOPY arith.c 480;" d file:
YYDEBUG arith.c 268;" d file:
YYDPRINTF arith.c 836;" d file:
YYDPRINTF arith.c 982;" d file:
YYEMPTY arith.c 740;" d file:
YYEOF arith.c 741;" d file:
YYERRCODE arith.c 775;" d file:
YYERROR arith.c 745;" d file:
YYERROR_VERBOSE arith.c 273;" d file:
YYERROR_VERBOSE arith.c 274;" d file:
YYERROR_VERBOSE arith.c 276;" d file:
YYFAIL arith.c 752;" d file:
YYFINAL arith.c 510;" d file:
YYFPRINTF arith.c 833;" d file:
YYFREE arith.c 443;" d file:
YYID arith.c /^YYID (i)$/;" f file:
YYID arith.c 367;" d file:
YYINITDEPTH arith.c 991;" d file:
YYLAST arith.c 512;" d file:
YYLEX arith.c 823;" d file:
YYLEX arith.c 825;" d file:
YYLLOC_DEFAULT arith.c 784;" d file:
YYLSP_NEEDED arith.c 59;" d file:
YYMALLOC arith.c 436;" d file:
YYMAXDEPTH arith.c 1002;" d file:
YYMAXUTOK arith.c 525;" d file:
YYNNTS arith.c 517;" d file:
YYNRULES arith.c 519;" d file:
YYNSTATES arith.c 521;" d file:
YYNTOKENS arith.c 515;" d file:
YYPACT_NINF arith.c 660;" d file:
YYPOPSTACK arith.c 1340;" d file:
YYPURE arith.c 56;" d file:
YYRECOVERING arith.c 754;" d file:
YYRHSLOC arith.c 782;" d file:
YYSIZE_MAXIMUM arith.c 344;" d file:
YYSIZE_T arith.c 332;" d file:
YYSIZE_T arith.c 334;" d file:
YYSIZE_T arith.c 338;" d file:
YYSIZE_T arith.c 340;" d file:
YYSKELETON_NAME arith.c 53;" d file:
YYSTACK_ALLOC arith.c 390;" d file:
YYSTACK_ALLOC arith.c 394;" d file:
YYSTACK_ALLOC arith.c 399;" d file:
YYSTACK_ALLOC arith.c 422;" d file:
YYSTACK_ALLOC_MAXIMUM arith.c 419;" d file:
YYSTACK_ALLOC_MAXIMUM arith.c 425;" d file:
YYSTACK_BYTES arith.c 469;" d file:
YYSTACK_FREE arith.c 413;" d file:
YYSTACK_FREE arith.c 423;" d file:
YYSTACK_GAP_MAXIMUM arith.c 465;" d file:
YYSTACK_RELOCATE arith.c 1428;" d file:
YYSTACK_RELOCATE arith.c 496;" d file:
YYSTYPE arith.c /^typedef int YYSTYPE;$/;" t file:
YYSTYPE arith.h /^typedef int YYSTYPE;$/;" t
YYSTYPE_IS_DECLARED arith.c 287;" d file:
YYSTYPE_IS_DECLARED arith.h 102;" d
YYSTYPE_IS_TRIVIAL arith.c 288;" d file:
YYSTYPE_IS_TRIVIAL arith.h 103;" d
YYTABLE_NINF arith.c 681;" d file:
YYTERROR arith.c 774;" d file:
YYTOKENTYPE arith.c 65;" d file:
YYTOKENTYPE arith.h 38;" d
YYTOKEN_TABLE arith.c 281;" d file:
YYTRANSLATE arith.c 527;" d file:
YYUNDEFTOK arith.c 524;" d file:
YYUSE arith.c 360;" d file:
YYUSE arith.c 362;" d file:
YY_ arith.c 350;" d file:
YY_ arith.c 354;" d file:
YY_LOCATION_PRINT arith.c 810;" d file:
YY_LOCATION_PRINT arith.c 815;" d file:
YY_REDUCE_PRINT arith.c 972;" d file:
YY_REDUCE_PRINT arith.c 985;" d file:
YY_STACK_PRINT arith.c 934;" d file:
YY_STACK_PRINT arith.c 984;" d file:
YY_SYMBOL_PRINT arith.c 842;" d file:
YY_SYMBOL_PRINT arith.c 983;" d file:
_STDLIB_H arith.c 404;" d file:
_STDLIB_H arith.c 432;" d file:
_rmescapes expand.c /^_rmescapes(str, flag)$/;" f
action error.c /^ short action; \/* operation which encountered the error *\/$/;" m struct:errname file:
add mksyntax.c /^add(p, type)$/;" f file:
addchar mkinit.c /^addchar(c, text)$/;" f
addcmd setmode.c /^addcmd(set, op, who, oparg, mask)$/;" f file:
addcmdentry exec.c /^addcmdentry(name, entry)$/;" f
addfname expand.c /^addfname(name)$/;" f
addglob expand.c /^addglob(pglob)$/;" f
addstr mkinit.c /^addstr(s, text)$/;" f
aexpr bltin/test.c /^aexpr(n)$/;" f file:
aflag options.h 63;" d
alias alias.h /^struct alias {$/;" s
aliascmd alias.c /^aliascmd(argc, argv)$/;" f
align machdep.h /^union align {$/;" u
alloca arith.c 397;" d file:
amiddecls mkinit.c /^int amiddecls; \/* for formatting *\/$/;" v
andor parser.c /^andor() {$/;" f
ap input.c /^ struct alias *ap; \/* if push was associated with an alias *\/$/;" m struct:strpush file:
arg0 options.c /^char *arg0; \/* value of $0 *\/$/;" v
argbackq expand.c /^struct nodelist *argbackq; \/* list of back quote expressions *\/$/;" v
arglist expand.h /^struct arglist {$/;" s
argptr options.c /^char **argptr; \/* argument list for builtin commands *\/$/;" v
argstr expand.c /^argstr(p, flag)$/;" f
arith arith.c /^arith(s)$/;" f
arith_buf arith.c /^const char *arith_buf, *arith_startbuf;$/;" v
arith_startbuf arith.c /^const char *arith_buf, *arith_startbuf;$/;" v
atab alias.c /^struct alias *atab[ATABSIZE];$/;" v
attyset var.h 110;" d
backcmd eval.h /^struct backcmd { \/* result of evalbackcmd *\/$/;" s
backgndpid jobs.c /^MKINIT short backgndpid = -1; \/* pid of last background process *\/$/;" v
backquotelist parser.c /^struct nodelist *backquotelist;$/;" v
base mksyntax.c /^static int base;$/;" v file:
basebuf input.c /^char basebuf[BUFSIZ]; \/* buffer for top level input file *\/$/;" v
basepf input.c /^MKINIT struct parsefile basepf; \/* top level input file *\/$/;" v
basestrpush input.c /^ struct strpush basestrpush; \/* so pushing one is fast *\/$/;" m struct:parsefile file:
bash_group_member bltin/test.c /^bash_group_member (gid)$/;" f file:
begoff expand.c /^ int begoff; \/* offset of start of region *\/$/;" m struct:ifsregion file:
bflag options.h 64;" d
bgcmd jobs.c /^bgcmd(argc, argv)$/;" f
binop bltin/test.c /^binop()$/;" f file:
bitcmd setmode.c /^typedef struct bitcmd {$/;" s file:
bits setmode.c /^ mode_t bits;$/;" m struct:bitcmd file:
block mkinit.c /^struct block {$/;" s file:
bltincmd eval.c /^bltincmd(argc, argv)$/;" f
bltinlookup var.c /^bltinlookup(name, doall)$/;" f
breakcmd eval.c /^breakcmd(argc, argv)$/;" f
buf eval.h /^ char *buf; \/* buffer *\/$/;" m struct:backcmd
buf input.c /^ char *buf; \/* input buffer *\/$/;" m struct:parsefile file:
buf output.h /^ char *buf;$/;" m struct:output
bufsize output.h /^ int bufsize;$/;" m struct:output
builtinloc exec.c /^STATIC int builtinloc = -1; \/* index in path of %builtin, or -1 *\/$/;" v
casematch expand.c /^casematch(pattern, val)$/;" f
cdcmd cd.c /^cdcmd(argc, argv)$/;" f
cdcomppath cd.c /^STATIC char *cdcomppath;$/;" v
cfile mksyntax.c /^static FILE *cfile;$/;" v file:
changed jobs.h /^ char changed; \/* true if status has changed *\/$/;" m struct:job
changepath exec.c /^changepath(newval)$/;" f
checkkwd parser.c /^MKINIT int checkkwd; \/* 1 == check for kwds, 2 == also eat newlines *\/$/;" v
chkmail mail.c /^chkmail(silent)$/;" f
ckfopen mkinit.c /^ckfopen(file, mode)$/;" f
ckfree memalloc.h 81;" d
ckmalloc memalloc.c /^ckmalloc(nbytes)$/;" f
ckmalloc mkinit.c /^ckmalloc(nbytes)$/;" f
ckrealloc memalloc.c /^ckrealloc(p, nbytes)$/;" f
clear_traps trap.c /^clear_traps() {$/;" f
clearcmdentry exec.c /^clearcmdentry(firstchange)$/;" f
clearredir redir.c /^clearredir() {$/;" f
closememout output.c /^closememout() {$/;" f
closescript input.c /^closescript() {$/;" f
cmd jobs.h /^ char *cmd; \/* text of command being run *\/$/;" m struct:procstat
cmd miscbltin.c /^ int cmd;$/;" m struct:limits file:
cmd setmode.c /^ char cmd;$/;" m struct:bitcmd file:
cmd2 setmode.c /^ char cmd2;$/;" m struct:bitcmd file:
cmdentry exec.h /^struct cmdentry {$/;" s
cmdenviron eval.c /^struct strlist *cmdenviron;$/;" v
cmdlookup exec.c /^cmdlookup(name, add)$/;" f
cmdloop main.c /^cmdloop(top)$/;" f
cmdname exec.c /^ char cmdname[ARB]; \/* name of command *\/$/;" m struct:tblentry file:
cmdnextc jobs.c /^STATIC char *cmdnextc;$/;" v
cmdnleft jobs.c /^STATIC int cmdnleft;$/;" v
cmdputs jobs.c /^cmdputs(s)$/;" f
cmdtable exec.c /^STATIC struct tblentry *cmdtable[CMDTABLESIZE];$/;" v
cmdtxt jobs.c /^cmdtxt(n)$/;" f
cmdtype exec.c /^ short cmdtype; \/* index identifying command *\/$/;" m struct:tblentry file:
cmdtype exec.h /^ int cmdtype;$/;" m struct:cmdentry
code mkinit.c /^ struct text code; \/* code for handling event *\/$/;" m struct:event file:
command parser.c /^command() {$/;" f
commandcmd exec.c /^commandcmd(argc, argv)$/;" f
commandname error.c /^char *commandname;$/;" v
commandname eval.c /^char *commandname;$/;" v
commandtext jobs.c /^commandtext(n)$/;" f
comment mkinit.c /^ char *comment; \/* comment describing routine *\/$/;" m struct:event file:
comment mksyntax.c /^ char *comment;$/;" m struct:synclass file:
compress_mode setmode.c /^compress_mode(set)$/;" f file:
copyfd redir.c /^copyfd(from, to)$/;" f
copyright mkinit.c /^static const char copyright[] =$/;" v file:
copyright mknodes.c /^static const char copyright[] =$/;" v file:
copyright mksyntax.c /^static const char copyright[] =$/;" v file:
cp machdep.h /^ char *cp;$/;" m union:align
curcmd main.c /^STATIC union node *curcmd;$/;" v
curdir cd.c /^char *curdir = NULL; \/* current working directory *\/$/;" v
curfile mkinit.c /^char *curfile; \/* current file *\/$/;" v
curjob jobs.c /^short curjob; \/* current job *\/$/;" v
curstr mknodes.c /^static struct str *curstr; \/* current structure *\/$/;" v file:
cvtnum expand.c /^cvtnum(num, buf)$/;" f
debug show.c /^int debug = 0;$/;" v
debug show.c /^int debug = 1;$/;" v
decl mknodes.c /^ char *decl; \/* declaration of field *\/$/;" m struct:field file:
decls mkinit.c /^struct text decls; \/* declarations *\/$/;" v
decode_signal trap.c /^int decode_signal(const char *string)$/;" f
defines mkinit.c /^struct text defines; \/* #define statements *\/$/;" v
defun exec.c /^defun(name, func)$/;" f
delete_cmd_entry exec.c /^delete_cmd_entry() {$/;" f
deletefuncs exec.c /^deletefuncs() {$/;" f
describe_command exec.c /^describe_command(command, verbose)$/;" f
digit output.c /^static const char digit[] = "0123456789ABCDEF";$/;" v file:
digit_contig mksyntax.c /^static int digit_contig;\/* true if digits are contiguous *\/$/;" v file:
digit_convert mksyntax.c /^digit_convert()$/;" f file:
displayhist histedit.c /^int displayhist;$/;" v
docd cd.c /^docd(dest, print)$/;" f
dodecl mkinit.c /^dodecl(line1, fp)$/;" f
doevent mkinit.c /^doevent(ep, fp, fname)$/;" f
doformat output.c /^doformat(dest, f, ap)$/;" f
doformat output.h 100;" d
doinclude mkinit.c /^doinclude(line)$/;" f
done mknodes.c /^ int done; \/* set if fully parsed *\/$/;" m struct:str file:
doprompt parser.c /^int doprompt; \/* if set, prompt the user *\/$/;" v
dotcmd main.c /^dotcmd(argc, argv)$/;" f
dotrap trap.c /^dotrap() {$/;" f
dowait jobs.c /^dowait(block, job)$/;" f
dprintf output.c /^dprintf(const char *fmt, ...)$/;" f
dumpmode setmode.c /^dumpmode(set)$/;" f file:
dupredirect redir.c /^dupredirect(redir, f, memory)$/;" f
editing histedit.c 87;" d file:
eflag options.h 51;" d
el histedit.c /^EditLine *el; \/* editline cookie *\/$/;" v
el input.c /^EditLine *el; \/* cookie for editline package *\/$/;" v
el_in histedit.c /^static FILE *el_in, *el_out;$/;" v file:
el_out histedit.c /^static FILE *el_in, *el_out;$/;" v file:
emptyoutbuf output.c /^emptyoutbuf(dest)$/;" f
endoff expand.c /^ int endoff; \/* offset of end of region *\/$/;" m struct:ifsregion file:
environment var.c /^environment() {$/;" f
eofmark parser.c /^ char *eofmark; \/* string indicating end of input *\/$/;" m struct:heredoc file:
equal mkinit.c 172;" d file:
equal mystring.h 48;" d
equalf bltin/test.c /^equalf (f1, f2)$/;" f file:
errcode error.c /^ short errcode; \/* error number *\/$/;" m struct:errname file:
errmsg error.c /^errmsg(e, action)$/;" f
errname error.c /^struct errname {$/;" s file:
error arith.c /^error(s)$/;" f
error bltin/test.c /^error(const char *msg, ...)$/;" f file:
error error.c /^error(const char *msg, ...)$/;" f
error mkinit.c /^error(msg)$/;" f
error mknodes.c /^error(const char *msg, ...)$/;" f file:
errormsg error.c /^STATIC const struct errname errormsg[] = {$/;" v
errout output.c /^struct output errout = {NULL, 0, NULL, 100, 2, 0};$/;" v
errout output.c /^struct output errout = {NULL, NULL, 0, NULL, 0, 2, 0};$/;" v
evalbackcmd eval.c /^evalbackcmd(n, result)$/;" f
evalcase eval.c /^evalcase(n, flags)$/;" f
evalcmd eval.c /^evalcmd(argc, argv)$/;" f
evalcommand eval.c /^evalcommand(cmd, flags, backcmd)$/;" f
evalfor eval.c /^evalfor(n, flags)$/;" f
evalloop eval.c /^evalloop(n, flags)$/;" f
evalpipe eval.c /^evalpipe(n)$/;" f
evalskip eval.c /^MKINIT int evalskip; \/* set if we are skipping commands *\/$/;" v
evalstring eval.c /^evalstring(s, flag)$/;" f
evalsubshell eval.c /^evalsubshell(n, flags)$/;" f
evaltree eval.c /^evaltree(n, flags)$/;" f
evalvar expand.c /^evalvar(p, flag)$/;" f
event mkinit.c /^struct event event[] = {$/;" v
event mkinit.c /^struct event {$/;" s file:
exception error.c /^int exception;$/;" v
execcmd eval.c /^execcmd(argc, argv)$/;" f
execinterp exec.c /^execinterp(argv, envp)$/;" f
exerrno exec.c /^int exerrno = 0; \/* Last exec error *\/$/;" v
exerror error.c /^exerror(int cond, const char *msg, ...)$/;" f
exitcmd main.c /^exitcmd(argc, argv)$/;" f
exitshell trap.c /^exitshell(status)$/;" f
exitstatus eval.c /^int exitstatus; \/* exit status of last command *\/$/;" v
exp arith.y /^exp: expr {$/;" l
expandarg expand.c /^expandarg(arg, arglist, flag)$/;" f
expandhere expand.c /^expandhere(arg, fd)$/;" f
expandmeta expand.c /^expandmeta(str, flag)$/;" f
exparg expand.c /^struct arglist exparg; \/* holds expanded arg list *\/$/;" v
expari expand.c /^expari(flag)$/;" f
expbackq expand.c /^expbackq(cmd, quoted, flag)$/;" f
expcmd arith.c /^expcmd(argc, argv)$/;" f
expdest expand.c /^char *expdest; \/* output of current string *\/$/;" v
expdir expand.c /^char *expdir;$/;" v
expmeta expand.c /^expmeta(enddir, name)$/;" f
exportcmd var.c /^exportcmd(argc, argv)$/;" f
expr arith.y /^expr: ARITH_LPAREN expr ARITH_RPAREN { $$ = $2; }$/;" l
expredir eval.c /^expredir(n)$/;" f
expsort expand.c /^expsort(str)$/;" f
exptilde expand.c /^exptilde(p, flag)$/;" f
exraise error.c /^exraise(e)$/;" f
exverror error.c /^exverror(cond, msg, ap)$/;" f file:
factor miscbltin.c /^ int factor; \/* multiply by to get rlim_{cur,max} values *\/$/;" m struct:limits file:
falsecmd eval.c /^falsecmd(argc, argv)$/;" f
fc_replace histedit.c /^fc_replace(s, p, r)$/;" f
fd eval.h /^ int fd; \/* file descriptor to read from *\/$/;" m struct:backcmd
fd input.c /^ int fd; \/* file descriptor (or -1 if string) *\/$/;" m struct:parsefile file:
fd output.h /^ int fd;$/;" m struct:output
fd0_redirected redir.c /^int fd0_redirected = 0;$/;" v
fd0_redirected_p redir.c /^fd0_redirected_p () {$/;" f
fd2 redir.c /^int fd2 = 2;$/;" v
fflag options.h 52;" d
fflush bltin/bltin.h 60;" d
fgcmd jobs.c /^fgcmd(argc, argv)$/;" f
field mknodes.c /^ struct field field[MAXFIELDS]; \/* the fields of the structure *\/$/;" m struct:str file:
field mknodes.c /^struct field { \/* a structure field *\/$/;" s file:
filltable mksyntax.c /^filltable(dftval)$/;" f file:
filstat bltin/test.c /^filstat(nm, mode)$/;" f file:
find_builtin exec.c /^find_builtin(name)$/;" f
find_command exec.c /^find_command(name, entry, act, path)$/;" f
find_dot_file main.c /^find_dot_file(basename)$/;" f
fixredir parser.c /^void fixredir(union node *n, const char *text, int err)$/;" f
flag alias.h /^ int flag;$/;" m struct:alias
flags output.h /^ short flags;$/;" m struct:output
flags var.c /^ int flags;$/;" m struct:varinit file:
flags var.h /^ int flags; \/* flags are defined above *\/$/;" m struct:var
flags var.h /^ int flags; \/* saved flags *\/$/;" m struct:localvar
flushall output.c /^flushall() {$/;" f
flushout output.c /^flushout(dest)$/;" f
flushout output.h 99;" d
fmtstr output.c /^fmtstr(char *outbuf, size_t length, const char *fmt, ...)$/;" f
forkshell jobs.c /^forkshell(jp, n, mode)$/;" f
fprintf bltin/bltin.h 58;" d
fputs bltin/bltin.h 59;" d
freejob jobs.c /^freejob(jp)$/;" f
freeparam options.c /^freeparam(param)$/;" f
freestdout output.c /^freestdout() {$/;" f
func exec.h /^ union node *func;$/;" m union:cmdentry::param
func var.c /^ void (*func) __P((const char *));$/;" m struct:varinit file:
func var.h /^ void (*func) __P((const char *));$/;" m struct:var
funcnest eval.c /^int funcnest; \/* depth of function calls *\/$/;" v
get_standard_path eval.c /^get_standard_path()$/;" f
getcmdentry exec.c /^getcmdentry(name, entry)$/;" f
getcomponent cd.c /^getcomponent() {$/;" f
getjob jobs.c /^getjob(name)$/;" f
getmode setmode.c /^getmode(bbox, omode)$/;" f
getn bltin/test.c /^getn(s)$/;" f file:
getopts options.c /^getopts(optstr, optvar, optfirst, optind, optoff)$/;" f
getoptscmd options.c /^getoptscmd(argc, argv)$/;" f
getoptsreset options.c /^getoptsreset(value)$/;" f
getprompt parser.c /^getprompt(void *unused)$/;" f
getpwd cd.c /^getpwd()$/;" f
gooddefine mkinit.c /^gooddefine(line)$/;" f
goodname parser.c /^goodname(char *name)$/;" f
gotsig trap.c /^char gotsig[NSIG]; \/* indicates specified signal received *\/$/;" v
gotsigchild jobs.c /^STATIC int gotsigchild;$/;" v
grabstackblock memalloc.c /^grabstackblock(len)$/;" f
grabstackstr memalloc.h 79;" d
group_array bltin/test.c /^static gid_t *group_array = NULL;$/;" v file:
growstackblock memalloc.c /^growstackblock() {$/;" f
growstackstr memalloc.c /^growstackstr() {$/;" f
handler error.c /^struct jmploc *handler;$/;" v
hashalias alias.c /^hashalias(p)$/;" f
hashcd exec.c /^hashcd() {$/;" f
hashcmd exec.c /^hashcmd(argc, argv)$/;" f
hashvar var.c /^hashvar(p)$/;" f
header_files mkinit.c /^char *header_files[200]; \/* list of header files *\/$/;" v
here parser.c /^ union node *here; \/* redirection node *\/$/;" m struct:heredoc file:
heredoc parser.c /^struct heredoc *heredoc;$/;" v
heredoc parser.c /^struct heredoc {$/;" s file:
heredoclist parser.c /^struct heredoc *heredoclist; \/* list of here documents to read *\/$/;" v
herefd memalloc.c /^int herefd = -1;$/;" v
hetio_init hetio.c /^void hetio_init(void)$/;" f
hetio_inter hetio.c /^int hetio_inter = 0;$/;" v
hetio_read_input hetio.c /^int hetio_read_input(int fd)$/;" f
hetio_reset_term hetio.c /^void hetio_reset_term(void)$/;" f
hfile mksyntax.c /^static FILE *hfile;$/;" v file:
his_end hetio.c /^static struct history *his_end = NULL; \/* Last element in command line list *\/$/;" v file:
his_front hetio.c /^static struct history *his_front = NULL; \/* First element in command line list *\/$/;" v file:
hist histedit.c /^History *hist; \/* history cookie *\/$/;" v
histcmd histedit.c /^histcmd(argc, argv)$/;" f
histedit histedit.c /^histedit()$/;" f
history hetio.c /^struct history$/;" s file:
history_counter hetio.c /^static int history_counter = 0; \/* Number of commands in history list *\/$/;" v file:
histsizeval var.h 105;" d
i machdep.h /^ int i;$/;" m union:align
iflag options.h 54;" d
ifsbreakup expand.c /^ifsbreakup(string, arglist)$/;" f
ifsfirst expand.c /^struct ifsregion ifsfirst; \/* first struct in list of ifs regions *\/$/;" v
ifsfree expand.c /^ifsfree()$/;" f
ifslastp expand.c /^struct ifsregion *ifslastp; \/* last struct in list *\/$/;" v
ifsregion expand.c /^struct ifsregion {$/;" s file:
ifsset var.h 97;" d
ifsval var.h 96;" d
ignoresig trap.c /^ignoresig(signo)$/;" f
in_function eval.h 67;" d
indent mknodes.c /^indent(amount, fp)$/;" f file:
indent show.c /^indent(amount, pfx, fp)$/;" f file:
index exec.h /^ int index;$/;" m union:cmdentry::param
infp mknodes.c /^static FILE *infp;$/;" v file:
init mkinit.c /^char init[] = "\\$/;" v
init mksyntax.c /^init()$/;" f file:
init_editline input.c /^int init_editline = 0; \/* editline library initialized? *\/$/;" v
initialize_group_array bltin/test.c /^initialize_group_array ()$/;" f file:
initialize_signames mksignames.c /^initialize_signames ()$/;" f
initialpgrp jobs.c /^int initialpgrp; \/* pgrp of shell on invocation *\/$/;" v
initstreams output.c /^void initstreams() {$/;" f
initvar var.c /^initvar() {$/;" f
input_backspace hetio.c /^input_backspace(int *cursor, int *len)$/;" f
input_delete hetio.c /^void input_delete(int cursor)$/;" f
input_end hetio.c /^void input_end(int *cursor, int len)$/;" f
input_home hetio.c /^void input_home(int *cursor) \/* Command line input routines *\/$/;" f
int_pending error.h 91;" d
intpending error.c /^volatile int intpending;$/;" v
intreceived jobs.c /^STATIC int intreceived;$/;" v
is_assignment_builtin eval.c /^is_assignment_builtin (command)$/;" f
is_entry mksyntax.c /^struct synclass is_entry[] = {$/;" v
is_number mystring.c /^is_number(p)$/;" f
is_regular_builtin exec.c /^is_regular_builtin(name)$/;" f
is_special_builtin eval.c /^is_special_builtin(name)$/;" f
isoperand bltin/test.c /^isoperand()$/;" f file:
jmploc error.h /^struct jmploc {$/;" s
job jobs.h /^struct job {$/;" s
job_warning jobs.c /^int job_warning = 0;$/;" v
jobctl jobs.c /^MKINIT int jobctl;$/;" v
jobctl jobs.h /^ char jobctl; \/* job running under job control *\/$/;" m struct:job
jobidcmd jobs.c /^jobidcmd(argc, argv)$/;" f
jobscmd jobs.c /^jobscmd(argc, argv)$/;" f
jobtab jobs.c /^struct job *jobtab; \/* array of jobs *\/$/;" v
jp eval.h /^ struct job *jp; \/* job structure for command *\/$/;" m struct:backcmd
killcmd jobs.c /^killcmd(argc, argv)$/;" f
last mkinit.c /^ struct block *last;$/;" m struct:text file:
lastcmdentry exec.c /^struct tblentry **lastcmdentry;$/;" v
lastp expand.h /^ struct strlist **lastp;$/;" m struct:arglist
lasttoken parser.c /^int lasttoken; \/* last token read *\/$/;" v
letter options.h /^ const char letter;$/;" m struct:optent
limits miscbltin.c /^static const struct limits limits[] = {$/;" v file:
limits miscbltin.c /^struct limits {$/;" s file:
line mknodes.c /^static char line[1024];$/;" v file:
linep mknodes.c /^static char *linep;$/;" v file:
linno input.c /^ int linno; \/* current line *\/$/;" m struct:parsefile file:
linno mkinit.c /^int linno; \/* current line *\/$/;" v
linno mknodes.c /^static int linno;$/;" v file:
list expand.h /^ struct strlist *list;$/;" m struct:arglist
list parser.c /^list(nlflag)$/;" f
listsetvar var.c /^listsetvar(list)$/;" f
lleft input.c /^ int lleft; \/* number of chars left in this buffer *\/$/;" m struct:parsefile file:
loc error.h /^ jmp_buf loc;$/;" m struct:jmploc
localcmd var.c /^localcmd(argc, argv)$/;" f
localvar var.h /^struct localvar {$/;" s
localvars var.h /^struct localvar *localvars;$/;" v
longjmp error.h 107;" d
lookupalias alias.c /^lookupalias(name, check)$/;" f
lookupvar var.c /^lookupvar(name)$/;" f
loopnest eval.c /^MKINIT int loopnest; \/* current loop nesting level *\/$/;" v
macro mksyntax.c /^static char *macro[] = {$/;" v file:
mailtime mail.c /^STATIC time_t mailtime[MAXMBOXES]; \/* times of mailboxes *\/$/;" v
mailval var.h 98;" d
main arith.c /^main(argc, argv)$/;" f
main bltin/bltin.h 72;" d
main bltin/echo.c /^main(argc, argv) char **argv; {$/;" f
main bltin/echo.c 45;" d file:
main bltin/times.c /^int main() {$/;" f
main bltin/times.c 12;" d file:
main main.c /^main(argc, argv)$/;" f
main mkinit.c /^main(argc, argv)$/;" f
main mknodes.c /^main(argc, argv)$/;" f
main mksignames.c /^main (argc, argv)$/;" f
main mksyntax.c /^main(argc, argv)$/;" f
makejob jobs.c /^makejob(node, nprocs)$/;" f
makename parser.c /^makename() {$/;" f
makestrspace memalloc.c /^makestrspace() {$/;" f
malloc options.h /^ unsigned char malloc; \/* if parameter list dynamically allocated *\/$/;" m struct:shparam
marknext memalloc.h /^ struct stackmark *marknext;$/;" m struct:stackmark
markp memalloc.c /^struct stackmark *markp;$/;" v
match mkinit.c /^match(name, line)$/;" f
memout output.c /^struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};$/;" v
memout output.c /^struct output memout = {NULL, NULL, 0, NULL, 0, MEM_OUT, 0};$/;" v
mflag options.h 55;" d
minus_o options.c /^minus_o(name, val)$/;" f
minusc options.c /^char *minusc; \/* argument to -c option *\/$/;" v
mklocal var.c /^mklocal(name)$/;" f
mpathset var.h 112;" d
mpathval var.h 99;" d
msg error.c /^ const char *msg; \/* text describing the error *\/$/;" m struct:errname file:
msort expand.c /^msort(list, len)$/;" f
n hetio.c /^ struct history *n;$/;" m struct:history file:
name alias.h /^ char *name;$/;" m struct:alias
name miscbltin.c /^ const char *name;$/;" m struct:limits file:
name mkinit.c /^ char *name; \/* name of event (e.g. INIT) *\/$/;" m struct:event file:
name mknodes.c /^ char *name; \/* name of field *\/$/;" m struct:field file:
name mksyntax.c /^ char *name;$/;" m struct:synclass file:
name options.h /^ const char *name;$/;" m struct:optent
nbits mksyntax.c /^static int nbits; \/* number of bits in a character *\/$/;" v file:
needprompt parser.c /^int needprompt; \/* true if interactive and at start of line *\/$/;" v
new_term hetio.c /^static struct termios old_term, new_term; \/* Current termio and the previous termio before starting ash *\/$/;" v file:
newerf bltin/test.c /^newerf (f1, f2)$/;" f file:
nexpr bltin/test.c /^nexpr(n)$/;" f file:
next alias.h /^ struct alias *next;$/;" m struct:alias
next exec.c /^ struct tblentry *next; \/* next entry in hash chain *\/$/;" m struct:tblentry file:
next expand.c /^ struct ifsregion *next; \/* next region in list *\/$/;" m struct:ifsregion file:
next expand.h /^ struct strlist *next;$/;" m struct:strlist
next mkinit.c /^ struct block *next;$/;" m struct:block file:
next parser.c /^ struct heredoc *next; \/* next here document in list *\/$/;" m struct:heredoc file:
next redir.c /^ struct redirtab *next;$/;" m struct:redirtab file:
next var.h /^ struct localvar *next; \/* next local variable in list *\/$/;" m struct:localvar
next var.h /^ struct var *next; \/* next entry in hash list *\/$/;" m struct:var
nextc input.c /^ char *nextc; \/* next char in buffer *\/$/;" m struct:parsefile file:
nextc mkinit.c /^ char *nextc;$/;" m struct:text file:
nextc output.h /^ char *nextc;$/;" m struct:output
nextfield mknodes.c /^nextfield(buf)$/;" f file:
nextopt options.c /^nextopt(optstring)$/;" f
nfields mknodes.c /^ int nfields; \/* number of fields in the structure *\/$/;" m struct:str file:
nflag options.h 56;" d
ngroups bltin/test.c /^static int ngroups;$/;" v file:
njobs jobs.c /^int njobs; \/* size of array *\/$/;" v
nleft eval.h /^ int nleft; \/* number of chars in buffer *\/$/;" m struct:backcmd
nleft input.c /^ int nleft; \/* number of chars left in this line *\/$/;" m struct:parsefile file:
nleft mkinit.c /^ int nleft;$/;" m struct:text file:
nleft output.h /^ int nleft;$/;" m struct:output
nmboxes mail.c /^STATIC int nmboxes; \/* number of mailboxes *\/$/;" v
noclobberopen redir.c /^noclobberopen(fname)$/;" f
nodename mknodes.c /^static char *nodename[MAXTYPES]; \/* names of the nodes *\/$/;" v file:
nodestr mknodes.c /^static struct str *nodestr[MAXTYPES]; \/* type of structure used by the node *\/$/;" v file:
noexpand parser.c /^noexpand(text)$/;" f
not_fcnumber histedit.c /^not_fcnumber(s)$/;" f
nparam options.h /^ int nparam; \/* # of positional parameters (without $0) *\/$/;" m struct:shparam
nprocs jobs.h /^ short nprocs; \/* number of processes *\/$/;" m struct:job
nstr mknodes.c /^static int nstr; \/* number of structures *\/$/;" v file:
ntypes mknodes.c /^static int ntypes; \/* number of node types *\/$/;" v file:
nullstr mystring.c /^char nullstr[1]; \/* zero length string *\/$/;" v
nulonly expand.c /^ int nulonly; \/* search for nul bytes only *\/$/;" m struct:ifsregion file:
number mystring.c /^number(s)$/;" f
oexitstatus eval.c /^int oexitstatus; \/* saved exit status *\/$/;" v
oexpr bltin/test.c /^oexpr(n)$/;" f file:
old_term hetio.c /^static struct termios old_term, new_term; \/* Current termio and the previous termio before starting ash *\/$/;" v file:
olderf bltin/test.c /^olderf (f1, f2)$/;" f file:
onint error.c /^onint() {$/;" f
onsig trap.c /^onsig(signo)$/;" f
onsigchild jobs.c /^STATIC int onsigchild() {$/;" f
op_num bltin/test.c /^ short op_num, op_type;$/;" m struct:t_op file:
op_text bltin/test.c /^ const char *op_text;$/;" m struct:t_op file:
op_type bltin/test.c /^ short op_num, op_type;$/;" m struct:t_op file:
open_mem output.c /^open_mem(block, length, file)$/;" f
openhere redir.c /^openhere(redir)$/;" f
openmemout output.c /^openmemout() {$/;" f
openredirect redir.c /^openredirect(redir)$/;" f
opentrace show.c /^opentrace() {$/;" f
ops bltin/test.c /^} const ops [] = {$/;" v file:
optarg options.c /^char *optarg; \/* set by nextopt (like getopt) *\/$/;" v
optent options.h /^struct optent {$/;" s
optind options.h /^ int optind; \/* next parameter to be processed by getopts *\/$/;" m struct:shparam
optindval var.h 103;" d
option miscbltin.c /^ char option;$/;" m struct:limits file:
options options.c /^options(cmdline)$/;" f
optlist options.h /^struct optent optlist[NOPTS] = {$/;" v
optoff options.h /^ int optoff; \/* used by getopts *\/$/;" m struct:shparam
optptr options.c /^char *optptr; \/* used by nextopt *\/$/;" v
optschanged options.c /^optschanged()$/;" f
out1 output.c /^struct output *out1 = &output;$/;" v
out1c output.h 104;" d
out1fmt output.c /^out1fmt(const char *fmt, ...)$/;" f
out1str output.h 106;" d
out2 output.c /^struct output *out2 = &errout;$/;" v
out2c output.h 105;" d
out2str output.h 107;" d
out_junk output.c /^char out_junk[16];$/;" v
outc output.h 102;" d
outc output.h 98;" d
outfmt output.c /^outfmt(struct output *file, const char *fmt, ...)$/;" f
outfunc mknodes.c /^outfunc(cfile, calcsize)$/;" f file:
output mkinit.c /^output() {$/;" f
output mknodes.c /^output(file)$/;" f file:
output output.c /^struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};$/;" v
output output.c /^struct output output = {NULL, NULL, 0, NULL, 0, 1, 0};$/;" v
output output.h /^struct output {$/;" s
output_type_macros mksyntax.c /^output_type_macros()$/;" f file:
outsizes mknodes.c /^outsizes(cfile)$/;" f file:
outstr output.c /^outstr(p, file)$/;" f
p hetio.c /^ struct history *p;$/;" m struct:history file:
p options.h /^ char **p; \/* parameter list *\/$/;" m struct:shparam
padvance exec.c /^padvance(path, name)$/;" f
param exec.c /^ union param param; \/* definition of builtin function *\/$/;" m struct:tblentry file:
param exec.h /^ union param {$/;" u struct:cmdentry
parsebackquote parser.c /^int parsebackquote; \/* nonzero if we are inside backquotes *\/$/;" v
parsecmd parser.c /^parsecmd(int interact)$/;" f
parsefield mknodes.c /^parsefield()$/;" f file:
parsefile input.c /^struct parsefile *parsefile = &basepf; \/* current input file *\/$/;" v
parsefile input.c /^struct parsefile {$/;" s file:
parsefname parser.c /^parsefname() {$/;" f
parseheredoc parser.c /^parseheredoc() {$/;" f
parselleft input.c /^MKINIT int parselleft; \/* copy of parsefile->lleft *\/$/;" v
parsenextc input.c /^char *parsenextc; \/* copy of parsefile->nextc *\/$/;" v
parsenleft input.c /^MKINIT int parsenleft; \/* copy of parsefile->nleft *\/$/;" v
parsenode mknodes.c /^parsenode()$/;" f file:
path_change exec.c /^path_change(newval, bltin)$/;" f
pathopt exec.c /^const char *pathopt;$/;" v
pathval var.h 100;" d
patmatch expand.c /^patmatch(pattern, string, squoted)$/;" f
patmatch2 expand.c /^patmatch2(pattern, string, squoted)$/;" f
patmatch2 expand.c 131;" d file:
peektoken parser.c /^peektoken() {$/;" f
pendingsigs trap.c /^int pendingsigs; \/* indicates some signal received *\/$/;" v
pfgets input.c /^pfgets(line, len)$/;" f
pgetc input.c /^pgetc()$/;" f
pgetc_macro input.h 66;" d
pgrp jobs.h /^ short pgrp; \/* process group of this job *\/$/;" m struct:job
pid jobs.h /^ pid_t pid; \/* process id *\/$/;" m struct:procstat
pipeline parser.c /^pipeline() {$/;" f
plinno input.c /^int plinno = 1; \/* input line number *\/$/;" v
pmatch expand.c /^pmatch(pattern, string, squoted)$/;" f
pointer shell.h /^typedef char *pointer;$/;" t
pointer shell.h /^typedef void *pointer;$/;" t
popallfiles input.c /^popallfiles() {$/;" f
popfile input.c /^popfile() {$/;" f
poplocalvars var.c /^poplocalvars() {$/;" f
popredir redir.c /^popredir() {$/;" f
popstackmark memalloc.c /^popstackmark(mark)$/;" f
popstring input.c /^popstring()$/;" f
preadbuffer input.c /^preadbuffer()$/;" f
preadfd input.c /^preadfd()$/;" f file:
prefix mystring.c /^prefix(pfx, string)$/;" f
preglob expand.c /^preglob(str)$/;" f
prehash eval.c /^prehash(n)$/;" f
prev input.c /^ struct parsefile *prev; \/* preceding file on stack *\/$/;" m struct:parsefile file:
prev input.c /^ struct strpush *prev; \/* preceding string on stack *\/$/;" m struct:strpush file:
prev memalloc.c /^ struct stack_block *prev;$/;" m struct:stack_block file:
prevcmd main.c /^STATIC union node *prevcmd;$/;" v
prevdir cd.c /^char *prevdir; \/* previous working directory *\/$/;" v
prevlleft input.c /^ int prevlleft;$/;" m struct:strpush file:
prevnleft input.c /^ int prevnleft;$/;" m struct:strpush file:
prevstring input.c /^ char *prevstring;$/;" m struct:strpush file:
primary bltin/test.c /^primary(n)$/;" f file:
print mksyntax.c /^print(name)$/;" f file:
printentry exec.c /^printentry(cmdp, verbose)$/;" f
printf bltin/bltin.h 55;" d
procargs options.c /^procargs(argc, argv)$/;" f
procstat jobs.h /^struct procstat {$/;" s
profile_buf main.c /^short profile_buf[16384];$/;" v
progname mksignames.c /^char *progname;$/;" v
ps jobs.h /^ struct procstat *ps; \/* status or processes when more than one *\/$/;" m struct:job
ps0 jobs.h /^ struct procstat ps0; \/* status of process *\/$/;" m struct:job
ps1val var.h 101;" d
ps2val var.h 102;" d
pungetc input.c /^pungetc() {$/;" f
pushfile input.c /^pushfile() {$/;" f
pushstring input.c /^pushstring(s, len, ap)$/;" f
putc bltin/bltin.h 56;" d
putchar bltin/bltin.h 57;" d
pwdcmd cd.c /^pwdcmd(argc, argv)$/;" f
qflag options.h 66;" d
quoteflag parser.c /^int quoteflag; \/* set if (part of) last token was quoted *\/$/;" v
rcsid mkinit.c /^static const char rcsid[] =$/;" v file:
rcsid mknodes.c /^static const char rcsid[] =$/;" v file:
rcsid mksyntax.c /^static const char rcsid[] =$/;" v file:
read_profile main.c /^read_profile(name)$/;" f
readcmd miscbltin.c /^readcmd(argc, argv)$/;" f
readcmdfile main.c /^readcmdfile(name)$/;" f
readfile mkinit.c /^readfile(fname)$/;" f
readline mknodes.c /^readline()$/;" f file:
readtoken parser.c /^readtoken() {$/;" f
readtoken1 parser.c /^readtoken1(firstc, syntax, eofmark, striptabs)$/;" f
recordregion expand.c /^recordregion(start, end, nulonly)$/;" f
redirect redir.c /^redirect(redir, flags)$/;" f
redirlist redir.c /^MKINIT struct redirtab *redirlist;$/;" v
redirnode parser.c /^union node *redirnode;$/;" v
redirtab redir.c /^struct redirtab {$/;" s file:
rehash exec.c /^ char rehash; \/* if set, cd done since entry created *\/$/;" m struct:tblentry file:
removerecordregions expand.c /^removerecordregions(endoff)$/;" f
renamed redir.c /^ short renamed[10];$/;" m struct:redirtab file:
reset mkinit.c /^char reset[] = "\\$/;" v
reset_term hetio.c /^static int reset_term = 0; \/* Set to true if the terminal needs to be reset upon exit *\/$/;" v file:
restartjob jobs.c /^restartjob(jp)$/;" f
returncmd eval.c /^returncmd(argc, argv)$/;" f
rflag miscbltin.c 71;" d file:
rlim_t miscbltin.c /^typedef enum __rlimit_resource rlim_t;$/;" t file:
rmaliases alias.c /^rmaliases() {$/;" f
rmescapes expand.c /^rmescapes(str)$/;" f
rootpid main.c /^int rootpid;$/;" v
rootshell main.c /^int rootshell;$/;" v
routine mkinit.c /^ char *routine; \/* name of routine called on event *\/$/;" m struct:event file:
s hetio.c /^ char *s;$/;" m struct:history file:
savestr memalloc.c /^savestr(s)$/;" f
savestr mkinit.c /^savestr(s)$/;" f
savestr mknodes.c /^savestr(s)$/;" f file:
sccsid arith.c /^static char sccsid[] = "@(#)arith.y 8.3 (Berkeley) 5\/4\/95";$/;" v file:
scopy mystring.h 49;" d
scopyn mystring.c /^scopyn(from, to, size)$/;" f
setIO hetio.c /^void setIO(struct termios *new, struct termios *old) \/* Set terminal IO to canonical mode, and save old term settings. *\/$/;" f
setalias alias.c /^setalias(name, val)$/;" f
setcmd options.c /^setcmd(argc, argv)$/;" f
sethistsize histedit.c /^sethistsize(hs)$/;" f
setinputfd input.c /^setinputfd(fd, push)$/;" f
setinputfile input.c /^setinputfile(fname, push)$/;" f
setinputstring input.c /^setinputstring(string, push)$/;" f
setinteractive trap.c /^setinteractive(on)$/;" f
setjmp error.h 106;" d
setjobctl jobs.c /^setjobctl(on)$/;" f
setjobctl jobs.h 97;" d
setmode setmode.c /^setmode(p)$/;" f
setoption options.c /^setoption(flag, val)$/;" f
setparam options.c /^setparam(argv)$/;" f
setprompt parser.c /^setprompt(which)$/;" f
setsignal trap.c /^setsignal(signo)$/;" f
setstackmark memalloc.c /^setstackmark(mark)$/;" f
setterm histedit.c /^setterm(term)$/;" f
setvar var.c /^setvar(name, val, flags)$/;" f
setvarcmd var.c /^setvarcmd(argc, argv)$/;" f
setvareq var.c /^setvareq(s, flags)$/;" f
setvarsafe var.c /^setvarsafe(name, val, flags)$/;" f
sflag options.h 57;" d
sharg show.c /^sharg(arg, fp)$/;" f file:
shcmd show.c /^shcmd(cmd, fp)$/;" f file:
shellexec exec.c /^shellexec(argv, envp, path, idx)$/;" f
shellparam options.c /^struct shparam shellparam; \/* current positional parameters *\/$/;" v
shellproc mkinit.c /^char shellproc[] = "\\$/;" v
shiftcmd options.c /^shiftcmd(argc, argv)$/;" f
short arith.c 300;" d file:
showjobs jobs.c /^showjobs(change)$/;" f
showtree show.c /^showtree(n)$/;" f
showvarscmd var.c /^showvarscmd(argc, argv)$/;" f
shparam options.h /^struct shparam {$/;" s
shprocvar var.c /^shprocvar() {$/;" f
shtree show.c /^shtree(n, ind, pfx, fp)$/;" f file:
sigmode trap.c /^MKINIT char sigmode[NSIG]; \/* current value of signal *\/$/;" v
signal_names mksignames.c /^char *signal_names[2 * NSIG];$/;" v
simplecmd parser.c /^simplecmd(rpp, redir)$/;" f
size mksyntax.c /^static int size; \/* number of values which a char variable can have *\/$/;" v file:
skipbl mknodes.c /^skipbl()$/;" f file:
skipcount eval.c /^STATIC int skipcount; \/* number of levels to skip *\/$/;" v
space memalloc.c /^ char space[MINSIZE];$/;" m struct:stack_block file:
sstrnleft memalloc.c /^int sstrnleft;$/;" v
stack_block memalloc.c /^struct stack_block {$/;" s file:
stackbase memalloc.c /^struct stack_block stackbase;$/;" v
stackblock memalloc.h 69;" d
stackblocksize memalloc.h 70;" d
stackmark memalloc.h /^struct stackmark {$/;" s
stacknleft memalloc.c /^int stacknleft = MINSIZE;$/;" v
stacknleft memalloc.h /^ int stacknleft;$/;" m struct:stackmark
stacknxt memalloc.c /^char *stacknxt = stackbase.space;$/;" v
stacknxt memalloc.h /^ char *stacknxt;$/;" m struct:stackmark
stackp memalloc.c /^struct stack_block *stackp = &stackbase;$/;" v
stackp memalloc.h /^ struct stack_block *stackp;$/;" m struct:stackmark
stalloc memalloc.c /^stalloc(nbytes)$/;" f
start mkinit.c /^ struct block *start;$/;" m struct:text file:
startlinno parser.c /^int startlinno; \/* line # where last token started *\/$/;" v
state jobs.h /^ char state; \/* true if job is finished *\/$/;" m struct:job
status jobs.h /^ int status; \/* status flags (defined above) *\/$/;" m struct:procstat
stderr bltin/bltin.h 54;" d
stdout bltin/bltin.h 53;" d
stoppedjobs jobs.c /^stoppedjobs()$/;" f
str mknodes.c /^static struct str str[MAXTYPES]; \/* the structures *\/$/;" v file:
str mknodes.c /^struct str { \/* struct representing a node structure *\/$/;" s file:
str_to_event histedit.c /^str_to_event(str, last)$/;" f
stream output.h /^ FILE *stream;$/;" m struct:output
striptabs parser.c /^ int striptabs; \/* if set, strip leading tabs *\/$/;" m struct:heredoc file:
strlist expand.h /^struct strlist {$/;" s
strpush input.c /^ struct strpush *strpush; \/* for pushing strings at this level *\/$/;" m struct:parsefile file:
strpush input.c /^struct strpush {$/;" s file:
strtodest expand.c /^strtodest(p, quoted, allow_split)$/;" f
stunalloc memalloc.c /^stunalloc(p)$/;" f
subevalvar expand.c /^subevalvar(p, str, strloc, subtype, startloc, varflags)$/;" f
suppressint error.c /^volatile int suppressint;$/;" v
synclass mksyntax.c /^struct synclass synclass[] = {$/;" v
synclass mksyntax.c /^struct synclass {$/;" s file:
synerror parser.c /^synerror(msg)$/;" f
synexpect parser.c /^synexpect(token)$/;" f
syntax bltin/test.c /^syntax(op, msg)$/;" f file:
syntax mksyntax.c /^static char *syntax[513];$/;" v file:
t_lex bltin/test.c /^t_lex(s)$/;" f file:
t_op bltin/test.c /^static struct t_op {$/;" s file:
t_wp bltin/test.c /^static char **t_wp;$/;" v file:
t_wp_op bltin/test.c /^static struct t_op const *t_wp_op;$/;" v file:
tag mknodes.c /^ char *tag; \/* structure tag *\/$/;" m struct:str file:
tblentry exec.c /^struct tblentry {$/;" s file:
termval var.h 106;" d
test_eaccess bltin/test.c /^test_eaccess (path, mode)$/;" f file:
testcmd bltin/test.c /^testcmd(argc, argv)$/;" f
text expand.h /^ char *text;$/;" m struct:strlist
text mkinit.c /^ char text[BLOCKSIZE];$/;" m struct:block file:
text mkinit.c /^struct text {$/;" s file:
text var.c /^ const char *text;$/;" m struct:varinit file:
text var.h /^ char *text; \/* name=value *\/$/;" m struct:var
text var.h /^ char *text; \/* saved text *\/$/;" m struct:localvar
token bltin/test.c /^enum token {$/;" g file:
token_types bltin/test.c /^enum token_types {$/;" g file:
tokpushback parser.c /^MKINIT int tokpushback; \/* last token pushed back *\/$/;" v
trace show.c /^trace(const char *fmt, ...)$/;" f
tracefile show.c /^FILE *tracefile;$/;" v
trap trap.c /^char *trap[NSIG+1]; \/* trap handler commands *\/$/;" v
trapcmd trap.c /^trapcmd(argc, argv)$/;" f
trargs show.c /^trargs(ap)$/;" f
trputc show.c /^trputc(c)$/;" f
trputs show.c /^trputs(s)$/;" f
trstring show.c /^trstring(s)$/;" f file:
truecmd eval.c /^truecmd(argc, argv)$/;" f
tryexec exec.c /^tryexec(cmd, argv, envp)$/;" f
type mknodes.c /^ int type; \/* type of field *\/$/;" m struct:field file:
typecmd exec.c /^typecmd(argc, argv)$/;" f
u exec.h /^ } u;$/;" m struct:cmdentry
uflag options.h 65;" d
ulimitcmd miscbltin.c /^ulimitcmd(argc, argv)$/;" f
umaskcmd miscbltin.c /^umaskcmd(argc, argv)$/;" f
unalias alias.c /^unalias(name)$/;" f
unaliascmd alias.c /^unaliascmd(argc, argv)$/;" f
ungrabstackstr memalloc.c /^ungrabstackstr(s, p)$/;" f
unsetcmd var.c /^unsetcmd(argc, argv)$/;" f
unsetfunc exec.c /^unsetfunc(name)$/;" f
unsetvar var.c /^unsetvar(s)$/;" f
updatepwd cd.c /^updatepwd(dir)$/;" f
used jobs.h /^ char used; \/* true if this entry is in used *\/$/;" m struct:job
val alias.h /^ char *val;$/;" m struct:alias
val options.h /^ char val;$/;" m struct:optent
var var.c /^ struct var *var;$/;" m struct:varinit file:
var var.h /^struct var {$/;" s
varequal var.c /^varequal(p, q)$/;" f
varinit var.c /^const struct varinit varinit[] = {$/;" v
varinit var.c /^struct varinit {$/;" s file:
varisset expand.c /^varisset(name, nulok)$/;" f
vartab var.c /^struct var *vartab[VTABSIZE];$/;" v
varvalue expand.c /^varvalue(name, quoted, allow_split)$/;" f
vatty var.c /^struct var vatty;$/;" v
vflag options.h 59;" d
vhistsize var.c /^struct var vhistsize;$/;" v
vifs var.c /^struct var vifs;$/;" v
vmail var.c /^struct var vmail;$/;" v
vmpath var.c /^struct var vmpath;$/;" v
voptind var.c /^struct var voptind;$/;" v
vp var.h /^ struct var *vp; \/* the variable that was made local *\/$/;" m struct:localvar
vpath var.c /^struct var vpath;$/;" v
vps1 var.c /^struct var vps1;$/;" v
vps2 var.c /^struct var vps2;$/;" v
vterm var.c /^struct var vterm;$/;" v
vvers var.c /^struct var vvers;$/;" v
waitcmd jobs.c /^waitcmd(argc, argv)$/;" f
waitforjob jobs.c /^waitforjob(jp)$/;" f
waitonint jobs.c /^STATIC void waitonint(int sig) {$/;" f
waitproc jobs.c /^waitproc(block, status)$/;" f
warnx bltin/bltin.h 61;" d
whichprompt input.c /^int whichprompt; \/* 1 == PS1, 2 == PS2 *\/$/;" v
wordtext parser.c /^char *wordtext; \/* text of last word returned by readtoken *\/$/;" v
write_signames mksignames.c /^write_signames (stream)$/;" f
writer mkinit.c /^char writer[] = "\\$/;" v
writer mknodes.c /^char writer[] = "\\$/;" v
writer mksyntax.c /^static char writer[] = "\\$/;" v file:
writetext mkinit.c /^writetext(text, fp)$/;" f
xflag options.h 58;" d
xioctl output.c /^xioctl(fd, request, arg)$/;" f
xwrite output.c /^xwrite(fd, buf, nbytes)$/;" f
xxreadtoken parser.c /^xxreadtoken() {$/;" f
yy_reduce_print arith.c /^yy_reduce_print (yyvsp, yyrule)$/;" f file:
yy_stack_print arith.c /^yy_stack_print (bottom, top)$/;" f file:
yy_symbol_print arith.c /^yy_symbol_print (yyoutput, yytype, yyvaluep)$/;" f file:
yy_symbol_value_print arith.c /^yy_symbol_value_print (yyoutput, yytype, yyvaluep)$/;" f file:
yyalloc arith.c /^union yyalloc$/;" u file:
yychar arith.c /^int yychar;$/;" v
yycheck arith.c /^static const yytype_int8 yycheck[] =$/;" v file:
yyclearin arith.c 739;" d file:
yydebug arith.c /^int yydebug;$/;" v
yydefact arith.c /^static const yytype_uint8 yydefact[] =$/;" v file:
yydefgoto arith.c /^static const yytype_int8 yydefgoto[] =$/;" v file:
yydestruct arith.c /^yydestruct (yymsg, yytype, yyvaluep)$/;" f file:
yyerrok arith.c 738;" d file:
yyerror arith.c /^yyerror(s)$/;" f
yylval arith.c /^YYSTYPE yylval;$/;" v
yynerrs arith.c /^int yynerrs;$/;" v
yypact arith.c /^static const yytype_int16 yypact[] =$/;" v file:
yypgoto arith.c /^static const yytype_int8 yypgoto[] =$/;" v file:
yyprhs arith.c /^static const yytype_uint8 yyprhs[] =$/;" v file:
yyr1 arith.c /^static const yytype_uint8 yyr1[] =$/;" v file:
yyr2 arith.c /^static const yytype_uint8 yyr2[] =$/;" v file:
yyrhs arith.c /^static const yytype_int8 yyrhs[] =$/;" v file:
yyrline arith.c /^static const yytype_uint8 yyrline[] =$/;" v file:
yyss arith.c /^ yytype_int16 yyss;$/;" m union:yyalloc file:
yystos arith.c /^static const yytype_uint8 yystos[] =$/;" v file:
yystpcpy arith.c /^yystpcpy (yydest, yysrc)$/;" f file:
yystpcpy arith.c 1034;" d file:
yystrlen arith.c /^yystrlen (yystr)$/;" f file:
yystrlen arith.c 1011;" d file:
yystype arith.c 286;" d file:
yystype arith.h 101;" d
yysyntax_error arith.c /^yysyntax_error (char *yyresult, int yystate, int yychar)$/;" f file:
yytable arith.c /^static const yytype_uint8 yytable[] =$/;" v file:
yytname arith.c /^static const char *const yytname[] =$/;" v file:
yytnamerr arith.c /^yytnamerr (char *yyres, const char *yystr)$/;" f file:
yytokentype arith.c /^ enum yytokentype {$/;" g file:
yytokentype arith.h /^ enum yytokentype {$/;" g
yytoknum arith.c /^static const yytype_uint16 yytoknum[] =$/;" v file:
yytranslate arith.c /^static const yytype_uint8 yytranslate[] =$/;" v file:
yytype_int16 arith.c /^typedef YYTYPE_INT16 yytype_int16;$/;" t file:
yytype_int16 arith.c /^typedef short int yytype_int16;$/;" t file:
yytype_int8 arith.c /^typedef YYTYPE_INT8 yytype_int8;$/;" t file:
yytype_int8 arith.c /^typedef short int yytype_int8;$/;" t file:
yytype_int8 arith.c /^typedef signed char yytype_int8;$/;" t file:
yytype_uint16 arith.c /^typedef YYTYPE_UINT16 yytype_uint16;$/;" t file:
yytype_uint16 arith.c /^typedef unsigned short int yytype_uint16;$/;" t file:
yytype_uint8 arith.c /^typedef YYTYPE_UINT8 yytype_uint8;$/;" t file:
yytype_uint8 arith.c /^typedef unsigned char yytype_uint8;$/;" t file:
yyvs arith.c /^ YYSTYPE yyvs;$/;" m union:yyalloc file:
/trunk/uspace/app/ash/histedit.c
0,0 → 1,513
/* $NetBSD: histedit.c,v 1.24 2000/11/06 04:21:14 mycroft 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
 
#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.24 2000/11/06 04:21:14 mycroft Exp $");
#endif
#endif /* not lint */
 
#include <sys/param.h>
#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
/*
* Editline and history functions (and glue).
*/
#include "shell.h"
#include "parser.h"
#include "var.h"
#include "options.h"
#include "main.h"
#include "output.h"
#include "mystring.h"
#include "error.h"
#ifndef SMALL
#include "myhistedit.h"
#include "eval.h"
#include "memalloc.h"
 
#define MAXHISTLOOPS 4 /* max recursions through fc */
#define DEFEDITOR "ed" /* default editor *should* be $EDITOR */
 
History *hist; /* history cookie */
EditLine *el; /* editline cookie */
int displayhist;
static FILE *el_in, *el_out;
 
STATIC const char *fc_replace (const char *, char *, char *);
 
/*
* Set history and editing status. Called whenever the status may
* have changed (figures out what to do).
*/
void
histedit()
{
 
#define editing (Eflag || Vflag)
 
if (iflag) {
if (!hist) {
/*
* turn history on
*/
INTOFF;
hist = history_init();
INTON;
 
if (hist != NULL)
sethistsize(histsizeval());
else
out2str("sh: can't initialize history\n");
}
if (editing && !el && isatty(0)) { /* && isatty(2) ??? */
/*
* turn editing on
*/
INTOFF;
if (el_in == NULL)
el_in = fdopen(0, "r");
if (el_out == NULL)
el_out = fdopen(2, "w");
if (el_in == NULL || el_out == NULL)
goto bad;
el = el_init(arg0, el_in, el_out, el_out);
if (el != NULL) {
if (hist)
el_set(el, EL_HIST, history, hist);
el_set(el, EL_PROMPT, getprompt);
} else {
bad:
out2str("sh: can't initialize editing\n");
}
INTON;
} else if (!editing && el) {
INTOFF;
el_end(el);
el = NULL;
INTON;
}
if (el) {
if (Vflag)
el_set(el, EL_EDITOR, "vi");
else if (Eflag)
el_set(el, EL_EDITOR, "emacs");
el_source(el, NULL);
}
} else {
INTOFF;
if (el) { /* no editing if not interactive */
el_end(el);
el = NULL;
}
if (hist) {
history_end(hist);
hist = NULL;
}
INTON;
}
}
 
 
void
sethistsize(hs)
const char *hs;
{
int histsize;
HistEvent he;
 
if (hist != NULL) {
if (hs == NULL || *hs == '\0' ||
(histsize = atoi(hs)) < 0)
histsize = 100;
history(hist, &he, H_SETSIZE, histsize);
}
}
 
void
setterm(term)
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");
}
}
 
/*
* This command is provided since POSIX decided to standardize
* the Korn shell fc command. Oh well...
*/
int
histcmd(argc, argv)
int argc;
char **argv;
{
int ch;
const char *editor = NULL;
HistEvent he;
int lflg = 0, nflg = 0, rflg = 0, sflg = 0;
int i, retval;
const char *firststr, *laststr;
int first, last, direction;
char *pat = NULL, *repl; /* ksh "fc old=new" crap */
static int active = 0;
struct jmploc jmploc;
struct jmploc *volatile savehandler;
char editfile[MAXPATHLEN + 1];
FILE *efp;
#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;
#endif
 
if (hist == NULL)
error("history not active");
 
if (argc == 1)
error("missing history argument");
 
#ifdef __GLIBC__
optind = 1;
#else
optreset = 1; optind = 1; /* initialize getopt */
#endif
while (not_fcnumber(argv[optind]) &&
(ch = getopt(argc, argv, ":e:lnrs")) != -1)
switch ((char)ch) {
case 'e':
editor = optarg;
break;
case 'l':
lflg = 1;
break;
case 'n':
nflg = 1;
break;
case 'r':
rflg = 1;
break;
case 's':
sflg = 1;
break;
case ':':
error("option -%c expects argument", optopt);
/* NOTREACHED */
case '?':
default:
error("unknown option: -%c", optopt);
/* NOTREACHED */
}
argc -= optind, argv += optind;
 
/*
* If executing...
*/
if (lflg == 0 || editor || sflg) {
lflg = 0; /* ignore */
editfile[0] = '\0';
/*
* Catch interrupts to reset active counter and
* cleanup temp files.
*/
if (setjmp(jmploc.loc)) {
active = 0;
if (*editfile)
unlink(editfile);
handler = savehandler;
longjmp(handler->loc, 1);
}
savehandler = handler;
handler = &jmploc;
if (++active > MAXHISTLOOPS) {
active = 0;
displayhist = 0;
error("called recursively too many times");
}
/*
* Set editor.
*/
if (sflg == 0) {
if (editor == NULL &&
(editor = bltinlookup("FCEDIT", 1)) == NULL &&
(editor = bltinlookup("EDITOR", 1)) == NULL)
editor = DEFEDITOR;
if (editor[0] == '-' && editor[1] == '\0') {
sflg = 1; /* no edit */
editor = NULL;
}
}
}
 
/*
* If executing, parse [old=new] now
*/
if (lflg == 0 && argc > 0 &&
((repl = strchr(argv[0], '=')) != NULL)) {
pat = argv[0];
*repl++ = '\0';
argc--, argv++;
}
/*
* determine [first] and [last]
*/
switch (argc) {
case 0:
firststr = lflg ? "-16" : "-1";
laststr = "-1";
break;
case 1:
firststr = argv[0];
laststr = lflg ? "-1" : argv[0];
break;
case 2:
firststr = argv[0];
laststr = argv[1];
break;
default:
error("too many args");
/* NOTREACHED */
}
/*
* Turn into event numbers.
*/
first = str_to_event(firststr, 0);
last = str_to_event(laststr, 1);
 
if (rflg) {
i = last;
last = first;
first = i;
}
/*
* XXX - this should not depend on the event numbers
* always increasing. Add sequence numbers or offset
* to the history element in next (diskbased) release.
*/
direction = first < last ? H_PREV : H_NEXT;
 
/*
* If editing, grab a temp file.
*/
if (editor) {
int fd;
INTOFF; /* easier */
sprintf(editfile, "%s_shXXXXXX", _PATH_TMP);
if ((fd = mkstemp(editfile)) < 0)
error("can't create temporary file %s", editfile);
if ((efp = fdopen(fd, "w")) == NULL) {
close(fd);
error("can't allocate stdio buffer for temp");
}
}
 
/*
* Loop through selected history events. If listing or executing,
* do it now. Otherwise, put into temp file and call the editor
* after.
*
* The history interface needs rethinking, as the following
* convolutions will demonstrate.
*/
history(hist, &he, H_FIRST);
retval = history(hist, &he, H_NEXT_EVENT, first);
for (;retval != -1; retval = history(hist, &he, direction)) {
if (lflg) {
if (!nflg)
out1fmt("%5d ", he.num);
out1str(he.str);
} else {
const char *s = pat ?
fc_replace(he.str, pat, repl) : he.str;
char *sp;
 
if (sflg) {
if (displayhist) {
out2str(s);
}
 
evalstring(strcpy(stalloc(strlen(s) + 1), s), 0);
free(sp);
if (displayhist && hist) {
/*
* XXX what about recursive and
* relative histnums.
*/
history(hist, &he, H_ENTER, s);
}
} else
fputs(s, efp);
}
/*
* At end? (if we were to lose last, we'd sure be
* messed up).
*/
if (he.num == last)
break;
}
if (editor) {
char *editcmd;
 
fclose(efp);
editcmd = stalloc(strlen(editor) + strlen(editfile) + 2);
sprintf(editcmd, "%s %s", editor, editfile);
evalstring(editcmd, 0); /* XXX - should use no JC command */
INTON;
readcmdfile(editfile); /* XXX - should read back - quick tst */
unlink(editfile);
}
 
if (lflg == 0 && active > 0)
--active;
if (displayhist)
displayhist = 0;
return 0;
}
 
STATIC const char *
fc_replace(s, p, r)
const char *s;
char *p, *r;
{
char *dest;
int plen = strlen(p);
 
STARTSTACKSTR(dest);
while (*s) {
if (*s == *p && strncmp(s, p, plen) == 0) {
while (*r)
STPUTC(*r++, dest);
s += plen;
*p = '\0'; /* so no more matches */
} else
STPUTC(*s++, dest);
}
STACKSTRNUL(dest);
dest = grabstackstr(dest);
 
return (dest);
}
 
int
not_fcnumber(s)
char *s;
{
if (s == NULL)
return 0;
if (*s == '-')
s++;
return (!is_number(s));
}
 
int
str_to_event(str, last)
const char *str;
int last;
{
HistEvent he;
const char *s = str;
int relative = 0;
int i, retval;
 
retval = history(hist, &he, H_FIRST);
switch (*s) {
case '-':
relative = 1;
/*FALLTHROUGH*/
case '+':
s++;
}
if (is_number(s)) {
i = atoi(s);
if (relative) {
while (retval != -1 && i--) {
retval = history(hist, &he, H_NEXT);
}
if (retval == -1)
retval = history(hist, &he, H_LAST);
} else {
retval = history(hist, &he, H_NEXT_EVENT, i);
if (retval == -1) {
/*
* the notion of first and last is
* backwards to that of the history package
*/
retval = history(hist, &he,
last ? H_FIRST : H_LAST);
}
}
if (retval == -1)
error("history number %s not found (internal error)",
str);
} else {
/*
* pattern
*/
retval = history(hist, &he, H_PREV_STR, str);
if (retval == -1)
error("history pattern not found: %s", str);
}
return (he.num);
}
#else
int
histcmd(argc, argv)
int argc;
char **argv;
{
error("not compiled with history support");
/* NOTREACHED */
}
#endif
/trunk/uspace/app/ash/show.c
0,0 → 1,447
/* $NetBSD: show.c,v 1.18 1999/10/08 21:10:44 pk 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
 
#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.18 1999/10/08 21:10:44 pk Exp $");
#endif
#endif /* not lint */
 
#include <stdio.h>
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
 
#include "shell.h"
#include "parser.h"
#include "nodes.h"
#include "mystring.h"
#include "show.h"
 
 
#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 *);
 
 
void
showtree(n)
union node *n;
{
trputs("showtree called\n");
shtree(n, 1, NULL, stdout);
}
 
 
static void
shtree(n, ind, pfx, fp)
union node *n;
int ind;
char *pfx;
FILE *fp;
{
struct nodelist *lp;
const char *s;
 
if (n == NULL)
return;
 
indent(ind, pfx, fp);
switch(n->type) {
case NSEMI:
s = "; ";
goto binop;
case NAND:
s = " && ";
goto binop;
case NOR:
s = " || ";
binop:
shtree(n->nbinary.ch1, ind, NULL, fp);
/* if (ind < 0) */
fputs(s, fp);
shtree(n->nbinary.ch2, ind, NULL, fp);
break;
case NCMD:
shcmd(n, fp);
if (ind >= 0)
putc('\n', fp);
break;
case NPIPE:
for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
shcmd(lp->n, fp);
if (lp->next)
fputs(" | ", fp);
}
if (n->npipe.backgnd)
fputs(" &", fp);
if (ind >= 0)
putc('\n', fp);
break;
default:
fprintf(fp, "<node type %d>", n->type);
if (ind >= 0)
putc('\n', fp);
break;
}
}
 
 
 
static void
shcmd(cmd, fp)
union node *cmd;
FILE *fp;
{
union node *np;
int first;
const char *s;
int dftfd;
 
first = 1;
for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
if (! first)
putchar(' ');
sharg(np, fp);
first = 0;
}
for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
if (! first)
putchar(' ');
switch (np->nfile.type) {
case NTO: s = ">"; dftfd = 1; break;
case NAPPEND: s = ">>"; dftfd = 1; break;
case NTOFD: s = ">&"; dftfd = 1; break;
case NTOOV: s = ">|"; dftfd = 1; break;
case NFROM: 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) {
fprintf(fp, "%d", np->ndup.dupfd);
} else {
sharg(np->nfile.fname, fp);
}
first = 0;
}
}
 
 
 
static void
sharg(arg, fp)
union node *arg;
FILE *fp;
{
char *p;
struct nodelist *bqlist;
int subtype;
 
if (arg->type != NARG) {
printf("<node type %d>\n", arg->type);
fflush(stdout);
abort();
}
bqlist = arg->narg.backquote;
for (p = arg->narg.text ; *p ; p++) {
switch (*p) {
case CTLESC:
putc(*++p, fp);
break;
case CTLVAR:
putc('$', fp);
putc('{', fp);
subtype = *++p;
if (subtype == VSLENGTH)
putc('#', fp);
 
while (*p != '=')
putc(*p++, fp);
 
if (subtype & VSNUL)
putc(':', fp);
 
switch (subtype & VSTYPE) {
case VSNORMAL:
putc('}', fp);
break;
case VSMINUS:
putc('-', fp);
break;
case VSPLUS:
putc('+', fp);
break;
case VSQUESTION:
putc('?', fp);
break;
case VSASSIGN:
putc('=', fp);
break;
case VSTRIMLEFT:
putc('#', fp);
break;
case VSTRIMLEFTMAX:
putc('#', fp);
putc('#', fp);
break;
case VSTRIMRIGHT:
putc('%', fp);
break;
case VSTRIMRIGHTMAX:
putc('%', fp);
putc('%', fp);
break;
case VSLENGTH:
break;
default:
printf("<subtype %d>", subtype);
}
break;
case CTLENDVAR:
putc('}', fp);
break;
case CTLBACKQ:
case CTLBACKQ|CTLQUOTE:
putc('$', fp);
putc('(', fp);
shtree(bqlist->n, -1, NULL, fp);
putc(')', fp);
break;
default:
putc(*p, fp);
break;
}
}
}
 
 
static void
indent(amount, pfx, fp)
int amount;
char *pfx;
FILE *fp;
{
int i;
 
for (i = 0 ; i < amount ; i++) {
if (pfx && i == amount - 1)
fputs(pfx, fp);
putc('\t', fp);
}
}
#endif
 
 
 
/*
* Debugging stuff.
*/
 
 
FILE *tracefile;
 
#if DEBUG == 2
int debug = 1;
#else
int debug = 0;
#endif
 
 
#ifdef DEBUG
void
trputc(c)
int c;
{
if (tracefile == NULL)
return;
putc(c, tracefile);
if (c == '\n')
fflush(tracefile);
}
#endif
 
void
#ifdef __STDC__
trace(const char *fmt, ...)
#else
trace(va_alist)
va_dcl
#endif
{
#ifdef DEBUG
va_list va;
#ifdef __STDC__
va_start(va, fmt);
#else
char *fmt;
va_start(va);
fmt = va_arg(va, char *);
#endif
if (tracefile != NULL) {
(void) vfprintf(tracefile, fmt, va);
if (strchr(fmt, '\n'))
(void) fflush(tracefile);
}
va_end(va);
#endif
}
 
 
#ifdef DEBUG
void
trputs(s)
const char *s;
{
if (tracefile == NULL)
return;
fputs(s, tracefile);
if (strchr(s, '\n'))
fflush(tracefile);
}
 
 
static void
trstring(s)
char *s;
{
char *p;
char c;
 
if (tracefile == NULL)
return;
putc('"', tracefile);
for (p = s ; *p ; p++) {
switch (*p) {
case '\n': c = 'n'; goto backslash;
case '\t': c = 't'; goto backslash;
case '\r': c = 'r'; goto backslash;
case '"': c = '"'; goto backslash;
case '\\': c = '\\'; goto backslash;
case CTLESC: c = 'e'; goto backslash;
case CTLVAR: c = 'v'; goto backslash;
case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
case CTLBACKQ: c = 'q'; goto backslash;
case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
backslash: putc('\\', tracefile);
putc(c, tracefile);
break;
default:
if (*p >= ' ' && *p <= '~')
putc(*p, tracefile);
else {
putc('\\', tracefile);
putc(*p >> 6 & 03, tracefile);
putc(*p >> 3 & 07, tracefile);
putc(*p & 07, tracefile);
}
break;
}
}
putc('"', tracefile);
}
#endif
 
 
void
trargs(ap)
char **ap;
{
#ifdef DEBUG
if (tracefile == NULL)
return;
while (*ap) {
trstring(*ap++);
if (*ap)
putc(' ', tracefile);
else
putc('\n', tracefile);
}
fflush(tracefile);
#endif
}
 
 
#ifdef DEBUG
void
opentrace() {
char s[100];
#ifdef O_APPEND
int flags;
#endif
 
if (!debug)
return;
#ifdef not_this_way
{
char *p;
if ((p = getenv("HOME")) == NULL) {
if (geteuid() == 0)
p = "/";
else
p = "/tmp";
}
scopy(p, s);
strcat(s, "/trace");
}
#else
scopy("./trace", s);
#endif /* not_this_way */
if ((tracefile = fopen(s, "a")) == NULL) {
fprintf(stderr, "Can't open %s\n", s);
return;
}
#ifdef O_APPEND
if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
#endif
fputs("\nTracing started.\n", tracefile);
fflush(tracefile);
}
#endif /* DEBUG */
/trunk/uspace/app/ash/mystring.h
0,0 → 1,49
/* $NetBSD: mystring.h,v 1.9 1995/05/11 21:29:42 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)mystring.h 8.2 (Berkeley) 5/4/95
*/
 
#include <string.h>
 
void scopyn (const char *, char *, int);
int prefix (const char *, const char *);
int number (const char *);
int is_number (const char *);
 
#define equal(s1, s2) (strcmp(s1, s2) == 0)
#define scopy(s1, s2) ((void)strcpy(s2, s1))
/trunk/uspace/app/ash/show.h
0,0 → 1,46
/* $NetBSD: show.h,v 1.4 1999/10/08 21:10:44 pk Exp $ */
 
/*-
* Copyright (c) 1995
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)show.h 1.1 (Berkeley) 5/4/95
*/
 
union node;
void showtree (union node *);
void trace (const char *, ...);
void trargs (char **);
#ifdef DEBUG
void trputc (int);
void trputs (const char *);
void opentrace (void);
#endif
/trunk/uspace/app/ash/myhistedit.h
0,0 → 1,50
/* $NetBSD: myhistedit.h,v 1.7 1999/07/09 03:05:50 christos Exp $ */
 
/*-
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)myhistedit.h 8.2 (Berkeley) 5/4/95
*/
 
#include <histedit.h>
 
extern History *hist;
extern EditLine *el;
extern int displayhist;
 
void histedit (void);
void sethistsize (const char *);
void setterm (const char *);
int histcmd (int, char **);
int not_fcnumber (char *);
int str_to_event (const char *, int);
 
/trunk/uspace/app/ash/arith_lex.l
0,0 → 1,95
%{
/* $NetBSD: arith_lex.l,v 1.10 1999/02/05 07:52:52 christos 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
 
#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.10 1999/02/05 07:52:52 christos Exp $");
#endif
#endif /* not lint */
 
#include <unistd.h>
#include "arith.h"
#include "error.h"
#include "expand.h"
 
extern int yylval;
extern 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
%}
 
%%
[ \t\n] { ; }
[0-9]+ { yylval = atol(yytext); return(ARITH_NUM); }
"(" { 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\"\n", arith_startbuf); }
%%
 
void
arith_lex_reset() {
#ifdef YY_NEW_FILE
YY_NEW_FILE;
#endif
}
/trunk/uspace/app/ash/funcs/dirs
0,0 → 1,74
# $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.
#
# 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. All advertising materials mentioning features or use of this software
# must display the following acknowledgement:
# This product includes software developed by the University of
# California, Berkeley and its contributors.
# 4. Neither the name of the University nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# @(#)dirs 8.2 (Berkeley) 5/4/95
 
# pushd, popd, and dirs --- written by Chris Bertin
# Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris
# as modified by Patrick Elam of GTRI and Kenneth Almquist at UW
 
pushd () {
SAVE=`pwd`
if [ "$1" = "" ]
then if [ "$DSTACK" = "" ]
then echo "pushd: directory stack empty."
return 1
fi
set $DSTACK
cd $1 || return
shift 1
DSTACK="$*"
else cd $1 > /dev/null || return
fi
DSTACK="$SAVE $DSTACK"
dirs
}
 
popd () {
if [ "$DSTACK" = "" ]
then echo "popd: directory stack empty."
return 1
fi
set $DSTACK
cd $1
shift
DSTACK=$*
dirs
}
 
dirs () {
echo "`pwd` $DSTACK"
return 0
}
/trunk/uspace/app/ash/funcs/suspend
0,0 → 1,42
# $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.
#
# 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. All advertising materials mentioning features or use of this software
# must display the following acknowledgement:
# This product includes software developed by the University of
# California, Berkeley and its contributors.
# 4. Neither the name of the University nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# @(#)suspend 8.2 (Berkeley) 5/4/95
 
suspend() {
local -
set +j
kill -TSTP 0
}
/trunk/uspace/app/ash/funcs/newgrp
0,0 → 1,38
# $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.
#
# 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. All advertising materials mentioning features or use of this software
# must display the following acknowledgement:
# This product includes software developed by the University of
# California, Berkeley and its contributors.
# 4. Neither the name of the University nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# @(#)newgrp 8.2 (Berkeley) 5/4/95
 
newgrp() exec newgrp "$@"
/trunk/uspace/app/ash/funcs/popd
0,0 → 1,74
# $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.
#
# 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. All advertising materials mentioning features or use of this software
# must display the following acknowledgement:
# This product includes software developed by the University of
# California, Berkeley and its contributors.
# 4. Neither the name of the University nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# @(#)popd 8.2 (Berkeley) 5/4/95
 
# pushd, popd, and dirs --- written by Chris Bertin
# Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris
# as modified by Patrick Elam of GTRI and Kenneth Almquist at UW
 
pushd () {
SAVE=`pwd`
if [ "$1" = "" ]
then if [ "$DSTACK" = "" ]
then echo "pushd: directory stack empty."
return 1
fi
set $DSTACK
cd $1 || return
shift 1
DSTACK="$*"
else cd $1 > /dev/null || return
fi
DSTACK="$SAVE $DSTACK"
dirs
}
 
popd () {
if [ "$DSTACK" = "" ]
then echo "popd: directory stack empty."
return 1
fi
set $DSTACK
cd $1
shift
DSTACK=$*
dirs
}
 
dirs () {
echo "`pwd` $DSTACK"
return 0
}
/trunk/uspace/app/ash/funcs/pushd
0,0 → 1,74
# $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.
#
# 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. All advertising materials mentioning features or use of this software
# must display the following acknowledgement:
# This product includes software developed by the University of
# California, Berkeley and its contributors.
# 4. Neither the name of the University nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# @(#)pushd 8.2 (Berkeley) 5/4/95
 
# pushd, popd, and dirs --- written by Chris Bertin
# Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris
# as modified by Patrick Elam of GTRI and Kenneth Almquist at UW
 
pushd () {
SAVE=`pwd`
if [ "$1" = "" ]
then if [ "$DSTACK" = "" ]
then echo "pushd: directory stack empty."
return 1
fi
set $DSTACK
cd $1 || return
shift 1
DSTACK="$*"
else cd $1 > /dev/null || return
fi
DSTACK="$SAVE $DSTACK"
dirs
}
 
popd () {
if [ "$DSTACK" = "" ]
then echo "popd: directory stack empty."
return 1
fi
set $DSTACK
cd $1
shift
DSTACK=$*
dirs
}
 
dirs () {
echo "`pwd` $DSTACK"
return 0
}
/trunk/uspace/app/ash/funcs/cmv
0,0 → 1,50
# $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.
#
# 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. All advertising materials mentioning features or use of this software
# must display the following acknowledgement:
# This product includes software developed by the University of
# California, Berkeley and its contributors.
# 4. Neither the name of the University nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# @(#)cmv 8.2 (Berkeley) 5/4/95
 
# Conditional move--don't replace an existing file.
 
cmv() {
if test $# != 2
then echo "cmv: arg count"
return 2
fi
if test -f "$2" -o -w "$2"
then echo "$2 exists"
return 2
fi
/bin/mv "$1" "$2"
}
/trunk/uspace/app/ash/funcs/login
0,0 → 1,39
# $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.
#
# 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. All advertising materials mentioning features or use of this software
# must display the following acknowledgement:
# This product includes software developed by the University of
# California, Berkeley and its contributors.
# 4. Neither the name of the University nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# @(#)login 8.2 (Berkeley) 5/4/95
 
# replaces the login builtin in the BSD shell
login () exec login "$@"
/trunk/uspace/app/ash/funcs/kill
0,0 → 1,50
# $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.
#
# 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. All advertising materials mentioning features or use of this software
# must display the following acknowledgement:
# This product includes software developed by the University of
# California, Berkeley and its contributors.
# 4. Neither the name of the University nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# @(#)kill 8.2 (Berkeley) 5/4/95
 
# Convert job names to process ids and then run /bin/kill.
 
kill() {
local args x
args=
for x in "$@"
do case $x in
%*) x=`jobid "$x"` ;;
esac
args="$args $x"
done
/bin/kill $args
}
/trunk/uspace/app/ash/input.c
0,0 → 1,531
/* $NetBSD: input.c,v 1.34 2000/05/22 10:18:47 elric 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
 
#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.34 2000/05/22 10:18:47 elric Exp $");
#endif
#endif /* not lint */
 
#include <stdio.h> /* defines BUFSIZ */
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
 
/*
* This file implements the input routines used by the parser.
*/
 
#include "shell.h"
#include "redir.h"
#include "syntax.h"
#include "input.h"
#include "output.h"
#include "options.h"
#include "memalloc.h"
#include "error.h"
#include "alias.h"
#include "parser.h"
#ifndef SMALL
#include "myhistedit.h"
#endif
 
#ifdef HETIO
#include "hetio.h"
#endif
 
#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
 
MKINIT
struct strpush {
struct strpush *prev; /* preceding string on stack */
char *prevstring;
int prevnleft;
int prevlleft;
struct alias *ap; /* if push was associated with an alias */
};
 
/*
* The parsefile structure pointed to by the global variable parsefile
* contains information about the current file being read.
*/
 
MKINIT
struct parsefile {
struct parsefile *prev; /* preceding file on stack */
int linno; /* current line */
int fd; /* file descriptor (or -1 if string) */
int nleft; /* number of chars left in this line */
int lleft; /* number of chars left in this buffer */
char *nextc; /* next char in buffer */
char *buf; /* input buffer */
struct strpush *strpush; /* for pushing strings at this level */
struct strpush basestrpush; /* so pushing one is fast */
};
 
 
int plinno = 1; /* input line number */
MKINIT 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 */
struct parsefile *parsefile = &basepf; /* current input file */
int init_editline = 0; /* editline library initialized? */
int whichprompt; /* 1 == PS1, 2 == PS2 */
 
#ifndef SMALL
EditLine *el; /* cookie for editline package */
#endif
 
STATIC void pushfile (void);
static int preadfd (void);
 
#ifdef mkinit
INCLUDE "input.h"
INCLUDE "error.h"
 
INIT {
extern char basebuf[];
 
basepf.nextc = basepf.buf = basebuf;
}
 
RESET {
if (exception != EXSHELLPROC)
parselleft = parsenleft = 0; /* clear input buffer */
popallfiles();
}
 
SHELLPROC {
popallfiles();
}
#endif
 
 
/*
* Read a line from the script.
*/
 
char *
pfgets(line, len)
char *line;
int len;
{
char *p = line;
int nleft = len;
int c;
 
while (--nleft > 0) {
c = pgetc_macro();
if (c == PEOF) {
if (p == line)
return NULL;
break;
}
*p++ = c;
if (c == '\n')
break;
}
*p = '\0';
return line;
}
 
 
 
/*
* Read a character from the script, returning PEOF on end of file.
* Nul characters in the input are silently discarded.
*/
 
int
pgetc()
{
return pgetc_macro();
}
 
 
static int
preadfd()
{
int nr;
char *buf = parsefile->buf;
parsenextc = buf;
 
retry:
#ifndef SMALL
if (parsefile->fd == 0 && el) {
const char *rl_cp;
 
rl_cp = el_gets(el, &nr);
if (rl_cp == NULL)
nr = 0;
else {
/* XXX - BUFSIZE should redesign so not necessary */
(void) strcpy(buf, rl_cp);
}
} else
#endif
 
#ifdef HETIO
nr = hetio_read_input(parsefile->fd);
if (nr == -255)
#endif
nr = read(parsefile->fd, buf, BUFSIZ - 1);
 
 
if (nr <= 0) {
if (nr < 0) {
if (errno == EINTR)
goto retry;
if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
int flags = fcntl(0, F_GETFL, 0);
if (flags >= 0 && flags & O_NONBLOCK) {
flags &=~ O_NONBLOCK;
if (fcntl(0, F_SETFL, flags) >= 0) {
out2str("sh: turning off NDELAY mode\n");
goto retry;
}
}
}
}
nr = -1;
}
return nr;
}
 
/*
* Refill the input buffer and return the next input character:
*
* 1) If a string was pushed back on the input, pop it;
* 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
* from a string so we can't refill the buffer, return EOF.
* 3) If 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.
*/
 
int
preadbuffer()
{
char *p, *q;
int more;
int something;
char savec;
 
if (parsefile->strpush) {
popstring();
if (--parsenleft >= 0)
return (*parsenextc++);
}
if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
return PEOF;
flushout(&output);
flushout(&errout);
 
again:
if (parselleft <= 0) {
if ((parselleft = preadfd()) == -1) {
parselleft = parsenleft = EOF_NLEFT;
return PEOF;
}
}
 
q = p = parsenextc;
 
/* delete nul characters */
something = 0;
for (more = 1; more;) {
switch (*p) {
case '\0':
p++; /* Skip nul */
goto check;
 
case '\t':
case ' ':
break;
 
case '\n':
parsenleft = q - parsenextc;
more = 0; /* Stop processing here */
break;
 
default:
something = 1;
break;
}
 
*q++ = *p++;
check:
if (--parselleft <= 0) {
parsenleft = q - parsenextc - 1;
if (parsenleft < 0)
goto again;
*q = '\0';
more = 0;
}
}
 
savec = *q;
*q = '\0';
 
#ifndef SMALL
if (parsefile->fd == 0 && hist && something) {
HistEvent he;
INTOFF;
history(hist, &he, whichprompt == 1? H_ENTER : H_APPEND,
parsenextc);
INTON;
}
#endif
 
if (vflag) {
out2str(parsenextc);
flushout(out2);
}
 
*q = savec;
 
return *parsenextc++;
}
 
/*
* Undo the last call to pgetc. Only one character may be pushed back.
* PEOF may be pushed back.
*/
 
void
pungetc() {
parsenleft++;
parsenextc--;
}
 
/*
* Push a string back onto the input at this current parsefile level.
* We handle aliases this way.
*/
void
pushstring(s, len, ap)
char *s;
int len;
void *ap;
{
struct strpush *sp;
 
INTOFF;
/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
if (parsefile->strpush) {
sp = ckmalloc(sizeof (struct strpush));
sp->prev = parsefile->strpush;
parsefile->strpush = sp;
} else
sp = parsefile->strpush = &(parsefile->basestrpush);
sp->prevstring = parsenextc;
sp->prevnleft = parsenleft;
sp->prevlleft = parselleft;
sp->ap = (struct alias *)ap;
if (ap)
((struct alias *)ap)->flag |= ALIASINUSE;
parsenextc = s;
parsenleft = len;
INTON;
}
 
void
popstring()
{
struct strpush *sp = parsefile->strpush;
 
INTOFF;
parsenextc = sp->prevstring;
parsenleft = sp->prevnleft;
parselleft = sp->prevlleft;
/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
if (sp->ap)
sp->ap->flag &= ~ALIASINUSE;
parsefile->strpush = sp->prev;
if (sp != &(parsefile->basestrpush))
ckfree(sp);
INTON;
}
 
/*
* Set the input to take input from a file. If push is set, push the
* old input onto the stack first.
*/
 
void
setinputfile(fname, push)
const char *fname;
int push;
{
int fd;
int fd2;
 
INTOFF;
if ((fd = open(fname, O_RDONLY)) < 0)
error("Can't open %s", fname);
if (fd < 10) {
fd2 = copyfd(fd, 10);
close(fd);
if (fd2 < 0)
error("Out of file descriptors");
fd = fd2;
}
setinputfd(fd, push);
INTON;
}
 
 
/*
* Like setinputfile, but takes an open file descriptor. Call this with
* interrupts off.
*/
 
void
setinputfd(fd, push)
int fd, push;
{
(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
if (push) {
pushfile();
parsefile->buf = ckmalloc(BUFSIZ);
}
if (parsefile->fd > 0)
close(parsefile->fd);
parsefile->fd = fd;
if (parsefile->buf == NULL)
parsefile->buf = ckmalloc(BUFSIZ);
parselleft = parsenleft = 0;
plinno = 1;
}
 
 
/*
* Like setinputfile, but takes input from a string.
*/
 
void
setinputstring(string, push)
char *string;
int push;
{
INTOFF;
if (push)
pushfile();
parsenextc = string;
parselleft = parsenleft = strlen(string);
parsefile->buf = NULL;
plinno = 1;
INTON;
}
 
 
 
/*
* To handle the "." command, a stack of input files is used. Pushfile
* adds a new entry to the stack and popfile restores the previous level.
*/
 
STATIC void
pushfile() {
struct parsefile *pf;
 
parsefile->nleft = parsenleft;
parsefile->lleft = parselleft;
parsefile->nextc = parsenextc;
parsefile->linno = plinno;
pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
pf->prev = parsefile;
pf->fd = -1;
pf->strpush = NULL;
pf->basestrpush.prev = NULL;
parsefile = pf;
}
 
 
void
popfile() {
struct parsefile *pf = parsefile;
 
INTOFF;
if (pf->fd >= 0)
close(pf->fd);
if (pf->buf)
ckfree(pf->buf);
while (pf->strpush)
popstring();
parsefile = pf->prev;
ckfree(pf);
parsenleft = parsefile->nleft;
parselleft = parsefile->lleft;
parsenextc = parsefile->nextc;
plinno = parsefile->linno;
INTON;
}
 
 
/*
* Return to top level.
*/
 
void
popallfiles() {
while (parsefile != &basepf)
popfile();
}
 
 
 
/*
* Close the file(s) that the shell is reading commands from. Called
* after a fork is done.
*/
 
void
closescript() {
popallfiles();
if (parsefile->fd > 0) {
close(parsefile->fd);
parsefile->fd = 0;
}
}
/trunk/uspace/app/ash/input.h
0,0 → 1,66
/* $NetBSD: input.h,v 1.12 2000/05/22 10:18:47 elric 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)input.h 8.2 (Berkeley) 5/4/95
*/
 
/* PEOF (the end of file marker) is defined in syntax.h */
 
/*
* The input line number. Input.c just defines this variable, and saves
* and restores it when files are pushed and popped. The user of this
* package must set its value.
*/
extern int plinno;
extern int parsenleft; /* number of characters left in input buffer */
extern char *parsenextc; /* next character in input buffer */
extern int init_editline; /* 0 == not setup, 1 == OK, -1 == failed */
 
char *pfgets (char *, int);
int pgetc (void);
int preadbuffer (void);
void pungetc (void);
void pushstring (char *, int, void *);
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);
 
#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
/trunk/uspace/app/ash/redir.c
0,0 → 1,492
/* $NetBSD: redir.c,v 1.22 2000/05/22 10:18:47 elric 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
 
#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.22 2000/05/22 10:18:47 elric Exp $");
#endif
#endif /* not lint */
 
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/param.h> /* PIPE_BUF */
#include <signal.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
 
/*
* Code for dealing with input/output redirection.
*/
 
#include "shell.h"
#include "nodes.h"
#include "jobs.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 */
#ifndef PIPE_BUF
# define PIPESIZE 4096 /* amount of buffering in a pipe */
#else
# define PIPESIZE PIPE_BUF
#endif
 
 
MKINIT
struct redirtab {
struct redirtab *next;
short renamed[10];
};
 
 
MKINIT struct redirtab *redirlist;
 
/*
* We keep track of whether or not fd0 has been redirected. This is for
* background commands, where we want to redirect fd0 to /dev/null only
* if it hasn't already been redirected.
*/
int fd0_redirected = 0;
 
/*
* We also keep track of where fd2 goes.
*/
int fd2 = 2;
 
STATIC int openredirect (union node *);
STATIC void dupredirect (union node *, int, char[10 ]);
STATIC int openhere (union node *);
STATIC int noclobberopen (const char *);
 
 
/*
* Process a list of redirection commands. If the REDIR_PUSH flag is set,
* old file descriptors are stashed away so that the redirection can be
* undone by calling popredir. If the REDIR_BACKQ flag is set, then the
* standard output, and the standard error if it becomes a duplicate of
* stdout, is saved in memory.
*/
 
void
redirect(redir, flags)
union node *redir;
int flags;
{
union node *n;
struct redirtab *sv = NULL;
int i;
int fd;
int newfd;
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) {
sv = ckmalloc(sizeof (struct redirtab));
for (i = 0 ; i < 10 ; i++)
sv->renamed[i] = EMPTY;
sv->next = redirlist;
redirlist = sv;
}
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 */
 
INTOFF;
newfd = openredirect(n);
if (((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) ||
(fd == fd2)) {
if (newfd == fd) {
try++;
} else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
switch (errno) {
case EBADF:
if (!try) {
dupredirect(n, newfd, memory);
try++;
break;
}
/* FALLTHROUGH*/
default:
if (newfd >= 0) {
close(newfd);
}
INTON;
error("%d: %s", fd, strerror(errno));
/* NOTREACHED */
}
}
if (!try) {
close(fd);
if (flags & REDIR_PUSH) {
sv->renamed[fd] = i;
}
if (fd == fd2) {
fd2 = i;
}
}
} else if (fd != newfd) {
close(fd);
}
if (fd == 0)
fd0_redirected++;
if (!try)
dupredirect(n, newfd, memory);
INTON;
}
if (memory[1])
out1 = &memout;
if (memory[2])
out2 = &memout;
}
 
 
STATIC int
openredirect(redir)
union node *redir;
{
char *fname;
int f;
 
switch (redir->nfile.type) {
case NFROM:
fname = redir->nfile.expfname;
if ((f = open(fname, O_RDONLY)) < 0)
goto eopen;
break;
case NFROMTO:
fname = redir->nfile.expfname;
if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
goto ecreate;
break;
case NTO:
/* Take care of noclobber mode. */
if (Cflag) {
fname = redir->nfile.expfname;
if ((f = noclobberopen(fname)) < 0)
goto ecreate;
break;
}
case NTOOV:
fname = redir->nfile.expfname;
#ifdef O_CREAT
if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
goto ecreate;
#else
if ((f = creat(fname, 0666)) < 0)
goto ecreate;
#endif
break;
case NAPPEND:
fname = redir->nfile.expfname;
#ifdef O_APPEND
if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
goto ecreate;
#else
if ((f = open(fname, O_WRONLY)) < 0
&& (f = creat(fname, 0666)) < 0)
goto ecreate;
lseek(f, (off_t)0, 2);
#endif
break;
case NTOFD:
case NFROMFD:
f = -1;
break;
case NHERE:
case NXHERE:
f = openhere(redir);
break;
default:
abort();
}
 
return f;
ecreate:
error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
eopen:
error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
}
 
 
STATIC void
dupredirect(redir, f, memory)
union node *redir;
int f;
char memory[10];
{
int fd = redir->nfile.fd;
 
memory[fd] = 0;
if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
if (memory[redir->ndup.dupfd])
memory[fd] = 1;
else
copyfd(redir->ndup.dupfd, fd);
}
return;
}
 
if (f != fd) {
copyfd(f, fd);
close(f);
}
return;
}
 
 
/*
* Handle here documents. Normally we fork off a process to write the
* data to a pipe. If the document is short, we can stuff the data in
* the pipe without forking.
*/
 
STATIC int
openhere(redir)
union node *redir;
{
int pip[2];
int len = 0;
 
if (pipe(pip) < 0)
error("Pipe call failed");
if (redir->type == NHERE) {
len = strlen(redir->nhere.doc->narg.text);
if (len <= PIPESIZE) {
xwrite(pip[1], redir->nhere.doc->narg.text, len);
goto out;
}
}
if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
close(pip[0]);
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
signal(SIGHUP, SIG_IGN);
#ifdef SIGTSTP
signal(SIGTSTP, SIG_IGN);
#endif
signal(SIGPIPE, SIG_DFL);
if (redir->type == NHERE)
xwrite(pip[1], redir->nhere.doc->narg.text, len);
else
expandhere(redir->nhere.doc, pip[1]);
_exit(0);
}
out:
close(pip[1]);
return pip[0];
}
 
 
 
/*
* Undo the effects of the last redirection.
*/
 
void
popredir() {
struct redirtab *rp = redirlist;
int i;
 
INTOFF;
for (i = 0 ; i < 10 ; i++) {
if (rp->renamed[i] != EMPTY) {
if (i == 0)
fd0_redirected--;
close(i);
if (rp->renamed[i] >= 0) {
copyfd(rp->renamed[i], i);
close(rp->renamed[i]);
}
if (rp->renamed[i] == fd2) {
fd2 = i;
}
}
}
redirlist = rp->next;
ckfree(rp);
INTON;
}
 
/*
* Undo all redirections. Called on error or interrupt.
*/
 
#ifdef mkinit
 
INCLUDE "redir.h"
 
RESET {
while (redirlist)
popredir();
}
 
SHELLPROC {
clearredir();
}
 
#endif
 
/* Return true if fd 0 has already been redirected at least once. */
int
fd0_redirected_p () {
return fd0_redirected != 0;
}
 
/*
* Discard all saved file descriptors.
*/
 
void
clearredir() {
struct redirtab *rp;
int i;
 
for (rp = redirlist ; rp ; rp = rp->next) {
for (i = 0 ; i < 10 ; i++) {
if (rp->renamed[i] >= 0) {
close(rp->renamed[i]);
if (rp->renamed[i] == fd2) {
fd2 = -1;
}
}
rp->renamed[i] = EMPTY;
}
}
}
 
 
 
/*
* 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(from, to)
int from;
int to;
{
int newfd;
 
newfd = fcntl(from, F_DUPFD, to);
if (newfd < 0) {
if (errno == EMFILE)
return EMPTY;
else
error("%d: %s", from, strerror(errno));
}
return newfd;
}
 
/*
* Open a file in noclobber mode.
* The code was copied from bash.
*/
int
noclobberopen(fname)
const char *fname;
{
int r, fd;
struct stat finfo, finfo2;
 
/*
* If the file exists and is a regular file, return an error
* immediately.
*/
r = stat(fname, &finfo);
if (r == 0 && S_ISREG(finfo.st_mode)) {
errno = EEXIST;
return -1;
}
 
/*
* If the file was not present (r != 0), make sure we open it
* exclusively so that if it is created before we open it, our open
* will fail. Make sure that we do not truncate an existing file.
* Note that we don't turn on O_EXCL unless the stat failed -- if the
* file was not a regular file, we leave O_EXCL off.
*/
if (r != 0)
return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
fd = open(fname, O_WRONLY|O_CREAT, 0666);
 
/* If the open failed, return the file descriptor right away. */
if (fd < 0)
return fd;
 
/*
* OK, the open succeeded, but the file may have been changed from a
* non-regular file to a regular file between the stat and the open.
* We are assuming that the O_EXCL open handles the case where FILENAME
* did not exist and is symlinked to an existing file between the stat
* and open.
*/
 
/*
* If we can open it and fstat the file descriptor, and neither check
* revealed that it was a regular file, and the file has not been
* replaced, return the file descriptor.
*/
if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
return fd;
 
/* The file has been replaced. badness. */
close(fd);
errno = EEXIST;
return -1;
}
/trunk/uspace/app/ash/trap.c
0,0 → 1,401
/* $NetBSD: trap.c,v 1.24 2000/05/22 10:18:47 elric 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
 
#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.24 2000/05/22 10:18:47 elric 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 "syntax.h"
#include "output.h"
#include "memalloc.h"
#include "error.h"
#include "trap.h"
#include "mystring.h"
#include "mail.h"
 
#ifdef HETIO
#include "hetio.h"
#endif
 
/*
* 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 */
 
 
extern char nullstr[1]; /* null string */
 
char *trap[NSIG+1]; /* trap handler commands */
MKINIT char sigmode[NSIG]; /* current value of signal */
char gotsig[NSIG]; /* indicates specified signal received */
int pendingsigs; /* indicates some signal received */
 
extern char *signal_names[];
 
/*
* The trap builtin.
*/
 
int
trapcmd(argc, argv)
int argc;
char **argv;
{
char *action;
char **ap;
int signo;
 
if (argc <= 1) {
for (signo = 0 ; signo <= NSIG ; signo++) {
if (trap[signo] != NULL)
out1fmt("%d: %s\n", signo, trap[signo]);
}
return 0;
}
ap = argv + 1;
if (argc == 2)
action = NULL;
else
action = *ap++;
while (*ap) {
if ((signo = decode_signal(*ap)) < 0)
error("%s: bad trap", *ap);
INTOFF;
if (action) {
if (action[0] == '-' && action[1] == '\0')
action = NULL;
else
action = savestr(action);
}
if (trap[signo])
ckfree(trap[signo]);
trap[signo] = action;
if (signo != 0)
setsignal(signo);
INTON;
ap++;
}
return 0;
}
 
 
 
/*
* Clear traps on a fork.
*/
 
void
clear_traps() {
char **tp;
 
for (tp = trap ; tp <= &trap[NSIG] ; tp++) {
if (*tp && **tp) { /* trap not NULL or SIG_IGN */
INTOFF;
ckfree(*tp);
*tp = NULL;
if (tp != &trap[0])
setsignal(tp - trap);
INTON;
}
}
}
 
 
 
/*
* Set the signal handler for the specified signal. The routine figures
* out what it should be set to.
*/
 
void
setsignal(signo)
int signo;
{
int action;
char *t;
struct sigaction act;
 
if ((t = trap[signo]) == NULL)
action = S_DFL;
else if (*t != '\0')
action = S_CATCH;
else
action = S_IGN;
if (rootshell && action == S_DFL) {
switch (signo) {
case SIGINT:
if (iflag || minusc || sflag == 0)
action = S_CATCH;
break;
case SIGQUIT:
#ifdef DEBUG
{
extern int 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];
if (*t == 0) {
/*
* current setting unknown
*/
if (sigaction(signo, 0, &act) == -1) {
/*
* 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;
}
if (act.sa_handler == SIG_IGN) {
if (mflag && (signo == SIGTSTP ||
signo == SIGTTIN || signo == SIGTTOU)) {
*t = S_IGN; /* don't hard ignore these */
} else
*t = S_HARD_IGN;
} else {
*t = S_RESET; /* force to be set */
}
}
if (*t == S_HARD_IGN || *t == action)
return;
switch (action) {
case S_CATCH:
act.sa_handler = onsig;
break;
case S_IGN:
act.sa_handler = SIG_IGN;
break;
default:
act.sa_handler = SIG_DFL;
}
*t = action;
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
sigaction(signo, &act, 0);
}
 
/*
* Ignore a signal.
*/
 
void
ignoresig(signo)
int signo;
{
if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
signal(signo, SIG_IGN);
}
sigmode[signo - 1] = S_HARD_IGN;
}
 
 
#ifdef mkinit
INCLUDE <signal.h>
INCLUDE "trap.h"
 
SHELLPROC {
char *sm;
 
clear_traps();
for (sm = sigmode ; sm < sigmode + NSIG ; sm++) {
if (*sm == S_IGN)
*sm = S_HARD_IGN;
}
}
#endif
 
 
 
/*
* Signal handler.
*/
 
void
onsig(signo)
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() {
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(on)
int on;
{
static int is_interactive;
 
if (on == is_interactive)
return;
setsignal(SIGINT);
setsignal(SIGQUIT);
setsignal(SIGTERM);
chkmail(1);
is_interactive = on;
}
 
 
 
/*
* Called to exit the shell.
*/
 
void
exitshell(status)
int status;
{
struct jmploc loc1, loc2;
char *p;
 
TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
#ifdef HETIO
hetio_reset_term();
#endif
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 */
}
 
int decode_signal(const char *string)
{
int signo;
 
if (is_number(string)) return atoi(string);
 
for (signo=0; signo < NSIG; signo++)
if (strcasecmp(string, signal_names[signo]) == 0 ||
strcasecmp(string, &(signal_names[signo])[3]) == 0)
return signo;
 
return -1;
}
/trunk/uspace/app/ash/arith.c
0,0 → 1,1907
/* A Bison parser, made by GNU Bison 2.3. */
 
/* Skeleton implementation for Bison's Yacc-like parsers in C
 
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
 
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA. */
 
/* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work
under terms of your choice, so long as that work isn't itself a
parser generator using the skeleton or a modified version thereof
as a parser skeleton. Alternatively, if you modify or redistribute
the parser skeleton itself, you may (at your option) remove this
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
 
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
 
/* C LALR(1) parser skeleton written by Richard Stallman, by
simplifying the original so-called "semantic" parser. */
 
/* All symbols defined below should begin with yy or YY, to avoid
infringing on user name space. This should be done even for local
variables, as they might otherwise be expanded by user macros.
There are some unavoidable exceptions within include files to
define necessary library symbols; they are noted "INFRINGES ON
USER NAME SPACE" below. */
 
/* Identify Bison output. */
#define YYBISON 1
 
/* Bison version. */
#define YYBISON_VERSION "2.3"
 
/* Skeleton name. */
#define YYSKELETON_NAME "yacc.c"
 
/* Pure parsers. */
#define YYPURE 0
 
/* Using locations. */
#define YYLSP_NEEDED 0
 
 
 
/* Tokens. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
/* Put the tokens into the symbol table, so that GDB and other debuggers
know about them. */
enum yytokentype {
ARITH_NUM = 258,
ARITH_LPAREN = 259,
ARITH_RPAREN = 260,
ARITH_OR = 261,
ARITH_AND = 262,
ARITH_BOR = 263,
ARITH_BXOR = 264,
ARITH_BAND = 265,
ARITH_NE = 266,
ARITH_EQ = 267,
ARITH_LE = 268,
ARITH_GE = 269,
ARITH_GT = 270,
ARITH_LT = 271,
ARITH_RSHIFT = 272,
ARITH_LSHIFT = 273,
ARITH_SUB = 274,
ARITH_ADD = 275,
ARITH_REM = 276,
ARITH_DIV = 277,
ARITH_MUL = 278,
ARITH_BNOT = 279,
ARITH_NOT = 280,
ARITH_UNARYPLUS = 281,
ARITH_UNARYMINUS = 282
};
#endif
/* Tokens. */
#define ARITH_NUM 258
#define ARITH_LPAREN 259
#define ARITH_RPAREN 260
#define ARITH_OR 261
#define ARITH_AND 262
#define ARITH_BOR 263
#define ARITH_BXOR 264
#define ARITH_BAND 265
#define ARITH_NE 266
#define ARITH_EQ 267
#define ARITH_LE 268
#define ARITH_GE 269
#define ARITH_GT 270
#define ARITH_LT 271
#define ARITH_RSHIFT 272
#define ARITH_LSHIFT 273
#define ARITH_SUB 274
#define ARITH_ADD 275
#define ARITH_REM 276
#define ARITH_DIV 277
#define ARITH_MUL 278
#define ARITH_BNOT 279
#define ARITH_NOT 280
#define ARITH_UNARYPLUS 281
#define ARITH_UNARYMINUS 282
 
 
 
 
/* Copy the first part of user declarations. */
#line 1 "arith.y"
 
/* $NetBSD: arith.y,v 1.13 1999/07/09 03:05:49 christos 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
 
#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.13 1999/07/09 03:05:49 christos Exp $");
#endif
#endif /* not lint */
 
#include <stdlib.h>
#include "expand.h"
#include "shell.h"
#include "error.h"
#include "output.h"
#include "memalloc.h"
 
const char *arith_buf, *arith_startbuf;
 
void yyerror (const char *);
int yyparse (void);
#ifdef TESTARITH
int main (int , char *[]);
int error (char *);
#endif
 
int
arith(s)
const char *s;
{
long result;
 
arith_buf = arith_startbuf = s;
 
INTOFF;
result = yyparse();
arith_lex_reset(); /* reprime lex */
INTON;
 
return (result);
}
 
 
/*
* The exp(1) builtin.
*/
int
expcmd(argc, argv)
int argc;
char **argv;
{
const 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(argc, argv)
char *argv[];
{
printf("%d\n", exp(argv[1]));
}
error(s)
char *s;
{
fprintf(stderr, "exp: %s\n", s);
exit(1);
}
#endif
 
 
/* Enabling traces. */
#ifndef YYDEBUG
# define YYDEBUG 0
#endif
 
/* Enabling verbose error messages. */
#ifdef YYERROR_VERBOSE
# undef YYERROR_VERBOSE
# define YYERROR_VERBOSE 1
#else
# define YYERROR_VERBOSE 0
#endif
 
/* Enabling the token table. */
#ifndef YYTOKEN_TABLE
# define YYTOKEN_TABLE 0
#endif
 
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef int YYSTYPE;
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
# define YYSTYPE_IS_TRIVIAL 1
#endif
 
 
 
/* Copy the second part of user declarations. */
 
 
/* Line 216 of yacc.c. */
#line 298 "y.tab.c"
 
#ifdef short
# undef short
#endif
 
#ifdef YYTYPE_UINT8
typedef YYTYPE_UINT8 yytype_uint8;
#else
typedef unsigned char yytype_uint8;
#endif
 
#ifdef YYTYPE_INT8
typedef YYTYPE_INT8 yytype_int8;
#elif (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
typedef signed char yytype_int8;
#else
typedef short int yytype_int8;
#endif
 
#ifdef YYTYPE_UINT16
typedef YYTYPE_UINT16 yytype_uint16;
#else
typedef unsigned short int yytype_uint16;
#endif
 
#ifdef YYTYPE_INT16
typedef YYTYPE_INT16 yytype_int16;
#else
typedef short int yytype_int16;
#endif
 
#ifndef YYSIZE_T
# ifdef __SIZE_TYPE__
# define YYSIZE_T __SIZE_TYPE__
# elif defined size_t
# define YYSIZE_T size_t
# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
# define YYSIZE_T size_t
# else
# define YYSIZE_T unsigned int
# endif
#endif
 
#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
 
#ifndef YY_
# if YYENABLE_NLS
# if ENABLE_NLS
# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
# define YY_(msgid) dgettext ("bison-runtime", msgid)
# endif
# endif
# ifndef YY_
# define YY_(msgid) msgid
# endif
#endif
 
/* Suppress unused-variable warnings by "using" E. */
#if ! defined lint || defined __GNUC__
# define YYUSE(e) ((void) (e))
#else
# define YYUSE(e) /* empty */
#endif
 
/* Identity function, used to suppress warnings about constant conditions. */
#ifndef lint
# define YYID(n) (n)
#else
#if (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
static int
YYID (int i)
#else
static int
YYID (i)
int i;
#endif
{
return i;
}
#endif
 
#if ! defined yyoverflow || YYERROR_VERBOSE
 
/* The parser invokes alloca or malloc; define the necessary symbols. */
 
# ifdef YYSTACK_USE_ALLOCA
# if YYSTACK_USE_ALLOCA
# ifdef __GNUC__
# define YYSTACK_ALLOC __builtin_alloca
# elif defined __BUILTIN_VA_ARG_INCR
# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
# elif defined _AIX
# define YYSTACK_ALLOC __alloca
# elif defined _MSC_VER
# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
# define alloca _alloca
# else
# define YYSTACK_ALLOC alloca
# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
# ifndef _STDLIB_H
# define _STDLIB_H 1
# endif
# endif
# endif
# endif
# endif
 
# ifdef YYSTACK_ALLOC
/* Pacify GCC's `empty if-body' warning. */
# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
# ifndef YYSTACK_ALLOC_MAXIMUM
/* The OS might guarantee only one guard page at the bottom of the stack,
and a page size can be as small as 4096 bytes. So we cannot safely
invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
to allow for a few compiler-allocated temporary stack slots. */
# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
# endif
# else
# define YYSTACK_ALLOC YYMALLOC
# define YYSTACK_FREE YYFREE
# ifndef YYSTACK_ALLOC_MAXIMUM
# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
# endif
# if (defined __cplusplus && ! defined _STDLIB_H \
&& ! ((defined YYMALLOC || defined malloc) \
&& (defined YYFREE || defined free)))
# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
# ifndef _STDLIB_H
# define _STDLIB_H 1
# endif
# endif
# ifndef YYMALLOC
# define YYMALLOC malloc
# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
# endif
# endif
# ifndef YYFREE
# define YYFREE free
# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
void free (void *); /* INFRINGES ON USER NAME SPACE */
# endif
# endif
# endif
#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
 
 
#if (! defined yyoverflow \
&& (! defined __cplusplus \
|| (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
 
/* A type that is properly aligned for any stack member. */
union yyalloc
{
yytype_int16 yyss;
YYSTYPE yyvs;
};
 
/* The size of the maximum gap between one aligned stack and the next. */
# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
 
/* The size of an array large to enough to hold all stacks, each with
N elements. */
# define YYSTACK_BYTES(N) \
((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ YYSTACK_GAP_MAXIMUM)
 
/* Copy COUNT objects from FROM to TO. The source and destination do
not overlap. */
# ifndef YYCOPY
# if defined __GNUC__ && 1 < __GNUC__
# define YYCOPY(To, From, Count) \
__builtin_memcpy (To, From, (Count) * sizeof (*(From)))
# else
# define YYCOPY(To, From, Count) \
do \
{ \
YYSIZE_T yyi; \
for (yyi = 0; yyi < (Count); yyi++) \
(To)[yyi] = (From)[yyi]; \
} \
while (YYID (0))
# endif
# endif
 
/* Relocate STACK from its old location to the new one. The
local variables YYSIZE and YYSTACKSIZE give the old and new number of
elements in the stack, and YYPTR gives the new location of the
stack. Advance YYPTR to a properly aligned location for the next
stack. */
# define YYSTACK_RELOCATE(Stack) \
do \
{ \
YYSIZE_T yynewbytes; \
YYCOPY (&yyptr->Stack, Stack, yysize); \
Stack = &yyptr->Stack; \
yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
yyptr += yynewbytes / sizeof (*yyptr); \
} \
while (YYID (0))
 
#endif
 
/* YYFINAL -- State number of the termination state. */
#define YYFINAL 14
/* YYLAST -- Last index in YYTABLE. */
#define YYLAST 170
 
/* YYNTOKENS -- Number of terminals. */
#define YYNTOKENS 28
/* YYNNTS -- Number of nonterminals. */
#define YYNNTS 3
/* YYNRULES -- Number of rules. */
#define YYNRULES 26
/* YYNRULES -- Number of states. */
#define YYNSTATES 52
 
/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
#define YYUNDEFTOK 2
#define YYMAXUTOK 282
 
#define YYTRANSLATE(YYX) \
((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
 
/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
static const yytype_uint8 yytranslate[] =
{
0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27
};
 
#if YYDEBUG
/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
YYRHS. */
static const yytype_uint8 yyprhs[] =
{
0, 0, 3, 5, 9, 13, 17, 21, 25, 29,
33, 37, 41, 45, 49, 53, 57, 61, 65, 69,
73, 77, 81, 84, 87, 90, 93
};
 
/* YYRHS -- A `-1'-separated list of the rules' RHS. */
static const yytype_int8 yyrhs[] =
{
29, 0, -1, 30, -1, 4, 30, 5, -1, 30,
6, 30, -1, 30, 7, 30, -1, 30, 8, 30,
-1, 30, 9, 30, -1, 30, 10, 30, -1, 30,
12, 30, -1, 30, 15, 30, -1, 30, 14, 30,
-1, 30, 16, 30, -1, 30, 13, 30, -1, 30,
11, 30, -1, 30, 18, 30, -1, 30, 17, 30,
-1, 30, 20, 30, -1, 30, 19, 30, -1, 30,
23, 30, -1, 30, 22, 30, -1, 30, 21, 30,
-1, 25, 30, -1, 24, 30, -1, 19, 30, -1,
20, 30, -1, 3, -1
};
 
/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
static const yytype_uint8 yyrline[] =
{
0, 153, 153, 159, 160, 161, 162, 163, 164, 165,
166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
176, 181, 186, 187, 188, 189, 190
};
#endif
 
#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
First, the terminals, then, starting at YYNTOKENS, nonterminals. */
static const char *const yytname[] =
{
"$end", "error", "$undefined", "ARITH_NUM", "ARITH_LPAREN",
"ARITH_RPAREN", "ARITH_OR", "ARITH_AND", "ARITH_BOR", "ARITH_BXOR",
"ARITH_BAND", "ARITH_NE", "ARITH_EQ", "ARITH_LE", "ARITH_GE", "ARITH_GT",
"ARITH_LT", "ARITH_RSHIFT", "ARITH_LSHIFT", "ARITH_SUB", "ARITH_ADD",
"ARITH_REM", "ARITH_DIV", "ARITH_MUL", "ARITH_BNOT", "ARITH_NOT",
"ARITH_UNARYPLUS", "ARITH_UNARYMINUS", "$accept", "exp", "expr", 0
};
#endif
 
# ifdef YYPRINT
/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
token YYLEX-NUM. */
static const yytype_uint16 yytoknum[] =
{
0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
275, 276, 277, 278, 279, 280, 281, 282
};
# endif
 
/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
static const yytype_uint8 yyr1[] =
{
0, 28, 29, 30, 30, 30, 30, 30, 30, 30,
30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30, 30, 30, 30, 30, 30, 30
};
 
/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
static const yytype_uint8 yyr2[] =
{
0, 2, 1, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 2, 2, 2, 2, 1
};
 
/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
STATE-NUM when YYTABLE doesn't specify something else to do. Zero
means the default is an error. */
static const yytype_uint8 yydefact[] =
{
0, 26, 0, 0, 0, 0, 0, 0, 2, 0,
24, 25, 23, 22, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 3, 4, 5, 6, 7, 8, 14,
9, 13, 11, 10, 12, 16, 15, 18, 17, 21,
20, 19
};
 
/* YYDEFGOTO[NTERM-NUM]. */
static const yytype_int8 yydefgoto[] =
{
-1, 7, 8
};
 
/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
STATE-NUM. */
#define YYPACT_NINF -13
static const yytype_int16 yypact[] =
{
28, -13, 28, 28, 28, 28, 28, 12, 67, 49,
-13, -13, -13, -13, -13, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, -13, 84, 100, 115, 23, 128, 139,
139, -12, -12, -12, -12, 144, 144, 147, 147, -13,
-13, -13
};
 
/* YYPGOTO[NTERM-NUM]. */
static const yytype_int8 yypgoto[] =
{
-13, -13, -2
};
 
/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
positive, shift that token. If negative, reduce the rule which
number is the opposite. If zero, do what YYDEFACT says.
If YYTABLE_NINF, syntax error. */
#define YYTABLE_NINF -1
static const yytype_uint8 yytable[] =
{
9, 10, 11, 12, 13, 26, 27, 28, 29, 30,
31, 32, 14, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
51, 1, 2, 19, 20, 21, 22, 23, 24, 25,
26, 27, 28, 29, 30, 31, 32, 3, 4, 0,
0, 0, 5, 6, 33, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
30, 31, 32, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31, 32, 17, 18,
19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
29, 30, 31, 32, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31, 32, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
31, 32, 22, 23, 24, 25, 26, 27, 28, 29,
30, 31, 32, 28, 29, 30, 31, 32, 30, 31,
32
};
 
static const yytype_int8 yycheck[] =
{
2, 3, 4, 5, 6, 17, 18, 19, 20, 21,
22, 23, 0, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 3, 4, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 19, 20, -1,
-1, -1, 24, 25, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 11,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 19, 20, 21, 22, 23, 21, 22,
23
};
 
/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
symbol of state STATE-NUM. */
static const yytype_uint8 yystos[] =
{
0, 3, 4, 19, 20, 24, 25, 29, 30, 30,
30, 30, 30, 30, 0, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 5, 30, 30, 30, 30, 30, 30,
30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30, 30
};
 
#define yyerrok (yyerrstatus = 0)
#define yyclearin (yychar = YYEMPTY)
#define YYEMPTY (-2)
#define YYEOF 0
 
#define YYACCEPT goto yyacceptlab
#define YYABORT goto yyabortlab
#define YYERROR goto yyerrorlab
 
 
/* Like YYERROR except do call yyerror. This remains here temporarily
to ease the transition to the new meaning of YYERROR, for GCC.
Once GCC version 2 has supplanted version 1, this can go. */
 
#define YYFAIL goto yyerrlab
 
#define YYRECOVERING() (!!yyerrstatus)
 
#define YYBACKUP(Token, Value) \
do \
if (yychar == YYEMPTY && yylen == 1) \
{ \
yychar = (Token); \
yylval = (Value); \
yytoken = YYTRANSLATE (yychar); \
YYPOPSTACK (1); \
goto yybackup; \
} \
else \
{ \
yyerror (YY_("syntax error: cannot back up")); \
YYERROR; \
} \
while (YYID (0))
 
 
#define YYTERROR 1
#define YYERRCODE 256
 
 
/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
If N is 0, then set CURRENT to the empty location which ends
the previous symbol: RHS[0] (always defined). */
 
#define YYRHSLOC(Rhs, K) ((Rhs)[K])
#ifndef YYLLOC_DEFAULT
# define YYLLOC_DEFAULT(Current, Rhs, N) \
do \
if (YYID (N)) \
{ \
(Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
(Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
(Current).last_line = YYRHSLOC (Rhs, N).last_line; \
(Current).last_column = YYRHSLOC (Rhs, N).last_column; \
} \
else \
{ \
(Current).first_line = (Current).last_line = \
YYRHSLOC (Rhs, 0).last_line; \
(Current).first_column = (Current).last_column = \
YYRHSLOC (Rhs, 0).last_column; \
} \
while (YYID (0))
#endif
 
 
/* YY_LOCATION_PRINT -- Print the location on the stream.
This macro was not mandated originally: define only if we know
we won't break user code: when these are the locations we know. */
 
#ifndef YY_LOCATION_PRINT
# if YYLTYPE_IS_TRIVIAL
# define YY_LOCATION_PRINT(File, Loc) \
fprintf (File, "%d.%d-%d.%d", \
(Loc).first_line, (Loc).first_column, \
(Loc).last_line, (Loc).last_column)
# else
# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
# endif
#endif
 
 
/* YYLEX -- calling `yylex' with the right arguments. */
 
#ifdef YYLEX_PARAM
# define YYLEX yylex (YYLEX_PARAM)
#else
# define YYLEX yylex ()
#endif
 
/* Enable debugging if requested. */
#if YYDEBUG
 
# ifndef YYFPRINTF
# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
# define YYFPRINTF fprintf
# endif
 
# define YYDPRINTF(Args) \
do { \
if (yydebug) \
YYFPRINTF Args; \
} while (YYID (0))
 
# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
do { \
if (yydebug) \
{ \
YYFPRINTF (stderr, "%s ", Title); \
yy_symbol_print (stderr, \
Type, Value); \
YYFPRINTF (stderr, "\n"); \
} \
} while (YYID (0))
 
 
/*--------------------------------.
| Print this symbol on YYOUTPUT. |
`--------------------------------*/
 
/*ARGSUSED*/
#if (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
static void
yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
#else
static void
yy_symbol_value_print (yyoutput, yytype, yyvaluep)
FILE *yyoutput;
int yytype;
YYSTYPE const * const yyvaluep;
#endif
{
if (!yyvaluep)
return;
# ifdef YYPRINT
if (yytype < YYNTOKENS)
YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
# else
YYUSE (yyoutput);
# endif
switch (yytype)
{
default:
break;
}
}
 
 
/*--------------------------------.
| Print this symbol on YYOUTPUT. |
`--------------------------------*/
 
#if (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
static void
yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
#else
static void
yy_symbol_print (yyoutput, yytype, yyvaluep)
FILE *yyoutput;
int yytype;
YYSTYPE const * const yyvaluep;
#endif
{
if (yytype < YYNTOKENS)
YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
else
YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
 
yy_symbol_value_print (yyoutput, yytype, yyvaluep);
YYFPRINTF (yyoutput, ")");
}
 
/*------------------------------------------------------------------.
| yy_stack_print -- Print the state stack from its BOTTOM up to its |
| TOP (included). |
`------------------------------------------------------------------*/
 
#if (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
static void
yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
#else
static void
yy_stack_print (bottom, top)
yytype_int16 *bottom;
yytype_int16 *top;
#endif
{
YYFPRINTF (stderr, "Stack now");
for (; bottom <= top; ++bottom)
YYFPRINTF (stderr, " %d", *bottom);
YYFPRINTF (stderr, "\n");
}
 
# define YY_STACK_PRINT(Bottom, Top) \
do { \
if (yydebug) \
yy_stack_print ((Bottom), (Top)); \
} while (YYID (0))
 
 
/*------------------------------------------------.
| Report that the YYRULE is going to be reduced. |
`------------------------------------------------*/
 
#if (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
static void
yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
#else
static void
yy_reduce_print (yyvsp, yyrule)
YYSTYPE *yyvsp;
int yyrule;
#endif
{
int yynrhs = yyr2[yyrule];
int yyi;
unsigned long int yylno = yyrline[yyrule];
YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
yyrule - 1, yylno);
/* The symbols being reduced. */
for (yyi = 0; yyi < yynrhs; yyi++)
{
fprintf (stderr, " $%d = ", yyi + 1);
yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
&(yyvsp[(yyi + 1) - (yynrhs)])
);
fprintf (stderr, "\n");
}
}
 
# define YY_REDUCE_PRINT(Rule) \
do { \
if (yydebug) \
yy_reduce_print (yyvsp, Rule); \
} while (YYID (0))
 
/* Nonzero means print parse trace. It is left uninitialized so that
multiple parsers can coexist. */
int yydebug;
#else /* !YYDEBUG */
# define YYDPRINTF(Args)
# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
# define YY_STACK_PRINT(Bottom, Top)
# define YY_REDUCE_PRINT(Rule)
#endif /* !YYDEBUG */
 
 
/* YYINITDEPTH -- initial size of the parser's stacks. */
#ifndef YYINITDEPTH
# define YYINITDEPTH 200
#endif
 
/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
if the built-in stack extension method is used).
 
Do not make this value too large; the results are undefined if
YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
evaluated with infinite-precision integer arithmetic. */
 
#ifndef YYMAXDEPTH
# define YYMAXDEPTH 10000
#endif
 
 
#if YYERROR_VERBOSE
 
# ifndef yystrlen
# if defined __GLIBC__ && defined _STRING_H
# define yystrlen strlen
# else
/* Return the length of YYSTR. */
#if (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
static YYSIZE_T
yystrlen (const char *yystr)
#else
static YYSIZE_T
yystrlen (yystr)
const char *yystr;
#endif
{
YYSIZE_T yylen;
for (yylen = 0; yystr[yylen]; yylen++)
continue;
return yylen;
}
# endif
# endif
 
# ifndef yystpcpy
# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
# define yystpcpy stpcpy
# else
/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
YYDEST. */
#if (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
static char *
yystpcpy (char *yydest, const char *yysrc)
#else
static char *
yystpcpy (yydest, yysrc)
char *yydest;
const char *yysrc;
#endif
{
char *yyd = yydest;
const char *yys = yysrc;
 
while ((*yyd++ = *yys++) != '\0')
continue;
 
return yyd - 1;
}
# endif
# endif
 
# ifndef yytnamerr
/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
quotes and backslashes, so that it's suitable for yyerror. The
heuristic is that double-quoting is unnecessary unless the string
contains an apostrophe, a comma, or backslash (other than
backslash-backslash). YYSTR is taken from yytname. If YYRES is
null, do not copy; instead, return the length of what the result
would have been. */
static YYSIZE_T
yytnamerr (char *yyres, const char *yystr)
{
if (*yystr == '"')
{
YYSIZE_T yyn = 0;
char const *yyp = yystr;
 
for (;;)
switch (*++yyp)
{
case '\'':
case ',':
goto do_not_strip_quotes;
 
case '\\':
if (*++yyp != '\\')
goto do_not_strip_quotes;
/* Fall through. */
default:
if (yyres)
yyres[yyn] = *yyp;
yyn++;
break;
 
case '"':
if (yyres)
yyres[yyn] = '\0';
return yyn;
}
do_not_strip_quotes: ;
}
 
if (! yyres)
return yystrlen (yystr);
 
return yystpcpy (yyres, yystr) - yyres;
}
# endif
 
/* Copy into YYRESULT an error message about the unexpected token
YYCHAR while in state YYSTATE. Return the number of bytes copied,
including the terminating null byte. If YYRESULT is null, do not
copy anything; just return the number of bytes that would be
copied. As a special case, return 0 if an ordinary "syntax error"
message will do. Return YYSIZE_MAXIMUM if overflow occurs during
size calculation. */
static YYSIZE_T
yysyntax_error (char *yyresult, int yystate, int yychar)
{
int yyn = yypact[yystate];
 
if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
return 0;
else
{
int yytype = YYTRANSLATE (yychar);
YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
YYSIZE_T yysize = yysize0;
YYSIZE_T yysize1;
int yysize_overflow = 0;
enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
int yyx;
 
# if 0
/* This is so xgettext sees the translatable formats that are
constructed on the fly. */
YY_("syntax error, unexpected %s");
YY_("syntax error, unexpected %s, expecting %s");
YY_("syntax error, unexpected %s, expecting %s or %s");
YY_("syntax error, unexpected %s, expecting %s or %s or %s");
YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
# endif
char *yyfmt;
char const *yyf;
static char const yyunexpected[] = "syntax error, unexpected %s";
static char const yyexpecting[] = ", expecting %s";
static char const yyor[] = " or %s";
char yyformat[sizeof yyunexpected
+ sizeof yyexpecting - 1
+ ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
* (sizeof yyor - 1))];
char const *yyprefix = yyexpecting;
 
/* Start YYX at -YYN if negative to avoid negative indexes in
YYCHECK. */
int yyxbegin = yyn < 0 ? -yyn : 0;
 
/* Stay within bounds of both yycheck and yytname. */
int yychecklim = YYLAST - yyn + 1;
int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
int yycount = 1;
 
yyarg[0] = yytname[yytype];
yyfmt = yystpcpy (yyformat, yyunexpected);
 
for (yyx = yyxbegin; yyx < yyxend; ++yyx)
if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
{
if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
{
yycount = 1;
yysize = yysize0;
yyformat[sizeof yyunexpected - 1] = '\0';
break;
}
yyarg[yycount++] = yytname[yyx];
yysize1 = yysize + yytnamerr (0, yytname[yyx]);
yysize_overflow |= (yysize1 < yysize);
yysize = yysize1;
yyfmt = yystpcpy (yyfmt, yyprefix);
yyprefix = yyor;
}
 
yyf = YY_(yyformat);
yysize1 = yysize + yystrlen (yyf);
yysize_overflow |= (yysize1 < yysize);
yysize = yysize1;
 
if (yysize_overflow)
return YYSIZE_MAXIMUM;
 
if (yyresult)
{
/* Avoid sprintf, as that infringes on the user's name space.
Don't have undefined behavior even if the translation
produced a string with the wrong number of "%s"s. */
char *yyp = yyresult;
int yyi = 0;
while ((*yyp = *yyf) != '\0')
{
if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
{
yyp += yytnamerr (yyp, yyarg[yyi++]);
yyf += 2;
}
else
{
yyp++;
yyf++;
}
}
}
return yysize;
}
}
#endif /* YYERROR_VERBOSE */
 
/*-----------------------------------------------.
| Release the memory associated to this symbol. |
`-----------------------------------------------*/
 
/*ARGSUSED*/
#if (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
static void
yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
#else
static void
yydestruct (yymsg, yytype, yyvaluep)
const char *yymsg;
int yytype;
YYSTYPE *yyvaluep;
#endif
{
YYUSE (yyvaluep);
 
if (!yymsg)
yymsg = "Deleting";
YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
 
switch (yytype)
{
 
default:
break;
}
}
 
/* Prevent warnings from -Wmissing-prototypes. */
 
#ifdef YYPARSE_PARAM
#if defined __STDC__ || defined __cplusplus
int yyparse (void *YYPARSE_PARAM);
#else
int yyparse ();
#endif
#else /* ! YYPARSE_PARAM */
#if defined __STDC__ || defined __cplusplus
int yyparse (void);
#else
int yyparse ();
#endif
#endif /* ! YYPARSE_PARAM */
 
 
 
/* The look-ahead symbol. */
int yychar;
 
/* The semantic value of the look-ahead symbol. */
YYSTYPE yylval;
 
/* Number of syntax errors so far. */
int yynerrs;
 
 
 
/*----------.
| yyparse. |
`----------*/
 
#ifdef YYPARSE_PARAM
#if (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
int
yyparse (void *YYPARSE_PARAM)
#else
int
yyparse (YYPARSE_PARAM)
void *YYPARSE_PARAM;
#endif
#else /* ! YYPARSE_PARAM */
#if (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
int
yyparse (void)
#else
int
yyparse ()
 
#endif
#endif
{
int yystate;
int yyn;
int yyresult;
/* Number of tokens to shift before error messages enabled. */
int yyerrstatus;
/* Look-ahead token as an internal (translated) token number. */
int yytoken = 0;
#if YYERROR_VERBOSE
/* Buffer for error messages, and its allocated size. */
char yymsgbuf[128];
char *yymsg = yymsgbuf;
YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
#endif
 
/* Three stacks and their tools:
`yyss': related to states,
`yyvs': related to semantic values,
`yyls': related to locations.
 
Refer to the stacks thru separate pointers, to allow yyoverflow
to reallocate them elsewhere. */
 
/* The state stack. */
yytype_int16 yyssa[YYINITDEPTH];
yytype_int16 *yyss = yyssa;
yytype_int16 *yyssp;
 
/* The semantic value stack. */
YYSTYPE yyvsa[YYINITDEPTH];
YYSTYPE *yyvs = yyvsa;
YYSTYPE *yyvsp;
 
 
 
#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
 
YYSIZE_T yystacksize = YYINITDEPTH;
 
/* The variables used to return semantic value and location from the
action routines. */
YYSTYPE yyval;
 
 
/* The number of symbols on the RHS of the reduced rule.
Keep to zero when no symbol should be popped. */
int yylen = 0;
 
YYDPRINTF ((stderr, "Starting parse\n"));
 
yystate = 0;
yyerrstatus = 0;
yynerrs = 0;
yychar = YYEMPTY; /* Cause a token to be read. */
 
/* Initialize stack pointers.
Waste one element of value and location stack
so that they stay on the same level as the state stack.
The wasted elements are never initialized. */
 
yyssp = yyss;
yyvsp = yyvs;
 
goto yysetstate;
 
/*------------------------------------------------------------.
| yynewstate -- Push a new state, which is found in yystate. |
`------------------------------------------------------------*/
yynewstate:
/* In all cases, when you get here, the value and location stacks
have just been pushed. So pushing a state here evens the stacks. */
yyssp++;
 
yysetstate:
*yyssp = yystate;
 
if (yyss + yystacksize - 1 <= yyssp)
{
/* Get the current used size of the three stacks, in elements. */
YYSIZE_T yysize = yyssp - yyss + 1;
 
#ifdef yyoverflow
{
/* Give user a chance to reallocate the stack. Use copies of
these so that the &'s don't force the real ones into
memory. */
YYSTYPE *yyvs1 = yyvs;
yytype_int16 *yyss1 = yyss;
 
 
/* Each stack pointer address is followed by the size of the
data in use in that stack, in bytes. This used to be a
conditional around just the two extra args, but that might
be undefined if yyoverflow is a macro. */
yyoverflow (YY_("memory exhausted"),
&yyss1, yysize * sizeof (*yyssp),
&yyvs1, yysize * sizeof (*yyvsp),
 
&yystacksize);
 
yyss = yyss1;
yyvs = yyvs1;
}
#else /* no yyoverflow */
# ifndef YYSTACK_RELOCATE
goto yyexhaustedlab;
# else
/* Extend the stack our own way. */
if (YYMAXDEPTH <= yystacksize)
goto yyexhaustedlab;
yystacksize *= 2;
if (YYMAXDEPTH < yystacksize)
yystacksize = YYMAXDEPTH;
 
{
yytype_int16 *yyss1 = yyss;
union yyalloc *yyptr =
(union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
if (! yyptr)
goto yyexhaustedlab;
YYSTACK_RELOCATE (yyss);
YYSTACK_RELOCATE (yyvs);
 
# undef YYSTACK_RELOCATE
if (yyss1 != yyssa)
YYSTACK_FREE (yyss1);
}
# endif
#endif /* no yyoverflow */
 
yyssp = yyss + yysize - 1;
yyvsp = yyvs + yysize - 1;
 
 
YYDPRINTF ((stderr, "Stack size increased to %lu\n",
(unsigned long int) yystacksize));
 
if (yyss + yystacksize - 1 <= yyssp)
YYABORT;
}
 
YYDPRINTF ((stderr, "Entering state %d\n", yystate));
 
goto yybackup;
 
/*-----------.
| yybackup. |
`-----------*/
yybackup:
 
/* Do appropriate processing given the current state. Read a
look-ahead token if we need one and don't already have one. */
 
/* First try to decide what to do without reference to look-ahead token. */
yyn = yypact[yystate];
if (yyn == YYPACT_NINF)
goto yydefault;
 
/* Not known => get a look-ahead token if don't already have one. */
 
/* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */
if (yychar == YYEMPTY)
{
YYDPRINTF ((stderr, "Reading a token: "));
yychar = YYLEX;
}
 
if (yychar <= YYEOF)
{
yychar = yytoken = YYEOF;
YYDPRINTF ((stderr, "Now at end of input.\n"));
}
else
{
yytoken = YYTRANSLATE (yychar);
YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
}
 
/* If the proper action on seeing token YYTOKEN is to reduce or to
detect an error, take that action. */
yyn += yytoken;
if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
goto yydefault;
yyn = yytable[yyn];
if (yyn <= 0)
{
if (yyn == 0 || yyn == YYTABLE_NINF)
goto yyerrlab;
yyn = -yyn;
goto yyreduce;
}
 
if (yyn == YYFINAL)
YYACCEPT;
 
/* Count tokens shifted since error; after three, turn off error
status. */
if (yyerrstatus)
yyerrstatus--;
 
/* Shift the look-ahead token. */
YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
 
/* Discard the shifted token unless it is eof. */
if (yychar != YYEOF)
yychar = YYEMPTY;
 
yystate = yyn;
*++yyvsp = yylval;
 
goto yynewstate;
 
 
/*-----------------------------------------------------------.
| yydefault -- do the default action for the current state. |
`-----------------------------------------------------------*/
yydefault:
yyn = yydefact[yystate];
if (yyn == 0)
goto yyerrlab;
goto yyreduce;
 
 
/*-----------------------------.
| yyreduce -- Do a reduction. |
`-----------------------------*/
yyreduce:
/* yyn is the number of a rule to reduce with. */
yylen = yyr2[yyn];
 
/* If YYLEN is nonzero, implement the default value of the action:
`$$ = $1'.
 
Otherwise, the following line sets YYVAL to garbage.
This behavior is undocumented and Bison
users should not rely upon it. Assigning to YYVAL
unconditionally makes the parser a bit smaller, and it avoids a
GCC warning that YYVAL may be used uninitialized. */
yyval = yyvsp[1-yylen];
 
 
YY_REDUCE_PRINT (yyn);
switch (yyn)
{
case 2:
#line 153 "arith.y"
{
return ((yyvsp[(1) - (1)]));
}
break;
 
case 3:
#line 159 "arith.y"
{ (yyval) = (yyvsp[(2) - (3)]); }
break;
 
case 4:
#line 160 "arith.y"
{ (yyval) = (yyvsp[(1) - (3)]) ? (yyvsp[(1) - (3)]) : (yyvsp[(3) - (3)]) ? (yyvsp[(3) - (3)]) : 0; }
break;
 
case 5:
#line 161 "arith.y"
{ (yyval) = (yyvsp[(1) - (3)]) ? ( (yyvsp[(3) - (3)]) ? (yyvsp[(3) - (3)]) : 0 ) : 0; }
break;
 
case 6:
#line 162 "arith.y"
{ (yyval) = (yyvsp[(1) - (3)]) | (yyvsp[(3) - (3)]); }
break;
 
case 7:
#line 163 "arith.y"
{ (yyval) = (yyvsp[(1) - (3)]) ^ (yyvsp[(3) - (3)]); }
break;
 
case 8:
#line 164 "arith.y"
{ (yyval) = (yyvsp[(1) - (3)]) & (yyvsp[(3) - (3)]); }
break;
 
case 9:
#line 165 "arith.y"
{ (yyval) = (yyvsp[(1) - (3)]) == (yyvsp[(3) - (3)]); }
break;
 
case 10:
#line 166 "arith.y"
{ (yyval) = (yyvsp[(1) - (3)]) > (yyvsp[(3) - (3)]); }
break;
 
case 11:
#line 167 "arith.y"
{ (yyval) = (yyvsp[(1) - (3)]) >= (yyvsp[(3) - (3)]); }
break;
 
case 12:
#line 168 "arith.y"
{ (yyval) = (yyvsp[(1) - (3)]) < (yyvsp[(3) - (3)]); }
break;
 
case 13:
#line 169 "arith.y"
{ (yyval) = (yyvsp[(1) - (3)]) <= (yyvsp[(3) - (3)]); }
break;
 
case 14:
#line 170 "arith.y"
{ (yyval) = (yyvsp[(1) - (3)]) != (yyvsp[(3) - (3)]); }
break;
 
case 15:
#line 171 "arith.y"
{ (yyval) = (yyvsp[(1) - (3)]) << (yyvsp[(3) - (3)]); }
break;
 
case 16:
#line 172 "arith.y"
{ (yyval) = (yyvsp[(1) - (3)]) >> (yyvsp[(3) - (3)]); }
break;
 
case 17:
#line 173 "arith.y"
{ (yyval) = (yyvsp[(1) - (3)]) + (yyvsp[(3) - (3)]); }
break;
 
case 18:
#line 174 "arith.y"
{ (yyval) = (yyvsp[(1) - (3)]) - (yyvsp[(3) - (3)]); }
break;
 
case 19:
#line 175 "arith.y"
{ (yyval) = (yyvsp[(1) - (3)]) * (yyvsp[(3) - (3)]); }
break;
 
case 20:
#line 176 "arith.y"
{
if ((yyvsp[(3) - (3)]) == 0)
yyerror("division by zero");
(yyval) = (yyvsp[(1) - (3)]) / (yyvsp[(3) - (3)]);
}
break;
 
case 21:
#line 181 "arith.y"
{
if ((yyvsp[(3) - (3)]) == 0)
yyerror("division by zero");
(yyval) = (yyvsp[(1) - (3)]) % (yyvsp[(3) - (3)]);
}
break;
 
case 22:
#line 186 "arith.y"
{ (yyval) = !((yyvsp[(2) - (2)])); }
break;
 
case 23:
#line 187 "arith.y"
{ (yyval) = ~((yyvsp[(2) - (2)])); }
break;
 
case 24:
#line 188 "arith.y"
{ (yyval) = -((yyvsp[(2) - (2)])); }
break;
 
case 25:
#line 189 "arith.y"
{ (yyval) = (yyvsp[(2) - (2)]); }
break;
 
 
/* Line 1267 of yacc.c. */
#line 1682 "y.tab.c"
default: break;
}
YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
 
YYPOPSTACK (yylen);
yylen = 0;
YY_STACK_PRINT (yyss, yyssp);
 
*++yyvsp = yyval;
 
 
/* Now `shift' the result of the reduction. Determine what state
that goes to, based on the state we popped back to and the rule
number reduced by. */
 
yyn = yyr1[yyn];
 
yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
yystate = yytable[yystate];
else
yystate = yydefgoto[yyn - YYNTOKENS];
 
goto yynewstate;
 
 
/*------------------------------------.
| yyerrlab -- here on detecting error |
`------------------------------------*/
yyerrlab:
/* If not already recovering from an error, report this error. */
if (!yyerrstatus)
{
++yynerrs;
#if ! YYERROR_VERBOSE
yyerror (YY_("syntax error"));
#else
{
YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
{
YYSIZE_T yyalloc = 2 * yysize;
if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
yyalloc = YYSTACK_ALLOC_MAXIMUM;
if (yymsg != yymsgbuf)
YYSTACK_FREE (yymsg);
yymsg = (char *) YYSTACK_ALLOC (yyalloc);
if (yymsg)
yymsg_alloc = yyalloc;
else
{
yymsg = yymsgbuf;
yymsg_alloc = sizeof yymsgbuf;
}
}
 
if (0 < yysize && yysize <= yymsg_alloc)
{
(void) yysyntax_error (yymsg, yystate, yychar);
yyerror (yymsg);
}
else
{
yyerror (YY_("syntax error"));
if (yysize != 0)
goto yyexhaustedlab;
}
}
#endif
}
 
 
 
if (yyerrstatus == 3)
{
/* If just tried and failed to reuse look-ahead token after an
error, discard it. */
 
if (yychar <= YYEOF)
{
/* Return failure if at end of input. */
if (yychar == YYEOF)
YYABORT;
}
else
{
yydestruct ("Error: discarding",
yytoken, &yylval);
yychar = YYEMPTY;
}
}
 
/* Else will try to reuse look-ahead token after shifting the error
token. */
goto yyerrlab1;
 
 
/*---------------------------------------------------.
| yyerrorlab -- error raised explicitly by YYERROR. |
`---------------------------------------------------*/
yyerrorlab:
 
/* Pacify compilers like GCC when the user code never invokes
YYERROR and the label yyerrorlab therefore never appears in user
code. */
if (/*CONSTCOND*/ 0)
goto yyerrorlab;
 
/* Do not reclaim the symbols of the rule which action triggered
this YYERROR. */
YYPOPSTACK (yylen);
yylen = 0;
YY_STACK_PRINT (yyss, yyssp);
yystate = *yyssp;
goto yyerrlab1;
 
 
/*-------------------------------------------------------------.
| yyerrlab1 -- common code for both syntax error and YYERROR. |
`-------------------------------------------------------------*/
yyerrlab1:
yyerrstatus = 3; /* Each real token shifted decrements this. */
 
for (;;)
{
yyn = yypact[yystate];
if (yyn != YYPACT_NINF)
{
yyn += YYTERROR;
if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
{
yyn = yytable[yyn];
if (0 < yyn)
break;
}
}
 
/* Pop the current state because it cannot handle the error token. */
if (yyssp == yyss)
YYABORT;
 
 
yydestruct ("Error: popping",
yystos[yystate], yyvsp);
YYPOPSTACK (1);
yystate = *yyssp;
YY_STACK_PRINT (yyss, yyssp);
}
 
if (yyn == YYFINAL)
YYACCEPT;
 
*++yyvsp = yylval;
 
 
/* Shift the error token. */
YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
 
yystate = yyn;
goto yynewstate;
 
 
/*-------------------------------------.
| yyacceptlab -- YYACCEPT comes here. |
`-------------------------------------*/
yyacceptlab:
yyresult = 0;
goto yyreturn;
 
/*-----------------------------------.
| yyabortlab -- YYABORT comes here. |
`-----------------------------------*/
yyabortlab:
yyresult = 1;
goto yyreturn;
 
#ifndef yyoverflow
/*-------------------------------------------------.
| yyexhaustedlab -- memory exhaustion comes here. |
`-------------------------------------------------*/
yyexhaustedlab:
yyerror (YY_("memory exhausted"));
yyresult = 2;
/* Fall through. */
#endif
 
yyreturn:
if (yychar != YYEOF && yychar != YYEMPTY)
yydestruct ("Cleanup: discarding lookahead",
yytoken, &yylval);
/* Do not reclaim the symbols of the rule which action triggered
this YYABORT or YYACCEPT. */
YYPOPSTACK (yylen);
YY_STACK_PRINT (yyss, yyssp);
while (yyssp != yyss)
{
yydestruct ("Cleanup: popping",
yystos[*yyssp], yyvsp);
YYPOPSTACK (1);
}
#ifndef yyoverflow
if (yyss != yyssa)
YYSTACK_FREE (yyss);
#endif
#if YYERROR_VERBOSE
if (yymsg != yymsgbuf)
YYSTACK_FREE (yymsg);
#endif
/* Make sure YYID is used. */
return YYID (yyresult);
}
 
 
#line 192 "arith.y"
 
void
yyerror(s)
const char *s;
{
 
yyclearin;
arith_lex_reset(); /* reprime lex */
error("arithmetic expression: %s: \"%s\"", s, arith_startbuf);
/* NOTREACHED */
}
 
/trunk/uspace/app/ash/redir.h
0,0 → 1,53
/* $NetBSD: redir.h,v 1.12 2000/05/22 10:18:47 elric 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)redir.h 8.2 (Berkeley) 5/4/95
*/
 
/* flags passed to redirect */
#define REDIR_PUSH 01 /* save previous values of file descriptors */
#define REDIR_BACKQ 02 /* save the command output in memory */
 
extern int fd2;
 
union node;
void redirect (union node *, int);
void popredir (void);
int fd0_redirected_p (void);
void clearredir (void);
int copyfd (int, int);
 
/trunk/uspace/app/ash/trap.h
0,0 → 1,51
/* $NetBSD: trap.h,v 1.14 2000/05/22 10:18:47 elric 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)trap.h 8.3 (Berkeley) 6/5/95
*/
 
extern int pendingsigs;
 
int trapcmd (int, char **);
void clear_traps (void);
void setsignal (int);
void ignoresig (int);
void onsig (int);
void dotrap (void);
void setinteractive (int);
void exitshell (int) __attribute__((noreturn));
int decode_signal (const char *);
/trunk/uspace/app/ash/arith.h
0,0 → 1,107
/* A Bison parser, made by GNU Bison 2.3. */
 
/* Skeleton interface for Bison's Yacc-like parsers in C
 
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
 
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA. */
 
/* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work
under terms of your choice, so long as that work isn't itself a
parser generator using the skeleton or a modified version thereof
as a parser skeleton. Alternatively, if you modify or redistribute
the parser skeleton itself, you may (at your option) remove this
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
 
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
 
/* Tokens. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
/* Put the tokens into the symbol table, so that GDB and other debuggers
know about them. */
enum yytokentype {
ARITH_NUM = 258,
ARITH_LPAREN = 259,
ARITH_RPAREN = 260,
ARITH_OR = 261,
ARITH_AND = 262,
ARITH_BOR = 263,
ARITH_BXOR = 264,
ARITH_BAND = 265,
ARITH_NE = 266,
ARITH_EQ = 267,
ARITH_LE = 268,
ARITH_GE = 269,
ARITH_GT = 270,
ARITH_LT = 271,
ARITH_RSHIFT = 272,
ARITH_LSHIFT = 273,
ARITH_SUB = 274,
ARITH_ADD = 275,
ARITH_REM = 276,
ARITH_DIV = 277,
ARITH_MUL = 278,
ARITH_BNOT = 279,
ARITH_NOT = 280,
ARITH_UNARYPLUS = 281,
ARITH_UNARYMINUS = 282
};
#endif
/* Tokens. */
#define ARITH_NUM 258
#define ARITH_LPAREN 259
#define ARITH_RPAREN 260
#define ARITH_OR 261
#define ARITH_AND 262
#define ARITH_BOR 263
#define ARITH_BXOR 264
#define ARITH_BAND 265
#define ARITH_NE 266
#define ARITH_EQ 267
#define ARITH_LE 268
#define ARITH_GE 269
#define ARITH_GT 270
#define ARITH_LT 271
#define ARITH_RSHIFT 272
#define ARITH_LSHIFT 273
#define ARITH_SUB 274
#define ARITH_ADD 275
#define ARITH_REM 276
#define ARITH_DIV 277
#define ARITH_MUL 278
#define ARITH_BNOT 279
#define ARITH_NOT 280
#define ARITH_UNARYPLUS 281
#define ARITH_UNARYMINUS 282
 
 
 
 
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef int YYSTYPE;
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
# define YYSTYPE_IS_TRIVIAL 1
#endif
 
extern YYSTYPE yylval;
 
/trunk/uspace/app/ash/expand.c
0,0 → 1,1750
/* $NetBSD: expand.c,v 1.49 2000/03/13 22:47:19 soren 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
 
#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.49 2000/03/13 22:47:19 soren Exp $");
#endif
#endif /* not lint */
 
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <errno.h>
#include <dirent.h>
#include <unistd.h>
#include <pwd.h>
#include <stdlib.h>
#include <stdio.h>
#if defined(__GLIBC__) && !defined(GLOB_BROKEN)
#include <fnmatch.h>
#include <glob.h>
#endif
 
/*
* Routines to expand arguments to commands. We have to deal with
* backquotes, shell variables, and file metacharacters.
*/
 
#include "shell.h"
#include "main.h"
#include "nodes.h"
#include "eval.h"
#include "expand.h"
#include "syntax.h"
#include "parser.h"
#include "jobs.h"
#include "options.h"
#include "var.h"
#include "input.h"
#include "output.h"
#include "memalloc.h"
#include "error.h"
#include "mystring.h"
#include "show.h"
 
/*
* Structure specifying which parts of the string should be searched
* for IFS characters.
*/
 
struct ifsregion {
struct ifsregion *next; /* next region in list */
int begoff; /* offset of start of region */
int endoff; /* offset of end of region */
int nulonly; /* search for nul bytes only */
};
 
 
char *expdest; /* output of current string */
struct nodelist *argbackq; /* list of back quote expressions */
struct ifsregion ifsfirst; /* first struct in list of ifs regions */
struct ifsregion *ifslastp; /* last struct in list */
struct arglist exparg; /* holds expanded arg list */
 
STATIC void argstr (char *, int);
STATIC char *exptilde (char *, int);
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 char *strtodest (char *, int, int);
STATIC void varvalue (char *, 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);
#if defined(__GLIBC__) && !defined(GLOB_BROKEN)
STATIC const char *preglob (const char *);
STATIC void addglob (const glob_t *);
#else
STATIC void expmeta (char *, char *);
#endif
STATIC void addfname (char *);
#if defined(__GLIBC__) && !defined(GLOB_BROKEN)
STATIC int patmatch (char *, char *, int);
STATIC int patmatch2 (char *, char *, int);
STATIC char * _rmescapes (char *, int);
#else
STATIC struct strlist *expsort (struct strlist *);
STATIC struct strlist *msort (struct strlist *, int);
STATIC int pmatch (char *, char *, int);
#define patmatch2 patmatch
#endif
STATIC char *cvtnum (int, char *);
 
/*
* Expand shell variables and backquotes inside a here document.
*/
 
void
expandhere(arg, fd)
union node *arg; /* the document */
int fd; /* where to write the expanded version */
{
herefd = fd;
expandarg(arg, (struct arglist *)NULL, 0);
xwrite(fd, stackblock(), expdest - stackblock());
}
 
 
/*
* Perform variable substitution and command substitution on an argument,
* placing the resulting list of arguments in arglist. If EXP_FULL is true,
* perform splitting and file name expansion. When arglist is NULL, perform
* here document expansion.
*/
 
void
expandarg(arg, arglist, flag)
union node *arg;
struct arglist *arglist;
int flag;
{
struct strlist *sp;
char *p;
 
argbackq = arg->narg.backquote;
STARTSTACKSTR(expdest);
ifsfirst.next = NULL;
ifslastp = NULL;
argstr(arg->narg.text, flag);
if (arglist == NULL) {
return; /* here document expanded */
}
STPUTC('\0', expdest);
p = grabstackstr(expdest);
exparg.lastp = &exparg.list;
/*
* TODO - EXP_REDIR
*/
if (flag & EXP_FULL) {
ifsbreakup(p, &exparg);
*exparg.lastp = NULL;
exparg.lastp = &exparg.list;
expandmeta(exparg.list, flag);
} else {
if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
rmescapes(p);
sp = (struct strlist *)stalloc(sizeof (struct strlist));
sp->text = p;
*exparg.lastp = sp;
exparg.lastp = &sp->next;
}
ifsfree();
*exparg.lastp = NULL;
if (exparg.list) {
*arglist->lastp = exparg.list;
arglist->lastp = exparg.lastp;
}
}
 
 
 
/*
* Perform variable and command substitution. If EXP_FULL is set, output CTLESC
* characters to allow for further processing. Otherwise treat
* $@ like $* since no splitting will be performed.
*/
 
STATIC void
argstr(p, flag)
char *p;
int flag;
{
char c;
int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
int firsteq = 1;
 
if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
p = exptilde(p, flag);
for (;;) {
switch (c = *p++) {
case '\0':
case CTLENDVAR: /* ??? */
goto breakloop;
case CTLQUOTEMARK:
/* "$@" syntax adherence hack */
if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
break;
if ((flag & EXP_FULL) != 0)
STPUTC(c, expdest);
break;
case CTLESC:
if (quotes)
STPUTC(c, expdest);
c = *p++;
STPUTC(c, expdest);
break;
case CTLVAR:
p = evalvar(p, flag);
break;
case CTLBACKQ:
case CTLBACKQ|CTLQUOTE:
expbackq(argbackq->n, c & CTLQUOTE, flag);
argbackq = argbackq->next;
break;
case CTLENDARI:
expari(flag);
break;
case ':':
case '=':
/*
* sort of a hack - expand tildes in variable
* assignments (after the first '=' and after ':'s).
*/
STPUTC(c, expdest);
if (flag & EXP_VARTILDE && *p == '~') {
if (c == '=') {
if (firsteq)
firsteq = 0;
else
break;
}
p = exptilde(p, flag);
}
break;
default:
STPUTC(c, expdest);
}
}
breakloop:;
return;
}
 
STATIC char *
exptilde(p, flag)
char *p;
int flag;
{
char c, *startp = p;
struct passwd *pw;
const char *home;
int quotes = flag & (EXP_FULL | EXP_CASE);
 
while ((c = *p) != '\0') {
switch(c) {
case CTLESC:
return (startp);
case CTLQUOTEMARK:
return (startp);
case ':':
if (flag & EXP_VARTILDE)
goto done;
break;
case '/':
goto done;
}
p++;
}
done:
*p = '\0';
if (*(startp+1) == '\0') {
if ((home = lookupvar("HOME")) == NULL)
goto lose;
} else {
if ((pw = getpwnam(startp+1)) == NULL)
goto lose;
home = pw->pw_dir;
}
if (*home == '\0')
goto lose;
*p = c;
while ((c = *home++) != '\0') {
if (quotes && SQSYNTAX[(int)c] == CCTL)
STPUTC(CTLESC, expdest);
STPUTC(c, expdest);
}
return (p);
lose:
*p = c;
return (startp);
}
 
 
STATIC void
removerecordregions(endoff)
int endoff;
{
if (ifslastp == NULL)
return;
 
if (ifsfirst.endoff > endoff) {
while (ifsfirst.next != NULL) {
struct ifsregion *ifsp;
INTOFF;
ifsp = ifsfirst.next->next;
ckfree(ifsfirst.next);
ifsfirst.next = ifsp;
INTON;
}
if (ifsfirst.begoff > endoff)
ifslastp = NULL;
else {
ifslastp = &ifsfirst;
ifsfirst.endoff = endoff;
}
return;
}
ifslastp = &ifsfirst;
while (ifslastp->next && ifslastp->next->begoff < endoff)
ifslastp=ifslastp->next;
while (ifslastp->next != NULL) {
struct ifsregion *ifsp;
INTOFF;
ifsp = ifslastp->next->next;
ckfree(ifslastp->next);
ifslastp->next = ifsp;
INTON;
}
if (ifslastp->endoff > endoff)
ifslastp->endoff = endoff;
}
 
 
/*
* Expand arithmetic expression. Backup to start of expression,
* evaluate, place result in (backed up) result, adjust string position.
*/
void
expari(flag)
int flag;
{
char *p, *start;
int result;
int begoff;
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 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.
*/
CHECKSTRSPACE(10, expdest);
USTPUTC('\0', expdest);
start = stackblock();
p = expdest - 1;
while (*p != CTLARI && p >= start)
--p;
if (*p != CTLARI)
error("missing CTLARI (shouldn't happen)");
if (p > start && *(p-1) == CTLESC)
for (p = start; *p != CTLARI; p++)
if (*p == CTLESC)
p++;
 
if (p[1] == '"')
quoted=1;
else
quoted=0;
begoff = p - start;
removerecordregions(begoff);
if (quotes)
rmescapes(p+2);
result = arith(p+2);
fmtstr(p, 12, "%d", result);
 
while (*p++)
;
 
if (quoted == 0)
recordregion(begoff, p - 1 - start, 0);
result = expdest - p + 1;
STADJUST(-result, expdest);
}
 
 
/*
* Expand stuff in backwards quotes.
*/
 
STATIC void
expbackq(cmd, quoted, flag)
union node *cmd;
int quoted;
int flag;
{
struct backcmd in;
int i;
char buf[128];
char *p;
char *dest = expdest;
struct ifsregion saveifs, *savelastp;
struct nodelist *saveargbackq;
char lastc;
int startloc = dest - stackblock();
char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
int saveherefd;
int quotes = flag & (EXP_FULL | EXP_CASE);
 
INTOFF;
saveifs = ifsfirst;
savelastp = ifslastp;
saveargbackq = argbackq;
saveherefd = herefd;
herefd = -1;
p = grabstackstr(dest);
evalbackcmd(cmd, &in);
ungrabstackstr(p, dest);
ifsfirst = saveifs;
ifslastp = savelastp;
argbackq = saveargbackq;
herefd = saveherefd;
 
p = in.buf;
lastc = '\0';
for (;;) {
if (--in.nleft < 0) {
if (in.fd < 0)
break;
while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR);
TRACE(("expbackq: read returns %d\n", i));
if (i <= 0)
break;
p = buf;
in.nleft = i - 1;
}
lastc = *p++;
if (lastc != '\0') {
if (quotes && syntax[(int)lastc] == CCTL)
STPUTC(CTLESC, dest);
STPUTC(lastc, dest);
}
}
 
/* Eat all trailing newlines */
for (p--; lastc == '\n'; lastc = *--p)
STUNPUTC(dest);
 
if (in.fd >= 0)
close(in.fd);
if (in.buf)
ckfree(in.buf);
if (in.jp)
exitstatus = waitforjob(in.jp);
if (quoted == 0)
recordregion(startloc, dest - stackblock(), 0);
TRACE(("evalbackq: size=%d: \"%.*s\"\n",
(dest - stackblock()) - startloc,
(dest - stackblock()) - startloc,
stackblock() + startloc));
expdest = dest;
INTON;
}
 
 
 
STATIC int
subevalvar(p, str, strloc, subtype, startloc, varflags)
char *p;
char *str;
int strloc;
int subtype;
int startloc;
int varflags;
{
char *startp;
char *loc = NULL;
char *q;
int c = 0;
int saveherefd = herefd;
struct nodelist *saveargbackq = argbackq;
int amount;
 
herefd = -1;
argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
STACKSTRNUL(expdest);
herefd = saveherefd;
argbackq = saveargbackq;
startp = stackblock() + startloc;
if (str == NULL)
str = stackblock() + strloc;
 
switch (subtype) {
case VSASSIGN:
setvar(str, startp, 0);
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("%.*s: parameter %snot set", p - str - 1,
str, (varflags & VSNUL) ? "null or "
: nullstr);
/* NOTREACHED */
 
case VSTRIMLEFT:
for (loc = startp; loc < str; loc++) {
c = *loc;
*loc = '\0';
if (patmatch2(str, startp, varflags & VSQUOTE))
goto recordleft;
*loc = c;
if ((varflags & VSQUOTE) && *loc == CTLESC)
loc++;
}
return 0;
 
case VSTRIMLEFTMAX:
for (loc = str - 1; loc >= startp;) {
c = *loc;
*loc = '\0';
if (patmatch2(str, startp, varflags & VSQUOTE))
goto recordleft;
*loc = c;
loc--;
if ((varflags & VSQUOTE) && loc > startp &&
*(loc - 1) == CTLESC) {
for (q = startp; q < loc; q++)
if (*q == CTLESC)
q++;
if (q > loc)
loc--;
}
}
return 0;
 
case VSTRIMRIGHT:
for (loc = str - 1; loc >= startp;) {
if (patmatch2(str, loc, varflags & VSQUOTE))
goto recordright;
loc--;
if ((varflags & VSQUOTE) && loc > startp &&
*(loc - 1) == CTLESC) {
for (q = startp; q < loc; q++)
if (*q == CTLESC)
q++;
if (q > loc)
loc--;
}
}
return 0;
 
case VSTRIMRIGHTMAX:
for (loc = startp; loc < str - 1; loc++) {
if (patmatch2(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;
}
 
 
/*
* Expand a variable, and return a pointer to the next character in the
* input string.
*/
 
STATIC char *
evalvar(p, flag)
char *p;
int flag;
{
int subtype;
int varflags;
char *var;
char *val;
int patloc;
int c;
int set;
int special;
int startloc;
int varlen;
int easy;
int quotes = flag & (EXP_FULL | EXP_CASE);
 
varflags = *p++;
subtype = varflags & VSTYPE;
var = p;
special = 0;
if (! is_name(*p))
special = 1;
p = strchr(p, '=') + 1;
again: /* jump here after setting a variable with ${var=text} */
if (special) {
set = varisset(var, varflags & VSNUL);
val = NULL;
} else {
val = lookupvar(var);
if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
val = NULL;
set = 0;
} else
set = 1;
}
varlen = 0;
startloc = expdest - stackblock();
if (set && subtype != VSPLUS) {
/* insert the value of the variable */
if (special) {
varvalue(var, varflags & VSQUOTE, flag & EXP_FULL);
if (subtype == VSLENGTH) {
varlen = expdest - stackblock() - startloc;
STADJUST(-varlen, expdest);
}
} else {
char const *syntax = (varflags & VSQUOTE) ? DQSYNTAX
: BASESYNTAX;
 
if (subtype == VSLENGTH) {
for (;*val; val++)
varlen++;
}
else {
while (*val) {
if (quotes && syntax[(int)*val] == CCTL)
STPUTC(CTLESC, expdest);
STPUTC(*val++, expdest);
}
 
}
}
}
 
if (subtype == VSPLUS)
set = ! set;
 
easy = ((varflags & VSQUOTE) == 0 ||
(*var == '@' && shellparam.nparam != 1));
 
 
switch (subtype) {
case VSLENGTH:
expdest = cvtnum(varlen, expdest);
goto record;
 
case VSNORMAL:
if (!easy)
break;
record:
recordregion(startloc, expdest - stackblock(),
varflags & VSQUOTE);
break;
 
case VSPLUS:
case VSMINUS:
if (!set) {
argstr(p, flag);
break;
}
if (easy)
goto record;
break;
 
case VSTRIMLEFT:
case VSTRIMLEFTMAX:
case VSTRIMRIGHT:
case VSTRIMRIGHTMAX:
if (!set)
break;
/*
* Terminate the string and start recording the pattern
* right after it
*/
STPUTC('\0', expdest);
patloc = expdest - stackblock();
if (subevalvar(p, NULL, patloc, subtype,
startloc, varflags) == 0) {
int amount = (expdest - stackblock() - patloc) + 1;
STADJUST(-amount, expdest);
}
/* Remove any recorded regions beyond start of variable */
removerecordregions(startloc);
goto record;
 
case VSASSIGN:
case VSQUESTION:
if (!set) {
if (subevalvar(p, var, 0, subtype, startloc,
varflags)) {
varflags &= ~VSNUL;
/*
* Remove any recorded regions beyond
* start of variable
*/
removerecordregions(startloc);
goto again;
}
break;
}
if (easy)
goto record;
break;
 
default:
abort();
}
 
if (subtype != VSNORMAL) { /* skip to end of alternative */
int nesting = 1;
for (;;) {
if ((c = *p++) == CTLESC)
p++;
else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
if (set)
argbackq = argbackq->next;
} else if (c == CTLVAR) {
if ((*p++ & VSTYPE) != VSNORMAL)
nesting++;
} else if (c == CTLENDVAR) {
if (--nesting == 0)
break;
}
}
}
return p;
}
 
 
 
/*
* Test whether a specialized variable is set.
*/
 
STATIC int
varisset(name, nulok)
char *name;
int nulok;
{
if (*name == '!')
return backgndpid != -1;
else if (*name == '@' || *name == '*') {
if (*shellparam.p == NULL)
return 0;
 
if (nulok) {
char **av;
 
for (av = shellparam.p; *av; av++)
if (**av != '\0')
return 1;
return 0;
}
} else if (is_digit(*name)) {
char *ap;
int num = atoi(name);
 
if (num > shellparam.nparam)
return 0;
 
if (num == 0)
ap = arg0;
else
ap = shellparam.p[num - 1];
 
if (nulok && (ap == NULL || *ap == '\0'))
return 0;
}
return 1;
}
 
 
 
/*
* Put a string on the stack.
*/
 
STATIC char *
strtodest(p, quoted, allow_split)
char *p;
int quoted;
int allow_split;
{
char const *syntax;
 
if (allow_split) {
syntax = quoted ? DQSYNTAX : BASESYNTAX;
while (*p) {
if (syntax[(int) *p] == CCTL)
STPUTC(CTLESC, expdest);
STPUTC(*p++, expdest);
}
} else
while (*p)
STPUTC(*p++, expdest);
 
return p;
}
 
 
 
/*
* Add the value of a specialized variable to the stack string.
*/
 
STATIC void
varvalue(name, quoted, allow_split)
char *name;
int quoted;
int allow_split;
{
int num;
char *p;
int i;
extern int oexitstatus;
char sep;
char **ap;
 
switch (*name) {
case '$':
num = rootpid;
goto numvar;
case '?':
num = oexitstatus;
goto numvar;
case '#':
num = shellparam.nparam;
goto numvar;
case '!':
num = backgndpid;
numvar:
expdest = cvtnum(num, expdest);
break;
case '-':
for (i = 0 ; i < NOPTS ; i++) {
if (optlist[i].val)
STPUTC(optlist[i].letter, expdest);
}
break;
case '@':
if (allow_split && quoted) {
for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
p = strtodest(p, quoted, allow_split);
if (*ap)
STPUTC('\0', expdest);
}
break;
}
/* fall through */
case '*':
if (ifsset() != 0)
sep = ifsval()[0];
else
sep = ' ';
for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
p = strtodest(p, quoted, allow_split);
if (*ap && sep)
STPUTC(sep, expdest);
}
break;
case '0':
p = strtodest(arg0, quoted, allow_split);
break;
default:
if (is_digit(*name)) {
num = atoi(name);
if (num > 0 && num <= shellparam.nparam) {
p = strtodest(shellparam.p[num - 1], quoted,
allow_split);
}
}
break;
}
}
 
 
 
/*
* Record the fact that we have to scan this region of the
* string for IFS characters.
*/
 
STATIC void
recordregion(start, end, nulonly)
int start;
int end;
int nulonly;
{
struct ifsregion *ifsp;
 
if (ifslastp == NULL) {
ifsp = &ifsfirst;
} else {
ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
ifslastp->next = ifsp;
}
ifslastp = ifsp;
ifslastp->next = NULL;
ifslastp->begoff = start;
ifslastp->endoff = end;
ifslastp->nulonly = nulonly;
}
 
 
 
/*
* Break the argument string into pieces based upon IFS and add the
* strings to the argument list. The regions of the string to be
* searched for IFS characters have been stored by recordregion.
*/
STATIC void
ifsbreakup(string, arglist)
char *string;
struct arglist *arglist;
{
struct ifsregion *ifsp;
struct strlist *sp;
char *start;
char *p;
char *q;
const char *ifs;
int ifsspc;
int nulonly;
 
 
start = string;
ifsspc = 0;
nulonly = 0;
if (ifslastp != NULL) {
ifsp = &ifsfirst;
do {
p = string + ifsp->begoff;
nulonly = ifsp->nulonly;
ifs = nulonly ? nullstr :
( ifsset() ? ifsval() : " \t\n" );
ifsspc = 0;
while (p < string + ifsp->endoff) {
q = p;
if (*p == CTLESC)
p++;
if (strchr(ifs, *p)) {
if (!nulonly)
ifsspc = (strchr(" \t\n", *p) != NULL);
/* Ignore IFS whitespace at start */
if (q == start && ifsspc) {
p++;
start = p;
continue;
}
*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;
}
q = p;
if (*p == CTLESC)
p++;
if (strchr(ifs, *p) == NULL ) {
p = q;
break;
} else if (strchr(" \t\n",*p) == NULL) {
if (ifsspc) {
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))) {
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()
{
while (ifsfirst.next != NULL) {
struct ifsregion *ifsp;
INTOFF;
ifsp = ifsfirst.next->next;
ckfree(ifsfirst.next);
ifsfirst.next = ifsp;
INTON;
}
ifslastp = NULL;
ifsfirst.next = NULL;
}
 
 
 
/*
* Expand shell metacharacters. At this point, the only control characters
* should be escapes. The results are stored in the list exparg.
*/
 
#if defined(__GLIBC__) && !defined(GLOB_BROKEN)
STATIC void
expandmeta(str, flag)
struct strlist *str;
int flag;
{
const char *p;
glob_t pglob;
/* TODO - EXP_REDIR */
 
while (str) {
if (fflag)
goto nometa;
p = preglob(str->text);
INTOFF;
switch (glob(p, GLOB_NOMAGIC, 0, &pglob)) {
case 0:
if (!(pglob.gl_flags & GLOB_MAGCHAR))
goto nometa2;
addglob(&pglob);
globfree(&pglob);
INTON;
break;
case GLOB_NOMATCH:
nometa2:
globfree(&pglob);
INTON;
nometa:
*exparg.lastp = str;
rmescapes(str->text);
exparg.lastp = &str->next;
break;
default: /* GLOB_NOSPACE */
error("Out of space");
}
str = str->next;
}
}
 
 
/*
* Prepare the string for glob(3).
*/
 
STATIC const char *
preglob(str)
const char *str;
{
const char *p;
char *q, *r;
size_t len;
 
p = str;
while (*p != CTLQUOTEMARK && *p != CTLESC) {
if (*p++ == '\0')
return str;
}
len = p - str;
q = r = stalloc(strlen(str) + 1);
if (len > 0) {
memcpy(q, str, len);
q += len;
}
do {
if (*p == CTLQUOTEMARK)
continue;
if (*p == CTLESC) {
if (*++p != '/')
*q++ = '\\';
}
*q++ = *p;
} while (*++p);
*q = '\0';
return r;
}
 
 
/*
* Add the result of glob(3) to the list.
*/
 
STATIC void
addglob(pglob)
const glob_t *pglob;
{
char **p = pglob->gl_pathv;
 
do {
addfname(*p);
} while (*++p);
}
#else
char *expdir;
 
 
STATIC void
expandmeta(str, flag)
struct strlist *str;
int flag;
{
char *p;
struct strlist **savelastp;
struct strlist *sp;
char c;
/* TODO - EXP_REDIR */
 
while (str) {
if (fflag)
goto nometa;
p = str->text;
for (;;) { /* fast check for meta chars */
if ((c = *p++) == '\0')
goto nometa;
if (c == '*' || c == '?' || c == '[' || c == '!')
break;
}
savelastp = exparg.lastp;
INTOFF;
if (expdir == NULL) {
int i = strlen(str->text);
expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
}
 
expmeta(expdir, str->text);
ckfree(expdir);
expdir = NULL;
INTON;
if (exparg.lastp == savelastp) {
/*
* no matches
*/
nometa:
*exparg.lastp = str;
rmescapes(str->text);
exparg.lastp = &str->next;
} else {
*exparg.lastp = NULL;
*savelastp = sp = expsort(*savelastp);
while (sp->next != NULL)
sp = sp->next;
exparg.lastp = &sp->next;
}
str = str->next;
}
}
 
 
/*
* Do metacharacter (i.e. *, ?, [...]) expansion.
*/
 
STATIC void
expmeta(enddir, name)
char *enddir;
char *name;
{
char *p;
const char *cp;
char *q;
char *start;
char *endname;
int metaflag;
struct stat statb;
DIR *dirp;
struct dirent *dp;
int atend;
int matchdot;
 
metaflag = 0;
start = name;
for (p = name ; ; p++) {
if (*p == '*' || *p == '?')
metaflag = 1;
else if (*p == '[') {
q = p + 1;
if (*q == '!')
q++;
for (;;) {
while (*q == CTLQUOTEMARK)
q++;
if (*q == CTLESC)
q++;
if (*q == '/' || *q == '\0')
break;
if (*++q == ']') {
metaflag = 1;
break;
}
}
} else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) {
metaflag = 1;
} else if (*p == '\0')
break;
else if (*p == CTLQUOTEMARK)
continue;
else if (*p == CTLESC)
p++;
if (*p == '/') {
if (metaflag)
break;
start = p + 1;
}
}
if (metaflag == 0) { /* we've reached the end of the file name */
if (enddir != expdir)
metaflag++;
for (p = name ; ; p++) {
if (*p == CTLQUOTEMARK)
continue;
if (*p == CTLESC)
p++;
*enddir++ = *p;
if (*p == '\0')
break;
}
if (metaflag == 0 || stat(expdir, &statb) >= 0)
addfname(expdir);
return;
}
endname = p;
if (start != name) {
p = name;
while (p < start) {
while (*p == CTLQUOTEMARK)
p++;
if (*p == CTLESC)
p++;
*enddir++ = *p++;
}
}
if (enddir == expdir) {
cp = ".";
} else if (enddir == expdir + 1 && *expdir == '/') {
cp = "/";
} else {
cp = expdir;
enddir[-1] = '\0';
}
if ((dirp = opendir(cp)) == NULL)
return;
if (enddir != expdir)
enddir[-1] = '/';
if (*endname == 0) {
atend = 1;
} else {
atend = 0;
*endname++ = '\0';
}
matchdot = 0;
p = start;
while (*p == CTLQUOTEMARK)
p++;
if (*p == CTLESC)
p++;
if (*p == '.')
matchdot++;
while (! int_pending() && (dp = readdir(dirp)) != NULL) {
if (dp->d_name[0] == '.' && ! matchdot)
continue;
if (patmatch(start, dp->d_name, 0)) {
if (atend) {
scopy(dp->d_name, enddir);
addfname(expdir);
} else {
for (p = enddir, cp = dp->d_name;
(*p++ = *cp++) != '\0';)
continue;
p[-1] = '/';
expmeta(p, endname);
}
}
}
closedir(dirp);
if (! atend)
endname[-1] = '/';
}
#endif
 
 
/*
* Add a file name to the list.
*/
 
STATIC void
addfname(name)
char *name;
{
char *p;
struct strlist *sp;
 
p = stalloc(strlen(name) + 1);
scopy(name, p);
sp = (struct strlist *)stalloc(sizeof *sp);
sp->text = p;
*exparg.lastp = sp;
exparg.lastp = &sp->next;
}
 
 
#if !(defined(__GLIBC__) && !defined(GLOB_BROKEN))
/*
* Sort the results of file name expansion. It calculates the number of
* strings to sort and then calls msort (short for merge sort) to do the
* work.
*/
 
STATIC struct strlist *
expsort(str)
struct strlist *str;
{
int len;
struct strlist *sp;
 
len = 0;
for (sp = str ; sp ; sp = sp->next)
len++;
return msort(str, len);
}
 
 
STATIC struct strlist *
msort(list, len)
struct strlist *list;
int len;
{
struct strlist *p, *q = NULL;
struct strlist **lpp;
int half;
int n;
 
if (len <= 1)
return list;
half = len >> 1;
p = list;
for (n = half ; --n >= 0 ; ) {
q = p;
p = p->next;
}
q->next = NULL; /* terminate first half of list */
q = msort(list, half); /* sort first half of list */
p = msort(p, len - half); /* sort second half */
lpp = &list;
for (;;) {
if (strcmp(p->text, q->text) < 0) {
*lpp = p;
lpp = &p->next;
if ((p = *lpp) == NULL) {
*lpp = q;
break;
}
} else {
*lpp = q;
lpp = &q->next;
if ((q = *lpp) == NULL) {
*lpp = p;
break;
}
}
}
return list;
}
#endif
 
 
 
/*
* Returns true if the pattern matches the string.
*/
 
#if defined(__GLIBC__) && !defined(GLOB_BROKEN)
STATIC int
patmatch(pattern, string, squoted)
char *pattern;
char *string;
int squoted; /* string might have quote chars */
{
const char *p;
char *q;
 
p = preglob(pattern);
q = squoted ? _rmescapes(string, 1) : string;
 
return !fnmatch(p, q, 0);
}
 
 
STATIC int
patmatch2(pattern, string, squoted)
char *pattern;
char *string;
int squoted; /* string might have quote chars */
{
char *p;
int res;
 
sstrnleft--;
p = grabstackstr(expdest);
res = patmatch(pattern, string, squoted);
ungrabstackstr(p, expdest);
return res;
}
#else
int
patmatch(pattern, string, squoted)
char *pattern;
char *string;
int squoted; /* string might have quote chars */
{
#ifdef notdef
if (pattern[0] == '!' && pattern[1] == '!')
return 1 - pmatch(pattern + 2, string);
else
#endif
return pmatch(pattern, string, squoted);
}
 
 
STATIC int
pmatch(pattern, string, squoted)
char *pattern;
char *string;
int squoted;
{
char *p, *q;
char c;
 
p = pattern;
q = string;
for (;;) {
switch (c = *p++) {
case '\0':
goto breakloop;
case CTLESC:
if (squoted && *q == CTLESC)
q++;
if (*q++ != *p++)
return 0;
break;
case CTLQUOTEMARK:
continue;
case '?':
if (squoted && *q == CTLESC)
q++;
if (*q++ == '\0')
return 0;
break;
case '*':
c = *p;
while (c == CTLQUOTEMARK || c == '*')
c = *++p;
if (c != CTLESC && c != CTLQUOTEMARK &&
c != '?' && c != '*' && c != '[') {
while (*q != c) {
if (squoted && *q == CTLESC &&
q[1] == c)
break;
if (*q == '\0')
return 0;
if (squoted && *q == CTLESC)
q++;
q++;
}
}
do {
if (pmatch(p, q, squoted))
return 1;
if (squoted && *q == CTLESC)
q++;
} while (*q++ != '\0');
return 0;
case '[': {
char *endp;
int invert, found;
char chr;
 
endp = p;
if (*endp == '!')
endp++;
for (;;) {
while (*endp == CTLQUOTEMARK)
endp++;
if (*endp == '\0')
goto dft; /* no matching ] */
if (*endp == CTLESC)
endp++;
if (*++endp == ']')
break;
}
invert = 0;
if (*p == '!') {
invert++;
p++;
}
found = 0;
chr = *q++;
if (squoted && chr == CTLESC)
chr = *q++;
if (chr == '\0')
return 0;
c = *p++;
do {
if (c == CTLQUOTEMARK)
continue;
if (c == CTLESC)
c = *p++;
if (*p == '-' && p[1] != ']') {
p++;
while (*p == CTLQUOTEMARK)
p++;
if (*p == CTLESC)
p++;
if (chr >= c && chr <= *p)
found = 1;
p++;
} else {
if (chr == c)
found = 1;
}
} while ((c = *p++) != ']');
if (found == invert)
return 0;
break;
}
dft: default:
if (squoted && *q == CTLESC)
q++;
if (*q++ != c)
return 0;
break;
}
}
breakloop:
if (*q != '\0')
return 0;
return 1;
}
#endif
 
 
 
/*
* Remove any CTLESC characters from a string.
*/
 
#if defined(__GLIBC__) && !defined(GLOB_BROKEN)
void
rmescapes(str)
char *str;
{
_rmescapes(str, 0);
}
 
 
STATIC char *
_rmescapes(str, flag)
char *str;
int flag;
{
char *p, *q, *r;
 
p = str;
while (*p != CTLESC && *p != CTLQUOTEMARK) {
if (*p++ == '\0')
return str;
}
q = p;
r = str;
if (flag) {
size_t len = p - str;
q = r = stalloc(strlen(p) + len + 1);
if (len > 0) {
memcpy(q, str, len);
q += len;
}
}
while (*p) {
if (*p == CTLQUOTEMARK) {
p++;
continue;
}
if (*p == CTLESC)
p++;
*q++ = *p++;
}
*q = '\0';
return r;
}
#else
void
rmescapes(str)
char *str;
{
char *p, *q;
 
p = str;
while (*p != CTLESC && *p != CTLQUOTEMARK) {
if (*p++ == '\0')
return;
}
q = p;
while (*p) {
if (*p == CTLQUOTEMARK) {
p++;
continue;
}
if (*p == CTLESC)
p++;
*q++ = *p++;
}
*q = '\0';
}
#endif
 
 
 
/*
* See if a pattern matches in a case statement.
*/
 
int
casematch(pattern, val)
union node *pattern;
char *val;
{
struct stackmark smark;
int result;
char *p;
 
setstackmark(&smark);
argbackq = pattern->narg.backquote;
STARTSTACKSTR(expdest);
ifslastp = NULL;
argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
STPUTC('\0', expdest);
p = grabstackstr(expdest);
result = patmatch(p, val, 0);
popstackmark(&smark);
return result;
}
 
/*
* Our own itoa().
*/
 
STATIC char *
cvtnum(num, buf)
int num;
char *buf;
{
char temp[32];
int neg = num < 0;
char *p = temp + 31;
 
temp[31] = '\0';
 
do {
*--p = num % 10 + '0';
} while ((num /= 10) != 0);
 
if (neg)
*--p = '-';
 
while (*p)
STPUTC(*p++, buf);
return buf;
}
/trunk/uspace/app/ash/mail.c
0,0 → 1,125
/* $NetBSD: mail.c,v 1.14 2000/07/03 03:26:19 matt 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
 
#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.14 2000/07/03 03:26:19 matt Exp $");
#endif
#endif /* not lint */
 
/*
* Routines to check for mail. (Perhaps make part of main.c?)
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
 
#include "shell.h"
#include "exec.h" /* defines padvance() */
#include "var.h"
#include "output.h"
#include "memalloc.h"
#include "error.h"
#include "mail.h"
 
 
#define MAXMBOXES 10
 
 
STATIC int nmboxes; /* number of mailboxes */
STATIC time_t mailtime[MAXMBOXES]; /* times of mailboxes */
 
 
 
/*
* Print appropriate message(s) if mail has arrived. If the argument is
* nozero, then the value of MAIL has changed, so we just update the
* values.
*/
 
void
chkmail(silent)
int silent;
{
int i;
const char *mpath;
char *p;
char *q;
struct stackmark smark;
struct stat statb;
 
if (silent)
nmboxes = 10;
if (nmboxes == 0)
return;
setstackmark(&smark);
mpath = mpathset()? mpathval() : mailval();
for (i = 0 ; i < nmboxes ; i++) {
p = padvance(&mpath, nullstr);
if (p == NULL)
break;
if (*p == '\0')
continue;
for (q = p ; *q ; q++);
if (q[-1] != '/')
abort();
q[-1] = '\0'; /* delete trailing '/' */
#ifdef notdef /* this is what the System V shell claims to do (it lies) */
if (stat(p, &statb) < 0)
statb.st_mtime = 0;
if (statb.st_mtime > mailtime[i] && ! silent) {
out2str(pathopt? pathopt : "you have mail");
out2c('\n');
}
mailtime[i] = statb.st_mtime;
#else /* this is what it should do */
if (stat(p, &statb) < 0)
statb.st_size = 0;
if (statb.st_size > mailtime[i] && ! silent) {
out2str(pathopt? pathopt : "you have mail");
out2c('\n');
}
mailtime[i] = statb.st_size;
#endif
}
nmboxes = i;
popstackmark(&smark);
}
/trunk/uspace/app/ash/miscbltin.c
0,0 → 1,422
/* $NetBSD: miscbltin.c,v 1.29 2001/01/04 15:39:51 lukem 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
 
#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.29 2001/01/04 15:39:51 lukem Exp $");
#endif
#endif /* not lint */
 
/*
* Miscelaneous builtins.
*/
 
#include <sys/types.h> /* quad_t */
#include <sys/param.h> /* BSD4_4 */
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
 
#include "shell.h"
#include "options.h"
#include "var.h"
#include "output.h"
#include "memalloc.h"
#include "error.h"
#include "miscbltin.h"
#include "mystring.h"
 
#undef rflag
 
#ifdef __GLIBC__
mode_t getmode(const void *, mode_t);
void *setmode(const char *);
 
#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
typedef enum __rlimit_resource rlim_t;
#endif
#endif
 
extern char **argptr; /* argument list for builtin command */
 
 
/*
* The read builtin. The -e option causes backslashes to escape the
* following character.
*
* This uses unbuffered input, which may be avoidable in some cases.
*/
 
int
readcmd(argc, argv)
int argc;
char **argv;
{
char **ap;
int backslash;
char c;
int rflag;
char *prompt;
char *ifs;
char *p;
int startword;
int status;
int i;
 
rflag = 0;
prompt = NULL;
while ((i = nextopt("p:r")) != '\0') {
if (i == 'p')
prompt = optarg;
else
rflag = 1;
}
if (prompt && isatty(0)) {
out2str(prompt);
flushall();
}
if (*(ap = argptr) == NULL)
error("arg count");
if ((ifs = bltinlookup("IFS", 1)) == NULL)
ifs = nullstr;
status = 0;
startword = 1;
backslash = 0;
STARTSTACKSTR(p);
for (;;) {
if (read(0, &c, 1) != 1) {
status = 1;
break;
}
if (c == '\0')
continue;
if (backslash) {
backslash = 0;
if (c != '\n')
STPUTC(c, p);
continue;
}
if (!rflag && c == '\\') {
backslash++;
continue;
}
if (c == '\n')
break;
if (startword && *ifs == ' ' && strchr(ifs, c)) {
continue;
}
startword = 0;
if (backslash && c == '\\') {
if (read(0, &c, 1) != 1) {
status = 1;
break;
}
STPUTC(c, p);
} else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
STACKSTRNUL(p);
setvar(*ap, stackblock(), 0);
ap++;
startword = 1;
STARTSTACKSTR(p);
} else {
STPUTC(c, p);
}
}
STACKSTRNUL(p);
/* Remove trailing blanks */
while (stackblock() <= --p && strchr(ifs, *p) != NULL)
*p = '\0';
setvar(*ap, stackblock(), 0);
while (*++ap != NULL)
setvar(*ap, nullstr, 0);
return status;
}
 
 
 
int
umaskcmd(argc, argv)
int argc;
char **argv;
{
char *ap;
int mask;
int i;
int symbolic_mode = 0;
 
while ((i = nextopt("S")) != '\0') {
symbolic_mode = 1;
}
 
INTOFF;
mask = umask(0);
umask(mask);
INTON;
 
if ((ap = *argptr) == NULL) {
if (symbolic_mode) {
char u[4], g[4], o[4];
 
i = 0;
if ((mask & S_IRUSR) == 0)
u[i++] = 'r';
if ((mask & S_IWUSR) == 0)
u[i++] = 'w';
if ((mask & S_IXUSR) == 0)
u[i++] = 'x';
u[i] = '\0';
 
i = 0;
if ((mask & S_IRGRP) == 0)
g[i++] = 'r';
if ((mask & S_IWGRP) == 0)
g[i++] = 'w';
if ((mask & S_IXGRP) == 0)
g[i++] = 'x';
g[i] = '\0';
 
i = 0;
if ((mask & S_IROTH) == 0)
o[i++] = 'r';
if ((mask & S_IWOTH) == 0)
o[i++] = 'w';
if ((mask & S_IXOTH) == 0)
o[i++] = 'x';
o[i] = '\0';
 
out1fmt("u=%s,g=%s,o=%s\n", u, g, o);
} else {
out1fmt("%.4o\n", mask);
}
} else {
if (isdigit((unsigned char)*ap)) {
mask = 0;
do {
if (*ap >= '8' || *ap < '0')
error("Illegal number: %s", argv[1]);
mask = (mask << 3) + (*ap - '0');
} while (*++ap != '\0');
umask(mask);
} else {
void *set;
 
INTOFF;
if ((set = setmode(ap)) != 0) {
mask = getmode(set, ~mask & 0777);
ckfree(set);
}
INTON;
if (!set)
error("Illegal mode: %s", ap);
 
umask(~mask & 0777);
}
}
return 0;
}
 
/*
* ulimit builtin
*
* This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
* Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
* ash by J.T. Conklin.
*
* Public domain.
*/
 
struct limits {
const char *name;
int cmd;
int factor; /* multiply by to get rlim_{cur,max} values */
char option;
};
 
static const struct limits limits[] = {
#ifdef RLIMIT_CPU
{ "time(seconds)", RLIMIT_CPU, 1, 't' },
#endif
#ifdef RLIMIT_FSIZE
{ "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
#endif
#ifdef RLIMIT_DATA
{ "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
#endif
#ifdef RLIMIT_STACK
{ "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
#endif
#ifdef RLIMIT_CORE
{ "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
#endif
#ifdef RLIMIT_RSS
{ "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
#endif
#ifdef RLIMIT_MEMLOCK
{ "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
#endif
#ifdef RLIMIT_NPROC
{ "process(processes)", RLIMIT_NPROC, 1, 'p' },
#endif
#ifdef RLIMIT_NOFILE
{ "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
#endif
#ifdef RLIMIT_VMEM
{ "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' },
#endif
#ifdef RLIMIT_SWAP
{ "swap(kbytes)", RLIMIT_SWAP, 1024, 'w' },
#endif
{ (char *) 0, 0, 0, '\0' }
};
 
int
ulimitcmd(argc, argv)
int argc;
char **argv;
{
int c;
rlim_t val = 0;
enum { SOFT = 0x1, HARD = 0x2 }
how = SOFT | HARD;
const struct limits *l;
int set, all = 0;
int optc, what;
struct rlimit limit;
 
what = 'f';
while ((optc = nextopt("HSatfdsmcnpl")) != '\0')
switch (optc) {
case 'H':
how = HARD;
break;
case 'S':
how = SOFT;
break;
case 'a':
all = 1;
break;
default:
what = optc;
}
 
for (l = limits; l->name && l->option != what; l++)
;
if (!l->name)
error("internal error (%c)", what);
 
set = *argptr ? 1 : 0;
if (set) {
char *p = *argptr;
 
if (all || argptr[1])
error("too many arguments");
if (strcmp(p, "unlimited") == 0)
val = RLIM_INFINITY;
else {
val = (rlim_t) 0;
 
while ((c = *p++) >= '0' && c <= '9')
{
val = (val * 10) + (long)(c - '0');
if (val < (rlim_t) 0)
break;
}
if (c)
error("bad number");
val *= l->factor;
}
}
if (all) {
for (l = limits; l->name; l++) {
getrlimit(l->cmd, &limit);
if (how & SOFT)
val = limit.rlim_cur;
else if (how & HARD)
val = limit.rlim_max;
 
out1fmt("%-20s ", l->name);
if (val == RLIM_INFINITY)
out1fmt("unlimited\n");
else
{
val /= l->factor;
#ifdef BSD4_4
out1fmt("%lld\n", (long long) val);
#else
out1fmt("%ld\n", (long) val);
#endif
}
}
return 0;
}
 
getrlimit(l->cmd, &limit);
if (set) {
if (how & HARD)
limit.rlim_max = val;
if (how & SOFT)
limit.rlim_cur = val;
if (setrlimit(l->cmd, &limit) < 0)
error("error setting limit (%s)", strerror(errno));
} else {
if (how & SOFT)
val = limit.rlim_cur;
else if (how & HARD)
val = limit.rlim_max;
 
if (val == RLIM_INFINITY)
out1fmt("unlimited\n");
else
{
val /= l->factor;
#ifdef BSD4_4
out1fmt("%lld\n", (long long) val);
#else
out1fmt("%ld\n", (long) val);
#endif
}
}
return 0;
}
/trunk/uspace/app/ash/main.c
0,0 → 1,432
/* $NetBSD: main.c,v 1.39 2000/11/01 19:56:01 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
 
#include <sys/cdefs.h>
#ifndef lint
__COPYRIGHT("@(#) Copyright (c) 1991, 1993\n\
The Regents of the University of California. All rights reserved.\n");
#endif /* not lint */
 
#ifndef lint
#if 0
static char sccsid[] = "@(#)main.c 8.7 (Berkeley) 7/19/95";
#else
__RCSID("$NetBSD: main.c,v 1.39 2000/11/01 19:56:01 christos Exp $");
#endif
#endif /* not lint */
 
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
 
 
#include "shell.h"
#include "main.h"
#include "mail.h"
#include "options.h"
#include "output.h"
#include "parser.h"
#include "nodes.h"
#include "expand.h"
#include "eval.h"
#include "jobs.h"
#include "input.h"
#include "trap.h"
#include "var.h"
#include "show.h"
#include "memalloc.h"
#include "error.h"
#include "init.h"
#include "mystring.h"
#include "exec.h"
#include "cd.h"
 
#ifdef HETIO
#include "hetio.h"
#endif
 
#define PROFILE 0
 
int rootpid;
int rootshell;
STATIC union node *curcmd;
STATIC union node *prevcmd;
#if PROFILE
short profile_buf[16384];
extern int etext();
#endif
 
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
* profiles if we're a login shell, and then call cmdloop to execute
* commands. The setjmp call sets up the location to jump to when an
* exception occurs. When an exception occurs the variable "state"
* is used to figure out how far we had gotten.
*/
 
int
main(argc, argv)
int argc;
char **argv;
{
struct jmploc jmploc;
struct stackmark smark;
volatile int state;
char *shinit;
int priviliged;
 
priviliged = getuid() != geteuid() || getgid() != getegid();
 
#if PROFILE
monitor(4, etext, profile_buf, sizeof profile_buf, 50);
#endif
#if defined(linux) || defined(__GNU__)
signal(SIGCHLD, SIG_DFL);
#endif
state = 0;
if (setjmp(jmploc.loc)) {
/*
* When a shell procedure is executed, we raise the
* exception EXSHELLPROC to clean up before executing
* the shell procedure.
*/
switch (exception) {
case EXSHELLPROC:
rootpid = getpid();
rootshell = 1;
minusc = NULL;
state = 3;
break;
 
case EXEXEC:
exitstatus = exerrno;
break;
 
case EXERROR:
exitstatus = 2;
break;
 
default:
break;
}
 
if (exception != EXSHELLPROC) {
if (state == 0 || iflag == 0 || ! rootshell)
exitshell(exitstatus);
}
reset();
if (exception == EXINT
#if ATTY
&& (! attyset() || equal(termval(), "emacs"))
#endif
) {
out2c('\n');
flushout(&errout);
}
popstackmark(&smark);
FORCEINTON; /* enable interrupts */
if (state == 1)
goto state1;
else if (state == 2)
goto state2;
else if (state == 3)
goto state3;
else
goto state4;
}
handler = &jmploc;
#ifdef DEBUG
opentrace();
trputs("Shell args: "); trargs(argv);
#endif
rootpid = getpid();
rootshell = 1;
init();
setstackmark(&smark);
procargs(argc, argv);
if (argv[0] && argv[0][0] == '-') {
state = 1;
read_profile("/etc/profile");
state1:
state = 2;
if (priviliged == 0)
read_profile(".profile");
else
read_profile("/etc/suid_profile");
}
state2:
state = 3;
if (iflag && !priviliged) {
if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
state = 3;
read_profile(shinit);
}
}
state3:
state = 4;
if (sflag == 0 || minusc) {
static int sigs[] = {
SIGINT, SIGQUIT, SIGHUP,
#ifdef SIGTSTP
SIGTSTP,
#endif
SIGPIPE
};
#define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0]))
int i;
 
for (i = 0; i < SIGSSIZE; i++)
setsignal(sigs[i]);
}
 
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 */
}
 
 
/*
* Read and execute commands. "Top" is nonzero for the top level command
* loop; it turns on prompting if the shell is interactive.
*/
 
void
cmdloop(top)
int top;
{
union node *n;
struct stackmark smark;
int inter;
int numeof = 0;
 
TRACE(("cmdloop(%d) called\n", top));
setstackmark(&smark);
#ifdef HETIO
if(iflag && top)
hetio_init();
#endif
for (;;) {
if (pendingsigs)
dotrap();
inter = 0;
if (iflag && top) {
inter++;
showjobs(1);
chkmail(0);
flushout(&output);
}
n = parsecmd(inter);
/* showtree(n); DEBUG */
if (n == NEOF) {
if (!top || numeof >= 50)
break;
if (!stoppedjobs()) {
if (!Iflag)
break;
out2str("\nUse \"exit\" to leave shell.\n");
}
numeof++;
} else if (n != NULL && nflag == 0) {
job_warning = (job_warning == 2) ? 1 : 0;
numeof = 0;
evaltree(n, 0);
}
popstackmark(&smark);
setstackmark(&smark);
if (evalskip == SKIPFILE) {
evalskip = 0;
break;
}
}
popstackmark(&smark);
}
 
 
 
/*
* Read /etc/profile or .profile. Return on error.
*/
 
STATIC void
read_profile(name)
const char *name;
{
int fd;
int xflag_set = 0;
int vflag_set = 0;
 
INTOFF;
if ((fd = open(name, O_RDONLY)) >= 0)
setinputfd(fd, 1);
INTON;
if (fd < 0)
return;
/* -q turns off -x and -v just when executing init files */
if (qflag) {
if (xflag)
xflag = 0, xflag_set = 1;
if (vflag)
vflag = 0, vflag_set = 1;
}
cmdloop(0);
if (qflag) {
if (xflag_set)
xflag = 1;
if (vflag_set)
vflag = 1;
}
popfile();
}
 
 
 
/*
* Read a file containing shell functions.
*/
 
void
readcmdfile(name)
char *name;
{
int fd;
 
INTOFF;
if ((fd = open(name, O_RDONLY)) >= 0)
setinputfd(fd, 1);
else
error("Can't open %s", name);
INTON;
cmdloop(0);
popfile();
}
 
 
 
/*
* Take commands from a file. To be compatable we should do a path
* search for the file, which is necessary to find sub-commands.
*/
 
 
STATIC char *
find_dot_file(basename)
char *basename;
{
char *fullname;
const char *path = pathval();
struct stat statb;
 
/* don't try this for absolute or relative paths */
if (strchr(basename, '/'))
return basename;
 
while ((fullname = padvance(&path, basename)) != NULL) {
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;
}
stunalloc(fullname);
}
 
/* not found in the PATH */
error("%s: not found", basename);
/* NOTREACHED */
}
 
int
dotcmd(argc, argv)
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;
struct stackmark smark;
 
setstackmark(&smark);
fullname = find_dot_file(argv[1]);
setinputfile(fullname, 1);
commandname = fullname;
cmdloop(0);
popfile();
popstackmark(&smark);
}
return exitstatus;
}
 
 
int
exitcmd(argc, argv)
int argc;
char **argv;
{
extern int oexitstatus;
 
if (stoppedjobs())
return 0;
if (argc > 1)
exitstatus = number(argv[1]);
else
exitstatus = oexitstatus;
exitshell(exitstatus);
/* NOTREACHED */
}
/trunk/uspace/app/ash/expand.h
0,0 → 1,77
/* $NetBSD: expand.h,v 1.12 1999/07/09 03:05:50 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)expand.h 8.2 (Berkeley) 5/4/95
*/
 
struct strlist {
struct strlist *next;
char *text;
};
 
 
struct arglist {
struct strlist *list;
struct strlist **lastp;
};
 
/*
* expandarg() flags
*/
#define EXP_FULL 0x1 /* perform word splitting & file globbing */
#define EXP_TILDE 0x2 /* do normal tilde expansion */
#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
 
 
union node;
void expandhere (union node *, int);
void expandarg (union node *, struct arglist *, int);
void expari (int);
#if !(defined(__GLIBC__) && !defined(GLOB_BROKEN))
int patmatch (char *, char *, int);
#endif
void rmescapes (char *);
int casematch (union node *, char *);
 
/* From arith.y */
int arith (const char *);
int expcmd (int , char **);
void arith_lex_reset (void);
int yylex (void);
/trunk/uspace/app/ash/mail.h
0,0 → 1,41
/* $NetBSD: mail.h,v 1.8 1995/05/11 21:29:23 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)mail.h 8.2 (Berkeley) 5/4/95
*/
 
void chkmail (int);
/trunk/uspace/app/ash/eval.c
0,0 → 1,1159
/* $NetBSD: eval.c,v 1.56 2000/05/22 10:18:46 elric 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
 
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)eval.c 8.9 (Berkeley) 6/8/95";
#else
__RCSID("$NetBSD: eval.c,v 1.56 2000/05/22 10:18:46 elric Exp $");
#endif
#endif /* not lint */
 
#include <sys/types.h>
#include <signal.h>
#include <malloc.h>
#include <unistd.h>
 
/*
* Evaluate a command.
*/
 
#include "shell.h"
#include "nodes.h"
#include "syntax.h"
#include "expand.h"
#include "parser.h"
#include "jobs.h"
#include "eval.h"
#include "builtins.h"
#include "options.h"
#include "exec.h"
#include "redir.h"
#include "input.h"
#include "output.h"
#include "trap.h"
#include "var.h"
#include "memalloc.h"
#include "error.h"
#include "show.h"
#include "mystring.h"
#ifndef SMALL
#include "myhistedit.h"
#endif
 
 
/* flags in argument to evaltree */
#define EV_EXIT 01 /* exit after evaluating tree */
#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
#define EV_BACKCMD 04 /* command executing within back quotes */
 
MKINIT int evalskip; /* set if we are skipping commands */
STATIC int skipcount; /* number of levels to skip */
MKINIT int loopnest; /* current loop nesting level */
int funcnest; /* depth of function calls */
 
 
char *commandname;
struct strlist *cmdenviron;
int exitstatus; /* exit status of last command */
int oexitstatus; /* saved exit status */
 
 
STATIC void evalloop (union node *, int);
STATIC void evalfor (union node *, int);
STATIC void evalcase (union node *, int);
STATIC void evalsubshell (union node *, int);
STATIC void expredir (union node *);
STATIC void evalpipe (union node *);
STATIC void evalcommand (union node *, int, struct backcmd *);
STATIC void prehash (union node *);
STATIC int is_assignment_builtin (const char *);
STATIC const char *get_standard_path (void);
 
 
/*
* Called to reset things after an exception.
*/
 
#ifdef mkinit
INCLUDE "eval.h"
 
RESET {
evalskip = 0;
loopnest = 0;
funcnest = 0;
}
 
SHELLPROC {
exitstatus = 0;
}
#endif
 
 
 
/*
* The eval commmand.
*/
 
int
evalcmd(argc, argv)
int argc;
char **argv;
{
char *p;
char *concat;
char **ap;
 
if (argc > 1) {
p = argv[1];
if (argc > 2) {
STARTSTACKSTR(concat);
ap = argv + 2;
for (;;) {
while (*p)
STPUTC(*p++, concat);
if ((p = *ap++) == NULL)
break;
STPUTC(' ', concat);
}
STPUTC('\0', concat);
p = grabstackstr(concat);
}
evalstring(p, EV_TESTED);
}
return exitstatus;
}
 
 
/*
* Execute a command or commands contained in a string.
*/
 
void
evalstring(s, flag)
char *s;
int flag;
{
union node *n;
struct stackmark smark;
 
setstackmark(&smark);
setinputstring(s, 1);
while ((n = parsecmd(0)) != NEOF) {
evaltree(n, flag);
popstackmark(&smark);
}
popfile();
popstackmark(&smark);
}
 
 
 
/*
* Evaluate a parse tree. The value is left in the global variable
* exitstatus.
*/
 
void
evaltree(n, flags)
union node *n;
int flags;
{
if (n == NULL) {
TRACE(("evaltree(NULL) called\n"));
exitstatus = 0;
goto out;
}
#ifndef SMALL
displayhist = 1; /* show history substitutions done with fc */
#endif
TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
switch (n->type) {
case NSEMI:
evaltree(n->nbinary.ch1, flags & EV_TESTED);
if (evalskip)
goto out;
evaltree(n->nbinary.ch2, flags);
break;
case NAND:
evaltree(n->nbinary.ch1, EV_TESTED);
if (evalskip || exitstatus != 0) {
/* don't bomb out on "set -e; false && true" */
flags |= EV_TESTED;
goto out;
}
evaltree(n->nbinary.ch2, flags | EV_TESTED);
break;
case NOR:
evaltree(n->nbinary.ch1, EV_TESTED);
if (evalskip || exitstatus == 0)
goto out;
evaltree(n->nbinary.ch2, flags | EV_TESTED);
break;
case NREDIR:
expredir(n->nredir.redirect);
redirect(n->nredir.redirect, REDIR_PUSH);
evaltree(n->nredir.n, flags);
popredir();
break;
case NSUBSHELL:
evalsubshell(n, flags);
break;
case NBACKGND:
evalsubshell(n, flags);
break;
case NIF: {
evaltree(n->nif.test, EV_TESTED);
if (evalskip)
goto out;
if (exitstatus == 0)
evaltree(n->nif.ifpart, flags);
else if (n->nif.elsepart)
evaltree(n->nif.elsepart, flags);
else
exitstatus = 0;
break;
}
case NWHILE:
case NUNTIL:
evalloop(n, flags);
break;
case NFOR:
evalfor(n, flags);
break;
case NCASE:
evalcase(n, flags);
break;
case NDEFUN:
if (is_special_builtin(n->narg.text)) {
outfmt(out2, "%s is a special built-in\n", n->narg.text);
exitstatus = 1;
break;
}
defun(n->narg.text, n->narg.next);
exitstatus = 0;
break;
case NNOT:
evaltree(n->nnot.com, EV_TESTED);
exitstatus = !exitstatus;
break;
 
case NPIPE:
evalpipe(n);
break;
case NCMD:
evalcommand(n, flags, (struct backcmd *)NULL);
break;
default:
out1fmt("Node type = %d\n", n->type);
flushout(&output);
break;
}
out:
if (pendingsigs)
dotrap();
if ((flags & EV_EXIT) || (eflag && exitstatus && !(flags & EV_TESTED)))
exitshell(exitstatus);
}
 
 
STATIC void
evalloop(n, flags)
union node *n;
int flags;
{
int status;
 
loopnest++;
status = 0;
for (;;) {
evaltree(n->nbinary.ch1, EV_TESTED);
if (evalskip) {
skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
evalskip = 0;
continue;
}
if (evalskip == SKIPBREAK && --skipcount <= 0)
evalskip = 0;
break;
}
if (n->type == NWHILE) {
if (exitstatus != 0)
break;
} else {
if (exitstatus == 0)
break;
}
evaltree(n->nbinary.ch2, flags & EV_TESTED);
status = exitstatus;
if (evalskip)
goto skipping;
}
loopnest--;
exitstatus = status;
}
 
 
 
STATIC void
evalfor(n, flags)
union node *n;
int flags;
{
struct arglist arglist;
union node *argp;
struct strlist *sp;
struct stackmark smark;
 
setstackmark(&smark);
arglist.lastp = &arglist.list;
for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
oexitstatus = exitstatus;
expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
if (evalskip)
goto out;
}
*arglist.lastp = NULL;
 
exitstatus = 0;
loopnest++;
for (sp = arglist.list ; sp ; sp = sp->next) {
setvar(n->nfor.var, sp->text, 0);
evaltree(n->nfor.body, flags & EV_TESTED);
if (evalskip) {
if (evalskip == SKIPCONT && --skipcount <= 0) {
evalskip = 0;
continue;
}
if (evalskip == SKIPBREAK && --skipcount <= 0)
evalskip = 0;
break;
}
}
loopnest--;
out:
popstackmark(&smark);
}
 
 
 
STATIC void
evalcase(n, flags)
union node *n;
int flags;
{
union node *cp;
union node *patp;
struct arglist arglist;
struct stackmark smark;
 
setstackmark(&smark);
arglist.lastp = &arglist.list;
oexitstatus = exitstatus;
expandarg(n->ncase.expr, &arglist, EXP_TILDE);
for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
if (casematch(patp, arglist.list->text)) {
if (evalskip == 0) {
evaltree(cp->nclist.body, flags);
}
goto out;
}
}
}
out:
popstackmark(&smark);
}
 
 
 
/*
* Kick off a subshell to evaluate a tree.
*/
 
STATIC void
evalsubshell(n, flags)
union node *n;
int flags;
{
struct job *jp;
int backgnd = (n->type == NBACKGND);
 
expredir(n->nredir.redirect);
jp = makejob(n, 1);
if (forkshell(jp, n, backgnd) == 0) {
if (backgnd)
flags &=~ EV_TESTED;
redirect(n->nredir.redirect, 0);
evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
}
if (! backgnd) {
INTOFF;
exitstatus = waitforjob(jp);
INTON;
}
}
 
 
 
/*
* Compute the names of the files in a redirection list.
*/
 
STATIC void
expredir(n)
union node *n;
{
union node *redir;
 
for (redir = n ; redir ; redir = redir->nfile.next) {
struct arglist fn;
fn.lastp = &fn.list;
oexitstatus = exitstatus;
switch (redir->type) {
case NFROMTO:
case NFROM:
case NTO:
case NAPPEND:
case NTOOV:
expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
redir->nfile.expfname = fn.list->text;
break;
case NFROMFD:
case NTOFD:
if (redir->ndup.vname) {
expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
fixredir(redir, fn.list->text, 1);
}
break;
}
}
}
 
 
 
/*
* Evaluate a pipeline. All the processes in the pipeline are children
* of the process creating the pipeline. (This differs from some versions
* of the shell, which make the last process in a pipeline the parent
* of all the rest.)
*/
 
STATIC void
evalpipe(n)
union node *n;
{
struct job *jp;
struct nodelist *lp;
int pipelen;
int prevfd;
int pip[2];
 
TRACE(("evalpipe(0x%lx) called\n", (long)n));
pipelen = 0;
for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
pipelen++;
INTOFF;
jp = makejob(n, pipelen);
prevfd = -1;
for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
prehash(lp->n);
pip[1] = -1;
if (lp->next) {
if (pipe(pip) < 0) {
close(prevfd);
error("Pipe call failed");
}
}
if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
INTON;
if (prevfd > 0) {
close(0);
copyfd(prevfd, 0);
close(prevfd);
if (pip[0] == 0) {
pip[0] = -1;
}
}
if (pip[1] >= 0) {
if (pip[0] >= 0) {
close(pip[0]);
}
if (pip[1] != 1) {
close(1);
copyfd(pip[1], 1);
close(pip[1]);
}
}
evaltree(lp->n, EV_EXIT);
}
if (prevfd >= 0)
close(prevfd);
prevfd = pip[0];
close(pip[1]);
}
INTON;
if (n->npipe.backgnd == 0) {
INTOFF;
exitstatus = waitforjob(jp);
TRACE(("evalpipe: job done exit status %d\n", exitstatus));
INTON;
}
}
 
 
 
/*
* Execute a command inside back quotes. If it's a builtin command, we
* want to save its output in a block obtained from malloc. Otherwise
* we fork off a subprocess and get the output of the command via a pipe.
* Should be called with interrupts off.
*/
 
void
evalbackcmd(n, result)
union node *n;
struct backcmd *result;
{
int pip[2];
struct job *jp;
struct stackmark smark; /* unnecessary */
 
setstackmark(&smark);
result->fd = -1;
result->buf = NULL;
result->nleft = 0;
result->jp = NULL;
if (n == NULL) {
exitstatus = 0;
goto out;
}
#ifdef notyet
/*
* For now we disable executing builtins in the same
* context as the shell, because we are not keeping
* enough state to recover from changes that are
* supposed only to affect subshells. eg. echo "`cd /`"
*/
if (n->type == NCMD) {
exitstatus = oexitstatus;
evalcommand(n, EV_BACKCMD, result);
} else
#endif
{
exitstatus = 0;
if (pipe(pip) < 0)
error("Pipe call failed");
jp = makejob(n, 1);
if (forkshell(jp, n, FORK_NOJOB) == 0) {
FORCEINTON;
close(pip[0]);
if (pip[1] != 1) {
close(1);
copyfd(pip[1], 1);
close(pip[1]);
}
eflag = 0;
evaltree(n, EV_EXIT);
}
close(pip[1]);
result->fd = pip[0];
result->jp = jp;
}
out:
popstackmark(&smark);
TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
result->fd, result->buf, result->nleft, result->jp));
}
 
 
 
/*
* Execute a simple command.
*/
 
STATIC void
evalcommand(cmd, flags, backcmd)
union node *cmd;
int flags;
struct backcmd *backcmd;
{
struct stackmark smark;
union node *argp;
struct arglist arglist;
struct arglist varlist;
char **argv;
int argc;
char **envp;
int varflag;
int pseudovarflag;
struct strlist *sp;
int mode;
int pip[2];
struct cmdentry cmdentry;
struct job *jp;
struct jmploc jmploc;
struct jmploc *volatile savehandler;
char *volatile savecmdname;
volatile struct shparam saveparam;
struct localvar *volatile savelocalvars;
volatile int e;
char *lastarg;
int not_special;
const char *path;
const char *standard_path;
#if __GNUC__
/* Avoid longjmp clobbering */
(void) &argv;
(void) &argc;
(void) &lastarg;
(void) &flags;
(void) &not_special;
(void) &standard_path;
#endif
 
/* First expand the arguments. */
TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
setstackmark(&smark);
arglist.lastp = &arglist.list;
varlist.lastp = &varlist.list;
arglist.list = 0;
varflag = 1;
pseudovarflag = 0;
oexitstatus = exitstatus;
exitstatus = 0;
not_special = 0;
path = pathval();
standard_path = NULL;
for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
char *p = argp->narg.text;
if ((varflag || pseudovarflag) && is_name(*p)) {
do {
p++;
} while (is_in_name(*p));
if (*p == '=') {
if (varflag)
expandarg(argp, &varlist, EXP_VARTILDE);
else
expandarg(argp, &arglist, EXP_VARTILDE);
continue;
}
}
expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
if (varflag && arglist.list && is_assignment_builtin(arglist.list->text))
pseudovarflag = 1;
varflag = 0;
}
*arglist.lastp = NULL;
*varlist.lastp = NULL;
expredir(cmd->ncmd.redirect);
argc = 0;
for (sp = arglist.list ; sp ; sp = sp->next)
argc++;
argv = stalloc(sizeof (char *) * (argc + 1));
 
for (sp = arglist.list ; sp ; sp = sp->next) {
TRACE(("evalcommand arg: %s\n", sp->text));
*argv++ = sp->text;
}
*argv = NULL;
lastarg = NULL;
if (iflag && funcnest == 0 && argc > 0)
lastarg = argv[-1];
argv -= argc;
 
/* Print the command if xflag is set. */
if (xflag) {
outc('+', &errout);
for (sp = varlist.list ; sp ; sp = sp->next) {
outc(' ', &errout);
out2str(sp->text);
}
for (sp = arglist.list ; sp ; sp = sp->next) {
outc(' ', &errout);
out2str(sp->text);
}
outc('\n', &errout);
flushout(&errout);
}
 
/* Now locate the command. */
if (argc == 0) {
cmdentry.cmdtype = CMDBUILTIN;
cmdentry.u.index = BLTINCMD;
} else {
static const char PATH[] = "PATH=";
const char *oldpath = NULL;
int findflag = DO_ERR;
 
/*
* Modify the command lookup path, if a PATH= assignment
* is present
*/
for (sp = varlist.list ; sp ; sp = sp->next)
if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0) {
path = sp->text + sizeof(PATH) - 1;
findflag |= DO_BRUTE;
}
for(;;) {
find_command(argv[0], &cmdentry, findflag, path);
if (oldpath) {
path = oldpath;
oldpath = NULL;
}
if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */
exitstatus = 127;
flushout(&errout);
goto out;
}
/* implement the bltin builtin here */
if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) {
not_special = 1;
for(;;) {
argv++;
if (--argc == 0)
break;
if ((cmdentry.u.index = find_builtin(*argv)) < 0) {
outfmt(&errout, "%s: not found\n", *argv);
exitstatus = 127;
flushout(&errout);
goto out;
}
if (cmdentry.u.index != BLTINCMD)
break;
}
}
if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == COMMANDCMD) {
not_special = 1;
argv++;
if (--argc == 0) {
exitstatus = 0;
goto out;
}
if (*argv[0] == '-') {
if (!equal(argv[0], "-p")) {
argv--;
argc++;
break;
}
argv++;
if (--argc == 0) {
exitstatus = 0;
goto out;
}
if (!standard_path) {
standard_path = get_standard_path();
}
oldpath = path;
path = standard_path;
findflag |= DO_BRUTE;
}
findflag |= DO_NOFUN;
continue;
}
break;
}
}
 
/* Fork off a child process if necessary. */
if (cmd->ncmd.backgnd
|| (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
|| ((flags & EV_BACKCMD) != 0
&& (cmdentry.cmdtype != CMDBUILTIN
|| cmdentry.u.index == DOTCMD
|| cmdentry.u.index == EVALCMD))) {
jp = makejob(cmd, 1);
mode = cmd->ncmd.backgnd;
if (flags & EV_BACKCMD) {
mode = FORK_NOJOB;
if (pipe(pip) < 0)
error("Pipe call failed");
}
if (forkshell(jp, cmd, mode) != 0)
goto parent; /* at end of routine */
if (flags & EV_BACKCMD) {
FORCEINTON;
close(pip[0]);
if (pip[1] != 1) {
close(1);
copyfd(pip[1], 1);
close(pip[1]);
}
}
flags |= EV_EXIT;
}
 
/* This is the child process if a fork occurred. */
/* Execute the command. */
if (cmdentry.cmdtype == CMDFUNCTION) {
#ifdef DEBUG
trputs("Shell function: "); trargs(argv);
#endif
exitstatus = oexitstatus;
redirect(cmd->ncmd.redirect, REDIR_PUSH);
saveparam = shellparam;
shellparam.malloc = 0;
shellparam.nparam = argc - 1;
shellparam.p = argv + 1;
INTOFF;
savelocalvars = localvars;
localvars = NULL;
INTON;
if (setjmp(jmploc.loc)) {
if (exception == EXSHELLPROC) {
freeparam((volatile struct shparam *)
&saveparam);
} else {
saveparam.optind = shellparam.optind;
saveparam.optoff = shellparam.optoff;
freeparam(&shellparam);
shellparam = saveparam;
}
poplocalvars();
localvars = savelocalvars;
handler = savehandler;
longjmp(handler->loc, 1);
}
savehandler = handler;
handler = &jmploc;
for (sp = varlist.list ; sp ; sp = sp->next)
mklocal(sp->text);
funcnest++;
evaltree(cmdentry.u.func, flags & EV_TESTED);
funcnest--;
INTOFF;
poplocalvars();
localvars = savelocalvars;
saveparam.optind = shellparam.optind;
saveparam.optoff = shellparam.optoff;
freeparam(&shellparam);
shellparam = saveparam;
handler = savehandler;
popredir();
INTON;
if (evalskip == SKIPFUNC) {
evalskip = 0;
skipcount = 0;
}
if (flags & EV_EXIT)
exitshell(exitstatus);
} else if (cmdentry.cmdtype == CMDBUILTIN) {
#ifdef DEBUG
trputs("builtin command: "); trargs(argv);
#endif
mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH;
if (flags == EV_BACKCMD) {
#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
openmemout();
#else
memout.nleft = 0;
memout.nextc = memout.buf;
memout.bufsize = 64;
#endif
mode |= REDIR_BACKQ;
}
redirect(cmd->ncmd.redirect, mode);
savecmdname = commandname;
cmdenviron = varlist.list;
e = -1;
if (setjmp(jmploc.loc)) {
e = exception;
exitstatus = (e == EXINT)? SIGINT+128 : 2;
goto cmddone;
}
savehandler = handler;
handler = &jmploc;
commandname = argv[0];
argptr = argv + 1;
optptr = NULL; /* initialize nextopt */
exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv);
flushall();
cmddone:
out1 = &output;
out2 = &errout;
freestdout();
if (!not_special && is_special_builtin(commandname))
listsetvar(cmdenviron);
cmdenviron = NULL;
if (e != EXSHELLPROC) {
commandname = savecmdname;
if (flags & EV_EXIT)
exitshell(exitstatus);
}
handler = savehandler;
if (e != -1) {
if ((e != EXERROR && e != EXEXEC)
|| cmdentry.u.index == BLTINCMD
|| cmdentry.u.index == DOTCMD
|| cmdentry.u.index == EVALCMD
#ifndef SMALL
|| cmdentry.u.index == HISTCMD
#endif
|| cmdentry.u.index == EXECCMD)
exraise(e);
FORCEINTON;
}
if (cmdentry.u.index != EXECCMD)
popredir();
if (flags == EV_BACKCMD) {
#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
closememout();
#endif
backcmd->buf = memout.buf;
#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
backcmd->nleft = memout.bufsize;
#else
backcmd->nleft = memout.nextc - memout.buf;
#endif
memout.buf = NULL;
}
cmdenviron = NULL;
} else {
#ifdef DEBUG
trputs("normal command: "); trargs(argv);
#endif
clearredir();
redirect(cmd->ncmd.redirect, 0);
for (sp = varlist.list ; sp ; sp = sp->next)
setvareq(sp->text, VEXPORT|VSTACK);
envp = environment();
shellexec(argv, envp, path, cmdentry.u.index);
}
goto out;
 
parent: /* parent process gets here (if we forked) */
if (mode == 0) { /* argument to fork */
INTOFF;
exitstatus = waitforjob(jp);
INTON;
} else if (mode == 2) {
backcmd->fd = pip[0];
close(pip[1]);
backcmd->jp = jp;
}
 
out:
if (lastarg)
setvar("_", lastarg, 0);
popstackmark(&smark);
 
if (eflag && exitstatus && !(flags & EV_TESTED))
exitshell(exitstatus);
}
 
 
 
/*
* Search for a command. This is called before we fork so that the
* location of the command will be available in the parent as well as
* the child. The check for "goodname" is an overly conservative
* check that the name will not be subject to expansion.
*/
 
STATIC void
prehash(n)
union node *n;
{
struct cmdentry entry;
 
if (n->type == NCMD && n->ncmd.args)
if (goodname(n->ncmd.args->narg.text))
find_command(n->ncmd.args->narg.text, &entry, 0,
pathval());
}
 
 
 
/*
* Builtin commands. Builtin commands whose functions are closely
* tied to evaluation are implemented here.
*/
 
/*
* No command given, or a bltin command with no arguments. Set the
* specified variables.
*/
 
int
bltincmd(argc, argv)
int argc;
char **argv;
{
listsetvar(cmdenviron);
/*
* Preserve exitstatus of a previous possible redirection
* as POSIX mandates
*/
return exitstatus;
}
 
 
/*
* Handle break and continue commands. Break, continue, and return are
* all handled by setting the evalskip flag. The evaluation routines
* above all check this flag, and if it is set they start skipping
* commands rather than executing them. The variable skipcount is
* the number of loops to break/continue, or the number of function
* levels to return. (The latter is always 1.) It should probably
* be an error to break out of more loops than exist, but it isn't
* in the standard shell so we don't make it one here.
*/
 
int
breakcmd(argc, argv)
int argc;
char **argv;
{
int n = argc > 1 ? number(argv[1]) : 1;
 
if (n > loopnest)
n = loopnest;
if (n > 0) {
evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
skipcount = n;
}
return 0;
}
 
 
/*
* The return command.
*/
 
int
returncmd(argc, argv)
int argc;
char **argv;
{
int ret = argc > 1 ? number(argv[1]) : oexitstatus;
 
if (funcnest) {
evalskip = SKIPFUNC;
skipcount = 1;
return ret;
}
else {
/* Do what ksh does; skip the rest of the file */
evalskip = SKIPFILE;
skipcount = 1;
return ret;
}
}
 
 
int
falsecmd(argc, argv)
int argc;
char **argv;
{
return 1;
}
 
 
int
truecmd(argc, argv)
int argc;
char **argv;
{
return 0;
}
 
 
int
execcmd(argc, argv)
int argc;
char **argv;
{
if (argc > 1) {
struct strlist *sp;
 
iflag = 0; /* exit on error */
mflag = 0;
optschanged();
for (sp = cmdenviron; sp ; sp = sp->next)
setvareq(sp->text, VEXPORT|VSTACK);
shellexec(argv + 1, environment(), pathval(), 0);
}
return 0;
}
 
STATIC int
is_assignment_builtin (command)
const char *command;
{
static const char *assignment_builtins[] = {
"alias", "declare", "export", "local", "readonly", "typeset",
(char *)NULL
};
int i;
 
for (i = 0; assignment_builtins[i]; i++)
if (strcmp(command, assignment_builtins[i]) == 0) return 1;
return 0;
}
 
int
is_special_builtin(name)
const char *name;
{
static const char *special_builtins[] = {
"break", ":", ".", "continue", "eval", "exec", "exit",
"export", "readonly", "return", "set", "shift", "times",
"trap", "unset", (char *)NULL
};
int i;
 
if (!name) return 0;
for (i = 0; special_builtins[i]; i++)
if (equal(name, special_builtins[i])) return 1;
return 0;
}
 
STATIC const char *
get_standard_path()
{
char *p;
size_t len;
 
len = confstr(_CS_PATH, NULL, 0);
p = stalloc(len + 2);
*p = '\0';
confstr(_CS_PATH, p, len);
return p;
}
/trunk/uspace/app/ash/var.c
0,0 → 1,777
/* $NetBSD: var.c,v 1.26 2000/12/20 00:15:10 cgd 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
 
#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.26 2000/12/20 00:15:10 cgd Exp $");
#endif
#endif /* not lint */
 
#include <unistd.h>
#include <stdlib.h>
#include <paths.h>
 
/*
* Shell variables.
*/
 
#include "shell.h"
#include "output.h"
#include "expand.h"
#include "nodes.h" /* for other headers */
#include "eval.h" /* defines cmdenviron */
#include "exec.h"
#include "syntax.h"
#include "options.h"
#include "mail.h"
#include "var.h"
#include "memalloc.h"
#include "error.h"
#include "mystring.h"
#include "parser.h"
#ifndef SMALL
#include "myhistedit.h"
#endif
 
 
#define VTABSIZE 39
 
 
struct varinit {
struct var *var;
int flags;
const char *text;
void (*func) (const char *);
};
 
 
#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 vps1;
struct var vps2;
struct var vvers;
struct var voptind;
 
const struct varinit varinit[] = {
#if ATTY
{ &vatty, VSTRFIXED|VTEXTFIXED|VUNSET, "ATTY=",
NULL },
#endif
#ifndef SMALL
{ &vhistsize, VSTRFIXED|VTEXTFIXED|VUNSET, "HISTSIZE=",
sethistsize },
#endif
{ &vifs, VSTRFIXED|VTEXTFIXED, "IFS= \t\n",
NULL },
{ &vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=",
NULL },
{ &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=",
NULL },
{ &vpath, VSTRFIXED|VTEXTFIXED, "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
changepath },
/*
* vps1 depends on uid
*/
{ &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ",
NULL },
#ifndef SMALL
{ &vterm, VSTRFIXED|VTEXTFIXED|VUNSET, "TERM=",
setterm },
#endif
{ &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1",
getoptsreset },
{ NULL, 0, NULL,
NULL }
};
 
struct var *vartab[VTABSIZE];
 
STATIC struct var **hashvar (const char *);
STATIC int varequal (const char *, const char *);
 
/*
* Initialize the varable symbol tables and import the environment
* Setting PWD added by herbert
*/
 
#ifdef mkinit
INCLUDE "cd.h"
INCLUDE "var.h"
INIT {
char **envp;
extern char **environ;
extern char *curdir;
 
initvar();
for (envp = environ ; *envp ; envp++) {
if (strchr(*envp, '=')) {
setvareq(*envp, VEXPORT|VTEXTFIXED);
}
}
 
getpwd();
setvar("PWD", curdir, VEXPORT|VTEXTFIXED);
}
#endif
 
 
/*
* This routine initializes the builtin variables. It is called when the
* shell is initialized and again when a shell procedure is spawned.
*/
 
void
initvar() {
const struct varinit *ip;
struct var *vp;
struct var **vpp;
char ppid[30];
 
for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
if ((vp->flags & VEXPORT) == 0) {
vpp = hashvar(ip->text);
vp->next = *vpp;
*vpp = vp;
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=");
vps1.next = *vpp;
*vpp = &vps1;
vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# ");
vps1.flags = VSTRFIXED|VTEXTFIXED;
}
snprintf(ppid, 29, "%ld", (long)getppid());
setvar("PPID", ppid, VREADONLY|VNOFUNC);
}
 
/*
* Safe version of setvar, returns 1 on success 0 on failure.
*/
 
int
setvarsafe(name, val, flags)
const char *name, *val;
int flags;
{
struct jmploc jmploc;
struct jmploc *volatile savehandler = handler;
int err = 0;
#ifdef __GNUC__
(void) &err;
#endif
 
if (setjmp(jmploc.loc))
err = 1;
else {
handler = &jmploc;
setvar(name, val, flags);
}
handler = savehandler;
return err;
}
 
/*
* Set the value of a variable. The flags argument is ored with the
* flags of the variable. If val is NULL, the variable is unset.
*/
 
void
setvar(name, val, flags)
const char *name, *val;
int flags;
{
const char *p;
const char *q;
char *d;
int len;
int namelen;
char *nameeq;
int isbad;
 
isbad = 0;
p = name;
if (! is_name(*p))
isbad = 1;
p++;
for (;;) {
if (! is_in_name(*p)) {
if (*p == '\0' || *p == '=')
break;
isbad = 1;
}
p++;
}
namelen = p - name;
if (isbad)
error("%.*s: bad variable name", namelen, name);
len = namelen + 2; /* 2 is space for '=' and '\0' */
if (val == NULL) {
flags |= VUNSET;
} else {
len += strlen(val);
}
d = nameeq = ckmalloc(len);
q = name;
while (--namelen >= 0)
*d++ = *q++;
*d++ = '=';
*d = '\0';
if (val)
scopy(val, d);
setvareq(nameeq, flags);
}
 
 
 
/*
* Same as setvar except that the variable and value are passed in
* the first argument as name=value. Since the first argument will
* be actually stored in the table, it should not be a string that
* will go away.
*/
 
void
setvareq(s, flags)
char *s;
int flags;
{
struct var *vp, **vpp;
 
vpp = hashvar(s);
flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
for (vp = *vpp ; vp ; vp = vp->next) {
if (varequal(s, vp->text)) {
if (vp->flags & VREADONLY) {
size_t len = strchr(s, '=') - s;
error("%.*s: is read only", len, s);
}
INTOFF;
 
if (vp->func && (flags & VNOFUNC) == 0)
(*vp->func)(strchr(s, '=') + 1);
 
if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
ckfree(vp->text);
 
vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
vp->flags |= flags;
vp->text = s;
 
/*
* We could roll this to a function, to handle it as
* a regular variable function callback, but why bother?
*/
if (iflag &&
(vp == &vmpath || (vp == &vmail && ! mpathset())))
chkmail(1);
INTON;
return;
}
}
/* not found */
vp = ckmalloc(sizeof (*vp));
vp->flags = flags;
vp->text = s;
vp->next = *vpp;
vp->func = NULL;
*vpp = vp;
}
 
 
 
/*
* Process a linked list of variable assignments.
*/
 
void
listsetvar(list)
struct strlist *list;
{
struct strlist *lp;
 
INTOFF;
for (lp = list ; lp ; lp = lp->next) {
setvareq(savestr(lp->text), 0);
}
INTON;
}
 
 
 
/*
* Find the value of a variable. Returns NULL if not set.
*/
 
char *
lookupvar(name)
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;
}
}
return NULL;
}
 
 
 
/*
* Search the environment of a builtin command. If the second argument
* is nonzero, return the value of a variable even if it hasn't been
* exported.
*/
 
char *
bltinlookup(name, doall)
const char *name;
int doall;
{
struct strlist *sp;
struct var *v;
 
for (sp = cmdenviron ; sp ; sp = sp->next) {
if (varequal(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;
}
}
return NULL;
}
 
 
 
/*
* Generate a list of exported variables. This routine is used to construct
* the third argument to execve when executing a program.
*/
 
char **
environment() {
int nenv;
struct var **vpp;
struct var *vp;
char **env;
char **ep;
 
nenv = 0;
for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
for (vp = *vpp ; vp ; vp = vp->next)
if (vp->flags & VEXPORT)
nenv++;
}
ep = env = stalloc((nenv + 1) * sizeof *env);
for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
for (vp = *vpp ; vp ; vp = vp->next)
if (vp->flags & VEXPORT)
*ep++ = vp->text;
}
*ep = NULL;
return env;
}
 
 
/*
* Called when a shell procedure is invoked to clear out nonexported
* variables. It is also necessary to reallocate variables of with
* VSTACK set since these are currently allocated on the stack.
*/
 
#ifdef mkinit
MKINIT void shprocvar (void);
 
SHELLPROC {
shprocvar();
}
#endif
 
void
shprocvar() {
struct var **vpp;
struct var *vp, **prev;
 
for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
for (prev = vpp ; (vp = *prev) != NULL ; ) {
if ((vp->flags & VEXPORT) == 0) {
*prev = vp->next;
if ((vp->flags & VTEXTFIXED) == 0)
ckfree(vp->text);
if ((vp->flags & VSTRFIXED) == 0)
ckfree(vp);
} else {
if (vp->flags & VSTACK) {
vp->text = savestr(vp->text);
vp->flags &=~ VSTACK;
}
prev = &vp->next;
}
}
}
initvar();
}
 
 
 
/*
* Command to list all variables which are set. Currently this command
* is invoked from the set command when the set command is called without
* any variables.
*/
 
int
showvarscmd(argc, argv)
int argc;
char **argv;
{
struct var **vpp;
struct var *vp;
 
for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
for (vp = *vpp ; vp ; vp = vp->next) {
if ((vp->flags & VUNSET) == 0)
out1fmt("%s\n", vp->text);
}
}
return 0;
}
 
 
 
/*
* The export and readonly commands.
*/
 
int
exportcmd(argc, argv)
int argc;
char **argv;
{
struct var **vpp;
struct var *vp;
char *name;
const char *p;
int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
int pflag;
 
listsetvar(cmdenviron);
pflag = (nextopt("p") == 'p');
if (argc > 1 && !pflag) {
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->flags |= flag;
goto found;
}
}
}
setvar(name, p, flag);
found:;
}
} else {
for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
for (vp = *vpp ; vp ; vp = vp->next) {
if ((vp->flags & flag) == 0)
continue;
if (pflag) {
out1fmt("%s %s\n", argv[0], vp->text);
} else {
for (p = vp->text ; *p != '=' ; p++)
out1c(*p);
out1c('\n');
}
}
}
}
return 0;
}
 
 
/*
* The "local" command.
*/
 
int
localcmd(argc, argv)
int argc;
char **argv;
{
char *name;
 
if (! in_function())
error("Not in a function");
while ((name = *argptr++) != NULL) {
mklocal(name);
}
return 0;
}
 
 
/*
* Make a variable a local variable. When a variable is made local, it's
* 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(name)
char *name;
{
struct localvar *lvp;
struct var **vpp;
struct var *vp;
 
INTOFF;
lvp = ckmalloc(sizeof (struct localvar));
if (name[0] == '-' && name[1] == '\0') {
char *p;
p = ckmalloc(sizeof optlist);
lvp->text = memcpy(p, optlist, sizeof optlist);
vp = NULL;
} else {
vpp = hashvar(name);
for (vp = *vpp ; vp && ! varequal(vp->text, name) ; vp = vp->next);
if (vp == NULL) {
if (strchr(name, '='))
setvareq(savestr(name), VSTRFIXED);
else
setvar(name, NULL, VSTRFIXED);
vp = *vpp; /* the new variable */
lvp->text = NULL;
lvp->flags = VUNSET;
} else {
lvp->text = vp->text;
lvp->flags = vp->flags;
vp->flags |= VSTRFIXED|VTEXTFIXED;
if (strchr(name, '='))
setvareq(savestr(name), 0);
}
}
lvp->vp = vp;
lvp->next = localvars;
localvars = lvp;
INTON;
}
 
 
/*
* Called after a function returns.
*/
 
void
poplocalvars() {
struct localvar *lvp;
struct var *vp;
 
while ((lvp = localvars) != NULL) {
localvars = lvp->next;
vp = lvp->vp;
if (vp == NULL) { /* $- saved */
memcpy(optlist, lvp->text, sizeof optlist);
ckfree(lvp->text);
} else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
(void)unsetvar(vp->text);
} else {
if ((vp->flags & VTEXTFIXED) == 0)
ckfree(vp->text);
vp->flags = lvp->flags;
vp->text = lvp->text;
}
ckfree(lvp);
}
}
 
 
int
setvarcmd(argc, argv)
int argc;
char **argv;
{
if (argc <= 2)
return unsetcmd(argc, argv);
else if (argc == 3)
setvar(argv[1], argv[2], 0);
else
error("List assignment not implemented");
return 0;
}
 
 
/*
* The unset builtin command. We unset the function before we unset the
* variable to allow a function to be unset when there is a readonly variable
* with the same name.
*/
 
int
unsetcmd(argc, argv)
int argc;
char **argv;
{
char **ap;
int i;
int flg_func = 0;
int flg_var = 0;
int ret = 0;
 
while ((i = nextopt("vf")) != '\0') {
if (i == 'f')
flg_func = 1;
else
flg_var = 1;
}
if (flg_func == 0 && flg_var == 0)
flg_var = 1;
 
for (ap = argptr; *ap ; ap++) {
if (flg_func)
ret |= unsetfunc(*ap);
if (flg_var)
ret |= unsetvar(*ap);
}
return ret;
}
 
 
/*
* Unset the specified variable.
*/
 
int
unsetvar(s)
const char *s;
{
struct var **vpp;
struct var *vp;
 
vpp = hashvar(s);
for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) {
if (varequal(vp->text, s)) {
if (vp->flags & VREADONLY)
return (1);
INTOFF;
if (*(strchr(vp->text, '=') + 1) != '\0')
setvar(s, nullstr, 0);
vp->flags &= ~VEXPORT;
vp->flags |= VUNSET;
if ((vp->flags & VSTRFIXED) == 0) {
if ((vp->flags & VTEXTFIXED) == 0)
ckfree(vp->text);
*vpp = vp->next;
ckfree(vp);
}
INTON;
return (0);
}
}
 
return (1);
}
 
 
 
/*
* Find the appropriate entry in the hash table from the name.
*/
 
STATIC struct var **
hashvar(p)
const char *p;
{
unsigned int hashval;
 
hashval = ((unsigned char) *p) << 4;
while (*p && *p != '=')
hashval += (unsigned char) *p++;
return &vartab[hashval % VTABSIZE];
}
 
 
 
/*
* Returns true if the two strings specify the same varable. The first
* variable name is terminated by '='; the second may be terminated by
* either '=' or '\0'.
*/
 
STATIC int
varequal(p, q)
const char *p, *q;
{
while (*p == *q++) {
if (*p++ == '=')
return 1;
}
if (*p == '=' && *(q - 1) == '\0')
return 1;
return 0;
}
/trunk/uspace/app/ash/miscbltin.h
0,0 → 1,34
/* $NetBSD: miscbltin.h,v 1.1 1997/07/04 21:02:10 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Christos Zoulas.
* 4. 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 **);
/trunk/uspace/app/ash/main.h
0,0 → 1,48
/* $NetBSD: main.h,v 1.8 1995/05/11 21:29:27 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)main.h 8.2 (Berkeley) 5/4/95
*/
 
extern int rootpid; /* pid of main shell */
extern int rootshell; /* true if we aren't a child of the main shell */
 
void readcmdfile (char *);
void cmdloop (int);
int dotcmd (int, char **);
int exitcmd (int, char **);
 
/trunk/uspace/app/ash/options.c
0,0 → 1,551
/* $NetBSD: options.c,v 1.29 1999/07/09 03:05:50 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
 
#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.29 1999/07/09 03:05:50 christos Exp $");
#endif
#endif /* not lint */
 
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
 
#include "shell.h"
#define DEFINE_OPTIONS
#include "options.h"
#undef DEFINE_OPTIONS
#include "nodes.h" /* for other header files */
#include "eval.h"
#include "jobs.h"
#include "input.h"
#include "output.h"
#include "trap.h"
#include "var.h"
#include "memalloc.h"
#include "error.h"
#include "mystring.h"
#ifndef SMALL
#include "myhistedit.h"
#endif
 
char *arg0; /* value of $0 */
struct shparam shellparam; /* current positional parameters */
char **argptr; /* argument list for builtin commands */
char *optarg; /* set by nextopt (like getopt) */
char *optptr; /* used by nextopt */
 
char *minusc; /* argument to -c option */
 
 
STATIC void options (int);
STATIC void minus_o (char *, int);
STATIC void setoption (int, int);
STATIC int getopts (char *, char *, char **, int *, int *);
 
 
/*
* Process the shell command line arguments.
*/
 
void
procargs(argc, argv)
int argc;
char **argv;
{
int i;
 
argptr = argv;
if (argc > 0)
argptr++;
for (i = 0; i < NOPTS; i++)
optlist[i].val = 2;
options(1);
if (*argptr == NULL && minusc == NULL)
sflag = 1;
if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
iflag = 1;
if (mflag == 2)
mflag = iflag;
for (i = 0; i < NOPTS; i++)
if (optlist[i].val == 2)
optlist[i].val = 0;
arg0 = argv[0];
if (sflag == 0 && minusc == NULL) {
commandname = arg0 = *argptr++;
setinputfile(commandname, 0);
}
/* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
if (argptr && minusc && *argptr)
arg0 = *argptr++;
 
shellparam.p = argptr;
shellparam.optind = 1;
shellparam.optoff = -1;
/* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
while (*argptr) {
shellparam.nparam++;
argptr++;
}
optschanged();
}
 
 
void
optschanged()
{
setinteractive(iflag);
#ifndef SMALL
histedit();
#endif
setjobctl(mflag);
}
 
/*
* Process shell options. The global variable argptr contains a pointer
* to the argument list; we advance it past the options.
*/
 
STATIC void
options(cmdline)
int cmdline;
{
char *p;
int val;
int c;
 
if (cmdline)
minusc = NULL;
while ((p = *argptr) != NULL) {
argptr++;
if ((c = *p++) == '-') {
val = 1;
if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
if (!cmdline) {
/* "-" means turn off -x and -v */
if (p[0] == '\0')
xflag = vflag = 0;
/* "--" means reset params */
else if (*argptr == NULL)
setparam(argptr);
}
break; /* "-" or "--" terminates options */
}
} else if (c == '+') {
val = 0;
} else {
argptr--;
break;
}
while ((c = *p++) != '\0') {
if (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
} else if (c == 'o') {
minus_o(*argptr, val);
if (*argptr)
argptr++;
} else {
setoption(c, val);
}
}
}
}
 
STATIC void
minus_o(name, val)
char *name;
int val;
{
int i;
 
if (name == NULL) {
out1str("Current option settings\n");
for (i = 0; i < NOPTS; i++)
out1fmt("%-16s%s\n", optlist[i].name,
optlist[i].val ? "on" : "off");
} else {
for (i = 0; i < NOPTS; i++)
if (equal(name, optlist[i].name)) {
setoption(optlist[i].letter, val);
return;
}
error("Illegal option -o %s", name);
}
}
 
 
STATIC void
setoption(flag, val)
char flag;
int val;
{
int 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;
}
return;
}
error("Illegal option -%c", flag);
/* NOTREACHED */
}
 
 
 
#ifdef mkinit
INCLUDE "options.h"
 
SHELLPROC {
int i;
 
for (i = 0; i < NOPTS; i++)
optlist[i].val = 0;
optschanged();
 
}
#endif
 
 
/*
* Set the shell parameters.
*/
 
void
setparam(argv)
char **argv;
{
char **newparam;
char **ap;
int nparam;
 
for (nparam = 0 ; argv[nparam] ; nparam++);
ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
while (*argv) {
*ap++ = savestr(*argv++);
}
*ap = NULL;
freeparam(&shellparam);
shellparam.malloc = 1;
shellparam.nparam = nparam;
shellparam.p = newparam;
shellparam.optind = 1;
shellparam.optoff = -1;
}
 
 
/*
* Free the list of positional parameters.
*/
 
void
freeparam(param)
volatile struct shparam *param;
{
char **ap;
 
if (param->malloc) {
for (ap = param->p ; *ap ; ap++)
ckfree(*ap);
ckfree(param->p);
}
}
 
 
 
/*
* The shift builtin command.
*/
 
int
shiftcmd(argc, argv)
int argc;
char **argv;
{
int n;
char **ap1, **ap2;
 
n = 1;
if (argc > 1)
n = number(argv[1]);
if (n > shellparam.nparam)
error("can't shift that many");
INTOFF;
shellparam.nparam -= n;
for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
if (shellparam.malloc)
ckfree(*ap1);
}
ap2 = shellparam.p;
while ((*ap2++ = *ap1++) != NULL);
shellparam.optind = 1;
shellparam.optoff = -1;
INTON;
return 0;
}
 
 
 
/*
* The set command builtin.
*/
 
int
setcmd(argc, argv)
int argc;
char **argv;
{
if (argc == 1)
return showvarscmd(argc, argv);
INTOFF;
options(0);
optschanged();
if (*argptr != NULL) {
setparam(argptr);
}
INTON;
return 0;
}
 
 
void
getoptsreset(value)
const char *value;
{
shellparam.optind = number(value);
shellparam.optoff = -1;
}
 
/*
* The getopts builtin. Shellparam.optnext points to the next argument
* to be processed. Shellparam.optptr points to the next character to
* be processed in the current argument. If shellparam.optnext is NULL,
* then it's the first time getopts has been called.
*/
 
int
getoptscmd(argc, argv)
int argc;
char **argv;
{
char **optbase;
 
if (argc < 3)
error("Usage: getopts optstring var [arg]");
else if (argc == 3) {
optbase = shellparam.p;
if (shellparam.optind > shellparam.nparam + 1) {
shellparam.optind = 1;
shellparam.optoff = -1;
}
}
else {
optbase = &argv[3];
if (shellparam.optind > argc - 2) {
shellparam.optind = 1;
shellparam.optoff = -1;
}
}
 
return getopts(argv[1], argv[2], optbase, &shellparam.optind,
&shellparam.optoff);
}
 
STATIC int
getopts(optstr, optvar, optfirst, optind, optoff)
char *optstr;
char *optvar;
char **optfirst;
int *optind;
int *optoff;
{
char *p, *q;
char c = '?';
int done = 0;
int err = 0;
char s[10];
char **optnext = optfirst + *optind - 1;
 
if (*optind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
strlen(*(optnext - 1)) < *optoff)
p = NULL;
else
p = *(optnext - 1) + *optoff;
if (p == NULL || *p == '\0') {
/* Current word is done, advance */
if (optnext == NULL)
return 1;
p = *optnext;
if (p == NULL || *p != '-' || *++p == '\0') {
atend:
*optind = optnext - optfirst + 1;
p = NULL;
done = 1;
goto out;
}
optnext++;
if (p[0] == '-' && p[1] == '\0') /* check for "--" */
goto atend;
}
 
c = *p++;
for (q = optstr; *q != c; ) {
if (*q == '\0') {
if (optstr[0] == ':') {
s[0] = c;
s[1] = '\0';
err |= setvarsafe("OPTARG", s, 0);
}
else {
outfmt(&errout, "Illegal option -%c\n", c);
(void) unsetvar("OPTARG");
}
c = '?';
goto bad;
}
if (*++q == ':')
q++;
}
 
if (*++q == ':') {
if (*p == '\0' && (p = *optnext) == NULL) {
if (optstr[0] == ':') {
s[0] = c;
s[1] = '\0';
err |= setvarsafe("OPTARG", s, 0);
c = ':';
}
else {
outfmt(&errout, "No arg for -%c option\n", c);
(void) unsetvar("OPTARG");
c = '?';
}
goto bad;
}
 
if (p == *optnext)
optnext++;
setvarsafe("OPTARG", p, 0);
p = NULL;
}
else
setvarsafe("OPTARG", "", 0);
*optind = optnext - optfirst + 1;
goto out;
 
bad:
*optind = 1;
p = NULL;
out:
*optoff = p ? p - *(optnext - 1) : -1;
fmtstr(s, sizeof(s), "%d", *optind);
err |= setvarsafe("OPTIND", s, VNOFUNC);
s[0] = c;
s[1] = '\0';
err |= setvarsafe(optvar, s, 0);
if (err) {
*optind = 1;
*optoff = -1;
flushall();
exraise(EXERROR);
}
return done;
}
 
/*
* XXX - should get rid of. have all builtins use getopt(3). the
* library getopt must have the BSD extension static variable "optreset"
* otherwise it can't be used within the shell safely.
*
* Standard option processing (a la getopt) for builtin routines. The
* only argument that is passed to nextopt is the option string; the
* other arguments are unnecessary. It return the character, or '\0' on
* end of input.
*/
 
int
nextopt(optstring)
const char *optstring;
{
char *p;
const char *q;
char c;
 
if ((p = optptr) == NULL || *p == '\0') {
p = *argptr;
if (p == NULL || *p != '-' || *++p == '\0')
return '\0';
argptr++;
if (p[0] == '-' && p[1] == '\0') /* check for "--" */
return '\0';
}
c = *p++;
for (q = optstring ; *q != c ; ) {
if (*q == '\0')
error("Illegal option -%c", c);
if (*++q == ':')
q++;
}
if (*++q == ':') {
if (*p == '\0' && (p = *argptr++) == NULL)
error("No arg for -%c option", c);
optarg = p;
p = NULL;
}
optptr = p;
return c;
}
/trunk/uspace/app/ash/eval.h
0,0 → 1,75
/* $NetBSD: eval.h,v 1.10 2000/01/27 23:39:40 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)eval.h 8.2 (Berkeley) 5/4/95
*/
 
extern char *commandname; /* currently executing command */
extern int exitstatus; /* exit status of last command */
extern struct strlist *cmdenviron; /* environment for builtin command */
 
 
struct backcmd { /* result of evalbackcmd */
int fd; /* file descriptor to read from */
char *buf; /* buffer */
int nleft; /* number of chars in buffer */
struct job *jp; /* job structure for command */
};
 
int evalcmd (int, 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 is_special_builtin (const char *);
 
/* in_function returns nonzero if we are currently evaluating a function */
#define in_function() funcnest
extern int funcnest;
extern int evalskip;
 
/* reasons for skipping commands (see comment on breakcmd routine) */
#define SKIPBREAK 1
#define SKIPCONT 2
#define SKIPFUNC 3
#define SKIPFILE 4
/trunk/uspace/app/ash/arith.y
0,0 → 1,202
%{
/* $NetBSD: arith.y,v 1.13 1999/07/09 03:05:49 christos 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
 
#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.13 1999/07/09 03:05:49 christos Exp $");
#endif
#endif /* not lint */
 
#include <stdlib.h>
#include "expand.h"
#include "shell.h"
#include "error.h"
#include "output.h"
#include "memalloc.h"
 
const char *arith_buf, *arith_startbuf;
 
void yyerror (const char *);
int yyparse (void);
#ifdef TESTARITH
int main (int , char *[]);
int error (char *);
#endif
 
int
arith(s)
const char *s;
{
long result;
 
arith_buf = arith_startbuf = s;
 
INTOFF;
result = yyparse();
arith_lex_reset(); /* reprime lex */
INTON;
 
return (result);
}
 
 
/*
* The exp(1) builtin.
*/
int
expcmd(argc, argv)
int argc;
char **argv;
{
const 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(argc, argv)
char *argv[];
{
printf("%d\n", exp(argv[1]));
}
error(s)
char *s;
{
fprintf(stderr, "exp: %s\n", s);
exit(1);
}
#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 {
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
;
%%
void
yyerror(s)
const char *s;
{
 
yyclearin;
arith_lex_reset(); /* reprime lex */
error("arithmetic expression: %s: \"%s\"", s, arith_startbuf);
/* NOTREACHED */
}
/trunk/uspace/app/ash/var.h
0,0 → 1,131
/* $NetBSD: var.h,v 1.18 2000/05/22 10:18:47 elric 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)var.h 8.2 (Berkeley) 5/4/95
*/
 
/*
* Shell variables.
*/
 
/* 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 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 */
 
 
struct var {
struct var *next; /* next entry in hash list */
int flags; /* flags are defined above */
char *text; /* name=value */
void (*func) (const char *);
/* function to be called when */
/* the variable gets set/unset */
};
 
 
struct localvar {
struct localvar *next; /* next local variable in list */
struct var *vp; /* the variable that was made local */
int flags; /* saved flags */
char *text; /* saved text */
};
 
 
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 vps1;
extern struct var vps2;
#ifndef SMALL
extern struct var vterm;
extern struct var vtermcap;
extern struct var vhistsize;
#endif
 
/*
* The following macros access the values of the above variables.
* They have to skip over the name. They return the null string
* for unset variables.
*/
 
#define ifsval() (vifs.text + 4)
#define ifsset() ((vifs.flags & VUNSET) == 0)
#define mailval() (vmail.text + 5)
#define mpathval() (vmpath.text + 9)
#define pathval() (vpath.text + 5)
#define ps1val() (vps1.text + 4)
#define ps2val() (vps2.text + 4)
#define optindval() (voptind.text + 7)
#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 (const char *, const char *, int);
void setvareq (char *, int);
struct strlist;
void listsetvar (struct strlist *);
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 *);
void poplocalvars (void);
int setvarcmd (int, char **);
int unsetcmd (int, char **);
int unsetvar (const char *);
int setvarsafe (const char *, const char *, int);