2 * Copyright (c) 2002 Juli Mallett.
3 * Copyright (c) 1988, 1989, 1990, 1993
4 * The Regents of the University of California. All rights reserved.
5 * Copyright (c) 1989 by Berkeley Softworks
8 * This code is derived from software contributed to Berkeley by
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * @(#)var.c 8.3 (Berkeley) 3/19/94
40 * $FreeBSD: src/usr.bin/make/var.c,v 1.16.2.3 2002/02/27 14:18:57 cjc Exp $
41 * $DragonFly: src/usr.bin/make/Attic/var_modify.c,v 1.20 2005/01/31 09:49:14 okumoto Exp $
55 *-----------------------------------------------------------------------
57 * Remove the tail of the given word and place the result in the given
61 * TRUE if characters were added to the buffer (a space needs to be
62 * added to the buffer before the next word).
65 * The trimmed word is added to the buffer.
67 *-----------------------------------------------------------------------
70 VarHead(const char *word, Boolean addSpace, Buffer *buf, void *dummy __unused)
74 slash = strrchr(word, '/');
77 Buf_AddByte(buf, (Byte)' ');
79 Buf_AppendRange(buf, word, slash);
82 * If no directory part, give . (q.v. the POSIX standard)
85 Buf_Append(buf, " .");
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_Append(buf, slash);
122 Buf_Append(buf, word);
128 *-----------------------------------------------------------------------
130 * Place the suffix of the given word in the given buffer.
133 * TRUE if characters were added to the buffer (a space needs to be
134 * added to the buffer before the next word).
137 * The suffix from the word is placed in the buffer.
139 *-----------------------------------------------------------------------
142 VarSuffix(const char *word, Boolean addSpace, Buffer *buf, void *dummy __unused)
146 dot = strrchr(word, '.');
149 Buf_AddByte(buf, (Byte)' ');
152 Buf_Append(buf, dot);
159 *-----------------------------------------------------------------------
161 * Remove the suffix of the given word and place the result in the
165 * TRUE if characters were added to the buffer (a space needs to be
166 * added to the buffer before the next word).
169 * The trimmed word is added to the buffer.
171 *-----------------------------------------------------------------------
174 VarRoot(const char *word, Boolean addSpace, Buffer *buf, void *dummy __unused)
179 Buf_AddByte(buf, (Byte)' ');
182 dot = strrchr(word, '.');
184 Buf_AppendRange(buf, word, dot);
186 Buf_Append(buf, word);
192 *-----------------------------------------------------------------------
194 * Place the word in the buffer if it matches the given pattern.
195 * Callback function for VarModify to implement the :M modifier.
196 * A space will be added if requested. A pattern is supplied
197 * which the word must match.
200 * TRUE if a space should be placed in the buffer before the next
204 * The word may be copied to the buffer.
206 *-----------------------------------------------------------------------
209 VarMatch(const char *word, Boolean addSpace, Buffer *buf, void *pattern)
212 if (Str_Match(word, pattern)) {
214 Buf_AddByte(buf, (Byte)' ');
217 Buf_Append(buf, word);
224 *-----------------------------------------------------------------------
226 * Place the word in the buffer if it matches the given pattern.
227 * Callback function for VarModify to implement the System V %
228 * modifiers. A space is added if requested.
231 * TRUE if a space should be placed in the buffer before the next
235 * The word may be copied to the buffer.
237 *-----------------------------------------------------------------------
240 VarSYSVMatch(const char *word, Boolean addSpace, Buffer *buf, void *patp)
244 VarPattern *pat = (VarPattern *)patp;
247 Buf_AddByte(buf, (Byte)' ');
251 if ((ptr = Str_SYSVMatch(word, pat->lhs, &len)) != NULL)
252 Str_SYSVSubst(buf, pat->rhs, ptr, len);
254 Buf_Append(buf, word);
262 *-----------------------------------------------------------------------
264 * Place the word in the buffer if it doesn't match the given pattern.
265 * Callback function for VarModify to implement the :N modifier. A
266 * space is added if requested.
269 * TRUE if a space should be placed in the buffer before the next
273 * The word may be copied to the buffer.
275 *-----------------------------------------------------------------------
278 VarNoMatch(const char *word, Boolean addSpace, Buffer *buf, void *pattern)
281 if (!Str_Match(word, pattern)) {
283 Buf_AddByte(buf, (Byte)' ');
286 Buf_Append(buf, word);
293 *-----------------------------------------------------------------------
295 * Perform a string-substitution on the given word, placing the
296 * result in the passed buffer. A space is added if requested.
299 * TRUE if a space is needed before more characters are added.
304 *-----------------------------------------------------------------------
307 VarSubstitute(const char *word, Boolean addSpace, Buffer *buf, void *patternp)
309 size_t wordLen; /* Length of word */
310 const char *cp; /* General pointer */
311 VarPattern *pattern = patternp;
313 wordLen = strlen(word);
314 if (1) { /* substitute in each word of the variable */
316 * Break substitution down into simple anchored cases
317 * and if none of them fits, perform the general substitution case.
319 if ((pattern->flags & VAR_MATCH_START) &&
320 (strncmp(word, pattern->lhs, pattern->leftLen) == 0)) {
322 * Anchored at start and beginning of word matches pattern
324 if ((pattern->flags & VAR_MATCH_END) &&
325 (wordLen == pattern->leftLen)) {
327 * Also anchored at end and matches to the end (word
328 * is same length as pattern) add space and rhs only
329 * if rhs is non-null.
331 if (pattern->rightLen != 0) {
333 Buf_AddByte(buf, (Byte)' ');
336 Buf_AddBytes(buf, pattern->rightLen,
337 (Byte *)pattern->rhs);
339 } else if (pattern->flags & VAR_MATCH_END) {
341 * Doesn't match to end -- copy word wholesale
346 * Matches at start but need to copy in trailing characters
348 if ((pattern->rightLen + wordLen - pattern->leftLen) != 0){
350 Buf_AddByte(buf, (Byte)' ');
354 Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs);
355 Buf_AddBytes(buf, wordLen - pattern->leftLen,
356 (const Byte *)(word + pattern->leftLen));
358 } else if (pattern->flags & VAR_MATCH_START) {
360 * Had to match at start of word and didn't -- copy whole word.
363 } else if (pattern->flags & VAR_MATCH_END) {
365 * Anchored at end, Find only place match could occur (leftLen
366 * characters from the end of the word) and see if it does. Note
367 * that because the $ will be left at the end of the lhs, we have
370 cp = word + (wordLen - pattern->leftLen);
372 (strncmp(cp, pattern->lhs, pattern->leftLen) == 0)) {
374 * Match found. If we will place characters in the buffer,
375 * add a space before hand as indicated by addSpace, then
376 * stuff in the initial, unmatched part of the word followed
377 * by the right-hand-side.
379 if (((cp - word) + pattern->rightLen) != 0) {
381 Buf_AddByte(buf, (Byte)' ');
385 Buf_AppendRange(buf, word, cp);
386 Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs);
389 * Had to match at end and didn't. Copy entire word.
395 * Pattern is unanchored: search for the pattern in the word using
396 * strstr(3), copying unmatched portions and the
397 * right-hand-side for each match found, handling non-global
398 * substitutions correctly, etc. When the loop is done, any
399 * remaining part of the word (word and wordLen are adjusted
400 * accordingly through the loop) is copied straight into the
402 * addSpace is set FALSE as soon as a space is added to the
409 origSize = Buf_Size(buf);
411 cp = strstr(word, pattern->lhs);
413 if (addSpace && (((cp - word) + pattern->rightLen) != 0)){
414 Buf_AddByte(buf, (Byte)' ');
417 Buf_AppendRange(buf, word, cp);
418 Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs);
419 wordLen -= (cp - word) + pattern->leftLen;
420 word = cp + pattern->leftLen;
421 if (wordLen == 0 || (pattern->flags & VAR_SUB_GLOBAL) == 0){
430 Buf_AddByte(buf, (Byte)' ');
432 Buf_AddBytes(buf, wordLen, (const Byte *)word);
435 * If added characters to the buffer, need to add a space
436 * before we add any more. If we didn't add any, just return
437 * the previous value of addSpace.
439 return ((Buf_Size(buf) != origSize) || addSpace);
442 * Common code for anchored substitutions:
443 * addSpace was set TRUE if characters were added to the buffer.
449 Buf_AddByte(buf, (Byte)' ');
451 Buf_AddBytes(buf, wordLen, (const Byte *)word);
456 *-----------------------------------------------------------------------
458 * Perform a regex substitution on the given word, placing the
459 * result in the passed buffer. A space is added if requested.
462 * TRUE if a space is needed before more characters are added.
467 *-----------------------------------------------------------------------
470 VarRESubstitute(const char *word, Boolean addSpace, Buffer *buf, void *patternp)
479 #define MAYBE_ADD_SPACE() \
480 if (addSpace && !added) \
481 Buf_AddByte(buf, (Byte)' '); \
488 if ((pat->flags & (VAR_SUB_ONE | VAR_SUB_MATCHED)) ==
489 (VAR_SUB_ONE | VAR_SUB_MATCHED))
493 xrv = regexec(&pat->re, wp, pat->nsub, pat->matches, flags);
498 pat->flags |= VAR_SUB_MATCHED;
499 if (pat->matches[0].rm_so > 0) {
501 Buf_AddBytes(buf, pat->matches[0].rm_so, (const Byte *)wp);
504 for (rp = pat->replace; *rp; rp++) {
505 if ((*rp == '\\') && ((rp[1] == '&') || (rp[1] == '\\'))) {
507 Buf_AddByte(buf, (Byte)rp[1]);
510 else if ((*rp == '&') ||
511 ((*rp == '\\') && isdigit((unsigned char)rp[1]))) {
530 Error("No subexpression %s", &errstr[0]);
533 } else if ((pat->matches[n].rm_so == -1) &&
534 (pat->matches[n].rm_eo == -1)) {
535 Error("No match for subexpression %s", &errstr[0]);
539 subbuf = wp + pat->matches[n].rm_so;
540 sublen = pat->matches[n].rm_eo - pat->matches[n].rm_so;
545 Buf_AddBytes(buf, sublen, (const Byte *)subbuf);
549 Buf_AddByte(buf, (Byte)*rp);
552 wp += pat->matches[0].rm_eo;
553 if (pat->flags & VAR_SUB_GLOBAL) {
555 if (pat->matches[0].rm_so == 0 && pat->matches[0].rm_eo == 0) {
557 Buf_AddByte(buf, (Byte)*wp);
570 VarREError(xrv, &pat->re, "Unexpected regex error");
579 return (addSpace || added);