void Xdol(void) { word *a, *star; char *s, *t; int n; if(count(runq->argv->words)!=1){ Xerror1("variable name not singleton!"); return; } s = runq->argv->words->word; deglob(s); n = 0; for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0'; a = runq->argv->next->words; if(n==0 || *t) a = copywords(vlook(s)->val, a); else{ star = vlook("*")->val; if(star && 1<=n && n<=count(star)){ while(--n) star = star->next; a = newword(star->word, a); } } poplist(); runq->argv->words = a; }
void dotrap(void) { Var *trapreq; Word *starval; while(refdec(&ntrap) >= 0) { if(flag['S']) exits(truestatus()?"":getstatus()); starval=vlook("*")->val; trapreq=vlook("sysint"); if(trapreq->fn){ start(trapreq->fn, trapreq->pc, (Var*)0); runq->local=newvar(strdup("*"), runq->local); runq->local->val=copywords(starval, (Word*)0); runq->local->changed=1; runq->redir=runq->startredir=0; } else { /* * run the stack down until we uncover the * command reading loop. Xreturn will exit * if there is none (i.e. if this is not * an interactive rc.) */ while(!runq->iflag) Xreturn(); } } }
void Xcount(void) { word *a; char *s, *t; int n; char num[12]; if(count(runq->argv->words)!=1){ Xerror1("variable name not singleton!"); return; } s = runq->argv->words->word; deglob(s); n = 0; for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0'; if(n==0 || *t){ a = vlook(s)->val; inttoascii(num, count(a)); } else{ a = vlook("*")->val; inttoascii(num, a && 1<=n && n<=count(a)?1:0); } poplist(); pushword(num); }
void dotrap(void) { int i; struct var *trapreq; struct word *starval; starval = vlook("*")->val; while(ntrap) for(i = 0;i!=NSIG;i++) while(trap[i]){ --trap[i]; --ntrap; if(getpid()!=mypid) Exit(getstatus()); trapreq = vlook(Signame[i]); if(trapreq->fn){ start(trapreq->fn, trapreq->pc, (struct var *)0); runq->local = newvar(strdup("*"), runq->local); runq->local->val = copywords(starval, (struct word *)0); runq->local->changed = 1; runq->redir = runq->startredir = 0; } else if(i==SIGINT || i==SIGQUIT){ /* * run the stack down until we uncover the * command reading loop. Xreturn will exit * if there is none (i.e. if this is not * an interactive rc.) */ while(!runq->iflag) Xreturn(); } else Exit(getstatus()); } }
void execshift(void) { int n; word *a; var *star; switch(count(runq->argv->words)){ default: pfmt(err, "Usage: shift [n]\n"); setstatus("shift usage"); poplist(); return; case 2: n = atoi(runq->argv->words->next->word); break; case 1: n = 1; break; } star = vlook("*"); for(;n && star->val;--n){ a = star->val->next; efree(star->val->word); efree((char *)star->val); star->val = a; star->changed = 1; } setstatus(""); poplist(); }
void Xqdol(void) { word *a, *p; char *s; int n; if(count(runq->argv->words)!=1){ Xerror1("variable name not singleton!"); return; } s = runq->argv->words->word; deglob(s); a = vlook(s)->val; poplist(); n = count(a); if(n==0){ pushword(""); return; } for(p = a;p;p = p->next) n+=strlen(p->word); s = emalloc(n); if(a){ strcpy(s, a->word); for(p = a->next;p;p = p->next){ strcat(s, " "); strcat(s, p->word); } } else s[0]='\0'; pushword(s); efree(s); }
void vinit(void) { char **env, *name, *val, *p; int i; Word *w; Io *f; int n; Var *v; env = _environ; for(i=0; env[i]; free(name), i++) { name = strdup(env[i]); p = strchr(name, '='); if(p == 0 || p == name) continue; *p = 0; val = p+1; n = strlen(val); if(n == 0) continue; if(strncmp(name, "fn#", 3)!=0) { /* variable */ w = 0; p = val+n-1; while(*p) { if(*p == IWS) *p-- = 0; for(; *p && *p != IWS; p--) ; w=newword(p+1, w); } setvar(name, w); vlook(name)->changed=0; } else { /* function */ f = opencore(val, n); execcmds(f); } } v = vlook("path"); p = getenv("path"); if(v->val == 0 && p) v->val = newword(p, 0); }
void setvar(char *name, Word *val) { Var *v=vlook(name); freewords(v->val); v->val=val; v->changed=1; }
void execcd(void) { word *a = runq->argv->words; word *cdpath; char dir[512]; setstatus("can't cd"); cdpath = vlook("cdpath")->val; switch(count(a)){ default: pfmt(err, "Usage: cd [directory]\n"); break; case 2: if(a->next->word[0]=='/' || cdpath==0) cdpath=&nullpath; for(;cdpath;cdpath = cdpath->next){ strcpy(dir, cdpath->word); if(dir[0]) strcat(dir, "/"); strcat(dir, a->next->word); if(dochdir(dir)>=0){ if(strlen(cdpath->word) && strcmp(cdpath->word, ".")!=0) pfmt(err, "%s\n", dir); setstatus(""); break; } } if(cdpath==0) pfmt(err, "Can't cd %s: %r\n", a->next->word); break; case 1: a = vlook("home")->val; if(count(a)>=1){ if(dochdir(a->word)>=0) setstatus(""); else pfmt(err, "Can't cd %s: %r\n", a->word); } else pfmt(err, "Can't cd -- $home empty\n"); break; } poplist(); }
void _setvar(char *name, word *val, int callfn) { struct var *v = vlook(name); freewords(v->val); v->val=val; v->changed=1; if(callfn && v->changefn) v->changefn(v); }
void Vinit(void) { int dir, f, len, i, n, nent; char *buf, *s; char envname[Maxenvname]; word *val; Dir *ent; dir = open("/env", OREAD); if(dir<0){ pfmt(err, "rc: can't open /env: %r\n"); return; } ent = nil; for(;;){ nent = dirread(dir, &ent); if(nent <= 0) break; for(i = 0; i<nent; i++){ len = ent[i].length; if(len && strncmp(ent[i].name, "fn#", 3)!=0){ snprint(envname, sizeof envname, "/env/%s", ent[i].name); if((f = open(envname, 0))>=0){ buf = emalloc(len+1); n = readn(f, buf, len); if (n <= 0) buf[0] = '\0'; else buf[n] = '\0'; val = 0; /* Charitably add a 0 at the end if need be */ if(buf[len-1]) buf[len++]='\0'; s = buf+len-1; for(;;){ while(s!=buf && s[-1]!='\0') --s; val = newword(s, val); if(s==buf) break; --s; } setvar(ent[i].name, val); vlook(ent[i].name)->changed = 0; close(f); efree(buf); } } } free(ent); } close(dir); }
word* searchpath(char *w) { word *path; if(strncmp(w, "/", 1)==0 /* || strncmp(w, "#", 1)==0 */ || strncmp(w, "./", 2)==0 || strncmp(w, "../", 3)==0 || (path = vlook("path")->val)==0) path=&nullpath; return path; }
void Xrdcmds(void) { struct thread *p = runq; word *prompt; flush(err); nerror = 0; if(flag['s'] && !truestatus()) pfmt(err, "status=%v\n", vlook("status")->val); if(runq->iflag){ prompt = vlook("prompt")->val; if(prompt) promptstr = prompt->word; else promptstr="% "; } Noerror(); if(yyparse()){ if(!p->iflag || p->eof && !Eintr()){ if(p->cmdfile) efree(p->cmdfile); closeio(p->cmdfd); Xreturn(); /* should this be omitted? */ } else{ if(Eintr()){ pchr(err, '\n'); p->eof = 0; } --p->pc; /* go back for next command */ } } else{ ntrap = 0; /* avoid double-interrupts during blocked writes */ --p->pc; /* re-execute Xrdcmds after codebuf runs */ start(codebuf, 1, runq->local); } freenodes(); }
void Xunlocal(void) { var *v = runq->local, *hid; if(v==0) panic("Xunlocal: no locals!", 0); runq->local = v->next; hid = vlook(v->name); hid->changed = 1; efree(v->name); freewords(v->val); efree((char *)v); }
void Xexit(void) { struct var *trapreq; struct word *starval; static int beenhere = 0; if(getpid()==mypid && !beenhere){ trapreq = vlook("sigexit"); if(trapreq->fn){ beenhere = 1; --runq->pc; starval = vlook("*")->val; start(trapreq->fn, trapreq->pc, (struct var *)0); runq->local = newvar(strdup("*"), runq->local); runq->local->val = copywords(starval, (struct word *)0); runq->local->changed = 1; runq->redir = runq->startredir = 0; return; } } Exit(getstatus()); }
/* * Initialise awk ARGC, ARGV variables. */ static void awkarginit(int ac, char **av) { int i; wchar_t *cp; ARGVsubi = node(INDEX, vlook(s_ARGV), constant); running = 1; constant->n_int = ac; (void) assign(varARGC, constant); for (i = 0; i < ac; ++i) { cp = mbstowcsdup(av[i]); constant->n_int = i; strassign(exprreduce(ARGVsubi), cp, FSTATIC|FSENSE, wcslen(cp)); } running = 0; }
void Xsub(void) { word *a, *v; char *s; if(count(runq->argv->next->words)!=1){ Xerror1("variable name not singleton!"); return; } s = runq->argv->next->words->word; deglob(s); a = runq->argv->next->next->words; v = vlook(s)->val; a = subwords(v, count(v), runq->argv->words, a); poplist(); poplist(); runq->argv->words = a; }
void Xassign(void) { var *v; if(count(runq->argv->words)!=1){ Xerror1("variable name not singleton!"); return; } deglob(runq->argv->words->word); v = vlook(runq->argv->words->word); poplist(); globlist(); freewords(v->val); v->val = runq->argv->words; v->changed = 1; if(v->changefn) v->changefn(v); runq->argv->words = 0; poplist(); }
/* * mainline for awk */ int main(int argc, char *argv[]) { wchar_t *ap; char *cmd; cmd = argv[0]; _cmdname = cmd; linebuf = emalloc(NLINE * sizeof (wchar_t)); /* * At this point only messaging should be internationalized. * numbers are still scanned as in the Posix locale. */ (void) setlocale(LC_ALL, ""); (void) setlocale(LC_NUMERIC, "C"); #if !defined(TEXT_DOMAIN) #define TEXT_DOMAIN "SYS_TEST" #endif (void) textdomain(TEXT_DOMAIN); awkvarinit(); /* running = 1; */ while (argc > 1 && *argv[1] == '-') { void *save_ptr = NULL; ap = mbstowcsdup(&argv[1][1]); if (ap == NULL) break; if (*ap == '\0') { free(ap); break; } save_ptr = (void *) ap; ++argv; --argc; if (*ap == '-' && ap[1] == '\0') break; for (; *ap != '\0'; ++ap) { switch (*ap) { #ifdef DEBUG case 'd': dflag = 1; continue; #endif case 'f': if (argc < 2) { (void) fprintf(stderr, gettext("Missing script file\n")); return (1); } *progfilep++ = argv[1]; --argc; ++argv; continue; case 'F': if (ap[1] == '\0') { if (argc < 2) { (void) fprintf(stderr, gettext("Missing field separator\n")); return (1); } ap = mbstowcsdup(argv[1]); --argc; ++argv; } else ++ap; strescape(ap); strassign(varFS, linebuf, FALLOC, wcslen(linebuf)); break; case 'v': { wchar_t *vp; wchar_t *arg; if (argc < 2) { (void) fprintf(stderr, gettext("Missing variable assignment\n")); return (1); } arg = mbconvert(argv[1]); /* * Ensure the variable expression * is valid (correct form). */ if (((vp = wcschr(arg, '=')) != NULL) && isclvar(arg)) { *vp = '\0'; strescape(vp+1); strassign(vlook(arg), linebuf, FALLOC|FSENSE, wcslen(linebuf)); *vp = '='; } else { (void) fprintf(stderr, gettext( "Invalid form for variable " "assignment: %S\n"), arg); return (1); } --argc; ++argv; continue; } default: (void) fprintf(stderr, gettext("Unknown option \"-%S\"\n"), ap); return (usage()); } break; } if (save_ptr) free(save_ptr); } if (progfilep == &progfiles[0]) { if (argc < 2) return (usage()); filename = "[command line]"; /* BUG: NEEDS TRANSLATION */ progptr = mbstowcsdup(argv[1]); proglen = wcslen(progptr); --argc; ++argv; } argv[0] = cmd; awkarginit(argc, argv); /* running = 0; */ (void) yyparse(); lineno = 0; /* * Ok, done parsing, so now activate the rest of the nls stuff, set * the radix character. */ (void) setlocale(LC_ALL, ""); radixpoint = *localeconv()->decimal_point; awk(); /* NOTREACHED */ return (0); }
/* * Read an identifier. * Input is first character of identifier. * Return VAR. */ static int lexid(wint_t c) { wchar_t *cp; size_t i; NODE *np; cp = linebuf; do { *cp++ = c; c = lexgetc(); } while (iswalpha(c) || iswdigit(c) || c == '_'); *cp = '\0'; lexungetc(c); yylval.node = np = vlook(linebuf); switch (np->n_type) { case KEYWORD: switch (np->n_keywtype) { case PRINT: case PRINTF: ++inprint; /* FALLTHROUGH */ default: return ((int)np->n_keywtype); } /* NOTREACHED */ case ARRAY: case VAR: /* * If reading the argument list, create a dummy node * for the duration of that function. These variables * can be removed from the symbol table at function end * but they must still exist because the execution tree * knows about them. */ if (funparm) { do_funparm: np = emptynode(PARM, i = (cp-linebuf)); np->n_flags = FSTRING; np->n_string = _null; np->n_strlen = 0; (void) memcpy(np->n_name, linebuf, (i+1) * sizeof (wchar_t)); addsymtab(np); yylval.node = np; } else if (np == varNF || (np == varFS && (!doing_begin || begin_getline))) { /* * If the user program references NF or sets * FS either outside of a begin block or * in a begin block after a getline then the * input line will be split immediately upon read * rather than when a field is first referenced. */ needsplit = 1; } else if (np == varENVIRON) needenviron = 1; /* FALLTHROUGH */ case PARM: return (VAR); case UFUNC: /* * It is ok to redefine functions as parameters */ if (funparm) goto do_funparm; /* FALLTHROUGH */ case FUNC: case GETLINE: /* * When a getline is encountered, clear the 'doing_begin' flag. * This will force the 'needsplit' flag to be set, even inside * a begin block, if FS is altered. (See VAR case above) */ if (doing_begin) begin_getline = 1; return (np->n_type); } /* NOTREACHED */ return (0); }
/* * Do initial setup of buffers, etc. * This must be called before most processing * and especially before lexical analysis. * Variables initialised here will be overruled by command * line parameter initialisation. */ static void awkvarinit() { NODE *np; (void) setvbuf(stderr, NULL, _IONBF, 0); if ((NIOSTREAM = sysconf(_SC_OPEN_MAX) - 4) <= 0) { (void) fprintf(stderr, gettext("not enough available file descriptors")); exit(1); } ofiles = (OFILE *)emalloc(sizeof (OFILE)*NIOSTREAM); #ifdef A_ZERO_POINTERS (void) memset((wchar_t *)ofiles, 0, sizeof (OFILE) * NIOSTREAM); #else { /* initialize file descriptor table */ OFILE *fp; for (fp = ofiles; fp < &ofiles[NIOSTREAM]; fp += 1) { fp->f_fp = FNULL; fp->f_mode = 0; fp->f_name = (char *)0; } } #endif constant = intnode((INT)0); const0 = intnode((INT)0); const1 = intnode((INT)1); constundef = emptynode(CONSTANT, 0); constundef->n_flags = FSTRING|FVINT; constundef->n_string = _null; constundef->n_strlen = 0; inc_oper = emptynode(ADD, 0); inc_oper->n_right = const1; asn_oper = emptynode(ADD, 0); field0 = node(FIELD, const0, NNULL); { RESFUNC near*rp; for (rp = &resfuncs[0]; rp->rf_name != (LOCCHARP)NULL; ++rp) { np = finstall(rp->rf_name, rp->rf_func, rp->rf_type); } } { RESERVED near*rp; for (rp = &reserved[0]; rp->r_name != (LOCCHARP)NULL; ++rp) { switch (rp->r_type) { case SVAR: case VAR: running = 1; np = vlook(rp->r_name); if (rp->r_type == SVAR) np->n_flags |= FSPECIAL; if (rp->r_svalue != NULL) strassign(np, rp->r_svalue, FSTATIC, (size_t)rp->r_ivalue); else { constant->n_int = rp->r_ivalue; (void) assign(np, constant); } running = 0; break; case KEYWORD: kinstall(rp->r_name, (int)rp->r_ivalue); break; } } } varNR = vlook(s_NR); varFNR = vlook(s_FNR); varNF = vlook(s_NF); varOFMT = vlook(s_OFMT); varCONVFMT = vlook(s_CONVFMT); varOFS = vlook(s_OFS); varORS = vlook(s_ORS); varRS = vlook(s_RS); varFS = vlook(s_FS); varARGC = vlook(s_ARGC); varSUBSEP = vlook(s_SUBSEP); varENVIRON = vlook(s_ENVIRON); varFILENAME = vlook(s_FILENAME); varSYMTAB = vlook(s_SYMTAB); incNR = node(ASG, varNR, node(ADD, varNR, const1)); incFNR = node(ASG, varFNR, node(ADD, varFNR, const1)); clrFNR = node(ASG, varFNR, const0); }
char* getstatus(void) { var *status = vlook("status"); return status->val?status->val->word:""; }
void execwhatis(void){ /* mildly wrong -- should fork before writing */ word *a, *b, *path; var *v; struct builtin *bp; char file[512]; struct io out[1]; int found, sep; a = runq->argv->words->next; if(a==0){ Xerror1("Usage: whatis name ..."); return; } setstatus(""); out->fd = mapfd(1); out->bufp = out->buf; out->ebuf = &out->buf[NBUF]; out->strp = 0; for(;a;a = a->next){ v = vlook(a->word); if(v->val){ pfmt(out, "%s=", a->word); if(v->val->next==0) pfmt(out, "%q\n", v->val->word); else{ sep='('; for(b = v->val;b && b->word;b = b->next){ pfmt(out, "%c%q", sep, b->word); sep=' '; } pfmt(out, ")\n"); } found = 1; } else found = 0; v = gvlook(a->word); if(v->fn) pfmt(out, "fn %s %s\n", v->name, v->fn[v->pc-1].s); else{ for(bp = Builtin;bp->name;bp++) if(strcmp(a->word, bp->name)==0){ pfmt(out, "builtin %s\n", a->word); break; } if(!bp->name){ for(path = searchpath(a->word);path;path = path->next){ strcpy(file, path->word); if(file[0]) strcat(file, "/"); strcat(file, a->word); if(Executable(file)){ pfmt(out, "%s\n", file); break; } } if(!path && !found){ pfmt(err, "%s: not found\n", a->word); setstatus("not found"); } } } } poplist(); flush(err); }