1 /* 2 * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. 3 * Copyright (c) 1988, 1989 by Adam de Boor 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 are permitted 11 * provided that the above copyright notice and this paragraph are 12 * duplicated in all such forms and that any documentation, 13 * advertising materials, and other materials related to such 14 * distribution and use acknowledge that the software was developed 15 * by the University of California, Berkeley. The name of the 16 * University may not be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 21 */ 22 23 #ifndef lint 24 static char sccsid[] = "@(#)str.c 5.2 (Berkeley) 03/11/90"; 25 #endif /* not lint */ 26 27 /*- 28 * str.c -- 29 * General utilites for handling strings. 30 * 31 * Interface: 32 * Str_Concat Concatenate two strings, placing some sort 33 * of separator between them and freeing 34 * the two strings, all this under the control 35 * of the STR_ flags given as the third arg. 36 * 37 * Str_New Duplicate a string and return the copy. 38 * 39 * Str_FindSubstring Find a substring within a string (from 40 * original Sprite libc). 41 * 42 * Str_Match Pattern match two strings. 43 */ 44 45 #include "make.h" 46 47 /*- 48 *----------------------------------------------------------------------- 49 * Str_Concat -- 50 * Str_Concatenate and the two strings, inserting a space between them 51 * and/or freeing them if requested 52 * 53 * Results: 54 * the resulting string 55 * 56 * Side Effects: 57 * The strings s1 and s2 are free'd 58 *----------------------------------------------------------------------- 59 */ 60 char * 61 Str_Concat (s1, s2, flags) 62 char *s1; /* first string */ 63 char *s2; /* second string */ 64 int flags; /* flags governing Str_Concatenation */ 65 { 66 int len; /* total length */ 67 register char *cp1, /* pointer into s1 */ 68 *cp2, /* pointer into s2 */ 69 *cp; /* pointer into result */ 70 char *result; /* result string */ 71 72 /* 73 * get the length of both strings 74 */ 75 for (cp1 = s1; *cp1; cp1++) { 76 /* void */ ; 77 } 78 for (cp2 = s2; *cp2; cp2++) { 79 /* void */ ; 80 } 81 82 len = (cp1 - s1) + 83 (cp2 - s2) + 84 (flags & (STR_ADDSPACE | STR_ADDSLASH) ? 1 : 0) + 85 1; 86 87 result = malloc (len); 88 89 for (cp1 = s1, cp = result; *cp1 != '\0'; cp++, cp1++) { 90 *cp = *cp1; 91 } 92 93 if (flags & STR_ADDSPACE) { 94 *cp++ = ' '; 95 } else if (flags & STR_ADDSLASH) { 96 *cp++ = '/'; 97 } 98 99 for (cp2 = s2; *cp2 != '\0'; cp++, cp2++) { 100 *cp = *cp2; 101 } 102 103 *cp = '\0'; 104 105 if (flags & STR_DOFREE) { 106 free (s1); 107 free (s2); 108 } 109 return (result); 110 } 111 112 /*- 113 *----------------------------------------------------------------------- 114 * Str_New -- 115 * Create a new unique copy of the given string 116 * 117 * Results: 118 * A pointer to the new copy of it 119 * 120 * Side Effects: 121 * None 122 *----------------------------------------------------------------------- 123 */ 124 char * 125 Str_New (str) 126 char *str; /* string to duplicate */ 127 { 128 register char *cp; /* new space */ 129 130 cp = malloc (strlen (str) + 1); 131 (void) strcpy (cp, str); 132 return (cp); 133 } 134 135 static char 136 DoBackslash (c) 137 char c; 138 { 139 switch (c) { 140 case 'n': return ('\n'); 141 case 't': return ('\t'); 142 case 'b': return ('\b'); 143 case 'r': return ('\r'); 144 case 'f': return ('\f'); 145 default: return (c); 146 } 147 } 148 149 /*- 150 *----------------------------------------------------------------------- 151 * Str_BreakString -- 152 * Fracture a string into an array of words, taking quotation marks 153 * into account. The string should have its leading 'breaks' 154 * characters removed. 155 * 156 * Results: 157 * Pointer to the array of pointers to the words. This array must 158 * be freed by the caller. To make life easier, the first word is 159 * always the value of the .PMAKE variable. 160 * 161 * Side Effects: 162 * None. 163 * 164 *----------------------------------------------------------------------- 165 */ 166 char ** 167 Str_BreakString (str, breaks, end, argcPtr) 168 register char *str; /* String to fracture */ 169 register char *breaks; /* Word delimiters */ 170 register char *end; /* Characters to end on */ 171 int *argcPtr; /* OUT: Place to stuff number of 172 * words */ 173 { 174 char *defargv[256]; /* Temporary argument vector. 175 * Big enough for most purposes. */ 176 char **argv; /* Argv being built */ 177 int maxargc; /* Length of argv */ 178 register int argc; /* Count of words */ 179 char **av; /* Returned vector */ 180 register char *tstr; /* Pointer into tstring */ 181 char tstring[512]; /* Temporary storage for the 182 * current word */ 183 184 argc = 1; 185 argv = defargv; 186 maxargc = sizeof(defargv)/sizeof(defargv[0]); 187 argv[0] = Var_Value (".PMAKE", VAR_GLOBAL); 188 189 tstr = tstring; 190 while ((*str != '\0') && (index (end, *str) == (char *)NULL)) { 191 if (index (breaks, *str) != (char *)NULL) { 192 *tstr++ = '\0'; 193 argv[argc++] = Str_New(tstring); 194 while ((*str != '\0') && 195 (index (breaks, *str) != (char *)NULL) && 196 (index (end, *str) == (char *)NULL)) { 197 str++; 198 } 199 tstr = tstring; 200 /* 201 * Enlarge the argument vector, if necessary 202 */ 203 if (argc == maxargc) { 204 maxargc *= 2; 205 if (argv == defargv) { 206 argv = (char **)malloc(maxargc*sizeof(char *)); 207 bcopy(defargv, argv, sizeof(defargv)); 208 } else { 209 argv = (char **)realloc(argv, 210 maxargc*sizeof(char *)); 211 } 212 } 213 } else if (*str == '"') { 214 str += 1; 215 while ((*str != '"') && 216 (index (end, *str) == (char *)NULL)) { 217 if (*str == '\\') { 218 str += 1; 219 *tstr = DoBackslash(*str); 220 } else { 221 *tstr = *str; 222 } 223 str += 1; 224 tstr += 1; 225 } 226 227 if (*str == '"') { 228 str+=1; 229 } 230 } else if (*str == '\'') { 231 str += 1; 232 while ((*str != '\'') && 233 (index (end, *str) == (char *)NULL)) { 234 if (*str == '\\') { 235 str += 1; 236 *tstr = DoBackslash(*str); 237 } else { 238 *tstr = *str; 239 } 240 str += 1; 241 tstr += 1; 242 } 243 244 if (*str == '\'') { 245 str+=1; 246 } 247 } else if (*str == '\\') { 248 str += 1; 249 *tstr = DoBackslash(*str); 250 str += 1; 251 tstr += 1; 252 } else { 253 *tstr = *str; 254 tstr += 1; 255 str += 1; 256 } 257 } 258 if (tstr != tstring) { 259 /* 260 * If any word is left over, add it to the vector 261 */ 262 *tstr = '\0'; 263 argv[argc++] = Str_New(tstring); 264 } 265 argv[argc] = (char *) 0; 266 *argcPtr = argc; 267 if (argv == defargv) { 268 av = (char **) malloc ((argc+1) * sizeof(char *)); 269 bcopy ((char *)argv, (char *)av, (argc + 1) * sizeof(char *)); 270 } else { 271 /* 272 * Shrink vector to match actual number of args. 273 */ 274 av = (char **)realloc(argv, (argc+1) * sizeof(char *)); 275 } 276 277 return av; 278 } 279 280 /*- 281 *----------------------------------------------------------------------- 282 * Str_FreeVec -- 283 * Free a string vector returned by Str_BreakString. Frees all the 284 * strings in the vector and then frees the vector itself. 285 * 286 * Results: 287 * None. 288 * 289 * Side Effects: 290 * The blocks addressed by the vector are freed. 291 * 292 *----------------------------------------------------------------------- 293 */ 294 void 295 Str_FreeVec (count, vecPtr) 296 register int count; 297 register char **vecPtr; 298 { 299 for (count -= 1; count > 0; count -= 1) { 300 free (vecPtr[count]); 301 } 302 free (vecPtr); 303 } 304 #ifndef Sprite 305 306 /* 307 *---------------------------------------------------------------------- 308 * Str_FindSubstring -- 309 * See if a string contains a particular substring. 310 * 311 * Results: 312 * If string contains substring, the return value is the 313 * location of the first matching instance of substring 314 * in string. If string doesn't contain substring, the 315 * return value is NULL. Matching is done on an exact 316 * character-for-character basis with no wildcards or special 317 * characters. 318 * 319 * Side effects: 320 * None. 321 *---------------------------------------------------------------------- 322 */ 323 char * 324 Str_FindSubstring(string, substring) 325 register char *string; /* String to search. */ 326 char *substring; /* Substring to try to find in string. */ 327 { 328 register char *a, *b; 329 330 /* 331 * First scan quickly through the two strings looking for a 332 * single-character match. When it's found, then compare the 333 * rest of the substring. 334 */ 335 336 b = substring; 337 for ( ; *string != 0; string += 1) { 338 if (*string != *b) { 339 continue; 340 } 341 a = string; 342 while (TRUE) { 343 if (*b == 0) { 344 return string; 345 } 346 if (*a++ != *b++) { 347 break; 348 } 349 } 350 b = substring; 351 } 352 return (char *) NULL; 353 } 354 355 #endif /* !Sprite */ 356 357 /* 358 *---------------------------------------------------------------------- 359 * 360 * Str_Match -- 361 * 362 * See if a particular string matches a particular pattern. 363 * 364 * Results: 365 * Non-zero is returned if string matches pattern, 0 otherwise. 366 * The matching operation permits the following special characters 367 * in the pattern: *?\[] (see the man page for details on what 368 * these mean). 369 * 370 * Side effects: 371 * None. 372 * 373 *---------------------------------------------------------------------- 374 */ 375 376 int 377 Str_Match(string, pattern) 378 register char *string; /* String. */ 379 register char *pattern; /* Pattern, which may contain 380 * special characters. 381 */ 382 { 383 char c2; 384 385 while (1) { 386 /* See if we're at the end of both the pattern and the string. 387 * If, we succeeded. If we're at the end of the pattern but 388 * not at the end of the string, we failed. 389 */ 390 391 if (*pattern == 0) { 392 if (*string == 0) { 393 return 1; 394 } else { 395 return 0; 396 } 397 } 398 if ((*string == 0) && (*pattern != '*')) { 399 return 0; 400 } 401 402 /* Check for a "*" as the next pattern character. It matches 403 * any substring. We handle this by calling ourselves 404 * recursively for each postfix of string, until either we 405 * match or we reach the end of the string. 406 */ 407 408 if (*pattern == '*') { 409 pattern += 1; 410 if (*pattern == 0) { 411 return 1; 412 } 413 while (*string != 0) { 414 if (Str_Match(string, pattern)) { 415 return 1; 416 } 417 string += 1; 418 } 419 return 0; 420 } 421 422 /* Check for a "?" as the next pattern character. It matches 423 * any single character. 424 */ 425 426 if (*pattern == '?') { 427 goto thisCharOK; 428 } 429 430 /* Check for a "[" as the next pattern character. It is followed 431 * by a list of characters that are acceptable, or by a range 432 * (two characters separated by "-"). 433 */ 434 435 if (*pattern == '[') { 436 pattern += 1; 437 while (1) { 438 if ((*pattern == ']') || (*pattern == 0)) { 439 return 0; 440 } 441 if (*pattern == *string) { 442 break; 443 } 444 if (pattern[1] == '-') { 445 c2 = pattern[2]; 446 if (c2 == 0) { 447 return 0; 448 } 449 if ((*pattern <= *string) && (c2 >= *string)) { 450 break; 451 } 452 if ((*pattern >= *string) && (c2 <= *string)) { 453 break; 454 } 455 pattern += 2; 456 } 457 pattern += 1; 458 } 459 while ((*pattern != ']') && (*pattern != 0)) { 460 pattern += 1; 461 } 462 goto thisCharOK; 463 } 464 465 /* If the next pattern character is '/', just strip off the '/' 466 * so we do exact matching on the character that follows. 467 */ 468 469 if (*pattern == '\\') { 470 pattern += 1; 471 if (*pattern == 0) { 472 return 0; 473 } 474 } 475 476 /* There's no special character. Just make sure that the next 477 * characters of each string match. 478 */ 479 480 if (*pattern != *string) { 481 return 0; 482 } 483 484 thisCharOK: pattern += 1; 485 string += 1; 486 } 487 } 488