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.3 (Berkeley) 03/19/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 continue; 118 case ' ': 119 case '\t': 120 if (inquote) 121 break; 122 if (!start) 123 continue; 124 /* FALLTHROUGH */ 125 case '\n': 126 case '\0': 127 /* 128 * end of a token -- make sure there's enough argv 129 * space and save off a pointer. 130 */ 131 *t++ = '\0'; 132 if (argc == argmax) { 133 argmax *= 2; /* ramp up fast */ 134 if (!(argv = (char **)realloc(argv, 135 argmax * sizeof(char *)))) 136 enomem(); 137 } 138 argv[argc++] = start; 139 start = (char *)NULL; 140 if (ch == '\n' || ch == '\0') 141 goto done; 142 continue; 143 case '\\': 144 switch (ch = *++p) { 145 case '\0': 146 case '\n': 147 /* hmmm; fix it up as best we can */ 148 ch = '\\'; 149 --p; 150 break; 151 case 'b': 152 ch = '\b'; 153 break; 154 case 'f': 155 ch = '\f'; 156 break; 157 case 'n': 158 ch = '\n'; 159 break; 160 case 'r': 161 ch = '\r'; 162 break; 163 case 't': 164 ch = '\t'; 165 break; 166 } 167 break; 168 } 169 if (!start) 170 start = t; 171 *t++ = (char) ch; 172 } 173 done: argv[argc] = (char *)NULL; 174 *store_argc = argc; 175 return(argv); 176 } 177 178 /* 179 * Str_FindSubstring -- See if a string contains a particular substring. 180 * 181 * Results: If string contains substring, the return value is the location of 182 * the first matching instance of substring in string. If string doesn't 183 * contain substring, the return value is NULL. Matching is done on an exact 184 * character-for-character basis with no wildcards or special characters. 185 * 186 * Side effects: None. 187 */ 188 char * 189 Str_FindSubstring(string, substring) 190 register char *string; /* String to search. */ 191 char *substring; /* Substring to find in string */ 192 { 193 register char *a, *b; 194 195 /* 196 * First scan quickly through the two strings looking for a single- 197 * character match. When it's found, then compare the rest of the 198 * substring. 199 */ 200 201 for (b = substring; *string != 0; string += 1) { 202 if (*string != *b) 203 continue; 204 a = string; 205 for (;;) { 206 if (*b == 0) 207 return(string); 208 if (*a++ != *b++) 209 break; 210 } 211 b = substring; 212 } 213 return((char *) NULL); 214 } 215 216 /* 217 * Str_Match -- 218 * 219 * See if a particular string matches a particular pattern. 220 * 221 * Results: Non-zero is returned if string matches pattern, 0 otherwise. The 222 * matching operation permits the following special characters in the 223 * pattern: *?\[] (see the man page for details on what these mean). 224 * 225 * Side effects: None. 226 */ 227 int 228 Str_Match(string, pattern) 229 register char *string; /* String */ 230 register char *pattern; /* Pattern */ 231 { 232 char c2; 233 234 for (;;) { 235 /* 236 * See if we're at the end of both the pattern and the 237 * string. If, we succeeded. If we're at the end of the 238 * pattern but not at the end of the string, we failed. 239 */ 240 if (*pattern == 0) 241 return(!*string); 242 if (*string == 0 && *pattern != '*') 243 return(0); 244 /* 245 * Check for a "*" as the next pattern character. It matches 246 * any substring. We handle this by calling ourselves 247 * recursively for each postfix of string, until either we 248 * match or we reach the end of the string. 249 */ 250 if (*pattern == '*') { 251 pattern += 1; 252 if (*pattern == 0) 253 return(1); 254 while (*string != 0) { 255 if (Str_Match(string, pattern)) 256 return(1); 257 ++string; 258 } 259 return(0); 260 } 261 /* 262 * Check for a "?" as the next pattern character. It matches 263 * any single character. 264 */ 265 if (*pattern == '?') 266 goto thisCharOK; 267 /* 268 * Check for a "[" as the next pattern character. It is 269 * followed by a list of characters that are acceptable, or 270 * by a range (two characters separated by "-"). 271 */ 272 if (*pattern == '[') { 273 ++pattern; 274 for (;;) { 275 if ((*pattern == ']') || (*pattern == 0)) 276 return(0); 277 if (*pattern == *string) 278 break; 279 if (pattern[1] == '-') { 280 c2 = pattern[2]; 281 if (c2 == 0) 282 return(0); 283 if ((*pattern <= *string) && 284 (c2 >= *string)) 285 break; 286 if ((*pattern >= *string) && 287 (c2 <= *string)) 288 break; 289 pattern += 2; 290 } 291 ++pattern; 292 } 293 while ((*pattern != ']') && (*pattern != 0)) 294 ++pattern; 295 goto thisCharOK; 296 } 297 /* 298 * If the next pattern character is '/', just strip off the 299 * '/' so we do exact matching on the character that follows. 300 */ 301 if (*pattern == '\\') { 302 ++pattern; 303 if (*pattern == 0) 304 return(0); 305 } 306 /* 307 * There's no special character. Just make sure that the 308 * next characters of each string match. 309 */ 310 if (*pattern != *string) 311 return(0); 312 thisCharOK: ++pattern; 313 ++string; 314 } 315 } 316 317 318 /*- 319 *----------------------------------------------------------------------- 320 * Str_SYSVMatch -- 321 * Check word against pattern for a match (% is wild), 322 * 323 * Results: 324 * Returns the beginning position of a match or null. The number 325 * of characters matched is returned in len. 326 * 327 * Side Effects: 328 * None 329 * 330 *----------------------------------------------------------------------- 331 */ 332 char * 333 Str_SYSVMatch(word, pattern, len) 334 char *word; /* Word to examine */ 335 char *pattern; /* Pattern to examine against */ 336 int *len; /* Number of characters to substitute */ 337 { 338 char *p = pattern; 339 char *w = word; 340 char *m; 341 342 if (*p == '\0') 343 return NULL; 344 345 if ((m = strchr(p, '%')) != NULL) { 346 /* check that the prefix matches */ 347 for (; p != m && *w && *w == *p; w++, p++) 348 continue; 349 350 if (p != m) 351 return NULL; /* No match */ 352 353 if (*++p == '\0') { 354 /* No more pattern, return the rest of the string */ 355 *len = strlen(w); 356 return w; 357 } 358 } 359 360 m = w; 361 362 /* Find a matching tail */ 363 do 364 if (strcmp(p, w) == 0) { 365 *len = w - m; 366 return m; 367 } 368 while (*w++ != '\0'); 369 370 return NULL; 371 } 372 373 374 /*- 375 *----------------------------------------------------------------------- 376 * Str_SYSVSubst -- 377 * Substitute '%' on the pattern with len characters from src. 378 * If the pattern does not contain a '%' prepend len characters 379 * from src. 380 * 381 * Results: 382 * None 383 * 384 * Side Effects: 385 * Places result on buf 386 * 387 *----------------------------------------------------------------------- 388 */ 389 void 390 Str_SYSVSubst(buf, pat, src, len) 391 Buffer buf; 392 char *pat; 393 char *src; 394 int len; 395 { 396 char *m; 397 398 if ((m = strchr(pat, '%')) != NULL) { 399 /* Copy the prefix */ 400 Buf_AddBytes(buf, m - pat, (Byte *) pat); 401 /* skip the % */ 402 pat = m + 1; 403 } 404 405 /* Copy the pattern */ 406 Buf_AddBytes(buf, len, (Byte *) src); 407 408 /* append the rest */ 409 Buf_AddBytes(buf, strlen(pat), (Byte *) pat); 410 } 411