In GNU M4, I've been trying to write a function that determines how many non-empty (args that don't equal `'
) passed to it.
It's supposed to be callable like so:
ne_nargs(0, `1', `')
# 1
ne_nargs(0, `')
# 0
ne_nargs(0, `1')
# 1
Note that the first argument should always be 0
.
Here's the code that I've got so far:
define(`ne_nargs', `ifelse(`$#', `1`, $1,
`ifelse(`$2', `', `pushdef(`$2', $1)ne_nargs(shift($@))',
`pushdef(`$2', incr($1))ne_nargs(shift($@))')')')
And here's the pseudo-code for it:
if (number_of_args == 1); then
return first_arg; // which is `0` by default.
else if (second_arg == ''); then
second_arg = first_arg;
return ne_nargs(shift(all_args));
else
second_arg = (++first_arg);
return ne_nargs(shift(all_args));
ne_nargs(`0', `', `1', `i', `', `l')
# what I get
m4:test.m4:8: empty string treated as 0 in builtin `incr'
m4:test.m4:8: empty string treated as 0 in builtin `incr'
1
# what I expect
3
I can't figure out what I'm doing wrong in the definition of ne_nargs
, and after trying a few different ways of abstracting parts of the macro, I'm about ready to give up.
I don't think you should try to overwrite $@
; you can see from the warnings that overwriting $2 definitely isn't affecting $@
. The join example in the docs instead shifts out the second argument with:
`$0(`$1', shift(shift($@)))'
So the following works:
define(`ne_nargs', `ifelse(`$#', `2', `ifelse(`$2', `', `$1', incr(`$1'))',
`ifelse(`$2', `', `$0(`$1', shift(shift($@)))',
`$0(incr($1), shift(shift($@)))')')')
ne_nargs(`0', `', `1', `i', `', `l')
(I don't know a good way to cleanup the recursive call so the 2 argument call doesn't have to be independently checked, so that may be something to improve on if you are concerned about DRYness.)