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.5 2004/12/13 21:45:05 okumoto Exp $
44 #include <sys/types.h>
52 *-----------------------------------------------------------------------
54 * Remove the tail of the given word and place the result in the given
58 * TRUE if characters were added to the buffer (a space needs to be
59 * added to the buffer before the next word).
62 * The trimmed word is added to the buffer.
64 *-----------------------------------------------------------------------
67 VarHead(const char *word, Boolean addSpace, Buffer buf, void *dummy __unused)
71 slash = strrchr(word, '/');
74 Buf_AddByte(buf, (Byte)' ');
77 Buf_AddBytes(buf, strlen(word), (Byte *)word);
82 * If no directory part, give . (q.v. the POSIX standard)
85 Buf_AddBytes(buf, 2, (Byte *)" .");
87 Buf_AddByte(buf, (Byte)'.');
94 *-----------------------------------------------------------------------
96 * Remove the head of the given word and place the result in the given
100 * TRUE if characters were added to the buffer (a space needs to be
101 * added to the buffer before the next word).
104 * The trimmed word is added to the buffer.
106 *-----------------------------------------------------------------------
109 VarTail(const char *word, Boolean addSpace, Buffer buf, void *dummy __unused)
114 Buf_AddByte(buf, (Byte)' ');
117 slash = strrchr(word, '/');
120 Buf_AddBytes(buf, strlen(slash), (Byte *)slash);
123 Buf_AddBytes(buf, strlen(word), (Byte *)word);
129 *-----------------------------------------------------------------------
131 * Place the suffix of the given word in the given buffer.
134 * TRUE if characters were added to the buffer (a space needs to be
135 * added to the buffer before the next word).
138 * The suffix from the word is placed in the buffer.
140 *-----------------------------------------------------------------------
143 VarSuffix(const char *word, Boolean addSpace, Buffer buf, void *dummy __unused)
147 dot = strrchr(word, '.');
150 Buf_AddByte(buf, (Byte)' ');
153 Buf_AddBytes(buf, strlen(dot), (Byte *)dot);
161 *-----------------------------------------------------------------------
163 * Remove the suffix of the given word and place the result in the
167 * TRUE if characters were added to the buffer (a space needs to be
168 * added to the buffer before the next word).
171 * The trimmed word is added to the buffer.
173 *-----------------------------------------------------------------------
176 VarRoot(const char *word, Boolean addSpace, Buffer buf, void *dummy __unused)
181 Buf_AddByte(buf, (Byte)' ');
184 dot = strrchr(word, '.');
187 Buf_AddBytes(buf, strlen(word), (Byte *)word);
190 Buf_AddBytes(buf, strlen(word), (Byte *)word);
196 *-----------------------------------------------------------------------
198 * Place the word in the buffer if it matches the given pattern.
199 * Callback function for VarModify to implement the :M modifier.
200 * A space will be added if requested. A pattern is supplied
201 * which the word must match.
204 * TRUE if a space should be placed in the buffer before the next
208 * The word may be copied to the buffer.
210 *-----------------------------------------------------------------------
213 VarMatch(const char *word, Boolean addSpace, Buffer buf, void *pattern)
216 if (Str_Match(word, pattern)) {
218 Buf_AddByte(buf, (Byte)' ');
221 Buf_AddBytes(buf, strlen(word), (Byte *)word);
228 *-----------------------------------------------------------------------
230 * Place the word in the buffer if it matches the given pattern.
231 * Callback function for VarModify to implement the System V %
232 * modifiers. A space is added if requested.
235 * TRUE if a space should be placed in the buffer before the next
239 * The word may be copied to the buffer.
241 *-----------------------------------------------------------------------
244 VarSYSVMatch(const char *word, Boolean addSpace, Buffer buf, void *patp)
248 VarPattern *pat = (VarPattern *)patp;
251 Buf_AddByte(buf, (Byte)' ');
255 if ((ptr = Str_SYSVMatch(word, pat->lhs, &len)) != NULL)
256 Str_SYSVSubst(buf, pat->rhs, ptr, len);
258 Buf_AddBytes(buf, strlen(word), (Byte *) word);
266 *-----------------------------------------------------------------------
268 * Place the word in the buffer if it doesn't match the given pattern.
269 * Callback function for VarModify to implement the :N modifier. A
270 * space is added if requested.
273 * TRUE if a space should be placed in the buffer before the next
277 * The word may be copied to the buffer.
279 *-----------------------------------------------------------------------
282 VarNoMatch(const char *word, Boolean addSpace, Buffer buf, void *pattern)
285 if (!Str_Match(word, pattern)) {
287 Buf_AddByte(buf, (Byte)' ');
290 Buf_AddBytes(buf, strlen(word), (Byte *)word);
297 *-----------------------------------------------------------------------
299 * Perform a string-substitution on the given word, placing the
300 * result in the passed buffer. A space is added if requested.
303 * TRUE if a space is needed before more characters are added.
308 *-----------------------------------------------------------------------
311 VarSubstitute(const char *word, Boolean addSpace, Buffer buf, void *patternp)
313 int wordLen; /* Length of word */
314 const char *cp; /* General pointer */
315 VarPattern *pattern = (VarPattern *)patternp;
317 wordLen = strlen(word);
318 if (1) { /* substitute in each word of the variable */
320 * Break substitution down into simple anchored cases
321 * and if none of them fits, perform the general substitution case.
323 if ((pattern->flags & VAR_MATCH_START) &&
324 (strncmp(word, pattern->lhs, pattern->leftLen) == 0)) {
326 * Anchored at start and beginning of word matches pattern
328 if ((pattern->flags & VAR_MATCH_END) &&
329 (wordLen == pattern->leftLen)) {
331 * Also anchored at end and matches to the end (word
332 * is same length as pattern) add space and rhs only
333 * if rhs is non-null.
335 if (pattern->rightLen != 0) {
337 Buf_AddByte(buf, (Byte)' ');
340 Buf_AddBytes(buf, pattern->rightLen,
341 (Byte *)pattern->rhs);
343 } else if (pattern->flags & VAR_MATCH_END) {
345 * Doesn't match to end -- copy word wholesale
350 * Matches at start but need to copy in trailing characters
352 if ((pattern->rightLen + wordLen - pattern->leftLen) != 0){
354 Buf_AddByte(buf, (Byte)' ');
358 Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs);
359 Buf_AddBytes(buf, wordLen - pattern->leftLen,
360 (Byte *)(word + pattern->leftLen));
362 } else if (pattern->flags & VAR_MATCH_START) {
364 * Had to match at start of word and didn't -- copy whole word.
367 } else if (pattern->flags & VAR_MATCH_END) {
369 * Anchored at end, Find only place match could occur (leftLen
370 * characters from the end of the word) and see if it does. Note
371 * that because the $ will be left at the end of the lhs, we have
374 cp = word + (wordLen - pattern->leftLen);
376 (strncmp(cp, pattern->lhs, pattern->leftLen) == 0)) {
378 * Match found. If we will place characters in the buffer,
379 * add a space before hand as indicated by addSpace, then
380 * stuff in the initial, unmatched part of the word followed
381 * by the right-hand-side.
383 if (((cp - word) + pattern->rightLen) != 0) {
385 Buf_AddByte(buf, (Byte)' ');
389 Buf_AddBytes(buf, cp - word, (Byte *)word);
390 Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs);
393 * Had to match at end and didn't. Copy entire word.
399 * Pattern is unanchored: search for the pattern in the word using
400 * strstr(3), copying unmatched portions and the
401 * right-hand-side for each match found, handling non-global
402 * substitutions correctly, etc. When the loop is done, any
403 * remaining part of the word (word and wordLen are adjusted
404 * accordingly through the loop) is copied straight into the
406 * addSpace is set FALSE as soon as a space is added to the
413 origSize = Buf_Size(buf);
415 cp = strstr(word, pattern->lhs);
417 if (addSpace && (((cp - word) + pattern->rightLen) != 0)){
418 Buf_AddByte(buf, (Byte)' ');
421 Buf_AddBytes(buf, cp-word, (Byte *)word);
422 Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs);
423 wordLen -= (cp - word) + pattern->leftLen;
424 word = cp + pattern->leftLen;
425 if (wordLen == 0 || (pattern->flags & VAR_SUB_GLOBAL) == 0){
434 Buf_AddByte(buf, (Byte)' ');
436 Buf_AddBytes(buf, wordLen, (Byte *)word);
439 * If added characters to the buffer, need to add a space
440 * before we add any more. If we didn't add any, just return
441 * the previous value of addSpace.
443 return ((Buf_Size(buf) != origSize) || addSpace);
446 * Common code for anchored substitutions:
447 * addSpace was set TRUE if characters were added to the buffer.
453 Buf_AddByte(buf, (Byte)' ');
455 Buf_AddBytes(buf, wordLen, (Byte *)word);
460 *-----------------------------------------------------------------------
462 * Perform a regex substitution on the given word, placing the
463 * result in the passed buffer. A space is added if requested.
466 * TRUE if a space is needed before more characters are added.
471 *-----------------------------------------------------------------------
474 VarRESubstitute(const char *word, Boolean addSpace, Buffer buf, void *patternp)
483 #define MAYBE_ADD_SPACE() \
484 if (addSpace && !added) \
485 Buf_AddByte(buf, ' '); \
492 if ((pat->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) ==
493 (VAR_SUB_ONE|VAR_SUB_MATCHED))
497 xrv = regexec(&pat->re, wp, pat->nsub, pat->matches, flags);
502 pat->flags |= VAR_SUB_MATCHED;
503 if (pat->matches[0].rm_so > 0) {
505 Buf_AddBytes(buf, pat->matches[0].rm_so, wp);
508 for (rp = pat->replace; *rp; rp++) {
509 if ((*rp == '\\') && ((rp[1] == '&') || (rp[1] == '\\'))) {
511 Buf_AddByte(buf,rp[1]);
514 else if ((*rp == '&') ||
515 ((*rp == '\\') && isdigit((unsigned char)rp[1]))) {
534 Error("No subexpression %s", &errstr[0]);
537 } else if ((pat->matches[n].rm_so == -1) &&
538 (pat->matches[n].rm_eo == -1)) {
539 Error("No match for subexpression %s", &errstr[0]);
543 subbuf = wp + pat->matches[n].rm_so;
544 sublen = pat->matches[n].rm_eo - pat->matches[n].rm_so;
549 Buf_AddBytes(buf, sublen, subbuf);
553 Buf_AddByte(buf, *rp);
556 wp += pat->matches[0].rm_eo;
557 if (pat->flags & VAR_SUB_GLOBAL) {
559 if (pat->matches[0].rm_so == 0 && pat->matches[0].rm_eo == 0) {
561 Buf_AddByte(buf, *wp);
570 Buf_AddBytes(buf, strlen(wp), wp);
574 VarREError(xrv, &pat->re, "Unexpected regex error");
579 Buf_AddBytes(buf,strlen(wp),wp);
583 return (addSpace||added);