📄 subst.c
字号:
ret = (WORD_LIST *)NULL; /* Remove sequences of whitespace characters at the start of the string, as long as those characters are delimiters. */ for (i = 0; member (string[i], d) && spctabnl (string[i]); i++) ; if (string[i] == '\0') return (ret); ts = i; nw = 0; cw = -1; dflags = flags|SD_NOJMP; while (1) { te = skip_to_delim (string, ts, d, dflags); /* If we have a non-whitespace delimiter character, use it to make a separate field. This is just about what $IFS splitting does and is closer to the behavior of the shell parser. */ if (ts == te && d2 && member (string[ts], d2)) { te = ts + 1; /* If we're using IFS splitting, the non-whitespace delimiter char and any additional IFS whitespace delimits a field. */ if (ifs_split) while (member (string[te], d) && spctabnl (string[te])) te++; else while (member (string[te], d2)) te++; } token = substring (string, ts, te); ret = add_string_to_list (token, ret); free (token); nw++; if (sentinel >= ts && sentinel <= te) cw = nw; /* If the cursor is at whitespace just before word start, set the sentinel word to the current word. */ if (cwp && cw == -1 && sentinel == ts-1) cw = nw; /* If the cursor is at whitespace between two words, make a new, empty word, add it before (well, after, since the list is in reverse order) the word we just added, and set the current word to that one. */ if (cwp && cw == -1 && sentinel < ts) { tl = make_word_list (make_word (""), ret->next); ret->next = tl; cw = nw; nw++; } if (string[te] == 0) break; i = te; while (member (string[i], d) && (ifs_split || spctabnl(string[i]))) i++; if (string[i]) ts = i; else break; } /* Special case for SENTINEL at the end of STRING. If we haven't found the word containing SENTINEL yet, and the index we're looking for is at the end of STRING (or past the end of the previously-found token, possible if the end of the line is composed solely of IFS whitespace) add an additional null argument and set the current word pointer to that. */ if (cwp && cw == -1 && (sentinel >= slen || sentinel >= te)) { if (whitespace (string[sentinel - 1])) { token = ""; ret = add_string_to_list (token, ret); nw++; } cw = nw; } if (nwp) *nwp = nw; if (cwp) *cwp = cw; return (REVERSE_LIST (ret, WORD_LIST *));}#endif /* READLINE */#if 0/* UNUSED *//* Extract the name of the variable to bind to from the assignment string. */char *assignment_name (string) char *string;{ int offset; char *temp; offset = assignment (string, 0); if (offset == 0) return (char *)NULL; temp = substring (string, 0, offset); return (temp);}#endif/* **************************************************************** *//* *//* Functions to convert strings to WORD_LISTs and vice versa *//* *//* **************************************************************** *//* Return a single string of all the words in LIST. SEP is the separator to put between individual elements of LIST in the output string. */char *string_list_internal (list, sep) WORD_LIST *list; char *sep;{ register WORD_LIST *t; char *result, *r; int word_len, sep_len, result_size; if (list == 0) return ((char *)NULL); /* Short-circuit quickly if we don't need to separate anything. */ if (list->next == 0) return (savestring (list->word->word)); /* This is nearly always called with either sep[0] == 0 or sep[1] == 0. */ sep_len = STRLEN (sep); result_size = 0; for (t = list; t; t = t->next) { if (t != list) result_size += sep_len; result_size += strlen (t->word->word); } r = result = (char *)xmalloc (result_size + 1); for (t = list; t; t = t->next) { if (t != list && sep_len) { if (sep_len > 1) { FASTCOPY (sep, r, sep_len); r += sep_len; } else *r++ = sep[0]; } word_len = strlen (t->word->word); FASTCOPY (t->word->word, r, word_len); r += word_len; } *r = '\0'; return (result);}/* Return a single string of all the words present in LIST, separating each word with a space. */char *string_list (list) WORD_LIST *list;{ return (string_list_internal (list, " "));}/* An external interface that can be used by the rest of the shell to obtain a string containing the first character in $IFS. Handles all the multibyte complications. If LENP is non-null, it is set to the length of the returned string. */char *ifs_firstchar (lenp) int *lenp;{ char *ret; int len; ret = xmalloc (MB_LEN_MAX + 1);#if defined (HANDLE_MULTIBYTE) if (ifs_firstc_len == 1) { ret[0] = ifs_firstc[0]; ret[1] = '\0'; len = ret[0] ? 1 : 0; } else { memcpy (ret, ifs_firstc, ifs_firstc_len); ret[len = ifs_firstc_len] = '\0'; }#else ret[0] = ifs_firstc; ret[1] = '\0'; len = ret[0] ? 0 : 1;#endif if (lenp) *lenp = len; return ret;}/* Return a single string of all the words present in LIST, obeying the quoting rules for "$*", to wit: (P1003.2, draft 11, 3.5.2) "If the expansion [of $*] appears within a double quoted string, it expands to a single field with the value of each parameter separated by the first character of the IFS variable, or by a <space> if IFS is unset." */char *string_list_dollar_star (list) WORD_LIST *list;{ char *ret;#if defined (HANDLE_MULTIBYTE)# if defined (__GNUC__) char sep[MB_CUR_MAX + 1];# else char *sep = 0;# endif#else char sep[2];#endif#if defined (HANDLE_MULTIBYTE)# if !defined (__GNUC__) sep = (char *)xmalloc (MB_CUR_MAX + 1);# endif /* !__GNUC__ */ if (ifs_firstc_len == 1) { sep[0] = ifs_firstc[0]; sep[1] = '\0'; } else { memcpy (sep, ifs_firstc, ifs_firstc_len); sep[ifs_firstc_len] = '\0'; }#else sep[0] = ifs_firstc; sep[1] = '\0';#endif ret = string_list_internal (list, sep);#if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__) free (sep);#endif return ret;}/* Turn $@ into a string. If (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) is non-zero, the $@ appears within double quotes, and we should quote the list before converting it into a string. If IFS is unset, and the word is not quoted, we just need to quote CTLESC and CTLNUL characters in the words in the list, because the default value of $IFS is <space><tab><newline>, IFS characters in the words in the list should also be split. If IFS is null, and the word is not quoted, we need to quote the words in the list to preserve the positional parameters exactly. */char *string_list_dollar_at (list, quoted) WORD_LIST *list; int quoted;{ char *ifs, *ret;#if defined (HANDLE_MULTIBYTE)# if defined (__GNUC__) char sep[MB_CUR_MAX + 1];# else char *sep = 0;# endif /* !__GNUC__ */#else char sep[2];#endif WORD_LIST *tlist; /* XXX this could just be ifs = ifs_value; */ ifs = ifs_var ? value_cell (ifs_var) : (char *)0;#if defined (HANDLE_MULTIBYTE)# if !defined (__GNUC__) sep = (char *)xmalloc (MB_CUR_MAX + 1);# endif /* !__GNUC__ */ if (ifs && *ifs) { if (ifs_firstc_len == 1) { sep[0] = ifs_firstc[0]; sep[1] = '\0'; } else { memcpy (sep, ifs_firstc, ifs_firstc_len); sep[ifs_firstc_len] = '\0'; } } else { sep[0] = ' '; sep[1] = '\0'; }#else sep[0] = (ifs == 0 || *ifs == 0) ? ' ' : *ifs; sep[1] = '\0';#endif /* XXX -- why call quote_list if ifs == 0? we can get away without doing it now that quote_escapes quotes spaces */ tlist = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES|Q_PATQUOTE)) ? quote_list (list) : list_quote_escapes (list); ret = string_list_internal (tlist, sep);#if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__) free (sep);#endif return ret;}/* Turn the positional paramters into a string, understanding quoting and the various subtleties of using the first character of $IFS as the separator. Calls string_list_dollar_at, string_list_dollar_star, and string_list as appropriate. */char *string_list_pos_params (pchar, list, quoted) int pchar; WORD_LIST *list; int quoted;{ char *ret; WORD_LIST *tlist; if (pchar == '*' && (quoted & Q_DOUBLE_QUOTES)) { tlist = quote_list (list); word_list_remove_quoted_nulls (tlist); ret = string_list_dollar_star (tlist); } else if (pchar == '*' && (quoted & Q_HERE_DOCUMENT)) { tlist = quote_list (list); word_list_remove_quoted_nulls (tlist); ret = string_list (tlist); } else if (pchar == '*') { /* Even when unquoted, string_list_dollar_star does the right thing making sure that the first character of $IFS is used as the separator. */ ret = string_list_dollar_star (list); } else if (pchar == '@' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) /* We use string_list_dollar_at, but only if the string is quoted, since that quotes the escapes if it's not, which we don't want. We could use string_list (the old code did), but that doesn't do the right thing if the first character of $IFS is not a space. We use string_list_dollar_star if the string is unquoted so we make sure that the elements of $@ are separated by the first character of $IFS for later splitting. */ ret = string_list_dollar_at (list, quoted); else if (pchar == '@') ret = string_list_dollar_star (list); else ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (list) : list); return ret;}/* Return the list of words present in STRING. Separate the string into words at any of the characters found in SEPARATORS. If QUOTED is non-zero then word in the list will have its quoted flag set, otherwise the quoted flag is left as make_word () deemed fit. This obeys the P1003.2 word splitting semantics. If `separators' is exactly <space><tab><newline>, then the splitting algorithm is that of the Bourne shell, which treats any sequence of characters from `separators' as a delimiter. If IFS is unset, which results in `separators' being set to "", no splitting occurs. If separators has some other value, the following rules are applied (`IFS white space' means zero or more occurrences of <space>, <tab>, or <newline>, as long as those characters are in `separators'): 1) IFS white space is ignored at the start and the end of the string. 2) Each occurrence of a character in `separators' that is not IFS white space, along with any adjacent occurrences of IFS white space delimits a field. 3) Any nonzero-length sequence of IFS white space delimits a field. *//* BEWARE! list_string strips null arguments. Don't call it twice and expect to have "" preserved! *//* This performs word splitting and quoted null character removal on STRING. */#define issep(c) \ (((separators)[0]) ? ((separators)[1] ? isifs(c) \ : (c) == (separators)[0]) \ : 0)WORD_LIST *list_string (string, separators, quoted) register char *string, *separators; int quoted;{ WORD_LIST *result; WORD_DESC *t; char *current_word, *s; int sindex, sh_style_split, whitesep, xflags; size_t slen; if (!string || !*string) return ((WORD_LIST *)NULL); sh_style_split = separators && separators[0] == ' ' && separators[1] == '\t' && separators[2] == '\n' && separators[3] == '\0'; for (xflags = 0, s = ifs_value; s && *s; s++) { if (*s == CTLESC) xflags |= SX_NOCTLESC; else if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL; } slen = 0; /* Remove sequences of whitespace at the beginning of STRING, as long as those characters appear in IFS. Do not do this if STRING is quoted or if there are no separator characters. */ if (!quoted || !separators || !*separators) { for (s = string; *s && spctabnl (*s) && issep (*s); s++); if (!*s) return ((WORD_LIST *)NULL); string = s; } /* OK, now STRING points to a word that does not begin with white space. The splitting algorithm is: extract a word, stopping at a separator skip sequences of spc, tab, or nl as long as they are separators This obeys the field splitting rules in Posix.2. */ slen = (MB_CUR_MAX > 1) ? strlen (string) : 1; for (result = (WORD_LIST *)NULL, sindex = 0; string[sindex]; ) { /* Don't need string length in ADVANCE_CHAR or string_extract_verbatim unless multibyte chars are possible. */ current_word = string_extract_verbatim (string, slen, &sindex, separators, xflags); if (current_word == 0) break; /* If we have a quoted empty string, add a quoted null argument. We want to preserve the quoted null character iff this is a quoted empty string; otherwise the quoted null characters are removed below. */ if (QUOTED_NULL (current_word)) { t = alloc_word_desc (); t->word = make_quoted_char ('\0'); t->flags |= W_QUOTED|W_HASQUOTEDNULL; result = make_word_list (t, result); } else if (current_word[0] != '\0') { /* If we have something, then add it regardless. However, perform quoted null character removal on the current word. */ remove_quoted_nulls (current_word); result = add_string_to_list (current_word, result); result->word->flags &= ~W_HASQUOTEDNULL; /* just to be sure */ if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) result->word->flags |= W_QUOTED; } /* If we're not doing sequences of
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -