📄 subst.c
字号:
static inline char *string_extract_single_quoted (string, sindex) char *string; int *sindex;{ register int i; size_t slen; char *t; DECLARE_MBSTATE; /* Don't need slen for ADVANCE_CHAR unless multibyte chars possible. */ slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0; i = *sindex; while (string[i] && string[i] != '\'') ADVANCE_CHAR (string, slen, i); t = substring (string, *sindex, i); if (string[i]) i++; *sindex = i; return (t);}static inline intskip_single_quoted (string, slen, sind) const char *string; size_t slen; int sind;{ register int c; DECLARE_MBSTATE; c = sind; while (string[c] && string[c] != '\'') ADVANCE_CHAR (string, slen, c); if (string[c]) c++; return c;}/* Just like string_extract, but doesn't hack backslashes or any of that other stuff. Obeys CTLESC quoting. Used to do splitting on $IFS. */static char *string_extract_verbatim (string, slen, sindex, charlist, flags) char *string; size_t slen; int *sindex; char *charlist; int flags;{ register int i;#if defined (HANDLE_MULTIBYTE) size_t clen; wchar_t *wcharlist;#endif int c; char *temp; DECLARE_MBSTATE; if (charlist[0] == '\'' && charlist[1] == '\0') { temp = string_extract_single_quoted (string, sindex); --*sindex; /* leave *sindex at separator character */ return temp; } i = *sindex;#if 0 /* See how the MBLEN and ADVANCE_CHAR macros work to understand why we need this only if MB_CUR_MAX > 1. */ slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 1;#endif#if defined (HANDLE_MULTIBYTE) clen = strlen (charlist); wcharlist = 0;#endif while (c = string[i]) {#if defined (HANDLE_MULTIBYTE) size_t mblength;#endif if ((flags & SX_NOCTLESC) == 0 && c == CTLESC) { i += 2; continue; } /* Even if flags contains SX_NOCTLESC, we let CTLESC quoting CTLNUL through, to protect the CTLNULs from later calls to remove_quoted_nulls. */ else if ((flags & SX_NOESCCTLNUL) == 0 && c == CTLESC && string[i+1] == CTLNUL) { i += 2; continue; }#if defined (HANDLE_MULTIBYTE) mblength = MBLEN (string + i, slen - i); if (mblength > 1) { wchar_t wc; mblength = mbtowc (&wc, string + i, slen - i); if (MB_INVALIDCH (mblength)) { if (MEMBER (c, charlist)) break; } else { if (wcharlist == 0) { size_t len; len = mbstowcs (wcharlist, charlist, 0); if (len == -1) len = 0; wcharlist = (wchar_t *)xmalloc (sizeof (wchar_t) * (len + 1)); mbstowcs (wcharlist, charlist, len + 1); } if (wcschr (wcharlist, wc)) break; } } else #endif if (MEMBER (c, charlist)) break; ADVANCE_CHAR (string, slen, i); }#if defined (HANDLE_MULTIBYTE) FREE (wcharlist);#endif temp = substring (string, *sindex, i); *sindex = i; return (temp);}/* Extract the $( construct in STRING, and return a new string. Start extracting at (SINDEX) as if we had just seen "$(". Make (SINDEX) get the position of the matching ")". ) XFLAGS is additional flags to pass to other extraction functions. */char *extract_command_subst (string, sindex, xflags) char *string; int *sindex; int xflags;{ if (string[*sindex] == LPAREN) return (extract_delimited_string (string, sindex, "$(", "(", ")", xflags|SX_COMMAND)); /*)*/ else { xflags |= (no_longjmp_on_fatal_error ? SX_NOLONGJMP : 0); return (xparse_dolparen (string, string+*sindex, sindex, xflags)); }}/* Extract the $[ construct in STRING, and return a new string. (]) Start extracting at (SINDEX) as if we had just seen "$[". Make (SINDEX) get the position of the matching "]". */char *extract_arithmetic_subst (string, sindex) char *string; int *sindex;{ return (extract_delimited_string (string, sindex, "$[", "[", "]", 0)); /*]*/}#if defined (PROCESS_SUBSTITUTION)/* Extract the <( or >( construct in STRING, and return a new string. Start extracting at (SINDEX) as if we had just seen "<(". Make (SINDEX) get the position of the matching ")". */ /*))*/char *extract_process_subst (string, starter, sindex) char *string; char *starter; int *sindex;{ return (extract_delimited_string (string, sindex, starter, "(", ")", 0));}#endif /* PROCESS_SUBSTITUTION */#if defined (ARRAY_VARS)/* This can be fooled by unquoted right parens in the passed string. If each caller verifies that the last character in STRING is a right paren, we don't even need to call extract_delimited_string. */char *extract_array_assignment_list (string, sindex) char *string; int *sindex;{ int slen; char *ret; slen = strlen (string); /* ( */ if (string[slen - 1] == ')') { ret = substring (string, *sindex, slen - 1); *sindex = slen - 1; return ret; } return 0; }#endif/* Extract and create a new string from the contents of STRING, a character string delimited with OPENER and CLOSER. SINDEX is the address of an int describing the current offset in STRING; it should point to just after the first OPENER found. On exit, SINDEX gets the position of the last character of the matching CLOSER. If OPENER is more than a single character, ALT_OPENER, if non-null, contains a character string that can also match CLOSER and thus needs to be skipped. */static char *extract_delimited_string (string, sindex, opener, alt_opener, closer, flags) char *string; int *sindex; char *opener, *alt_opener, *closer; int flags;{ int i, c, si; size_t slen; char *t, *result; int pass_character, nesting_level, in_comment; int len_closer, len_opener, len_alt_opener; DECLARE_MBSTATE; slen = strlen (string + *sindex) + *sindex; len_opener = STRLEN (opener); len_alt_opener = STRLEN (alt_opener); len_closer = STRLEN (closer); pass_character = in_comment = 0; nesting_level = 1; i = *sindex; while (nesting_level) { c = string[i]; if (c == 0) break; if (in_comment) { if (c == '\n') in_comment = 0; ADVANCE_CHAR (string, slen, i); continue; } if (pass_character) /* previous char was backslash */ { pass_character = 0; ADVANCE_CHAR (string, slen, i); continue; } /* Not exactly right yet; should handle shell metacharacters and multibyte characters, too. See COMMENT_BEGIN define in parse.y */ if ((flags & SX_COMMAND) && c == '#' && (i == 0 || string[i - 1] == '\n' || shellblank (string[i - 1]))) { in_comment = 1; ADVANCE_CHAR (string, slen, i); continue; } if (c == CTLESC || c == '\\') { pass_character++; i++; continue; } /* Process a nested command substitution, but only if we're parsing an arithmetic substitution. */ if ((flags & SX_COMMAND) && string[i] == '$' && string[i+1] == LPAREN) { si = i + 2; t = extract_command_subst (string, &si, flags|SX_NOALLOC); i = si + 1; continue; } /* Process a nested OPENER. */ if (STREQN (string + i, opener, len_opener)) { si = i + len_opener; t = extract_delimited_string (string, &si, opener, alt_opener, closer, flags|SX_NOALLOC); i = si + 1; continue; } /* Process a nested ALT_OPENER */ if (len_alt_opener && STREQN (string + i, alt_opener, len_alt_opener)) { si = i + len_alt_opener; t = extract_delimited_string (string, &si, alt_opener, alt_opener, closer, flags|SX_NOALLOC); i = si + 1; continue; } /* If the current substring terminates the delimited string, decrement the nesting level. */ if (STREQN (string + i, closer, len_closer)) { i += len_closer - 1; /* move to last byte of the closer */ nesting_level--; if (nesting_level == 0) break; } /* Pass old-style command substitution through verbatim. */ if (c == '`') { si = i + 1; t = string_extract (string, &si, "`", flags|SX_NOALLOC); i = si + 1; continue; } /* Pass single-quoted and double-quoted strings through verbatim. */ if (c == '\'' || c == '"') { si = i + 1; i = (c == '\'') ? skip_single_quoted (string, slen, si) : skip_double_quoted (string, slen, si); continue; } /* move past this character, which was not special. */ ADVANCE_CHAR (string, slen, i); } if (c == 0 && nesting_level) { if (no_longjmp_on_fatal_error == 0) { report_error (_("bad substitution: no closing `%s' in %s"), closer, string); last_command_exit_value = EXECUTION_FAILURE; exp_jump_to_top_level (DISCARD); } else { *sindex = i; return (char *)NULL; } } si = i - *sindex - len_closer + 1; if (flags & SX_NOALLOC) result = (char *)NULL; else { result = (char *)xmalloc (1 + si); strncpy (result, string + *sindex, si); result[si] = '\0'; } *sindex = i; return (result);}/* Extract a parameter expansion expression within ${ and } from STRING. Obey the Posix.2 rules for finding the ending `}': count braces while skipping over enclosed quoted strings and command substitutions. SINDEX is the address of an int describing the current offset in STRING; it should point to just after the first `{' found. On exit, SINDEX gets the position of the matching `}'. QUOTED is non-zero if this occurs inside double quotes. *//* XXX -- this is very similar to extract_delimited_string -- XXX */static char *extract_dollar_brace_string (string, sindex, quoted, flags) char *string; int *sindex, quoted, flags;{ register int i, c; size_t slen; int pass_character, nesting_level, si, dolbrace_state; char *result, *t; DECLARE_MBSTATE; pass_character = 0; nesting_level = 1; slen = strlen (string + *sindex) + *sindex; /* The handling of dolbrace_state needs to agree with the code in parse.y: parse_matched_pair() */ dolbrace_state = 0; if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) dolbrace_state = (flags & SX_POSIXEXP) ? DOLBRACE_QUOTE : DOLBRACE_PARAM; i = *sindex; while (c = string[i]) { if (pass_character) { pass_character = 0; ADVANCE_CHAR (string, slen, i); continue; } /* CTLESCs and backslashes quote the next character. */ if (c == CTLESC || c == '\\') { pass_character++; i++; continue; } if (string[i] == '$' && string[i+1] == LBRACE) { nesting_level++; i += 2; continue; } if (c == RBRACE) { nesting_level--; if (nesting_level == 0) break; i++; continue; } /* Pass the contents of old-style command substitutions through verbatim. */ if (c == '`') { si = i + 1; t = string_extract (string, &si, "`", flags|SX_NOALLOC); i = si + 1; continue; } /* Pass the contents of new-style command substitutions and arithmetic substitutions through verbatim. */ if (string[i] == '$' && string[i+1] == LPAREN) { si = i + 2; t = extract_command_subst (string, &si, flags|SX_NOALLOC); i = si + 1; continue; }#if 0 /* Pass the contents of single-quoted and double-quoted strings through verbatim. */ if (c == '\'' || c == '"') { si = i + 1; i = (c == '\'') ? skip_single_quoted (string, slen, si) : skip_double_quoted (string, slen, si); /* skip_XXX_quoted leaves index one past close quote */ continue; }#else /* XXX - bash-4.2 */ /* Pass the contents of double-quoted strings through verbatim. */ if (c == '"') { si = i + 1; i = skip_double_quoted (string, slen, si); /* skip_XXX_quoted leaves index one past close quote */ continue; } if (c == '\'') {/*itrace("extract_dollar_brace_string: c == single quote flags = %d quoted = %d dolbrace_state = %d", flags, quoted, dolbrace_state);*/ if (posixly_correct && shell_compatibility_level > 41 && dolbrace_state != DOLBRACE_QUOTE && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) ADVANCE_CHAR (string, slen, i); else { si = i + 1; i = skip_single_quoted (string, slen, si); } continue; }#endif /* move past this character, which was not special. */ ADVANCE_CHAR (string, slen, i); /* This logic must agree with parse.y:parse_matched_pair, since they share the same defines. */ if (dolbrace_state == DOLBRACE_PARAM && c == '%' && (i - *sindex) > 1)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -