/* Definitions for using variables in GNU Make. Copyright (C) 1988-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make 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. GNU Make 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 this program. If not, see . */ #include "hash.h" #ifdef CONFIG_WITH_COMPILER # include "kmk_cc_exec.h" #endif /* Codes in a variable definition saying where the definition came from. Increasing numeric values signify less-overridable definitions. */ enum variable_origin { o_default, /* Variable from the default set. */ o_env, /* Variable from environment. */ o_file, /* Variable given in a makefile. */ o_env_override, /* Variable from environment, if -e. */ o_command, /* Variable given by user. */ o_override, /* Variable from an 'override' directive. */ #ifdef CONFIG_WITH_LOCAL_VARIABLES o_local, /* Variable from an 'local' directive. */ #endif o_automatic, /* Automatic variable -- cannot be set. */ o_invalid /* Core dump time. */ }; enum variable_flavor { f_bogus, /* Bogus (error) */ f_simple, /* Simple definition (:= or ::=) */ f_recursive, /* Recursive definition (=) */ f_append, /* Appending definition (+=) */ #ifdef CONFIG_WITH_PREPEND_ASSIGNMENT f_prepend, /* Prepending definition (>=) */ #endif f_conditional, /* Conditional definition (?=) */ f_shell /* Shell assignment (!=) */ }; /* Structure that represents one variable definition. Each bucket of the hash table is a chain of these, chained through 'next'. */ #define EXP_COUNT_BITS 15 /* This gets all the bitfields into 32 bits */ #define EXP_COUNT_MAX ((1<1, allow this many self-referential expansions. */ #ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE unsigned int rdonly_val:1; /* VALUE is read only (strcache/const). */ #endif #ifdef KMK unsigned int alias:1; /* Nonzero if alias. VALUE points to the real variable. */ unsigned int aliased:1; /* Nonzero if aliased. Cannot be undefined. */ #endif enum variable_flavor flavor ENUM_BITFIELD (3); /* Variable flavor. */ enum variable_origin #ifdef CONFIG_WITH_LOCAL_VARIABLES origin ENUM_BITFIELD (4); /* Variable origin. */ #else origin ENUM_BITFIELD (3); /* Variable origin. */ #endif enum variable_export { v_export, /* Export this variable. */ v_noexport, /* Don't export this variable. */ v_ifset, /* Export it if it has a non-default value. */ v_default /* Decide in target_environment. */ } export ENUM_BITFIELD (2); #ifdef CONFIG_WITH_COMPILER int recursive_without_dollar : 2; /* 0 if undetermined, 1 if value has no '$' chars, -1 if it has. */ #endif #ifdef CONFIG_WITH_MAKE_STATS unsigned int changes; /* Variable modification count. */ unsigned int reallocs; /* Realloc on value count. */ unsigned int references; /* Lookup count. */ unsigned long long cTicksEvalVal; /* Number of ticks spend in cEvalVal. */ #endif #if defined (CONFIG_WITH_COMPILER) || defined (CONFIG_WITH_MAKE_STATS) unsigned int evalval_count; /* Times used with $(evalval ) or $(evalctx ) since last change. */ unsigned int expand_count; /* Times expanded since last change (not to be confused with exp_count). */ #endif #ifdef CONFIG_WITH_COMPILER struct kmk_cc_evalprog *evalprog; /* Pointer to evalval/evalctx "program". */ struct kmk_cc_expandprog *expandprog; /* Pointer to variable expand "program". */ #endif }; /* Update statistics and invalidates optimizations when a variable changes. */ #ifdef CONFIG_WITH_COMPILER # define VARIABLE_CHANGED(v) \ do { \ MAKE_STATS_2((v)->changes++); \ if ((v)->evalprog || (v)->expandprog) kmk_cc_variable_changed(v); \ (v)->expand_count = 0; \ (v)->evalval_count = 0; \ (v)->recursive_without_dollar = 0; \ } while (0) #else # define VARIABLE_CHANGED(v) MAKE_STATS_2((v)->changes++) #endif /* Macro that avoids a lot of CONFIG_WITH_COMPILER checks when accessing recursive_without_dollar. */ #ifdef CONFIG_WITH_COMPILER # define IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR(v) ((v)->recursive_without_dollar > 0) #else # define IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR(v) 0 #endif /* Structure that represents a variable set. */ struct variable_set { struct hash_table table; /* Hash table of variables. */ }; /* Structure that represents a list of variable sets. */ struct variable_set_list { struct variable_set_list *next; /* Link in the chain. */ struct variable_set *set; /* Variable set. */ int next_is_parent; /* True if next is a parent target. */ }; /* Structure used for pattern-specific variables. */ struct pattern_var { struct pattern_var *next; const char *suffix; const char *target; unsigned int len; struct variable variable; }; extern char *variable_buffer; extern struct variable_set_list *current_variable_set_list; extern struct variable *default_goal_var; extern struct variable shell_var; #ifdef KMK extern struct variable_set global_variable_set; extern struct variable_set_list global_setlist; extern unsigned int variable_buffer_length; # define VARIABLE_BUFFER_ZONE 5 #endif /* expand.c */ #ifndef KMK char * variable_buffer_output (char *ptr, const char *string, unsigned int length); #else /* KMK */ # include /* Subroutine of variable_expand and friends: The text to add is LENGTH chars starting at STRING to the variable_buffer. The text is added to the buffer at PTR, and the updated pointer into the buffer is returned as the value. Thus, the value returned by each call to variable_buffer_output should be the first argument to the following call. */ K_INLINE char *variable_buffer_output (char *ptr, const char *string, unsigned int length) { register unsigned int newlen = length + (ptr - variable_buffer); if ((newlen + VARIABLE_BUFFER_ZONE) > variable_buffer_length) { unsigned int offset = ptr - variable_buffer; variable_buffer_length = variable_buffer_length <= 1024 ? 2048 : variable_buffer_length * 4; if (variable_buffer_length < newlen + 100) variable_buffer_length = (newlen + 100 + 1023) & ~1023U; variable_buffer = xrealloc (variable_buffer, variable_buffer_length); ptr = variable_buffer + offset; } # ifndef _MSC_VER switch (length) { case 4: ptr[3] = string[3]; /* fall thru */ case 3: ptr[2] = string[2]; /* fall thru */ case 2: ptr[1] = string[1]; /* fall thru */ case 1: ptr[0] = string[0]; /* fall thru */ case 0: break; default: memcpy (ptr, string, length); break; } # else memcpy (ptr, string, length); # endif return ptr + length; } #endif /* KMK */ char *variable_expand (const char *line); char *variable_expand_for_file (const char *line, struct file *file); #if defined (CONFIG_WITH_VALUE_LENGTH) || defined (CONFIG_WITH_COMMANDS_FUNC) char *variable_expand_for_file_2 (char *o, const char *line, unsigned int lenght, struct file *file, unsigned int *value_lenp); #endif char *allocated_variable_expand_for_file (const char *line, struct file *file); #ifndef CONFIG_WITH_VALUE_LENGTH #define allocated_variable_expand(line) \ allocated_variable_expand_for_file (line, (struct file *) 0) #else /* CONFIG_WITH_VALUE_LENGTH */ # define allocated_variable_expand(line) \ allocated_variable_expand_2 (line, -1, NULL) char *allocated_variable_expand_2 (const char *line, unsigned int length, unsigned int *value_lenp); char *allocated_variable_expand_3 (const char *line, unsigned int length, unsigned int *value_lenp, unsigned int *buffer_lengthp); void recycle_variable_buffer (char *buffer, unsigned int length); #endif /* CONFIG_WITH_VALUE_LENGTH */ char *expand_argument (const char *str, const char *end); #ifndef CONFIG_WITH_VALUE_LENGTH char * variable_expand_string (char *line, const char *string, long length); #else /* CONFIG_WITH_VALUE_LENGTH */ # include char * variable_expand_string_2 (char *line, const char *string, long length, char **eol); K_INLINE char *variable_expand_string (char *line, const char *string, long length) { char *ignored; return variable_expand_string_2 (line, string, length, &ignored); } #endif /* CONFIG_WITH_VALUE_LENGTH */ void install_variable_buffer (char **bufp, unsigned int *lenp); void restore_variable_buffer (char *buf, unsigned int len); char *install_variable_buffer_with_hint (char **bufp, unsigned int *lenp, unsigned int size_hint); /* bird */ char *ensure_variable_buffer_space (char *ptr, unsigned int size); /* bird */ #ifdef CONFIG_WITH_VALUE_LENGTH void append_expanded_string_to_variable (struct variable *v, const char *value, unsigned int value_len, int append); #endif /* function.c */ #ifndef CONFIG_WITH_VALUE_LENGTH int handle_function (char **op, const char **stringp); #else int handle_function (char **op, const char **stringp, const char *nameend, const char *eol); #endif #ifdef CONFIG_WITH_COMPILER typedef char *(*make_function_ptr_t) (char *, char **, const char *); make_function_ptr_t lookup_function_for_compiler (const char *name, unsigned int len, unsigned char *minargsp, unsigned char *maxargsp, char *expargsp, const char **funcnamep); #endif int pattern_matches (const char *pattern, const char *percent, const char *str); char *subst_expand (char *o, const char *text, const char *subst, const char *replace, unsigned int slen, unsigned int rlen, int by_word); char *patsubst_expand_pat (char *o, const char *text, const char *pattern, const char *replace, const char *pattern_percent, const char *replace_percent); char *patsubst_expand (char *o, const char *text, char *pattern, char *replace); char *func_shell_base (char *o, char **argv, int trim_newlines); void shell_completed (int exit_code, int exit_sig); #ifdef CONFIG_WITH_COMMANDS_FUNC /* for append.c */ char *func_commands (char *o, char **argv, const char *funcname); #endif #if defined (CONFIG_WITH_VALUE_LENGTH) /* Avoid calling handle_function for every variable, do the basic checks in variable_expand_string_2. */ extern char func_char_map[256]; # define MAX_FUNCTION_LENGTH 14 # define MIN_FUNCTION_LENGTH 2 K_INLINE const char *may_be_function_name (const char *name, const char *eos) { unsigned char ch; unsigned int len = name - eos; /* Minimum length is MIN + whitespace. Check this directly. ASSUMES: MIN_FUNCTION_LENGTH == 2 */ if (MY_PREDICT_TRUE(len < MIN_FUNCTION_LENGTH + 1 || !func_char_map[(int)(name[0])] || !func_char_map[(int)(name[1])])) return 0; if (MY_PREDICT_TRUE(!func_char_map[ch = name[2]])) return ISSPACE (ch) ? name + 2 : 0; name += 3; if (len > MAX_FUNCTION_LENGTH) len = MAX_FUNCTION_LENGTH - 3; else if (len == 3) len -= 3; if (!len) return 0; /* Loop over the remaining possiblities. */ while (func_char_map[ch = *name]) { if (!len--) return 0; name++; } if (ch == '\0' || ISBLANK (ch)) return name; return 0; } #endif /* CONFIG_WITH_VALUE_LENGTH */ /* expand.c */ #ifndef CONFIG_WITH_VALUE_LENGTH char *recursively_expand_for_file (struct variable *v, struct file *file); #define recursively_expand(v) recursively_expand_for_file (v, NULL) #else char *recursively_expand_for_file (struct variable *v, struct file *file, unsigned int *value_lenp); # define recursively_expand(v) recursively_expand_for_file (v, NULL, NULL) #endif /* CONFIG_WITH_VALUE_LENGTH */ #ifdef CONFIG_WITH_COMPILER char *reference_recursive_variable (char *o, struct variable *v); #endif /* variable.c */ struct variable_set_list *create_new_variable_set (void); void free_variable_set (struct variable_set_list *); struct variable_set_list *push_new_variable_scope (void); void pop_variable_scope (void); void define_automatic_variables (void); void initialize_file_variables (struct file *file, int reading); void print_file_variables (const struct file *file); void print_target_variables (const struct file *file); void merge_variable_set_lists (struct variable_set_list **to_list, struct variable_set_list *from_list); #ifdef KMK void print_variable_set (struct variable_set *set, const char *prefix, int pauto); #endif #ifndef CONFIG_WITH_VALUE_LENGTH struct variable *do_variable_definition (const floc *flocp, const char *name, const char *value, enum variable_origin origin, enum variable_flavor flavor, int target_var); #else /* CONFIG_WITH_VALUE_LENGTH */ # define do_variable_definition(flocp, varname, value, origin, flavor, target_var) \ do_variable_definition_2 ((flocp), (varname), (value), ~0U, 0, NULL, \ (origin), (flavor), (target_var)) struct variable *do_variable_definition_2 (const floc *flocp, const char *varname, const char *value, unsigned int value_len, int simple_value, char *free_value, enum variable_origin origin, enum variable_flavor flavor, int target_var); #endif /* CONFIG_WITH_VALUE_LENGTH */ char *parse_variable_definition (const char *line, struct variable *v); struct variable *assign_variable_definition (struct variable *v, const char *line IF_WITH_VALUE_LENGTH_PARAM(char *eos)); struct variable *try_variable_definition (const floc *flocp, const char *line IF_WITH_VALUE_LENGTH_PARAM(char *eos), enum variable_origin origin, int target_var); void init_hash_global_variable_set (void); void hash_init_function_table (void); void define_new_function(const floc *flocp, const char *name, unsigned int min, unsigned int max, unsigned int flags, gmk_func_ptr func); struct variable *lookup_variable (const char *name, unsigned int length); struct variable *lookup_variable_in_set (const char *name, unsigned int length, const struct variable_set *set); #ifdef CONFIG_WITH_STRCACHE2 struct variable *lookup_variable_strcached (const char *name); #endif #ifdef CONFIG_WITH_VALUE_LENGTH void append_string_to_variable (struct variable *v, const char *value, unsigned int value_len, int append); struct variable * do_variable_definition_append (const floc *flocp, struct variable *v, const char *value, unsigned int value_len, int simple_value, enum variable_origin origin, int append); struct variable *define_variable_in_set (const char *name, unsigned int length, const char *value, unsigned int value_length, int duplicate_value, enum variable_origin origin, int recursive, struct variable_set *set, const floc *flocp); /* Define a variable in the current variable set. */ #define define_variable(n,l,v,o,r) \ define_variable_in_set((n),(l),(v),~0U,1,(o),(r),\ current_variable_set_list->set,NILF) #define define_variable_vl(n,l,v,vl,dv,o,r) \ define_variable_in_set((n),(l),(v),(vl),(dv),(o),(r),\ current_variable_set_list->set,NILF) /* Define a variable with a constant name in the current variable set. */ #define define_variable_cname(n,v,o,r) \ define_variable_in_set((n),(sizeof (n) - 1),(v),~0U,1,(o),(r),\ current_variable_set_list->set,NILF) /* Define a variable with a location in the current variable set. */ #define define_variable_loc(n,l,v,o,r,f) \ define_variable_in_set((n),(l),(v),~0U,1,(o),(r),\ current_variable_set_list->set,(f)) /* Define a variable with a location in the global variable set. */ #define define_variable_global(n,l,v,o,r,f) \ define_variable_in_set((n),(l),(v),~0U,1,(o),(r),NULL,(f)) #define define_variable_vl_global(n,l,v,vl,dv,o,r,f) \ define_variable_in_set((n),(l),(v),(vl),(dv),(o),(r),NULL,(f)) /* Define a variable in FILE's variable set. */ #define define_variable_for_file(n,l,v,o,r,f) \ define_variable_in_set((n),(l),(v),~0U,1,(o),(r),(f)->variables->set,NILF) #else /* !CONFIG_WITH_VALUE_LENGTH */ struct variable *define_variable_in_set (const char *name, unsigned int length, const char *value, enum variable_origin origin, int recursive, struct variable_set *set, const floc *flocp); /* Define a variable in the current variable set. */ #define define_variable(n,l,v,o,r) \ define_variable_in_set((n),(l),(v),(o),(r),\ current_variable_set_list->set,NILF) /* force merge conflict */ /* Define a variable with a constant name in the current variable set. */ #define define_variable_cname(n,v,o,r) \ define_variable_in_set((n),(sizeof (n) - 1),(v),(o),(r),\ current_variable_set_list->set,NILF) /* force merge conflict */ /* Define a variable with a location in the current variable set. */ #define define_variable_loc(n,l,v,o,r,f) \ define_variable_in_set((n),(l),(v),(o),(r),\ current_variable_set_list->set,(f)) /* force merge conflict */ /* Define a variable with a location in the global variable set. */ #define define_variable_global(n,l,v,o,r,f) \ define_variable_in_set((n),(l),(v),(o),(r),NULL,(f)) /* force merge conflict */ /* Define a variable in FILE's variable set. */ #define define_variable_for_file(n,l,v,o,r,f) \ define_variable_in_set((n),(l),(v),(o),(r),(f)->variables->set,NILF) /* force merge conflict */ #endif /* !CONFIG_WITH_VALUE_LENGTH */ void undefine_variable_in_set (const char *name, unsigned int length, enum variable_origin origin, struct variable_set *set); /* Remove variable from the current variable set. */ #define undefine_variable_global(n,l,o) \ undefine_variable_in_set((n),(l),(o),NULL) #ifdef KMK struct variable * define_variable_alias_in_set (const char *name, unsigned int length, struct variable *target, enum variable_origin origin, struct variable_set *set, const floc *flocp); #endif /* Warn that NAME is an undefined variable. */ #define warn_undefined(n,l) do{\ if (warn_undefined_variables_flag) \ error (reading_file, (l), \ _("warning: undefined variable '%.*s'"), \ (int)(l), (n)); \ }while(0) char **target_environment (struct file *file); struct pattern_var *create_pattern_var (const char *target, const char *suffix); extern int export_all_variables; #ifdef CONFIG_WITH_STRCACHE2 extern struct strcache2 variable_strcache; #endif #ifdef KMK # define MAKELEVEL_NAME "KMK_LEVEL" #else #define MAKELEVEL_NAME "MAKELEVEL" #endif #define MAKELEVEL_LENGTH (CSTRLEN (MAKELEVEL_NAME))