Hiding pointer in typedefs is evil. 'Buffer *' -> 'Buffer'
[dragonfly.git] / usr.bin / make / var_modify.c
CommitLineData
4faecc47
MD
1/*
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
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Adam de Boor.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
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.
25 *
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
36 * SUCH DAMAGE.
37 *
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 $
6a3d9147 40 * $DragonFly: src/usr.bin/make/Attic/var_modify.c,v 1.13 2005/01/06 13:18:58 okumoto Exp $
4faecc47
MD
41 */
42
9863ce62
MO
43#include <ctype.h>
44#include <stdlib.h>
45#include <string.h>
46
47#include "buf.h"
48#include "config.h"
49#include "str.h"
50#include "util.h"
51#include "var.h"
4faecc47
MD
52
53/*-
54 *-----------------------------------------------------------------------
55 * VarHead --
56 * Remove the tail of the given word and place the result in the given
57 * buffer.
58 *
59 * Results:
60 * TRUE if characters were added to the buffer (a space needs to be
61 * added to the buffer before the next word).
62 *
63 * Side Effects:
64 * The trimmed word is added to the buffer.
65 *
66 *-----------------------------------------------------------------------
67 */
68Boolean
6a3d9147 69VarHead(const char *word, Boolean addSpace, Buffer *buf, void *dummy __unused)
4faecc47
MD
70{
71 char *slash;
72
2839d5df 73 slash = strrchr(word, '/');
b43288f3 74 if (slash != NULL) {
4faecc47 75 if (addSpace) {
2839d5df 76 Buf_AddByte(buf, (Byte)' ');
4faecc47 77 }
2cc22ebb 78 Buf_AddBytes(buf, slash - word, (Byte *)word);
4faecc47
MD
79 } else {
80 /*
81 * If no directory part, give . (q.v. the POSIX standard)
82 */
83 if (addSpace) {
c85c1181 84 Buf_AddBytes(buf, 2, (const Byte *)" .");
4faecc47
MD
85 } else {
86 Buf_AddByte(buf, (Byte)'.');
87 }
88 }
89 return (TRUE);
90}
91
92/*-
93 *-----------------------------------------------------------------------
94 * VarTail --
95 * Remove the head of the given word and place the result in the given
96 * buffer.
97 *
98 * Results:
99 * TRUE if characters were added to the buffer (a space needs to be
100 * added to the buffer before the next word).
101 *
102 * Side Effects:
103 * The trimmed word is added to the buffer.
104 *
105 *-----------------------------------------------------------------------
106 */
107Boolean
6a3d9147 108VarTail(const char *word, Boolean addSpace, Buffer *buf, void *dummy __unused)
4faecc47 109{
2cc22ebb 110 const char *slash;
4faecc47
MD
111
112 if (addSpace) {
b83dbac0 113 Buf_AddByte (buf, (Byte)' ');
4faecc47
MD
114 }
115
2839d5df 116 slash = strrchr(word, '/');
b43288f3 117 if (slash != NULL) {
2cc22ebb 118 slash++;
c85c1181 119 Buf_AddBytes(buf, strlen(slash), (const Byte *)slash);
4faecc47 120 } else {
c85c1181 121 Buf_AddBytes(buf, strlen(word), (const Byte *)word);
4faecc47
MD
122 }
123 return (TRUE);
124}
125
126/*-
127 *-----------------------------------------------------------------------
128 * VarSuffix --
129 * Place the suffix of the given word in the given buffer.
130 *
131 * Results:
132 * TRUE if characters were added to the buffer (a space needs to be
133 * added to the buffer before the next word).
134 *
135 * Side Effects:
136 * The suffix from the word is placed in the buffer.
137 *
138 *-----------------------------------------------------------------------
139 */
140Boolean
6a3d9147 141VarSuffix(const char *word, Boolean addSpace, Buffer *buf, void *dummy __unused)
4faecc47 142{
2cc22ebb 143 const char *dot;
4faecc47 144
2839d5df 145 dot = strrchr(word, '.');
b43288f3 146 if (dot != NULL) {
4faecc47 147 if (addSpace) {
2839d5df 148 Buf_AddByte(buf, (Byte)' ');
4faecc47 149 }
2cc22ebb 150 dot++;
c85c1181 151 Buf_AddBytes(buf, strlen(dot), (const Byte *)dot);
4faecc47
MD
152 addSpace = TRUE;
153 }
154 return (addSpace);
155}
156
157/*-
158 *-----------------------------------------------------------------------
159 * VarRoot --
160 * Remove the suffix of the given word and place the result in the
161 * buffer.
162 *
163 * Results:
164 * TRUE if characters were added to the buffer (a space needs to be
165 * added to the buffer before the next word).
166 *
167 * Side Effects:
168 * The trimmed word is added to the buffer.
169 *
170 *-----------------------------------------------------------------------
171 */
172Boolean
6a3d9147 173VarRoot(const char *word, Boolean addSpace, Buffer *buf, void *dummy __unused)
4faecc47
MD
174{
175 char *dot;
176
177 if (addSpace) {
2839d5df 178 Buf_AddByte(buf, (Byte)' ');
4faecc47
MD
179 }
180
2839d5df 181 dot = strrchr(word, '.');
b43288f3 182 if (dot != NULL) {
2cc22ebb 183 Buf_AddBytes(buf, dot - word, (Byte *)word);
4faecc47 184 } else {
76ac8a58 185 Buf_AddBytes(buf, strlen(word), (Byte *)word);
4faecc47
MD
186 }
187 return (TRUE);
188}
189
190/*-
191 *-----------------------------------------------------------------------
192 * VarMatch --
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.
197 *
198 * Results:
199 * TRUE if a space should be placed in the buffer before the next
200 * word.
201 *
202 * Side Effects:
203 * The word may be copied to the buffer.
204 *
205 *-----------------------------------------------------------------------
206 */
207Boolean
6a3d9147 208VarMatch(const char *word, Boolean addSpace, Buffer *buf, void *pattern)
4faecc47 209{
fbfaa208 210
b43288f3 211 if (Str_Match(word, pattern)) {
4faecc47
MD
212 if (addSpace) {
213 Buf_AddByte(buf, (Byte)' ');
214 }
215 addSpace = TRUE;
2cc22ebb 216 Buf_AddBytes(buf, strlen(word), word);
4faecc47 217 }
fbfaa208 218 return (addSpace);
4faecc47
MD
219}
220
221#ifdef SYSVVARSUB
222/*-
223 *-----------------------------------------------------------------------
224 * VarSYSVMatch --
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.
228 *
229 * Results:
230 * TRUE if a space should be placed in the buffer before the next
231 * word.
232 *
233 * Side Effects:
234 * The word may be copied to the buffer.
235 *
236 *-----------------------------------------------------------------------
237 */
238Boolean
6a3d9147 239VarSYSVMatch(const char *word, Boolean addSpace, Buffer *buf, void *patp)
4faecc47
MD
240{
241 int len;
242 const char *ptr;
fbfaa208 243 VarPattern *pat = (VarPattern *)patp;
4faecc47
MD
244
245 if (addSpace)
246 Buf_AddByte(buf, (Byte)' ');
247
248 addSpace = TRUE;
249
250 if ((ptr = Str_SYSVMatch(word, pat->lhs, &len)) != NULL)
251 Str_SYSVSubst(buf, pat->rhs, ptr, len);
252 else
c85c1181 253 Buf_AddBytes(buf, strlen(word), (const Byte *)word);
4faecc47 254
fbfaa208 255 return (addSpace);
4faecc47
MD
256}
257#endif
258
259
260/*-
261 *-----------------------------------------------------------------------
262 * VarNoMatch --
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.
266 *
267 * Results:
268 * TRUE if a space should be placed in the buffer before the next
269 * word.
270 *
271 * Side Effects:
272 * The word may be copied to the buffer.
273 *
274 *-----------------------------------------------------------------------
275 */
276Boolean
6a3d9147 277VarNoMatch(const char *word, Boolean addSpace, Buffer *buf, void *pattern)
4faecc47 278{
fbfaa208 279
b43288f3 280 if (!Str_Match(word, pattern)) {
4faecc47
MD
281 if (addSpace) {
282 Buf_AddByte(buf, (Byte)' ');
283 }
284 addSpace = TRUE;
c85c1181 285 Buf_AddBytes(buf, strlen(word), (const Byte *)word);
4faecc47 286 }
fbfaa208 287 return (addSpace);
4faecc47
MD
288}
289
290
291/*-
292 *-----------------------------------------------------------------------
293 * VarSubstitute --
294 * Perform a string-substitution on the given word, placing the
295 * result in the passed buffer. A space is added if requested.
296 *
297 * Results:
298 * TRUE if a space is needed before more characters are added.
299 *
300 * Side Effects:
301 * None.
302 *
303 *-----------------------------------------------------------------------
304 */
305Boolean
6a3d9147 306VarSubstitute(const char *word, Boolean addSpace, Buffer *buf, void *patternp)
4faecc47 307{
9cf296a4 308 size_t wordLen; /* Length of word */
4faecc47 309 const char *cp; /* General pointer */
9a4c88c2 310 VarPattern *pattern = patternp;
4faecc47
MD
311
312 wordLen = strlen(word);
313 if (1) { /* substitute in each word of the variable */
314 /*
315 * Break substitution down into simple anchored cases
316 * and if none of them fits, perform the general substitution case.
317 */
318 if ((pattern->flags & VAR_MATCH_START) &&
319 (strncmp(word, pattern->lhs, pattern->leftLen) == 0)) {
320 /*
321 * Anchored at start and beginning of word matches pattern
322 */
323 if ((pattern->flags & VAR_MATCH_END) &&
324 (wordLen == pattern->leftLen)) {
325 /*
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.
329 */
330 if (pattern->rightLen != 0) {
331 if (addSpace) {
332 Buf_AddByte(buf, (Byte)' ');
333 }
334 addSpace = TRUE;
335 Buf_AddBytes(buf, pattern->rightLen,
336 (Byte *)pattern->rhs);
337 }
338 } else if (pattern->flags & VAR_MATCH_END) {
339 /*
340 * Doesn't match to end -- copy word wholesale
341 */
342 goto nosub;
343 } else {
344 /*
345 * Matches at start but need to copy in trailing characters
346 */
347 if ((pattern->rightLen + wordLen - pattern->leftLen) != 0){
348 if (addSpace) {
349 Buf_AddByte(buf, (Byte)' ');
350 }
351 addSpace = TRUE;
352 }
353 Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs);
354 Buf_AddBytes(buf, wordLen - pattern->leftLen,
c85c1181 355 (const Byte *)(word + pattern->leftLen));
4faecc47
MD
356 }
357 } else if (pattern->flags & VAR_MATCH_START) {
358 /*
359 * Had to match at start of word and didn't -- copy whole word.
360 */
361 goto nosub;
362 } else if (pattern->flags & VAR_MATCH_END) {
363 /*
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
367 * to use strncmp.
368 */
369 cp = word + (wordLen - pattern->leftLen);
370 if ((cp >= word) &&
371 (strncmp(cp, pattern->lhs, pattern->leftLen) == 0)) {
372 /*
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.
377 */
378 if (((cp - word) + pattern->rightLen) != 0) {
379 if (addSpace) {
380 Buf_AddByte(buf, (Byte)' ');
381 }
382 addSpace = TRUE;
383 }
c85c1181 384 Buf_AddBytes(buf, cp - word, (const Byte *)word);
4faecc47
MD
385 Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs);
386 } else {
387 /*
388 * Had to match at end and didn't. Copy entire word.
389 */
390 goto nosub;
391 }
392 } else {
393 /*
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
400 * buffer.
401 * addSpace is set FALSE as soon as a space is added to the
402 * buffer.
403 */
404 Boolean done;
4f762dd1 405 size_t origSize;
4faecc47
MD
406
407 done = FALSE;
408 origSize = Buf_Size(buf);
409 while (!done) {
410 cp = strstr(word, pattern->lhs);
b43288f3 411 if (cp != NULL) {
4faecc47
MD
412 if (addSpace && (((cp - word) + pattern->rightLen) != 0)){
413 Buf_AddByte(buf, (Byte)' ');
414 addSpace = FALSE;
415 }
c85c1181 416 Buf_AddBytes(buf, cp-word, (const Byte *)word);
4faecc47
MD
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){
421 done = TRUE;
422 }
423 } else {
424 done = TRUE;
425 }
426 }
427 if (wordLen != 0) {
428 if (addSpace) {
429 Buf_AddByte(buf, (Byte)' ');
430 }
c85c1181 431 Buf_AddBytes(buf, wordLen, (const Byte *)word);
4faecc47
MD
432 }
433 /*
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.
437 */
438 return ((Buf_Size(buf) != origSize) || addSpace);
439 }
440 /*
441 * Common code for anchored substitutions:
442 * addSpace was set TRUE if characters were added to the buffer.
443 */
444 return (addSpace);
445 }
446 nosub:
447 if (addSpace) {
448 Buf_AddByte(buf, (Byte)' ');
449 }
c85c1181 450 Buf_AddBytes(buf, wordLen, (const Byte *)word);
fbfaa208 451 return (TRUE);
4faecc47
MD
452}
453
454/*-
455 *-----------------------------------------------------------------------
456 * VarRESubstitute --
457 * Perform a regex substitution on the given word, placing the
458 * result in the passed buffer. A space is added if requested.
459 *
460 * Results:
461 * TRUE if a space is needed before more characters are added.
462 *
463 * Side Effects:
464 * None.
465 *
466 *-----------------------------------------------------------------------
467 */
468Boolean
6a3d9147 469VarRESubstitute(const char *word, Boolean addSpace, Buffer *buf, void *patternp)
4faecc47
MD
470{
471 VarREPattern *pat;
472 int xrv;
473 const char *wp;
474 char *rp;
475 int added;
476 int flags = 0;
477
9a4c88c2
MO
478#define MAYBE_ADD_SPACE() \
479 if (addSpace && !added) \
480 Buf_AddByte(buf, (Byte)' '); \
4faecc47
MD
481 added = 1
482
483 added = 0;
484 wp = word;
485 pat = patternp;
486
9a4c88c2
MO
487 if ((pat->flags & (VAR_SUB_ONE | VAR_SUB_MATCHED)) ==
488 (VAR_SUB_ONE | VAR_SUB_MATCHED))
4faecc47
MD
489 xrv = REG_NOMATCH;
490 else {
491 tryagain:
492 xrv = regexec(&pat->re, wp, pat->nsub, pat->matches, flags);
493 }
494
495 switch (xrv) {
496 case 0:
497 pat->flags |= VAR_SUB_MATCHED;
498 if (pat->matches[0].rm_so > 0) {
499 MAYBE_ADD_SPACE();
c85c1181 500 Buf_AddBytes(buf, pat->matches[0].rm_so, (const Byte *)wp);
4faecc47
MD
501 }
502
503 for (rp = pat->replace; *rp; rp++) {
504 if ((*rp == '\\') && ((rp[1] == '&') || (rp[1] == '\\'))) {
505 MAYBE_ADD_SPACE();
9a4c88c2 506 Buf_AddByte(buf, (Byte)rp[1]);
4faecc47
MD
507 rp++;
508 }
509 else if ((*rp == '&') ||
510 ((*rp == '\\') && isdigit((unsigned char)rp[1]))) {
511 int n;
512 const char *subbuf;
513 int sublen;
514 char errstr[3];
515
516 if (*rp == '&') {
517 n = 0;
518 errstr[0] = '&';
519 errstr[1] = '\0';
520 } else {
521 n = rp[1] - '0';
522 errstr[0] = '\\';
523 errstr[1] = rp[1];
524 errstr[2] = '\0';
525 rp++;
526 }
527
528 if (n > pat->nsub) {
529 Error("No subexpression %s", &errstr[0]);
530 subbuf = "";
531 sublen = 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]);
535 subbuf = "";
536 sublen = 0;
537 } else {
538 subbuf = wp + pat->matches[n].rm_so;
539 sublen = pat->matches[n].rm_eo - pat->matches[n].rm_so;
540 }
541
542 if (sublen > 0) {
543 MAYBE_ADD_SPACE();
c85c1181 544 Buf_AddBytes(buf, sublen, (const Byte *)subbuf);
4faecc47
MD
545 }
546 } else {
547 MAYBE_ADD_SPACE();
9a4c88c2 548 Buf_AddByte(buf, (Byte)*rp);
4faecc47
MD
549 }
550 }
551 wp += pat->matches[0].rm_eo;
552 if (pat->flags & VAR_SUB_GLOBAL) {
553 flags |= REG_NOTBOL;
554 if (pat->matches[0].rm_so == 0 && pat->matches[0].rm_eo == 0) {
555 MAYBE_ADD_SPACE();
9a4c88c2 556 Buf_AddByte(buf, (Byte)*wp);
4faecc47
MD
557 wp++;
558
559 }
560 if (*wp)
561 goto tryagain;
562 }
563 if (*wp) {
564 MAYBE_ADD_SPACE();
c85c1181 565 Buf_AddBytes(buf, strlen(wp), (const Byte *)wp);
4faecc47
MD
566 }
567 break;
568 default:
569 VarREError(xrv, &pat->re, "Unexpected regex error");
570 /* fall through */
571 case REG_NOMATCH:
572 if (*wp) {
573 MAYBE_ADD_SPACE();
c85c1181 574 Buf_AddBytes(buf, strlen(wp), (const Byte *)wp);
4faecc47
MD
575 }
576 break;
577 }
9a4c88c2 578 return (addSpace || added);
4faecc47
MD
579}
580