📄 subst.c
字号:
/* subst.c -- The part of the shell that does parameter, command, arithmetic, and globbing substitutions. *//* ``Have a little faith, there's magic in the night. You ain't a beauty, but, hey, you're alright.'' *//* Copyright (C) 1987-2010 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. Bash is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Bash is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Bash. If not, see <http://www.gnu.org/licenses/>.*/#include "config.h"#include "bashtypes.h"#include <stdio.h>#include "chartypes.h"#if defined (HAVE_PWD_H)# include <pwd.h>#endif#include <signal.h>#include <errno.h>#if defined (HAVE_UNISTD_H)# include <unistd.h>#endif#include "bashansi.h"#include "posixstat.h"#include "bashintl.h"#include "shell.h"#include "parser.h"#include "flags.h"#include "jobs.h"#include "execute_cmd.h"#include "filecntl.h"#include "trap.h"#include "pathexp.h"#include "mailcheck.h"#include "shmbutil.h"#include "typemax.h"#include "builtins/getopt.h"#include "builtins/common.h"#include "builtins/builtext.h"#include <tilde/tilde.h>#include <glob/strmatch.h>#if !defined (errno)extern int errno;#endif /* !errno *//* The size that strings change by. */#define DEFAULT_INITIAL_ARRAY_SIZE 112#define DEFAULT_ARRAY_SIZE 128/* Variable types. */#define VT_VARIABLE 0#define VT_POSPARMS 1#define VT_ARRAYVAR 2#define VT_ARRAYMEMBER 3#define VT_ASSOCVAR 4#define VT_STARSUB 128 /* $* or ${array[*]} -- used to split *//* Flags for quoted_strchr */#define ST_BACKSL 0x01#define ST_CTLESC 0x02#define ST_SQUOTE 0x04 /* unused yet */#define ST_DQUOTE 0x08 /* unused yet *//* Flags for the `pflags' argument to param_expand() */#define PF_NOCOMSUB 0x01 /* Do not perform command substitution */#define PF_IGNUNBOUND 0x02 /* ignore unbound vars even if -u set */#define PF_NOSPLIT2 0x04 /* same as W_NOSPLIT2 *//* These defs make it easier to use the editor. */#define LBRACE '{'#define RBRACE '}'#define LPAREN '('#define RPAREN ')'#if defined (HANDLE_MULTIBYTE)#define WLPAREN L'('#define WRPAREN L')'#endif/* Evaluates to 1 if C is one of the shell's special parameters whose length can be taken, but is also one of the special expansion characters. */#define VALID_SPECIAL_LENGTH_PARAM(c) \ ((c) == '-' || (c) == '?' || (c) == '#')/* Evaluates to 1 if C is one of the shell's special parameters for which an indirect variable reference may be made. */#define VALID_INDIR_PARAM(c) \ ((posixly_correct == 0 && (c) == '#') || (posixly_correct == 0 && (c) == '?') || (c) == '@' || (c) == '*')/* Evaluates to 1 if C is one of the OP characters that follows the parameter in ${parameter[:]OPword}. */#define VALID_PARAM_EXPAND_CHAR(c) (sh_syntaxtab[(unsigned char)c] & CSUBSTOP)/* Evaluates to 1 if this is one of the shell's special variables. */#define SPECIAL_VAR(name, wi) \ ((DIGIT (*name) && all_digits (name)) || \ (name[1] == '\0' && (sh_syntaxtab[(unsigned char)*name] & CSPECVAR)) || \ (wi && name[2] == '\0' && VALID_INDIR_PARAM (name[1])))/* An expansion function that takes a string and a quoted flag and returns a WORD_LIST *. Used as the type of the third argument to expand_string_if_necessary(). */typedef WORD_LIST *EXPFUNC __P((char *, int));/* Process ID of the last command executed within command substitution. */pid_t last_command_subst_pid = NO_PID;pid_t current_command_subst_pid = NO_PID;/* Variables used to keep track of the characters in IFS. */SHELL_VAR *ifs_var;char *ifs_value;unsigned char ifs_cmap[UCHAR_MAX + 1];#if defined (HANDLE_MULTIBYTE)unsigned char ifs_firstc[MB_LEN_MAX];size_t ifs_firstc_len;#elseunsigned char ifs_firstc;#endif/* Sentinel to tell when we are performing variable assignments preceding a command name and putting them into the environment. Used to make sure we use the temporary environment when looking up variable values. */int assigning_in_environment;/* Used to hold a list of variable assignments preceding a command. Global so the SIGCHLD handler in jobs.c can unwind-protect it when it runs a SIGCHLD trap and so it can be saved and restored by the trap handlers. */WORD_LIST *subst_assign_varlist = (WORD_LIST *)NULL;/* Extern functions and variables from different files. */extern int last_command_exit_value, last_command_exit_signal;extern int subshell_environment, line_number;extern int subshell_level, parse_and_execute_level, sourcelevel;extern int eof_encountered;extern int return_catch_flag, return_catch_value;extern pid_t dollar_dollar_pid;extern int posixly_correct;extern char *this_command_name;extern struct fd_bitmap *current_fds_to_close;extern int wordexp_only;extern int expanding_redir;extern int tempenv_assign_error;#if !defined (HAVE_WCSDUP) && defined (HANDLE_MULTIBYTE)extern wchar_t *wcsdup __P((const wchar_t *));#endif/* Non-zero means to allow unmatched globbed filenames to expand to a null file. */int allow_null_glob_expansion;/* Non-zero means to throw an error when globbing fails to match anything. */int fail_glob_expansion;#if 0/* Variables to keep track of which words in an expanded word list (the output of expand_word_list_internal) are the result of globbing expansions. GLOB_ARGV_FLAGS is used by execute_cmd.c. (CURRENTLY UNUSED). */char *glob_argv_flags;static int glob_argv_flags_size;#endifstatic WORD_LIST expand_word_error, expand_word_fatal;static WORD_DESC expand_wdesc_error, expand_wdesc_fatal;static char expand_param_error, expand_param_fatal;static char extract_string_error, extract_string_fatal;/* Tell the expansion functions to not longjmp back to top_level on fatal errors. Enabled when doing completion and prompt string expansion. */static int no_longjmp_on_fatal_error = 0;/* Set by expand_word_unsplit; used to inhibit splitting and re-joining $* on $IFS, primarily when doing assignment statements. */static int expand_no_split_dollar_star = 0;/* A WORD_LIST of words to be expanded by expand_word_list_internal, without any leading variable assignments. */static WORD_LIST *garglist = (WORD_LIST *)NULL;static char *quoted_substring __P((char *, int, int));static int quoted_strlen __P((char *));static char *quoted_strchr __P((char *, int, int));static char *expand_string_if_necessary __P((char *, int, EXPFUNC *));static inline char *expand_string_to_string_internal __P((char *, int, EXPFUNC *));static WORD_LIST *call_expand_word_internal __P((WORD_DESC *, int, int, int *, int *));static WORD_LIST *expand_string_internal __P((char *, int));static WORD_LIST *expand_string_leave_quoted __P((char *, int));static WORD_LIST *expand_string_for_rhs __P((char *, int, int *, int *));static WORD_LIST *list_quote_escapes __P((WORD_LIST *));static char *make_quoted_char __P((int));static WORD_LIST *quote_list __P((WORD_LIST *));static int unquoted_substring __P((char *, char *));static int unquoted_member __P((int, char *));#if defined (ARRAY_VARS)static SHELL_VAR *do_compound_assignment __P((char *, char *, int));#endifstatic int do_assignment_internal __P((const WORD_DESC *, int));static char *string_extract_verbatim __P((char *, size_t, int *, char *, int));static char *string_extract __P((char *, int *, char *, int));static char *string_extract_double_quoted __P((char *, int *, int));static inline char *string_extract_single_quoted __P((char *, int *));static inline int skip_single_quoted __P((const char *, size_t, int));static int skip_double_quoted __P((char *, size_t, int));static char *extract_delimited_string __P((char *, int *, char *, char *, char *, int));static char *extract_dollar_brace_string __P((char *, int *, int, int));static int skip_matched_pair __P((const char *, int, int, int, int));static char *pos_params __P((char *, int, int, int));static unsigned char *mb_getcharlens __P((char *, int));static char *remove_upattern __P((char *, char *, int));#if defined (HANDLE_MULTIBYTE) static wchar_t *remove_wpattern __P((wchar_t *, size_t, wchar_t *, int));#endifstatic char *remove_pattern __P((char *, char *, int));static int match_upattern __P((char *, char *, int, char **, char **));#if defined (HANDLE_MULTIBYTE)static int match_wpattern __P((wchar_t *, char **, size_t, wchar_t *, int, char **, char **));#endifstatic int match_pattern __P((char *, char *, int, char **, char **));static int getpatspec __P((int, char *));static char *getpattern __P((char *, int, int));static char *variable_remove_pattern __P((char *, char *, int, int));static char *list_remove_pattern __P((WORD_LIST *, char *, int, int, int));static char *parameter_list_remove_pattern __P((int, char *, int, int));#ifdef ARRAY_VARSstatic char *array_remove_pattern __P((SHELL_VAR *, char *, int, char *, int));#endifstatic char *parameter_brace_remove_pattern __P((char *, char *, int, char *, int, int, int));static char *process_substitute __P((char *, int));static char *read_comsub __P((int, int, int *));#ifdef ARRAY_VARSstatic arrayind_t array_length_reference __P((char *));#endifstatic int valid_brace_expansion_word __P((char *, int));static int chk_atstar __P((char *, int, int *, int *));static int chk_arithsub __P((const char *, int));static WORD_DESC *parameter_brace_expand_word __P((char *, int, int, int, arrayind_t *));static WORD_DESC *parameter_brace_expand_indir __P((char *, int, int, int *, int *));static WORD_DESC *parameter_brace_expand_rhs __P((char *, char *, int, int, int *, int *));static void parameter_brace_expand_error __P((char *, char *));static int valid_length_expression __P((char *));static intmax_t parameter_brace_expand_length __P((char *));static char *skiparith __P((char *, int));static int verify_substring_values __P((SHELL_VAR *, char *, char *, int, intmax_t *, intmax_t *));static int get_var_and_type __P((char *, char *, arrayind_t, int, int, SHELL_VAR **, char **));static char *mb_substring __P((char *, int, int));static char *parameter_brace_substring __P((char *, char *, int, char *, int, int));static int shouldexp_replacement __P((char *));static char *pos_params_pat_subst __P((char *, char *, char *, int));static char *parameter_brace_patsub __P((char *, char *, int, char *, int, int));static char *pos_params_casemod __P((char *, char *, int, int));static char *parameter_brace_casemod __P((char *, char *, int, int, char *, int, int));static WORD_DESC *parameter_brace_expand __P((char *, int *, int, int, int *, int *));static WORD_DESC *param_expand __P((char *, int *, int, int *, int *, int *, int *, int));static WORD_LIST *expand_word_internal __P((WORD_DESC *, int, int, int *, int *));static WORD_LIST *word_list_split __P((WORD_LIST *));static void exp_jump_to_top_level __P((int));static WORD_LIST *separate_out_assignments __P((WORD_LIST *));static WORD_LIST *glob_expand_word_list __P((WORD_LIST *, int));#ifdef BRACE_EXPANSIONstatic WORD_LIST *brace_expand_word_list __P((WORD_LIST *, int));#endif#if defined (ARRAY_VARS)static int make_internal_declare __P((char *, char *));#endifstatic WORD_LIST *shell_expand_word_list __P((WORD_LIST *, int));static WORD_LIST *expand_word_list_internal __P((WORD_LIST *, int));/* **************************************************************** *//* *//* Utility Functions *//* *//* **************************************************************** */#if defined (DEBUG)voiddump_word_flags (flags) int flags;{ int f; f = flags; fprintf (stderr, "%d -> ", f); if (f & W_ASSIGNASSOC) { f &= ~W_ASSIGNASSOC; fprintf (stderr, "W_ASSIGNASSOC%s", f ? "|" : ""); } if (f & W_HASCTLESC) { f &= ~W_HASCTLESC; fprintf (stderr, "W_HASCTLESC%s", f ? "|" : ""); } if (f & W_NOPROCSUB) { f &= ~W_NOPROCSUB; fprintf (stderr, "W_NOPROCSUB%s", f ? "|" : ""); } if (f & W_DQUOTE) { f &= ~W_DQUOTE; fprintf (stderr, "W_DQUOTE%s", f ? "|" : ""); } if (f & W_HASQUOTEDNULL) { f &= ~W_HASQUOTEDNULL; fprintf (stderr, "W_HASQUOTEDNULL%s", f ? "|" : ""); } if (f & W_ASSIGNARG) { f &= ~W_ASSIGNARG; fprintf (stderr, "W_ASSIGNARG%s", f ? "|" : ""); } if (f & W_ASSNBLTIN) { f &= ~W_ASSNBLTIN; fprintf (stderr, "W_ASSNBLTIN%s", f ? "|" : ""); } if (f & W_COMPASSIGN) { f &= ~W_COMPASSIGN; fprintf (stderr, "W_COMPASSIGN%s", f ? "|" : ""); } if (f & W_NOEXPAND) { f &= ~W_NOEXPAND; fprintf (stderr, "W_NOEXPAND%s", f ? "|" : ""); } if (f & W_ITILDE) { f &= ~W_ITILDE; fprintf (stderr, "W_ITILDE%s", f ? "|" : ""); } if (f & W_NOTILDE) { f &= ~W_NOTILDE; fprintf (stderr, "W_NOTILDE%s", f ? "|" : ""); } if (f & W_ASSIGNRHS) { f &= ~W_ASSIGNRHS; fprintf (stderr, "W_ASSIGNRHS%s", f ? "|" : ""); } if (f & W_NOCOMSUB) { f &= ~W_NOCOMSUB; fprintf (stderr, "W_NOCOMSUB%s", f ? "|" : ""); } if (f & W_DOLLARSTAR) { f &= ~W_DOLLARSTAR; fprintf (stderr, "W_DOLLARSTAR%s", f ? "|" : ""); } if (f & W_DOLLARAT) { f &= ~W_DOLLARAT; fprintf (stderr, "W_DOLLARAT%s", f ? "|" : ""); } if (f & W_TILDEEXP) { f &= ~W_TILDEEXP; fprintf (stderr, "W_TILDEEXP%s", f ? "|" : ""); } if (f & W_NOSPLIT2) { f &= ~W_NOSPLIT2; fprintf (stderr, "W_NOSPLIT2%s", f ? "|" : ""); } if (f & W_NOGLOB) { f &= ~W_NOGLOB; fprintf (stderr, "W_NOGLOB%s", f ? "|" : ""); } if (f & W_NOSPLIT) { f &= ~W_NOSPLIT; fprintf (stderr, "W_NOSPLIT%s", f ? "|" : ""); } if (f & W_GLOBEXP) { f &= ~W_GLOBEXP; fprintf (stderr, "W_GLOBEXP%s", f ? "|" : ""); } if (f & W_ASSIGNMENT) { f &= ~W_ASSIGNMENT; fprintf (stderr, "W_ASSIGNMENT%s", f ? "|" : ""); } if (f & W_QUOTED) { f &= ~W_QUOTED; fprintf (stderr, "W_QUOTED%s", f ? "|" : ""); } if (f & W_HASDOLLAR) { f &= ~W_HASDOLLAR; fprintf (stderr, "W_HASDOLLAR%s", f ? "|" : ""); } fprintf (stderr, "\n"); fflush (stderr);}#endif#ifdef INCLUDE_UNUSEDstatic char *quoted_substring (string, start, end) char *string; int start, end;{ register int len, l; register char *result, *s, *r; len = end - start; /* Move to string[start], skipping quoted characters. */ for (s = string, l = 0; *s && l < start; ) { if (*s == CTLESC) { s++; continue; } l++; if (*s == 0) break; } r = result = (char *)xmalloc (2*len + 1); /* save room for quotes */ /* Copy LEN characters, including quote characters. */ s = string + l; for (l = 0; l < len; s++) { if (*s == CTLESC) *r++ = *s++; *r++ = *s; l++; if (*s == 0) break; } *r = '\0'; return result;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -