/branches/tracing/uspace/app/cli/cli.c |
---|
File deleted |
/branches/tracing/uspace/app/cli/Makefile |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/exec.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/scli.c |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/Makefile |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/scli.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/input.c |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/LICENSE |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/input.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/AUTHORS |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/mknewcmd |
---|
File deleted |
Property changes: |
Deleted: svn:executable |
-* |
\ No newline at end of property |
/branches/tracing/uspace/app/bdsh/cmds/mod_cmds.c |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/sleep/sleep.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/sleep/entry.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/sleep/sleep.c |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/sleep/sleep_def.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/help/help_def.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/help/help.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/help/entry.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/help/help.c |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/pwd/pwd_def.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/pwd/pwd.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/pwd/entry.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/pwd/pwd.c |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/module_aliases.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/README |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/modules.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/ls/ls_def.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/ls/ls.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/ls/entry.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/ls/ls.c |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/rm/rm.c |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/rm/rm_def.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/rm/rm.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/rm/entry.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/cp/entry.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/cp/cp.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/cp/cp.c |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/cp/cp_def.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/quit/quit.c |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/quit/quit_def.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/quit/entry.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/quit/quit.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/touch/touch_def.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/touch/entry.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/touch/touch.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/touch/touch.c |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/mkdir/mkdir_def.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/mkdir/mkdir.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/mkdir/mkdir.c |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/mkdir/entry.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/cat/entry.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/cat/cat.c |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/cat/cat_def.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/modules/cat/cat.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/builtins/cd/cd_def.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/builtins/cd/cd.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/builtins/cd/cd.c |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/builtins/cd/entry.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/builtins/README |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/builtins/builtin_aliases.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/builtins/builtins.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/cmds.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/cmds/builtin_cmds.c |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/config.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/errors.c |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/README |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/util.c |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/errors.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/util.h |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/TODO |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/exec.c |
---|
File deleted |
/branches/tracing/uspace/app/bdsh/errstr.h |
---|
File deleted |
/branches/tracing/uspace/app/init/init.c |
---|
45,6 → 45,10 |
#include "init.h" |
#include "version.h" |
#define BUF_SIZE 150000 |
static char *buf; |
static void console_wait(void) |
{ |
while (get_cons_phone() < 0) |
51,13 → 55,13 |
usleep(50000); // FIXME |
} |
static bool mount_fs(const char *fstype) |
static bool mount_tmpfs(void) |
{ |
int rc = -1; |
while (rc < 0) { |
rc = mount(fstype, "/", "initrd"); |
rc = mount("tmpfs", "/", "initrd"); |
switch (rc) { |
case EOK: |
printf(NAME ": Root filesystem mounted\n"); |
68,9 → 72,6 |
case ELIMIT: |
printf(NAME ": Unable to mount root filesystem\n"); |
return false; |
case ENOENT: |
printf(NAME ": Unknown filesystem type (%s)\n", fstype); |
return false; |
default: |
sleep(5); // FIXME |
} |
81,16 → 82,28 |
static void spawn(char *fname) |
{ |
char *argv[2]; |
printf(NAME ": Spawning %s\n", fname); |
argv[0] = fname; |
argv[1] = NULL; |
if (task_spawn(fname, argv) != 0) { |
/* Success */ |
sleep(1); |
int fd = open(fname, O_RDONLY); |
if (fd >= 0) { |
ssize_t rd; |
size_t len = 0; |
// FIXME: cannot do long reads yet |
do { |
rd = read(fd, buf + len, 1024); |
if (rd > 0) |
len += rd; |
} while (rd > 0); |
if (len > 0) { |
task_spawn(buf, len); |
sleep(1); // FIXME |
} |
close(fd); |
} |
} |
99,21 → 112,27 |
info_print(); |
sleep(5); // FIXME |
if (!mount_fs("tmpfs") && !mount_fs("fat")) { |
if (!mount_tmpfs()) { |
printf(NAME ": Exiting\n"); |
return -1; |
} |
// FIXME: spawn("/srv/pci"); |
spawn("/srv/fb"); |
spawn("/srv/kbd"); |
spawn("/srv/console"); |
buf = malloc(BUF_SIZE); |
// FIXME: spawn("/sbin/pci"); |
spawn("/sbin/fb"); |
spawn("/sbin/kbd"); |
spawn("/sbin/console"); |
console_wait(); |
version_print(); |
spawn("/app/bdsh"); |
spawn("/sbin/fat"); |
spawn("/sbin/tetris"); |
// FIXME: spawn("/sbin/tester"); |
spawn("/sbin/klog"); |
free(buf); |
return 0; |
} |
/branches/tracing/uspace/app/init/Makefile |
---|
61,7 → 61,7 |
.PHONY: all clean depend disasm |
all: $(OUTPUT) $(OUTPUT).disasm |
all: $(OUTPUT) disasm |
-include Makefile.depend |
74,11 → 74,9 |
$(OUTPUT): $(OBJECTS) $(LIBS) |
$(LD) -T $(LIBC_PREFIX)/arch/$(ARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map |
disasm: $(OUTPUT).disasm |
disasm: |
$(OBJDUMP) -d $(OUTPUT) >$(OUTPUT).disasm |
$(OUTPUT).disasm: $(OUTPUT) |
$(OBJDUMP) -d $< >$@ |
%.o: %.S |
$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@ |
/branches/tracing/uspace/app/tester/tester.c |
---|
108,17 → 108,8 |
printf("*\t\t\tRun all safe tests\n"); |
} |
int main(int argc, char **argv) |
int main(void) |
{ |
printf("Number of arguments: %d\n", argc); |
if (argv) { |
printf("Arguments:"); |
while (*argv) { |
printf(" '%s'", *argv++); |
} |
printf("\n"); |
} |
while (1) { |
char c; |
test_t *test; |
134,7 → 125,7 |
if (c == 'a') |
break; |
if (test->name == NULL) |
if (c > 'a') |
printf("Unknown test\n\n"); |
else |
run_test(test); |
/branches/tracing/uspace/app/tester/Makefile |
---|
60,7 → 60,7 |
.PHONY: all clean depend disasm |
all: $(OUTPUT) $(OUTPUT).disasm |
all: $(OUTPUT) disasm |
-include Makefile.depend |
73,11 → 73,9 |
$(OUTPUT): $(OBJECTS) $(LIBS) |
$(LD) -T $(LIBC_PREFIX)/arch/$(ARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map |
disasm: $(OUTPUT).disasm |
disasm: |
$(OBJDUMP) -d -S $(OUTPUT) >$(OUTPUT).disasm |
$(OUTPUT).disasm: $(OUTPUT) |
$(OBJDUMP) -d $< >$@ |
%.o: %.S |
$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@ |
/branches/tracing/uspace/app/tetris/input.c |
---|
96,7 → 96,6 |
struct timeval starttv, endtv, *s; |
static ipc_call_t charcall; |
ipcarg_t rc; |
int cons_phone; |
/* |
* Someday, select() will do this for us. |
111,11 → 110,8 |
s = NULL; |
if (!lastchar) { |
if (!getchar_inprog) { |
cons_phone = get_cons_phone(); |
getchar_inprog = async_send_2(cons_phone, |
CONSOLE_GETCHAR, 0, 0, &charcall); |
} |
if (!getchar_inprog) |
getchar_inprog = async_send_2(1,CONSOLE_GETCHAR,0,0,&charcall); |
if (!s) |
async_wait_for(getchar_inprog, &rc); |
else if (async_wait_timeout(getchar_inprog, &rc, s->tv_usec) == ETIMEOUT) { |
/branches/tracing/uspace/app/tetris/Makefile |
---|
10,7 → 10,7 |
.PHONY: all clean depend disasm |
all: $(OUTPUT) $(OUTPUT).disasm |
all: $(OUTPUT) disasm |
-include Makefile.depend |
22,12 → 22,9 |
clean: |
-rm -f $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm Makefile.depend *.o |
disasm: |
$(OBJDUMP) -d $(OUTPUT) >$(OUTPUT).disasm |
disasm: $(OUTPUT).disasm |
$(OUTPUT).disasm: $(OUTPUT) |
$(OBJDUMP) -d $< >$@ |
%.o: %.S |
$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@ |
/branches/tracing/uspace/app/klog/Makefile |
---|
47,7 → 47,7 |
.PHONY: all clean depend disasm |
all: $(OUTPUT) $(OUTPUT).disasm |
all: $(OUTPUT) disasm |
-include Makefile.depend |
60,11 → 60,9 |
$(OUTPUT): $(OBJECTS) $(LIBS) |
$(LD) -T $(LIBC_PREFIX)/arch/$(ARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map |
disasm: $(OUTPUT).disasm |
disasm: |
$(OBJDUMP) -d $(OUTPUT) >$(OUTPUT).disasm |
$(OUTPUT).disasm: $(OUTPUT) |
$(OBJDUMP) -d $< >$@ |
%.o: %.S |
$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@ |
/branches/tracing/uspace/app/ash/tools/mksyntax.c |
---|
0,0 → 1,428 |
/* $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 <stdlib.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); |
} |
/branches/tracing/uspace/app/ash/tools/Makefile |
---|
0,0 → 1,56 |
# |
# 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 := $(addprefix ../,$(basename $(SOURCES))) |
.PHONY: all clean move-output |
all: $(OUTPUT) |
$(OUTPUT): $(OBJECTS) |
$(CC) $< $(LFLAGS) -o $@ |
clean: |
-rm -f $(OUTPUT) $(OBJECTS) |
%.o: %.S |
$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@ |
%.o: %.s |
$(AS) $(AFLAGS) $< -o $@ |
%.o: %.c |
$(CC) $(DEFS) $(CFLAGS) -c $< -o $@ |
/branches/tracing/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<OSTOP) */ |
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); |
} |
/branches/tracing/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; |
} |
/branches/tracing/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 */ |
} |
/branches/tracing/uspace/app/ash/Makefile |
---|
0,0 → 1,180 |
# |
# 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} |
SUBDIRS = tools |
OBJECTS := $(addsuffix .o,$(basename $(SOURCES))) |
.PHONY: all clean depend disasm all-subdirs |
all: all-subdirs $(OUTPUT) disasm |
all-subdirs: |
for i in $(SUBDIRS); do \ |
echo "make all in $$i..."; \ |
make -C $$i all; \ |
done |
-include Makefile.depend |
.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) |
for i in $(SUBDIRS); do \ |
echo "make clean in $$i..."; \ |
make -C $$i clean; \ |
done |
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 $@ |
/branches/tracing/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++; |
} |
} |
} |
/branches/tracing/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 *); |
/branches/tracing/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 |
/branches/tracing/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; |
} |
/branches/tracing/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); |
/branches/tracing/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 |
/branches/tracing/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. |
/branches/tracing/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 |
} |
/branches/tracing/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 |
/branches/tracing/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; |
} |
/branches/tracing/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 |
/branches/tracing/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 |
/branches/tracing/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. |
/branches/tracing/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 |
/branches/tracing/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$$ |
/branches/tracing/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 |
/branches/tracing/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; |
/branches/tracing/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; |
} |
/branches/tracing/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 |
} |
/branches/tracing/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; |
} |
/branches/tracing/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); |
} |
/branches/tracing/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 */ |
/branches/tracing/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. |
/branches/tracing/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; |
/branches/tracing/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); |
} |
/branches/tracing/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]; |
} |
/branches/tracing/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 **); |
/branches/tracing/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); |
} |
/branches/tracing/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 **); |
/branches/tracing/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 = ≈ |
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) "ef; |
(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>"; |
} |
} |
/branches/tracing/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; |
} |
/branches/tracing/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)) |
/branches/tracing/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); |
/branches/tracing/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 |
/branches/tracing/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 *); |
/branches/tracing/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 |
/branches/tracing/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 |
/branches/tracing/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 |
/branches/tracing/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; |
} |
/branches/tracing/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: |
/branches/tracing/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 |
/branches/tracing/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 */ |
/branches/tracing/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)) |
/branches/tracing/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 |
/branches/tracing/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); |
/branches/tracing/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 |
} |
/branches/tracing/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 |
} |
/branches/tracing/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 |
} |
/branches/tracing/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 "$@" |
/branches/tracing/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 |
} |
/branches/tracing/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 |
} |
/branches/tracing/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" |
} |
/branches/tracing/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 "$@" |
/branches/tracing/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 |
} |
/branches/tracing/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; |
} |
} |
/branches/tracing/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()) |
/branches/tracing/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; |
} |
/branches/tracing/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; |
} |
/branches/tracing/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 */ |
} |
/branches/tracing/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); |
/branches/tracing/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 *); |
/branches/tracing/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; |
/branches/tracing/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; |
} |
/branches/tracing/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); |
} |
/branches/tracing/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; |
} |
/branches/tracing/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 */ |
} |
/branches/tracing/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); |
/branches/tracing/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); |
/branches/tracing/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) ¬_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; |
} |
/branches/tracing/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; |
} |
/branches/tracing/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 **); |
/branches/tracing/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 **); |
/branches/tracing/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; |
} |
/branches/tracing/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 |
/branches/tracing/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 */ |
} |
/branches/tracing/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); |