Public Domain Korn Shell - Part.05 of 7
USENET Administration
netnews at netcom.UUCP
Wed Dec 12 22:38:04 AEST 1990
#!/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
More information about the Alt.sources
mailing list