📄 wordexp.c
字号:
*result *= arg; } else if (**expr == '/') { ++(*expr); if (eval_expr_val(expr, &arg) != 0) return WRDE_SYNTAX; *result /= arg; } else break; } return 0;}static int eval_expr(char *expr, long int *result){ long int arg; /* Read a Multdiv */ if (eval_expr_multdiv(&expr, result) != 0) return WRDE_SYNTAX; while (*expr) { /* Skip white space */ for (; expr && *expr && isspace(*expr); ++expr); if (*expr == '+') { ++expr; if (eval_expr_multdiv(&expr, &arg) != 0) return WRDE_SYNTAX; *result += arg; } else if (*expr == '-') { ++expr; if (eval_expr_multdiv(&expr, &arg) != 0) return WRDE_SYNTAX; *result -= arg; } else break; } return 0;}static intparse_arith(char **word, size_t * word_length, size_t * max_length, const char *words, size_t * offset, int flags, int bracket){ /* We are poised just after "$((" or "$[" */ int error; int paren_depth = 1; size_t expr_length; size_t expr_maxlen; char *expr; expr = w_newword(&expr_length, &expr_maxlen); for (; words[*offset]; ++(*offset)) { switch (words[*offset]) { case '$': error = parse_dollars(&expr, &expr_length, &expr_maxlen, words, offset, flags, NULL, NULL, NULL, 1); /* The ``1'' here is to tell parse_dollars not to * split the fields. */ if (error) { free(expr); return error; } break; case '`': (*offset)++; error = parse_backtick(&expr, &expr_length, &expr_maxlen, words, offset, flags, NULL, NULL, NULL); /* The first NULL here is to tell parse_backtick not to * split the fields. */ if (error) { free(expr); return error; } break; case '\\': error = parse_qtd_backslash(&expr, &expr_length, &expr_maxlen, words, offset); if (error) { free(expr); return error; } /* I think that a backslash within an * arithmetic expansion is bound to * cause an error sooner or later anyway though. */ break; case ')': if (--paren_depth == 0) { char result[21]; /* 21 = ceil(log10(2^64)) + 1 */ long int numresult = 0; long long int convertme; if (bracket || words[1 + *offset] != ')') { free(expr); return WRDE_SYNTAX; } ++(*offset); /* Go - evaluate. */ if (*expr && eval_expr(expr, &numresult) != 0) { free(expr); return WRDE_SYNTAX; } if (numresult < 0) { convertme = -numresult; *word = w_addchar(*word, word_length, max_length, '-'); if (!*word) { free(expr); return WRDE_NOSPACE; } } else convertme = numresult; result[20] = '\0'; *word = w_addstr(*word, word_length, max_length, _itoa(convertme, &result[20])); free(expr); return *word ? 0 : WRDE_NOSPACE; } expr = w_addchar(expr, &expr_length, &expr_maxlen, words[*offset]); if (expr == NULL) return WRDE_NOSPACE; break; case ']': if (bracket && paren_depth == 1) { char result[21]; /* 21 = ceil(log10(2^64)) + 1 */ long int numresult = 0; /* Go - evaluate. */ if (*expr && eval_expr(expr, &numresult) != 0) { free(expr); return WRDE_SYNTAX; } result[20] = '\0'; *word = w_addstr(*word, word_length, max_length, _itoa(numresult, &result[20])); free(expr); return *word ? 0 : WRDE_NOSPACE; } free(expr); return WRDE_SYNTAX; case '\n': case ';': case '{': case '}': free(expr); return WRDE_BADCHAR; case '(': ++paren_depth; default: expr = w_addchar(expr, &expr_length, &expr_maxlen, words[*offset]); if (expr == NULL) return WRDE_NOSPACE; } } /* Premature end */ free(expr); return WRDE_SYNTAX;}/* Function called by child process in exec_comm() */static voidexec_comm_child(char *comm, int *fildes, int showerr, int noexec){ const char *args[4] = { _PATH_BSHELL, "-c", comm, NULL }; /* Execute the command, or just check syntax? */ if (noexec) args[1] = "-nc"; /* Redirect output. */ dup2(fildes[1], 1); close(fildes[1]); /* Redirect stderr to /dev/null if we have to. */ if (showerr == 0) { int fd; close(2); fd = open(_PATH_DEVNULL, O_WRONLY); if (fd >= 0 && fd != 2) { dup2(fd, 2); close(fd); } } /* Make sure the subshell doesn't field-split on our behalf. */ unsetenv("IFS"); close(fildes[0]); execve(_PATH_BSHELL, (char *const *) args, __environ); /* Bad. What now? */ abort();}/* Function to execute a command and retrieve the results *//* pwordexp contains NULL if field-splitting is forbidden */static intexec_comm(char *comm, char **word, size_t * word_length, size_t * max_length, int flags, wordexp_t * pwordexp, const char *ifs, const char *ifs_white){ int fildes[2]; int bufsize = 128; int buflen; int i; int status = 0; size_t maxnewlines = 0; char *buffer; pid_t pid; /* Don't fork() unless necessary */ if (!comm || !*comm) return 0; if (pipe(fildes)) /* Bad */ return WRDE_NOSPACE; if ((pid = fork()) < 0) { /* Bad */ close(fildes[0]); close(fildes[1]); return WRDE_NOSPACE; } if (pid == 0) exec_comm_child(comm, fildes, (flags & WRDE_SHOWERR), 0); /* Parent */ close(fildes[1]); buffer = alloca(bufsize); if (!pwordexp) /* Quoted - no field splitting */ { while (1) { if ((buflen = read(fildes[0], buffer, bufsize)) < 1) { if (waitpid(pid, &status, WNOHANG) == 0) continue; if ((buflen = read(fildes[0], buffer, bufsize)) < 1) break; } maxnewlines += buflen; *word = w_addmem(*word, word_length, max_length, buffer, buflen); if (*word == NULL) goto no_space; } } else /* Not quoted - split fields */ { int copying = 0; /* 'copying' is: * 0 when searching for first character in a field not IFS white space * 1 when copying the text of a field * 2 when searching for possible non-whitespace IFS * 3 when searching for non-newline after copying field */ while (1) { if ((buflen = read(fildes[0], buffer, bufsize)) < 1) { if (waitpid(pid, &status, WNOHANG) == 0) continue; if ((buflen = read(fildes[0], buffer, bufsize)) < 1) break; } for (i = 0; i < buflen; ++i) { if (strchr(ifs, buffer[i]) != NULL) { /* Current character is IFS */ if (strchr(ifs_white, buffer[i]) == NULL) { /* Current character is IFS but not whitespace */ if (copying == 2) { /* current character * | * V * eg: text<space><comma><space>moretext * * So, strip whitespace IFS (like at the start) */ copying = 0; continue; } copying = 0; /* fall through and delimit field.. */ } else { if (buffer[i] == '\n') { /* Current character is (IFS) newline */ /* If copying a field, this is the end of it, but maybe all that's left is trailing newlines. So start searching for a non-newline. */ if (copying == 1) copying = 3; continue; } else { /* Current character is IFS white space, but not a newline */ /* If not either copying a field or searching for non-newline after a field, ignore it */ if (copying != 1 && copying != 3) continue; /* End of field (search for non-ws IFS afterwards) */ copying = 2; } } /* First IFS white space (non-newline), or IFS non-whitespace. * Delimit the field. Nulls are converted by w_addword. */ if (w_addword(pwordexp, *word) == WRDE_NOSPACE) goto no_space; *word = w_newword(word_length, max_length); maxnewlines = 0; /* fall back round the loop.. */ } else { /* Not IFS character */ if (copying == 3) { /* Nothing but (IFS) newlines since the last field, so delimit it here before starting new word */ if (w_addword(pwordexp, *word) == WRDE_NOSPACE) goto no_space; *word = w_newword(word_length, max_length); } copying = 1; if (buffer[i] == '\n') /* happens if newline not in IFS */ maxnewlines++; else maxnewlines = 0; *word = w_addchar(*word, word_length, max_length, buffer[i]); if (*word == NULL) goto no_space; } } } } /* Chop off trailing newlines (required by POSIX.2) */ /* Ensure we don't go back further than the beginning of the substitution (i.e. remove maxnewlines bytes at most) */ while (maxnewlines-- != 0 && *word_length > 0 && (*word)[*word_length - 1] == '\n') { (*word)[--*word_length] = '\0'; /* If the last word was entirely newlines, turn it into a new word * which can be ignored if there's nothing following it. */ if (*word_length == 0) { free(*word); *word = w_newword(word_length, max_length); break; } } close(fildes[0]); /* Check for syntax error (re-execute but with "-n" flag) */ if (buflen < 1 && status != 0) { if ((pid = fork()) < 0) { /* Bad */ return WRDE_NOSPACE; } if (pid == 0) { fildes[0] = fildes[1] = -1; exec_comm_child(comm, fildes, 0, 1); } if (waitpid(pid, &status, 0) == pid && status != 0) return WRDE_SYNTAX; } return 0; no_space: kill(pid, SIGKILL); waitpid(pid, NULL, 0); close(fildes[0]); return WRDE_NOSPACE;}static intparse_comm(char **word, size_t * word_length, size_t * max_length, const char *words, size_t * offset, int flags, wordexp_t * pwordexp, const char *ifs, const char *ifs_white){ /* We are poised just after "$(" */ int paren_depth = 1; int error = 0; int quoted = 0; /* 1 for singly-quoted, 2 for doubly-quoted */ size_t comm_length; size_t comm_maxlen; char *comm = w_newword(&comm_length, &comm_maxlen); for (; words[*offset]; ++(*offset)) { switch (words[*offset]) { case '\'': if (quoted == 0) quoted = 1; else if (quoted == 1) quoted = 0; break; case '"': if (quoted == 0) quoted = 2; else if (quoted == 2) quoted = 0; break; case ')': if (!quoted && --paren_depth == 0) { /* Go -- give script to the shell */ if (comm) { error = exec_comm(comm, word, word_length, max_length, flags, pwordexp, ifs, ifs_white); free(comm); } return error; } /* This is just part of the script */ break; case '(': if (!quoted) ++paren_depth; } comm = w_addchar(comm, &comm_length, &comm_maxlen, words[*offset]); if (comm == NULL) return WRDE_NOSPACE; } /* Premature end */ if (comm) free(comm); return WRDE_SYNTAX;}static intparse_backtick(char **word, size_t * word_length, size_t * max_length, const char *words, size_t * offset, int flags, wordexp_t * pwordexp, const char *ifs, const char *ifs_white){ /* We are poised just after "`" */ int error; int squoting = 0; size_t comm_length; size_t comm_maxlen; char *comm = w_newword(&comm_length, &comm_maxlen); for (; words[*offset]; ++(*offset)) { switch (words[*offset]) { case '`': /* Go -- give the script to the shell */ error = exec_comm(comm, word, word_length, max_length, flags, pwordexp, ifs, ifs_white); free(comm); return error; case '\\': if (squoting) { error = parse_qtd_backslash(&comm, &comm_length, &comm_maxlen, words, offset); if (error) { free(comm); return error; } break; } ++(*offset); error = parse_backslash(&comm, &comm_length, &comm_maxlen, words, offset); if (error) { free(comm); return error; } break; case '\'': squoting = 1 - squoting; default: comm = w_addchar(comm, &comm_length, &comm_maxlen, words[*offset]); if (comm == NULL) return WRDE_NOSPACE; } } /* Premature end */ free(comm); return WRDE_SYNTAX;}static intparse_param(char **word, size_t * word_length, size_t * max_length, const char *words, size_t * offset, int flags, wordexp_t * pwordexp, const char *ifs, const char *ifs_white, int quoted){ /* We are poised just after "$" */ enum action { ACT_NONE, ACT_RP_SHORT_LEFT = '#', ACT_RP_LONG_LEFT = 'L', ACT_RP_SHORT_RIGHT = '%', ACT_RP_LONG_RIGHT = 'R', ACT_NULL_ERROR = '?', ACT_NULL_SUBST = '-', ACT_NONNULL_SUBST = '+', ACT_NULL_ASSIGN = '='
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -