If there was a \ at the end of the buffer, the code would
return a pointer after the trailing \0 leading to unallocated
memory access and weird results in some cases.
See commit 817959609b.
macro.c: In function ‘mbopt’:
macro.c:895:19: warning: unused variable ‘me’ [-Wunused-variable]
895 | rpmMacroEntry me = mb->me;
| ^~
rpmlua.c: In function ‘fd_seek’:
rpmlua.c:985:22: warning: unused variable ‘mode’ [-Wunused-variable]
985 | static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END};
| ^~~~
The former is actually unused, the latter should be used.
Avoids code duplication (glibc quirks and whatnot) between macro and lua
option parsing, isolate the global opt* variable accesses to one spot.
Makes it easier to ensure identical behavior between the users if/when
something changes.
No behavior changes intended.
This seems to be the intention of the code but it did
not work because macro parsing was resumed at the wrong
point of the input string. Without this commit, "%{}"
expanded to "%" instead of "%{}".
We already have the macro arguments in an ARGV that's suitable for
passing to Lua, just store it in the macro buffer for passing around.
As macros can nest arbitrarily, we need to store and restore the mb
args which is a bit hacky, but much less trouble than changing all the
related functions to pass argound an argv which only one function
ever uses. Ditto with the macro entry itself, which is needed to pass
around the options (and name, and maybe something else too later).
Besides all the normal rpm defined macros for arguments and options,
parametric Lua macros now get pre-processed options and arguments
in native local tables "opt" and "arg" for much more pleasant access.
"opt" and "arg" tables are always there even if no options or arguments
were passed, this avoids having to deal with multiple cases and test
for nil's all over the place.
Fixes: #1092
Add support for passing getopt options and arguments to natively to Lua
scriptlets via the internal API. The processed opts and args are stored
in two chunk local two tables, options keyed by the letter and arguments
by their numeric index.
Update call sites accordingly, but no actual functionality changes here,
just pre-requisites for next steps.
Commit cb4e5e755a added flags arguments
to rpmExprBool() and rpmExprStr(), but unfortunately rpm 4.15 sailed
with flagless versions them. It's extremely unlikely that anything out
there is actually using these, but then you never really know.
Rpm soname bumps are so inconvenient that we really do not want to do
that just for these two, so preserve binary compatibility and restore
flagless variants of both, adjust internal code to use flagged versions
always. If only we had symbol versioning, sigh.
Whether a macro is defined can be tested with eg rpmExpandNumeric()
but this is somewhat cumbersome and expensive for such a simple thing.
Prior to this, there was no way to find out whether a macro is
parametric (aka parameterized) or not.
%{expand:...} is a rather special built-in as its *purpose* is to
double-expand its argument, so it makes sense to separate it from
the others.
No functional changes intended here.
%{uncompress:...} is fairly complicated as far as builtin macros go:
it needs to first expand its argument to discover the actual file
its supposed to look at, then determine whether the file exists and
what sort of compression to use, then determine the macro to use
for decompressing that kind of file, expand said macro and finally
catenate the expanded argument to the lot. That's a lot of goo to
do inline doFoo(), so refactor it into a separate function.
Up to now the last step was implemented by re-expanding the argument
too, which makes it impossible to reliably handle paths with percent
signs. Just expand the command, and catenate the argument as deity
intended.
Additionally make behavior with empty argument consistent with other
builtins: %{uncompress:} expands to nothing instead of printing out
an error message with an empty filename.
We can't assume that a buffer allocated for one thing is sufficient
for another thing. The S and P macros share the same exact logic,
refactor to use common code to avoid having to fix twice, cleaning
up doFoo() a bit in the process.
Fixes: #1019
Before this commit, there was an "escape" flag that made the macro
expansion keep '%%' escapes. But this did not work for macros
that returned an '%' character by other means.
Remove the old escape mechanism and instead double the '%' characters
when the body is split into argument.
Fixes: #1055
The calculation of the slen parameter was not correct, as it didn't
account for already processed characters. The parameter itself was
also not used to limit the passed string, as the code assumed zero
termination. Thus we can as well simplify the code by using strlen()
on the passed string.
Supports the same expressions as spec %if conditions because, well,
it's the same expression parser. Only this returns the result as
a string instead of a boolean.
There has been no way to add comments to multiline macros, and while
spec files technically support #-commenting at beginning of lines, it
does not apply to all sections and causes generation after generation
of packagers to stumble on the same items over and over: macros
are expanded within spec comment lines, which makes commenting multiline
macros such as %configure annoying, comments inteded for scriptlets
end up being in the previous scriptlets body, and numerous other quirks.
This implements the M4-inspired %dnl macro primitive which literally
discards everything until the next newline (or end of string), without
expanding the contents. This allows comments to be used inside multiline
macros and everywhere in spec.
Caveat: in some places such as %description the newline doesn't actually
get discarded but this is a a spec parser issue, not on the macro side.
Closes: #158
Report file name and/or line number on macro errors if %__file_name
and/or %__file_lineno macros are defined, arrange them to be
appropriately defined when loading macro files. Drop the former per-file
failure counting as its no longer useful. Add a testcase.
rdcl() reads line continuations so its useful to know how many
physical lines it read. The returned buffer was never used by anything
so no actual behavior changes here, but we'll need this shortly.
Problem was in a buffer over-read of the memory right after
the end of the allocated area when expanding of an unfinished macro
starting "%{" that can contain only exclamation marks and question
marks. Like "%{", or "%{!", or "%{??!".
Similar problem as in commit 54f24ec548
with the difference that this problem was not found by a memory
sanitizer.
This is a good opportunity to refactor the corresponding code
(setting variables according to the number of exclamation marks and
question mark after % an before the macro).
These are very different from the other built-ins as these do their
own parsing and return a continue address, so we need a separate
prototype for them. Having two pointers for each macro makes the table
a bit ugly but the alternative of tracking type by some other means
would lose type-safety. Other than all the boilerplate needed, this is
remarkably straightforward. No functional changes.
All built-in macros are now invoked via the lookup-table, which means
that adding new built-ins just got more straightforward and less ad hocey
pokey.
%trace differs from the others as it doesn't take any arguments,
it just silently eats any passed. Not that it really matters here.
No functional changes.
Annoyingly the amount of other boilerplate makes this slightly more code
than the original, but then saner code isn't always smaller, and it does
make expandMacros() smaller, which can only be a good thing.
No functional changes.
Handle log level determination inside doOutput() to make the interface
match with the others and as a bonus, make expandMacros() that little
bit smaller again. Empty argument needs to be handled differently
but shouldn't affect functionality.
No functional changes. chkexist and negate arguments are unused for
now, but they could perhaps be used for error condition handling later
(similar to %load)
Replace the "necessary but clunky" string comparisons in expandMacro()
with a lookup on the builtins. For starters, only the primitives
handled in doFoo() are converted, others will require varying amount
of further changes. chkexist argument is unused by doFoo() but will be
needed later for others, add now to avoid having to change more later.
No functional changes intended, anything like that would simply be a bug.
For current uses this shouldn't make any difference, but much of the
macro engine works with string lengths so to avoid having to create
\0-terminated versions of all strings we might look at...
There's an increasing number of placing wanting to know the number of
CPU's for parallel processing, and increasingly these things are running
in containers and such where the total host CPU count is not meaningful.
The algorithm that detects the end of a macro counts for all macro chars their level of nested. It iteratively moves from the first char of the macro further.
Before the patch the rpm function does not implement this algorithm correctly. After finishing with the last char of a macro line, it additionally skips one char of the next line. The first char in the line was omitted.
Probably affects every rpm version from this millenium.
It's much easier for rpm to point out the location of invalid macro
definitions than it is for humans to grep all the places a given rpm
version might look at. Log the macro file path once per file in case
of failures, and additionally return and error if all definitions fail.
Based on patch by Pavlina Moravcova Varekova.
Prior to this patch if a name of a newly created macro was the same as a built-in macro name, the macro looked correctly defined. But the newly defined macro could not be used.
It is obvious that a built-in macro can not be undefined.