static rlim_t zstrtorlimt(const char *s, char **t, int base) { rlim_t ret = 0; if (strcmp(s, "unlimited") == 0) { if (t) *t = (char *) s + 9; return RLIM_INFINITY; } # if defined(RLIM_T_IS_QUAD_T) || defined(RLIM_T_IS_LONG_LONG) || defined(RLIM_T_IS_UNSIGNED) if (!base) { if (*s != '0') base = 10; else if (*++s == 'x' || *s == 'X') base = 16, s++; else base = 8; } if (base <= 10) for (; *s >= '0' && *s < ('0' + base); s++) ret = ret * base + *s - '0'; else for (; idigit(*s) || (*s >= 'a' && *s < ('a' + base - 10)) || (*s >= 'A' && *s < ('A' + base - 10)); s++) ret = ret * base + (idigit(*s) ? (*s - '0') : (*s & 0x1f) + 9); if (t) *t = (char *)s; # else /* !RLIM_T_IS_QUAD_T && !RLIM_T_IS_LONG_LONG && !RLIM_T_IS_UNSIGNED */ ret = zstrtol(s, t, base); # endif /* !RLIM_T_IS_QUAD_T && !RLIM_T_IS_LONG_LONG && !RLIM_T_IS_UNSIGNED */ return ret; }
static int bin_sysopen(char *nam, char **args, Options ops, UNUSED(int func)) { int read = OPT_ISSET(ops, 'r'); int write = OPT_ISSET(ops, 'w'); int append = OPT_ISSET(ops, 'a') ? O_APPEND : 0; int flags = O_NOCTTY | append | ((append || write) ? (read ? O_RDWR : O_WRONLY) : O_RDONLY); char *opt, *ptr, *nextopt, *fdvar; int o, fd, explicit = -1; mode_t perms = 0666; #if defined(FD_CLOEXEC) && !defined(O_CLOEXEC) int fdflags; #endif if (!OPT_ISSET(ops, 'u')) { zwarnnam(nam, "file descriptor not specified"); return 1; } /* file descriptor, either 0-9 or a variable name */ fdvar = OPT_ARG(ops, 'u'); if (idigit(*fdvar) && !fdvar[1]) { explicit = atoi(fdvar); } else if (!isident(fdvar)) {
static int parsedigit(int inkey) { #ifdef MULTIBYTE_SUPPORT /* * It's too dangerous to allow metafied input. See * universalargument for comments on (possibly suboptimal) handling * of digits. We are assuming ASCII is a subset of the multibyte * encoding. */ #else /* allow metafied as well as ordinary digits */ inkey &= 0x7f; #endif /* remember inkey is not a wide character */ if (zmod.base > 10) { if (inkey >= 'a' && inkey < 'a' + zmod.base - 10) return inkey - 'a' + 10; if (inkey >= 'A' && inkey < 'A' + zmod.base - 10) return inkey - 'A' + 10; if (idigit(inkey)) return inkey - '0'; return -1; } if (inkey >= '0' && inkey < '0' + zmod.base) return inkey - '0'; return -1; }
void yank() /**/ { int cc; char *buf = cutbuf; if (!cutbuf) { feep(); return; } if (mult < 0) return; if (vibufspec) { vibufspec = tolower(vibufspec); vibufspec += (idigit(vibufspec)) ? -'1'+26 : -'a'; if (!(buf = vibuf[vibufspec])) { feep(); vibufspec = 0; return; } vibufspec = 0; } yankb = cs; while (mult--) { kct = kringnum; cc = strlen(buf); spaceinline(cc); strncpy((char *) line+cs,buf,cc); cs += cc; yanke = cs; } }
static int isnumglob(void) { int c, ec = '-', ret = 0; int tbs = 256, n = 0; char *tbuf = (char *)zalloc(tbs); while(1) { c = hgetc(); if(lexstop) { lexstop = 0; break; } tbuf[n++] = c; if(!idigit(c)) { if(c != ec) break; if(ec == '>') { ret = 1; break; } ec = '>'; } if(n == tbs) tbuf = (char *)realloc(tbuf, tbs *= 2); } while(n--) hungetc(tbuf[n]); zfree(tbuf, tbs); return ret; }
static unsigned long getnumeric(char *p, int *errp) { unsigned long ret; if (!idigit(*p)) { *errp = 1; return 0; } ret = strtoul(p, &p, 10); *errp = !!*p; return ret; }
static int bin_syserror(char *nam, char **args, Options ops, UNUSED(int func)) { int num = 0; char *errvar = NULL, *msg, *pfx = "", *str; /* variable in which to write error message */ if (OPT_ISSET(ops, 'e')) { errvar = OPT_ARG(ops, 'e'); if (!isident(errvar)) { zwarnnam(nam, "not an identifier: %s", errvar); return 1; } } /* prefix for error message */ if (OPT_ISSET(ops, 'p')) pfx = OPT_ARG(ops, 'p'); if (!*args) num = errno; else { char *ptr = *args; while (*ptr && idigit(*ptr)) ptr++; if (!*ptr && ptr > *args) num = atoi(*args); else { const char **eptr; for (eptr = sys_errnames; *eptr; eptr++) { if (!strcmp(*eptr, *args)) { num = (eptr - sys_errnames) + 1; break; } } if (!*eptr) return 2; } } msg = strerror(num); if (errvar) { str = (char *)zalloc(strlen(msg) + strlen(pfx) + 1); sprintf(str, "%s%s", pfx, msg); setsparam(errvar, str); } else { fprintf(stderr, "%s%s\n", pfx, msg); } return 0; }
void visetbuffer(void) { int ch; if (gotvibufspec || (((ch = getkey(0)) < '1' || ch > '9') && (ch < 'a' || ch > 'z') && (ch < 'A' || ch > 'Z'))) { feep(); return; } if (ch >= 'A' && ch <= 'Z') /* needed in cut() */ vibufappend = 1; else vibufappend = 0; vibufspec = tulower(ch) + (idigit(ch) ? -'1' + 26 : -'a'); gotvibufspec = 1; }
/* * Handle an fd by adding it to the current fd_set. * Return 1 for error (after printing a message), 0 for OK. */ static int handle_digits(char *nam, char *argptr, fd_set *fdset, int *fdmax) { int fd; char *endptr; if (!idigit(*argptr)) { zwarnnam(nam, "expecting file descriptor: %s", argptr); return 1; } fd = (int)zstrtol(argptr, &endptr, 10); if (*endptr) { zwarnnam(nam, "garbage after file descriptor: %s", endptr); return 1; } FD_SET(fd, fdset); if (fd+1 > *fdmax) *fdmax = fd+1; return 0; }
void viputafter() /**/ { int cc; char *buf = cutbuf; if (!cutbuf) { feep(); return; } if (mult < 0) return; if (vibufspec) { vibufspec = tolower(vibufspec); vibufspec += (idigit(vibufspec)) ? -'1'+26 : -'a'; if (!(buf = vibuf[vibufspec])) { feep(); vibufspec = 0; return; } vibufspec = 0; } if (strchr(buf,'\n')) { cs = findeol(); if (cs == ll) { spaceinline(1); line[cs] = '\n'; } } if (cs != ll) cs++; yankb = cs; while (mult--) { kct = kringnum; cc = strlen(buf); spaceinline(cc); strncpy((char *) line+cs,buf,cc); cs += cc; yanke = cs; } cs = yankb; }
static int zzlex(void) { int cct = 0; char *ie; yyval.type = MN_INTEGER; for (;; cct = 0) switch (*ptr++) { case '+': if (*ptr == '+') { ptr++; return (unary) ? PREPLUS : POSTPLUS; } if (*ptr == '=') { ptr++; return PLUSEQ; } return (unary) ? UPLUS : PLUS; case '-': if (*ptr == '-') { ptr++; return (unary) ? PREMINUS : POSTMINUS; } if (*ptr == '=') { ptr++; return MINUSEQ; } if (unary) { if (idigit(*ptr) || *ptr == '.') { ptr--; return lexconstant(); } else return UMINUS; } else return MINUS; case '(': return M_INPAR; case ')': return M_OUTPAR; case '!': if (*ptr == '=') { ptr++; return NEQ; } return NOT; case '~': return COMP; case '&': if (*ptr == '&') { if (*++ptr == '=') { ptr++; return DANDEQ; } return DAND; } else if (*ptr == '=') { ptr++; return ANDEQ; } return AND; case '|': if (*ptr == '|') { if (*++ptr == '=') { ptr++; return DOREQ; } return DOR; } else if (*ptr == '=') { ptr++; return OREQ; } return OR; case '^': if (*ptr == '^') { if (*++ptr == '=') { ptr++; return DXOREQ; } return DXOR; } else if (*ptr == '=') { ptr++; return XOREQ; } return XOR; case '*': if (*ptr == '*') { if (*++ptr == '=') { ptr++; return POWEREQ; } return POWER; } if (*ptr == '=') { ptr++; return MULEQ; } return MUL; case '/': if (*ptr == '=') { ptr++; return DIVEQ; } return DIV; case '%': if (*ptr == '=') { ptr++; return MODEQ; } return MOD; case '<': if (*ptr == '<') { if (*++ptr == '=') { ptr++; return SHLEFTEQ; } return SHLEFT; } else if (*ptr == '=') { ptr++; return LEQ; } return LES; case '>': if (*ptr == '>') { if (*++ptr == '=') { ptr++; return SHRIGHTEQ; } return SHRIGHT; } else if (*ptr == '=') { ptr++; return GEQ; } return GRE; case '=': if (*ptr == '=') { ptr++; return DEQ; } return EQ; case '$': yyval.u.l = mypid; return NUM; case '?': if (unary) { yyval.u.l = lastval; return NUM; } return QUEST; case ':': return COLON; case ',': return COMMA; case '\0': ptr--; return EOI; case '[': { int n, checkradix = 0; if (idigit(*ptr)) { n = zstrtol(ptr, &ptr, 10); if (*ptr != ']' || !idigit(*++ptr)) { zerr("bad base syntax"); return EOI; } yyval.u.l = zstrtol(ptr, &ptr, lastbase = n); return NUM; } if (*ptr == '#') { n = 1; if (*++ptr == '#') { n = -1; ptr++; } if (!idigit(*ptr) && *ptr != '_') goto bofs; if (idigit(*ptr)) { outputradix = n * zstrtol(ptr, &ptr, 10); checkradix = 1; } if (*ptr == '_') { ptr++; if (idigit(*ptr)) outputunderscore = zstrtol(ptr, &ptr, 10); else outputunderscore = 3; } } else { bofs: zerr("bad output format specification"); return EOI; } if(*ptr != ']') goto bofs; if (checkradix) { n = (outputradix < 0) ? -outputradix : outputradix; if (n < 2 || n > 36) { zerr("invalid base (must be 2 to 36 inclusive): %d", outputradix); return EOI; } } ptr++; break; } case ' ': case '\t': case '\n': break; /* Fall through! */ default: if (idigit(*--ptr) || *ptr == '.') return lexconstant(); if (*ptr == '#') { if (*++ptr == '\\' || *ptr == '#') { int v; ptr++; if (!*ptr) { zerr("character missing after ##"); return EOI; } ptr = getkeystring(ptr, NULL, GETKEYS_MATH, &v); yyval.u.l = v; return NUM; } cct = 1; } if ((ie = itype_end(ptr, IIDENT, 0)) != ptr) { int func = 0; char *p; p = ptr; ptr = ie; if (*ptr == '[' || (!cct && *ptr == '(')) { char op = *ptr, cp = ((*ptr == '[') ? ']' : ')'); int l; func = (op == '('); for (ptr++, l = 1; *ptr && l; ptr++) { if (*ptr == op) l++; if (*ptr == cp) l--; if (*ptr == '\\' && ptr[1]) ptr++; } } yylval = dupstrpfx(p, ptr - p); return (func ? FUNC : (cct ? CID : ID)); } else if (cct) { yyval.u.l = poundgetfn(NULL); return NUM; } return EOI; } }
static int lexconstant(void) { #ifdef USE_LOCALE char *prev_locale; #endif char *nptr; nptr = ptr; if (*nptr == '-') nptr++; if (*nptr == '0') { int lowchar; nptr++; lowchar = tolower(*nptr); if (lowchar == 'x' || lowchar == 'b') { /* Let zstrtol parse number with base */ yyval.u.l = zstrtol_underscore(ptr, &ptr, 0, 1); /* Should we set lastbase here? */ lastbase = (lowchar == 'b') ? 2 : 16; if (isset(FORCEFLOAT)) { yyval.type = MN_FLOAT; yyval.u.d = (double)yyval.u.l; } return NUM; } else if (isset(OCTALZEROES)) { char *ptr2; /* * Make sure this is a real octal constant; * it can't be a base indication (always decimal) * or a floating point number. */ for (ptr2 = nptr; idigit(*ptr2) || *ptr2 == '_'; ptr2++) ; if (ptr2 > nptr && *ptr2 != '.' && *ptr2 != 'e' && *ptr2 != 'E' && *ptr2 != '#') { yyval.u.l = zstrtol_underscore(ptr, &ptr, 0, 1); lastbase = 8; if (isset(FORCEFLOAT)) { yyval.type = MN_FLOAT; yyval.u.d = (double)yyval.u.l; } return NUM; } nptr = ptr2; } } while (idigit(*nptr) || *nptr == '_') nptr++; if (*nptr == '.' || *nptr == 'e' || *nptr == 'E') { char *ptr2; /* it's a float */ yyval.type = MN_FLOAT; #ifdef USE_LOCALE prev_locale = dupstring(setlocale(LC_NUMERIC, NULL)); setlocale(LC_NUMERIC, "POSIX"); #endif if (*nptr == '.') { nptr++; while (idigit(*nptr) || *nptr == '_') nptr++; } if (*nptr == 'e' || *nptr == 'E') { nptr++; if (*nptr == '+' || *nptr == '-') nptr++; while (idigit(*nptr) || *nptr == '_') nptr++; } for (ptr2 = ptr; ptr2 < nptr; ptr2++) { if (*ptr2 == '_') { int len = nptr - ptr; ptr = strdup(ptr); for (ptr2 = ptr; len; len--) { if (*ptr2 == '_') chuck(ptr2); else ptr2++; } break; } } yyval.u.d = strtod(ptr, &nptr); #ifdef USE_LOCALE if (prev_locale) setlocale(LC_NUMERIC, prev_locale); #endif if (ptr == nptr || *nptr == '.') { zerr("bad floating point constant"); return EOI; } ptr = nptr; } else { /* it's an integer */ yyval.u.l = zstrtol_underscore(ptr, &ptr, 10, 1); if (*ptr == '#') { ptr++; lastbase = yyval.u.l; yyval.u.l = zstrtol_underscore(ptr, &ptr, lastbase, 1); } if (isset(FORCEFLOAT)) { yyval.type = MN_FLOAT; yyval.u.d = (double)yyval.u.l; } } return NUM; }
static int bin_sched(char *nam, char **argv, UNUSED(Options ops), UNUSED(int func)) { char *s, **argptr; time_t t; long h, m, sec; struct tm *tm; struct schedcmd *sch, *sch2, *schl; int sn, flags = 0; /* If the argument begins with a -, remove the specified item from the schedule. */ for (argptr = argv; *argptr && **argptr == '-'; argptr++) { char *arg = *argptr + 1; if (idigit(*arg)) { sn = atoi(arg); if (!sn) { zwarnnam("sched", "usage for delete: sched -<item#>."); return 1; } for (schl = NULL, sch = schedcmds, sn--; sch && sn; sch = (schl = sch)->next, sn--); if (!sch) { zwarnnam("sched", "not that many entries"); return 1; } if (schl) schl->next = sch->next; else { scheddeltimed(); schedcmds = sch->next; if (schedcmds) { DPUTS(timedfns && firstnode(timedfns), "BUG: already timed fn (2)"); schedaddtimed(schedcmds->time); } } zsfree(sch->cmd); zfree(sch, sizeof(struct schedcmd)); return 0; } else if (*arg == '-') { /* end of options */ argptr++; break; } else if (!strcmp(arg, "o")) { flags |= SCHEDFLAG_TRASH_ZLE; } else { if (*arg) zwarnnam(nam, "bad option: -%c", *arg); else zwarnnam(nam, "option expected"); return 1; } } /* given no arguments, display the schedule list */ if (!*argptr) { for (sn = 1, sch = schedcmds; sch; sch = sch->next, sn++) { char tbuf[60], *flagstr, *endstr; time_t t; struct tm *tmp; t = sch->time; tmp = localtime(&t); ztrftime(tbuf, 40, "%a %b %e %k:%M:%S", tmp, 0L); if (sch->flags & SCHEDFLAG_TRASH_ZLE) flagstr = "-o "; else flagstr = ""; if (*sch->cmd == '-') endstr = "-- "; else endstr = ""; printf("%3d %s %s%s%s\n", sn, tbuf, flagstr, endstr, sch->cmd); } return 0; } else if (!argptr[1]) { /* other than the two cases above, sched * *requires at least two arguments */ zwarnnam("sched", "not enough arguments"); return 1; } /* The first argument specifies the time to schedule the command for. The remaining arguments form the command. */ s = *argptr++; if (*s == '+') { /* * + introduces a relative time. The rest of the argument may be an * hour:minute offset from the current time. Once the hour and minute * numbers have been extracted, and the format verified, the resulting * offset is simply added to the current time. */ zlong zl = zstrtol(s + 1, &s, 10); if (*s == ':') { m = (long)zstrtol(s + 1, &s, 10); if (*s == ':') sec = (long)zstrtol(s + 1, &s, 10); else sec = 0; if (*s) { zwarnnam("sched", "bad time specifier"); return 1; } t = time(NULL) + (long)zl * 3600 + m * 60 + sec; } else if (!*s) { /* * Alternatively, it may simply be a number of seconds. * This is here for consistency with absolute times. */ t = time(NULL) + (time_t)zl; } else { zwarnnam("sched", "bad time specifier"); return 1; } } else { /* * If there is no +, an absolute time must have been given. * This may be in hour:minute format, optionally followed by a string * starting with `a' or `p' (for a.m. or p.m.). Characters after the * `a' or `p' are ignored. */ zlong zl = zstrtol(s, &s, 10); if (*s == ':') { h = (long)zl; m = (long)zstrtol(s + 1, &s, 10); if (*s == ':') sec = (long)zstrtol(s + 1, &s, 10); else sec = 0; if (*s && *s != 'a' && *s != 'A' && *s != 'p' && *s != 'P') { zwarnnam("sched", "bad time specifier"); return 1; } t = time(NULL); tm = localtime(&t); t -= tm->tm_sec + tm->tm_min * 60 + tm->tm_hour * 3600; if (*s == 'p' || *s == 'P') h += 12; t += h * 3600 + m * 60 + sec; /* * If the specified time is before the current time, it must refer * to tomorrow. */ if (t < time(NULL)) t += 3600 * 24; } else if (!*s) { /* * Otherwise, it must be a raw time specifier. */ t = (long)zl; } else { zwarnnam("sched", "bad time specifier"); return 1; } } /* The time has been calculated; now add the new entry to the linked list of scheduled commands. */ sch = (struct schedcmd *) zalloc(sizeof *sch); sch->time = t; sch->cmd = zjoin(argptr, ' ', 0); sch->flags = flags; /* Insert into list in time order */ if (schedcmds) { if (sch->time < schedcmds->time) { scheddeltimed(); sch->next = schedcmds; schedcmds = sch; DPUTS(timedfns && firstnode(timedfns), "BUG: already timed fn (3)"); schedaddtimed(t); } else { for (sch2 = schedcmds; sch2->next && sch2->next->time < sch->time; sch2 = sch2->next) ; sch->next = sch2->next; sch2->next = sch; } } else { sch->next = NULL; schedcmds = sch; DPUTS(timedfns && firstnode(timedfns), "BUG: already timed fn (4)"); schedaddtimed(t); } return 0; }
static int gettokstr(int c, int sub) { int bct = 0, pct = 0, brct = 0, fdpar = 0; int intpos = 1, in_brace_param = 0; int peek, inquote, unmatched = 0; char endchar='"'; #ifdef DEBUG int ocmdsp = cmdsp; #endif peek = STRING; if (!sub) { len = 0; bptr = tokstr = (char *) hcalloc(bsiz = 32); } for (;;) { int act; int e; int inbl = inblank(c); if (fdpar && !inbl && c != ')') fdpar = 0; if (inbl && !in_brace_param && !pct) act = LX2_BREAK; else { act = lexact2[STOUC(c)]; c = lextok2[STOUC(c)]; } switch (act) { case LX2_BREAK: if (!in_brace_param && !sub) goto brk; break; case LX2_META: c = hgetc(); #ifdef DEBUG if (lexstop) { fputs("BUG: input terminated by Meta\n", stderr); fflush(stderr); goto brk; } #endif add(Meta); break; case LX2_OUTPAR: if (fdpar) { /* this is a single word `( )', treat as INOUTPAR */ add(c); *bptr = '\0'; return INOUTPAR; } if ((sub || in_brace_param) && isset(SHGLOB)) break; if (!in_brace_param && !pct--) { if (sub) { pct = 0; break; } else goto brk; } c = Outpar; break; case LX2_BAR: if (!pct && !in_brace_param) { if (sub) break; else goto brk; } if (unset(SHGLOB) || (!sub && !in_brace_param)) c = Bar; break; case LX2_STRING: e = hgetc(); if (e == '[') { cmdpush(CS_MATHSUBST); add(String); add(Inbrack); c = dquote_parse(']', sub); cmdpop(); if (c) { peek = LEXERR; goto brk; } c = Outbrack; } else if (e == '(') { add(String); c = cmd_or_math_sub(); if (c) { peek = LEXERR; goto brk; } c = Outpar; } else { if (e == '{') { add(c); c = Inbrace; ++bct; cmdpush(CS_BRACEPAR); if (!in_brace_param) in_brace_param = bct; } else { hungetc(e); lexstop = 0; } } break; case LX2_INBRACK: if (!in_brace_param) brct++; c = Inbrack; break; case LX2_OUTBRACK: if (!in_brace_param) brct--; if (brct < 0) brct = 0; c = Outbrack; break; case LX2_INPAR: if (isset(SHGLOB)) { if (sub || in_brace_param) break; if (incasepat && !len) return INPAR; } if (!in_brace_param) { if (!sub) { e = hgetc(); hungetc(e); lexstop = 0; /* For command words, parentheses are only * special at the start. But now we're tokenising * the remaining string. So I don't see what * the old incmdpos test here is for. * pws 1999/6/8 * * Oh, no. * func1( ) * is a valid function definition in [k]sh. The best * thing we can do, without really nasty lookahead tricks, * is break if we find a blank after a parenthesis. At * least this can't happen inside braces or brackets. We * only allow this with SHGLOB (set for both sh and ksh). * * Things like `print @( |foo)' should still * work, because [k]sh don't allow multiple words * in a function definition, so we only do this * in command position. * pws 1999/6/14 */ if (e == ')' || (isset(SHGLOB) && inblank(e) && !bct && !brct && !intpos && incmdpos)) goto brk; } /* * This also handles the [k]sh `foo( )' function definition. * Maintain a variable fdpar, set as long as a single set of * parentheses contains only space. Then if we get to the * closing parenthesis and it is still set, we can assume we * have a function definition. Only do this at the start of * the word, since the (...) must be a separate token. */ if (!pct++ && isset(SHGLOB) && intpos && !bct && !brct) fdpar = 1; } c = Inpar; break; case LX2_INBRACE: if (isset(IGNOREBRACES) || sub) c = '{'; else { if (!len && incmdpos) { add('{'); *bptr = '\0'; return STRING; } if (in_brace_param) { cmdpush(CS_BRACE); } bct++; } break; case LX2_OUTBRACE: if ((isset(IGNOREBRACES) || sub) && !in_brace_param) break; if (!bct) break; if (in_brace_param) { cmdpop(); } if (bct-- == in_brace_param) in_brace_param = 0; c = Outbrace; break; case LX2_COMMA: if (unset(IGNOREBRACES) && !sub && bct > in_brace_param) c = Comma; break; case LX2_OUTANG: if (!intpos) { if (in_brace_param || sub) break; else goto brk; } e = hgetc(); if (e != '(') { hungetc(e); lexstop = 0; goto brk; } add(Outang); if (skipcomm()) { peek = LEXERR; goto brk; } c = Outpar; break; case LX2_INANG: if (isset(SHGLOB) && sub) break; e = hgetc(); if(e == '(' && intpos) { add(Inang); if (skipcomm()) { peek = LEXERR; goto brk; } c = Outpar; break; } hungetc(e); if(isnumglob()) { add(Inang); while ((c = hgetc()) != '>') add(c); c = Outang; break; } lexstop = 0; if (in_brace_param || sub) break; goto brk; case LX2_EQUALS: if (intpos) { e = hgetc(); if (e != '(') { hungetc(e); lexstop = 0; c = Equals; } else { add(Equals); if (skipcomm()) { peek = LEXERR; goto brk; } c = Outpar; } } else if (!sub && peek != ENVSTRING && incmdpos && !bct && !brct) { char *t = tokstr; if (idigit(*t)) while (++t < bptr && idigit(*t)); else { while (iident(*t) && ++t < bptr); if (t < bptr) { *bptr = '\0'; skipparens(Inbrack, Outbrack, &t); } } if (*t == '+') t++; if (t == bptr) { e = hgetc(); if (e == '(' && incmdpos) { *bptr = '\0'; return ENVARRAY; } hungetc(e); lexstop = 0; peek = ENVSTRING; intpos = 2; } else c = Equals; } else c = Equals; break; #ifndef __SYMBIAN32__ case LX2_BKSLASH: c = hgetc(); if (c == '\n') { c = hgetc(); if (!lexstop) continue; } else add(Bnull); if (lexstop) goto brk; break; #endif case LX2_QUOTE: { int strquote = (len && bptr[-1] == String); add(Snull); cmdpush(CS_QUOTE); for (;;) { STOPHIST while ((c = hgetc()) != '\'' && !lexstop) { if (strquote && c == '\\') { add(c); c = hgetc(); if (lexstop) break; } else if (!sub && isset(CSHJUNKIEQUOTES) && c == '\n') { if (bptr[-1] == '\\') bptr--, len--; else break; } add(c); } ALLOWHIST if (c != '\'') { unmatched = '\''; peek = LEXERR; cmdpop(); goto brk; } e = hgetc(); if (e != '\'' || unset(RCQUOTES) || strquote) break; add(c); } cmdpop(); hungetc(e); lexstop = 0; c = Snull; break; } case LX2_DQUOTE: add(Dnull); cmdpush(CS_DQUOTE); c = dquote_parse('"', sub); cmdpop(); if (c) { unmatched = '"'; peek = LEXERR; goto brk; } c = Dnull; break; case LX2_BQUOTE: add(Tick); cmdpush(CS_BQUOTE); SETPARBEGIN inquote = 0; while ((c = hgetc()) != '`' && !lexstop) { if (c == '\\') { c = hgetc(); if (c != '\n') { add(c == '`' || c == '\\' || c == '$' ? Bnull : '\\'); add(c); } else if (!sub && isset(CSHJUNKIEQUOTES)) add(c); } else { if (!sub && isset(CSHJUNKIEQUOTES) && c == '\n') { break; } add(c); if (c == '\'') { if ((inquote = !inquote)) STOPHIST else ALLOWHIST } } } if (inquote) ALLOWHIST cmdpop(); if (c != '`') { unmatched = '`'; peek = LEXERR; goto brk; } c = Tick; SETPAREND break; } #ifdef __SYMBIAN32__ if(c=='\\') { c = hgetc(); if (c != '\n') { if (c == endchar) add(Bnull); else { /* lexstop is implicitly handled here */ add('\\'); } } } #endif add(c); c = hgetc(); if (intpos) intpos--; if (lexstop) break; } brk: hungetc(c); if (unmatched) zerr("unmatched %c", NULL, unmatched); if (in_brace_param) { while(bct-- >= in_brace_param) cmdpop(); zerr("closing brace expected", NULL, 0); } else if (unset(IGNOREBRACES) && !sub && len > 1 && peek == STRING && bptr[-1] == '}' && bptr[-2] != Bnull) { /* hack to get {foo} command syntax work */ bptr--; len--; lexstop = 0; hungetc('}'); } *bptr = '\0'; DPUTS(cmdsp != ocmdsp, "BUG: gettok: cmdstack changed."); return peek; }
int gettok(void) { int c, d; int peekfd = -1, peek; beginning: tokstr = NULL; while (iblank(c = hgetc()) && !lexstop); if (lexstop) return (errflag) ? LEXERR : ENDINPUT; isfirstln = 0; wordbeg = inbufct - (qbang && c == bangchar); hwbegin(-1-(qbang && c == bangchar)); /* word includes the last character read and possibly \ before ! */ if (dbparens) { len = 0; bptr = tokstr = (char *) hcalloc(bsiz = 32); hungetc(c); cmdpush(CS_MATH); c = dquote_parse(infor ? ';' : ')', 0); cmdpop(); *bptr = '\0'; if (!c && infor) { infor--; return DINPAR; } if (c || (c = hgetc()) != ')') { hungetc(c); return LEXERR; } dbparens = 0; return DOUTPAR; } else if (idigit(c)) { /* handle 1< foo */ d = hgetc(); if(d == '&') { d = hgetc(); if(d == '>') { peekfd = c - '0'; hungetc('>'); c = '&'; } else { hungetc(d); lexstop = 0; hungetc('&'); } } else if (d == '>' || d == '<') { peekfd = c - '0'; c = d; } else { hungetc(d); lexstop = 0; } } /* chars in initial position in word */ if (c == hashchar && !nocomments && (isset(INTERACTIVECOMMENTS) || (!zleparse && !expanding && (!interact || unset(SHINSTDIN) || strin)))) { /* History is handled here to prevent extra * * newlines being inserted into the history. */ while ((c = ingetc()) != '\n' && !lexstop) { hwaddc(c); addtoline(c); } if (errflag) peek = LEXERR; else { hwend(); hwbegin(0); hwaddc('\n'); addtoline('\n'); peek = NEWLIN; } return peek; } switch (lexact1[STOUC(c)]) { case LX1_BKSLASH: d = hgetc(); if (d == '\n') goto beginning; hungetc(d); lexstop = 0; break; case LX1_NEWLIN: return NEWLIN; case LX1_SEMI: d = hgetc(); if(d == ';') return DSEMI; else if(d == '&') return SEMIAMP; hungetc(d); lexstop = 0; return SEMI; case LX1_AMPER: d = hgetc(); if (d == '&') return DAMPER; else if (d == '!' || d == '|') return AMPERBANG; else if (d == '>') { tokfd = peekfd; d = hgetc(); if (d == '!' || d == '|') return OUTANGAMPBANG; else if (d == '>') { d = hgetc(); if (d == '!' || d == '|') return DOUTANGAMPBANG; hungetc(d); lexstop = 0; return DOUTANGAMP; } hungetc(d); lexstop = 0; return AMPOUTANG; } hungetc(d); lexstop = 0; return AMPER; case LX1_BAR: d = hgetc(); if (d == '|') return DBAR; else if (d == '&') return BARAMP; hungetc(d); lexstop = 0; return BAR; case LX1_INPAR: d = hgetc(); if (d == '(') { if (infor) { dbparens = 1; return DINPAR; } if (incmdpos) { len = 0; bptr = tokstr = (char *) hcalloc(bsiz = 32); return cmd_or_math(CS_MATH) ? DINPAR : INPAR; } } else if (d == ')') return INOUTPAR; hungetc(d); lexstop = 0; if (!(incond == 1 || incmdpos)) break; return INPAR; case LX1_OUTPAR: return OUTPAR; case LX1_INANG: d = hgetc(); if (!incmdpos && d == '(') { hungetc(d); lexstop = 0; unpeekfd: if(peekfd != -1) { hungetc(c); c = '0' + peekfd; } break; } if (d == '>') { peek = INOUTANG; } else if (d == '<') { int e = hgetc(); if (e == '(') { hungetc(e); hungetc(d); peek = INANG; } else if (e == '<') peek = TRINANG; else if (e == '-') peek = DINANGDASH; else { hungetc(e); lexstop = 0; peek = DINANG; } } else if (d == '&') { peek = INANGAMP; } else { hungetc(d); if(isnumglob()) goto unpeekfd; peek = INANG; } tokfd = peekfd; return peek; case LX1_OUTANG: d = hgetc(); if (d == '(') { hungetc(d); goto unpeekfd; } else if (d == '&') { d = hgetc(); if (d == '!' || d == '|') peek = OUTANGAMPBANG; else { hungetc(d); lexstop = 0; peek = OUTANGAMP; } } else if (d == '!' || d == '|') peek = OUTANGBANG; else if (d == '>') { d = hgetc(); if (d == '&') { d = hgetc(); if (d == '!' || d == '|') peek = DOUTANGAMPBANG; else { hungetc(d); lexstop = 0; peek = DOUTANGAMP; } } else if (d == '!' || d == '|') peek = DOUTANGBANG; else if (d == '(') { hungetc(d); hungetc('>'); peek = OUTANG; } else { hungetc(d); lexstop = 0; peek = DOUTANG; if (isset(HISTALLOWCLOBBER)) hwaddc('|'); } } else { hungetc(d); lexstop = 0; peek = OUTANG; if (!incond && isset(HISTALLOWCLOBBER)) hwaddc('|'); } tokfd = peekfd; return peek; } /* we've started a string, now get the * * rest of it, performing tokenization */ return gettokstr(c, 0); }
static int putpromptchar(int doprint, int endchar, unsigned int *txtchangep) { char *ss, *hostnam; int t0, arg, test, sep, j, numjobs; struct tm *tm; struct timezone dummy_tz; struct timeval tv; time_t timet; Nameddir nd; for (; *bv->fm && *bv->fm != endchar; bv->fm++) { arg = 0; if (*bv->fm == '%' && isset(PROMPTPERCENT)) { int minus = 0; bv->fm++; if (*bv->fm == '-') { minus = 1; bv->fm++; } if (idigit(*bv->fm)) { arg = zstrtol(bv->fm, &bv->fm, 10); if (minus) arg *= -1; } else if (minus) arg = -1; if (*bv->fm == '(') { int tc, otruncwidth; if (idigit(*++bv->fm)) { arg = zstrtol(bv->fm, &bv->fm, 10); } else if (arg < 0) { /* negative numbers don't make sense here */ arg *= -1; } test = 0; ss = pwd; switch (tc = *bv->fm) { case 'c': case '.': case '~': if ((nd = finddir(ss))) { arg--; ss += strlen(nd->dir); } /*FALLTHROUGH*/ case '/': case 'C': /* `/' gives 0, `/any' gives 1, etc. */ if (*ss++ == '/' && *ss) arg--; for (; *ss; ss++) if (*ss == '/') arg--; if (arg <= 0) test = 1; break; case 't': case 'T': case 'd': case 'D': case 'w': timet = time(NULL); tm = localtime(&timet); switch (tc) { case 't': test = (arg == tm->tm_min); break; case 'T': test = (arg == tm->tm_hour); break; case 'd': test = (arg == tm->tm_mday); break; case 'D': test = (arg == tm->tm_mon); break; case 'w': test = (arg == tm->tm_wday); break; } break; case '?': if (lastval == arg) test = 1; break; case '#': if (geteuid() == (uid_t)arg) test = 1; break; case 'g': if (getegid() == (gid_t)arg) test = 1; break; case 'j': for (numjobs = 0, j = 1; j <= maxjob; j++) if (jobtab[j].stat && jobtab[j].procs && !(jobtab[j].stat & STAT_NOPRINT)) numjobs++; if (numjobs >= arg) test = 1; break; case 'l': *bv->bp = '\0'; countprompt(bv->bufline, &t0, 0, 0); if (minus) t0 = zterm_columns - t0; if (t0 >= arg) test = 1; break; case 'e': { Funcstack fsptr = funcstack; test = arg; while (fsptr && test > 0) { test--; fsptr = fsptr->prev; } test = !test; } break; case 'L': if (shlvl >= arg) test = 1; break; case 'S': if (time(NULL) - shtimer.tv_sec >= arg) test = 1; break; case 'v': if (arrlen(psvar) >= arg) test = 1; break; case 'V': if (arrlen(psvar) >= arg) { if (*psvar[(arg ? arg : 1) - 1]) test = 1; } break; case '_': test = (cmdsp >= arg); break; case '!': test = privasserted(); break; default: test = -1; break; } if (!*bv->fm || !(sep = *++bv->fm)) return 0; bv->fm++; /* Don't do the current truncation until we get back */ otruncwidth = bv->truncwidth; bv->truncwidth = 0; if (!putpromptchar(test == 1 && doprint, sep, txtchangep) || !*++bv->fm || !putpromptchar(test == 0 && doprint, ')', txtchangep)) { bv->truncwidth = otruncwidth; return 0; } bv->truncwidth = otruncwidth; continue; } if (!doprint) switch(*bv->fm) { case '[': while(idigit(*++bv->fm)); while(*++bv->fm != ']'); continue; case '<': while(*++bv->fm != '<'); continue; case '>': while(*++bv->fm != '>'); continue; case 'D': if(bv->fm[1]=='{') while(*++bv->fm != '}'); continue; default: continue; } switch (*bv->fm) { case '~': promptpath(pwd, arg, 1); break; case 'd': case '/': promptpath(pwd, arg, 0); break; case 'c': case '.': promptpath(pwd, arg ? arg : 1, 1); break; case 'C': promptpath(pwd, arg ? arg : 1, 0); break; case 'N': promptpath(scriptname ? scriptname : argzero, arg, 0); break; case 'h': case '!': addbufspc(DIGBUFSIZE); convbase(bv->bp, curhist, 10); bv->bp += strlen(bv->bp); break; case 'j': for (numjobs = 0, j = 1; j <= maxjob; j++) if (jobtab[j].stat && jobtab[j].procs && !(jobtab[j].stat & STAT_NOPRINT)) numjobs++; addbufspc(DIGBUFSIZE); sprintf(bv->bp, "%d", numjobs); bv->bp += strlen(bv->bp); break; case 'M': queue_signals(); if ((hostnam = getsparam("HOST"))) stradd(hostnam); unqueue_signals(); break; case 'm': if (!arg) arg++; queue_signals(); if (!(hostnam = getsparam("HOST"))) break; if (arg < 0) { for (ss = hostnam + strlen(hostnam); ss > hostnam; ss--) if (ss[-1] == '.' && !++arg) break; stradd(ss); } else { for (ss = hostnam; *ss; ss++) if (*ss == '.' && !--arg) break; stradd(*ss ? dupstrpfx(hostnam, ss - hostnam) : hostnam); } unqueue_signals(); break; case 'S': txtchangeset(txtchangep, TXTSTANDOUT, TXTNOSTANDOUT); txtset(TXTSTANDOUT); tsetcap(TCSTANDOUTBEG, TSC_PROMPT); break; case 's': txtchangeset(txtchangep, TXTNOSTANDOUT, TXTSTANDOUT); txtunset(TXTSTANDOUT); tsetcap(TCSTANDOUTEND, TSC_PROMPT|TSC_DIRTY); break; case 'B': txtchangeset(txtchangep, TXTBOLDFACE, TXTNOBOLDFACE); txtset(TXTBOLDFACE); tsetcap(TCBOLDFACEBEG, TSC_PROMPT|TSC_DIRTY); break; case 'b': txtchangeset(txtchangep, TXTNOBOLDFACE, TXTBOLDFACE); txtchangeset(txtchangep, TXTNOSTANDOUT, TXTSTANDOUT); txtchangeset(txtchangep, TXTNOUNDERLINE, TXTUNDERLINE); txtunset(TXTBOLDFACE); tsetcap(TCALLATTRSOFF, TSC_PROMPT|TSC_DIRTY); break; case 'U': txtchangeset(txtchangep, TXTUNDERLINE, TXTNOUNDERLINE); txtset(TXTUNDERLINE); tsetcap(TCUNDERLINEBEG, TSC_PROMPT); break; case 'u': txtchangeset(txtchangep, TXTNOUNDERLINE, TXTUNDERLINE); txtunset(TXTUNDERLINE); tsetcap(TCUNDERLINEEND, TSC_PROMPT|TSC_DIRTY); break; case 'F': arg = parsecolorchar(arg, 1); if (arg >= 0 && !(arg & TXTNOFGCOLOUR)) { txtchangeset(txtchangep, arg & TXT_ATTR_FG_ON_MASK, TXTNOFGCOLOUR); txtset(arg & TXT_ATTR_FG_ON_MASK); set_colour_attribute(arg, COL_SEQ_FG, TSC_PROMPT); break; } /* else FALLTHROUGH */ case 'f': txtchangeset(txtchangep, TXTNOFGCOLOUR, TXT_ATTR_FG_ON_MASK); txtunset(TXT_ATTR_FG_ON_MASK); set_colour_attribute(TXTNOFGCOLOUR, COL_SEQ_FG, TSC_PROMPT); break; case 'K': arg = parsecolorchar(arg, 0); if (arg >= 0 && !(arg & TXTNOBGCOLOUR)) { txtchangeset(txtchangep, arg & TXT_ATTR_BG_ON_MASK, TXTNOBGCOLOUR); txtset(arg & TXT_ATTR_BG_ON_MASK); set_colour_attribute(arg, COL_SEQ_BG, TSC_PROMPT); break; } /* else FALLTHROUGH */ case 'k': txtchangeset(txtchangep, TXTNOBGCOLOUR, TXT_ATTR_BG_ON_MASK); txtunset(TXT_ATTR_BG_ON_MASK); set_colour_attribute(TXTNOBGCOLOUR, COL_SEQ_BG, TSC_PROMPT); break; case '[': if (idigit(*++bv->fm)) arg = zstrtol(bv->fm, &bv->fm, 10); if (!prompttrunc(arg, ']', doprint, endchar, txtchangep)) return *bv->fm; break; case '<': case '>': /* Test (minus) here so -0 means "at the right margin" */ if (minus) { *bv->bp = '\0'; countprompt(bv->bufline, &t0, 0, 0); arg = zterm_columns - t0 + arg; if (arg <= 0) arg = 1; } if (!prompttrunc(arg, *bv->fm, doprint, endchar, txtchangep)) return *bv->fm; break; case '{': /*}*/ if (!bv->dontcount++) { addbufspc(1); *bv->bp++ = Inpar; } if (arg <= 0) break; /* else */ /* FALLTHROUGH */ case 'G': if (arg > 0) { addbufspc(arg); while (arg--) *bv->bp++ = Nularg; } else { addbufspc(1); *bv->bp++ = Nularg; } break; case /*{*/ '}': if (bv->trunccount && bv->trunccount >= bv->dontcount) return *bv->fm; if (bv->dontcount && !--bv->dontcount) { addbufspc(1); *bv->bp++ = Outpar; } break; case 't': case '@': case 'T': case '*': case 'w': case 'W': case 'D': { char *tmfmt, *dd, *tmbuf = NULL; switch (*bv->fm) { case 'T': tmfmt = "%K:%M"; break; case '*': tmfmt = "%K:%M:%S"; break; case 'w': tmfmt = "%a %f"; break; case 'W': tmfmt = "%m/%d/%y"; break; case 'D': if (bv->fm[1] == '{' /*}*/) { for (ss = bv->fm + 2; *ss && *ss != /*{*/ '}'; ss++) if(*ss == '\\' && ss[1]) ss++; dd = tmfmt = tmbuf = zalloc(ss - bv->fm); for (ss = bv->fm + 2; *ss && *ss != /*{*/ '}'; ss++) { if(*ss == '\\' && ss[1]) ss++; *dd++ = *ss; } *dd = 0; bv->fm = ss - !*ss; if (!*tmfmt) { free(tmbuf); continue; } } else tmfmt = "%y-%m-%d"; break; default: tmfmt = "%l:%M%p"; break; } gettimeofday(&tv, &dummy_tz); tm = localtime(&tv.tv_sec); /* * Hack because strftime won't say how * much space it actually needs. Try to add it * a few times until it works. Some formats don't * actually have a length, so we could go on for * ever. */ for(j = 0, t0 = strlen(tmfmt)*8; j < 3; j++, t0*=2) { addbufspc(t0); if (ztrftime(bv->bp, t0, tmfmt, tm, tv.tv_usec) >= 0) break; } /* There is enough room for this because addbufspc(t0) * allocates room for t0 * 2 bytes. */ metafy(bv->bp, -1, META_NOALLOC); bv->bp += strlen(bv->bp); zsfree(tmbuf); break; } case 'n': stradd(get_username()); break; case 'l': if (*ttystrname) { ss = (strncmp(ttystrname, "/dev/tty", 8) ? ttystrname + 5 : ttystrname + 8); stradd(ss); } else stradd("()"); break; case 'y': if (*ttystrname) { ss = (strncmp(ttystrname, "/dev/", 5) ? ttystrname : ttystrname + 5); stradd(ss); } else stradd("()"); break; case 'L': addbufspc(DIGBUFSIZE); #if defined(ZLONG_IS_LONG_LONG) && defined(PRINTF_HAS_LLD) sprintf(bv->bp, "%lld", shlvl); #else sprintf(bv->bp, "%ld", (long)shlvl); #endif bv->bp += strlen(bv->bp); break; case '?': addbufspc(DIGBUFSIZE); #if defined(ZLONG_IS_LONG_LONG) && defined(PRINTF_HAS_LLD) sprintf(bv->bp, "%lld", lastval); #else sprintf(bv->bp, "%ld", (long)lastval); #endif bv->bp += strlen(bv->bp); break; case '%': case ')': addbufspc(1); *bv->bp++ = *bv->fm; break; case '#': addbufspc(1); *bv->bp++ = privasserted() ? '#' : '%'; break; case 'v': if (!arg) arg = 1; else if (arg < 0) arg += arrlen(psvar) + 1; if (arg > 0 && arrlen(psvar) >= arg) stradd(psvar[arg - 1]); break; case 'E': tsetcap(TCCLEAREOL, TSC_PROMPT); break; case '^': if (cmdsp) { if (arg >= 0) { if (arg > cmdsp || arg == 0) arg = cmdsp; for (t0 = cmdsp - 1; arg--; t0--) { stradd(cmdnames[cmdstack[t0]]); if (arg) { addbufspc(1); *bv->bp++=' '; } } } else { arg = -arg; if (arg > cmdsp) arg = cmdsp; for (t0 = arg - 1; arg--; t0--) { stradd(cmdnames[cmdstack[t0]]); if (arg) { addbufspc(1); *bv->bp++=' '; } } } } break; case '_': if (cmdsp) { if (arg >= 0) { if (arg > cmdsp || arg == 0) arg = cmdsp; for (t0 = cmdsp - arg; arg--; t0++) { stradd(cmdnames[cmdstack[t0]]); if (arg) { addbufspc(1); *bv->bp++=' '; } } } else { arg = -arg; if (arg > cmdsp) arg = cmdsp; for (t0 = 0; arg--; t0++) { stradd(cmdnames[cmdstack[t0]]); if (arg) { addbufspc(1); *bv->bp++=' '; } } } } break; case 'r': if(bv->rstring) stradd(bv->rstring); break; case 'R': if(bv->Rstring) stradd(bv->Rstring); break; case 'e': { int depth = 0; Funcstack fsptr = funcstack; while (fsptr) { depth++; fsptr = fsptr->prev; } addbufspc(DIGBUFSIZE); sprintf(bv->bp, "%d", depth); bv->bp += strlen(bv->bp); break; } case 'I': if (funcstack && funcstack->tp != FS_SOURCE && !IN_EVAL_TRAP()) { /* * We're in a function or an eval with * EVALLINENO. Calculate the line number in * the file. */ zlong flineno = lineno + funcstack->flineno; /* take account of eval line nos. starting at 1 */ if (funcstack->tp == FS_EVAL) lineno--; addbufspc(DIGBUFSIZE); #if defined(ZLONG_IS_LONG_LONG) && defined(PRINTF_HAS_LLD) sprintf(bv->bp, "%lld", flineno); #else sprintf(bv->bp, "%ld", (long)flineno); #endif bv->bp += strlen(bv->bp); break; } /* else we're in a file and lineno is already correct */ /* FALLTHROUGH */ case 'i': addbufspc(DIGBUFSIZE); #if defined(ZLONG_IS_LONG_LONG) && defined(PRINTF_HAS_LLD) sprintf(bv->bp, "%lld", lineno); #else sprintf(bv->bp, "%ld", (long)lineno); #endif bv->bp += strlen(bv->bp); break; case 'x': if (funcstack && funcstack->tp != FS_SOURCE && !IN_EVAL_TRAP()) promptpath(funcstack->filename ? funcstack->filename : "", arg, 0); else promptpath(scriptfilename ? scriptfilename : argzero, arg, 0); break; case '\0': return 0; case Meta: bv->fm++; break; } } else if(*bv->fm == '!' && isset(PROMPTBANG)) { if(doprint) { if(bv->fm[1] == '!') { bv->fm++; addbufspc(1); pputc('!'); } else { addbufspc(DIGBUFSIZE); convbase(bv->bp, curhist, 10); bv->bp += strlen(bv->bp); } } } else { char c = *bv->fm == Meta ? *++bv->fm ^ 32 : *bv->fm; if (doprint) { addbufspc(1); pputc(c); } } } return *bv->fm; }
static int eltpcmp(const void *a, const void *b) { const SortElt ae = *(const SortElt *)a; const SortElt be = *(const SortElt *)b; const char *as = ae->cmp, *bs = be->cmp; const char *ao = as; int cmp; if (ae->len != -1 || be->len != -1) { /* * Length recorded. We only do that if there are embedded * nulls we need to treat as regular characters. * * Since we don't know where multibyte characters start, * but do know that a null character can't occur inside * one (we are relying on multibyte characters being extensions * of ASCII), we can compare starting from after the last * null character that occurred in both strings. */ const char *cmpa, *cmpb; const char *laststarta = as; int len; if (ae->len != -1) { len = ae->len; if (be->len != -1 && len > be->len) len = be->len; } else len = be->len; for (cmpa = as, cmpb = bs; *cmpa == *cmpb && len--; cmpa++, cmpb++) { if (!*cmpa) { /* * If either string doesn't have a length, we've reached * the end. This is covered in the test below. */ if (ae->len == -1 || be->len == -1) break; laststarta = cmpa + 1; } } if (*cmpa == *cmpb && ae->len != be->len) { /* * Special case: one of the strings has finished, but * another one continues after the NULL. The string * that's finished sorts below the other. We need * to handle this here since strcoll() or strcmp() * will just compare the strings as equal. */ if (ae->len != -1) { if (be->len != -1) { /* * if a is shorter it's earlier, so return -1 and * vice versa */ return (ae->len - be->len) * sortdir; } else { /* * a has a length and so continues, hence * b sorts lower. */ return sortdir; } } else { /* * b must continue because it has a recorded length, * so a sorts lower. */ return - sortdir; } } bs += (laststarta - as); as += (laststarta - as); } #ifdef HAVE_STRCOLL cmp = strcoll(as, bs); #endif if (sortnumeric) { for (; *as == *bs && *as; as++, bs++); #ifndef HAVE_STRCOLL cmp = (int)STOUC(*as) - (int)STOUC(*bs); #endif if (idigit(*as) || idigit(*bs)) { for (; as > ao && idigit(as[-1]); as--, bs--); if (idigit(*as) && idigit(*bs)) { while (*as == '0') as++; while (*bs == '0') bs++; for (; idigit(*as) && *as == *bs; as++, bs++); if (idigit(*as) || idigit(*bs)) { cmp = (int)STOUC(*as) - (int)STOUC(*bs); while (idigit(*as) && idigit(*bs)) as++, bs++; if (idigit(*as) && !idigit(*bs)) return sortdir; if (idigit(*bs) && !idigit(*as)) return -sortdir; } } } } #ifndef HAVE_STRCOLL else cmp = strcmp(as, bs); #endif return sortdir * cmp; }
static int lexconstant(void) { #ifdef USE_LOCALE char *prev_locale; #endif char *nptr; nptr = ptr; if (*nptr == '-') nptr++; if (*nptr == '0') { nptr++; if (*nptr == 'x' || *nptr == 'X') { /* Let zstrtol parse number with base */ yyval.u.l = zstrtol(ptr, &ptr, 0); /* Should we set lastbase here? */ lastbase = 16; return NUM; } else if (isset(OCTALZEROES)) { char *ptr2; /* * Make sure this is a real octal constant; * it can't be a base indication (always decimal) * or a floating point number. */ for (ptr2 = nptr; idigit(*ptr2); ptr2++) ; if (ptr2 > nptr && *ptr2 != '.' && *ptr2 != 'e' && *ptr2 != 'E' && *ptr2 != '#') { yyval.u.l = zstrtol(ptr, &ptr, 0); lastbase = 8; return NUM; } nptr = ptr2; } } else { while (idigit(*nptr)) nptr++; } if (*nptr == '.' || *nptr == 'e' || *nptr == 'E') { /* it's a float */ yyval.type = MN_FLOAT; #ifdef USE_LOCALE prev_locale = dupstring(setlocale(LC_NUMERIC, NULL)); setlocale(LC_NUMERIC, "POSIX"); #endif yyval.u.d = strtod(ptr, &nptr); #ifdef USE_LOCALE if (prev_locale) setlocale(LC_NUMERIC, prev_locale); #endif if (ptr == nptr || *nptr == '.') { zerr("bad floating point constant"); return EOI; } ptr = nptr; } else { /* it's an integer */ yyval.u.l = zstrtol(ptr, &ptr, 10); if (*ptr == '#') { ptr++; yyval.u.l = zstrtol(ptr, &ptr, lastbase = yyval.u.l); } } return NUM; }
static int bin_zselect(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) { #ifdef HAVE_SELECT int i, fd, fdsetind = 0, fdmax = 0, fdcount; fd_set fdset[3]; const char fdchar[3] = "rwe"; struct timeval tv, *tvptr = NULL; char *outarray = "reply", **outdata, **outptr; char *outhash = NULL; LinkList fdlist; for (i = 0; i < 3; i++) FD_ZERO(fdset+i); for (; *args; args++) { char *argptr = *args, *endptr; zlong tempnum; if (*argptr == '-') { for (argptr++; *argptr; argptr++) { switch (*argptr) { /* * Array name for reply, if not $reply. * This gets set to e.g. `-r 0 -w 1' if 0 is ready * for reading and 1 is ready for writing. */ case 'a': case 'A': i = *argptr; if (argptr[1]) argptr++; else if (args[1]) { argptr = *++args; } else { zwarnnam(nam, "argument expected after -%c", *argptr); return 1; } if (idigit(*argptr) || !isident(argptr)) { zwarnnam(nam, "invalid array name: %s", argptr); return 1; } if (i == 'a') outarray = argptr; else outhash = argptr; /* set argptr to next to last char because of increment */ while (argptr[1]) argptr++; break; /* Following numbers indicate fd's for reading */ case 'r': fdsetind = 0; break; /* Following numbers indicate fd's for writing */ case 'w': fdsetind = 1; break; /* Following numbers indicate fd's for errors */ case 'e': fdsetind = 2; break; /* * Get a timeout value in hundredths of a second * (same units as KEYTIMEOUT). 0 means just poll. * If not given, blocks indefinitely. */ case 't': if (argptr[1]) argptr++; else if (args[1]) { argptr = *++args; } else { zwarnnam(nam, "argument expected after -%c", *argptr); return 1; } if (!idigit(*argptr)) { zwarnnam(nam, "number expected after -t"); return 1; } tempnum = zstrtol(argptr, &endptr, 10); if (*endptr) { zwarnnam(nam, "garbage after -t argument: %s", endptr); return 1; } /* timevalue now active */ tvptr = &tv; tv.tv_sec = (long)(tempnum / 100); tv.tv_usec = (long)(tempnum % 100) * 10000L; /* remember argptr is incremented at end of loop */ argptr = endptr - 1; break; /* Digits following option without arguments are fd's. */ default: if (handle_digits(nam, argptr, fdset+fdsetind, &fdmax)) return 1; } } } else if (handle_digits(nam, argptr, fdset+fdsetind, &fdmax)) return 1; } errno = 0; do { i = select(fdmax, (SELECT_ARG_2_T)fdset, (SELECT_ARG_2_T)(fdset+1), (SELECT_ARG_2_T)(fdset+2), tvptr); } while (i < 0 && errno == EINTR && !errflag); if (i <= 0) { if (i < 0) zwarnnam(nam, "error on select: %e", errno); /* else no fd's set. Presumably a timeout. */ return 1; } /* * Make a linked list of all file descriptors which are ready. * These go into an array preceded by -r, -w or -e for read, write, * error as appropriate. Typically there will only be one set * so this looks rather like overkill. */ fdlist = znewlinklist(); for (i = 0; i < 3; i++) { int doneit = 0; for (fd = 0; fd < fdmax; fd++) { if (FD_ISSET(fd, fdset+i)) { char buf[BDIGBUFSIZE]; if (outhash) { /* * Key/value pairs; keys are fd's (as strings), * value is a (possibly improper) subset of "rwe". */ LinkNode nptr; int found = 0; convbase(buf, fd, 10); for (nptr = firstnode(fdlist); nptr; nptr = nextnode(nextnode(nptr))) { if (!strcmp((char *)getdata(nptr), buf)) { /* Already there, add new character. */ void **dataptr = getaddrdata(nextnode(nptr)); char *data = (char *)*dataptr, *ptr; found = 1; if (!strchr(data, fdchar[i])) { strcpy(buf, data); for (ptr = buf; *ptr; ptr++) ; *ptr++ = fdchar[i]; *ptr = '\0'; zsfree(data); *dataptr = ztrdup(buf); } break; } } if (!found) { /* Add new key/value pair. */ zaddlinknode(fdlist, ztrdup(buf)); buf[0] = fdchar[i]; buf[1] = '\0'; zaddlinknode(fdlist, ztrdup(buf)); } } else { /* List of fd's preceded by -r, -w, -e. */ if (!doneit) { buf[0] = '-'; buf[1] = fdchar[i]; buf[2] = 0; zaddlinknode(fdlist, ztrdup(buf)); doneit = 1; } convbase(buf, fd, 10); zaddlinknode(fdlist, ztrdup(buf)); } } } } /* convert list to array */ fdcount = countlinknodes(fdlist); outptr = outdata = (char **)zalloc((fdcount+1)*sizeof(char *)); while (nonempty(fdlist)) *outptr++ = getlinknode(fdlist); *outptr = NULL; /* and store in array parameter */ if (outhash) sethparam(outhash, outdata); else setaparam(outarray, outdata); freelinklist(fdlist, NULL); return 0; #else /* TODO: use poll */ zerrnam(nam, "your system does not implement the select system call."); return 2; #endif }
static enum lextok gettokstr(int c, int sub) { int bct = 0, pct = 0, brct = 0, seen_brct = 0, fdpar = 0; int intpos = 1, in_brace_param = 0; int inquote, unmatched = 0; enum lextok peek; #ifdef DEBUG int ocmdsp = cmdsp; #endif peek = STRING; if (!sub) { lexbuf.len = 0; lexbuf.ptr = tokstr = (char *) hcalloc(lexbuf.siz = LEX_HEAP_SIZE); } for (;;) { int act; int e; int inbl = inblank(c); if (fdpar && !inbl && c != ')') fdpar = 0; if (inbl && !in_brace_param && !pct) act = LX2_BREAK; else { act = lexact2[STOUC(c)]; c = lextok2[STOUC(c)]; } switch (act) { case LX2_BREAK: if (!in_brace_param && !sub) goto brk; break; case LX2_META: c = hgetc(); #ifdef DEBUG if (lexstop) { fputs("BUG: input terminated by Meta\n", stderr); fflush(stderr); goto brk; } #endif add(Meta); break; case LX2_OUTPAR: if (fdpar) { /* this is a single word `( )', treat as INOUTPAR */ add(c); *lexbuf.ptr = '\0'; return INOUTPAR; } if ((sub || in_brace_param) && isset(SHGLOB)) break; if (!in_brace_param && !pct--) { if (sub) { pct = 0; break; } else goto brk; } c = Outpar; break; case LX2_BAR: if (!pct && !in_brace_param) { if (sub) break; else goto brk; } if (unset(SHGLOB) || (!sub && !in_brace_param)) c = Bar; break; case LX2_STRING: e = hgetc(); if (e == '[') { cmdpush(CS_MATHSUBST); add(String); add(Inbrack); c = dquote_parse(']', sub); cmdpop(); if (c) { peek = LEXERR; goto brk; } c = Outbrack; } else if (e == '(') { add(String); switch (cmd_or_math_sub()) { case CMD_OR_MATH_CMD: c = Outpar; break; case CMD_OR_MATH_MATH: c = Outparmath; break; default: peek = LEXERR; goto brk; } } else { if (e == '{') { add(c); c = Inbrace; ++bct; cmdpush(CS_BRACEPAR); if (!in_brace_param) { if ((in_brace_param = bct)) seen_brct = 0; } } else { hungetc(e); lexstop = 0; } } break; case LX2_INBRACK: if (!in_brace_param) { brct++; seen_brct = 1; } c = Inbrack; break; case LX2_OUTBRACK: if (!in_brace_param) brct--; if (brct < 0) brct = 0; c = Outbrack; break; case LX2_INPAR: if (isset(SHGLOB)) { if (sub || in_brace_param) break; if (incasepat && !lexbuf.len) return INPAR; if (!isset(KSHGLOB) && lexbuf.len) goto brk; } if (!in_brace_param) { if (!sub) { e = hgetc(); hungetc(e); lexstop = 0; /* For command words, parentheses are only * special at the start. But now we're tokenising * the remaining string. So I don't see what * the old incmdpos test here is for. * pws 1999/6/8 * * Oh, no. * func1( ) * is a valid function definition in [k]sh. The best * thing we can do, without really nasty lookahead tricks, * is break if we find a blank after a parenthesis. At * least this can't happen inside braces or brackets. We * only allow this with SHGLOB (set for both sh and ksh). * * Things like `print @( |foo)' should still * work, because [k]sh don't allow multiple words * in a function definition, so we only do this * in command position. * pws 1999/6/14 */ if (e == ')' || (isset(SHGLOB) && inblank(e) && !bct && !brct && !intpos && incmdpos)) { /* * Either a () token, or a command word with * something suspiciously like a ksh function * definition. * The current word isn't spellcheckable. */ nocorrect |= 2; goto brk; } } /* * This also handles the [k]sh `foo( )' function definition. * Maintain a variable fdpar, set as long as a single set of * parentheses contains only space. Then if we get to the * closing parenthesis and it is still set, we can assume we * have a function definition. Only do this at the start of * the word, since the (...) must be a separate token. */ if (!pct++ && isset(SHGLOB) && intpos && !bct && !brct) fdpar = 1; } c = Inpar; break; case LX2_INBRACE: if (isset(IGNOREBRACES) || sub) c = '{'; else { if (!lexbuf.len && incmdpos) { add('{'); *lexbuf.ptr = '\0'; return STRING; } if (in_brace_param) { cmdpush(CS_BRACE); } bct++; } break; case LX2_OUTBRACE: if ((isset(IGNOREBRACES) || sub) && !in_brace_param) break; if (!bct) break; if (in_brace_param) { cmdpop(); } if (bct-- == in_brace_param) in_brace_param = 0; c = Outbrace; break; case LX2_COMMA: if (unset(IGNOREBRACES) && !sub && bct > in_brace_param) c = Comma; break; case LX2_OUTANG: if (in_brace_param || sub) break; e = hgetc(); if (e != '(') { hungetc(e); lexstop = 0; goto brk; } add(OutangProc); if (skipcomm()) { peek = LEXERR; goto brk; } c = Outpar; break; case LX2_INANG: if (isset(SHGLOB) && sub) break; e = hgetc(); if (!(in_brace_param || sub) && e == '(') { add(Inang); if (skipcomm()) { peek = LEXERR; goto brk; } c = Outpar; break; } hungetc(e); if(isnumglob()) { add(Inang); while ((c = hgetc()) != '>') add(c); c = Outang; break; } lexstop = 0; if (in_brace_param || sub) break; goto brk; case LX2_EQUALS: if (!sub) { if (intpos) { e = hgetc(); if (e != '(') { hungetc(e); lexstop = 0; c = Equals; } else { add(Equals); if (skipcomm()) { peek = LEXERR; goto brk; } c = Outpar; } } else if (peek != ENVSTRING && (incmdpos || intypeset) && !bct && !brct) { char *t = tokstr; if (idigit(*t)) while (++t < lexbuf.ptr && idigit(*t)); else { int sav = *lexbuf.ptr; *lexbuf.ptr = '\0'; t = itype_end(t, IIDENT, 0); if (t < lexbuf.ptr) { skipparens(Inbrack, Outbrack, &t); } else { *lexbuf.ptr = sav; } } if (*t == '+') t++; if (t == lexbuf.ptr) { e = hgetc(); if (e == '(') { *lexbuf.ptr = '\0'; return ENVARRAY; } hungetc(e); lexstop = 0; peek = ENVSTRING; intpos = 2; } else c = Equals; } else c = Equals; } break; case LX2_BKSLASH: c = hgetc(); if (c == '\n') { c = hgetc(); if (!lexstop) continue; } else { add(Bnull); if (c == STOUC(Meta)) { c = hgetc(); #ifdef DEBUG if (lexstop) { fputs("BUG: input terminated by Meta\n", stderr); fflush(stderr); goto brk; } #endif add(Meta); } } if (lexstop) goto brk; break; case LX2_QUOTE: { int strquote = (lexbuf.len && lexbuf.ptr[-1] == String); add(Snull); cmdpush(CS_QUOTE); for (;;) { STOPHIST while ((c = hgetc()) != '\'' && !lexstop) { if (strquote && c == '\\') { c = hgetc(); if (lexstop) break; /* * Mostly we don't need to do anything special * with escape backslashes or closing quotes * inside $'...'; however in completion we * need to be able to strip multiple backslashes * neatly. */ if (c == '\\' || c == '\'') add(Bnull); else add('\\'); } else if (!sub && isset(CSHJUNKIEQUOTES) && c == '\n') { if (lexbuf.ptr[-1] == '\\') lexbuf.ptr--, lexbuf.len--; else break; } add(c); } ALLOWHIST if (c != '\'') { unmatched = '\''; peek = LEXERR; cmdpop(); goto brk; } e = hgetc(); if (e != '\'' || unset(RCQUOTES) || strquote) break; add(c); } cmdpop(); hungetc(e); lexstop = 0; c = Snull; break; } case LX2_DQUOTE: add(Dnull); cmdpush(CS_DQUOTE); c = dquote_parse('"', sub); cmdpop(); if (c) { unmatched = '"'; peek = LEXERR; goto brk; } c = Dnull; break; case LX2_BQUOTE: add(Tick); cmdpush(CS_BQUOTE); SETPARBEGIN inquote = 0; while ((c = hgetc()) != '`' && !lexstop) { if (c == '\\') { c = hgetc(); if (c != '\n') { add(c == '`' || c == '\\' || c == '$' ? Bnull : '\\'); add(c); } else if (!sub && isset(CSHJUNKIEQUOTES)) add(c); } else { if (!sub && isset(CSHJUNKIEQUOTES) && c == '\n') { break; } add(c); if (c == '\'') { if ((inquote = !inquote)) STOPHIST else ALLOWHIST } } } if (inquote) ALLOWHIST cmdpop(); if (c != '`') { unmatched = '`'; peek = LEXERR; goto brk; } c = Tick; SETPAREND break; case LX2_DASH: /* * - shouldn't be treated as a special character unless * we're in a pattern. Howeve,simply counting "[" doesn't * work as []a-z] is a valid expression and we don't know * down here what this "[" is for as $foo[stuff] is valid * in zsh. So just detect an opening [, which is enough * to turn this into a pattern; the Dash will be harmlessly * untokenised if not wanted. */ if (seen_brct) c = Dash; else c = '-'; break; case LX2_BANG: /* * Same logic as Dash, for ! to perform negation in range. */ if (seen_brct) c = Bang; else c = '!'; } add(c); c = hgetc(); if (intpos) intpos--; if (lexstop) break; } brk: if (errflag) { if (in_brace_param) { while(bct-- >= in_brace_param) cmdpop(); } return LEXERR; } hungetc(c); if (unmatched) zerr("unmatched %c", unmatched); if (in_brace_param) { while(bct-- >= in_brace_param) cmdpop(); zerr("closing brace expected"); } else if (unset(IGNOREBRACES) && !sub && lexbuf.len > 1 && peek == STRING && lexbuf.ptr[-1] == '}' && lexbuf.ptr[-2] != Bnull) { /* hack to get {foo} command syntax work */ lexbuf.ptr--; lexbuf.len--; lexstop = 0; hungetc('}'); } *lexbuf.ptr = '\0'; DPUTS(cmdsp != ocmdsp, "BUG: gettok: cmdstack changed."); return peek; }
static enum lextok gettok(void) { int c, d; int peekfd = -1; enum lextok peek; beginning: tokstr = NULL; while (iblank(c = hgetc()) && !lexstop); toklineno = lineno; if (lexstop) return (errflag) ? LEXERR : ENDINPUT; isfirstln = 0; if ((lexflags & LEXFLAGS_ZLE)) wordbeg = inbufct - (qbang && c == bangchar); hwbegin(-1-(qbang && c == bangchar)); /* word includes the last character read and possibly \ before ! */ if (dbparens) { lexbuf.len = 0; lexbuf.ptr = tokstr = (char *) hcalloc(lexbuf.siz = LEX_HEAP_SIZE); hungetc(c); cmdpush(CS_MATH); c = dquote_parse(infor ? ';' : ')', 0); cmdpop(); *lexbuf.ptr = '\0'; if (!c && infor) { infor--; return DINPAR; } if (c || (c = hgetc()) != ')') { hungetc(c); return LEXERR; } dbparens = 0; return DOUTPAR; } else if (idigit(c)) { /* handle 1< foo */ d = hgetc(); if(d == '&') { d = hgetc(); if(d == '>') { peekfd = c - '0'; hungetc('>'); c = '&'; } else { hungetc(d); lexstop = 0; hungetc('&'); } } else if (d == '>' || d == '<') { peekfd = c - '0'; c = d; } else { hungetc(d); lexstop = 0; } } /* chars in initial position in word */ /* * Handle comments. There are some special cases when this * is not normal command input: lexflags implies we are examining * a line lexically without it being used for normal command input. */ if (c == hashchar && !nocomments && (isset(INTERACTIVECOMMENTS) || ((!lexflags || (lexflags & LEXFLAGS_COMMENTS)) && !expanding && (!interact || unset(SHINSTDIN) || strin)))) { /* History is handled here to prevent extra * * newlines being inserted into the history. */ if (lexflags & LEXFLAGS_COMMENTS_KEEP) { lexbuf.len = 0; lexbuf.ptr = tokstr = (char *)hcalloc(lexbuf.siz = LEX_HEAP_SIZE); add(c); } hwend(); while ((c = ingetc()) != '\n' && !lexstop) { hwaddc(c); addtoline(c); if (lexflags & LEXFLAGS_COMMENTS_KEEP) add(c); } if (errflag) peek = LEXERR; else { if (lexflags & LEXFLAGS_COMMENTS_KEEP) { *lexbuf.ptr = '\0'; if (!lexstop) hungetc(c); peek = STRING; } else { hwend(); hwbegin(0); hwaddc('\n'); addtoline('\n'); /* * If splitting a line and removing comments, * we don't want a newline token since it's * treated specially. */ if ((lexflags & LEXFLAGS_COMMENTS_STRIP) && lexstop) peek = ENDINPUT; else peek = NEWLIN; } } return peek; } switch (lexact1[STOUC(c)]) { case LX1_BKSLASH: d = hgetc(); if (d == '\n') goto beginning; hungetc(d); lexstop = 0; break; case LX1_NEWLIN: return NEWLIN; case LX1_SEMI: d = hgetc(); if(d == ';') return DSEMI; else if(d == '&') return SEMIAMP; else if (d == '|') return SEMIBAR; hungetc(d); lexstop = 0; return SEMI; case LX1_AMPER: d = hgetc(); if (d == '&') return DAMPER; else if (d == '!' || d == '|') return AMPERBANG; else if (d == '>') { tokfd = peekfd; d = hgetc(); if (d == '!' || d == '|') return OUTANGAMPBANG; else if (d == '>') { d = hgetc(); if (d == '!' || d == '|') return DOUTANGAMPBANG; hungetc(d); lexstop = 0; return DOUTANGAMP; } hungetc(d); lexstop = 0; return AMPOUTANG; } hungetc(d); lexstop = 0; return AMPER; case LX1_BAR: d = hgetc(); if (d == '|') return DBAR; else if (d == '&') return BARAMP; hungetc(d); lexstop = 0; return BAR; case LX1_INPAR: d = hgetc(); if (d == '(') { if (infor) { dbparens = 1; return DINPAR; } if (incmdpos || (isset(SHGLOB) && !isset(KSHGLOB))) { lexbuf.len = 0; lexbuf.ptr = tokstr = (char *) hcalloc(lexbuf.siz = LEX_HEAP_SIZE); switch (cmd_or_math(CS_MATH)) { case CMD_OR_MATH_MATH: return DINPAR; case CMD_OR_MATH_CMD: /* * Not math, so we don't return the contents * as a string in this case. */ tokstr = NULL; return INPAR; case CMD_OR_MATH_ERR: /* * LEXFLAGS_ACTIVE means we came from bufferwords(), * so we treat as an incomplete math expression */ if (lexflags & LEXFLAGS_ACTIVE) tokstr = dyncat("((", tokstr ? tokstr : ""); /* fall through */ default: return LEXERR; } } } else if (d == ')') return INOUTPAR; hungetc(d); lexstop = 0; if (!(isset(SHGLOB) || incond == 1 || incmdpos)) break; return INPAR; case LX1_OUTPAR: return OUTPAR; case LX1_INANG: d = hgetc(); if (d == '(') { hungetc(d); lexstop = 0; unpeekfd: if(peekfd != -1) { hungetc(c); c = '0' + peekfd; } break; } if (d == '>') { peek = INOUTANG; } else if (d == '<') { int e = hgetc(); if (e == '(') { hungetc(e); hungetc(d); peek = INANG; } else if (e == '<') peek = TRINANG; else if (e == '-') peek = DINANGDASH; else { hungetc(e); lexstop = 0; peek = DINANG; } } else if (d == '&') { peek = INANGAMP; } else { hungetc(d); if(isnumglob()) goto unpeekfd; peek = INANG; } tokfd = peekfd; return peek; case LX1_OUTANG: d = hgetc(); if (d == '(') { hungetc(d); goto unpeekfd; } else if (d == '&') { d = hgetc(); if (d == '!' || d == '|') peek = OUTANGAMPBANG; else { hungetc(d); lexstop = 0; peek = OUTANGAMP; } } else if (d == '!' || d == '|') peek = OUTANGBANG; else if (d == '>') { d = hgetc(); if (d == '&') { d = hgetc(); if (d == '!' || d == '|') peek = DOUTANGAMPBANG; else { hungetc(d); lexstop = 0; peek = DOUTANGAMP; } } else if (d == '!' || d == '|') peek = DOUTANGBANG; else if (d == '(') { hungetc(d); hungetc('>'); peek = OUTANG; } else { hungetc(d); lexstop = 0; peek = DOUTANG; if (isset(HISTALLOWCLOBBER)) hwaddc('|'); } } else { hungetc(d); lexstop = 0; peek = OUTANG; if (!incond && isset(HISTALLOWCLOBBER)) hwaddc('|'); } tokfd = peekfd; return peek; } /* we've started a string, now get the * * rest of it, performing tokenization */ return gettokstr(c, 0); }
int filesubstr(char **namptr, int assign) { #define isend(c) ( !(c) || (c)=='/' || (c)==Inpar || (assign && (c)==':') ) #define isend2(c) ( !(c) || (c)==Inpar || (assign && (c)==':') ) char *str = *namptr; if (*str == Tilde && str[1] != '=' && str[1] != Equals) { char *ptr; int val; val = zstrtol(str + 1, &ptr, 10); if (isend(str[1])) { /* ~ */ *namptr = dyncat(home, str + 1); return 1; } else if (str[1] == '+' && isend(str[2])) { /* ~+ */ *namptr = dyncat(pwd, str + 2); return 1; } else if (str[1] == '-' && isend(str[2])) { /* ~- */ char *tmp; *namptr = dyncat((tmp = oldpwd) ? tmp : pwd, str + 2); return 1; } else if (!inblank(str[1]) && isend(*ptr) && (!idigit(str[1]) || (ptr - str < 4))) { char *ds; if (val < 0) val = -val; ds = dstackent(str[1], val); if (!ds) return 0; *namptr = dyncat(ds, ptr); return 1; } else if (iuser(str[1])) { /* ~foo */ char *ptr, *hom, save; for (ptr = ++str; *ptr && iuser(*ptr); ptr++); save = *ptr; if (!isend(save)) return 0; *ptr = 0; if (!(hom = getnameddir(str))) { if (isset(NOMATCH)) zerr("no such user or named directory: %s", str, 0); *ptr = save; return 0; } *ptr = save; *namptr = dyncat(hom, ptr); return 1; } } else if (*str == Equals && isset(EQUALS) && str[1]) { /* =foo */ char sav, *pp, *cnam; for (pp = str + 1; !isend2(*pp); pp++); sav = *pp; *pp = 0; if (!(cnam = findcmd(str + 1))) { Alias a = (Alias) aliastab->getnode(aliastab, str + 1); if (a) cnam = ztrdup(a->text); else { if (isset(NOMATCH)) zerr("%s not found", str + 1, 0); return 0; } } *namptr = dupstring(cnam); zsfree(cnam); if (sav) { *pp = sav; *namptr = dyncat(*namptr, pp); } return 1; } return 0; #undef isend #undef isend2 }