Changeset 3319 for trunk/src/kmk/function.c
- Timestamp:
- Apr 14, 2020, 9:53:09 PM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/kmk/function.c
r3317 r3319 5799 5799 } 5800 5800 5801 /* Helper for performer GNU make style quoting of one filename. */ 5802 5803 static char *helper_quote_make (char *o, const char *name, int is_dep, int is_tgt, 5804 int quote_trailing_slashes, const char *funcname) 5805 { 5806 unsigned const map_flags = MAP_NUL 5807 | MAP_BLANK 5808 | MAP_NEWLINE 5809 | MAP_COMMENT 5810 | MAP_VARIABLE 5811 | MAP_SEMI 5812 | MAP_EQUALS 5813 | (is_dep ? MAP_PIPE : 5814 is_tgt ? MAP_COLON : 0); 5815 const char *cur = name; 5816 if (*cur) 5817 { 5818 unsigned long len_out = 0; 5819 const char *prev = cur; 5820 for (;;) 5821 { 5822 char ch = *cur; 5823 unsigned int flags = stopchar_map[(unsigned int)ch] & map_flags; 5824 if (!flags) 5825 cur++; /* likely */ 5826 else 5827 { 5828 /* Flush pending output. */ 5829 if (prev != cur) 5830 { 5831 o = variable_buffer_output (o, prev, cur - prev); 5832 len_out += cur - prev; 5833 } 5834 5835 if (flags & MAP_NUL) 5836 break; 5837 5838 /* Dollar is quoted by duplicating the dollar: */ 5839 if (flags & MAP_VARIABLE) 5840 { 5841 prev = cur++; 5842 o = variable_buffer_output (o, "$", 1); 5843 } 5844 /* The rest is quoted by '\': */ 5845 else 5846 { 5847 size_t const max_slashes = cur - prev; 5848 size_t slashes = 0; 5849 while (slashes < max_slashes && cur[1 - slashes] == '\\') 5850 slashes++; 5851 if (slashes) 5852 { 5853 o = variable_buffer_output (o, &cur[0 - slashes], slashes); 5854 len_out += slashes; 5855 } 5856 o = variable_buffer_output (o, "\\", 1); 5857 prev = cur++; 5858 } 5859 } 5860 } 5861 5862 /* Escape trailing slashes when needed. */ 5863 if ( o[-1] == '\\' 5864 && quote_trailing_slashes) 5865 { 5866 size_t slashes = 1; 5867 while (slashes < len_out && o[-1 - slashes] == '\\') 5868 slashes++; 5869 while (slashes-- > 0) 5870 o = variable_buffer_output (o, "\\", 1); 5871 } 5872 } 5873 else 5874 OS (message, 0, "%s: cannot quote empty string", funcname); 5875 return o; 5876 } 5877 5878 /* Helper for func_quote_make that checks if there are more arguments 5879 that produces output or not. */ 5880 5881 static int func_quote_make_has_more_non_empty_args (char **argv) 5882 { 5883 for (;;) 5884 { 5885 char *arg = *argv; 5886 if (!arg) 5887 return 0; 5888 if (*arg) 5889 return 1; 5890 argv++; 5891 } 5892 } 5893 5894 /* Takes zero or more plain strings and escapes (quotes) spaces and other 5895 problematic characters, GNU make style. 5896 5897 There is one slightly problematic aspect of using this, if the input ends 5898 with backslashes whether or not they will be reduced or taken as-is depends 5899 on whether they appear at the end of a line or not. They are taken as-is 5900 when at the end of a line, otherwise they'll be subject to unescaping 5901 (unquoting) and reduced by half. 5902 5903 In addition, the quoting style differs for files on the left side and 5904 right side of the recipe colon. Colons aren't escaped are only escaped 5905 on the left side (target), and the pipe character is only escaped on the 5906 right side (deps). 5907 5908 For this reason there are four variants of this function. */ 5909 5910 static char *func_quote_make (char *o, char **argv, const char *funcname) 5911 { 5912 int const is_dep = funcname[5] == '-' && funcname[6] == 'd'; 5913 int const is_tgt = funcname[5] == '-' && funcname[6] == 't'; 5914 int const quote_trailing_slashes = funcname[5] == '\0' || funcname[9] == '\0'; 5915 unsigned const map_flags = MAP_NUL 5916 | MAP_BLANK 5917 | MAP_NEWLINE 5918 | MAP_COMMENT 5919 | MAP_VARIABLE 5920 | MAP_SEMI 5921 | MAP_EQUALS 5922 | (is_dep ? MAP_PIPE : 5923 is_tgt ? MAP_COLON : 0); 5924 char * const o_initial = o; 5925 int i; 5926 5927 assert ( quote_trailing_slashes 5928 == (!strcmp (funcname, "quote") || !strcmp (funcname, "quote-dep") || !strcmp (funcname, "quote-tgt"))); 5929 assert (is_dep == !strncmp (funcname, "quote-dep", sizeof ("quote-dep") - 1)); 5930 assert (is_tgt == !strncmp (funcname, "quote-tgt", sizeof ("quote-tgt") - 1)); 5931 5932 for (i = 0; argv[i]; i++) 5933 { 5934 char *arg = argv[i]; 5935 if (*arg) 5936 { 5937 /* Add space separator. */ 5938 if (o != o_initial) 5939 o = variable_buffer_output (o, " ", 1); 5940 5941 /* Output the quoted argument: */ 5942 if (quote_trailing_slashes) 5943 o = helper_quote_make (o, arg, is_dep, is_tgt, 5944 quote_trailing_slashes, funcname); 5945 else 5946 { 5947 char *end = strchr (arg, '\0'); 5948 int qts = end != arg && end[-1] == '\\' 5949 && func_quote_make_has_more_non_empty_args (&argv[i + 1]); 5950 o = helper_quote_make (o, arg, is_dep, is_tgt, qts, funcname); 5951 } 5952 } 5953 else 5954 OS (message, 0, "%s: cannot munge empty string", funcname); 5955 } 5956 5957 return o; 5958 } 5959 5960 /* Worker for func_quote_shell() for escaping a string that's inside 5961 double quotes. */ 5962 5963 static char *func_escape_shell_in_dq (char *o, const char *arg, size_t len) 5964 { 5965 const char *prev = arg; 5966 while (len-- > 0) 5967 { 5968 char const ch = *arg; 5969 switch (ch) 5970 { 5971 default: 5972 arg++; 5973 break; 5974 case '!': 5975 case '$': 5976 case '`': 5977 case '"': 5978 case '\\': 5979 case '\n': 5980 if (prev != arg) 5981 o = variable_buffer_output (o, prev, arg - prev); 5982 o = variable_buffer_output (o, "\\", 1); 5983 prev = arg; 5984 arg++; 5985 break; 5986 } 5987 } 5988 if (prev != arg) 5989 o = variable_buffer_output (o, prev, arg - prev); 5990 return o; 5991 } 5992 5993 /* quote-sh-dq */ 5994 5995 static char *func_quote_shell_dq (char *o, char **argv, const char *funcname UNUSED) 5996 { 5997 return func_escape_shell_in_dq (o, argv[0], strlen (argv[0])); 5998 } 5999 6000 6001 /* Worker for func_quote_shell() for escaping a string that's inside 6002 single quotes. */ 6003 6004 static char *func_escape_shell_in_sq (char *o, const char *arg, size_t len) 6005 { 6006 while (len > 0) 6007 { 6008 char *sq = memchr (arg, '\'', len); 6009 if (!sq) 6010 return variable_buffer_output (o, arg, len); 6011 if (sq != arg) 6012 o = variable_buffer_output (o, arg, sq - arg); 6013 o = variable_buffer_output (o, "'\\''", 4); 6014 6015 /* advance */ 6016 sq++; 6017 len -= sq - arg; 6018 arg = sq; 6019 } 6020 return o; 6021 } 6022 6023 /* quote-sh-dq */ 6024 6025 static char *func_quote_shell_sq (char *o, char **argv, const char *funcname UNUSED) 6026 { 6027 return func_escape_shell_in_sq (o, argv[0], strlen (argv[0])); 6028 } 6029 6030 /* Output a shell argument with quoting as needed. */ 6031 static char *helper_quote_shell (char *o, const char *arg, size_t len, 6032 int leading_space) 6033 { 6034 if ( memchr (arg, '$', len) != NULL 6035 || memchr (arg, '*', len) != NULL 6036 || memchr (arg, '?', len) != NULL 6037 || memchr (arg, '[', len) != NULL) 6038 { 6039 if (leading_space) 6040 o = variable_buffer_output (o, " '", 2); 6041 else 6042 o = variable_buffer_output (o, "'", 1); 6043 o = func_escape_shell_in_sq (o, arg, len); 6044 o = variable_buffer_output (o, "'", 1); 6045 } 6046 else if ( memchr (arg, ' ', len) != NULL 6047 || memchr (arg, '\t', len) != NULL 6048 || memchr (arg, '\\', len) != NULL 6049 || memchr (arg, '"', len) != NULL 6050 || memchr (arg, '`', len) != NULL 6051 || memchr (arg, '!', len) != NULL 6052 || memchr (arg, '|', len) != NULL 6053 || memchr (arg, '<', len) != NULL 6054 || memchr (arg, '>', len) != NULL 6055 || memchr (arg, '&', len) != NULL 6056 || memchr (arg, ';', len) != NULL 6057 || memchr (arg, '(', len) != NULL 6058 || memchr (arg, ')', len) != NULL 6059 || memchr (arg, '\n', len) != NULL) 6060 { 6061 if (leading_space) 6062 o = variable_buffer_output (o, " \"", 2); 6063 else 6064 o = variable_buffer_output (o, "\"", 1); 6065 o = func_escape_shell_in_dq (o, arg, len); 6066 o = variable_buffer_output (o, "\"", 1); 6067 } 6068 else 6069 { 6070 if (leading_space) 6071 o = variable_buffer_output (o, " ", 1); 6072 o = variable_buffer_output (o, arg, len); 6073 } 6074 return o; 6075 } 6076 6077 /* Takes zero or more plain strings and escapes/quotes spaces and other 6078 problematic characters, bourne make style. 6079 6080 The quote-sh-dq and quote-sh-sq variants is for escaping strings that 6081 going to be put into double quotes and single quotes respectively. 6082 6083 The normal quote-sh variant assumes it's free to do open and close 6084 quotes as it pleases. */ 6085 6086 static char *func_quote_shell (char *o, char **argv, const char *funcname UNUSED) 6087 { 6088 int i; 6089 for (i = 0; argv[i]; i++) 6090 o = helper_quote_shell (o, argv[i], strlen (argv[i]), 6091 i > 0 /*need_leading_space*/); 6092 return o; 6093 } 6094 6095 /* Unlinks CUR from *CHAINP and frees it, returning the next element. */ 6096 6097 static struct nameseq * 6098 helper_unlink_and_free_ns (struct nameseq *cur, struct nameseq *prev, 6099 struct nameseq **chainp) 6100 { 6101 struct nameseq *freeit = cur; \ 6102 free ((char *)cur->name); 6103 if (prev) 6104 prev->next = cur = cur->next; 6105 else 6106 *chainp = cur = cur->next; 6107 free_ns (freeit); 6108 return cur; 6109 } 6110 6111 /* Frees a chain returned by helper_parse_file_list. */ 6112 6113 static void free_ns_chain_no_strcache (struct nameseq *ns) 6114 { 6115 while (ns != 0) 6116 { 6117 struct nameseq *t = ns; 6118 free ((char *)ns->name); 6119 ns = ns->next; 6120 free_ns (t); 6121 } 6122 } 6123 6124 6125 #define Q_RET_MASK 0x000f 6126 #define Q_RET_UNQUOTED 0x0000 6127 #define Q_RET_QUOTED 0x0001 6128 #define Q_RET_QUOTED_DEP 0x0002 6129 #define Q_RET_QUOTED_DEP_END 0x0003 6130 #define Q_RET_QUOTED_TGT 0x0004 6131 #define Q_RET_QUOTED_TGT_END 0x0005 6132 #define Q_RET_SHELL 0x0006 6133 #define Q_RET_SHELL_IN_DQ 0x0007 6134 #define Q_RET_SHELL_IN_SQ 0x0008 6135 6136 #define Q_IN_MASK 0x0030 6137 #define Q_IN_QUOTED 0x0000 6138 #define Q_IN_UNQUOTED 0x0010 6139 #define Q_IN_QUOTED_DEP 0x0020 /** @todo needed? */ 6140 #define Q_IN_QUOTED_TGT 0x0030 /** @todo needed? */ 6141 #define Q_IN_SEP_COMMA 0x0040 /* for VMS hacks, file lists only */ 6142 6143 #define Q_SEP_MASK 0x0700 6144 #define Q_SEP_SHIFT 8 6145 #define Q_SEP_SPACE 0x0000 6146 #define Q_SEP_TAB 0x0100 6147 #define Q_SEP_NL 0x0200 6148 #define Q_SEP_NL_TAB 0x0300 6149 #define Q_SEP_COMMA 0x0400 /* for VMS, output only */ 6150 6151 #define Q_QDEFAULT 0x0000 6152 #ifndef VMS 6153 # define Q_QDEFAULT_VMS_TRICKS Q_QDEFAULT 6154 #else /* VMS: Treat ',' as file separators in input, maybe output too. */ 6155 # define Q_QDEFAULT_VMS_TRICKS (Q_IN_SEP_COMMA | \ 6156 (!vms_comma_separator ? Q_QDEFAULT \ 6157 : (Q_QDEFAULT & ~Q_SEP_MASK) | Q_SEP_COMMA) 6158 #endif 6159 6160 6161 /* Decodes the optional style argument. This is chiefly for the return 6162 style, but can also pick the input and space styles (just because we can). */ 6163 6164 static unsigned int helper_file_return_style (char *style, unsigned int intstyle) 6165 { 6166 if (style != NULL) 6167 { 6168 for (;;) 6169 { 6170 /* Skip blanks: */ 6171 while (ISBLANK(*style)) 6172 style++; 6173 if (*style != '\0') 6174 { 6175 /* Find the end of the current word: */ 6176 char * const start = style; 6177 size_t len; 6178 char ch; 6179 while (!ISBLANK((ch = *style)) && ch != '\0') 6180 style++; 6181 len = style - start; 6182 6183 /* String "switch" to decode the word: */ 6184 6185 #define MATCH(a_str) (len == sizeof (a_str) - 1 && memcmp (start, a_str, sizeof (a_str)) == 0) 6186 /* return styles: */ 6187 if (MATCH ("quoted") || MATCH ("q")) 6188 intstyle = (intstyle & ~Q_RET_MASK) | Q_RET_QUOTED; 6189 else if (MATCH ("unquoted") || MATCH ("unq") || MATCH ("u")) 6190 intstyle = (intstyle & ~Q_RET_MASK) | Q_RET_UNQUOTED; 6191 else if (MATCH ("quoted-dep") || MATCH ("q-dep") || MATCH ("q-d")) 6192 intstyle = (intstyle & ~Q_RET_MASK) | Q_RET_QUOTED_DEP; 6193 else if (MATCH ("quoted-dep-end") || MATCH ("q-dep-end") || MATCH ("q-d-e")) 6194 intstyle = (intstyle & ~Q_RET_MASK) | Q_RET_QUOTED_DEP_END; 6195 else if (MATCH ("quoted-tgt") || MATCH ("q-tgt") || MATCH ("q-t")) 6196 intstyle = (intstyle & ~Q_RET_MASK) | Q_RET_QUOTED_TGT; 6197 else if (MATCH ("quoted-tgt-end") || MATCH ("q-tgt-end") || MATCH ("q-t-e")) 6198 intstyle = (intstyle & ~Q_RET_MASK) | Q_RET_QUOTED_TGT_END; 6199 else if (MATCH ("shell") || MATCH ("sh")) 6200 intstyle = (intstyle & ~Q_RET_MASK) | Q_RET_SHELL; 6201 else if (MATCH ("shell-in-dq") || MATCH ("sh-i-d")) 6202 intstyle = (intstyle & ~Q_RET_MASK) | Q_RET_SHELL_IN_DQ; 6203 else if (MATCH ("shell-in-sq") || MATCH ("sh-i-s")) 6204 intstyle = (intstyle & ~Q_RET_MASK) | Q_RET_SHELL_IN_SQ; 6205 /* input styles: */ 6206 else if (MATCH ("in-quoted") || MATCH ("i-q")) 6207 intstyle = (intstyle & ~Q_IN_MASK) | Q_IN_QUOTED; 6208 else if (MATCH ("in-unquoted") || MATCH ("i-unq") || MATCH ("i-u")) 6209 intstyle = (intstyle & ~Q_IN_MASK) | Q_IN_UNQUOTED; 6210 else if (MATCH ("in-quoted-dep") || MATCH ("i-q-dep") || MATCH ("i-q-d")) 6211 intstyle = (intstyle & ~Q_IN_MASK) | Q_IN_QUOTED_DEP; 6212 else if (MATCH ("in-quoted-tgt") || MATCH ("i-q-tgt") || MATCH ("i-q-t")) 6213 intstyle = (intstyle & ~Q_IN_MASK) | Q_IN_QUOTED_TGT; 6214 else if (MATCH ("in-sep-comma") || MATCH ("i-s-com") || MATCH ("i-s-c")) 6215 intstyle = (intstyle & ~Q_SEP_MASK) | Q_IN_SEP_COMMA; 6216 /* separator styles (output): */ 6217 else if (MATCH ("sep-space") || MATCH ("s-space") || MATCH ("s-s")) 6218 intstyle = (intstyle & ~Q_SEP_MASK) | Q_SEP_SPACE; 6219 else if (MATCH ("sep-tab") || MATCH ("s-tab") || MATCH ("s-t")) 6220 intstyle = (intstyle & ~Q_SEP_MASK) | Q_SEP_TAB; 6221 else if (MATCH ("sep-nl") || MATCH ("s-nl") || MATCH ("s-n")) 6222 intstyle = (intstyle & ~Q_SEP_MASK) | Q_SEP_NL; 6223 else if (MATCH ("sep-nl-tab") || MATCH ("s-nl-tab") || MATCH ("s-n-t")) 6224 intstyle = (intstyle & ~Q_SEP_MASK) | Q_SEP_NL_TAB; 6225 else if (MATCH ("sep-comma") || MATCH ("s-comma") || MATCH ("s-c")) 6226 intstyle = (intstyle & ~Q_SEP_MASK) | Q_SEP_COMMA; 6227 else 6228 { 6229 char savedch = *style; 6230 *style = '\0'; 6231 OS (error, reading_file, "Unknown file return style: %s", start); 6232 *style = savedch; 6233 } 6234 #undef MATCH 6235 } 6236 else 6237 break; 6238 } 6239 } 6240 return intstyle; 6241 } 6242 6243 /* Output (returns) a separator according to STYLE. */ 6244 6245 static char *helper_return_sep (char *o, unsigned int style) 6246 { 6247 /* Note! Must match Q_SEP_MASK! */ 6248 static struct 6249 { 6250 const char *sep; 6251 size_t len; 6252 } const seps[8] = 6253 { 6254 { " ", 1 }, 6255 { "\t", 1 }, 6256 { "\n", 1 }, 6257 { "\n\t", 2 }, 6258 { ",", 1 }, 6259 { " ", 1 }, 6260 { " ", 1 }, 6261 { " ", 1 } 6262 }; 6263 6264 return variable_buffer_output(o, 6265 seps[(style & Q_SEP_MASK) >> Q_SEP_SHIFT].sep, 6266 seps[(style & Q_SEP_MASK) >> Q_SEP_SHIFT].len); 6267 } 6268 6269 /* Outputs (returns) the given file. */ 6270 6271 static char *helper_return_file_len (char *o, const char *file, size_t len, 6272 unsigned int style, int is_last) 6273 { 6274 assert (file[len] == '\0'); 6275 switch (style & Q_RET_MASK) 6276 { 6277 case Q_RET_UNQUOTED: 6278 o = variable_buffer_output (o, file, len); 6279 break; 6280 case Q_RET_QUOTED: 6281 o = helper_quote_make (o, file, 0 /*is_dep*/, 0 /*is_tgt*/, 6282 !is_last /*quote_trailing_slashes*/, NULL); 6283 break; 6284 case Q_RET_QUOTED_DEP: 6285 o = helper_quote_make (o, file, 1 /*is_dep*/, 0 /*is_tgt*/, 6286 !is_last /*quote_trailing_slashes*/, NULL); 6287 break; 6288 case Q_RET_QUOTED_DEP_END: 6289 o = helper_quote_make (o, file, 1 /*is_dep*/, 0 /*is_tgt*/, 6290 0 /*quote_trailing_slashes*/, NULL); 6291 break; 6292 case Q_RET_QUOTED_TGT: 6293 o = helper_quote_make (o, file, 0 /*is_dep*/, 1 /*is_tgt*/, 6294 !is_last /*quote_trailing_slashes*/, NULL); 6295 break; 6296 case Q_RET_QUOTED_TGT_END: 6297 o = helper_quote_make (o, file, 0 /*is_dep*/, 1 /*is_tgt*/, 6298 0 /*quote_trailing_slashes*/, NULL); 6299 break; 6300 case Q_RET_SHELL: 6301 o = helper_quote_shell (o, file, len, 0 /*need_leading_space*/); 6302 break; 6303 case Q_RET_SHELL_IN_DQ: 6304 o = func_escape_shell_in_dq (o, file, len); 6305 break; 6306 case Q_RET_SHELL_IN_SQ: 6307 o = func_escape_shell_in_sq (o, file, len); 6308 break; 6309 default: 6310 assert (0); 6311 } 6312 6313 /* Add separator space if not last. */ 6314 if (!is_last) 6315 o = helper_return_sep (o, style); 6316 return o; 6317 } 6318 6319 /* Outputs (returns) the given file. */ 6320 6321 static char *helper_return_file (char *o, const char *file, unsigned int style, int is_last) 6322 { 6323 return helper_return_file_len (o,file, strlen (file), style, is_last); 6324 } 6325 6326 /* Outputs (returns) the given CHAIN and frees it. */ 6327 6328 static char *helper_return_and_free_chain (char *o, struct nameseq *chain, unsigned int style) 6329 { 6330 struct nameseq *cur; 6331 for (cur = chain; cur; cur = cur->next) 6332 o = helper_return_file (o, cur->name, style, cur->next == NULL); 6333 free_ns_chain_no_strcache (chain); 6334 return o; 6335 } 6336 6337 6338 /* Helper for helper_parse_file_list that globs a name sequence. */ 6339 static struct nameseq * 6340 helper_glob_chain (struct nameseq *chain) 6341 { 6342 struct nameseq *prev = NULL; 6343 struct nameseq *cur = chain; 6344 glob_t gl; 6345 dir_setup_glob (&gl); 6346 6347 /** @todo XXX: !NO_ARCHIVES */ 6348 while (cur) 6349 { 6350 switch (glob (cur->name, GLOB_NOSORT | GLOB_ALTDIRFUNC, NULL, &gl)) 6351 { 6352 case 0: /* Replace CUR with the names found. */ 6353 { 6354 struct nameseq *subchain = NULL; 6355 struct nameseq **ppnext = &subchain; 6356 const char ** const names = (const char **)gl.gl_pathv; 6357 size_t const num_names = gl.gl_pathc; 6358 size_t idx; 6359 6360 cur = helper_unlink_and_free_ns (cur, prev, &chain); 6361 6362 for (idx = 0; idx < num_names; idx++) 6363 { 6364 #ifndef CONFIG_WITH_ALLOC_CACHES 6365 struct nameseq *newp = xcalloc (sizeof (*newp)); 6366 #else 6367 struct nameseq *newp = alloccache_calloc (&nameseq_cache); 6368 #endif 6369 newp->name = xstrdup (names[idx]); 6370 newp->next = NULL; 6371 *ppnext = newp; 6372 ppnext = &newp->next; 6373 } 6374 6375 if (subchain) /* parnaoia */ 6376 { 6377 *ppnext = cur; 6378 if (prev) 6379 prev->next = subchain; 6380 else 6381 chain = subchain; 6382 } 6383 break; 6384 } 6385 6386 case GLOB_NOMATCH: /* doesn't exist, remove */ 6387 cur = helper_unlink_and_free_ns (cur, prev, &chain); 6388 break; 6389 6390 default: /* Keep it. */ 6391 prev = cur; 6392 cur = cur->next; 6393 break; 6394 6395 case GLOB_NOSPACE: 6396 OUT_OF_MEM(); 6397 } 6398 globfree (&gl); 6399 } 6400 return chain; 6401 } 6402 6403 /* Parses a file/word list according to STYLE and returns a name list. */ 6404 6405 static struct nameseq * 6406 helper_parse_file_list (char *filelist, unsigned int style, int glob) 6407 { 6408 if (filelist && *filelist != '\0') 6409 switch (style & (Q_IN_MASK | Q_IN_SEP_COMMA)) 6410 { 6411 case Q_IN_QUOTED: 6412 case Q_IN_QUOTED_DEP: /** @todo ?? */ 6413 case Q_IN_QUOTED_TGT: /** @todo ?? */ 6414 return PARSE_FILE_SEQ(&filelist, struct nameseq, MAP_NUL, NULL, 6415 !glob 6416 ? PARSEFS_NOGLOB | PARSEFS_NOSTRIP | PARSEFS_NOCACHE 6417 : PARSEFS_NOSTRIP | PARSEFS_NOCACHE | PARSEFS_EXISTS); 6418 6419 case Q_IN_UNQUOTED: 6420 { 6421 struct nameseq *chain = NULL; 6422 struct nameseq **ppnext = &chain; 6423 const char *it = filelist; 6424 const char *cur; 6425 unsigned int curlen; 6426 while ((cur = find_next_token (&it, &curlen)) != NULL) 6427 { 6428 #ifndef CONFIG_WITH_ALLOC_CACHES 6429 struct nameseq *newp = xcalloc (sizeof (*newp)); 6430 #else 6431 struct nameseq *newp = alloccache_calloc (&nameseq_cache); 6432 #endif 6433 newp->name = xstrndup (cur, curlen); 6434 newp->next = NULL; 6435 *ppnext = newp; 6436 ppnext = &newp->next; 6437 } 6438 if (!glob) 6439 return chain; 6440 return helper_glob_chain (chain); 6441 } 6442 6443 /* Following works recursively. Mainly for VMS. */ 6444 case Q_IN_SEP_COMMA | Q_IN_UNQUOTED: 6445 case Q_IN_SEP_COMMA | Q_IN_QUOTED: 6446 case Q_IN_SEP_COMMA | Q_IN_QUOTED_DEP: /** @todo ?? */ 6447 case Q_IN_SEP_COMMA | Q_IN_QUOTED_TGT: /** @todo ?? */ 6448 { 6449 size_t len = strlen (filelist); 6450 char *comma = (char *)memchr (filelist, ',', len); 6451 struct nameseq *chain; 6452 if (!comma) 6453 chain = helper_parse_file_list (filelist, style & ~Q_IN_SEP_COMMA, 0); 6454 else 6455 { 6456 char *copy; 6457 char *start; 6458 start = copy = xmalloc (len + 1); 6459 memcpy (copy, filelist, len + 1); 6460 comma = copy + (comma - filelist); 6461 do 6462 { 6463 *comma = ' '; 6464 len -= comma - start - 1; 6465 if (len) 6466 { 6467 start = comma + 1; 6468 comma = (char *)memchr (start, ',', len); 6469 } 6470 else 6471 break; 6472 } 6473 while (comma != NULL); 6474 6475 chain = helper_parse_file_list (filelist, style & ~Q_IN_SEP_COMMA, 0); 6476 6477 free (copy); 6478 } 6479 return chain; 6480 } 6481 6482 default: 6483 assert (0); 6484 return NULL; 6485 } 6486 return NULL; 6487 } 6488 6489 /* $(firstfile file1 file2 ... fileN) - same as $(firstfile ), except for files 6490 rather than word tokens. See func_firstword(). */ 6491 6492 static char *func_firstfile (char *o, char **argv, const char *funcname UNUSED) 6493 { 6494 unsigned int const style = helper_file_return_style (argv[1], Q_QDEFAULT); 6495 char *line = argv[0]; 6496 if (line && *line != '\0') 6497 { 6498 struct nameseq *chain = helper_parse_file_list (line, style, 0); 6499 if (chain) 6500 { 6501 o = helper_return_file (o, chain->name, style, 1); 6502 free_ns_chain_no_strcache (chain); 6503 } 6504 } 6505 return o; 6506 } 6507 6508 /* $(lastfile file1 file2 ... fileN) - same as $(lastfile ), except for files 6509 rather than word tokens. See func_lastword(). */ 6510 6511 static char *func_lastfile (char *o, char **argv, const char *funcname UNUSED) 6512 { 6513 unsigned int const style = helper_file_return_style (argv[1], Q_QDEFAULT); 6514 char *line = argv[0]; 6515 if (line && *line != '\0') 6516 { 6517 struct nameseq *chain = helper_parse_file_list (line, style, 0); 6518 if (chain) 6519 { 6520 struct nameseq *last = chain; 6521 while (last->next) 6522 last = last->next; 6523 o = helper_return_file (o, last->name, style, 1); 6524 free_ns_chain_no_strcache (chain); 6525 } 6526 } 6527 return o; 6528 } 6529 6530 /* $(filelist start, end, file1..fileN [, style]) - same as $(wordlist), 6531 except for files rather than word tokens. See func_wordlist(). */ 6532 6533 static char *func_filelist (char *o, char **argv, const char *funcname UNUSED) 6534 { 6535 unsigned int const style = helper_file_return_style (argv[3], Q_QDEFAULT); 6536 int start; 6537 int count; 6538 6539 /* Check the arguments. */ 6540 check_numeric (argv[0], 6541 _("non-numeric first argument to 'filelist' function")); 6542 check_numeric (argv[1], 6543 _("non-numeric second argument to 'filelist' function")); 6544 6545 start = atoi (argv[0]); 6546 if (start < 1) 6547 ON (fatal, *expanding_var, 6548 "invalid first argument to 'filelist' function: '%d'", start); 6549 start--; /* make zero based */ 6550 6551 count = atoi (argv[1]) - start; 6552 6553 if (count > 0) 6554 { 6555 char *line = argv[2]; 6556 struct nameseq *cur; 6557 struct nameseq *chain; 6558 chain = helper_parse_file_list (line, style, 0); 6559 6560 /* Find the beginning of the "start"th word (1-based). */ 6561 for (cur = chain; cur && start > 1; cur = cur->next) 6562 start--; 6563 6564 /* Output the requested count */ 6565 while (cur && count-- > 0) 6566 o = helper_return_file (o, cur->name, style, count > 0 && cur->next); 6567 6568 free_ns_chain_no_strcache (chain); 6569 } 6570 6571 return o; 6572 } 6573 6574 /* $(countfiles file1 file2 ... fileN[,style]) - same as $(words ), except for 6575 files rather than word tokens. See func_words(). */ 6576 6577 static char *func_countfiles (char *o, char **argv, const char *funcname UNUSED) 6578 { 6579 unsigned int const style = helper_file_return_style (argv[1], Q_QDEFAULT); /* simpler */ 6580 char retval[32]; 6581 unsigned int files = 0; 6582 char *line = argv[0]; 6583 if (line && *line != '\0') 6584 { 6585 struct nameseq *cur; 6586 struct nameseq *chain = helper_parse_file_list (line, style, 0); 6587 for (cur = chain; cur; cur = cur->next) 6588 files++; 6589 free_ns_chain_no_strcache (chain); 6590 } 6591 6592 return variable_buffer_output (o, retval, sprintf (retval, "%u", files)); 6593 } 6594 6595 /* Helper that sets the variable value. */ 6596 6597 static void 6598 helper_set_var_value (struct variable *var, const char *value, size_t len) 6599 { 6600 #ifndef CONFIG_WITH_VALUE_LENGTH 6601 free (var->value); 6602 var->value = xstrndup (value, len); 6603 #else 6604 if (len >= var->value_alloc_len) 6605 { 6606 # ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE 6607 if (var->rdonly_val) 6608 var->rdonly_val = 0; 6609 else 6610 # endif 6611 free (var->value); 6612 var->value_alloc_len = VAR_ALIGN_VALUE_ALLOC (len + 1); 6613 var->value = xmalloc (var->value_alloc_len); 6614 } 6615 memcpy (var->value, value, len); 6616 var->value[len] = '\0'; 6617 var->value_length = len; 6618 VARIABLE_CHANGED (var); 6619 #endif 6620 } 6621 6622 /* $(foreachfile var, filelist, body [, style]) - same as $(foreach ), except 6623 for file rather than word tokens and flexible variable value encoding. 6624 See also func_foreach(). */ 6625 6626 static char * 6627 func_foreachfile (char *o, char **argv, const char *funcname UNUSED) 6628 { 6629 /* expand only the first two. */ 6630 char *varname = expand_argument (argv[0], NULL); 6631 char *list = expand_argument (argv[1], NULL); 6632 const char *body = argv[2]; 6633 #ifdef CONFIG_WITH_VALUE_LENGTH 6634 long body_len = strlen (body); 6635 #endif 6636 6637 unsigned int const style = helper_file_return_style (argv[3], Q_QDEFAULT); 6638 struct nameseq *chain = helper_parse_file_list (list, style, 0); 6639 struct nameseq *cur; 6640 6641 /* Clean up the variable name by removing whitespace. */ 6642 struct variable *var; 6643 char *vp = next_token (varname); 6644 char *vp_end = end_of_token (vp); 6645 vp_end[0] = '\0'; 6646 6647 push_new_variable_scope (); 6648 var = define_variable (vp, vp_end - vp, "", o_automatic, 0); 6649 6650 /* Don't need the list any more. */ 6651 free (list); 6652 list = NULL; 6653 6654 /* Loop through the chain. */ 6655 for (cur = chain; cur; cur = cur->next) 6656 { 6657 /* Update the variable value: */ 6658 unsigned int const len = strlen (cur->name); 6659 switch (style & Q_RET_MASK) 6660 { 6661 case Q_RET_UNQUOTED: 6662 helper_set_var_value (var, cur->name, len); 6663 break; 6664 default: 6665 { /* Use the output buffer as temporary storage. */ 6666 size_t const saved_off = o - variable_buffer; 6667 size_t quoted_len; 6668 char *quoted; 6669 o = helper_return_file_len (o, cur->name, len, style, 1 /*is_last*/); 6670 quoted = &variable_buffer[saved_off]; 6671 quoted_len = o - quoted; 6672 helper_set_var_value (var, quoted, quoted_len); 6673 o = quoted; 6674 break; 6675 } 6676 } 6677 6678 /* Expand the body: */ 6679 #ifndef CONFIG_WITH_VALUE_LENGTH 6680 { 6681 char *result = allocated_variable_expand (body); 6682 o = variable_buffer_output (o, result, strlen (result)); 6683 free (result); 6684 } 6685 #else 6686 variable_expand_string_2 (o, body, body_len, &o); 6687 #endif 6688 6689 /* Add separator: */ 6690 if (cur->next) 6691 o = helper_return_sep (o, style); 6692 } 6693 6694 pop_variable_scope (); 6695 free (varname); 6696 6697 return o; 6698 } 6699 6700 /* $(sortfiles file1 ... fileN [,style]) and 6701 $(rsortfiles file1 ... fileN [,style]) - same to $(sort ) and $(rsort ), 6702 except for files rather than word tokens. See func_sort(). */ 6703 6704 static char *func_sortfiles (char *o, char **argv, const char *funcname UNUSED) 6705 { 6706 unsigned int const style = helper_file_return_style (argv[1], Q_QDEFAULT); 6707 char *line = argv[0]; 6708 if (line && *line != '\0') 6709 { 6710 unsigned int num_files = 0; 6711 struct nameseq *cur; 6712 struct nameseq *chain = helper_parse_file_list (line, style, 0); 6713 for (cur = chain; cur; cur = cur->next) 6714 num_files++; 6715 if (num_files > 0) 6716 { 6717 char *prev_file; 6718 char **files = (char **)xmalloc (num_files * sizeof (char *)); 6719 unsigned int idx = 0; 6720 for (cur = chain; cur; cur = cur->next) 6721 files[idx++] = (char *)cur->name; 6722 6723 qsort (files, num_files, sizeof (char *), alpha_compare); 6724 6725 prev_file = NULL; 6726 if (funcname[0] == 'r') 6727 { 6728 idx = num_files; 6729 while (idx-- > 0) 6730 if (prev_file == NULL || strcmp (files[idx], prev_file) != 0) 6731 { 6732 prev_file = files[idx]; 6733 o = helper_return_file (o, files[idx], style, idx == 0); 6734 } 6735 } 6736 else 6737 for (idx = 0; idx < num_files; idx++) 6738 if (prev_file == NULL || strcmp (files[idx], prev_file) != 0) 6739 { 6740 prev_file = files[idx]; 6741 o = helper_return_file(o, files[idx], style, 6742 idx + 1 == num_files); 6743 } 6744 6745 free (files); 6746 } 6747 free_ns_chain_no_strcache (chain); 6748 } 6749 6750 return o; 6751 } 6752 6753 /* Helper for determining whether the given path is absolute or not. */ 6754 6755 static int helper_is_abs (const char *path) 6756 { 6757 #ifdef HAVE_DOS_PATHS 6758 return path[0] == '/' 6759 || path[0] == '\\' 6760 || (isalpha(path[0]) && path[1] == ':'); 6761 #else 6762 (void)len; 6763 return path[0] == '/'; 6764 #endif 6765 } 6766 6767 /* Worker for func_q_abspath and func_q_abspath_ex. */ 6768 6769 static char *worker_abspath (char *o, char *line, const char *cwd, 6770 size_t cwd_len, unsigned int style) 6771 { 6772 if (line && *line != '\0') 6773 { 6774 PATH_VAR (outbuf); 6775 int doneany = 0; 6776 struct nameseq *chain = helper_parse_file_list (line, style, 0); 6777 6778 /* Special case: single path, no cwd - no is_last path trouble */ 6779 if (chain && !chain->next && !cwd) 6780 { 6781 if (abspath (chain->name, outbuf)) 6782 o = helper_return_file(o, outbuf, style, 1); 6783 free_ns_chain_no_strcache (chain); 6784 } 6785 else if (chain) 6786 { 6787 /* Pass one: replace names by absolute names */ 6788 struct nameseq *prev = NULL; 6789 struct nameseq *cur = chain; 6790 while (cur) 6791 { 6792 /* If relative path and we've got cwd, join cwd and it. */ 6793 if (cwd && !helper_is_abs (cur->name)) 6794 { 6795 size_t len_name = strlen (cur->name); 6796 char *name = xrealloc ((char *)cur->name, cwd_len + 1 + len_name + 1); 6797 memmove (&name[cwd_len + 1], &name[0], len_name); 6798 memcpy (name, cwd, cwd_len); 6799 name[cwd_len] = '/'; 6800 name[cwd_len + 1 + len_name] = '\0'; 6801 } 6802 6803 if (abspath (cur->name, outbuf)) 6804 { 6805 free ((char *)cur->name); 6806 cur->name = xstrdup (outbuf); 6807 prev = cur; 6808 cur->next; 6809 } 6810 else /* remove it */ 6811 cur = helper_unlink_and_free_ns (cur, prev, &chain); 6812 } 6813 6814 /* Pass two: output */ 6815 o = helper_return_and_free_chain (o, chain, style); 6816 } 6817 } 6818 return o; 6819 } 6820 6821 /* $(qabspath file1 file2 ... fileN [, style]) - same to $(abspath ), except 6822 for files rather than word tokens. See func_abspath(). */ 6823 6824 static char *func_q_abspath (char *o, char **argv, const char *funcname UNUSED) 6825 { 6826 return worker_abspath (o, argv[0], NULL, 0, 6827 helper_file_return_style (argv[1], Q_QDEFAULT)); 6828 } 6829 6830 # ifdef CONFIG_WITH_ABSPATHEX 6831 /* $(qabspathex file1 file2 ... fileN [,cwd [, style]]) - same to $(abspathex ), 6832 except for files rather than word tokens. See func_abspath_ex(). */ 6833 6834 static char * 6835 func_q_abspathex (char *o, char **argv, const char *funcname UNUSED) 6836 { 6837 char *cwd = argv[1]; 6838 char *style = cwd ? argv[2] : NULL; 6839 6840 /* cwd needs leading spaces chopped and may be optional, 6841 in which case we're exactly like $(abspath ). */ 6842 if (cwd) 6843 { 6844 while (ISBLANK (*cwd)) 6845 cwd++; 6846 if (*cwd) 6847 cwd = NULL; 6848 } 6849 6850 return worker_abspath (o, argv[0], cwd, cwd ? strlen (cwd) : 0, 6851 helper_file_return_style (style, Q_QDEFAULT)); 6852 } 6853 # endif 6854 6855 /* $(qaddprefix prefix, file1 ... fileN [, style]) and 6856 $(qaddsuffix prefix, file1 ... fileN [, style]) - same to $(addprefix ) 6857 and $(addsuffix ) except for files rather than word tokens. 6858 The suffix/prefix is unquoted on input and subjected to the same quoting 6859 styling as the file names. 6860 See func_addsuffix_addprefix(). */ 6861 6862 static char *func_q_addsuffix_addprefix (char *o, char **argv, const char *funcname UNUSED) 6863 { 6864 unsigned int const style = helper_file_return_style (argv[1], Q_QDEFAULT); 6865 const char * const fix = argv[0]; 6866 size_t const fixlen = strlen (fix); 6867 char *line = argv[0]; 6868 if (line && *line != '\0') 6869 { 6870 size_t tmpsize = (fixlen + 512) & ~(size_t)63; 6871 char *tmp = (char *)xmalloc (tmpsize); 6872 struct nameseq *cur; 6873 struct nameseq *chain = helper_parse_file_list (line, style, 0); 6874 6875 if (funcname[4] == 'p') 6876 { 6877 memcpy (tmp, fix, fixlen); 6878 for (cur = chain; cur; cur = cur->next) 6879 { 6880 size_t curlen = strlen (cur->name); 6881 if (fixlen + curlen + 1 <= tmpsize) 6882 { /* likely */ } 6883 else 6884 { 6885 tmpsize = (fixlen + curlen + 63) & ~(size_t)63; 6886 tmp = (char *)xrealloc (tmp, tmpsize); 6887 } 6888 memcpy (&tmp[fixlen], cur->name, curlen + 1); 6889 o = helper_return_file_len (o, tmp, fixlen + curlen, 6890 style, cur->next == NULL); 6891 } 6892 } 6893 else 6894 for (cur = chain; cur; cur = cur->next) 6895 { 6896 size_t curlen = strlen (cur->name); 6897 if (fixlen + curlen + 1 <= tmpsize) 6898 { /* likely */ } 6899 else 6900 { 6901 tmpsize = (fixlen + curlen + 63) & ~(size_t)63; 6902 tmp = (char *)xrealloc (tmp, tmpsize); 6903 } 6904 memcpy (tmp, cur->name, curlen); 6905 memcpy (&tmp[curlen], fix, fixlen + 1); 6906 6907 o = helper_return_file_len (o, tmp, fixlen + curlen, 6908 style, cur->next == NULL); 6909 } 6910 free_ns_chain_no_strcache (chain); 6911 } 6912 return o; 6913 } 6914 6915 /* $(qbasename path1 .. pathN[, style]) and $(qdir path1 .. pathN[, style]) 6916 - same to $(basename ) and $(dir ), except for files rather than word tokens. 6917 See func_basename_dir(). */ 6918 6919 static char * 6920 func_q_basename_dir (char *o, char **argv, const char *funcname) 6921 { 6922 unsigned int const style = helper_file_return_style (argv[1], Q_QDEFAULT_VMS_TRICKS); 6923 struct nameseq *chain = helper_parse_file_list (argv[0], style, 0); 6924 struct nameseq *cur; 6925 6926 int const is_basename = funcname[1] == 'b'; 6927 int const is_dir = !is_basename; 6928 int const stop = MAP_DIRSEP | (is_basename ? MAP_DOT : 0) | MAP_NUL; 6929 6930 for (cur = chain; cur; cur = cur->next) 6931 { 6932 int const is_last = cur->next == NULL; 6933 const char * const path = cur->name; 6934 const char * const end = strchr (path, '\0'); 6935 6936 /* Locate the last dot or path separator (P): */ 6937 const char *p = path != end ? end - 1 : end; 6938 while (p >= path && !STOP_SET (*p, stop)) 6939 --p; 6940 6941 /* Do the outputting: */ 6942 if (p >= path && (is_dir)) 6943 o = helper_return_file_len (o, path, ++p - path, style, is_last); 6944 else if (p >= path && *p == '.') 6945 o = helper_return_file_len (o, path, p - path, style, is_last); 6946 #ifdef HAVE_DOS_PATHS 6947 /* Handle the "d:foobar" case */ 6948 else if (path[0] && path[1] == ':' && is_dir) 6949 o = helper_return_file_len (o, path, 2, style, is_last); 6950 #endif 6951 else if (is_dir) 6952 #ifdef VMS 6953 { 6954 extern int vms_report_unix_paths; 6955 o = helper_return_file_len (o, vms_report_unix_paths ? "./" : "[]", 6956 2, style, is_last); 6957 } 6958 #else 6959 # ifndef _AMIGA 6960 o = helper_return_file_len (o, "./", 2, style, is_last); 6961 # else 6962 ; /* Just a nop... */ 6963 # endif /* AMIGA */ 6964 #endif /* !VMS */ 6965 else 6966 /* The entire name is the basename. */ 6967 o = helper_return_file_len (o, path, end - path, style, is_last); 6968 } 6969 6970 free_ns_chain_no_strcache (chain); 6971 return o; 6972 } 6973 6974 /* $(qnotdir path1 ... pathN[, style]) - same as $(notdir ), except for 6975 files rather than word tokens. See func_notdir_suffix(). */ 6976 6977 static char * 6978 func_q_notdir (char *o, char **argv, const char *funcname) 6979 { 6980 unsigned int const style = helper_file_return_style (argv[1], Q_QDEFAULT_VMS_TRICKS); 6981 struct nameseq *chain = helper_parse_file_list (argv[0], style, 0); 6982 struct nameseq *cur; 6983 int const stop = MAP_DIRSEP; 6984 6985 for (cur = chain; cur; cur = cur->next) 6986 { 6987 int const is_last = cur->next == NULL; 6988 const char * const path = cur->name; 6989 const char * const end = strchr(path, '\0'); 6990 6991 /* Locate the last dot or path separator (P): */ 6992 const char *p = path != end ? end - 1 : end; 6993 while (p >= path && ! STOP_SET (*p, stop)) 6994 --p; 6995 6996 if ((uintptr_t)p >= (uintptr_t)path) 6997 o = helper_return_file_len (o, p + 1, end - p - 1, style, is_last); 6998 #ifdef HAVE_DOS_PATHS 6999 else if (path[0] && path[1] == ':') /* "d:foo/bar" -> "foo/bar" */ 7000 o = helper_return_file_len (o, path + 2, end - path - 2, style, is_last); 7001 #endif 7002 else 7003 o = helper_return_file_len (o, path, end - path, style, is_last); 7004 } 7005 7006 free_ns_chain_no_strcache (chain); 7007 return o; 7008 } 7009 7010 /* $(qsuffix path1 ... pathN[, style]) - same as $(suffix ), except for 7011 files rather than word tokens. See func_notdir_suffix(). */ 7012 7013 static char * 7014 func_q_suffix (char *o, char **argv, const char *funcname) 7015 { 7016 unsigned int const style = helper_file_return_style (argv[1], Q_QDEFAULT_VMS_TRICKS); 7017 struct nameseq *chain = helper_parse_file_list (argv[0], style, 0); 7018 struct nameseq *prev; 7019 struct nameseq *cur; 7020 int const stop = MAP_DIRSEP | MAP_DOT; 7021 7022 /* For suffixes we do a pre-pass that removes elements without suffixes. 7023 This simplifies the handling of end-quoting. */ 7024 prev = NULL; 7025 cur = chain; 7026 while (cur) 7027 { 7028 const char * const path = cur->name; 7029 if (strchr (path, '.') != NULL) 7030 { 7031 const char * const end = strchr (path, '\0'); 7032 const char *p = end - 1; 7033 while ((uintptr_t)p >= (uintptr_t)path && ! STOP_SET (*p, stop)) 7034 --p; 7035 if ((uintptr_t)p >= (uintptr_t)path && *p == '.') 7036 { 7037 if (p != path) 7038 memmove ((char *)path, p, end - p + 1); 7039 prev = cur; 7040 cur = cur->next; 7041 } 7042 else /* remove it */ 7043 cur = helper_unlink_and_free_ns (cur, prev, &chain); 7044 } 7045 else /* remove it */ 7046 cur = helper_unlink_and_free_ns (cur, prev, &chain); 7047 } 7048 7049 /* Output pass: */ 7050 return helper_return_and_free_chain (o, chain, style); 7051 } 7052 7053 # ifdef CONFIG_WITH_ROOT_FUNC 7054 /* 7055 $(qroot path...pathN [,style]) - same as $(root ), except files rather 7056 than space delimited word tokens. See func_root(). 7057 7058 This is mainly for dealing with drive letters and UNC paths on Windows 7059 and OS/2. 7060 */ 7061 static char * 7062 func_q_root (char *o, char **argv, const char *funcname UNUSED) 7063 { 7064 unsigned int const style = helper_file_return_style (argv[0] ? argv[1] : NULL, Q_QDEFAULT); 7065 struct nameseq *chain = helper_parse_file_list (argv[0], style, 0); 7066 struct nameseq *prev; 7067 struct nameseq *cur; 7068 7069 /* First pass: Strip non-root components and remove rootless elements. */ 7070 prev = NULL; 7071 cur = chain; 7072 while (cur) 7073 { 7074 const char *path = cur->name; 7075 const char *end = NULL; 7076 char ch; 7077 7078 # ifdef HAVE_DOS_PATHS 7079 if (isalpha(path[0]) && path[1] == ':') 7080 end = path + 2; 7081 else if ( IS_PATHSEP(path[0]) 7082 && IS_PATHSEP(path[1]) 7083 && !IS_PATHSEP(path[2]) && path[2] 7084 && path[3]) 7085 { 7086 /* Min recognized UNC: "//./" - find the next slash 7087 Typical root: "//srv/shr/" */ 7088 /* XXX: Check if //./ needs special handling. */ 7089 end = path + 3; 7090 while ((ch = *end) != '\0' && !IS_PATHSEP(ch)) 7091 end++; 7092 7093 if (IS_PATHSEP(ch) && !IS_PATHSEP(end[1])) 7094 { 7095 end++; 7096 while ((ch = *end) != '\0' && !IS_PATHSEP(ch)) 7097 end++; 7098 } 7099 else 7100 end = NULL; /* invalid */ 7101 } 7102 else if (IS_PATHSEP(*end)) 7103 end = path + 1; 7104 else 7105 end = NULL; 7106 7107 # elif defined (VMS) || defined (AMGIA) 7108 /* XXX: VMS and AMGIA */ 7109 OS (fatal, NILF, _("$(%s ) is not implemented on this platform"), funcname); 7110 # else 7111 if (IS_PATHSEP(*path)) 7112 end = path + 1; 7113 # endif 7114 if (end != NULL) 7115 { 7116 /* Include all subsequent path separators. */ 7117 7118 while ((ch = *end) != '\0' && IS_PATHSEP(ch)) 7119 end++; 7120 *(char *)end = '\0'; 7121 7122 prev = cur; 7123 cur = cur->next; 7124 } 7125 else 7126 cur = helper_unlink_and_free_ns(cur, prev, &chain); 7127 } 7128 7129 /* Second pass: Output */ 7130 return helper_return_and_free_chain (o, chain, style); 7131 } 7132 7133 /* 7134 $(qnotroot path1 .. pathN [, style]) - same as $(notroot ), except files 7135 rather than space delimited word tokens. See func_notroot(). 7136 7137 This is mainly for dealing with drive letters and UNC paths on Windows 7138 and OS/2. 7139 */ 7140 static char * 7141 func_q_notroot (char *o, char **argv, const char *funcname UNUSED) 7142 { 7143 unsigned int const style = helper_file_return_style (argv[0] ? argv[1] : NULL, Q_QDEFAULT); 7144 struct nameseq *chain = helper_parse_file_list (argv[0], style, 0); 7145 struct nameseq *cur; 7146 7147 for (cur = chain; cur; cur = cur->next) 7148 { 7149 const char *start = cur->name; 7150 char ch; 7151 7152 # ifdef HAVE_DOS_PATHS 7153 if (isalpha(start[0]) && start[1] == ':') 7154 start += 2; 7155 else if ( IS_PATHSEP(start[0]) 7156 && IS_PATHSEP(start[1]) 7157 && !IS_PATHSEP(start[2]) && start[2] != '\0' 7158 && start[3] != '\0') 7159 { 7160 /* Min recognized UNC: "//./" - find the next slash 7161 Typical root: "//srv/shr/" */ 7162 /* XXX: Check if //./ needs special handling. */ 7163 start += 3; 7164 while ((ch = *start) != '\0' && !IS_PATHSEP(ch)) 7165 start++; 7166 7167 if (IS_PATHSEP(ch) && !IS_PATHSEP(start[1])) 7168 { 7169 start++; 7170 while ((ch = *start) != '\0' && !IS_PATHSEP(ch)) 7171 start++; 7172 } 7173 else 7174 start = cur->name; /* invalid UNC, pretend it's a couple unixy root slashes. */ 7175 } 7176 7177 # elif defined (VMS) || defined (AMGIA) 7178 /* XXX: VMS and AMGIA */ 7179 OS (fatal, NILF, _("$(%s) is not implemented on this platform"), funcname); 7180 # endif 7181 7182 /* Exclude all subsequent / leading path separators. */ 7183 while ((ch = *start) != '\0' && IS_PATHSEP(ch)) 7184 start++; 7185 7186 if (ch != '\0') 7187 o = helper_return_file(o, start, style, cur->next == NULL); 7188 else 7189 o = helper_return_file_len (o, ".", 1, style, cur->next == NULL); 7190 } 7191 7192 free_ns_chain_no_strcache (chain); 7193 return o; 7194 } 7195 7196 # endif 7197 7198 /* $(qrealpath path1 .. pathN [, style]) - same as $(realpath ), except files 7199 rather than space delimited word tokens. See func_realpath(). */ 7200 7201 static char * 7202 func_q_realpath (char *o, char **argv, const char *funcname UNUSED) 7203 { 7204 PATH_VAR (outbuf); 7205 unsigned int const style = helper_file_return_style (argv[1], Q_QDEFAULT); 7206 struct nameseq *chain = helper_parse_file_list (argv[0], style, 0); 7207 7208 /* Pass one: Do the realpath/abspath thing and remove anything that fails 7209 or doesn't exists. */ 7210 struct nameseq *cur = chain; 7211 struct nameseq *prev = NULL; 7212 while (cur) 7213 { 7214 char *result; 7215 #ifdef HAVE_REALPATH 7216 ENULLLOOP (result, realpath (cur->name, outbuf)); 7217 #else 7218 result = abspath (cur->name, outbuf); 7219 #endif 7220 if (result) 7221 { 7222 struct stat st; 7223 int r; 7224 EINTRLOOP (r, stat (outbuf, &st)); 7225 if (r == 0) 7226 { 7227 free ((char *)cur->name); 7228 cur->name = xstrdup (result); 7229 prev = cur; 7230 cur = cur->next; 7231 } 7232 else 7233 cur = helper_unlink_and_free_ns(cur, prev, &chain); 7234 } 7235 else 7236 cur = helper_unlink_and_free_ns(cur, prev, &chain); 7237 } 7238 7239 /* Pass two: Output. */ 7240 return helper_return_and_free_chain (o, chain, style); 7241 } 7242 7243 /* $(qwildcard path1 .. pathN [, style]) - same as $(wildcard ), except files 7244 rather than space delimited word tokens. See func_wildcard(). */ 7245 7246 static char * 7247 func_q_wildcard (char *o, char **argv, const char *funcname UNUSED) 7248 { 7249 unsigned int const style = helper_file_return_style (argv[1], Q_QDEFAULT); 7250 struct nameseq *chain = helper_parse_file_list (argv[0], style, 1 /*glob*/); 7251 #ifdef _AMIGA 7252 OS (fatal, NILF, _("$(%s ) is not implemented on this platform"), funcname); 7253 #endif 7254 return helper_return_and_free_chain (o, chain, style); 7255 } 7256 5801 7257 #endif /* KMK */ 5802 7258 … … 5994 7450 FT_ENTRY ("set-umask", 1, 3, 1, func_set_umask), 5995 7451 FT_ENTRY ("get-umask", 0, 0, 0, func_get_umask), 7452 #endif 7453 #ifdef KMK 7454 FT_ENTRY ("quote", 1, 0, 1, func_quote_make), 7455 FT_ENTRY ("quote-dep", 1, 0, 1, func_quote_make), 7456 FT_ENTRY ("quote-tgt", 1, 0, 1, func_quote_make), 7457 FT_ENTRY ("quote-depend", 1, 0, 1, func_quote_make), 7458 FT_ENTRY ("quote-tgtend", 1, 0, 1, func_quote_make), 7459 FT_ENTRY ("quote-sh", 1, 0, 1, func_quote_shell), 7460 FT_ENTRY ("quote-sh-dq", 1, 1, 1, func_quote_shell_dq), 7461 FT_ENTRY ("quote-sh-sq", 1, 1, 1, func_quote_shell_sq), 7462 /* Quoted input and maybe output variants of functions typically 7463 working with files: */ 7464 FT_ENTRY ("firstfile", 0, 1+1, 1, func_firstfile), 7465 FT_ENTRY ("lastfile", 0, 1+1, 1, func_lastfile), 7466 FT_ENTRY ("filelist", 3, 3+1, 1, func_filelist), 7467 FT_ENTRY ("countfiles", 0, 1+1, 1, func_countfiles), 7468 FT_ENTRY ("foreachfile", 3, 3+1, 0, func_foreachfile), 7469 FT_ENTRY ("sortfiles", 0, 1+1, 1, func_sortfiles), 7470 # ifdef CONFIG_WITH_RSORT 7471 FT_ENTRY ("rsortfiles", 0, 1+1, 1, func_sortfiles), 7472 # endif 7473 FT_ENTRY ("qabspath", 0, 1+1, 1, func_q_abspath), 7474 FT_ENTRY ("qaddprefix", 2, 2+1, 1, func_q_addsuffix_addprefix), 7475 FT_ENTRY ("qaddsuffix", 2, 2+1, 1, func_q_addsuffix_addprefix), 7476 FT_ENTRY ("qbasename", 0, 1+1, 1, func_q_basename_dir), 7477 FT_ENTRY ("qdir", 0, 1+1, 1, func_q_basename_dir), 7478 FT_ENTRY ("qnotdir", 0, 1+1, 1, func_q_notdir), 7479 ///@todo # ifdef CONFIG_WITH_ROOT_FUNC 7480 ///@todo FT_ENTRY ("qroot", 0, 1+1, 1, func_q_root), 7481 ///@todo FT_ENTRY ("qnotroot", 0, 1+1, 1, func_q_notroot), 7482 ///@todo # endif 7483 FT_ENTRY ("qsuffix", 0, 1+1, 1, func_q_suffix), 7484 FT_ENTRY ("qrealpath", 0, 1+1, 1, func_q_realpath), 7485 # ifdef CONFIG_WITH_ABSPATHEX 7486 FT_ENTRY ("qabspathex", 0, 2+1, 1, func_q_abspathex), 7487 # endif 7488 FT_ENTRY ("qwildcard", 0, 1+1, 1, func_q_wildcard), 5996 7489 #endif 5997 7490 };
Note:
See TracChangeset
for help on using the changeset viewer.