1321964Ssjg/* $NetBSD: str.c,v 1.38 2017/04/21 22:15:44 sjg Exp $ */ 2236769Sobrien 3236769Sobrien/*- 4236769Sobrien * Copyright (c) 1988, 1989, 1990, 1993 5236769Sobrien * The Regents of the University of California. All rights reserved. 6236769Sobrien * 7236769Sobrien * This code is derived from software contributed to Berkeley by 8236769Sobrien * Adam de Boor. 9236769Sobrien * 10236769Sobrien * Redistribution and use in source and binary forms, with or without 11236769Sobrien * modification, are permitted provided that the following conditions 12236769Sobrien * are met: 13236769Sobrien * 1. Redistributions of source code must retain the above copyright 14236769Sobrien * notice, this list of conditions and the following disclaimer. 15236769Sobrien * 2. Redistributions in binary form must reproduce the above copyright 16236769Sobrien * notice, this list of conditions and the following disclaimer in the 17236769Sobrien * documentation and/or other materials provided with the distribution. 18236769Sobrien * 3. Neither the name of the University nor the names of its contributors 19236769Sobrien * may be used to endorse or promote products derived from this software 20236769Sobrien * without specific prior written permission. 21236769Sobrien * 22236769Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23236769Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24236769Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25236769Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26236769Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27236769Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28236769Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29236769Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30236769Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31236769Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32236769Sobrien * SUCH DAMAGE. 33236769Sobrien */ 34236769Sobrien 35236769Sobrien/*- 36236769Sobrien * Copyright (c) 1989 by Berkeley Softworks 37236769Sobrien * All rights reserved. 38236769Sobrien * 39236769Sobrien * This code is derived from software contributed to Berkeley by 40236769Sobrien * Adam de Boor. 41236769Sobrien * 42236769Sobrien * Redistribution and use in source and binary forms, with or without 43236769Sobrien * modification, are permitted provided that the following conditions 44236769Sobrien * are met: 45236769Sobrien * 1. Redistributions of source code must retain the above copyright 46236769Sobrien * notice, this list of conditions and the following disclaimer. 47236769Sobrien * 2. Redistributions in binary form must reproduce the above copyright 48236769Sobrien * notice, this list of conditions and the following disclaimer in the 49236769Sobrien * documentation and/or other materials provided with the distribution. 50236769Sobrien * 3. All advertising materials mentioning features or use of this software 51236769Sobrien * must display the following acknowledgement: 52236769Sobrien * This product includes software developed by the University of 53236769Sobrien * California, Berkeley and its contributors. 54236769Sobrien * 4. Neither the name of the University nor the names of its contributors 55236769Sobrien * may be used to endorse or promote products derived from this software 56236769Sobrien * without specific prior written permission. 57236769Sobrien * 58236769Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 59236769Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 60236769Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 61236769Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 62236769Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 63236769Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 64236769Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65236769Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66236769Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 67236769Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 68236769Sobrien * SUCH DAMAGE. 69236769Sobrien */ 70236769Sobrien 71236769Sobrien#ifndef MAKE_NATIVE 72321964Ssjgstatic char rcsid[] = "$NetBSD: str.c,v 1.38 2017/04/21 22:15:44 sjg Exp $"; 73236769Sobrien#else 74236769Sobrien#include <sys/cdefs.h> 75236769Sobrien#ifndef lint 76236769Sobrien#if 0 77236769Sobrienstatic char sccsid[] = "@(#)str.c 5.8 (Berkeley) 6/1/90"; 78236769Sobrien#else 79321964Ssjg__RCSID("$NetBSD: str.c,v 1.38 2017/04/21 22:15:44 sjg Exp $"); 80236769Sobrien#endif 81236769Sobrien#endif /* not lint */ 82236769Sobrien#endif 83236769Sobrien 84236769Sobrien#include "make.h" 85236769Sobrien 86236769Sobrien/*- 87236769Sobrien * str_concat -- 88236769Sobrien * concatenate the two strings, inserting a space or slash between them, 89236769Sobrien * freeing them if requested. 90236769Sobrien * 91236769Sobrien * returns -- 92236769Sobrien * the resulting string in allocated space. 93236769Sobrien */ 94236769Sobrienchar * 95236769Sobrienstr_concat(const char *s1, const char *s2, int flags) 96236769Sobrien{ 97236769Sobrien int len1, len2; 98236769Sobrien char *result; 99236769Sobrien 100236769Sobrien /* get the length of both strings */ 101236769Sobrien len1 = strlen(s1); 102236769Sobrien len2 = strlen(s2); 103236769Sobrien 104236769Sobrien /* allocate length plus separator plus EOS */ 105321964Ssjg result = bmake_malloc((unsigned int)(len1 + len2 + 2)); 106236769Sobrien 107236769Sobrien /* copy first string into place */ 108236769Sobrien memcpy(result, s1, len1); 109236769Sobrien 110236769Sobrien /* add separator character */ 111236769Sobrien if (flags & STR_ADDSPACE) { 112236769Sobrien result[len1] = ' '; 113236769Sobrien ++len1; 114236769Sobrien } else if (flags & STR_ADDSLASH) { 115236769Sobrien result[len1] = '/'; 116236769Sobrien ++len1; 117236769Sobrien } 118236769Sobrien 119236769Sobrien /* copy second string plus EOS into place */ 120236769Sobrien memcpy(result + len1, s2, len2 + 1); 121236769Sobrien 122236769Sobrien return(result); 123236769Sobrien} 124236769Sobrien 125236769Sobrien/*- 126236769Sobrien * brk_string -- 127236769Sobrien * Fracture a string into an array of words (as delineated by tabs or 128236769Sobrien * spaces) taking quotation marks into account. Leading tabs/spaces 129236769Sobrien * are ignored. 130236769Sobrien * 131236769Sobrien * If expand is TRUE, quotes are removed and escape sequences 132236769Sobrien * such as \r, \t, etc... are expanded. 133236769Sobrien * 134236769Sobrien * returns -- 135236769Sobrien * Pointer to the array of pointers to the words. 136236769Sobrien * Memory containing the actual words in *buffer. 137236769Sobrien * Both of these must be free'd by the caller. 138236769Sobrien * Number of words in *store_argc. 139236769Sobrien */ 140236769Sobrienchar ** 141236769Sobrienbrk_string(const char *str, int *store_argc, Boolean expand, char **buffer) 142236769Sobrien{ 143236769Sobrien int argc, ch; 144236769Sobrien char inquote, *start, *t; 145236769Sobrien const char *p; 146236769Sobrien int len; 147236769Sobrien int argmax = 50, curlen = 0; 148276305Sngie char **argv; 149236769Sobrien 150236769Sobrien /* skip leading space chars. */ 151236769Sobrien for (; *str == ' ' || *str == '\t'; ++str) 152236769Sobrien continue; 153236769Sobrien 154236769Sobrien /* allocate room for a copy of the string */ 155236769Sobrien if ((len = strlen(str) + 1) > curlen) 156236769Sobrien *buffer = bmake_malloc(curlen = len); 157236769Sobrien 158236769Sobrien /* 159276305Sngie * initial argmax based on len 160276305Sngie */ 161276305Sngie argmax = MAX((len / 5), 50); 162276305Sngie argv = bmake_malloc((argmax + 1) * sizeof(char *)); 163276305Sngie 164276305Sngie /* 165236769Sobrien * copy the string; at the same time, parse backslashes, 166236769Sobrien * quotes and build the argument list. 167236769Sobrien */ 168236769Sobrien argc = 0; 169236769Sobrien inquote = '\0'; 170236769Sobrien for (p = str, start = t = *buffer;; ++p) { 171236769Sobrien switch(ch = *p) { 172236769Sobrien case '"': 173236769Sobrien case '\'': 174236769Sobrien if (inquote) { 175236769Sobrien if (inquote == ch) 176236769Sobrien inquote = '\0'; 177236769Sobrien else 178236769Sobrien break; 179236769Sobrien } 180236769Sobrien else { 181236769Sobrien inquote = (char) ch; 182236769Sobrien /* Don't miss "" or '' */ 183236769Sobrien if (start == NULL && p[1] == inquote) { 184236769Sobrien if (!expand) { 185236769Sobrien start = t; 186236769Sobrien *t++ = ch; 187236769Sobrien } else 188236769Sobrien start = t + 1; 189236769Sobrien p++; 190236769Sobrien inquote = '\0'; 191236769Sobrien break; 192236769Sobrien } 193236769Sobrien } 194236769Sobrien if (!expand) { 195236769Sobrien if (!start) 196236769Sobrien start = t; 197236769Sobrien *t++ = ch; 198236769Sobrien } 199236769Sobrien continue; 200236769Sobrien case ' ': 201236769Sobrien case '\t': 202236769Sobrien case '\n': 203236769Sobrien if (inquote) 204236769Sobrien break; 205236769Sobrien if (!start) 206236769Sobrien continue; 207236769Sobrien /* FALLTHROUGH */ 208236769Sobrien case '\0': 209236769Sobrien /* 210236769Sobrien * end of a token -- make sure there's enough argv 211236769Sobrien * space and save off a pointer. 212236769Sobrien */ 213236769Sobrien if (!start) 214236769Sobrien goto done; 215236769Sobrien 216236769Sobrien *t++ = '\0'; 217236769Sobrien if (argc == argmax) { 218236769Sobrien argmax *= 2; /* ramp up fast */ 219236769Sobrien argv = (char **)bmake_realloc(argv, 220236769Sobrien (argmax + 1) * sizeof(char *)); 221236769Sobrien } 222236769Sobrien argv[argc++] = start; 223236769Sobrien start = NULL; 224236769Sobrien if (ch == '\n' || ch == '\0') { 225236769Sobrien if (expand && inquote) { 226236769Sobrien free(argv); 227236769Sobrien free(*buffer); 228236769Sobrien *buffer = NULL; 229236769Sobrien return NULL; 230236769Sobrien } 231236769Sobrien goto done; 232236769Sobrien } 233236769Sobrien continue; 234236769Sobrien case '\\': 235236769Sobrien if (!expand) { 236236769Sobrien if (!start) 237236769Sobrien start = t; 238236769Sobrien *t++ = '\\'; 239236769Sobrien if (*(p+1) == '\0') /* catch '\' at end of line */ 240236769Sobrien continue; 241236769Sobrien ch = *++p; 242236769Sobrien break; 243236769Sobrien } 244236769Sobrien 245236769Sobrien switch (ch = *++p) { 246236769Sobrien case '\0': 247236769Sobrien case '\n': 248236769Sobrien /* hmmm; fix it up as best we can */ 249236769Sobrien ch = '\\'; 250236769Sobrien --p; 251236769Sobrien break; 252236769Sobrien case 'b': 253236769Sobrien ch = '\b'; 254236769Sobrien break; 255236769Sobrien case 'f': 256236769Sobrien ch = '\f'; 257236769Sobrien break; 258236769Sobrien case 'n': 259236769Sobrien ch = '\n'; 260236769Sobrien break; 261236769Sobrien case 'r': 262236769Sobrien ch = '\r'; 263236769Sobrien break; 264236769Sobrien case 't': 265236769Sobrien ch = '\t'; 266236769Sobrien break; 267236769Sobrien } 268236769Sobrien break; 269236769Sobrien } 270236769Sobrien if (!start) 271236769Sobrien start = t; 272236769Sobrien *t++ = (char) ch; 273236769Sobrien } 274236769Sobriendone: argv[argc] = NULL; 275236769Sobrien *store_argc = argc; 276236769Sobrien return(argv); 277236769Sobrien} 278236769Sobrien 279236769Sobrien/* 280236769Sobrien * Str_FindSubstring -- See if a string contains a particular substring. 281236769Sobrien * 282236769Sobrien * Input: 283236769Sobrien * string String to search. 284236769Sobrien * substring Substring to find in string. 285236769Sobrien * 286236769Sobrien * Results: If string contains substring, the return value is the location of 287236769Sobrien * the first matching instance of substring in string. If string doesn't 288236769Sobrien * contain substring, the return value is NULL. Matching is done on an exact 289236769Sobrien * character-for-character basis with no wildcards or special characters. 290236769Sobrien * 291236769Sobrien * Side effects: None. 292236769Sobrien */ 293236769Sobrienchar * 294236769SobrienStr_FindSubstring(const char *string, const char *substring) 295236769Sobrien{ 296236769Sobrien const char *a, *b; 297236769Sobrien 298236769Sobrien /* 299236769Sobrien * First scan quickly through the two strings looking for a single- 300236769Sobrien * character match. When it's found, then compare the rest of the 301236769Sobrien * substring. 302236769Sobrien */ 303236769Sobrien 304236769Sobrien for (b = substring; *string != 0; string += 1) { 305236769Sobrien if (*string != *b) 306236769Sobrien continue; 307236769Sobrien a = string; 308236769Sobrien for (;;) { 309236769Sobrien if (*b == 0) 310236769Sobrien return UNCONST(string); 311236769Sobrien if (*a++ != *b++) 312236769Sobrien break; 313236769Sobrien } 314236769Sobrien b = substring; 315236769Sobrien } 316236769Sobrien return NULL; 317236769Sobrien} 318236769Sobrien 319236769Sobrien/* 320236769Sobrien * Str_Match -- 321236769Sobrien * 322236769Sobrien * See if a particular string matches a particular pattern. 323236769Sobrien * 324236769Sobrien * Results: Non-zero is returned if string matches pattern, 0 otherwise. The 325236769Sobrien * matching operation permits the following special characters in the 326236769Sobrien * pattern: *?\[] (see the man page for details on what these mean). 327236769Sobrien * 328236769Sobrien * XXX this function does not detect or report malformed patterns. 329236769Sobrien * 330236769Sobrien * Side effects: None. 331236769Sobrien */ 332236769Sobrienint 333236769SobrienStr_Match(const char *string, const char *pattern) 334236769Sobrien{ 335236769Sobrien char c2; 336236769Sobrien 337236769Sobrien for (;;) { 338236769Sobrien /* 339236769Sobrien * See if we're at the end of both the pattern and the 340236769Sobrien * string. If, we succeeded. If we're at the end of the 341236769Sobrien * pattern but not at the end of the string, we failed. 342236769Sobrien */ 343236769Sobrien if (*pattern == 0) 344236769Sobrien return(!*string); 345236769Sobrien if (*string == 0 && *pattern != '*') 346236769Sobrien return(0); 347236769Sobrien /* 348236769Sobrien * Check for a "*" as the next pattern character. It matches 349236769Sobrien * any substring. We handle this by calling ourselves 350236769Sobrien * recursively for each postfix of string, until either we 351236769Sobrien * match or we reach the end of the string. 352236769Sobrien */ 353236769Sobrien if (*pattern == '*') { 354236769Sobrien pattern += 1; 355236769Sobrien if (*pattern == 0) 356236769Sobrien return(1); 357236769Sobrien while (*string != 0) { 358236769Sobrien if (Str_Match(string, pattern)) 359236769Sobrien return(1); 360236769Sobrien ++string; 361236769Sobrien } 362236769Sobrien return(0); 363236769Sobrien } 364236769Sobrien /* 365236769Sobrien * Check for a "?" as the next pattern character. It matches 366236769Sobrien * any single character. 367236769Sobrien */ 368236769Sobrien if (*pattern == '?') 369236769Sobrien goto thisCharOK; 370236769Sobrien /* 371236769Sobrien * Check for a "[" as the next pattern character. It is 372236769Sobrien * followed by a list of characters that are acceptable, or 373236769Sobrien * by a range (two characters separated by "-"). 374236769Sobrien */ 375236769Sobrien if (*pattern == '[') { 376321964Ssjg int nomatch; 377321964Ssjg 378236769Sobrien ++pattern; 379321964Ssjg if (*pattern == '^') { 380321964Ssjg ++pattern; 381321964Ssjg nomatch = 1; 382321964Ssjg } else 383321964Ssjg nomatch = 0; 384236769Sobrien for (;;) { 385321964Ssjg if ((*pattern == ']') || (*pattern == 0)) { 386321964Ssjg if (nomatch) 387321964Ssjg break; 388236769Sobrien return(0); 389321964Ssjg } 390236769Sobrien if (*pattern == *string) 391236769Sobrien break; 392236769Sobrien if (pattern[1] == '-') { 393236769Sobrien c2 = pattern[2]; 394236769Sobrien if (c2 == 0) 395321964Ssjg return(nomatch); 396236769Sobrien if ((*pattern <= *string) && 397236769Sobrien (c2 >= *string)) 398236769Sobrien break; 399236769Sobrien if ((*pattern >= *string) && 400236769Sobrien (c2 <= *string)) 401236769Sobrien break; 402236769Sobrien pattern += 2; 403236769Sobrien } 404236769Sobrien ++pattern; 405236769Sobrien } 406321964Ssjg if (nomatch && (*pattern != ']') && (*pattern != 0)) 407321964Ssjg return 0; 408236769Sobrien while ((*pattern != ']') && (*pattern != 0)) 409236769Sobrien ++pattern; 410236769Sobrien goto thisCharOK; 411236769Sobrien } 412236769Sobrien /* 413236769Sobrien * If the next pattern character is '/', just strip off the 414236769Sobrien * '/' so we do exact matching on the character that follows. 415236769Sobrien */ 416236769Sobrien if (*pattern == '\\') { 417236769Sobrien ++pattern; 418236769Sobrien if (*pattern == 0) 419236769Sobrien return(0); 420236769Sobrien } 421236769Sobrien /* 422236769Sobrien * There's no special character. Just make sure that the 423236769Sobrien * next characters of each string match. 424236769Sobrien */ 425236769Sobrien if (*pattern != *string) 426236769Sobrien return(0); 427236769SobrienthisCharOK: ++pattern; 428236769Sobrien ++string; 429236769Sobrien } 430236769Sobrien} 431236769Sobrien 432236769Sobrien 433236769Sobrien/*- 434236769Sobrien *----------------------------------------------------------------------- 435236769Sobrien * Str_SYSVMatch -- 436236769Sobrien * Check word against pattern for a match (% is wild), 437236769Sobrien * 438236769Sobrien * Input: 439236769Sobrien * word Word to examine 440236769Sobrien * pattern Pattern to examine against 441236769Sobrien * len Number of characters to substitute 442236769Sobrien * 443236769Sobrien * Results: 444236769Sobrien * Returns the beginning position of a match or null. The number 445236769Sobrien * of characters matched is returned in len. 446236769Sobrien * 447236769Sobrien * Side Effects: 448236769Sobrien * None 449236769Sobrien * 450236769Sobrien *----------------------------------------------------------------------- 451236769Sobrien */ 452236769Sobrienchar * 453236769SobrienStr_SYSVMatch(const char *word, const char *pattern, int *len) 454236769Sobrien{ 455236769Sobrien const char *p = pattern; 456236769Sobrien const char *w = word; 457236769Sobrien const char *m; 458236769Sobrien 459236769Sobrien if (*p == '\0') { 460236769Sobrien /* Null pattern is the whole string */ 461236769Sobrien *len = strlen(w); 462236769Sobrien return UNCONST(w); 463236769Sobrien } 464236769Sobrien 465236769Sobrien if ((m = strchr(p, '%')) != NULL) { 466236769Sobrien /* check that the prefix matches */ 467236769Sobrien for (; p != m && *w && *w == *p; w++, p++) 468236769Sobrien continue; 469236769Sobrien 470236769Sobrien if (p != m) 471236769Sobrien return NULL; /* No match */ 472236769Sobrien 473236769Sobrien if (*++p == '\0') { 474236769Sobrien /* No more pattern, return the rest of the string */ 475236769Sobrien *len = strlen(w); 476236769Sobrien return UNCONST(w); 477236769Sobrien } 478236769Sobrien } 479236769Sobrien 480236769Sobrien m = w; 481236769Sobrien 482236769Sobrien /* Find a matching tail */ 483236769Sobrien do 484236769Sobrien if (strcmp(p, w) == 0) { 485236769Sobrien *len = w - m; 486236769Sobrien return UNCONST(m); 487236769Sobrien } 488236769Sobrien while (*w++ != '\0'); 489236769Sobrien 490236769Sobrien return NULL; 491236769Sobrien} 492236769Sobrien 493236769Sobrien 494236769Sobrien/*- 495236769Sobrien *----------------------------------------------------------------------- 496236769Sobrien * Str_SYSVSubst -- 497236769Sobrien * Substitute '%' on the pattern with len characters from src. 498236769Sobrien * If the pattern does not contain a '%' prepend len characters 499236769Sobrien * from src. 500236769Sobrien * 501236769Sobrien * Results: 502236769Sobrien * None 503236769Sobrien * 504236769Sobrien * Side Effects: 505236769Sobrien * Places result on buf 506236769Sobrien * 507236769Sobrien *----------------------------------------------------------------------- 508236769Sobrien */ 509236769Sobrienvoid 510236769SobrienStr_SYSVSubst(Buffer *buf, char *pat, char *src, int len) 511236769Sobrien{ 512236769Sobrien char *m; 513236769Sobrien 514236769Sobrien if ((m = strchr(pat, '%')) != NULL) { 515236769Sobrien /* Copy the prefix */ 516236769Sobrien Buf_AddBytes(buf, m - pat, pat); 517236769Sobrien /* skip the % */ 518236769Sobrien pat = m + 1; 519236769Sobrien } 520236769Sobrien 521236769Sobrien /* Copy the pattern */ 522236769Sobrien Buf_AddBytes(buf, len, src); 523236769Sobrien 524236769Sobrien /* append the rest */ 525236769Sobrien Buf_AddBytes(buf, strlen(pat), pat); 526236769Sobrien} 527