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 * %sccs.include.redist.c% 11 */ 12 13 #ifndef lint 14 static char sccsid[] = "@(#)str.c 8.6 (Berkeley) 04/28/95"; 15 #endif /* not lint */ 16 17 #include "make.h" 18 19 static char **argv, *buffer; 20 static int argmax, curlen; 21 22 /* 23 * str_init -- 24 * Initialize the strings package 25 * 26 */ 27 void 28 str_init() 29 { 30 char *p1; 31 argv = (char **)emalloc((argmax = 50) * sizeof(char *)); 32 argv[0] = Var_Value(".MAKE", VAR_GLOBAL, &p1); 33 } 34 35 36 /* 37 * str_end -- 38 * Cleanup the strings package 39 * 40 */ 41 void 42 str_end() 43 { 44 if (argv[0]) { 45 free(argv[0]); 46 free((Address) argv); 47 } 48 if (buffer) 49 free(buffer); 50 } 51 52 53 /*- 54 * str_concat -- 55 * concatenate the two strings, inserting a space or slash between them, 56 * freeing them if requested. 57 * 58 * returns -- 59 * the resulting string in allocated space. 60 */ 61 char * 62 str_concat(s1, s2, flags) 63 char *s1, *s2; 64 int flags; 65 { 66 register int len1, len2; 67 register char *result; 68 69 /* get the length of both strings */ 70 len1 = strlen(s1); 71 len2 = strlen(s2); 72 73 /* allocate length plus separator plus EOS */ 74 result = emalloc((u_int)(len1 + len2 + 2)); 75 76 /* copy first string into place */ 77 memcpy(result, s1, len1); 78 79 /* add separator character */ 80 if (flags & STR_ADDSPACE) { 81 result[len1] = ' '; 82 ++len1; 83 } else if (flags & STR_ADDSLASH) { 84 result[len1] = '/'; 85 ++len1; 86 } 87 88 /* copy second string plus EOS into place */ 89 memcpy(result + len1, s2, len2 + 1); 90 91 /* free original strings */ 92 if (flags & STR_DOFREE) { 93 (void)free(s1); 94 (void)free(s2); 95 } 96 return(result); 97 } 98 99 /*- 100 * brk_string -- 101 * Fracture a string into an array of words (as delineated by tabs or 102 * spaces) taking quotation marks into account. Leading tabs/spaces 103 * are ignored. 104 * 105 * returns -- 106 * Pointer to the array of pointers to the words. To make life easier, 107 * the first word is always the value of the .MAKE variable. 108 */ 109 char ** 110 brk_string(str, store_argc, expand) 111 register char *str; 112 int *store_argc; 113 Boolean expand; 114 { 115 register int argc, ch; 116 register char inquote, *p, *start, *t; 117 int len; 118 119 /* skip leading space chars. */ 120 for (; *str == ' ' || *str == '\t'; ++str) 121 continue; 122 123 /* allocate room for a copy of the string */ 124 if ((len = strlen(str) + 1) > curlen) { 125 if (buffer) 126 free(buffer); 127 buffer = emalloc(curlen = len); 128 } 129 130 /* 131 * copy the string; at the same time, parse backslashes, 132 * quotes and build the argument list. 133 */ 134 argc = 1; 135 inquote = '\0'; 136 for (p = str, start = t = buffer;; ++p) { 137 switch(ch = *p) { 138 case '"': 139 case '\'': 140 if (inquote) 141 if (inquote == ch) 142 inquote = '\0'; 143 else 144 break; 145 else { 146 inquote = (char) ch; 147 /* Don't miss "" or '' */ 148 if (start == NULL && p[1] == inquote) { 149 start = t + 1; 150 break; 151 } 152 } 153 if (!expand) { 154 if (!start) 155 start = t; 156 *t++ = ch; 157 } 158 continue; 159 case ' ': 160 case '\t': 161 case '\n': 162 if (inquote) 163 break; 164 if (!start) 165 continue; 166 /* FALLTHROUGH */ 167 case '\0': 168 /* 169 * end of a token -- make sure there's enough argv 170 * space and save off a pointer. 171 */ 172 if (!start) 173 goto done; 174 175 *t++ = '\0'; 176 if (argc == argmax) { 177 argmax *= 2; /* ramp up fast */ 178 if (!(argv = (char **)realloc(argv, 179 argmax * sizeof(char *)))) 180 enomem(); 181 } 182 argv[argc++] = start; 183 start = (char *)NULL; 184 if (ch == '\n' || ch == '\0') 185 goto done; 186 continue; 187 case '\\': 188 if (!expand) { 189 if (!start) 190 start = t; 191 *t++ = '\\'; 192 ch = *++p; 193 break; 194 } 195 196 switch (ch = *++p) { 197 case '\0': 198 case '\n': 199 /* hmmm; fix it up as best we can */ 200 ch = '\\'; 201 --p; 202 break; 203 case 'b': 204 ch = '\b'; 205 break; 206 case 'f': 207 ch = '\f'; 208 break; 209 case 'n': 210 ch = '\n'; 211 break; 212 case 'r': 213 ch = '\r'; 214 break; 215 case 't': 216 ch = '\t'; 217 break; 218 } 219 break; 220 } 221 if (!start) 222 start = t; 223 *t++ = (char) ch; 224 } 225 done: argv[argc] = (char *)NULL; 226 *store_argc = argc; 227 return(argv); 228 } 229 230 /* 231 * Str_FindSubstring -- See if a string contains a particular substring. 232 * 233 * Results: If string contains substring, the return value is the location of 234 * the first matching instance of substring in string. If string doesn't 235 * contain substring, the return value is NULL. Matching is done on an exact 236 * character-for-character basis with no wildcards or special characters. 237 * 238 * Side effects: None. 239 */ 240 char * 241 Str_FindSubstring(string, substring) 242 register char *string; /* String to search. */ 243 char *substring; /* Substring to find in string */ 244 { 245 register char *a, *b; 246 247 /* 248 * First scan quickly through the two strings looking for a single- 249 * character match. When it's found, then compare the rest of the 250 * substring. 251 */ 252 253 for (b = substring; *string != 0; string += 1) { 254 if (*string != *b) 255 continue; 256 a = string; 257 for (;;) { 258 if (*b == 0) 259 return(string); 260 if (*a++ != *b++) 261 break; 262 } 263 b = substring; 264 } 265 return((char *) NULL); 266 } 267 268 /* 269 * Str_Match -- 270 * 271 * See if a particular string matches a particular pattern. 272 * 273 * Results: Non-zero is returned if string matches pattern, 0 otherwise. The 274 * matching operation permits the following special characters in the 275 * pattern: *?\[] (see the man page for details on what these mean). 276 * 277 * Side effects: None. 278 */ 279 int 280 Str_Match(string, pattern) 281 register char *string; /* String */ 282 register char *pattern; /* Pattern */ 283 { 284 char c2; 285 286 for (;;) { 287 /* 288 * See if we're at the end of both the pattern and the 289 * string. If, we succeeded. If we're at the end of the 290 * pattern but not at the end of the string, we failed. 291 */ 292 if (*pattern == 0) 293 return(!*string); 294 if (*string == 0 && *pattern != '*') 295 return(0); 296 /* 297 * Check for a "*" as the next pattern character. It matches 298 * any substring. We handle this by calling ourselves 299 * recursively for each postfix of string, until either we 300 * match or we reach the end of the string. 301 */ 302 if (*pattern == '*') { 303 pattern += 1; 304 if (*pattern == 0) 305 return(1); 306 while (*string != 0) { 307 if (Str_Match(string, pattern)) 308 return(1); 309 ++string; 310 } 311 return(0); 312 } 313 /* 314 * Check for a "?" as the next pattern character. It matches 315 * any single character. 316 */ 317 if (*pattern == '?') 318 goto thisCharOK; 319 /* 320 * Check for a "[" as the next pattern character. It is 321 * followed by a list of characters that are acceptable, or 322 * by a range (two characters separated by "-"). 323 */ 324 if (*pattern == '[') { 325 ++pattern; 326 for (;;) { 327 if ((*pattern == ']') || (*pattern == 0)) 328 return(0); 329 if (*pattern == *string) 330 break; 331 if (pattern[1] == '-') { 332 c2 = pattern[2]; 333 if (c2 == 0) 334 return(0); 335 if ((*pattern <= *string) && 336 (c2 >= *string)) 337 break; 338 if ((*pattern >= *string) && 339 (c2 <= *string)) 340 break; 341 pattern += 2; 342 } 343 ++pattern; 344 } 345 while ((*pattern != ']') && (*pattern != 0)) 346 ++pattern; 347 goto thisCharOK; 348 } 349 /* 350 * If the next pattern character is '/', just strip off the 351 * '/' so we do exact matching on the character that follows. 352 */ 353 if (*pattern == '\\') { 354 ++pattern; 355 if (*pattern == 0) 356 return(0); 357 } 358 /* 359 * There's no special character. Just make sure that the 360 * next characters of each string match. 361 */ 362 if (*pattern != *string) 363 return(0); 364 thisCharOK: ++pattern; 365 ++string; 366 } 367 } 368 369 370 /*- 371 *----------------------------------------------------------------------- 372 * Str_SYSVMatch -- 373 * Check word against pattern for a match (% is wild), 374 * 375 * Results: 376 * Returns the beginning position of a match or null. The number 377 * of characters matched is returned in len. 378 * 379 * Side Effects: 380 * None 381 * 382 *----------------------------------------------------------------------- 383 */ 384 char * 385 Str_SYSVMatch(word, pattern, len) 386 char *word; /* Word to examine */ 387 char *pattern; /* Pattern to examine against */ 388 int *len; /* Number of characters to substitute */ 389 { 390 char *p = pattern; 391 char *w = word; 392 char *m; 393 394 if (*p == '\0') { 395 /* Null pattern is the whole string */ 396 *len = strlen(w); 397 return w; 398 } 399 400 if ((m = strchr(p, '%')) != NULL) { 401 /* check that the prefix matches */ 402 for (; p != m && *w && *w == *p; w++, p++) 403 continue; 404 405 if (p != m) 406 return NULL; /* No match */ 407 408 if (*++p == '\0') { 409 /* No more pattern, return the rest of the string */ 410 *len = strlen(w); 411 return w; 412 } 413 } 414 415 m = w; 416 417 /* Find a matching tail */ 418 do 419 if (strcmp(p, w) == 0) { 420 *len = w - m; 421 return m; 422 } 423 while (*w++ != '\0'); 424 425 return NULL; 426 } 427 428 429 /*- 430 *----------------------------------------------------------------------- 431 * Str_SYSVSubst -- 432 * Substitute '%' on the pattern with len characters from src. 433 * If the pattern does not contain a '%' prepend len characters 434 * from src. 435 * 436 * Results: 437 * None 438 * 439 * Side Effects: 440 * Places result on buf 441 * 442 *----------------------------------------------------------------------- 443 */ 444 void 445 Str_SYSVSubst(buf, pat, src, len) 446 Buffer buf; 447 char *pat; 448 char *src; 449 int len; 450 { 451 char *m; 452 453 if ((m = strchr(pat, '%')) != NULL) { 454 /* Copy the prefix */ 455 Buf_AddBytes(buf, m - pat, (Byte *) pat); 456 /* skip the % */ 457 pat = m + 1; 458 } 459 460 /* Copy the pattern */ 461 Buf_AddBytes(buf, len, (Byte *) src); 462 463 /* append the rest */ 464 Buf_AddBytes(buf, strlen(pat), (Byte *) pat); 465 } 466