netnews@netcom.UUCP (USENET Administration) (12/12/90)
#!/bin/sh # This is part 05 of ksh-pd # ============= src/c_ksh.c ============== if test ! -d 'src'; then echo 'x - creating directory src' mkdir 'src' fi if test -f 'src/c_ksh.c' -a X"$1" != X"-c"; then echo 'x - skipping src/c_ksh.c (File already exists)' else echo 'x - extracting src/c_ksh.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'src/c_ksh.c' && X/* X * built-in Korn commands: c_* X */ X Xstatic char *RCSid = "$Id: c_ksh.c,v 3.2 89/01/23 10:57:38 egisin Exp $"; X X#include <stddef.h> X#include <stdio.h> X#include <string.h> X#include <errno.h> X#include <setjmp.h> X#include "sh.h" X#include "table.h" X Xint Xc_hash(wp) X register char **wp; X{ X register int i; X register struct tbl *tp, **p; X X wp++; X if (*wp == NULL) { X for (p = tsort(&commands); (tp = *p++) != NULL; ) X if ((tp->flag&ISSET)) X printf("%s\n", tp->val.s); X return 0; X } X X if (strcmp(*wp, "-r") == 0) X flushcom(1); X while (*wp != NULL) X findcom(*wp++, 1); X return 0; X} X Xint Xc_print(wp) X register char **wp; X{ X int nl = 1; X int expand = 1; X FILE *f = stdout; X X for (wp++; *wp != NULL && **wp == '-'; wp++) { X register char *s = *wp + 1; X if (*s == '\0') { X wp++; X break; X } X while (*s) switch (*s++) { X case 'n': X nl = 0; X break; X case 'e': X expand = 1; X break; X case 'r': X expand = 0; X break; X case 'u': X if (!digit(*s) || (f = shf[*s++-'0']) == NULL) X errorf("bad -u argument\n"); X break; X } X } X X while (*wp != NULL) { X register char *s = *wp; X register int c; X while ((c = *s++) != '\0') X if (expand && c == '\\') { X switch ((c = *s++)) { X case 'b': c = '\b'; break; X case 'c': nl = 0; continue; /* AT&T brain damage */ X case 'f': c = '\f'; break; X case 'n': c = '\n'; break; X case 'r': c = '\r'; break; X case 't': c = '\t'; break; X case 'v': c = 0x0B; break; X case '0': case '1': case '2': case '3': X case '4': case '5': case '6': case '7': X c = c - '0'; X if (*s >= '0' && *s <= '7') X c = 8*c + *s++ - '0'; X if (*s >= '0' && *s <= '7') X c = 8*c + *s++ - '0'; X break; X case '\\': break; X default: X putc('\\', f); X } X putc(c, f); X } else X putc(c, f); X if (*++wp != NULL) X putc(' ', f); X } X if (nl) X putc('\n', f); X return 0; X} X X/* todo: handle case where id is both lexical and command */ Xint Xc_whence(wp) X register char **wp; X{ X register struct tbl *tp; X char *id; X int vflag = 0; X X for (wp++; (id = *wp) != NULL && *id == '-'; wp++) X if (id[1] == 'v') X vflag = 1; X X while ((id = *wp++) != NULL) { X tp = tsearch(&lexicals, id, hash(id)); X if (tp == NULL) X tp = findcom(id, 1); X if (vflag) X switch ((tp == NULL) ? CNONE : tp->type) { X case CNONE: X printf("%s is unknown\n", id); X break; X case CSHELL: X printf("%s is a shell builtin\n", id); X break; X case CFUNC: X printf("%s is a function\n", id); X fptreef(stdout, "function %s %T\n", id, tp->val.t); X break; X case CEXEC: X printf("%s is %s\n", id, X (tp->flag&ISSET) ? tp->val.s : "unknown"); X break; X case CALIAS: X printf("%s is the alias '%s'\n", id, tp->val.s); X break; X case CKEYWD: X printf("%s is a shell keyword\n", id); X break; X default: X printf("%s is *GOK*\n", id); X break; X } X else X switch ((tp == NULL) ? CNONE : tp->type) { X case CNONE: X printf("\n"); X break; X case CSHELL: X printf("builtin %s\n", id); X break; X case CFUNC: X printf("%s\n", id); X break; X case CEXEC: X printf("%s\n", (tp->flag&ISSET) ? tp->val.s : id); X break; X case CALIAS: X printf("%s\n", tp->val.s); X break; X case CKEYWD: X printf("%s\n", id); X break; X default: X printf("*GOK*\n"); X break; X } X } X return 0; X} X X/* typeset, export, and readonly */ Xint Xc_typeset(wp) X register char **wp; X{ X register char *id; X struct block *l = e.loc; X register struct tbl *vp, **p; X int fset = 0, fclr = 0; X int thing = 0, func = 0, local = 0; X X switch (**wp) { X case 'e': /* export */ X fset |= EXPORT; X break; X case 'r': /* readonly */ X fset |= RDONLY; X break; X case 't': /* typeset */ X local = 1; X break; X } X X for (wp++; (id = *wp) != NULL && (*id == '-' || *id == '+'); wp++) { X int flag = 0; X thing = *id; X while (*++id != '\0') switch (*id) { X case 'f': X flag |= FUNCT; X func = 1; X break; X case 'i': X flag |= INTEGER; X break; X case 'r': X flag |= RDONLY; X break; X case 'x': X flag |= EXPORT; X break; X case 't': X flag |= TRACE; X break; X default: X errorf("unknown flag -%c\n", *id); X } X if (flag != 0) { /* + or - with options */ X if (thing == '-') X fset |= flag; X else X fclr |= flag; X thing = 0; X } X } X X /* list variables and attributes */ X if (*wp == NULL) { X for (l = e.loc; l != NULL; l = l->next) { X for (p = tsort((func==0) ? &l->vars : &l->funs); X (vp = *p++) != NULL; ) X if ((vp->flag&ISSET)) X if (thing == 0 && fclr == 0 && fset == 0) { X printf("typeset "); X if ((vp->flag&INTEGER)) X printf("-i "); X if ((vp->flag&EXPORT)) X printf("-x "); X if ((vp->flag&RDONLY)) X printf("-r "); X if ((vp->flag&TRACE)) X printf("-t "); X printf("%s\n", vp->name); X } else X if (thing == '+' || X fclr && (vp->flag&fclr) == fclr) { X printf("%s\n", vp->name); X } else X if (thing == '-' || X fset && (vp->flag&fset) == fset) { X if (fset&FUNCT) X printf("function %s\n", vp->name); X else X printf("%s=%s\n", vp->name, strval(vp)); X } X } X return (0); X } X X if (local) X fset |= LOCAL; X for (; *wp != NULL; wp++) X#if 0 X if (func) { X } else X#endif X if (typeset(*wp, fset, fclr) == NULL) X errorf("%s: not identifier\n", *wp); X return 0; X} X Xint Xc_alias(wp) X register char **wp; X{ X register struct table *t = &lexicals; X register struct tbl *ap, **p; X register int i; X int rv = 0; X X if (*++wp != NULL && strcmp(*wp, "-d") == 0) { X t = &homedirs; X wp++; X } X X if (*wp == NULL) X for (p = tsort(t); (ap = *p++) != NULL; ) X if (ap->type == CALIAS && (ap->flag&DEFINED)) X printf("%s='%s'\n", ap->name, ap->val.s); X X for (; *wp != NULL; wp++) { X register char *id = *wp; X register char *val = strchr(id, '='); X X if (val == NULL) { X ap = tsearch(t, id, hash(id)); X if (ap != NULL && ap->type == CALIAS && (ap->flag&DEFINED)) X printf("%s='%s'\n", ap->name, ap->val.s); X else X rv = 1; X } else { X *val++ = '\0'; X ap = tenter(t, id, hash(id)); X if (ap->type == CKEYWD) X errorf("cannot alias keyword\n"); X if ((ap->flag&ALLOC)) { X afree((Void*)ap->val.s, APERM); X ap->flag &=~ ALLOC|ISSET; X } X ap->type = CALIAS; X ap->val.s = strsave(val, APERM); X ap->flag |= DEFINED|ALLOC|ISSET; X } X } X return rv; X} X Xint Xc_unalias(wp) X register char **wp; X{ X register struct table *t = &lexicals; X register struct tbl *ap; X X if (*++wp != NULL && strcmp(*wp, "-d") == 0) { X t = &homedirs; X wp++; X } X X for (; *wp != NULL; wp++) { X ap = tsearch(t, *wp, hash(*wp)); X if (ap == NULL || ap->type != CALIAS) X continue; X if ((ap->flag&ALLOC)) X afree((Void*)ap->val.s, APERM); X ap->flag &=~ DEFINED|ISSET|ALLOC; X } X return 0; X} X Xint Xc_let(wp) X char **wp; X{ X int rv = 1; X X for (wp++; *wp; wp++) X rv = evaluate(*wp) == 0; X return rv; X} X Xint Xc_jobs(wp) X char **wp; X{ X j_jobs(); X return 0; X} X X#if JOBS Xint Xc_fgbg(wp) X register char **wp; X{ X int bg = strcmp(*wp, "bg") == 0; X X if (!flag[FMONITOR]) X errorf("Job control not enabled\n"); X wp++; X j_resume(j_lookup((*wp == NULL) ? "%" : *wp), bg); X return 0; X} X#endif X Xint Xc_kill(wp) X register char **wp; X{ X register char *cp; X int sig = 15; /* SIGTERM */ X int rv = 0; X X if (*++wp == NULL) X errorf("Usage: kill [-l] [-signal] {pid|job} ...\n"); X if (strcmp(*wp, "-l") == 0) { X register struct trap *p = sigtraps; X for (sig = 0; sig < SIGNALS; sig++, p++) X if (p->signal) X printf("%2d %8s %s\n", p->signal, p->name, p->mess); X return 0; X } X X for (; (cp = *wp) != NULL; wp++) X if (*cp == '-') { X struct trap *p; X p = gettrap(cp+1); X if (p == NULL) X errorf("bad signal %s\n", cp+1); X sig = p->signal; X } else X if (digit(*cp)) { X if (kill(atoi(cp), sig) < 0) { X shellf("%s: %s\n", cp, strerror(errno)); X rv++; X } X } else X if (*cp == '%') X j_kill(j_lookup(cp), sig); X else X errorf("invalid argument\n"); X return rv; X} X Xint Xc_bind(wp) X register char **wp; X{ X int macro = 0; X register char *cp; X X for (wp++; (cp = *wp) != NULL && *cp == '-'; wp++) X if (cp[1] == 'm') X macro = 1; X X if (*wp == NULL) /* list all */ X x_bind((char*)NULL, (char*)NULL, 0); X X for (; *wp != NULL; wp++) { X cp = strchr(*wp, '='); X if (cp != NULL) X *cp++ = 0; X x_bind(*wp, cp, macro); X } X X return 0; X} X Xextern c_fc(); Xextern c_getopts(); X XConst struct builtin kshbuiltins [] = { X {"print", c_print}, X {"getopts", c_getopts}, X {"=typeset", c_typeset}, X {"=export", c_typeset}, X {"=readonly", c_typeset}, X {"whence", c_whence}, X {"alias", c_alias}, X {"unalias", c_unalias}, X {"hash", c_hash}, X {"let", c_let}, X {"fc", c_fc}, X {"jobs", c_jobs}, X {"kill", c_kill}, X#if JOBS X {"fg", c_fgbg}, X {"bg", c_fgbg}, X#endif X#if EDIT X {"bind", c_bind}, X#endif X {NULL, NULL} X}; X SHAR_EOF true || echo 'restore of src/c_ksh.c failed' fi # ============= src/c_test.c ============== if test -f 'src/c_test.c' -a X"$1" != X"-c"; then echo 'x - skipping src/c_test.c (File already exists)' else echo 'x - extracting src/c_test.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'src/c_test.c' && X/* X * test(1); version 7-like -- author Erik Baalbergen X * modified by Eric Gisin to be used as built-in. X * modified by Arnold Robbins to add SVR3 compatibility X * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket). X */ X Xstatic char *RCSid = "$Header: /tmp/egisin/src/RCS/c_test.c,v 3.2 88/12/17 21:39:26 egisin Exp $"; X X#include <stddef.h> X#include <string.h> X#include <signal.h> X#include <errno.h> X#include <setjmp.h> X#include <sys/types.h> X#include <sys/stat.h> X#include "sh.h" X X/* test(1) accepts the following grammar: X oexpr ::= aexpr | aexpr "-o" oexpr ; X aexpr ::= nexpr | nexpr "-a" aexpr ; X nexpr ::= primary ! "!" primary X primary ::= unary-operator operand X | operand binary-operator operand X | operand X | "(" oexpr ")" X ; X unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"| X "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S"; X X binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"| X "-nt"|"-ot"|"-ef"; X operand ::= <any legal UNIX file name> X*/ X X#define EOI 0 X#define FILRD 1 X#define FILWR 2 X#define FILREG 3 X#define FILID 4 X#define FILGZ 5 X#define FILTT 6 X#define STZER 7 X#define STNZE 8 X#define STEQL 9 X#define STNEQ 10 X#define INTEQ 11 X#define INTNE 12 X#define INTGE 13 X#define INTGT 14 X#define INTLE 15 X#define INTLT 16 X#define UNOT 17 X#define BAND 18 X#define BOR 19 X#define LPAREN 20 X#define RPAREN 21 X#define OPERAND 22 X#define FILEX 23 X#define FILCDEV 24 X#define FILBDEV 25 X#define FILFIFO 26 X#define FILSETU 27 X#define FILSETG 28 X#define FILSTCK 29 X#define FILSYM 30 X#define FILNT 31 X#define FILOT 32 X#define FILEQ 33 X#define FILSOCK 34 X#define FILUID 35 X#define FILGID 36 X#define OPTION 37 X X#define UNOP 1 X#define BINOP 2 X#define BUNOP 3 X#define BBINOP 4 X#define PAREN 5 X Xstruct t_op { X char *op_text; X short op_num, op_type; X} Const ops [] = { X {"-r", FILRD, UNOP}, X {"-w", FILWR, UNOP}, X {"-x", FILEX, UNOP}, X {"-f", FILREG, UNOP}, X {"-d", FILID, UNOP}, X {"-c", FILCDEV,UNOP}, X {"-b", FILBDEV,UNOP}, X {"-p", FILFIFO,UNOP}, X {"-u", FILSETU,UNOP}, X {"-g", FILSETG,UNOP}, X {"-k", FILSTCK,UNOP}, X {"-s", FILGZ, UNOP}, X {"-t", FILTT, UNOP}, X {"-z", STZER, UNOP}, X {"-n", STNZE, UNOP}, X#if 0 /* conficts with binary -o */ X {"-o", OPTION, UNOP}, X#endif X {"-U", FILUID, UNOP}, X {"-G", FILGID, UNOP}, X {"-L", FILSYM, UNOP}, X {"-S", FILSOCK,UNOP}, X {"=", STEQL, BINOP}, X {"!=", STNEQ, BINOP}, X {"-eq", INTEQ, BINOP}, X {"-ne", INTNE, BINOP}, X {"-ge", INTGE, BINOP}, X {"-gt", INTGT, BINOP}, X {"-le", INTLE, BINOP}, X {"-lt", INTLT, BINOP}, X {"-nt", FILNT, BINOP}, X {"-ot", FILOT, BINOP}, X {"-ef", FILEQ, BINOP}, X {"!", UNOT, BUNOP}, X {"-a", BAND, BBINOP}, X {"-o", BOR, BBINOP}, X {"(", LPAREN, PAREN}, X {")", RPAREN, PAREN}, X {0, 0, 0} X}; X Xchar **t_wp; Xstruct t_op Const *t_wp_op; X Xint Xc_test(wp) X char **wp; X{ X t_wp = wp+1; X if (strcmp(wp[0], "[") == 0) { X while (*wp != NULL) X wp++; X if (strcmp(*--wp, "]") != 0) X errorf("[: missing ]\n"); X *wp = NULL; X } X return *t_wp == NULL || !oexpr(t_lex(*t_wp)); X} X Xstatic Xsyntax() X{ X errorf("test: syntax error\n"); X} X Xoexpr(n) X{ X int res; X X res = aexpr(n); X if (t_lex(*++t_wp) == BOR) X return oexpr(t_lex(*++t_wp)) || res; X t_wp--; X return res; X} X Xaexpr(n) X{ X int res; X X res = nexpr(n); X if (t_lex(*++t_wp) == BAND) X return aexpr(t_lex(*++t_wp)) && res; X t_wp--; X return res; X} X Xnexpr(n) X int n; /* token */ X{ X if (n == UNOT) X return !nexpr(t_lex(*++t_wp)); X return primary(n); X} X Xprimary(n) X int n; /* token */ X{ X register char *opnd1, *opnd2; X int res; X X if (n == EOI) X syntax(); X if (n == LPAREN) { X res = oexpr(t_lex(*++t_wp)); X if (t_lex(*++t_wp) != RPAREN) X syntax(); X return res; X } X if (n == OPERAND) { X opnd1 = *t_wp; X (void) t_lex(*++t_wp); X if (t_wp_op && t_wp_op->op_type == BINOP) { X struct t_op Const *op = t_wp_op; X X if ((opnd2 = *++t_wp) == (char *)0) X syntax(); X X switch (op->op_num) { X case STEQL: X return strcmp(opnd1, opnd2) == 0; X case STNEQ: X return strcmp(opnd1, opnd2) != 0; X case INTEQ: X return evaluate(opnd1) == evaluate(opnd2); X case INTNE: X return evaluate(opnd1) != evaluate(opnd2); X case INTGE: X return evaluate(opnd1) >= evaluate(opnd2); X case INTGT: X return evaluate(opnd1) > evaluate(opnd2); X case INTLE: X return evaluate(opnd1) <= evaluate(opnd2); X case INTLT: X return evaluate(opnd1) < evaluate(opnd2); X case FILNT: X return newerf (opnd1, opnd2); X case FILOT: X return olderf (opnd1, opnd2); X case FILEQ: X return equalf (opnd1, opnd2); X } X } X t_wp--; X return strlen(opnd1) > 0; X } X if (t_wp_op->op_type == UNOP) { X /* unary expression */ X if (*++t_wp == NULL && n != FILTT) X syntax(); X switch (n) { X case OPTION: X return flag[option(*t_wp)]; X case STZER: X return strlen(*t_wp) == 0; X case STNZE: X return strlen(*t_wp) != 0; X case FILTT: X if (!digit(**t_wp)) X return filstat("0", n); X default: /* all other FIL* */ X return filstat(*t_wp, n); X } X } X syntax(); X} X Xfilstat(nm, mode) X char *nm; X{ X struct stat s; X X switch (mode) { X case FILRD: X return eaccess(nm, 4) == 0; X case FILWR: X return eaccess(nm, 2) == 0; X case FILEX: X return eaccess(nm, 1) == 0; X case FILREG: X return stat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFREG; X case FILID: X return stat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFDIR; X case FILCDEV: X return stat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFCHR; X case FILBDEV: X return stat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFBLK; X case FILFIFO: X#ifdef S_IFIFO X return stat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFIFO; X#else X return 0; X#endif X case FILSETU: X return stat(nm, &s) == 0 && (s.st_mode & S_ISUID) == S_ISUID; X case FILSETG: X return stat(nm, &s) == 0 && (s.st_mode & S_ISGID) == S_ISGID; X case FILSTCK: X return stat(nm, &s) == 0 && (s.st_mode & S_ISVTX) == S_ISVTX; X case FILGZ: X return stat(nm, &s) == 0 && s.st_size > 0L; X case FILTT: X return isatty(getn(nm)); X case FILUID: X return stat(nm, &s) == 0 && s.st_uid == geteuid(); X case FILGID: X return stat(nm, &s) == 0 && s.st_gid == getegid(); X#ifdef S_IFLNK X case FILSYM: X return lstat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFLNK; X#endif X#ifdef S_IFSOCK X case FILSOCK: X return stat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFSOCK; X#endif X default: X return 1; X } X} X Xint Xt_lex(s) X register char *s; X{ X register struct t_op Const *op = ops; X X if (s == 0) X return EOI; X while (op->op_text) { X if (strcmp(s, op->op_text) == 0) { X t_wp_op = op; X return op->op_num; X } X op++; X } X t_wp_op = (struct t_op *)0; X return OPERAND; X} X Xnewerf (f1, f2) Xchar *f1, *f2; X{ X struct stat b1, b2; X X return (stat (f1, &b1) == 0 && X stat (f2, &b2) == 0 && X b1.st_mtime > b2.st_mtime); X} X Xolderf (f1, f2) Xchar *f1, *f2; X{ X struct stat b1, b2; X X return (stat (f1, &b1) == 0 && X stat (f2, &b2) == 0 && X b1.st_mtime < b2.st_mtime); X} X Xequalf (f1, f2) Xchar *f1, *f2; X{ X struct stat b1, b2; X X return (stat (f1, &b1) == 0 && X stat (f2, &b2) == 0 && X b1.st_dev == b2.st_dev && X b1.st_ino == b2.st_ino); X} X SHAR_EOF true || echo 'restore of src/c_test.c failed' fi # ============= src/getopts.c ============== if test -f 'src/getopts.c' -a X"$1" != X"-c"; then echo 'x - skipping src/getopts.c (File already exists)' else echo 'x - extracting src/getopts.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'src/getopts.c' && X/* X * Reimplementation of SysVr3 sh builtin command "getopts" for S5R2 shell. X * X * created by Arnold Robbins X * modified by Doug Gwyn X * modified for PD ksh by Eric Gisin X */ X Xstatic char *RCSid = "$Header: /tmp/egisin/src/RCS/getopts.c,v 3.2 89/01/14 13:29:26 egisin Exp $"; X X#include <stddef.h> X#include <string.h> X#include <errno.h> X#include <setjmp.h> X#include "sh.h" X#include "table.h" X X/* X * The following is derived from getopt() source placed into the public X * domain by AT&T (the only time they're known to have done that). X * X * It has been modified somewhat to fit into the context of the shell. X * X * -D"FASCIST" if you really want to strictly enforce ALL the X * Command Syntax Standard rules (not recommended). X */ X X#define GETOPTEOF (-1) X#define ERR(S, C) shellf("%s%c\n", (S), (C)) X Xstatic int optind; Xstatic char *optarg; Xstatic int sp; X Xstatic int Xgetopt(argc, argv, opts) X int argc; X register char **argv, *opts; X{ X register int c; X register char *cp; X X if (sp == 1) X if (optind >= argc || X argv[optind][0] != '-' || argv[optind][1] == '\0') X return(GETOPTEOF); X else if (strcmp(argv[optind], "--") == 0) { X optind++; X return(GETOPTEOF); X } X c = argv[optind][sp]; X if (c == ':' || (cp=strchr(opts, c)) == NULL) { X ERR("illegal option -- ", c); X if (argv[optind][++sp] == '\0') { X optind++; X sp = 1; X } X optarg = NULL; X return('?'); X } X if (*++cp == ':') { X#if FASCIST X if (sp != 1) { X ERR("option must not be grouped -- ", c ); X optind++; X sp = 1; X optarg = NULL; X return('?'); X } else X#endif X if (argv[optind][sp+1] != '\0') { X#if FASCIST X ERR("option must be followed by whitespace -- ", c ); X optind++; X sp = 1; X optarg = NULL; X return('?'); X#else X optarg = &argv[optind++][sp+1]; X#endif X } else if (++optind >= argc) { X ERR("option requires an argument -- ", c); X sp = 1; X optarg = NULL; X return('?'); X } else X optarg = argv[optind++]; X sp = 1; X } else { X if (argv[optind][++sp] == '\0') { X sp = 1; X optind++; X } X optarg = NULL; X } X return(c); X} X X/* X * The following were created by Arnold Robbins. X */ X X/* resetopts --- magic code for when OPTIND is reset to 1 */ X Xvoid Xresetopts () X{ X optind = 1; X sp = 1; X} X Xint Xc_getopts(wp) X char **wp; X{ X int ret; X register int argc; X char temp[2]; X char *optstr; /* list of options */ X char *name; /* variable to get flag val */ X X if ((optstr = *++wp) == NULL || (name = *++wp) == NULL) X errorf("missing arguments\n"); X X for (argc = 1; wp[argc] != NULL; argc++) X ; X X if (argc > 1) X ret = getopt(argc, wp, optstr); X else X ret = getopt(e.loc->argc+1, e.loc->argv, optstr); X X /* X * set the OPTIND variable in any case, to handle "--" skipping X */ X X setint(global("OPTIND"), (long)optind); X X if (ret == GETOPTEOF) /* end of args */ X return (1); X X /* X * else, got an arg, set the various shell variables X */ X X if (optarg != NULL) X setstr(global("OPTARG"), optarg); X X temp[0] = (char) ret; X temp[1] = '\0'; X setstr(global(name), temp); X X return (0); X} X SHAR_EOF true || echo 'restore of src/getopts.c failed' fi # ============= src/ulimit.c ============== if test -f 'src/ulimit.c' -a X"$1" != X"-c"; then echo 'x - skipping src/ulimit.c (File already exists)' else echo 'x - extracting src/ulimit.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'src/ulimit.c' && X/* X ulimit -- handle "ulimit" builtin X X Eric Gisin, September 1988 X Adapted to PD KornShell. Removed AT&T code. X X last edit: 06-Jun-1987 D A Gwyn X X This started out as the BRL UNIX System V system call emulation X for 4.nBSD, and was later extended by Doug Kingston to handle X the extended 4.nBSD resource limits. It now includes the code X that was originally under case SYSULIMIT in source file "xec.c". X*/ X Xstatic char *RCSid = "$Header: /tmp/egisin/src/RCS/ulimit.c,v 3.1 88/11/03 09:18:11 egisin Exp $"; X X#include <stddef.h> X#include <errno.h> X#include <signal.h> X#include <setjmp.h> X#if defined(_BSD) || defined(_BSD_SYSV) X#include <sys/time.h> X#include <sys/resource.h> X#else X#define RLIMIT_FSIZE 2 X#endif X#include "sh.h" X Xextern long ulimit(); X Xint Xdo_ulimit(a1, a2) X char *a1, *a2; X{ X register int c; X long i; X#if defined(_BSD) || defined(_BSD_SYSV) X struct rlimit limit; /* data being gotten/set */ X int softonly = 0; /* set => soft limit, clear => hard limit */ X int factor = 1024; /* unit scaling (1K or 1) */ X#endif X int command = RLIMIT_FSIZE; X X if (a1 && (*a1 == '-')) /* DAG -- Gould added first test */ X { c = *++a1; /* DAG */ X#if defined(_BSD) || defined(_BSD_SYSV) X if (c >= 'A' && c <= 'Z') X { X ++softonly; X c += 'a' - 'A'; /* DAG -- map to lower-case */ X } X#endif X switch(c) X { X#if defined(_BSD) || defined(_BSD_SYSV) X case 'c': X command = RLIMIT_CORE; X break; X case 'd': X command = RLIMIT_DATA; X break; X case 'm': X command = RLIMIT_RSS; X break; X case 's': X command = RLIMIT_STACK; X break; X case 't': X factor = 1; X command = RLIMIT_CPU; X break; X#endif /* _BSD || _BSD_SYSV */ X case 'f': X command = RLIMIT_FSIZE; X#if _BSD_SYSV X factor = 512; X#endif X break; X default: X#if _BSD X errorf("Usage: %s [-cdmstf] [limit]\n", "ulimit"); X#else X errorf("Usage: %s [-f] [limit]\n", "ulimit"); X#endif X } X a1 = a2; X } X if (a1) X { X i = 0; X while ((c = *a1++) >= '0' && c <= '9') X { X i = (i * 10) + (long)(c - '0'); X if (i < 0) X goto Error; X } X if (c || i < 0) X goto Error; X } X#if !(defined(_BSD) || defined(_BSD_SYSV)) X else X { X i = -1; X command--; X } X X if ((i = ulimit(command, i)) < 0L) X goto Error; X X if (command != RLIMIT_FSIZE) X shellf("%ld\n", i); X#else /* DPK -- generalized for 4.nBSD: */ X if (getrlimit(command, &limit)) X goto Error; /* errno is already set */ X X if (a1) X { X limit.rlim_cur = i * factor; X X if (!softonly) X limit.rlim_max = limit.rlim_cur; X X if (setrlimit(command, &limit)) X goto Error; X } X else X { X i = softonly ? limit.rlim_cur : limit.rlim_max; X#if _BSD /* DAG -- System V always prints an integer */ X if (i == RLIM_INFINITY) X shellf("unlimited\n"); X else X#endif X shellf("%ld\n", i/factor); X } X#endif /* _BSD || _BSD_SYSV */ X return 0; X X Error: X errorf("bad ulimit\n"); X} X SHAR_EOF true || echo 'restore of src/ulimit.c failed' fi # ============= src/var.c ============== if test -f 'src/var.c' -a X"$1" != X"-c"; then echo 'x - skipping src/var.c (File already exists)' else echo 'x - extracting src/var.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'src/var.c' && Xstatic char *RCSid = "$Header: /tmp/egisin/src/RCS/var.c,v 3.1 88/11/03 09:18:22 egisin Exp $"; X X#include <stddef.h> X#include <string.h> X#include <errno.h> X#include <setjmp.h> X#include <time.h> X#include "sh.h" X#include "table.h" X#include "expand.h" X X/* X * Variables X * X * WARNING: unreadable code, needs a rewrite X * X * if (flag&INTEGER), val.i contains integer value, and type contains base. X * otherwise, (val.s + type) contains string value. X * if (flag&EXPORT), val.s contains "name=value" for E-Z exporting. X */ Xchar null [] = ""; Xstatic struct tbl vtemp; Xstatic void getspec(), setspec(); Xstatic void export ARGS((struct tbl *, char *val)); Xstatic int special ARGS ((char *name)); X X/* X * create a new block for function calls and simple commands X * assume caller has allocated and set up e.loc X */ Xvoid Xnewblock() X{ X register struct block *l = e.loc; X static char *empty[] = {""}; X X ainit(&l->area); X l->argc = 0; X l->argv = empty; X l->exit = l->error = NULL; X tinit(&l->vars, &l->area); X tinit(&l->funs, &l->area); X} X X/* X * pop a block handling special variables X */ Xvoid Xpopblock() X{ X register struct block *l = e.loc; X register struct tbl *vp, **vpp = l->vars.tbls; X register int i; X X e.loc = l->next; /* pop block */ X for (i = l->vars.size; --i >= 0; ) X if ((vp = *vpp++) != NULL && (vp->flag&SPECIAL)) X setspec(global(vp->name)); X afreeall(&l->area); X} X X/* X * Search for variable, if not found create globally. X */ Xstruct tbl * Xglobal(n) X register char *n; X{ X register struct block *l = e.loc; X register struct tbl *vp; X register int c; X unsigned h = hash(n); X X c = n[0]; X if (digit(c)) { X vp = &vtemp; X lastarea = ATEMP; X vp->flag = (DEFINED|RDONLY); X vp->type = 0; X *vp->name = c; /* should strncpy */ X for (c = 0; digit(*n) && c < 1000; n++) X c = c*10 + *n-'0'; X if (c <= l->argc) X setstr(vp, l->argv[c]); X return vp; X } else X if (!letter(c)) { X vp = &vtemp; X lastarea = ATEMP; X vp->flag = (DEFINED|RDONLY); X vp->type = 0; X *vp->name = c; X if (n[1] != '\0') X return vp; X vp->flag |= ISSET|INTEGER; X switch (c) { X case '$': X vp->val.i = getpid(); X break; X case '!': X vp->val.i = async; X break; X case '?': X vp->val.i = exstat; X break; X case '#': X vp->val.i = l->argc; X break; X case '-': X vp->flag &= ~ INTEGER; X vp->val.s = getoptions(); X break; X default: X vp->flag &= ~(ISSET|INTEGER); X } X return vp; X } X for (l = e.loc; l != NULL; l = l->next) { X vp = tsearch(&l->vars, n, h); X lastarea = &l->area; X if (vp != NULL) X return vp; X if (l->next == NULL) X break; X } X vp = tenter(&l->vars, n, h); X vp->flag |= DEFINED; X if (special(n)) X vp->flag |= SPECIAL; X return vp; X} X X/* X * Search for local variable, if not found create locally. X */ Xstruct tbl * Xlocal(n) X register char *n; X{ X register struct block *l = e.loc; X register struct tbl *vp; X unsigned h = hash(n); X X if (!letter(*n)) { X vp = &vtemp; X lastarea = ATEMP; X vp->flag = (DEFINED|RDONLY); X vp->type = 0; X return vp; X } X vp = tenter(&l->vars, n, h); X lastarea = &l->area; X vp->flag |= DEFINED; X if (special(n)) X vp->flag |= SPECIAL; X return vp; X} X X/* get variable string value */ Xchar * Xstrval(vp) X register struct tbl *vp; X{ X register char *s; X static char strbuf[40]; X X if ((vp->flag&SPECIAL)) X getspec(vp); X if (!(vp->flag&ISSET)) X return null; /* special to dollar() */ X if (!(vp->flag&INTEGER)) /* string source */ X s = vp->val.s + vp->type; X else { /* integer source */ X register unsigned long n; X register int base; X X s = strbuf + sizeof(strbuf); X n = (vp->val.i < 0) ? -vp->val.i : vp->val.i; X base = (vp->type == 0) ? 10 : vp->type; X X *--s = '\0'; X do { X *--s = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[n%base]; X n /= base; X } while (n != 0); X /* todo: should we output base# ? */ X if (vp->val.i < 0) X *--s = '-'; X } X return s; X} X X/* get variable integer value */ Xlong Xintval(vp) X register struct tbl *vp; X{ X register struct tbl *vq; X X if ((vp->flag&SPECIAL)) X getspec(vp); X if ((vp->flag&INTEGER)) X return vp->val.i; X vq = &vtemp; X vq->flag = (INTEGER); X vq->type = 0; X strint(vq, vp); X return vq->val.i; X} X X/* set variable to string value */ Xvoid Xsetstr(vq, s) X register struct tbl *vq; X char *s; X{ X if (!(vq->flag&INTEGER)) { /* string dest */ X if ((vq->flag&ALLOC)) X afree((Void*)vq->val.s, lastarea); X vq->flag &= ~ (ISSET|ALLOC); X vq->type = 0; X if ((vq->flag&EXPORT)) X export(vq, s); X else X vq->val.s = strsave(s, lastarea); X vq->flag |= ALLOC; X } else { /* integer dest */ X register struct tbl *vp = &vtemp; X vp->flag = (DEFINED|ISSET); X vp->type = 0; X vp->val.s = s; X strint(vq, vp); X } X vq->flag |= ISSET; X if ((vq->flag&SPECIAL)) X setspec(vq); X} X X/* convert variable to integer variable */ Xstruct tbl * Xstrint(vq, vp) X register struct tbl *vq, *vp; X{ X register char *s = vp->val.s + vp->type; X register int c; X int base, neg = 0; X X vq->flag |= INTEGER; X if ((vp->flag&INTEGER)) { X vq->val.i = vp->val.i; X return vq; X } X vq->val.i = 0; X base = 10; X for (c = *s++; c ; c = *s++) X if (c == '-') { X neg++; X } else if (c == '#') { X base = vq->type = vq->val.i; X vq->val.i = 0; X } else if (letnum(c)) { X if ('0' <= c && c <= '9') X c -= '0'; X else if ('a' <= c && c <= 'z') /* fuck EBCDIC */ X c -= 'a'-10; X else if ('A' <= c && c <= 'Z') X c -= 'A'-10; X vq->val.i = (vq->val.i*base) + c; X } else X break; X if (neg) X vq->val.i = -vq->val.i; X if (vq->type < 2 || vq->type > 36) X vq->type = 0; /* default base (10) */ X return vq; X} X X/* set variable to integer */ Xvoid Xsetint(vq, n) X register struct tbl *vq; X long n; X{ X if (!(vq->flag&INTEGER)) { X register struct tbl *vp = &vtemp; X vp->flag = (ISSET|INTEGER); X vp->type = 0; X vp->val.i = n; X setstr(vq, strval(vp)); /* ? */ X } else X vq->val.i = n; X vq->flag |= ISSET; X if ((vq->flag&SPECIAL)) X setspec(vq); X} X X/* set variable from enviroment */ Ximport(thing) X char *thing; X{ X register struct tbl *vp; X register char *val; X X val = strchr(thing, '='); X if (val == NULL) X return 0; X *val = '\0'; X vp = local(thing); X *val++ = '='; X vp->flag |= DEFINED|ISSET|EXPORT; X vp->val.s = thing; X vp->type = val - thing; X if ((vp->flag&SPECIAL)) X setspec(vp); X return 1; X} X X/* X * make vp->val.s be "name=value" for quick exporting. X */ Xstatic void Xexport(vp, val) X register struct tbl *vp; X char *val; X{ X register char *cp, *xp; X char *op = (vp->flag&ALLOC) ? vp->val.s : NULL; X X xp = (char*)alloc(strlen(vp->name) + strlen(val) + 2, lastarea); X vp->flag |= ALLOC; X vp->val.s = xp; X for (cp = vp->name; (*xp = *cp++) != '\0'; xp++) X ; X *xp++ = '='; X vp->type = xp - vp->val.s; /* offset to value */ X for (cp = val; (*xp++ = *cp++) != '\0'; ) X ; X if (op != NULL) X afree((Void*)op, lastarea); X} X X/* X * lookup variable (according to (set&LOCAL)), X * set its attributes (INTEGER, RDONLY, EXPORT, TRACE), X * and optionally set its value if an assignment. X */ Xstruct tbl * Xtypeset(var, set, clr) X register char *var; X int clr, set; X{ X register struct tbl *vp; X register char *val; X X /* check for valid variable name, search for value */ X val = var; X if (!letter(*val)) X return NULL; X for (val++; *val != '\0'; val++) X if (*val == '=') X break; X else if (letnum(*val)) X ; X else X return NULL; X if (*val == '=') X *val = '\0'; X else X val = NULL; X vp = (set&LOCAL) ? local(var) : global(var); X set &= ~ LOCAL; X if (val != NULL) X *val++ = '='; X X if (!(vp->flag&ISSET)) X vp->flag = vp->flag & ~clr | set; X else X if (!(vp->flag&INTEGER) && (set&INTEGER)) { X /* string to integer */ X vtemp.flag = (ISSET); X vtemp.type = 0; X vtemp.val.s = vp->val.s + vp->type; X if ((vp->flag&ALLOC)) X afree((Void*)vp->val.s, lastarea); /* dangerous, used later */ X vp->flag &= ~ ALLOC; X vp->flag |= INTEGER; X vp->type = 0; X strint(vp, &vtemp); X } else X if ((clr&INTEGER) && (vp->flag&INTEGER)) { X /* integer to string */ X vtemp.val.s = strval(vp); X vp->flag &= ~ INTEGER; X setstr(vp, vtemp.val.s); X } X X vp->flag = vp->flag & ~clr | set; X X if (val != NULL) { X if ((vp->flag&RDONLY)) X errorf("cannot set readonly %s\n", var); X if ((vp->flag&INTEGER)) X /* setstr should be able to handle this */ X (void)evaluate(var); X else X setstr(vp, val); X } X X if ((vp->flag&EXPORT) && !(vp->flag&INTEGER) && vp->type == 0) X export(vp, (vp->flag&ISSET) ? vp->val.s : null); X X return vp; X} X Xvoid Xunset(vp) X register struct tbl *vp; X{ X if ((vp->flag&ALLOC)) X afree((Void*)vp->val.s, lastarea); X vp->flag &= ~ (ALLOC|ISSET); X} X Xint Xisassign(s) X register char *s; X{ X if (!letter(*s)) X return (0); X for (s++; *s != '='; s++) X if (*s == 0 || !letnum(*s)) X return (0); X return (1); X} X X/* X * Make the exported environment from the exported names in the dictionary. X */ Xchar ** Xmakenv() X{ X struct block *l = e.loc; X XPtrV env; X register struct tbl *vp, **vpp; X register int i; X X XPinit(env, 64); X for (l = e.loc; l != NULL; l = l->next) X for (vpp = l->vars.tbls, i = l->vars.size; --i >= 0; ) X if ((vp = *vpp++) != NULL X && (vp->flag&(ISSET|EXPORT)) == (ISSET|EXPORT)) { X register struct block *l2; X register struct tbl *vp2; X unsigned h = hash(vp->name); X X lastarea = &l->area; X X /* unexport any redefined instances */ X for (l2 = l->next; l2 != NULL; l2 = l2->next) { X vp2 = tsearch(&l2->vars, vp->name, h); X if (vp2 != NULL) X vp2->flag &= ~ EXPORT; X } X if ((vp->flag&INTEGER)) { X /* integer to string */ X char *val; X val = strval(vp); X vp->flag &= ~ INTEGER; X setstr(vp, val); X } X XPput(env, vp->val.s); X } X XPput(env, NULL); X return (char **) XPclose(env); X} X X/* X * handle special variables with side effects - PATH, SECONDS. X */ X Xstatic int Xspecial(name) X register char * name; X{ X if (strcmp("PATH", name) == 0) X return V_PATH; X if (strcmp("IFS", name) == 0) X return V_IFS; X if (strcmp("SECONDS", name) == 0) X return V_SECONDS; X if (strcmp("OPTIND", name) == 0) X return V_OPTIND; X return V_NONE; X} X Xextern time_t time(); Xstatic time_t seconds; /* time SECONDS last set */ X Xstatic void Xgetspec(vp) X register struct tbl *vp; X{ X switch (special(vp->name)) { X case V_SECONDS: X vp->flag &= ~ SPECIAL; X setint(vp, time((time_t *)0) - seconds); X vp->flag |= SPECIAL; X break; X } X} X Xstatic void Xsetspec(vp) X register struct tbl *vp; X{ X switch (special(vp->name)) { X case V_PATH: X path = strval(vp); X flushcom(1); /* clear tracked aliases */ X break; X case V_IFS: X setctypes(strval(vp), C_IFS); X break; X case V_SECONDS: X seconds = time((time_t *)0); X break; X case V_OPTIND: X if (intval(vp) == 1) X resetopts(); X break; X } X} X SHAR_EOF true || echo 'restore of src/var.c failed' fi # ============= src/table.c ============== if test -f 'src/table.c' -a X"$1" != X"-c"; then echo 'x - skipping src/table.c (File already exists)' else echo 'x - extracting src/table.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'src/table.c' && Xstatic char *RCSid = "$Header: /tmp/egisin/src/RCS/table.c,v 3.1 88/11/03 09:17:53 egisin Exp $"; X X/* X * dynamic hashed associative table for commands and variables X */ X X#include <stddef.h> X#include <errno.h> X#include <setjmp.h> X#include "sh.h" X#include "table.h" X X#define INIT_TBLS 8 /* initial table size (power of 2) */ X Xstatic struct tstate { X int left; X struct tbl **next; X} tstate; X Xstatic void texpand(); X Xunsigned int Xhash(n) X register char * n; X{ X register unsigned int h = 0; X X while (*n != '\0') X h = 2*h + *n++; X return h * 32821; /* scatter bits */ X} X X#if 0 Xphash(s) char *s; { X printf("%2d: %s\n", hash(s)%32, s); X} X#endif X Xvoid Xtinit(tp, ap) X register struct table *tp; X register Area *ap; X{ X tp->areap = ap; X tp->size = tp->free = 0; X tp->tbls = NULL; X} X Xstatic void Xtexpand(tp, nsize) X register struct table *tp; X int nsize; X{ X register int i; X register struct tbl *tblp, **p; X register struct tbl **ntblp, **otblp = tp->tbls; X int osize = tp->size; X X ntblp = alloc(sizeofN(struct tbl *, nsize), tp->areap); X for (i = 0; i < nsize; i++) X ntblp[i] = NULL; X tp->size = nsize; X tp->free = 8*nsize/10; /* table can get 80% full */ X tp->tbls = ntblp; X if (otblp == NULL) X return; X for (i = 0; i < osize; i++) X if ((tblp = otblp[i]) != NULL) X if ((tblp->flag&DEFINED)) { X for (p = &ntblp[hash(tblp->name) & tp->size-1]; X *p != NULL; p--) X if (p == ntblp) /* wrap */ X p += tp->size; X *p = tblp; X tp->free--; X } else { X afree((Void*)tblp, tp->areap); X } X afree((Void*)otblp, tp->areap); X} X Xstruct tbl * Xtsearch(tp, n, h) X register struct table *tp; /* table */ X register char *n; /* name to enter */ X unsigned int h; /* hash(n) */ X{ X register struct tbl **pp, *p; X X if (tp->size == 0) X return NULL; X X /* search for name in hashed table */ X for (pp = &tp->tbls[h & tp->size-1]; (p = *pp) != NULL; pp--) { X if (*p->name == *n && strcmp(p->name, n) == 0 X && (p->flag&DEFINED)) X return p; X if (pp == tp->tbls) /* wrap */ X pp += tp->size; X } X X return NULL; X} X Xstruct tbl * Xtenter(tp, n, h) X register struct table *tp; /* table */ X register char *n; /* name to enter */ X unsigned int h; /* hash(n) */ X{ X register struct tbl **pp, *p; X register char *cp; X X if (tp->size == 0) X texpand(tp, INIT_TBLS); X Search: X /* search for name in hashed table */ X for (pp = &tp->tbls[h & tp->size-1]; (p = *pp) != NULL; pp--) { X if (*p->name == *n && strcmp(p->name, n) == 0) X return p; /* found */ X if (pp == tp->tbls) /* wrap */ X pp += tp->size; X } X X if (tp->free <= 0) { /* too full */ X texpand(tp, 2*tp->size); X goto Search; X } X X /* create new tbl entry */ X for (cp = n; *cp != '\0'; cp++) X ; X p = (struct tbl *) alloc(offsetof(struct tbl, name[(cp-n)+1]), tp->areap); X p->flag = 0; X p->type = 0; X for (cp = p->name; *n != '\0';) X *cp++ = *n++; X *cp = '\0'; X X /* enter in tp->tbls */ X tp->free--; X *pp = p; X return p; X} X Xvoid Xtdelete(p) X register struct tbl *p; X{ X p->flag = 0; X} X Xvoid Xtwalk(tp) X register struct table *tp; X{ X tstate.left = tp->size; X tstate.next = tp->tbls; X} X Xstruct tbl * Xtnext() X{ X while (--tstate.left >= 0) { X struct tbl *p = *tstate.next++; X if (p != NULL && (p->flag&DEFINED)) X return p; X } X return NULL; X} X Xstatic int Xtnamecmp(p1, p2) X Void *p1, *p2; X{ X return strcmp(((struct tbl *)p1)->name, ((struct tbl *)p2)->name); X} X Xstruct tbl ** Xtsort(tp) X register struct table *tp; X{ X register int i; X register struct tbl **p, **sp, **dp; X X p = (struct tbl **)alloc(sizeofN(struct tbl *, tp->size+1), ATEMP); X sp = tp->tbls; /* source */ X dp = p; /* dest */ X for (i = 0; i < tp->size; i++) X if ((*dp = *sp++) != NULL && ((*dp)->flag&DEFINED)) X dp++; X i = dp - p; X qsortp((Void**)p, (size_t)i, tnamecmp); X p[i] = NULL; X return p; X} X SHAR_EOF true || echo 'restore of src/table.c failed' fi true || echo 'restore of src/eval.c failed' echo End of part 5, continue with part 6 exit 0