extern int esopt(const char *options) { int c; const char *arg, *opt; assert(usage != NULL); assert(termarg == NULL); if (nextchar == 0) { if (args == NULL) return EOF; assert(args->term != NULL); arg = getstr(args->term); if (*arg != '-') return EOF; if (arg[1] == '-' && arg[2] == '\0') { args = args->next; return EOF; } nextchar = 1; } else { assert(args != NULL && args->term != NULL); arg = getstr(args->term); } c = arg[nextchar++]; opt = strchr(options, c); if (opt == NULL) { const char *msg = usage; usage = NULL; args = NULL; nextchar = 0; fail(invoker, "illegal option: -%c -- usage: %s", c, msg); } if (arg[nextchar] == '\0') { nextchar = 0; args = args->next; } if (opt[1] == ':') { if (args == NULL) { const char *msg = usage; fail(invoker, "option -%c expects an argument -- usage: %s", c, msg); } termarg = (nextchar == 0) ? args->term : mkterm(gcdup(arg + nextchar), NULL); nextchar = 0; args = args->next; } return c; }
static List *extractsinglematch(const char *subject, const char *pattern, const char *quoting, List *result) { int i; const char *s; if (!haswild(pattern, quoting) /* no wildcards, so no matches */ || !match(subject, pattern, quoting)) return NULL; for (s = subject, i = 0; pattern[i] != '\0'; s++) { if (ISQUOTED(quoting, i)) i++; else { int c = pattern[i++]; switch (c) { case '*': { const char *begin; if (pattern[i] == '\0') return mklist(mkstr(gcdup(s)), result); for (begin = s;; s++) { const char *q = TAILQUOTE(quoting, i); assert(*s != '\0'); if (match(s, pattern + i, q)) { result = mklist(mkstr(gcndup(begin, s - begin)), result); return haswild(pattern + i, q) ? extractsinglematch(s, pattern + i, q, result) : result; } } } case '[': { int j = rangematch(pattern + i, TAILQUOTE(quoting, i), *s); assert(j != RANGE_FAIL); if (j == RANGE_ERROR) { assert(*s == '['); break; } i += j; } /* FALLTHROUGH */ case '?': result = mklist(mkstr(str("%c", *s)), result); break; default: break; } } } return result; }
extern int yylex(void) { static Boolean dollar = FALSE; int c; size_t i; /* The purpose of all these local assignments is to */ const char *meta; /* allow optimizing compilers like gcc to load these */ char *buf = tokenbuf; /* values into registers. On a sparc this is a */ YYSTYPE *y = &yylval; /* win, in code size *and* execution time */ if (goterror) { goterror = FALSE; return NL; } /* rc variable-names may contain only alnum, '*' and '_', so use dnw if we are scanning one. */ meta = (dollar ? dnw : nw); dollar = FALSE; if (newline) { --input->lineno; /* slight space optimization; print_prompt2() always increments lineno */ print_prompt2(); newline = FALSE; } top: while ((c = GETC()) == ' ' || c == '\t') w = NW; if (c == EOF) return ENDFILE; if (!meta[(unsigned char) c]) { /* it's a word or keyword. */ InsertFreeCaret(); w = RW; i = 0; do { buf[i++] = c; if (i >= bufsize) buf = tokenbuf = erealloc(buf, bufsize *= 2); } while ((c = GETC()) != EOF && !meta[(unsigned char) c]); UNGETC(c); buf[i] = '\0'; w = KW; if (buf[1] == '\0') { int k = *buf; if (k == '@' || k == '~') return k; } else if (*buf == 'f') { if (streq(buf + 1, "n")) return FN; if (streq(buf + 1, "or")) return FOR; } else if (*buf == 'l') { if (streq(buf + 1, "ocal")) return LOCAL; if (streq(buf + 1, "et")) return LET; } else if (streq(buf, "~~")) return EXTRACT; else if (streq(buf, "%closure")) return CLOSURE; w = RW; y->str = gcdup(buf); return WORD; } if (c == '`' || c == '!' || c == '$' || c == '\'') { InsertFreeCaret(); if (c == '!') w = KW; } switch (c) { case '!': return '!'; case '`': c = GETC(); if (c == '`') return BACKBACK; UNGETC(c); return '`'; case '$': dollar = TRUE; switch (c = GETC()) { case '#': return COUNT; case '^': return FLAT; case '&': return PRIM; default: UNGETC(c); return '$'; } case '\'': w = RW; i = 0; while ((c = GETC()) != '\'' || (c = GETC()) == '\'') { buf[i++] = c; if (c == '\n') print_prompt2(); if (c == EOF) { w = NW; scanerror("eof in quoted string"); return ERROR; } if (i >= bufsize) buf = tokenbuf = erealloc(buf, bufsize *= 2); } UNGETC(c); buf[i] = '\0'; y->str = gcdup(buf); return QWORD; case '\\': if ((c = GETC()) == '\n') { print_prompt2(); UNGETC(' '); goto top; /* Pretend it was just another space. */ } if (c == EOF) { UNGETC(EOF); goto badescape; } UNGETC(c); c = '\\'; InsertFreeCaret(); w = RW; c = GETC(); switch (c) { case 'a': *buf = '\a'; break; case 'b': *buf = '\b'; break; case 'e': *buf = '\033'; break; case 'f': *buf = '\f'; break; case 'n': *buf = '\n'; break; case 'r': *buf = '\r'; break; case 't': *buf = '\t'; break; case 'x': case 'X': { int n = 0; for (;;) { c = GETC(); if (!isxdigit(c)) break; n = (n << 4) | (c - (isdigit(c) ? '0' : ((islower(c) ? 'a' : 'A') - 0xA))); } if (n == 0) goto badescape; UNGETC(c); *buf = n; break; } case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': { int n = 0; do { n = (n << 3) | (c - '0'); c = GETC(); } while (isodigit(c)); if (n == 0) goto badescape; UNGETC(c); *buf = n; break; } default: if (isalnum(c)) { badescape: scanerror("bad backslash escape"); return ERROR; } *buf = c; break; } buf[1] = 0; y->str = gcdup(buf); return QWORD; case '#': while ((c = GETC()) != '\n') /* skip comment until newline */ if (c == EOF) return ENDFILE; /* FALLTHROUGH */ case '\n': input->lineno++; newline = TRUE; w = NW; return NL; case '(': if (w == RW) /* not keywords, so let & friends work */ c = SUB; /* FALLTHROUGH */ case ';': case '^': case ')': case '=': case '{': case '}': w = NW; return c; case '&': w = NW; c = GETC(); if (c == '&') return ANDAND; UNGETC(c); return '&'; case '|': { int p[2]; w = NW; c = GETC(); if (c == '|') return OROR; if (!getfds(p, c, 1, 0)) return ERROR; if (p[1] == CLOSED) { scanerror("expected digit after '='"); /* can't close a pipe */ return ERROR; } y->tree = mk(nPipe, p[0], p[1]); return PIPE; } { char *cmd; int fd[2]; case '<': fd[0] = 0; if ((c = GETC()) == '>') if ((c = GETC()) == '>') { c = GETC(); cmd = "%open-append"; } else cmd = "%open-write"; else if (c == '<') if ((c = GETC()) == '<') { c = GETC(); cmd = "%here"; } else cmd = "%heredoc"; else if (c == '=') return CALL; else cmd = "%open"; goto redirection; case '>': fd[0] = 1; if ((c = GETC()) == '>') if ((c = GETC()) == '<') { c = GETC(); cmd = "%open-append"; } else cmd = "%append"; else if (c == '<') { c = GETC(); cmd = "%open-create"; } else cmd = "%create"; goto redirection; redirection: w = NW; if (!getfds(fd, c, fd[0], DEFAULT)) return ERROR; if (fd[1] != DEFAULT) { y->tree = (fd[1] == CLOSED) ? mkclose(fd[0]) : mkdup(fd[0], fd[1]); return DUP; } y->tree = mkredircmd(cmd, fd[0]); return REDIR; } default: assert(c != '\0'); w = NW; return c; /* don't know what it is, let yacc barf on it */ } }