Index: head/bin/sh/error.c =================================================================== --- head/bin/sh/error.c (revision 279568) +++ head/bin/sh/error.c (revision 279569) @@ -1,199 +1,199 @@ /*- * 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. * 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 #if 0 static char sccsid[] = "@(#)error.c 8.2 (Berkeley) 5/4/95"; #endif #endif /* not lint */ #include __FBSDID("$FreeBSD$"); /* * Errors and exceptions. */ #include "shell.h" +#include "eval.h" #include "main.h" #include "options.h" #include "output.h" #include "error.h" #include "nodes.h" /* show.h needs nodes.h */ #include "show.h" #include "trap.h" #include #include #include #include /* * Code to handle exceptions in C. */ struct jmploc *handler; volatile sig_atomic_t exception; volatile sig_atomic_t suppressint; volatile sig_atomic_t intpending; -char *commandname; static void exverror(int, const char *, va_list) __printf0like(2, 0) __dead2; /* * 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". * * Interrupts are disabled; they should be reenabled when the exception is * caught. */ void exraise(int e) { INTOFF; if (handler == NULL) abort(); exception = e; longjmp(handler->loc, 1); } /* * Called from trap.c when a SIGINT is received and not suppressed, or when * an interrupt is pending and interrupts are re-enabled using INTON. * (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. If SIGINTs are not * suppressed and the shell is not a root shell, then we want to be * terminated if we get here, as if we were terminated directly by a SIGINT. * Arrange for this here. */ void onint(void) { sigset_t sigs; intpending = 0; sigemptyset(&sigs); sigprocmask(SIG_SETMASK, &sigs, NULL); /* * This doesn't seem to be needed, since main() emits a newline. */ #if 0 if (tcgetpgrp(0) == getpid()) write(STDERR_FILENO, "\n", 1); #endif if (rootshell && iflag) exraise(EXINT); else { signal(SIGINT, SIG_DFL); kill(getpid(), SIGINT); _exit(128 + SIGINT); } } static void vwarning(const char *msg, va_list ap) { if (commandname) outfmt(out2, "%s: ", commandname); else if (arg0) outfmt(out2, "%s: ", arg0); doformat(out2, msg, ap); out2fmt_flush("\n"); } void warning(const char *msg, ...) { va_list ap; va_start(ap, msg); vwarning(msg, ap); va_end(ap); } /* * 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(int cond, const char *msg, va_list ap) { /* * An interrupt trumps an error. Certain places catch error * exceptions or transform them to a plain nonzero exit code * in child processes, and if an error exception can be handled, * an interrupt can be handled as well. * * exraise() will disable interrupts for the exception handler. */ FORCEINTON; #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) vwarning(msg, ap); flushall(); exraise(cond); } void error(const char *msg, ...) { va_list ap; va_start(ap, msg); exverror(EXERROR, msg, ap); va_end(ap); } void exerror(int cond, const char *msg, ...) { va_list ap; va_start(ap, msg); exverror(cond, msg, ap); va_end(ap); } Index: head/bin/sh/mknodes.c =================================================================== --- head/bin/sh/mknodes.c (revision 279568) +++ head/bin/sh/mknodes.c (revision 279569) @@ -1,449 +1,449 @@ /*- * 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. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if 0 #ifndef lint static char const copyright[] = "@(#) Copyright (c) 1991, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint static char sccsid[] = "@(#)mknodes.c 8.2 (Berkeley) 5/4/95"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); /* * This program reads the nodetypes file and nodes.c.pat file. It generates * the files nodes.h and nodes.c. */ #include #include #include #include #include #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 *, ...) __printf0like(1, 2) __dead2; static char *savestr(const char *); int main(int argc, char *argv[]) { if (argc != 3) error("usage: mknodes file"); infp = stdin; if ((infp = fopen(argv[1], "r")) == NULL) error("Can't open %s: %s", argv[1], strerror(errno)); while (readline()) { if (line[0] == ' ' || line[0] == '\t') parsefield(); else if (line[0] != '\0') parsenode(); } output(argv[2]); exit(0); } static void parsenode(void) { 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(void) { 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[] = "\ +static const char writer[] = "\ /*\n\ * This file was generated by the mknodes program.\n\ */\n\ \n"; static void output(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: %s", file, strerror(errno)); if ((hfile = fopen("nodes.h", "w")) == NULL) error("Can't create nodes.h: %s", strerror(errno)); 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("struct funcdef;\n", hfile); fputs("struct funcdef *copyfunc(union node *);\n", hfile); fputs("union node *getfuncnode(struct funcdef *);\n", hfile); fputs("void reffunc(struct funcdef *);\n", hfile); fputs("void unreffunc(struct funcdef *);\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(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(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(int amount, FILE *fp) { while (amount >= 8) { putc('\t', fp); amount -= 8; } while (--amount >= 0) { putc(' ', fp); } } static int nextfield(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(void) { while (*linep == ' ' || *linep == '\t') linep++; } static int readline(void) { 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 error(const char *msg, ...) { va_list va; va_start(va, msg); (void) fprintf(stderr, "line %d: ", linno); (void) vfprintf(stderr, msg, va); (void) fputc('\n', stderr); va_end(va); exit(2); } static char * savestr(const char *s) { char *p; if ((p = malloc(strlen(s) + 1)) == NULL) error("Out of space"); (void) strcpy(p, s); return p; } Index: head/bin/sh/mksyntax.c =================================================================== --- head/bin/sh/mksyntax.c (revision 279568) +++ head/bin/sh/mksyntax.c (revision 279569) @@ -1,329 +1,329 @@ /*- * 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. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if 0 #ifndef lint static char const copyright[] = "@(#) Copyright (c) 1991, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint static char sccsid[] = "@(#)mksyntax.c 8.2 (Berkeley) 5/4/95"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); /* * This program creates syntax.h and syntax.c. */ #include #include #include #include "parser.h" struct synclass { const char *name; const char *comment; }; /* Syntax classes */ -struct synclass synclass[] = { +static const struct synclass synclass[] = { { "CWORD", "character is nothing special" }, { "CNL", "newline character" }, { "CBACK", "a backslash character" }, { "CSBACK", "a backslash character in single quotes" }, { "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" }, { "CIGN", "character should be ignored" }, { 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[] = { +static const 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[] = "\ +static const char writer[] = "\ /*\n\ * This file was generated by the mksyntax program.\n\ */\n\ \n"; static FILE *cfile; static FILE *hfile; static void add_default(void); static void finish(void); static void init(const char *); static void add(const char *, const char *); static void output_type_macros(void); int main(int argc __unused, char **argv __unused) { int i; char buf[80]; int pos; /* 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); fputs("#include \n", hfile); fputs("#include \n\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); fputs("#define SYNBASE (1 - CHAR_MIN)\n", hfile); fputs("#define PEOF -SYNBASE\n\n", hfile); 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 \"parser.h\"\n", cfile); fputs("#include \"shell.h\"\n", cfile); fputs("#include \"syntax.h\"\n\n", cfile); fputs("/* syntax table used when not in quotes */\n", cfile); init("basesyntax"); add_default(); add("\n", "CNL"); add("\\", "CBACK"); add("'", "CSQUOTE"); add("\"", "CDQUOTE"); add("`", "CBQUOTE"); add("$", "CVAR"); add("}", "CENDVAR"); add("<>();&| \t", "CSPCL"); finish(); fputs("\n/* syntax table used when in double quotes */\n", cfile); init("dqsyntax"); add_default(); add("\n", "CNL"); add("\\", "CBACK"); add("\"", "CENDQUOTE"); add("`", "CBQUOTE"); add("$", "CVAR"); add("}", "CENDVAR"); /* ':/' for tilde expansion, '-^]' for [a\-x] pattern ranges */ add("!*?[]=~:/-^", "CCTL"); finish(); fputs("\n/* syntax table used when in single quotes */\n", cfile); init("sqsyntax"); add_default(); add("\n", "CNL"); add("\\", "CSBACK"); add("'", "CENDQUOTE"); /* ':/' for tilde expansion, '-^]' for [a\-x] pattern ranges */ add("!*?[]=~:/-^", "CCTL"); finish(); fputs("\n/* syntax table used when in arithmetic */\n", cfile); init("arisyntax"); add_default(); add("\n", "CNL"); add("\\", "CBACK"); add("`", "CBQUOTE"); add("\"", "CIGN"); add("$", "CVAR"); add("}", "CENDVAR"); add("(", "CLP"); add(")", "CRP"); finish(); fputs("\n/* character classification table */\n", cfile); init("is_type"); add("0123456789", "ISDIGIT"); add("abcdefghijklmnopqrstuvwxyz", "ISLOWER"); add("ABCDEFGHIJKLMNOPQRSTUVWXYZ", "ISUPPER"); add("_", "ISUNDER"); add("#?$!-*@", "ISSPECL"); finish(); exit(0); } /* * Output the header and declaration of a syntax table. */ static void init(const char *name) { fprintf(hfile, "extern const char %s[];\n", name); fprintf(cfile, "const char %s[SYNBASE + CHAR_MAX + 1] = {\n", name); } static void add_one(const char *key, const char *type) { fprintf(cfile, "\t[SYNBASE + %s] = %s,\n", key, type); } /* * Add default values to the syntax table. */ static void add_default(void) { add_one("PEOF", "CEOF"); add_one("CTLESC", "CCTL"); add_one("CTLVAR", "CCTL"); add_one("CTLENDVAR", "CCTL"); add_one("CTLBACKQ", "CCTL"); add_one("CTLBACKQ + CTLQUOTE", "CCTL"); add_one("CTLARI", "CCTL"); add_one("CTLENDARI", "CCTL"); add_one("CTLQUOTEMARK", "CCTL"); add_one("CTLQUOTEEND", "CCTL"); } /* * Output the footer of a syntax table. */ static void finish(void) { fputs("};\n", cfile); } /* * Add entries to the syntax table. */ static void add(const char *p, const char *type) { for (; *p; ++p) { char c = *p; switch (c) { case '\t': c = 't'; break; case '\n': c = 'n'; break; case '\'': c = '\''; break; case '\\': c = '\\'; break; default: fprintf(cfile, "\t[SYNBASE + '%c'] = %s,\n", c, type); continue; } fprintf(cfile, "\t[SYNBASE + '\\%c'] = %s,\n", c, type); } } /* * Output character classification macros (e.g. is_digit). If digits are * contiguous, we can test for them quickly. */ static const char *macro[] = { "#define is_digit(c)\t((unsigned int)((c) - '0') <= 9)", "#define is_eof(c)\t((c) == PEOF)", "#define is_alpha(c)\t((is_type+SYNBASE)[(int)c] & (ISUPPER|ISLOWER))", "#define is_name(c)\t((is_type+SYNBASE)[(int)c] & (ISUPPER|ISLOWER|ISUNDER))", "#define is_in_name(c)\t((is_type+SYNBASE)[(int)c] & (ISUPPER|ISLOWER|ISUNDER|ISDIGIT))", "#define is_special(c)\t((is_type+SYNBASE)[(int)c] & (ISSPECL|ISDIGIT))", "#define digit_val(c)\t((c) - '0')", NULL }; static void output_type_macros(void) { const char **pp; for (pp = macro ; *pp ; pp++) fprintf(hfile, "%s\n", *pp); } Index: head/bin/sh/var.c =================================================================== --- head/bin/sh/var.c (revision 279568) +++ head/bin/sh/var.c (revision 279569) @@ -1,955 +1,956 @@ /*- * 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. * 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 #if 0 static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 5/4/95"; #endif #endif /* not lint */ #include __FBSDID("$FreeBSD$"); #include #include #include /* * Shell variables. */ #include #include #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" #include "builtins.h" #ifndef NO_HISTORY #include "myhistedit.h" #endif #define VTABSIZE 39 struct varinit { struct var *var; int flags; const char *text; void (*func)(const char *); }; #ifndef NO_HISTORY 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 vps4; static struct var voptind; struct var vdisvfork; +struct localvar *localvars; int forcelocal; static const struct varinit varinit[] = { #ifndef NO_HISTORY { &vhistsize, VUNSET, "HISTSIZE=", sethistsize }, #endif { &vifs, 0, "IFS= \t\n", NULL }, { &vmail, VUNSET, "MAIL=", NULL }, { &vmpath, VUNSET, "MAILPATH=", NULL }, { &vpath, 0, "PATH=" _PATH_DEFPATH, changepath }, /* * vps1 depends on uid */ { &vps2, 0, "PS2=> ", NULL }, { &vps4, 0, "PS4=+ ", NULL }, #ifndef NO_HISTORY { &vterm, VUNSET, "TERM=", setterm }, #endif { &voptind, 0, "OPTIND=1", getoptsreset }, { &vdisvfork, VUNSET, "SH_DISABLE_VFORK=", NULL }, { NULL, 0, NULL, NULL } }; static struct var *vartab[VTABSIZE]; static const char *const locale_names[7] = { "LC_COLLATE", "LC_CTYPE", "LC_MONETARY", "LC_NUMERIC", "LC_TIME", "LC_MESSAGES", NULL }; static const int locale_categories[7] = { LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME, LC_MESSAGES, 0 }; static int varequal(const char *, const char *); static struct var *find_var(const char *, struct var ***, int *); static int localevar(const char *); static void setvareq_const(const char *s, int flags); extern char **environ; /* * This routine initializes the builtin variables and imports the environment. * It is called when the shell is initialized. */ void initvar(void) { char ppid[20]; const struct varinit *ip; struct var *vp; struct var **vpp; char **envp; for (ip = varinit ; (vp = ip->var) != NULL ; ip++) { if (find_var(ip->text, &vpp, &vp->name_len) != NULL) continue; vp->next = *vpp; *vpp = vp; vp->text = __DECONST(char *, ip->text); vp->flags = ip->flags | VSTRFIXED | VTEXTFIXED; vp->func = ip->func; } /* * PS1 depends on uid */ if (find_var("PS1", &vpp, &vps1.name_len) == NULL) { vps1.next = *vpp; *vpp = &vps1; vps1.text = __DECONST(char *, geteuid() ? "PS1=$ " : "PS1=# "); vps1.flags = VSTRFIXED|VTEXTFIXED; } fmtstr(ppid, sizeof(ppid), "%d", (int)getppid()); setvarsafe("PPID", ppid, 0); for (envp = environ ; *envp ; envp++) { if (strchr(*envp, '=')) { setvareq(*envp, VEXPORT|VTEXTFIXED); } } setvareq_const("OPTIND=1", 0); } /* * Safe version of setvar, returns 1 on success 0 on failure. */ int setvarsafe(const char *name, const char *val, int flags) { struct jmploc jmploc; struct jmploc *const savehandler = handler; int err = 0; int inton; inton = is_int_on(); if (setjmp(jmploc.loc)) err = 1; else { handler = &jmploc; setvar(name, val, flags); } handler = savehandler; SETINTON(inton); return err; } /* * Set the value of a variable. The flags argument is stored with the * flags of the variable. If val is NULL, the variable is unset. */ void setvar(const char *name, const char *val, int flags) { const char *p; size_t len; size_t namelen; size_t vallen; 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", (int)namelen, name); len = namelen + 2; /* 2 is space for '=' and '\0' */ if (val == NULL) { flags |= VUNSET; vallen = 0; } else { vallen = strlen(val); len += vallen; } INTOFF; nameeq = ckmalloc(len); memcpy(nameeq, name, namelen); nameeq[namelen] = '='; if (val) memcpy(nameeq + namelen + 1, val, vallen + 1); else nameeq[namelen + 1] = '\0'; setvareq(nameeq, flags); INTON; } static int localevar(const char *s) { const char *const *ss; if (*s != 'L') return 0; if (varequal(s + 1, "ANG")) return 1; if (strncmp(s + 1, "C_", 2) != 0) return 0; if (varequal(s + 3, "ALL")) return 1; for (ss = locale_names; *ss ; ss++) if (varequal(s + 3, *ss + 3)) return 1; return 0; } /* * Sets/unsets an environment variable from a pointer that may actually be a * pointer into environ where the string should not be manipulated. */ static void change_env(const char *s, int set) { char *eqp; char *ss; INTOFF; ss = savestr(s); if ((eqp = strchr(ss, '=')) != NULL) *eqp = '\0'; if (set && eqp != NULL) (void) setenv(ss, eqp + 1, 1); else (void) unsetenv(ss); ckfree(ss); INTON; return; } /* * 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(char *s, int flags) { struct var *vp, **vpp; int nlen; if (aflag) flags |= VEXPORT; if (forcelocal && !(flags & (VNOSET | VNOLOCAL))) mklocal(s); vp = find_var(s, &vpp, &nlen); if (vp != NULL) { if (vp->flags & VREADONLY) { if ((flags & (VTEXTFIXED|VSTACK)) == 0) ckfree(s); error("%.*s: is read only", vp->name_len, s); } if (flags & VNOSET) { if ((flags & (VTEXTFIXED|VSTACK)) == 0) ckfree(s); return; } INTOFF; if (vp->func && (flags & VNOFUNC) == 0) (*vp->func)(s + vp->name_len + 1); if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0) ckfree(vp->text); vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET); vp->flags |= flags; vp->text = s; /* * We could roll this to a function, to handle it as * a regular variable function callback, but why bother? * * Note: this assumes iflag is not set to 1 initially. * As part of initvar(), this is called before arguments * are looked at. */ if ((vp == &vmpath || (vp == &vmail && ! mpathset())) && iflag == 1) chkmail(1); if ((vp->flags & VEXPORT) && localevar(s)) { change_env(s, 1); (void) setlocale(LC_ALL, ""); updatecharset(); } INTON; return; } /* not found */ if (flags & VNOSET) { if ((flags & (VTEXTFIXED|VSTACK)) == 0) ckfree(s); return; } INTOFF; vp = ckmalloc(sizeof (*vp)); vp->flags = flags; vp->text = s; vp->name_len = nlen; vp->next = *vpp; vp->func = NULL; *vpp = vp; if ((vp->flags & VEXPORT) && localevar(s)) { change_env(s, 1); (void) setlocale(LC_ALL, ""); updatecharset(); } INTON; } static void setvareq_const(const char *s, int flags) { setvareq(__DECONST(char *, s), flags | VTEXTFIXED); } /* * Process a linked list of variable assignments. */ void listsetvar(struct strlist *list, int flags) { struct strlist *lp; INTOFF; for (lp = list ; lp ; lp = lp->next) { setvareq(savestr(lp->text), flags); } INTON; } /* * Find the value of a variable. Returns NULL if not set. */ char * lookupvar(const char *name) { struct var *v; v = find_var(name, NULL, NULL); if (v == NULL || v->flags & VUNSET) return NULL; return v->text + v->name_len + 1; } /* * 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(const char *name, int doall) { struct strlist *sp; struct var *v; char *result; result = NULL; for (sp = cmdenviron ; sp ; sp = sp->next) { if (varequal(sp->text, name)) result = strchr(sp->text, '=') + 1; } if (result != NULL) return result; v = find_var(name, NULL, NULL); if (v == NULL || v->flags & VUNSET || (!doall && (v->flags & VEXPORT) == 0)) return NULL; return v->text + v->name_len + 1; } /* * Set up locale for a builtin (LANG/LC_* assignments). */ void bltinsetlocale(void) { struct strlist *lp; int act = 0; char *loc, *locdef; int i; for (lp = cmdenviron ; lp ; lp = lp->next) { if (localevar(lp->text)) { act = 1; break; } } if (!act) return; loc = bltinlookup("LC_ALL", 0); INTOFF; if (loc != NULL) { setlocale(LC_ALL, loc); INTON; updatecharset(); return; } locdef = bltinlookup("LANG", 0); for (i = 0; locale_names[i] != NULL; i++) { loc = bltinlookup(locale_names[i], 0); if (loc == NULL) loc = locdef; if (loc != NULL) setlocale(locale_categories[i], loc); } INTON; updatecharset(); } /* * Undo the effect of bltinlocaleset(). */ void bltinunsetlocale(void) { struct strlist *lp; INTOFF; for (lp = cmdenviron ; lp ; lp = lp->next) { if (localevar(lp->text)) { setlocale(LC_ALL, ""); updatecharset(); return; } } INTON; } /* * Update the localeisutf8 flag. */ void updatecharset(void) { char *charset; charset = nl_langinfo(CODESET); localeisutf8 = !strcmp(charset, "UTF-8"); } void initcharset(void) { updatecharset(); initial_localeisutf8 = localeisutf8; } /* * Generate a list of exported variables. This routine is used to construct * the third argument to execve when executing a program. */ char ** environment(void) { int nenv; struct var **vpp; struct var *vp; char **env, **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; } static int var_compare(const void *a, const void *b) { const char *const *sa, *const *sb; sa = a; sb = b; /* * This compares two var=value strings which creates a different * order from what you would probably expect. POSIX is somewhat * ambiguous on what should be sorted exactly. */ return strcoll(*sa, *sb); } /* * Command to list all variables which are set. This is invoked from the * set command when it is called without any options or operands. */ int showvarscmd(int argc __unused, char **argv __unused) { struct var **vpp; struct var *vp; const char *s; const char **vars; int i, n; /* * POSIX requires us to sort the variables. */ n = 0; for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) { for (vp = *vpp; vp; vp = vp->next) { if (!(vp->flags & VUNSET)) n++; } } INTOFF; vars = ckmalloc(n * sizeof(*vars)); i = 0; for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) { for (vp = *vpp; vp; vp = vp->next) { if (!(vp->flags & VUNSET)) vars[i++] = vp->text; } } qsort(vars, n, sizeof(*vars), var_compare); for (i = 0; i < n; i++) { /* * Skip improper variable names so the output remains usable as * shell input. */ if (!isassignment(vars[i])) continue; s = strchr(vars[i], '='); s++; outbin(vars[i], s - vars[i], out1); out1qstr(s); out1c('\n'); } ckfree(vars); INTON; return 0; } /* * The export and readonly commands. */ int exportcmd(int argc __unused, char **argv) { struct var **vpp; struct var *vp; char **ap; char *name; char *p; char *cmdname; int ch, values; int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT; cmdname = argv[0]; values = 0; while ((ch = nextopt("p")) != '\0') { switch (ch) { case 'p': values = 1; break; } } if (values && *argptr != NULL) error("-p requires no arguments"); if (*argptr != NULL) { for (ap = argptr; (name = *ap) != NULL; ap++) { if ((p = strchr(name, '=')) != NULL) { p++; } else { vp = find_var(name, NULL, NULL); if (vp != NULL) { vp->flags |= flag; if ((vp->flags & VEXPORT) && localevar(vp->text)) { change_env(vp->text, 1); (void) setlocale(LC_ALL, ""); updatecharset(); } continue; } } setvar(name, p, flag); } } else { for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { for (vp = *vpp ; vp ; vp = vp->next) { if (vp->flags & flag) { if (values) { /* * Skip improper variable names * so the output remains usable * as shell input. */ if (!isassignment(vp->text)) continue; out1str(cmdname); out1c(' '); } if (values && !(vp->flags & VUNSET)) { outbin(vp->text, vp->name_len + 1, out1); out1qstr(vp->text + vp->name_len + 1); } else outbin(vp->text, vp->name_len, out1); out1c('\n'); } } } } return 0; } /* * The "local" command. */ int localcmd(int argc __unused, char **argv __unused) { char *name; nextopt(""); 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(char *name) { struct localvar *lvp; struct var **vpp; struct var *vp; INTOFF; lvp = ckmalloc(sizeof (struct localvar)); if (name[0] == '-' && name[1] == '\0') { lvp->text = ckmalloc(sizeof optlist); memcpy(lvp->text, optlist, sizeof optlist); vp = NULL; } else { vp = find_var(name, &vpp, NULL); if (vp == NULL) { if (strchr(name, '=')) setvareq(savestr(name), VSTRFIXED | VNOLOCAL); else setvar(name, NULL, VSTRFIXED | VNOLOCAL); 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 (name[vp->name_len] == '=') setvareq(savestr(name), VNOLOCAL); } } lvp->vp = vp; lvp->next = localvars; localvars = lvp; INTON; } /* * Called after a function returns. */ void poplocalvars(void) { struct localvar *lvp; struct var *vp; INTOFF; while ((lvp = localvars) != NULL) { localvars = lvp->next; vp = lvp->vp; if (vp == NULL) { /* $- saved */ memcpy(optlist, lvp->text, sizeof optlist); ckfree(lvp->text); optschanged(); } 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); } INTON; } int setvarcmd(int argc, char **argv) { if (argc <= 2) return unsetcmd(argc, argv); else if (argc == 3) setvar(argv[1], argv[2], 0); else error("too many arguments"); return 0; } /* * The unset builtin command. */ int unsetcmd(int argc __unused, char **argv __unused) { 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; INTOFF; for (ap = argptr; *ap ; ap++) { if (flg_func) ret |= unsetfunc(*ap); if (flg_var) ret |= unsetvar(*ap); } INTON; return ret; } /* * Unset the specified variable. * Called with interrupts off. */ int unsetvar(const char *s) { struct var **vpp; struct var *vp; vp = find_var(s, &vpp, NULL); if (vp == NULL) return (0); if (vp->flags & VREADONLY) return (1); if (vp->text[vp->name_len + 1] != '\0') setvar(s, "", 0); if ((vp->flags & VEXPORT) && localevar(vp->text)) { change_env(s, 0); setlocale(LC_ALL, ""); updatecharset(); } vp->flags &= ~VEXPORT; vp->flags |= VUNSET; if ((vp->flags & VSTRFIXED) == 0) { if ((vp->flags & VTEXTFIXED) == 0) ckfree(vp->text); *vpp = vp->next; ckfree(vp); } return (0); } /* * Returns true if the two strings specify the same variable. The first * variable name is terminated by '='; the second may be terminated by * either '=' or '\0'. */ static int varequal(const char *p, const char *q) { while (*p == *q++) { if (*p++ == '=') return 1; } if (*p == '=' && *(q - 1) == '\0') return 1; return 0; } /* * Search for a variable. * 'name' may be terminated by '=' or a NUL. * vppp is set to the pointer to vp, or the list head if vp isn't found * lenp is set to the number of characters in 'name' */ static struct var * find_var(const char *name, struct var ***vppp, int *lenp) { unsigned int hashval; int len; struct var *vp, **vpp; const char *p = name; hashval = 0; while (*p && *p != '=') hashval = 2 * hashval + (unsigned char)*p++; len = p - name; if (lenp) *lenp = len; vpp = &vartab[hashval % VTABSIZE]; if (vppp) *vppp = vpp; for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) { if (vp->name_len != len) continue; if (memcmp(vp->text, name, len) != 0) continue; if (vppp) *vppp = vpp; return vp; } return NULL; } Index: head/bin/sh/var.h =================================================================== --- head/bin/sh/var.h (revision 279568) +++ head/bin/sh/var.h (revision 279569) @@ -1,130 +1,130 @@ /*- * 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. * 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 * $FreeBSD$ */ /* * Shell variables. */ /* flags */ #define VEXPORT 0x01 /* variable is exported */ #define VREADONLY 0x02 /* variable cannot be modified */ #define VSTRFIXED 0x04 /* variable struct is statically allocated */ #define VTEXTFIXED 0x08 /* text is statically allocated */ #define VSTACK 0x10 /* text is allocated on the stack */ #define VUNSET 0x20 /* the variable is not set */ #define VNOFUNC 0x40 /* don't call the callback function */ #define VNOSET 0x80 /* do not set variable - just readonly test */ #define VNOLOCAL 0x100 /* ignore forcelocal */ struct var { struct var *next; /* next entry in hash list */ int flags; /* flags are defined above */ int name_len; /* length of name */ 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; +extern struct localvar *localvars; extern int forcelocal; extern struct var vifs; extern struct var vmail; extern struct var vmpath; extern struct var vpath; extern struct var vps1; extern struct var vps2; extern struct var vps4; extern struct var vdisvfork; #ifndef NO_HISTORY extern struct var vhistsize; extern struct var vterm; #endif extern int localeisutf8; /* The parser uses the locale that was in effect at startup. */ extern int initial_localeisutf8; /* * 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 ps4val() (vps4.text + 4) #define optindval() (voptind.text + 7) #ifndef NO_HISTORY #define histsizeval() (vhistsize.text + 9) #define termval() (vterm.text + 5) #endif #define mpathset() ((vmpath.flags & VUNSET) == 0) #define disvforkset() ((vdisvfork.flags & VUNSET) == 0) void initvar(void); void setvar(const char *, const char *, int); void setvareq(char *, int); struct strlist; void listsetvar(struct strlist *, int); char *lookupvar(const char *); char *bltinlookup(const char *, int); void bltinsetlocale(void); void bltinunsetlocale(void); void updatecharset(void); void initcharset(void); char **environment(void); int showvarscmd(int, char **); void mklocal(char *); void poplocalvars(void); int unsetvar(const char *); int setvarsafe(const char *, const char *, int);