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