1 divert(-1)dnl -*- m4 -*-
2 # Not intended for standalone usage. Instead, include it from dayXX.m4 as:
3 # include(`common.m4')ifelse(common(1), `ok', `',
4 # `errprint(`Missing common initialization
7 # Borrow from m4's examples/forloop3.m4
8 define(`forloop_arg', `ifelse(eval(`($1) <= ($2)'), `1',
9 `_forloop(eval(`$1'), `incr', eval(`$2'), `$3(', `)')')')
10 define(`forloop_var', `ifelse(eval(`($2) <= ($3)'), `1',
11 `pushdef(`$1')_forloop(eval(`$2'), `incr', eval(`$3'),
12 `define(`$1',', `)$4')popdef(`$1')')')
13 define(`forloop_rev', `ifelse(eval(`($1) >= ($2)'), `1',
14 `_forloop(eval(`$1'), `decr', eval(`$2'), `$3', `$4')')')
15 define(`forloop', `_$0($1, `incr', $2, `$3', `$4')')
16 define(`_forloop', `$4`$1'$5`'ifelse(`$1', `$3', `',
17 `$0($2(`$1'), `$2', $3, `$4', `$5')')')
19 # Idiomatic POSIX m4 uses tail recursion via shift($@), but it costs quadratic
20 # scanning time in GNU m4 1.4 as $@ gets longer. If we detect GNU m4, we
21 # can rely on $10 expanding to the tenth argument (instead of $1 concatenated
22 # with a literal 0), and exploit that for faster list processing.
23 # See https://git.sv.gnu.org/cgit/autoconf.git/tree/lib/m4sugar/foreach.m4
25 `define(`_foreach', `ifelse(`$#', 3, `', `pushdef(`t', `popdef(
26 `t')'_forloop(4, `incr', `$#', `$0_(1, 2,',
27 `)'))t($@)')')define(`_foreach_', ``$$1`$$3'$$2`''')',
28 `define(`_foreach', `ifelse(`$#', 3, `', `$1`$4'$2`'$0(`$1', `$2',
29 shift(shift(shift($@))))')')')
30 define(`foreach', `_$0(`$1(', `)', $@)')
32 # Borrow from Autoconf's m4sugar.m4
33 define(`stack_reverse', `ifdef(`$1', `pushdef(`$2',
34 defn(`$1'))$3`'popdef(`$1')$0($@)')')
35 define(`stack_foreach', `_$0(`$1', `$2(', `)', `t')')
36 define(`_stack_foreach', `stack_reverse(`$1', `$4')stack_reverse(`$4', `$1',
39 # Other frequently used macros
41 define(`alpha', `abcdefghijklmnopqrstuvwxyz')
42 define(`ALPHA', `ABCDEFGHIJKLMNOPQRSTUVWXYZ')
45 define(`errprintn', `errprint(`$1'nl())')
46 define(`fatal', `errprintn(`$1')m4exit(1)')
47 define(`exists', `syscmd(`test -f "$1"')ifelse(sysval, 0, `$2', `$3')')
48 define(`_include', defn(`include'))
49 pushdef(`include', `exists(`$1', `',
50 `fatal(`Could not locate file $1')')_$0(`$1')')
51 ifdef(`verbose', `ifelse(defn(`verbose'), `', `define(`verbose', 1)')',
52 `define(`verbose', 0)')
53 define(`output', `ifelse(eval(verbose >= $1), 1, `errprintn(`$2')')')
55 define(`quote', `ifelse($#, `0', `', ``$*'')')
56 define(`dquote', ``$@'')
58 # There are some puzzles where 'm4 -H...' makes a difference in runtime;
59 # if $2 is non-empty, attempt to re-exec if the command line learned
60 # from /proc/self is not at least that large. Not robust to command
61 # lines with ' or \n embedded, so use with caution.
62 define(`ensurehash', `define(`cmdline', dquote(patsubst(
63 esyscmd(`tr "\\0" "\\n" < /proc/$PPID/cmdline | sed s/^/#/'),
64 `#\(.*\)', ``\1',')))regexp(defn(`cmdline'),
65 ``\(-H\|--ha[a-z=]*\)\(.,.\)?\([0-9]*\)'',
66 `define(`foundhash', `\3')')ifdef(`foundhash', `', `define(`foundhash',
67 509)')ifelse(eval($1 <= foundhash), 1, `', ifdef(`hashsize', 1), 1,
68 `output(1, `-Dhashsize='hashsize` detected, not reexecing')',
69 index(defn(`cmdline'), `,`-','), -1, `reexec($1, cmdline)',
70 `errprintn(`refusing to reexec interactive run for hashsize $1')')')
71 define(`reexec', `output(1, `attempting reexec for larger hashsize $1')syscmd(
72 `exec $2 -H$1 -Dhashsize=$1'_$0(shift(shift($@))))m4exit(sysval)')
73 define(`_reexec', `ifelse(`$1', `-H', `$0(shift(shift($@)))', index(`$1',
74 `-H'), 0, `$0(shift($@))', index(`$1', `--ha')index(`$1', `='), 0-1,
75 `$0(shift(shift($@)))', index(`$1', `--ha'), 0, `$0(shift($@))', `$#', 1,
76 `', `` $1'$0(shift($@))')')
77 define(`common', `ifdef(`__gnu__', `ifelse(`$2', `', `', `ensurehash(ifdef(
78 `hashsize', hashsize, `$2'))')')ifdef(`file', `', `define(`file',
79 `day$1.input')')`ok'')