/* * COMPONENT_NAME: BLDPROCESS * * FUNCTIONS: Str_Match * _string_headtail * _string_prefsuff * brk_string * string_archmemb * string_concat * string_create * string_deref * string_finish * string_flatten * string_init * string_ref * string_setup * strndup * * ORIGINS: 27,71 * * This module contains IBM CONFIDENTIAL code. -- (IBM * Confidential Restricted when combined with the aggregated * modules for this product) * SOURCE MATERIALS * * (C) COPYRIGHT International Business Machines Corp. 1994 * All Rights Reserved * US Government Users Restricted Rights - Use, duplication or * disclosure restricted by GSA ADP Schedule Contract with IBM Corp. */ /* * @OSF_FREE_COPYRIGHT@ * COPYRIGHT NOTICE * Copyright (c) 1992, 1991, 1990 * Open Software Foundation, Inc. * * Permission is hereby granted to use, copy, modify and freely distribute * the software in this file and its documentation for any purpose without * fee, provided that the above copyright notice appears in all copies and * that both the copyright notice and this permission notice appear in * supporting documentation. Further, provided that the name of Open * Software Foundation, Inc. ("OSF") not be used in advertising or * publicity pertaining to distribution of the software without prior * written permission from OSF. OSF makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. */ /* * HISTORY * $Log: str.c,v $ * Revision 1.2.2.8 1992/12/03 19:07:19 damon * ODE 2.2 CR 346. Expanded copyright * [1992/12/03 18:36:34 damon] * * Revision 1.2.2.7 1992/11/13 15:19:56 root * Changed assignment of NULL to '\0' * [1992/11/13 14:57:58 root] * * Revision 1.2.2.6 1992/09/24 19:27:12 gm * CR286: Major improvements to make internals. * [1992/09/24 17:55:40 gm] * * Revision 1.2.2.5 1992/06/24 16:41:54 damon * CR 60. brk_string now counts args correctly * [1992/06/24 16:38:41 damon] * * Revision 1.2.2.4 1992/06/16 21:24:36 damon * 2.1.1 touch-up * [1992/06/16 21:18:22 damon] * * Revision 1.2.2.3 1992/06/12 00:49:18 damon * Synched with 2.1.1 * [1992/06/12 00:38:50 damon] * * Revision 1.2.4.3 1992/03/25 22:46:03 damon * Removed comment after endif * [1992/03/25 21:49:50 damon] * * Revision 1.2.4.2 1992/03/09 21:10:41 mhickey * Closed open comment in brk_string that was preventing * leading whitespace from being stripped from command lines. * [1992/03/09 21:01:44 mhickey] * * Revision 1.2 1991/12/05 20:45:15 devrcs * Changes for Reno make * [91/03/22 16:10:27 mckeen] * * $EndLog$ */ /*- * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. * Copyright (c) 1988, 1989 by Adam de Boor * Copyright (c) 1989 by Berkeley Softworks * All rights reserved. * * This code is derived from software contributed to Berkeley by * Adam de Boor. * * Redistribution and use in source and binary forms are permitted * provided that: (1) source distributions retain this entire copyright * notice and comment, and (2) distributions including binaries display * the following acknowledgement: ``This product includes software * developed by the University of California, Berkeley and its contributors'' * in the documentation or other materials provided with the distribution * and in all advertising materials mentioning features or use of this * software. Neither the name of the University nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #ifndef lint static char sccsid[] = "@(#)52 1.4 src/bldenv/make/str.c, bldprocess, bos412, GOLDA411a 1/19/94 16:31:37"; #endif /* not lint */ #ifndef lint static char rcsid[] = "@(#)str.c 5.8 (Berkeley) 6/1/90"; #endif /* not lint */ #include "make.h" #include "hash.h" Hash_Table stringHashTable; /*- * strndup -- * allocate and return a copy of the string s of length n. * * returns -- * the resulting string in allocated space. */ char * strndup(const char *s, int n) { char *r = (char *)malloc(n+1); if (r == NULL) enomem(); memcpy(r, s, n); r[n] = '\0'; return(r); } /*- * string_concat -- * concatenate the two strings, inserting a space or slash between them, * freeing them if requested. * * returns -- * the resulting string in allocated space. */ string_t string_concat(string_t s1, string_t s2, int flags) { register int len1, len2; register char *result; string_t rs; /* get the length of both strings */ len1 = s1 ? s1->len : 0; len2 = s2 ? s2->len : 0; /* allocate length plus separator plus EOS */ result = emalloc((u_int)(len1 + len2 + 2)); /* copy first string into place */ if (len1) memcpy(result, s1->data, len1); if (len1 && len2) { /* add separator character */ if (flags & STR_ADDSPACE) { result[len1] = ' '; ++len1; } else if (flags & STR_ADDSLASH) { result[len1] = '/'; ++len1; } } /* copy second string into place */ if (len2) memcpy(result + len1, s2->data, len2); result[len1+len2] = '\0'; rs = string_create(result); /* free original strings */ free(result); if (flags & STR_DOFREE) { string_deref(s1); string_deref(s2); } return(rs); } /*- * brk_string -- * Fracture a string into an array of words (as delineated by tabs or * spaces) taking quotation marks into account. Leading tabs/spaces * are ignored. * * returns -- * Pointer to the array of pointers to the words. To make life easier, * the first word is always the value of the MAKE variable. */ char ** brk_string(register char *str, int *store_argc) { static int argmax, curlen; static const char **argv; static char *buf; register int argc, ch; register char inquote, *p, *start, *t; int len; /* save off pmake variable */ if (!argv) { argv = (const char **)emalloc((argmax = 50) * sizeof(char *)); argv[0] = Var_Value(sMAKE, VAR_GLOBAL); } /* skip leading space chars. */ for (; *str == ' ' || *str == '\t'; ++str); /* allocate room for a copy of the string */ if ((len = strlen(str) + 1) > curlen) buf = emalloc(curlen = len); /* * copy the string; at the same time, parse backslashes, * quotes and build the argument list. */ argc = 1; inquote = '\0'; for (p = str, start = t = buf;; ++p) { switch(ch = *p) { case '"': case '\'': if (inquote) if (inquote == ch) inquote = '\0'; else break; else inquote = ch; continue; case ' ': case '\t': if (inquote) break; for (; *p == ' ' || *p == '\t'; ++p); ch = *p--; if (!start) continue; /* FALLTHROUGH */ case '\n': case '\0': /* * end of a token -- make sure there's enough argv * space and save off a pointer. */ *t++ = '\0'; if (argc == argmax) { argmax *= 2; /* ramp up fast */ if (!(argv = (const char **)realloc(argv, argmax * sizeof(char *)))) enomem(); } argv[argc++] = start; start = (char *)NULL; if (ch == '\n' || ch == '\0') goto done; continue; case '\\': switch (ch = *++p) { case '\0': case '\n': /* hmmm; fix it up as best we can */ ch = '\\'; --p; break; case 'b': ch = '\b'; break; case 'f': ch = '\f'; break; case 'n': ch = '\n'; break; case 'r': ch = '\r'; break; case 't': ch = '\t'; break; } break; } if (!start) start = t; *t++ = ch; } done: argv[argc] = (char *)NULL; *store_argc = argc; return((char **)argv); } /* * Str_Match -- * * See if a particular string matches a particular pattern. * * Results: Non-zero is returned if string matches pattern, 0 otherwise. The * matching operation permits the following special characters in the * pattern: *?\[] (see the man page for details on what these mean). * * Side effects: None. */ int Str_Match( register const char *string, /* String */ register const char *pattern) /* Pattern */ { int c2; for (;;) { /* * See if we're at the end of both the pattern and the * string. If, we succeeded. If we're at the end of the * pattern but not at the end of the string, we failed. */ if (*pattern == 0) return(!*string); if (*string == 0 && *pattern != '*') return(0); /* * Check for a "*" as the next pattern character. It matches * any substring. We handle this by calling ourselves * recursively for each postfix of string, until either we * match or we reach the end of the string. */ if (*pattern == '*') { pattern += 1; if (*pattern == 0) return(1); while (*string != 0) { if (Str_Match(string, pattern)) return(1); ++string; } return(0); } /* * Check for a "?" as the next pattern character. It matches * any single character. */ if (*pattern == '?') goto thisCharOK; /* * Check for a "[" as the next pattern character. It is * followed by a list of characters that are acceptable, or * by a range (two characters separated by "-"). */ if (*pattern == '[') { ++pattern; for (;;) { if ((*pattern == ']') || (*pattern == 0)) return(0); if (*pattern == *string) break; if (pattern[1] == '-') { c2 = pattern[2]; if (c2 == 0) return(0); if ((*pattern <= *string) && (c2 >= *string)) break; if ((*pattern >= *string) && (c2 <= *string)) break; pattern += 2; } ++pattern; } while ((*pattern != ']') && (*pattern != 0)) ++pattern; goto thisCharOK; } /* * If the next pattern character is '/', just strip off the * '/' so we do exact matching on the character that follows. */ if (*pattern == '\\') { ++pattern; if (*pattern == 0) return(0); } /* * There's no special character. Just make sure that the * next characters of each string match. */ if (*pattern != *string) return(0); thisCharOK: ++pattern; ++string; } } /*- * string_flatten - Flatten out a pathname */ string_t string_flatten(string_t spath) { register char *p, *q, *r; register char **sp, **tp; char *stack[64]; char *path = strdup(spath->data); string_t result; p = q = path; sp = tp = stack; if (*q == '/') { p++; while (*++q == '/') ; } for (r = q; *r; r = q) { while (*++q && *q != '/') ; if (q != r+1 || *r != '.') { if (q != r+2 || *r != '.' || *(r+1) != '.') *sp++ = r; else if (sp != tp) sp--; else { *p++ = '.'; *p++ = '.'; if (*q) *p++ = '/'; } } while (*q == '/') q++; } while (tp < sp) for (q = *tp++; *q; ) if ((*p++ = *q++) == '/') break; if (p > path+1 && *(p-1) == '/') --p; *p = 0; result = string_create(path); string_deref(spath); return(result); } string_t string_ref(string_t s) { if (s->_refCount == 0) printf("string %s had zero refs\n", s->data); else if (s->_refCount < 0) { printf("string %s had negative refs\n", s->data); s->_refCount = 0; } s->_refCount += 1; return s; } void string_deref(string_t s) { register Hash_Entry *he; s->_refCount -= 1; if (s->_refCount == 0) { if (s->_flags & STR_HEADTAIL) { string_deref(s->_head); string_deref(s->_tail); } if (s->_flags & STR_PREFSUFF) { string_deref(s->_pref); string_deref(s->_suff); } if (s->_arch) string_deref(s->_arch); if (s->_memb) string_deref(s->_memb); he = Hash_FindEntry(&stringHashTable, s); Hash_DeleteEntry(&stringHashTable, he); free((void *)s->data); free(s); } else if (s->_refCount < 0) printf("string %s negative refs\n", s->data); } static void string_setup(string_t s) { register unsigned h; register const char *p; h = 0; for (p = s->data; *p; p++) h = (h << 5) - h + *p; s->hashval = h; s->len = p - s->data; } static void string_finish(string_t s) { register const char *cp, *p, *tail, *suff; register int f; f = 0; cp = s->data; tail = NULL; suff = NULL; p = cp + s->len; while (p > cp) { p--; if (*p == '/') { tail = p + 1; break; } if (suff == NULL && *p == '.') { suff = p; continue; } if (*p == '$') f |= STR_HASVAR; } if (f == 0 && *cp == '$') f |= STR_HASVAR; else while (f == 0 && p > cp) if (*--p == '$') f |= STR_HASVAR; s->_flags = f; s->_tail = (string_t) tail; s->_pref = (string_t) (tail ? tail : cp); s->_suff = (string_t) suff; } string_t string_create(const char *cp) { struct string strtmpl; static struct string strzero; string_t s; strtmpl = strzero; strtmpl.data = cp; string_setup(&strtmpl); s = Hash_FindString(&stringHashTable, &strtmpl); if (s != (string_t) NULL) return(string_ref(s)); s = (string_t) malloc(sizeof(struct string)); if (s == NULL) enomem(); *s = strtmpl; s->data = (const char *)strndup(cp, s->len); string_finish(s); s->_refCount = 1; Hash_CreateString(&stringHashTable, s); return(s); } void string_init(void) { Hash_InitTable(&stringHashTable, 1024); } void _string_headtail(string_t s) { const char *cp = s->data; const char *p; p = (const char *) s->_tail; if (p == NULL) { s->_head = (string_t) NULL; s->_tail = string_ref(s); } else { s->_tail = string_create(p--); if (p == cp && *(p + 1) == '\0') s->_head = string_ref(s); else if (p == cp) s->_head = string_create("/"); else { p = (const char *)strndup(cp, p - cp); s->_head = string_create(p); free((char *)p); } } s->_flags |= STR_HEADTAIL; } void _string_prefsuff(string_t s) { const char *cp, *p; cp = (const char *) s->_pref; p = (const char *) s->_suff; if (p == NULL || (*p == '\0' && (p == cp + 1 || (p == cp + 2 && *(p-2) == '.')))) { s->_pref = string_create((const char *) s->_pref); s->_suff = (string_t) NULL; } else { if (p == cp) { s->_suff = string_ref(s); s->_pref = string_ref(sNULL); } else { s->_suff = string_create(p); p = (const char *)strndup(cp, p - cp); s->_pref = string_create(p); free((char *)p); } } s->_flags |= STR_PREFSUFF; } void string_archmemb(string_t s, string_t arch, string_t memb) { s->_arch = string_ref(arch); s->_memb = string_ref(memb); }