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