str.c revision 138232
1/*- 2 * Copyright (c) 1988, 1989, 1990, 1993 3 * The Regents of the University of California. All rights reserved. 4 * Copyright (c) 1989 by Berkeley Softworks 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Adam de Boor. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * @(#)str.c 5.8 (Berkeley) 6/1/90 39 */ 40 41#include <sys/cdefs.h> 42__FBSDID("$FreeBSD: head/usr.bin/make/str.c 138232 2004-11-30 17:46:29Z harti $"); 43 44#include "make.h" 45 46static char **argv, *buffer; 47static int argmax, curlen; 48 49/* 50 * str_init -- 51 * Initialize the strings package 52 * 53 */ 54void 55str_init(void) 56{ 57 char *p1; 58 59 argv = (char **)emalloc(((argmax = 50) + 1) * sizeof(char *)); 60 argv[0] = Var_Value(".MAKE", VAR_GLOBAL, &p1); 61} 62 63 64/* 65 * str_end -- 66 * Cleanup the strings package 67 * 68 */ 69void 70str_end(void) 71{ 72 if (argv) { 73 if (argv[0]) 74 free(argv[0]); 75 free(argv); 76 } 77 if (buffer) 78 free(buffer); 79} 80 81/*- 82 * str_concat -- 83 * concatenate the two strings, inserting a space or slash between them, 84 * freeing them if requested. 85 * 86 * returns -- 87 * the resulting string in allocated space. 88 */ 89char * 90str_concat(char *s1, char *s2, int flags) 91{ 92 int len1, len2; 93 char *result; 94 95 /* get the length of both strings */ 96 len1 = strlen(s1); 97 len2 = strlen(s2); 98 99 /* allocate length plus separator plus EOS */ 100 result = emalloc((u_int)(len1 + len2 + 2)); 101 102 /* copy first string into place */ 103 memcpy(result, s1, len1); 104 105 /* add separator character */ 106 if (flags & STR_ADDSPACE) { 107 result[len1] = ' '; 108 ++len1; 109 } else if (flags & STR_ADDSLASH) { 110 result[len1] = '/'; 111 ++len1; 112 } 113 114 /* copy second string plus EOS into place */ 115 memcpy(result + len1, s2, len2 + 1); 116 117 /* free original strings */ 118 if (flags & STR_DOFREE) { 119 free(s1); 120 free(s2); 121 } 122 return (result); 123} 124 125/*- 126 * brk_string -- 127 * Fracture a string into an array of words (as delineated by tabs or 128 * spaces) taking quotation marks into account. Leading tabs/spaces 129 * are ignored. 130 * 131 * returns -- 132 * Pointer to the array of pointers to the words. To make life easier, 133 * the first word is always the value of the .MAKE variable. 134 */ 135char ** 136brk_string(char *str, int *store_argc, Boolean expand) 137{ 138 int argc, ch; 139 char inquote, *p, *start, *t; 140 int len; 141 142 /* skip leading space chars. */ 143 for (; *str == ' ' || *str == '\t'; ++str) 144 continue; 145 146 /* allocate room for a copy of the string */ 147 if ((len = strlen(str) + 1) > curlen) { 148 if (buffer) 149 free(buffer); 150 buffer = emalloc(curlen = len); 151 } 152 153 /* 154 * copy the string; at the same time, parse backslashes, 155 * quotes and build the argument list. 156 */ 157 argc = 1; 158 inquote = '\0'; 159 for (p = str, start = t = buffer;; ++p) { 160 switch(ch = *p) { 161 case '"': 162 case '\'': 163 if (inquote) { 164 if (ch != inquote) 165 break; 166 inquote = '\0'; 167 /* Don't miss "" or '' */ 168 if (!start) 169 start = t; 170 } else 171 inquote = (char) ch; 172 if (expand) 173 continue; 174 break; 175 case ' ': 176 case '\t': 177 case '\n': 178 if (inquote) 179 break; 180 if (!start) 181 continue; 182 /* FALLTHROUGH */ 183 case '\0': 184 /* 185 * end of a token -- make sure there's enough argv 186 * space and save off a pointer. 187 */ 188 if (!start) 189 goto done; 190 191 *t++ = '\0'; 192 if (argc == argmax) { 193 argmax *= 2; /* ramp up fast */ 194 argv = (char **)erealloc(argv, 195 (argmax + 1) * sizeof(char *)); 196 } 197 argv[argc++] = start; 198 start = (char *)NULL; 199 if (ch == '\n' || ch == '\0') 200 goto done; 201 continue; 202 case '\\': 203 if (!expand) { 204 if (!start) 205 start = t; 206 *t++ = '\\'; 207 ch = *++p; 208 break; 209 } 210 211 switch (ch = *++p) { 212 case '\0': 213 case '\n': 214 /* hmmm; fix it up as best we can */ 215 ch = '\\'; 216 --p; 217 break; 218 case 'b': 219 ch = '\b'; 220 break; 221 case 'f': 222 ch = '\f'; 223 break; 224 case 'n': 225 ch = '\n'; 226 break; 227 case 'r': 228 ch = '\r'; 229 break; 230 case 't': 231 ch = '\t'; 232 break; 233 default: 234 break; 235 } 236 break; 237 default: 238 break; 239 } 240 if (!start) 241 start = t; 242 *t++ = (char)ch; 243 } 244done: argv[argc] = (char *)NULL; 245 *store_argc = argc; 246 return (argv); 247} 248 249/* 250 * Str_Match -- 251 * 252 * See if a particular string matches a particular pattern. 253 * 254 * Results: Non-zero is returned if string matches pattern, 0 otherwise. The 255 * matching operation permits the following special characters in the 256 * pattern: *?\[] (see the man page for details on what these mean). 257 * 258 * Side effects: None. 259 */ 260int 261Str_Match(const char *string, const char *pattern) 262{ 263 char c2; 264 265 for (;;) { 266 /* 267 * See if we're at the end of both the pattern and the 268 * string. If, we succeeded. If we're at the end of the 269 * pattern but not at the end of the string, we failed. 270 */ 271 if (*pattern == 0) 272 return (!*string); 273 if (*string == 0 && *pattern != '*') 274 return (0); 275 /* 276 * Check for a "*" as the next pattern character. It matches 277 * any substring. We handle this by calling ourselves 278 * recursively for each postfix of string, until either we 279 * match or we reach the end of the string. 280 */ 281 if (*pattern == '*') { 282 pattern += 1; 283 if (*pattern == 0) 284 return (1); 285 while (*string != 0) { 286 if (Str_Match(string, pattern)) 287 return (1); 288 ++string; 289 } 290 return (0); 291 } 292 /* 293 * Check for a "?" as the next pattern character. It matches 294 * any single character. 295 */ 296 if (*pattern == '?') 297 goto thisCharOK; 298 /* 299 * Check for a "[" as the next pattern character. It is 300 * followed by a list of characters that are acceptable, or 301 * by a range (two characters separated by "-"). 302 */ 303 if (*pattern == '[') { 304 ++pattern; 305 for (;;) { 306 if ((*pattern == ']') || (*pattern == 0)) 307 return (0); 308 if (*pattern == *string) 309 break; 310 if (pattern[1] == '-') { 311 c2 = pattern[2]; 312 if (c2 == 0) 313 return (0); 314 if ((*pattern <= *string) && 315 (c2 >= *string)) 316 break; 317 if ((*pattern >= *string) && 318 (c2 <= *string)) 319 break; 320 pattern += 2; 321 } 322 ++pattern; 323 } 324 while ((*pattern != ']') && (*pattern != 0)) 325 ++pattern; 326 goto thisCharOK; 327 } 328 /* 329 * If the next pattern character is '/', just strip off the 330 * '/' so we do exact matching on the character that follows. 331 */ 332 if (*pattern == '\\') { 333 ++pattern; 334 if (*pattern == 0) 335 return (0); 336 } 337 /* 338 * There's no special character. Just make sure that the 339 * next characters of each string match. 340 */ 341 if (*pattern != *string) 342 return (0); 343thisCharOK: ++pattern; 344 ++string; 345 } 346} 347 348 349/*- 350 *----------------------------------------------------------------------- 351 * Str_SYSVMatch -- 352 * Check word against pattern for a match (% is wild), 353 * 354 * Results: 355 * Returns the beginning position of a match or null. The number 356 * of characters matched is returned in len. 357 * 358 * Side Effects: 359 * None 360 * 361 *----------------------------------------------------------------------- 362 */ 363const char * 364Str_SYSVMatch(const char *word, const char *pattern, int *len) 365{ 366 const char *m, *p, *w; 367 368 p = pattern; 369 w = word; 370 371 if (*w == '\0') { 372 /* Zero-length word cannot be matched against */ 373 *len = 0; 374 return (NULL); 375 } 376 377 if (*p == '\0') { 378 /* Null pattern is the whole string */ 379 *len = strlen(w); 380 return (w); 381 } 382 383 if ((m = strchr(p, '%')) != NULL) { 384 /* check that the prefix matches */ 385 for (; p != m && *w && *w == *p; w++, p++) 386 continue; 387 388 if (p != m) 389 return (NULL); /* No match */ 390 391 if (*++p == '\0') { 392 /* No more pattern, return the rest of the string */ 393 *len = strlen(w); 394 return (w); 395 } 396 } 397 398 m = w; 399 400 /* Find a matching tail */ 401 do 402 if (strcmp(p, w) == 0) { 403 *len = w - m; 404 return (m); 405 } 406 while (*w++ != '\0'); 407 408 return (NULL); 409} 410 411 412/*- 413 *----------------------------------------------------------------------- 414 * Str_SYSVSubst -- 415 * Substitute '%' on the pattern with len characters from src. 416 * If the pattern does not contain a '%' prepend len characters 417 * from src. 418 * 419 * Results: 420 * None 421 * 422 * Side Effects: 423 * Places result on buf 424 * 425 *----------------------------------------------------------------------- 426 */ 427void 428Str_SYSVSubst(Buffer buf, const char *pat, const char *src, int len) 429{ 430 const char *m; 431 432 if ((m = strchr(pat, '%')) != NULL) { 433 /* Copy the prefix */ 434 Buf_AddBytes(buf, m - pat, (Byte *)pat); 435 /* skip the % */ 436 pat = m + 1; 437 } 438 439 /* Copy the pattern */ 440 Buf_AddBytes(buf, len, (Byte *)src); 441 442 /* append the rest */ 443 Buf_AddBytes(buf, strlen(pat), (Byte *)pat); 444} 445