str.c revision 124840
11590Srgrimes/*- 21590Srgrimes * Copyright (c) 1988, 1989, 1990, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * Copyright (c) 1989 by Berkeley Softworks 51590Srgrimes * All rights reserved. 61590Srgrimes * 71590Srgrimes * This code is derived from software contributed to Berkeley by 81590Srgrimes * Adam de Boor. 91590Srgrimes * 101590Srgrimes * Redistribution and use in source and binary forms, with or without 111590Srgrimes * modification, are permitted provided that the following conditions 121590Srgrimes * are met: 131590Srgrimes * 1. Redistributions of source code must retain the above copyright 141590Srgrimes * notice, this list of conditions and the following disclaimer. 151590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 161590Srgrimes * notice, this list of conditions and the following disclaimer in the 171590Srgrimes * documentation and/or other materials provided with the distribution. 181590Srgrimes * 3. All advertising materials mentioning features or use of this software 191590Srgrimes * must display the following acknowledgement: 201590Srgrimes * This product includes software developed by the University of 211590Srgrimes * California, Berkeley and its contributors. 221590Srgrimes * 4. Neither the name of the University nor the names of its contributors 231590Srgrimes * may be used to endorse or promote products derived from this software 241590Srgrimes * without specific prior written permission. 251590Srgrimes * 261590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 271590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 281590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 291590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 301590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 311590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 321590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 331590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 341590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 351590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 361590Srgrimes * SUCH DAMAGE. 3762833Swsanchez * 3862833Swsanchez * @(#)str.c 5.8 (Berkeley) 6/1/90 391590Srgrimes */ 401590Srgrimes 4162833Swsanchez#include <sys/cdefs.h> 4294587Sobrien__FBSDID("$FreeBSD: head/usr.bin/make/str.c 124840 2004-01-22 18:17:44Z ru $"); 431590Srgrimes 441590Srgrimes#include "make.h" 451590Srgrimes 465814Sjkhstatic char **argv, *buffer; 475814Sjkhstatic int argmax, curlen; 485814Sjkh 495814Sjkh/* 505814Sjkh * str_init -- 515814Sjkh * Initialize the strings package 525814Sjkh * 535814Sjkh */ 545814Sjkhvoid 55104696Sjmallettstr_init(void) 565814Sjkh{ 575814Sjkh char *p1; 5818730Ssteve argv = (char **)emalloc(((argmax = 50) + 1) * sizeof(char *)); 595814Sjkh argv[0] = Var_Value(".MAKE", VAR_GLOBAL, &p1); 605814Sjkh} 615814Sjkh 625814Sjkh 635814Sjkh/* 645814Sjkh * str_end -- 655814Sjkh * Cleanup the strings package 665814Sjkh * 675814Sjkh */ 685814Sjkhvoid 69104696Sjmallettstr_end(void) 705814Sjkh{ 719254Sache if (argv) { 729254Sache if (argv[0]) 739254Sache free(argv[0]); 7469531Swill free(argv); 759254Sache } 765814Sjkh if (buffer) 775814Sjkh free(buffer); 785814Sjkh} 795814Sjkh 801590Srgrimes/*- 811590Srgrimes * str_concat -- 821590Srgrimes * concatenate the two strings, inserting a space or slash between them, 831590Srgrimes * freeing them if requested. 841590Srgrimes * 851590Srgrimes * returns -- 861590Srgrimes * the resulting string in allocated space. 871590Srgrimes */ 881590Srgrimeschar * 89104696Sjmallettstr_concat(char *s1, char *s2, int flags) 901590Srgrimes{ 9194584Sobrien int len1, len2; 9294584Sobrien char *result; 931590Srgrimes 941590Srgrimes /* get the length of both strings */ 9594638Sobrien len1 = strlen(s1); 9694638Sobrien len2 = strlen(s2); 971590Srgrimes 981590Srgrimes /* allocate length plus separator plus EOS */ 991590Srgrimes result = emalloc((u_int)(len1 + len2 + 2)); 1001590Srgrimes 1011590Srgrimes /* copy first string into place */ 10294638Sobrien memcpy(result, s1, len1); 1031590Srgrimes 1041590Srgrimes /* add separator character */ 10594638Sobrien if (flags & STR_ADDSPACE) { 10694638Sobrien result[len1] = ' '; 10794638Sobrien ++len1; 10894638Sobrien } else if (flags & STR_ADDSLASH) { 10994638Sobrien result[len1] = '/'; 11094638Sobrien ++len1; 1111590Srgrimes } 1121590Srgrimes 11394638Sobrien /* copy second string plus EOS into place */ 11494638Sobrien memcpy(result + len1, s2, len2 + 1); 1151590Srgrimes 1161590Srgrimes /* free original strings */ 1171590Srgrimes if (flags & STR_DOFREE) { 118105826Sjmallett (void)free(s1); 119105826Sjmallett (void)free(s2); 1201590Srgrimes } 1211590Srgrimes return(result); 1221590Srgrimes} 1231590Srgrimes 1241590Srgrimes/*- 1251590Srgrimes * brk_string -- 1261590Srgrimes * Fracture a string into an array of words (as delineated by tabs or 1271590Srgrimes * spaces) taking quotation marks into account. Leading tabs/spaces 1281590Srgrimes * are ignored. 1291590Srgrimes * 1301590Srgrimes * returns -- 1311590Srgrimes * Pointer to the array of pointers to the words. To make life easier, 1321590Srgrimes * the first word is always the value of the .MAKE variable. 1331590Srgrimes */ 1341590Srgrimeschar ** 135104696Sjmallettbrk_string(char *str, int *store_argc, Boolean expand) 1361590Srgrimes{ 13794584Sobrien int argc, ch; 13894584Sobrien char inquote, *p, *start, *t; 1391590Srgrimes int len; 1401590Srgrimes 1411590Srgrimes /* skip leading space chars. */ 1421590Srgrimes for (; *str == ' ' || *str == '\t'; ++str) 1431590Srgrimes continue; 1441590Srgrimes 1451590Srgrimes /* allocate room for a copy of the string */ 1465814Sjkh if ((len = strlen(str) + 1) > curlen) { 1475814Sjkh if (buffer) 1485814Sjkh free(buffer); 1495814Sjkh buffer = emalloc(curlen = len); 1505814Sjkh } 1511590Srgrimes 1521590Srgrimes /* 1531590Srgrimes * copy the string; at the same time, parse backslashes, 1541590Srgrimes * quotes and build the argument list. 1551590Srgrimes */ 1561590Srgrimes argc = 1; 1571590Srgrimes inquote = '\0'; 1585814Sjkh for (p = str, start = t = buffer;; ++p) { 1591590Srgrimes switch(ch = *p) { 1601590Srgrimes case '"': 1611590Srgrimes case '\'': 16249938Shoek if (inquote) { 163124840Sru if (ch == inquote) 1641590Srgrimes inquote = '\0'; 1651590Srgrimes else 1661590Srgrimes break; 167124840Sru } else 1681590Srgrimes inquote = (char) ch; 169124840Sru if (expand) 170124840Sru continue; 171124840Sru break; 1721590Srgrimes case ' ': 1731590Srgrimes case '\t': 1745814Sjkh case '\n': 1751590Srgrimes if (inquote) 1761590Srgrimes break; 1771590Srgrimes if (!start) 1781590Srgrimes continue; 1791590Srgrimes /* FALLTHROUGH */ 1801590Srgrimes case '\0': 1811590Srgrimes /* 1821590Srgrimes * end of a token -- make sure there's enough argv 1831590Srgrimes * space and save off a pointer. 1841590Srgrimes */ 1855814Sjkh if (!start) 1865814Sjkh goto done; 1875814Sjkh 1881590Srgrimes *t++ = '\0'; 1891590Srgrimes if (argc == argmax) { 1901590Srgrimes argmax *= 2; /* ramp up fast */ 19118730Ssteve argv = (char **)erealloc(argv, 19218730Ssteve (argmax + 1) * sizeof(char *)); 1931590Srgrimes } 1941590Srgrimes argv[argc++] = start; 1951590Srgrimes start = (char *)NULL; 1961590Srgrimes if (ch == '\n' || ch == '\0') 1971590Srgrimes goto done; 1981590Srgrimes continue; 1991590Srgrimes case '\\': 2005814Sjkh if (!expand) { 2015814Sjkh if (!start) 2025814Sjkh start = t; 2035814Sjkh *t++ = '\\'; 2045814Sjkh ch = *++p; 2055814Sjkh break; 2065814Sjkh } 2078874Srgrimes 2081590Srgrimes switch (ch = *++p) { 2091590Srgrimes case '\0': 2101590Srgrimes case '\n': 2111590Srgrimes /* hmmm; fix it up as best we can */ 2121590Srgrimes ch = '\\'; 2131590Srgrimes --p; 2141590Srgrimes break; 2151590Srgrimes case 'b': 2161590Srgrimes ch = '\b'; 2171590Srgrimes break; 2181590Srgrimes case 'f': 2191590Srgrimes ch = '\f'; 2201590Srgrimes break; 2211590Srgrimes case 'n': 2221590Srgrimes ch = '\n'; 2231590Srgrimes break; 2241590Srgrimes case 'r': 2251590Srgrimes ch = '\r'; 2261590Srgrimes break; 2271590Srgrimes case 't': 2281590Srgrimes ch = '\t'; 2291590Srgrimes break; 230104108Sjmallett default: 231104108Sjmallett break; 2321590Srgrimes } 2331590Srgrimes break; 234104108Sjmallett default: 235104108Sjmallett break; 2361590Srgrimes } 2371590Srgrimes if (!start) 2381590Srgrimes start = t; 2391590Srgrimes *t++ = (char) ch; 2401590Srgrimes } 2411590Srgrimesdone: argv[argc] = (char *)NULL; 2421590Srgrimes *store_argc = argc; 2431590Srgrimes return(argv); 2441590Srgrimes} 2451590Srgrimes 2461590Srgrimes/* 2471590Srgrimes * Str_Match -- 2488874Srgrimes * 2491590Srgrimes * See if a particular string matches a particular pattern. 2508874Srgrimes * 2511590Srgrimes * Results: Non-zero is returned if string matches pattern, 0 otherwise. The 2521590Srgrimes * matching operation permits the following special characters in the 2531590Srgrimes * pattern: *?\[] (see the man page for details on what these mean). 2548874Srgrimes * 2551590Srgrimes * Side effects: None. 2561590Srgrimes */ 2571590Srgrimesint 258106106SjmallettStr_Match(const char *string, const char *pattern) 2591590Srgrimes{ 2601590Srgrimes char c2; 2611590Srgrimes 2621590Srgrimes for (;;) { 2631590Srgrimes /* 2641590Srgrimes * See if we're at the end of both the pattern and the 2651590Srgrimes * string. If, we succeeded. If we're at the end of the 2661590Srgrimes * pattern but not at the end of the string, we failed. 2671590Srgrimes */ 2681590Srgrimes if (*pattern == 0) 2691590Srgrimes return(!*string); 2701590Srgrimes if (*string == 0 && *pattern != '*') 2711590Srgrimes return(0); 2721590Srgrimes /* 2731590Srgrimes * Check for a "*" as the next pattern character. It matches 2741590Srgrimes * any substring. We handle this by calling ourselves 2751590Srgrimes * recursively for each postfix of string, until either we 2761590Srgrimes * match or we reach the end of the string. 2771590Srgrimes */ 2781590Srgrimes if (*pattern == '*') { 2791590Srgrimes pattern += 1; 2801590Srgrimes if (*pattern == 0) 2811590Srgrimes return(1); 2821590Srgrimes while (*string != 0) { 2831590Srgrimes if (Str_Match(string, pattern)) 2841590Srgrimes return(1); 2851590Srgrimes ++string; 2861590Srgrimes } 2871590Srgrimes return(0); 2881590Srgrimes } 2891590Srgrimes /* 2901590Srgrimes * Check for a "?" as the next pattern character. It matches 2911590Srgrimes * any single character. 2921590Srgrimes */ 2931590Srgrimes if (*pattern == '?') 2941590Srgrimes goto thisCharOK; 2951590Srgrimes /* 2961590Srgrimes * Check for a "[" as the next pattern character. It is 2971590Srgrimes * followed by a list of characters that are acceptable, or 2981590Srgrimes * by a range (two characters separated by "-"). 2991590Srgrimes */ 3001590Srgrimes if (*pattern == '[') { 3011590Srgrimes ++pattern; 3021590Srgrimes for (;;) { 3031590Srgrimes if ((*pattern == ']') || (*pattern == 0)) 3041590Srgrimes return(0); 3051590Srgrimes if (*pattern == *string) 3061590Srgrimes break; 3071590Srgrimes if (pattern[1] == '-') { 3081590Srgrimes c2 = pattern[2]; 3091590Srgrimes if (c2 == 0) 3101590Srgrimes return(0); 3111590Srgrimes if ((*pattern <= *string) && 3121590Srgrimes (c2 >= *string)) 3131590Srgrimes break; 3141590Srgrimes if ((*pattern >= *string) && 3151590Srgrimes (c2 <= *string)) 3161590Srgrimes break; 3171590Srgrimes pattern += 2; 3181590Srgrimes } 3191590Srgrimes ++pattern; 3201590Srgrimes } 3211590Srgrimes while ((*pattern != ']') && (*pattern != 0)) 3221590Srgrimes ++pattern; 3231590Srgrimes goto thisCharOK; 3241590Srgrimes } 3251590Srgrimes /* 3261590Srgrimes * If the next pattern character is '/', just strip off the 3271590Srgrimes * '/' so we do exact matching on the character that follows. 3281590Srgrimes */ 3291590Srgrimes if (*pattern == '\\') { 3301590Srgrimes ++pattern; 3311590Srgrimes if (*pattern == 0) 3321590Srgrimes return(0); 3331590Srgrimes } 3341590Srgrimes /* 3351590Srgrimes * There's no special character. Just make sure that the 3361590Srgrimes * next characters of each string match. 3371590Srgrimes */ 3381590Srgrimes if (*pattern != *string) 3391590Srgrimes return(0); 3401590SrgrimesthisCharOK: ++pattern; 3411590Srgrimes ++string; 3421590Srgrimes } 3431590Srgrimes} 3441590Srgrimes 3451590Srgrimes 3461590Srgrimes/*- 3471590Srgrimes *----------------------------------------------------------------------- 3481590Srgrimes * Str_SYSVMatch -- 3498874Srgrimes * Check word against pattern for a match (% is wild), 3508874Srgrimes * 3511590Srgrimes * Results: 3521590Srgrimes * Returns the beginning position of a match or null. The number 3531590Srgrimes * of characters matched is returned in len. 3541590Srgrimes * 3551590Srgrimes * Side Effects: 3561590Srgrimes * None 3571590Srgrimes * 3581590Srgrimes *----------------------------------------------------------------------- 3591590Srgrimes */ 360106106Sjmallettconst char * 361106106SjmallettStr_SYSVMatch(const char *word, const char *pattern, int *len) 3621590Srgrimes{ 363106106Sjmallett const char *m, *p, *w; 3641590Srgrimes 365106106Sjmallett p = pattern; 366106106Sjmallett w = word; 367106106Sjmallett 36896071Sjmallett if (*w == '\0') { 36996071Sjmallett /* Zero-length word cannot be matched against */ 37096071Sjmallett *len = 0; 37196071Sjmallett return NULL; 37296071Sjmallett } 37396071Sjmallett 3741590Srgrimes if (*p == '\0') { 3751590Srgrimes /* Null pattern is the whole string */ 3761590Srgrimes *len = strlen(w); 3771590Srgrimes return w; 3781590Srgrimes } 3791590Srgrimes 3801590Srgrimes if ((m = strchr(p, '%')) != NULL) { 3811590Srgrimes /* check that the prefix matches */ 3821590Srgrimes for (; p != m && *w && *w == *p; w++, p++) 3831590Srgrimes continue; 3841590Srgrimes 3851590Srgrimes if (p != m) 3861590Srgrimes return NULL; /* No match */ 3871590Srgrimes 3881590Srgrimes if (*++p == '\0') { 3891590Srgrimes /* No more pattern, return the rest of the string */ 3901590Srgrimes *len = strlen(w); 3911590Srgrimes return w; 3921590Srgrimes } 3931590Srgrimes } 3941590Srgrimes 3951590Srgrimes m = w; 3961590Srgrimes 3971590Srgrimes /* Find a matching tail */ 3981590Srgrimes do 3991590Srgrimes if (strcmp(p, w) == 0) { 4001590Srgrimes *len = w - m; 4011590Srgrimes return m; 4021590Srgrimes } 4031590Srgrimes while (*w++ != '\0'); 4048874Srgrimes 4051590Srgrimes return NULL; 4061590Srgrimes} 4071590Srgrimes 4081590Srgrimes 4091590Srgrimes/*- 4101590Srgrimes *----------------------------------------------------------------------- 4111590Srgrimes * Str_SYSVSubst -- 4121590Srgrimes * Substitute '%' on the pattern with len characters from src. 4131590Srgrimes * If the pattern does not contain a '%' prepend len characters 4141590Srgrimes * from src. 4158874Srgrimes * 4161590Srgrimes * Results: 4171590Srgrimes * None 4181590Srgrimes * 4191590Srgrimes * Side Effects: 4201590Srgrimes * Places result on buf 4211590Srgrimes * 4221590Srgrimes *----------------------------------------------------------------------- 4231590Srgrimes */ 4241590Srgrimesvoid 425106106SjmallettStr_SYSVSubst(Buffer buf, const char *pat, const char *src, int len) 4261590Srgrimes{ 427106106Sjmallett const char *m; 4281590Srgrimes 4291590Srgrimes if ((m = strchr(pat, '%')) != NULL) { 4301590Srgrimes /* Copy the prefix */ 4311590Srgrimes Buf_AddBytes(buf, m - pat, (Byte *) pat); 4321590Srgrimes /* skip the % */ 4331590Srgrimes pat = m + 1; 4341590Srgrimes } 4351590Srgrimes 4361590Srgrimes /* Copy the pattern */ 4371590Srgrimes Buf_AddBytes(buf, len, (Byte *) src); 4381590Srgrimes 4391590Srgrimes /* append the rest */ 4401590Srgrimes Buf_AddBytes(buf, strlen(pat), (Byte *) pat); 4411590Srgrimes} 442