| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: var.c,v 1.934 2021/06/21 08:40:44 rillig Exp $ */ | | 1 | /* $NetBSD: var.c,v 1.935 2021/06/21 17:21:37 rillig Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1988, 1989, 1990, 1993 | | 4 | * Copyright (c) 1988, 1989, 1990, 1993 |
5 | * The Regents of the University of California. All rights reserved. | | 5 | * The Regents of the University of California. All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to Berkeley by | | 7 | * This code is derived from software contributed to Berkeley by |
8 | * Adam de Boor. | | 8 | * Adam de Boor. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
| @@ -130,27 +130,27 @@ | | | @@ -130,27 +130,27 @@ |
130 | #include <regex.h> | | 130 | #include <regex.h> |
131 | #endif | | 131 | #endif |
132 | #include <errno.h> | | 132 | #include <errno.h> |
133 | #include <inttypes.h> | | 133 | #include <inttypes.h> |
134 | #include <limits.h> | | 134 | #include <limits.h> |
135 | #include <time.h> | | 135 | #include <time.h> |
136 | | | 136 | |
137 | #include "make.h" | | 137 | #include "make.h" |
138 | #include "dir.h" | | 138 | #include "dir.h" |
139 | #include "job.h" | | 139 | #include "job.h" |
140 | #include "metachar.h" | | 140 | #include "metachar.h" |
141 | | | 141 | |
142 | /* "@(#)var.c 8.3 (Berkeley) 3/19/94" */ | | 142 | /* "@(#)var.c 8.3 (Berkeley) 3/19/94" */ |
143 | MAKE_RCSID("$NetBSD: var.c,v 1.934 2021/06/21 08:40:44 rillig Exp $"); | | 143 | MAKE_RCSID("$NetBSD: var.c,v 1.935 2021/06/21 17:21:37 rillig Exp $"); |
144 | | | 144 | |
145 | /* | | 145 | /* |
146 | * Variables are defined using one of the VAR=value assignments. Their | | 146 | * Variables are defined using one of the VAR=value assignments. Their |
147 | * value can be queried by expressions such as $V, ${VAR}, or with modifiers | | 147 | * value can be queried by expressions such as $V, ${VAR}, or with modifiers |
148 | * such as ${VAR:S,from,to,g:Q}. | | 148 | * such as ${VAR:S,from,to,g:Q}. |
149 | * | | 149 | * |
150 | * There are 3 kinds of variables: scope variables, environment variables, | | 150 | * There are 3 kinds of variables: scope variables, environment variables, |
151 | * undefined variables. | | 151 | * undefined variables. |
152 | * | | 152 | * |
153 | * Scope variables are stored in a GNode.scope. The only way to undefine | | 153 | * Scope variables are stored in a GNode.scope. The only way to undefine |
154 | * a scope variable is using the .undef directive. In particular, it must | | 154 | * a scope variable is using the .undef directive. In particular, it must |
155 | * not be possible to undefine a variable during the evaluation of an | | 155 | * not be possible to undefine a variable during the evaluation of an |
156 | * expression, or Var.name might point nowhere. | | 156 | * expression, or Var.name might point nowhere. |
| @@ -1596,104 +1596,100 @@ struct ModifyWord_SubstRegexArgs { | | | @@ -1596,104 +1596,100 @@ struct ModifyWord_SubstRegexArgs { |
1596 | /* | | 1596 | /* |
1597 | * Callback for ModifyWords to implement the :C/from/to/ modifier. | | 1597 | * Callback for ModifyWords to implement the :C/from/to/ modifier. |
1598 | * Perform a regex substitution on the given word. | | 1598 | * Perform a regex substitution on the given word. |
1599 | */ | | 1599 | */ |
1600 | static void | | 1600 | static void |
1601 | ModifyWord_SubstRegex(Substring word, SepBuf *buf, void *data) | | 1601 | ModifyWord_SubstRegex(Substring word, SepBuf *buf, void *data) |
1602 | { | | 1602 | { |
1603 | struct ModifyWord_SubstRegexArgs *args = data; | | 1603 | struct ModifyWord_SubstRegexArgs *args = data; |
1604 | int xrv; | | 1604 | int xrv; |
1605 | const char *wp; | | 1605 | const char *wp; |
1606 | const char *rp; | | 1606 | const char *rp; |
1607 | int flags = 0; | | 1607 | int flags = 0; |
1608 | regmatch_t m[10]; | | 1608 | regmatch_t m[10]; |
| | | 1609 | size_t n; |
1609 | | | 1610 | |
1610 | assert(word.end[0] == '\0'); /* assume null-terminated word */ | | 1611 | assert(word.end[0] == '\0'); /* assume null-terminated word */ |
1611 | wp = word.start; | | 1612 | wp = word.start; |
1612 | if (args->pflags.subOnce && args->matched) | | 1613 | if (args->pflags.subOnce && args->matched) { |
1613 | goto nosub; | | 1614 | nosub: |
| | | 1615 | SepBuf_AddStr(buf, wp); |
| | | 1616 | return; |
| | | 1617 | } |
1614 | | | 1618 | |
1615 | tryagain: | | 1619 | again: |
1616 | xrv = regexec(&args->re, wp, args->nsub, m, flags); | | 1620 | xrv = regexec(&args->re, wp, args->nsub, m, flags); |
| | | 1621 | if (xrv == 0) |
| | | 1622 | goto ok; |
| | | 1623 | if (xrv != REG_NOMATCH) |
| | | 1624 | VarREError(xrv, &args->re, "Unexpected regex error"); |
| | | 1625 | goto nosub; |
1617 | | | 1626 | |
1618 | switch (xrv) { | | 1627 | ok: |
1619 | case 0: | | 1628 | args->matched = true; |
1620 | args->matched = true; | | 1629 | SepBuf_AddBytes(buf, wp, (size_t)m[0].rm_so); |
1621 | SepBuf_AddBytes(buf, wp, (size_t)m[0].rm_so); | | | |
1622 | | | 1630 | |
1623 | /* | | 1631 | /* |
1624 | * Replacement of regular expressions is not specified by | | 1632 | * Replacement of regular expressions is not specified by |
1625 | * POSIX, therefore implement it here. | | 1633 | * POSIX, therefore re-implement it here. |
1626 | */ | | 1634 | */ |
1627 | | | 1635 | |
1628 | for (rp = args->replace; *rp != '\0'; rp++) { | | 1636 | for (rp = args->replace; *rp != '\0'; rp++) { |
1629 | if (*rp == '\\' && (rp[1] == '&' || rp[1] == '\\')) { | | 1637 | if (*rp == '\\' && (rp[1] == '&' || rp[1] == '\\')) { |
1630 | SepBuf_AddBytes(buf, rp + 1, 1); | | 1638 | SepBuf_AddBytes(buf, rp + 1, 1); |
1631 | rp++; | | 1639 | rp++; |
1632 | continue; | | 1640 | continue; |
1633 | } | | 1641 | } |
1634 | | | 1642 | |
1635 | if (*rp == '&') { | | 1643 | if (*rp == '&') { |
1636 | SepBuf_AddBytesBetween(buf, | | 1644 | SepBuf_AddBytesBetween(buf, |
1637 | wp + m[0].rm_so, wp + m[0].rm_eo); | | 1645 | wp + m[0].rm_so, wp + m[0].rm_eo); |
1638 | continue; | | 1646 | continue; |
1639 | } | | 1647 | } |
1640 | | | 1648 | |
1641 | if (*rp != '\\' || !ch_isdigit(rp[1])) { | | 1649 | if (*rp != '\\' || !ch_isdigit(rp[1])) { |
1642 | SepBuf_AddBytes(buf, rp, 1); | | 1650 | SepBuf_AddBytes(buf, rp, 1); |
1643 | continue; | | 1651 | continue; |
1644 | } | | 1652 | } |
1645 | | | 1653 | |
1646 | { /* \0 to \9 backreference */ | | 1654 | /* \0 to \9 backreference */ |
1647 | size_t n = (size_t)(rp[1] - '0'); | | 1655 | n = (size_t)(rp[1] - '0'); |
1648 | rp++; | | 1656 | rp++; |
1649 | | | 1657 | |
1650 | if (n >= args->nsub) { | | 1658 | if (n >= args->nsub) { |
1651 | Error("No subexpression \\%u", | | 1659 | Error("No subexpression \\%u", (unsigned)n); |
1652 | (unsigned)n); | | 1660 | } else if (m[n].rm_so == -1) { |
1653 | } else if (m[n].rm_so == -1) { | | 1661 | if (opts.strict) { |
1654 | if (opts.strict) { | | 1662 | Error("No match for subexpression \\%u", |
1655 | Error( | | 1663 | (unsigned)n); |
1656 | "No match for subexpression \\%u", | | | |
1657 | (unsigned)n); | | | |
1658 | } | | | |
1659 | } else { | | | |
1660 | SepBuf_AddBytesBetween(buf, | | | |
1661 | wp + m[n].rm_so, wp + m[n].rm_eo); | | | |
1662 | } | | | |
1663 | } | | 1664 | } |
| | | 1665 | } else { |
| | | 1666 | SepBuf_AddBytesBetween(buf, |
| | | 1667 | wp + m[n].rm_so, wp + m[n].rm_eo); |
1664 | } | | 1668 | } |
| | | 1669 | } |
1665 | | | 1670 | |
1666 | wp += m[0].rm_eo; | | 1671 | wp += m[0].rm_eo; |
1667 | if (args->pflags.subGlobal) { | | 1672 | if (args->pflags.subGlobal) { |
1668 | flags |= REG_NOTBOL; | | 1673 | flags |= REG_NOTBOL; |
1669 | if (m[0].rm_so == 0 && m[0].rm_eo == 0) { | | 1674 | if (m[0].rm_so == 0 && m[0].rm_eo == 0) { |
1670 | SepBuf_AddBytes(buf, wp, 1); | | 1675 | SepBuf_AddBytes(buf, wp, 1); |
1671 | wp++; | | 1676 | wp++; |
1672 | } | | | |
1673 | if (*wp != '\0') | | | |
1674 | goto tryagain; | | | |
1675 | } | | 1677 | } |
1676 | if (*wp != '\0') | | 1678 | if (*wp != '\0') |
1677 | SepBuf_AddStr(buf, wp); | | 1679 | goto again; |
1678 | break; | | | |
1679 | default: | | | |
1680 | VarREError(xrv, &args->re, "Unexpected regex error"); | | | |
1681 | /* FALLTHROUGH */ | | | |
1682 | case REG_NOMATCH: | | | |
1683 | nosub: | | | |
1684 | SepBuf_AddStr(buf, wp); | | | |
1685 | break; | | | |
1686 | } | | 1680 | } |
| | | 1681 | if (*wp != '\0') |
| | | 1682 | SepBuf_AddStr(buf, wp); |
1687 | } | | 1683 | } |
1688 | #endif | | 1684 | #endif |
1689 | | | 1685 | |
1690 | | | 1686 | |
1691 | struct ModifyWord_LoopArgs { | | 1687 | struct ModifyWord_LoopArgs { |
1692 | GNode *scope; | | 1688 | GNode *scope; |
1693 | const char *var; /* name of the temporary variable */ | | 1689 | const char *var; /* name of the temporary variable */ |
1694 | const char *body; /* string to expand */ | | 1690 | const char *body; /* string to expand */ |
1695 | VarEvalMode emode; | | 1691 | VarEvalMode emode; |
1696 | }; | | 1692 | }; |
1697 | | | 1693 | |
1698 | /* Callback for ModifyWords to implement the :@var@...@ modifier of ODE make. */ | | 1694 | /* Callback for ModifyWords to implement the :@var@...@ modifier of ODE make. */ |
1699 | static void | | 1695 | static void |