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
7 * This code is derived from software contributed to Berkeley by
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * @(#)var.c 8.3 (Berkeley) 3/19/94
39 * $FreeBSD: src/usr.bin/make/var.c,v 1.16.2.3 2002/02/27 14:18:57 cjc Exp $
40 * $DragonFly: src/usr.bin/make/Attic/var_modify.c,v 1.14 2005/01/08 22:27:02 okumoto Exp $
54 *-----------------------------------------------------------------------
56 * Remove the tail of the given word and place the result in the given
60 * TRUE if characters were added to the buffer (a space needs to be
61 * added to the buffer before the next word).
64 * The trimmed word is added to the buffer.
66 *-----------------------------------------------------------------------
69 VarHead(const char *word, Boolean addSpace, Buffer *buf, void *dummy __unused)
73 slash = strrchr(word, '/');
76 Buf_AddByte(buf, (Byte)' ');
78 Buf_AddBytes(buf, slash - word, (const Byte *)word);
81 * If no directory part, give . (q.v. the POSIX standard)
84 Buf_AddBytes(buf, 2, (const Byte *)" .");
86 Buf_AddByte(buf, (Byte)'.');
93 *-----------------------------------------------------------------------
95 * Remove the head of the given word and place the result in the given
99 * TRUE if characters were added to the buffer (a space needs to be
100 * added to the buffer before the next word).
103 * The trimmed word is added to the buffer.
105 *-----------------------------------------------------------------------
108 VarTail(const char *word, Boolean addSpace, Buffer *buf, void *dummy __unused)
113 Buf_AddByte (buf, (Byte)' ');
116 slash = strrchr(word, '/');
119 Buf_AddBytes(buf, strlen(slash), (const Byte *)slash);
121 Buf_AddBytes(buf, strlen(word), (const Byte *)word);
127 *-----------------------------------------------------------------------
129 * Place the suffix of the given word in the given buffer.
132 * TRUE if characters were added to the buffer (a space needs to be
133 * added to the buffer before the next word).
136 * The suffix from the word is placed in the buffer.
138 *-----------------------------------------------------------------------
141 VarSuffix(const char *word, Boolean addSpace, Buffer *buf, void *dummy __unused)
145 dot = strrchr(word, '.');
148 Buf_AddByte(buf, (Byte)' ');
151 Buf_AddBytes(buf, strlen(dot), (const Byte *)dot);
158 *-----------------------------------------------------------------------
160 * Remove the suffix of the given word and place the result in the
164 * TRUE if characters were added to the buffer (a space needs to be
165 * added to the buffer before the next word).
168 * The trimmed word is added to the buffer.
170 *-----------------------------------------------------------------------
173 VarRoot(const char *word, Boolean addSpace, Buffer *buf, void *dummy __unused)
178 Buf_AddByte(buf, (Byte)' ');
181 dot = strrchr(word, '.');
183 Buf_AddBytes(buf, dot - word, (const Byte *)word);
185 Buf_AddBytes(buf, strlen(word), (const Byte *)word);
191 *-----------------------------------------------------------------------
193 * Place the word in the buffer if it matches the given pattern.
194 * Callback function for VarModify to implement the :M modifier.
195 * A space will be added if requested. A pattern is supplied
196 * which the word must match.
199 * TRUE if a space should be placed in the buffer before the next
203 * The word may be copied to the buffer.
205 *-----------------------------------------------------------------------
208 VarMatch(const char *word, Boolean addSpace, Buffer *buf, void *pattern)
211 if (Str_Match(word, pattern)) {
213 Buf_AddByte(buf, (Byte)' ');
216 Buf_AddBytes(buf, strlen(word), word);
223 *-----------------------------------------------------------------------
225 * Place the word in the buffer if it matches the given pattern.
226 * Callback function for VarModify to implement the System V %
227 * modifiers. A space is added if requested.
230 * TRUE if a space should be placed in the buffer before the next
234 * The word may be copied to the buffer.
236 *-----------------------------------------------------------------------
239 VarSYSVMatch(const char *word, Boolean addSpace, Buffer *buf, void *patp)
243 VarPattern *pat = (VarPattern *)patp;
246 Buf_AddByte(buf, (Byte)' ');
250 if ((ptr = Str_SYSVMatch(word, pat->lhs, &len)) != NULL)
251 Str_SYSVSubst(buf, pat->rhs, ptr, len);
253 Buf_AddBytes(buf, strlen(word), (const Byte *)word);
261 *-----------------------------------------------------------------------
263 * Place the word in the buffer if it doesn't match the given pattern.
264 * Callback function for VarModify to implement the :N modifier. A
265 * space is added if requested.
268 * TRUE if a space should be placed in the buffer before the next
272 * The word may be copied to the buffer.
274 *-----------------------------------------------------------------------
277 VarNoMatch(const char *word, Boolean addSpace, Buffer *buf, void *pattern)
280 if (!Str_Match(word, pattern)) {
282 Buf_AddByte(buf, (Byte)' ');
285 Buf_AddBytes(buf, strlen(word), (const Byte *)word);
292 *-----------------------------------------------------------------------
294 * Perform a string-substitution on the given word, placing the
295 * result in the passed buffer. A space is added if requested.
298 * TRUE if a space is needed before more characters are added.
303 *-----------------------------------------------------------------------
306 VarSubstitute(const char *word, Boolean addSpace, Buffer *buf, void *patternp)
308 size_t wordLen; /* Length of word */
309 const char *cp; /* General pointer */
310 VarPattern *pattern = patternp;
312 wordLen = strlen(word);
313 if (1) { /* substitute in each word of the variable */
315 * Break substitution down into simple anchored cases
316 * and if none of them fits, perform the general substitution case.
318 if ((pattern->flags & VAR_MATCH_START) &&
319 (strncmp(word, pattern->lhs, pattern->leftLen) == 0)) {
321 * Anchored at start and beginning of word matches pattern
323 if ((pattern->flags & VAR_MATCH_END) &&
324 (wordLen == pattern->leftLen)) {
326 * Also anchored at end and matches to the end (word
327 * is same length as pattern) add space and rhs only
328 * if rhs is non-null.
330 if (pattern->rightLen != 0) {
332 Buf_AddByte(buf, (Byte)' ');
335 Buf_AddBytes(buf, pattern->rightLen,
336 (Byte *)pattern->rhs);
338 } else if (pattern->flags & VAR_MATCH_END) {
340 * Doesn't match to end -- copy word wholesale
345 * Matches at start but need to copy in trailing characters
347 if ((pattern->rightLen + wordLen - pattern->leftLen) != 0){
349 Buf_AddByte(buf, (Byte)' ');
353 Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs);
354 Buf_AddBytes(buf, wordLen - pattern->leftLen,
355 (const Byte *)(word + pattern->leftLen));
357 } else if (pattern->flags & VAR_MATCH_START) {
359 * Had to match at start of word and didn't -- copy whole word.
362 } else if (pattern->flags & VAR_MATCH_END) {
364 * Anchored at end, Find only place match could occur (leftLen
365 * characters from the end of the word) and see if it does. Note
366 * that because the $ will be left at the end of the lhs, we have
369 cp = word + (wordLen - pattern->leftLen);
371 (strncmp(cp, pattern->lhs, pattern->leftLen) == 0)) {
373 * Match found. If we will place characters in the buffer,
374 * add a space before hand as indicated by addSpace, then
375 * stuff in the initial, unmatched part of the word followed
376 * by the right-hand-side.
378 if (((cp - word) + pattern->rightLen) != 0) {
380 Buf_AddByte(buf, (Byte)' ');
384 Buf_AddBytes(buf, cp - word, (const Byte *)word);
385 Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs);
388 * Had to match at end and didn't. Copy entire word.
394 * Pattern is unanchored: search for the pattern in the word using
395 * strstr(3), copying unmatched portions and the
396 * right-hand-side for each match found, handling non-global
397 * substitutions correctly, etc. When the loop is done, any
398 * remaining part of the word (word and wordLen are adjusted
399 * accordingly through the loop) is copied straight into the
401 * addSpace is set FALSE as soon as a space is added to the
408 origSize = Buf_Size(buf);
410 cp = strstr(word, pattern->lhs);
412 if (addSpace && (((cp - word) + pattern->rightLen) != 0)){
413 Buf_AddByte(buf, (Byte)' ');
416 Buf_AddBytes(buf, cp-word, (const Byte *)word);
417 Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs);
418 wordLen -= (cp - word) + pattern->leftLen;
419 word = cp + pattern->leftLen;
420 if (wordLen == 0 || (pattern->flags & VAR_SUB_GLOBAL) == 0){
429 Buf_AddByte(buf, (Byte)' ');
431 Buf_AddBytes(buf, wordLen, (const Byte *)word);
434 * If added characters to the buffer, need to add a space
435 * before we add any more. If we didn't add any, just return
436 * the previous value of addSpace.
438 return ((Buf_Size(buf) != origSize) || addSpace);
441 * Common code for anchored substitutions:
442 * addSpace was set TRUE if characters were added to the buffer.
448 Buf_AddByte(buf, (Byte)' ');
450 Buf_AddBytes(buf, wordLen, (const Byte *)word);
455 *-----------------------------------------------------------------------
457 * Perform a regex substitution on the given word, placing the
458 * result in the passed buffer. A space is added if requested.
461 * TRUE if a space is needed before more characters are added.
466 *-----------------------------------------------------------------------
469 VarRESubstitute(const char *word, Boolean addSpace, Buffer *buf, void *patternp)
478 #define MAYBE_ADD_SPACE() \
479 if (addSpace && !added) \
480 Buf_AddByte(buf, (Byte)' '); \
487 if ((pat->flags & (VAR_SUB_ONE | VAR_SUB_MATCHED)) ==
488 (VAR_SUB_ONE | VAR_SUB_MATCHED))
492 xrv = regexec(&pat->re, wp, pat->nsub, pat->matches, flags);
497 pat->flags |= VAR_SUB_MATCHED;
498 if (pat->matches[0].rm_so > 0) {
500 Buf_AddBytes(buf, pat->matches[0].rm_so, (const Byte *)wp);
503 for (rp = pat->replace; *rp; rp++) {
504 if ((*rp == '\\') && ((rp[1] == '&') || (rp[1] == '\\'))) {
506 Buf_AddByte(buf, (Byte)rp[1]);
509 else if ((*rp == '&') ||
510 ((*rp == '\\') && isdigit((unsigned char)rp[1]))) {
529 Error("No subexpression %s", &errstr[0]);
532 } else if ((pat->matches[n].rm_so == -1) &&
533 (pat->matches[n].rm_eo == -1)) {
534 Error("No match for subexpression %s", &errstr[0]);
538 subbuf = wp + pat->matches[n].rm_so;
539 sublen = pat->matches[n].rm_eo - pat->matches[n].rm_so;
544 Buf_AddBytes(buf, sublen, (const Byte *)subbuf);
548 Buf_AddByte(buf, (Byte)*rp);
551 wp += pat->matches[0].rm_eo;
552 if (pat->flags & VAR_SUB_GLOBAL) {
554 if (pat->matches[0].rm_so == 0 && pat->matches[0].rm_eo == 0) {
556 Buf_AddByte(buf, (Byte)*wp);
565 Buf_AddBytes(buf, strlen(wp), (const Byte *)wp);
569 VarREError(xrv, &pat->re, "Unexpected regex error");
574 Buf_AddBytes(buf, strlen(wp), (const Byte *)wp);
578 return (addSpace || added);