Skip to content

Commit 9d08fee

Browse files
committed
Add support for macro aliases
Implement support for multi-level macro aliases, useful for the kind of thing aliases are: shortcuts, added level of indirection here and there for eg choosing between alternatives without copying and so on. The new %alias macro primitive can be used to define an alias and get the alias definition. The dual functionality is necessary because all other references to the alias get routed to the aliased macro. With the exception of undefine which undefines the alias itself.
1 parent 643283f commit 9d08fee

File tree

3 files changed

+143
-7
lines changed

3 files changed

+143
-7
lines changed

docs/manual/macros.md

+1
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ various common operations.
8181
| %define ... | define a macro
8282
| %undefine ... | undefine a macro
8383
| %global ... | define a macro whose body is available in global context
84+
| %alias ... | define an alias on another macro or get alias definition | 4.20.0
8485
| %{load:...} | load a macro file | 4.12.0
8586
| %{expand:...} | like eval, expand ... to <body> and (re-)expand <body>
8687
| %{expr:...} | evaluate an [expression](#expression-expansion) | 4.15.0

rpmio/macro.c

+60-7
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ enum macroFlags_e {
3939
ME_LITERAL = (1 << 2),
4040
ME_PARSE = (1 << 3),
4141
ME_FUNC = (1 << 4),
42+
ME_ALIAS = (1 << 5),
4243
};
4344

4445
typedef struct MacroBuf_s *MacroBuf;
@@ -161,7 +162,7 @@ static rpmMacroContext rpmmctxRelease(rpmMacroContext mc)
161162
* @param mc macro context
162163
* @param name macro name
163164
* @param namelen no. of bytes
164-
* @param pos found/insert position
165+
* @retval pos found/insert position
165166
* @return address of slot in macro table with name (or NULL)
166167
*/
167168
static rpmMacroEntry *
@@ -198,6 +199,30 @@ findEntry(rpmMacroContext mc, const char *name, size_t namelen, size_t *pos)
198199
return NULL;
199200
}
200201

202+
static rpmMacroEntry *
203+
findAlias(rpmMacroContext mc, const char *name, size_t namelen, size_t *pos)
204+
{
205+
const char *m = name;
206+
size_t mlen = namelen;
207+
rpmMacroEntry *mep = NULL;
208+
int depth = 0;
209+
210+
while ((mep = findEntry(mc, m, mlen, pos))) {
211+
if (!((*mep)->flags & ME_ALIAS))
212+
break;
213+
/* XXX can't flag an error from here, just fail as not found */
214+
if (++depth > max_macro_depth) {
215+
mep = NULL;
216+
break;
217+
}
218+
m = (*mep)->body;
219+
mlen = strlen(m);
220+
221+
}
222+
223+
return mep;
224+
}
225+
201226
/**
202227
* Create a new entry in the macro table.
203228
* @param mc macro context
@@ -950,7 +975,7 @@ freeArgs(MacroBuf mb)
950975
if (me->level < mb->level)
951976
continue;
952977
/* Warn on defined but unused non-automatic, scoped macros */
953-
if (!(me->flags & (ME_AUTO|ME_USED))) {
978+
if (!(me->flags & (ME_AUTO|ME_USED|ME_ALIAS))) {
954979
mbErr(mb, 0, _("Macro %%%s defined but not used within scope\n"),
955980
me->name);
956981
/* Only whine once */
@@ -1061,7 +1086,7 @@ grabArgs(MacroBuf mb, const rpmMacroEntry me, ARGV_t *argvp,
10611086
static void doBody(MacroBuf mb, rpmMacroEntry me, ARGV_t argv, size_t *parsed)
10621087
{
10631088
if (*argv[1]) {
1064-
rpmMacroEntry *mep = findEntry(mb->mc, argv[1], 0, NULL);
1089+
rpmMacroEntry *mep = findAlias(mb->mc, argv[1], 0, NULL);
10651090
if (mep) {
10661091
mbAppendStr(mb, (*mep)->body);
10671092
} else {
@@ -1352,6 +1377,33 @@ static void doRpmver(MacroBuf mb, rpmMacroEntry me, ARGV_t argv, size_t *parsed)
13521377
mbAppendStr(mb, VERSION);
13531378
}
13541379

1380+
static void doAlias(MacroBuf mb, rpmMacroEntry me, ARGV_t argv, size_t *parsed)
1381+
{
1382+
int ac = argvCount(argv);
1383+
rpmMacroEntry *mep = NULL;
1384+
switch (ac) {
1385+
case 2:
1386+
mep = findAlias(mb->mc, argv[1], 0, NULL);
1387+
if (mep && strcmp(argv[1], (*mep)->name))
1388+
mbAppendStr(mb, (*mep)->name);
1389+
break;
1390+
case 3:
1391+
if (validName(mb, argv[1], 0, "%alias")) {
1392+
mep = findAlias(mb->mc, argv[2], 0, NULL);
1393+
if (mep && strcmp(argv[1], argv[2])) {
1394+
/* Aliases are always on the level of the aliased macro */
1395+
pushMacro(mb->mc, argv[1], NULL, argv[2],
1396+
(*mep)->level, ME_ALIAS);
1397+
} else {
1398+
mbErr(mb, 1, _("Invalid alias on %%%s\n"), argv[2]);
1399+
}
1400+
}
1401+
break;
1402+
default:
1403+
mbErr(mb, 1, _("invalid number of arguments for %%alias"));
1404+
}
1405+
}
1406+
13551407
static struct builtins_s {
13561408
const char * name;
13571409
macroFunc func;
@@ -1360,6 +1412,7 @@ static struct builtins_s {
13601412
} const builtinmacros[] = {
13611413
{ "P", doSP, 1, 0 },
13621414
{ "S", doSP, 1, 0 },
1415+
{ "alias", doAlias, -1, 0 },
13631416
{ "basename", doFoo, 1, 0 },
13641417
{ "define", doDef, 1, ME_PARSE },
13651418
{ "dirname", doFoo, 1, 0 },
@@ -1606,7 +1659,7 @@ expandMacro(MacroBuf mb, const char *src, size_t slen)
16061659
printMacro(mb, s, se);
16071660

16081661
/* Expand defined macros */
1609-
mep = findEntry(mb->mc, f, fn, NULL);
1662+
mep = findAlias(mb->mc, f, fn, NULL);
16101663
me = (mep ? *mep : NULL);
16111664

16121665
if (me) {
@@ -1926,7 +1979,7 @@ int rpmExpandThisMacro(rpmMacroContext mc, const char *n, ARGV_const_t args, ch
19261979
int rc = 1; /* assume failure */
19271980

19281981
mc = rpmmctxAcquire(mc);
1929-
mep = findEntry(mc, n, 0, NULL);
1982+
mep = findAlias(mc, n, 0, NULL);
19301983
if (mep) {
19311984
MacroBuf mb = mbCreate(mc, flags);
19321985
rc = expandThisMacro(mb, *mep, args, flags);
@@ -2005,7 +2058,7 @@ int rpmMacroIsDefined(rpmMacroContext mc, const char *n)
20052058
{
20062059
int defined = 0;
20072060
if ((mc = rpmmctxAcquire(mc)) != NULL) {
2008-
if (findEntry(mc, n, 0, NULL))
2061+
if (findAlias(mc, n, 0, NULL))
20092062
defined = 1;
20102063
rpmmctxRelease(mc);
20112064
}
@@ -2016,7 +2069,7 @@ int rpmMacroIsParametric(rpmMacroContext mc, const char *n)
20162069
{
20172070
int parametric = 0;
20182071
if ((mc = rpmmctxAcquire(mc)) != NULL) {
2019-
rpmMacroEntry *mep = findEntry(mc, n, 0, NULL);
2072+
rpmMacroEntry *mep = findAlias(mc, n, 0, NULL);
20202073
if (mep && (*mep)->opts)
20212074
parametric = 1;
20222075
rpmmctxRelease(mc);

tests/rpmmacro.at

+82
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,88 @@ runroot rpm --eval '1. %{this}' --define "this that" --eval '2. %{this}' --undef
5757
])
5858
RPMTEST_CLEANUP
5959

60+
AT_SETUP([macro alias])
61+
AT_KEYWORDS([macros])
62+
RPMTEST_CHECK([
63+
runroot rpm \
64+
--define "this that" \
65+
--eval "%alias clone this" \
66+
--eval "%this" \
67+
--eval "%clone" \
68+
--define "this what" \
69+
--eval "%this" \
70+
--eval "%clone" \
71+
--undefine clone \
72+
--eval "%this" \
73+
--eval "%clone"
74+
],
75+
[0],
76+
[
77+
that
78+
that
79+
what
80+
what
81+
what
82+
%clone
83+
],
84+
[])
85+
86+
RPMTEST_CHECK([
87+
runroot rpm \
88+
--define "this(a) that %{?-a:arg} %1" \
89+
--eval "%alias clone this" \
90+
--eval "%clone -a 123" \
91+
--eval "%clone -b"
92+
],
93+
[1],
94+
[
95+
that arg 123
96+
],
97+
[this: invalid option -- 'b'
98+
error: Unknown option b in this(a)
99+
])
100+
101+
RPMTEST_CHECK([
102+
runroot rpm \
103+
--define "this that" \
104+
--eval "%alias me this" \
105+
--eval "%alias myself me" \
106+
--eval "%myself"
107+
],
108+
[0],
109+
[
110+
111+
that
112+
],
113+
[])
114+
115+
RPMTEST_CHECK([
116+
runroot rpm \
117+
--define "param() %{alias one 1}%{one}" \
118+
--eval "%param 123" \
119+
--eval "%one"
120+
],
121+
[0],
122+
[123
123+
%one
124+
],
125+
[])
126+
127+
RPMTEST_CHECK([
128+
runroot rpm \
129+
--define "this that" \
130+
--eval "%alias what this" \
131+
--eval "%alias what" \
132+
--eval "%alias this"
133+
],
134+
[0],
135+
[
136+
this
137+
138+
],
139+
[])
140+
RPMTEST_CLEANUP
141+
60142
AT_SETUP([simple true conditional rpm --eval])
61143
AT_KEYWORDS([macros])
62144
RPMTEST_CHECK([

0 commit comments

Comments
 (0)