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 * %sccs.include.redist.c% 11 */ 12 13 #ifndef lint 14 static char sccsid[] = "@(#)str.c 5.8 (Berkeley) 06/01/90"; 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 bcopy(s1, result, 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 bcopy(s2, result + len1, 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 95 /* allocate room for a copy of the string */ 96 if ((len = strlen(str) + 1) > curlen) 97 buf = emalloc(curlen = len); 98 99 /* 100 * copy the string; at the same time, parse backslashes, 101 * quotes and build the argument list. 102 */ 103 argc = 1; 104 inquote = '\0'; 105 for (p = str, start = t = buf;; ++p) { 106 switch(ch = *p) { 107 case '"': 108 case '\'': 109 if (inquote) 110 if (inquote == ch) 111 inquote = NULL; 112 else 113 break; 114 else 115 inquote = ch; 116 continue; 117 case ' ': 118 case '\t': 119 if (inquote) 120 break; 121 if (!start) 122 continue; 123 /* FALLTHROUGH */ 124 case '\n': 125 case '\0': 126 /* 127 * end of a token -- make sure there's enough argv 128 * space and save off a pointer. 129 */ 130 *t++ = '\0'; 131 if (argc == argmax) { 132 argmax *= 2; /* ramp up fast */ 133 if (!(argv = (char **)realloc(argv, 134 argmax * sizeof(char *)))) 135 enomem(); 136 } 137 argv[argc++] = start; 138 start = (char *)NULL; 139 if (ch == '\n' || ch == '\0') 140 goto done; 141 continue; 142 case '\\': 143 switch (ch = *++p) { 144 case '\0': 145 case '\n': 146 /* hmmm; fix it up as best we can */ 147 ch = '\\'; 148 --p; 149 break; 150 case 'b': 151 ch = '\b'; 152 break; 153 case 'f': 154 ch = '\f'; 155 break; 156 case 'n': 157 ch = '\n'; 158 break; 159 case 'r': 160 ch = '\r'; 161 break; 162 case 't': 163 ch = '\t'; 164 break; 165 } 166 break; 167 } 168 if (!start) 169 start = t; 170 *t++ = ch; 171 } 172 done: argv[argc] = (char *)NULL; 173 *store_argc = argc; 174 return(argv); 175 } 176 177 /* 178 * Str_FindSubstring -- See if a string contains a particular substring. 179 * 180 * Results: If string contains substring, the return value is the location of 181 * the first matching instance of substring in string. If string doesn't 182 * contain substring, the return value is NULL. Matching is done on an exact 183 * character-for-character basis with no wildcards or special characters. 184 * 185 * Side effects: None. 186 */ 187 char * 188 Str_FindSubstring(string, substring) 189 register char *string; /* String to search. */ 190 char *substring; /* Substring to find in string */ 191 { 192 register char *a, *b; 193 194 /* 195 * First scan quickly through the two strings looking for a single- 196 * character match. When it's found, then compare the rest of the 197 * substring. 198 */ 199 200 for (b = substring; *string != 0; string += 1) { 201 if (*string != *b) 202 continue; 203 a = string; 204 for (;;) { 205 if (*b == 0) 206 return(string); 207 if (*a++ != *b++) 208 break; 209 } 210 b = substring; 211 } 212 return((char *) NULL); 213 } 214 215 /* 216 * Str_Match -- 217 * 218 * See if a particular string matches a particular pattern. 219 * 220 * Results: Non-zero is returned if string matches pattern, 0 otherwise. The 221 * matching operation permits the following special characters in the 222 * pattern: *?\[] (see the man page for details on what these mean). 223 * 224 * Side effects: None. 225 */ 226 Str_Match(string, pattern) 227 register char *string; /* String */ 228 register char *pattern; /* Pattern */ 229 { 230 char c2; 231 232 for (;;) { 233 /* 234 * See if we're at the end of both the pattern and the 235 * string. If, we succeeded. If we're at the end of the 236 * pattern but not at the end of the string, we failed. 237 */ 238 if (*pattern == 0) 239 return(!*string); 240 if (*string == 0 && *pattern != '*') 241 return(0); 242 /* 243 * Check for a "*" as the next pattern character. It matches 244 * any substring. We handle this by calling ourselves 245 * recursively for each postfix of string, until either we 246 * match or we reach the end of the string. 247 */ 248 if (*pattern == '*') { 249 pattern += 1; 250 if (*pattern == 0) 251 return(1); 252 while (*string != 0) { 253 if (Str_Match(string, pattern)) 254 return(1); 255 ++string; 256 } 257 return(0); 258 } 259 /* 260 * Check for a "?" as the next pattern character. It matches 261 * any single character. 262 */ 263 if (*pattern == '?') 264 goto thisCharOK; 265 /* 266 * Check for a "[" as the next pattern character. It is 267 * followed by a list of characters that are acceptable, or 268 * by a range (two characters separated by "-"). 269 */ 270 if (*pattern == '[') { 271 ++pattern; 272 for (;;) { 273 if ((*pattern == ']') || (*pattern == 0)) 274 return(0); 275 if (*pattern == *string) 276 break; 277 if (pattern[1] == '-') { 278 c2 = pattern[2]; 279 if (c2 == 0) 280 return(0); 281 if ((*pattern <= *string) && 282 (c2 >= *string)) 283 break; 284 if ((*pattern >= *string) && 285 (c2 <= *string)) 286 break; 287 pattern += 2; 288 } 289 ++pattern; 290 } 291 while ((*pattern != ']') && (*pattern != 0)) 292 ++pattern; 293 goto thisCharOK; 294 } 295 /* 296 * If the next pattern character is '/', just strip off the 297 * '/' so we do exact matching on the character that follows. 298 */ 299 if (*pattern == '\\') { 300 ++pattern; 301 if (*pattern == 0) 302 return(0); 303 } 304 /* 305 * There's no special character. Just make sure that the 306 * next characters of each string match. 307 */ 308 if (*pattern != *string) 309 return(0); 310 thisCharOK: ++pattern; 311 ++string; 312 } 313 } 314