1m4_divert(-1)m4_dnl -*- m4 -*-
2# This file is part of Mailfromd.
3# Copyright (C) 2006-2021 Sergey Poznyakoff
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 3, or (at your option)
8# any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18m4_changequote([<,>])
19m4_changecom(/*,*/)
20
21/* This qualifier is used when declaring C variables corresponding to
22 * MFL STRING parameters.  If the MFL function is declared with MF_DSEXP
23 * attribute (i.e. if it can cause dataseg expansion), __mf_dataseg is
24 * defined to MFL_DATASEG (volatile), exempting the corresponding variable
25 * from optimizations.
26 */
27m4_define([<__mf_dataseg>])
28
29/* The MF_DSEXP attribute indicates that the MF_DEFUN that follows it
30 * can cause dataseg expansion.
31 */
32m4_define([<MF_DSEXP>],[<m4_define([<__mf_dataseg>],[<MFL_DATASEG>])>])
33
34/* Flags that will be passed to va_builtin_install_ex. */
35m4_define([<__MF_DEFUN_FLAGS__>],0)
36
37/* __mf_add_defun_flag(F)
38 * ----------------------
39 * Add F to the current value of __MF_DEFUN_FLAGS__ via logical OR.
40 */
41m4_define([<__mf_add_defun_flag>],m4_dnl
42[<m4_define([<__MF_DEFUN_FLAGS__>],m4_ifelse(__MF_DEFUN_FLAGS__,0,$1,[<__MF_DEFUN_FLAGS__>]|$1))>])
43
44/* __MF_DSEXP_REQ - an auxiliary macro which checks, whether __mf_dataseg
45 * is empty.  If so, it issues a diagnostic message.
46 *
47 * The intent is to warn the programmer that the function in question can
48 * result in dataseg being expanded.  The warning is suppressed by MF_DSEXP
49 * attribute (for MF_DEFUNs) or by the use of MF_DSEXP_SUPPRESS macro (for
50 * C functions).
51 */
52m4_define([<__MF_DSEXP_REQ>],[<m4_dnl
53m4_ifelse(__mf_dataseg,[<>],[<m4_ifdef([<__MF_FUNCTION__>],[<m4_dnl
54m4_errprint(m4___file__:m4___line__: Function __MF_FUNCTION__ should be defined with [<MF_DSEXP>] attribute
55)>],m4_dnl
56[<m4_errprint(m4___file__:m4___line__: this call can cause dataseg expansion; consider using [<MF_DSEXP_SUPPRESS>]
57)>])>])>])
58
59/* __mf_define_fun(NAME) - Defines a macro NAME, which, when invoked,
60 * produces a warning if __mf_dataseg is not defined, and expands
61 * to the literal NAME.
62 */
63m4_define([<__mf_define_fun>],[<m4_ifelse([<$#>],[<0>],[<[<$0>]>],
64[<_$0([<$1>],[<$>][<*>])>])>])
65m4_define([<___mf_define_fun>],[<
66m4_define([<$1>],[<__MF_DSEXP_REQ()
67[<$1>]([<$2>])>])>])
68
69/* MF_DSEXP_SUPPRESS(NAME, DEFN)
70 * -----------------------------
71 * Suppresses dataseg expansion warnings within DEFN and redeclares NAME to
72 * produce a warning if used in a context which is not safe for dataseg
73 * expansion.
74 */
75m4_define([<MF_DSEXP_SUPPRESS>],[<m4_pushdef([<__mf_dataseg>],[</**/>])
76$2
77m4_popdef([<__mf_dataseg>])
78__mf_define_fun([<$1>])>])
79
80/* MF_MODULE_NAME()
81 * ----------------
82 * Expand to the name of this module.
83 */
84m4_pushdef([<MF_MODULE_NAME>])
85
86/* MF_BUILTIN_MODULE([NAME])
87 * -------------------------
88 * Start MFL built-in module text.  Optional NAME is the name of the module.
89 * If not supplied, the name is defined as the base name of the module file.
90 */
91m4_define([<MF_BUILTIN_MODULE>],m4_dnl
92[<m4_pushdef([<MF_MODULE_NAME>],m4_dnl
93m4_ifelse([<$1>],,[<m4_dnl
94m4_patsubst(m4___file__,\(.*/\)?\(.*\)\.bi,\2)>],[<$1>]))>])m4_dnl
95
96/* MF_MODULE_DEBUG_NAME
97 * --------------------
98 * Expand to the "debug" name for the MODULE.
99 */
100m4_define([<MF_MODULE_DEBUG_NAME>],[<m4_dnl
101[<bi_>]m4_translit(MF_MODULE_NAME,[<A-Z->],[<a-z_>])>])
102
103/* MF_MODULE_IDX()
104 * ---------------
105 * Expand to the BUILTIN_IDX_ constant for the current module.
106 */
107m4_define([<MF_MODULE_IDX>],[<m4_dnl
108[<BUILTIN_IDX_>]MF_MODULE_NAME()>])
109
110/* __mf_argtype(arg)
111 * -----------------
112 * Expand to Mailfromd value type code corresponding to ARG:
113 *
114 *   __mf_argtype(STRING) => dtype_string
115 *   __mf_argtype(NUMBER) => dtype_number
116 *   __mf_argtype(POINTER) => dtype_pointer
117 *   __mf_argtype(anything) => dtype_unspecified
118 */
119m4_define([<__mf_argtype>],m4_dnl
120[<m4_ifelse($1,STRING,dtype_string,$1,NUMBER,dtype_number,m4_dnl
121$1,POINTER,dtype_pointer,m4_dnl
122dtype_unspecified)>])
123
124/* mf_argtype(TYPE NAME)
125 * ---------------------
126 * Expand to the Mailfromd value type code corresponding to
127 * TYPE. See __mf_argtype above.
128 */
129m4_define([<mf_argtype>],m4_dnl
130[<__mf_argtype(m4_patsubst([<$1>],[<[ \t].*>],))>])
131
132/* mf_typelist(ARGLIST)
133 * --------------------
134 * Convert ARGLIST into a list of corresponding Mailfromd value type codes.
135 * E.g.:
136 *   mf_typelist(STRING a, NUMBER b) => dtype_string, dtype_number
137 */
138m4_define([<mf_typelist>],m4_dnl
139[<m4_ifelse($#, 1, [<mf_argtype($1)>], m4_dnl,
140$1, [<OPTIONAL>], [<mf_typelist(m4_shift($@))>],
141[<mf_argtype($1), >]m4_dnl
142[<mf_typelist(m4_shift($@))>])>])
143
144/* __mf_has_optarg(ARGS...)
145 * ------------------------
146 * Expand to 1 if ARGS contain OPTIONAL keyword, and to 0 otherwise
147 */
148m4_define([<__mf_has_optarg>],m4_dnl
149[<m4_ifelse($1, , 0,$1,[<OPTIONAL>], 1,[<m4_dnl
150__mf_has_optarg(m4_shift($@))>])>])
151
152/* __mf_c_type(TYPE)
153 * -----------------
154 * Expand to a C type corresponding to the Mailfromd TYPE
155 */
156m4_define([<__mf_c_type>],m4_dnl
157[<m4_ifelse($1,STRING,char * __mf_dataseg,$1,NUMBER,long ,$1,POINTER,void * __mf_dataseg, [<UNKNOWN TYPE $1>])>])
158
159/* __mf_c_getarg(TYPE)
160 * -------------------
161 * Expand to the get_(.*)_arg function call for the given MFL TYPE
162 */
163m4_define([<__mf_c_getarg>],m4_dnl
164[<m4_ifelse($1,STRING,get_string_arg,$1,NUMBER,get_numeric_arg,m4_dnl
165$1,POINTER,get_pointer_arg, ERROR )>])
166
167/* mf_c_argdcl(TYPE NAME)
168 * ----------------------
169 * Translate MFL declaration "TYPE NAME" to the corresponding C one:
170 *
171 *   mf_c_argdcl(STRING str) => char *str
172 */
173m4_define([<mf_c_argdcl>],m4_dnl
174[<m4_regexp([<$1>],[<\(\w+\)\W+\(\w+\)>],[<__mf_c_type(\1)>] \2)>])
175
176/* mf_c_arginit(TYPE NAME, NUM)
177 * ----------------------------
178 * Translate MFL declaration "TYPE NAME" to the corresponding C initialization:
179 *
180 *   mf_c_arginit(STRING str, NUM) => get_string_arg(env, NUM, &str)
181 */
182m4_define([<mf_c_arginit>],m4_dnl
183[<m4_regexp([<$1>],[<\(\w+\)\W+\(\w+\)>],[<__mf_c_getarg(\1)(env, $2, &\2)>])>])
184
185/* __mf_c_argdcl_list(NARG, LIST)
186 * ------------------------------
187 * Translate MFL declaration list to a set of corresponding C variable
188 * declarations.
189 * For more details, see mf_c_arglist below.
190 */
191m4_define([<__mf_c_argdcl_list>],m4_dnl
192[<m4_ifelse($2, , ,$2,[<OPTIONAL>],[<m4_dnl
193__mf_c_argdcl_list($1, m4_shift(m4_shift($@)))>],
194[<mf_c_argdcl($2);
195        __mf_c_argdcl_list(m4_incr($1), m4_shift(m4_shift($@)))>])>])
196
197/* __mf_c_arginit_list(NARG, LIST)
198 * -------------------------------
199 * Translate MFL declaration list to a set of corresponding C variable
200 * initializations.
201 * For more details, see mf_c_arglist below.
202 */
203m4_define([<__mf_c_arginit_list>],m4_dnl
204[<m4_ifelse($2, , ,$2,[<OPTIONAL>],[<m4_dnl
205__mf_c_arginit_list($1, m4_shift(m4_shift($@)))>],
206[<mf_c_arginit($2, m4_eval($1));
207        __mf_c_arginit_list(m4_incr($1), m4_shift(m4_shift($@)))>])>])
208
209/* __mf_c_arglist(NARG, LIST)
210 * --------------------------
211 * Translate MFL declaration list to a set of corresponding C variable
212 * declarations and initializations.
213 * Arguments:
214 *  NARG -- ordinal number of the first variable in LIST
215 *  LIST -- comma-separated list of Mailfromd declarations
216 */
217m4_define([<__mf_c_arglist>],[<__mf_c_argdcl_list($@)
218__mf_c_arginit_list($@)>])
219
220/* mf_c_arglist(LIST)
221 * ------------------
222 * Translate MFL declaration list to a set of corresponding C variable
223 * declarations with initializations.
224 * Insert an instruction to adjust the stack parameters after obtaining the
225 * variables.
226 * E.g.:
227 *   mf_c_arglist(STRING a, NUMBER n) =>
228 *         char *a;
229 *         long n;
230 *         get_string_arg(env, 0, &a);
231 *         get_numeric_arg(env, 1, &n);
232 *         adjust_stack(env, 2);
233 *
234 * Or, if the builtin takes optional parameters:
235 *
236 *  mf_c_arglist(STRING a, NUMBER n) =>
237 *         long __bi_argcnt;
238 *         char *a;
239 *         long n;
240 *         get_string_arg(env, 1, &a);
241 *         get_numeric_arg(env, 2, &n);
242 *         get_numeric_arg(env, 0, &__bi_argcnt);
243 *         adjust_stack(env, __bi_argcnt + 1);
244 */
245m4_define([<mf_c_arglist>],m4_dnl
246[<
247m4_pushdef([<__ARG1__>], m4_ifelse(__MF_VARARGS__,1,1,[<__mf_has_optarg($@)>]))
248m4_ifelse(__ARG1__,0,,[<long __bi_argcnt;>])
249__mf_c_arglist(__ARG1__, $@)
250m4_ifelse(__ARG1__,0,,[<get_numeric_arg(env, 0, &__bi_argcnt);>])
251        adjust_stack(env, m4_ifelse(__ARG1__,0,mf_argcount($@),__bi_argcnt + 1));
252m4_popdef([<__ARG1__>])m4_dnl
253>])
254
255/* __mf_printf_type(TYPE)
256 * ----------------------
257 * Translate the MFL data type TYPE to the printf conversion specification
258 * suitable for outputting it.
259 */
260m4_define([<__mf_printf_type>],m4_dnl
261[<m4_ifelse($1,STRING,s,$1,NUMBER,lu,$1,POINTER,p,%?)>])
262
263/* mf_printf_macro(TYPE NAME)
264 * --------------------------
265 * Translate TYPE to the printf conversion
266 */
267m4_define([<mf_printf_macro>],m4_dnl
268[<%[<>]m4_regexp([<$1>],[<\(\w+\)\W+.*>],[<__mf_printf_type(\1)>])>])
269
270/* mf_printf_list(LIST)
271 * --------------------
272 * Convert the list of MFL variable declarations to a space-delimited
273 * list of printf conversion specifications:
274 *   mf_printf_list(STRING a, NUMBER b) =>  %s %lu
275 * Notice, that the expansion begins with the space character.
276 */
277m4_define([<mf_printf_list>],m4_dnl
278[<m4_ifelse($1,,,$1,[<OPTIONAL>],m4_dnl
279[<mf_printf_list(m4_shift($@))>],m4_dnl
280[< mf_printf_macro($1)[<>]mf_printf_list(m4_shift($@))>])>])
281
282/* __mf_argname(TYPE NAME)
283 * -----------------------
284 * Expand to NAME
285 */
286m4_define([<__mf_argname>],m4_dnl
287[<m4_regexp($1,[<\w+\W+\(\w+\)>],\1)>])
288
289/* mf_argnames(LIST)
290 * -----------------
291 * Extract names from the Mailfromd declaration list:
292 *  mf_argnames(STRING a, NUMBER b) => a, b
293 */
294m4_define([<mf_argnames>],m4_dnl
295[<m4_ifelse($#,1, [<__mf_argname($1)>],m4_dnl
296$1,[<OPTIONAL>],[<mf_argnames(m4_shift($@))>],m4_dnl
297[<__mf_argname($1), mf_argnames(m4_shift($@))>])>])
298
299/* __mf_defined_argname(OPT, TYPE NAME)
300 * ------------------------------------
301 * Same as __mf_argname, but wrap the argument into MF_OPTVAL if OPT is 1.
302 */
303m4_define([<__mf_defined_argname>],m4_dnl
304[<m4_ifelse($1,1,[<m4_dnl
305MF_OPTVAL(__mf_argname($2),m4_ifelse(mf_argtype($2),[<dtype_string>],"",0))>],m4_dnl
306[<__mf_argname($2)>])>])
307
308/* __mf_defined_argnames(OPT, LIST)
309 * --------------------------------
310 * Same as mf_argnames, if OPT is 0.
311 * Otherwise, if OPT is 1, expands to list of MF_OPTVAL constructs with
312 * consecutive parameter names as arguments.
313 * After encountering the OPTIONAL keyword, changes OPT to 1.
314 */
315m4_define([<__mf_defined_argnames>],m4_dnl
316[<m4_ifelse($#,2, [<__mf_defined_argname($1,$2)>],m4_dnl
317$2,[<OPTIONAL>],[<__mf_defined_argnames(1,m4_shift(m4_shift($@)))>],m4_dnl
318[<__mf_defined_argname($1,$2), m4_dnl
319__mf_defined_argnames($1,m4_shift(m4_shift($@)))>])>])
320
321/* mf_defined_argnames(LIST)
322 * -------------------------
323 * Same as mf_argnames, but arguments after the OPTIONAL keywords are
324 * protected by MF_OPTVAL
325 */
326m4_define([<mf_defined_argnames>],m4_dnl
327[<__mf_defined_argnames(0,$@)>])
328
329/* __mf_argpos(POS,NEEDLE,STACK...)
330 * --------------------------------
331 * Expands to position at which NEEDLE occurs in STACK
332 * Arguments:
333 *  POS    -  Current position
334 *  NEEDLE -  String to find
335 *  STACK  -  Argument list
336 * Example:
337 *  __mf_argpos(0, x, a, b, x) => 2
338 */
339m4_define([<__mf_argpos>],m4_dnl
340[<m4_ifelse($2,$3,$1,$3,,[<m4_errprint(m4___file__:m4___line__: No such variable >]$2[<
341)>],[<__mf_argpos(m4_incr($1), $2, m4_shift(m4_shift(m4_shift($@))))>])>])
342
343/* mf_argpos(ARG, TYPE1 ARG1, TYPE2 ARG2 ...)
344 * ------------------------------------------
345 * Expand to the (zero-based) position of ARG in the argument list:
346 *
347 *  mf_argpos(x, STRING a, NUMBER b, OPTIONAL, STRING x) => 3
348 */
349m4_define([<mf_argpos>],m4_dnl
350[<__mf_argpos(0, $1, mf_argnames(m4_shift($@)))>])
351
352/* __mf_defined(NAME, ARGS...)
353 * ---------------------------
354 * Scan ARGS... for the definition of the built-in function parameter NAME,
355 * and expand to a C conditional expression that yields true if it is defined.
356 * ARGS are parameter declarations in the form:
357 *      TYPE NAME
358 */
359m4_define([<__mf_defined>],
360[<m4_ifelse(__mf_has_optarg($@),0,1,m4_dnl
361[<__bi_argcnt > mf_argpos($1,__MF_ARGLIST__)>])>])
362
363/* MF_DEFINED(NAME)
364 * ----------------
365 * Expand to a C conditional expression that yields true if the parameter
366 * NAME is defined.
367 *
368 *  __MF_ARGLIST__ => STRING a, NUMBER b, OPTIONAL, STRING x
369 *  MF_DEFINED(x) => (__bi_argcnt > 2)
370 *
371 *  __MF_ARGLIST__ => STRING a, NUMBER b, STRING x
372 *  MF_DEFINED(x) => (1)
373 */
374m4_define([<MF_DEFINED>],
375[<m4_ifdef([<__MF_ARGLIST__>],([<__mf_defined($1, __MF_ARGLIST__)>]),m4_dnl
376[<m4_errprint(m4___file__:m4___line__: [<MF_DEFINED used out of functional context
377>])>])>])
378
379/* MF_OPTVAL(NAME[, DEFVAL])
380 * -------------------------
381 * If the parameter NAME is defined, expand to its value, otherwise expand
382 * to DEFVAL or 0
383 */
384m4_define([<MF_OPTVAL>],
385[<m4_ifdef([<__MF_ARGLIST__>],m4_dnl
386[<(MF_DEFINED($1) ? $1 : m4_ifelse([<$2>],,0,$2))>],m4_dnl
387[<m4_errprint(m4___file__:m4___line__: [<MF_OPTVAL used out of functional context
388>])>])>])
389
390/* __mf_check_end()
391 * ----------------
392 * Signal error if the previous MF_DEFUN statement was not properly closed
393 * with END
394 */
395m4_define([<__mf_check_end>],m4_dnl
396[<m4_ifdef([<__MF_FUNCTION__>],m4_dnl
397[<m4_errprint(m4___file__:m4___line__: Function '>]__MF_FUNCTION__[<' was not closed
398)
399m4_popdef([<__MF_FUNCTION__>])
400m4_define([<__mf_error_code>],1)>])>])
401
402/* MF_STATE(state)
403 * ---------------
404 * Declare next MF_DEFUN as valid only in the given state.
405 * The state argument is any valid milter state, as declared in
406 * enum smtp_state (see mailfromd.h around line 74--87), but without the
407 * `smtp_state_' prefix.
408 *
409 * Multiple occurrences of MF_STATE accumulate.
410 */
411m4_define([<MF_STATE>],
412[<m4_ifdef([<__MF_STATE__>],m4_dnl
413[<m4_define([<__MF_STATE__>],__MF_STATE__[< | STATMASK(smtp_state_$1)>])>],m4_dnl
414[<m4_define([<__MF_STATE__>],[<STATMASK(smtp_state_$1)>])>])>])
415
416/* MF_CAPTURE([str])
417 * -----------------
418 * Declare next MF_DEFUN as requiring message capturing.
419 * The form with the STR argument can be used only in MF_STATE(eom)
420 * functions (FIXME: this should be enforced at compile time).  In that
421 * case a reference to the capture stream is stored in STR.
422 */
423m4_define([<MF_CAPTURE>],m4_dnl
424[<__mf_add_defun_flag([<MFD_BUILTIN_CAPTURE>])[<>]m4_dnl
425m4_ifelse([<$1>],,,[<m4_define([<__MF_CAPTURE__>],[<$1>])>])>])
426
427/* env_get_stream()
428 * ----------------
429 * Prohibit the use of the library function of the same name.
430 */
431m4_define([<env_get_stream>],m4_dnl
432[<m4_ifdef([<__MF_FUNCTION__>],m4_dnl
433[<m4_ifdef([<__MF_ENV_GET_STREAM_PROHIBIT>],m4_dnl
434[<m4_errprint(m4___file__:m4___line__: [<env_get_stream is illegal here>]
435)
436m4_define([<__mf_error_code>],1)>],[<[<env_get_stream>]($@)>])>],m4_dnl
437[<[<env_get_stream>]($@)>])>])
438
439/* mf_optcount(ARGS...)
440 * --------------------
441 * Return the number of optional arguments in ARGS
442 */
443m4_define([<mf_optcount>],[<m4_dnl
444m4_ifelse($#,1,0,$1,[<OPTIONAL>],m4_eval($# - 1),[<mf_optcount(m4_shift($@))>])>])
445
446/* __mf_argcount(COUNT, ARGS...)
447 * -----------------------------
448 * Auxiliary function for mf_argcount
449 *   COUNT is number of arguments counted so far
450 *   ARGS are the rest of the arguments
451 */
452m4_define([<__mf_argcount>],[<m4_dnl
453m4_ifelse($#,2,$1,$2,[<OPTIONAL>],[<__mf_argcount($1, m4_shift(m4_shift($@)))>],m4_dnl
454[<__mf_argcount(m4_incr($1), m4_shift(m4_shift($@)))>])>])
455
456/* mf_argcount(ARGS...)
457 * --------------------
458 * Return the number of arguments in ARGS, not counting eventual OPTIONAL
459 * modifier.
460 * FIXME: same as m4_eval($# - __mf_has_optarg($@))
461 */
462m4_define([<mf_argcount>],[<m4_dnl
463m4_ifelse($1,,0,__mf_argcount(1,$@))>])
464
465/* mf_prog_trace(FNAME[, ARGS...])
466 * -------------------------------
467 * Expand to the prog_trace call for function FNAME with arguments ARGS.
468 */
469m4_define([<mf_prog_trace>],[<m4_dnl
470prog_trace(env, "$1[<>]mf_printf_list(m4_shift($@))"m4_dnl
471m4_ifelse($2,,,[<,mf_defined_argnames(m4_shift($@))>]));>])
472
473/* __mf_mfl_type(TYPE)
474 * -------------------
475 * If TYPE is REGFLAGS, add MFD_BUILTIN_REGEX_FLAGS to the value of
476 * __MF_DEFUN_FLAGS__ and expand to NUMBER.  Otherwise, expand to
477 * TYPE.
478 */
479m4_define([<__mf_mfl_type>],
480[<m4_ifelse($1,REGFLAGS,[<m4_dnl
481__mf_add_defun_flag([<MFD_BUILTIN_REGEX_FLAGS>])m4_dnl
482NUMBER>],[<$1>])>])
483
484/* __mf_arglist_init(ARGS)
485 * -----------------------
486 * ARGS is the argument declaration list from MF_DEFUN.  The macro
487 * expands to the ARGS list with the type of its first element fixed,
488 * if necessary.  That is, if the first argument ha type designator
489 * REGFLAGS, it is changed to NUMBER and MFD_BUILTIN_REGEX_FLAGS is
490 * set in __MF_DEFUN_FLAGS__.  Otherwise, themacro expands to ARGS
491 * unchanged.
492 */
493m4_define([<__mf_arglist_init>],m4_dnl
494[<m4_ifelse([<$1>],OPTIONAL,[<$@>],[<m4_dnl
495m4_regexp([<$1>],[<\(\w+\)\W+\(\w+\)>],[<__mf_mfl_type(\1) \2>]) m4_dnl
496m4_ifelse([<$2>],,,[<, m4_shift($@)>])>])>])
497
498/* __mf_defun(VARARG, NAME, RETTYPE, ARGS...)
499 * ------------------------------------------
500 * Begin a built-in function declaration.
501 * Arguments:
502 *   VARARG
503 *     Initial value for the FLAGS argument to the va_builtin_install_ex
504 *     function.  Actually, MFD_BUILTIN_VARIADIC if NAME is a variadic
505 *     function, and 0 otherwise.
506 *   NAME
507 *     Name of the function.
508 *   RETTYPE
509 *     Return type (STRING or NUMBER).
510 *   ARGS
511 *     List of arguments with types.
512 */
513m4_define([<__mf_defun>],m4_dnl
514[<__mf_check_end[<>]m4_dnl
515void
516bi_$2(eval_environ_t env)
517m4_pushdef([<__MF_FUNCTION__>], $2)m4_dnl
518m4_pushdef([<__MF_RETTYPE__>], $3)m4_dnl
519m4_pushdef([<__MF_ARGLIST__>], [<__mf_arglist_init(m4_shift(m4_shift(m4_shift($*))))>])
520m4_ifelse($3,STRING,[<MF_DSEXP>])
521m4_divert(1)m4_dnl
522va_builtin_install_ex("$2", bi_$2,m4_dnl
523 m4_ifdef([<__MF_STATE__>],__MF_STATE__,0),m4_dnl
524 __mf_argtype($3),m4_dnl
525 mf_argcount(__MF_ARGLIST__),m4_dnl
526 mf_optcount(__MF_ARGLIST__),m4_dnl
527 __MF_DEFUN_FLAGS__|$1,m4_dnl
528 mf_typelist(__MF_ARGLIST__));
529m4_divert(2)m4_dnl
530{m4_ifdef([<__MF_CAPTURE__>],[<
531	  mu_stream_t __MF_CAPTURE__;
532>])
533	mf_c_arglist(__MF_ARGLIST__)
534m4_ifdef([<__MF_CAPTURE__>],[<{
535	  int rc = env_get_stream(env, &__MF_CAPTURE__);
536	  MF_ASSERT(rc == 0, mfe_failure,
537	            "cannot obtain capture stream reference: %s",
538		    mu_strerror(rc));
539m4_define([<__MF_ENV_GET_STREAM_PROHIBIT>])m4_dnl
540	}>])
541	if (builtin_module_trace(MF_MODULE_IDX))
542		mf_prog_trace($2,__MF_ARGLIST__);
543>])
544
545/* MF_DEFUN(NAME, RETTYPE, ARGS...)
546 * --------------------------------
547 * Start a declaration of the built-in function NAME.  The declaration
548 * must be terminated with END.
549 * Arguments:
550 *  NAME      - function name
551 *  RETTYPE   - return type
552 *  ARGS      - list of argument declarations, each one of the form
553 *              TYPE ARGNAME; special argument OPTIONAL begins the list of
554 *              optional parameters.
555 */
556m4_define([<MF_DEFUN>],[<m4_pushdef([<__MF_VARARGS__>], 0)m4_dnl
557__mf_defun(0, $@)>])
558
559m4_define([<__mf_defun_varargs>],[<m4_dnl
560m4_pushdef([<__MF_VARARGS__>], 1)m4_dnl
561m4_ifelse(__mf_has_optarg(m4_shift(m4_shift(m4_shift(m4_shift($@))))),0,m4_dnl
562[<__mf_defun($1, m4_shift($@))>],m4_dnl
563[<m4_errprint(m4___file__:m4___line__: A variadic function cannot take optional arguments
564)
565m4_define([<__mf_error_code>],1)>])>])
566
567/* MF_DEFUN_VARARGS(NAME, RETTYPE. [TYPE PARAM...])
568 * ------------------------------------------------
569 * Start the declaration of the built-in variadic function NAME.
570 * The declarationl must be terminated with END.
571 * Arguments:
572 *  NAME       - function name
573 *  RETTYPE    - return type
574 *  TYPE PARAM - declarations of mandatory parameters.
575 * Actual parameters can be retrieved using MF_VA_ARG(), which see,
576 * See also MF_VA_START and MF_VA_END
577 */
578m4_define([<MF_DEFUN_VARARGS>],[<__mf_defun_varargs(MFD_BUILTIN_VARIADIC,$@)>])
579
580/* MF_DEFUN_VARARGS_NO_PROM(NAME, RETTYPE, [TYPE PARAM...])
581 * --------------------------------------------------------
582 * Same as MF_DEFUN_VARARGS, but actual parameters are not promoted to
583 * STRING.
584 */
585m4_define([<MF_DEFUN_VARARGS_NO_PROM>],[<m4_dnl
586__mf_defun_varargs(MFD_BUILTIN_VARIADIC|MFD_BUILTIN_NO_PROMOTE,$@)>])
587
588/* Prevent the use of the `return' statement in defuns.
589 */
590m4_define([<return>],[<m4_dnl
591m4_ifdef([<__MF_FUNCTION__>],[<m4_dnl
592m4_errprint(m4___file__:m4___line__: [<return used in MF_DEFUN>]
593)
594m4_define([<__mf_error_code>],1)>],[<[<return>]>])>])
595
596/* MF_RETURN(VALUE[,TYPE])
597 * -----------------------
598 * Expand to C code for returning VALUE from the current function. If TYPE
599 * is supplied, cast value to this type.
600 */
601m4_define([<MF_RETURN>],[<
602m4_ifdef([<__MF_VA_START_USED__>],[<m4_dnl
603m4_errprint(m4___file__:m4___line__: [<MF_RETURN>] used before [<MF_VA_END>]
604)
605m4_define([<__mf_error_code>],1)>],[<m4_dnl
606do {
607m4_pushdef([<__type>],[<m4_ifelse($2,,__MF_RETTYPE__,$2)>])m4_dnl
608  m4_ifelse(__type,[<NUMBER>],[<push(env, (STKVAL)(mft_number)($1))>],m4_dnl
609__type,[<STRING>],[<pushs(env, $1)>],m4_dnl
610__type,[<string>],[<pushs(env, $1)>],m4_dnl
611__type,[<STKVAL>],[<push(env, (STKVAL) ($1))>],m4_dnl
612__type,,[<m4_errprint(m4___file__:m4___line__: return type undefined
613)>],m4_dnl
614[<push(env, (STKVAL) ([<mft_>]$2) ($1))>]);
615m4_popdef([<__type>])m4_dnl
616  goto endlab;
617m4_define([<__MF_ENDLAB__>])m4_dnl
618} while (0)>])>])
619
620/* MF_ALLOC_HEAP(OFF, LEN)
621 * -----------------------
622 * Allocate LEN bytes from the heap.  Return the offset of the allocated
623 * space in OFF.
624 */
625m4_define([<MF_ALLOC_HEAP>],[<m4_dnl
626__MF_DSEXP_REQ()m4_dnl
627(char*) env_data_ref(env, ([<$1>] = heap_reserve(env, $2)))>])
628
629/* MF_ALLOC_HEAP_TEMP(LEN)
630 * -----------------------
631 * Temporarly allocate LEN bytes from the heap.
632 */
633m4_define([<MF_ALLOC_HEAP_TEMP>],[<__MF_DSEXP_REQ()m4_dnl
634mf_c_val(heap_tempspace(env, $1), ptr)>])
635
636/* MF_COPY_STRING(off, string)
637 * ---------------------------
638 * Copy STRING to the heap.  Return the pointer to the copy.
639 */
640m4_define([<MF_COPY_STRING>],[<m4_dnl
641__MF_DSEXP_REQ()m4_dnl
642strcpy((char*)env_data_ref(env, $1 = heap_reserve(env, strlen($2) + 1)), $2)>])
643
644/* MF_OBSTACK_BEGIN()
645 * ------------------
646 * Begin temporary space manipulations.
647 * NOTE: No other heap manipulation function can be used between
648 * MF_OBSTACK_BEGIN and MF_OBSTACK_CANCEL/MF_RETURN_OBSTACK/MF_OBSTACK_FINISH
649 */
650m4_define([<MF_OBSTACK_BEGIN>],[<heap_obstack_begin(env)>])
651
652m4_define([<MF_OBSTACK_GROW>],[<m4_dnl
653m4_ifelse($2,,[<
654do {
655  char *__s = $1;
656  m4_ifelse($#,3,[<$3 = >])heap_obstack_grow(env, __s, strlen(__s));
657} while (0)>],[<m4_ifelse($#,3,[<$3 = >])heap_obstack_grow(env, $1, $2)>])>])
658
659m4_define([<MF_OBSTACK_1GROW>],[<m4_dnl
660do { char __c = $1; heap_obstack_grow(env, &__c, 1); } while(0)>])
661
662m4_define([<MF_OBSTACK_PRINTF>],[<heap_obstack_sprintf(env, $*)>])
663
664/* MF_OBSTACK_CANCEL()
665 * -------------------
666 * Cancel temporary heap allocation initiated by MF_OBSTACK_BEGIN
667 */
668m4_define([<MF_OBSTACK_CANCEL>],[<heap_obstack_cancel(env)>])
669
670/* MF_OBSTACK_BASE()
671 * -----------------
672 * Return a C pointer to the beginning of the currently
673 * allocated obstack space.
674 */
675m4_define([<MF_OBSTACK_BASE>],[<heap_obstack_base(env)>])
676
677/* MF_RETURN_OBSTACK()
678 * -------------------
679 * Relocate and return temporary space
680 */
681m4_define([<MF_RETURN_OBSTACK>],[<MF_RETURN(heap_obstack_finish(env),[<STKVAL>])>])
682
683/* MF_OBSTACK_FINISH()
684 * -------------------
685 * Relocate temporary space and return its starting offset.
686 */
687m4_define([<MF_OBSTACK_FINISH>],[<heap_obstack_finish(env)>])
688
689/* MF_VA_START()
690 * -------------
691 * Begin a code section for handling variable number of arguments.
692 */
693m4_define([<MF_VA_START>],[<
694m4_ifelse(__MF_VARARGS__,1,[<m4_dnl
695m4_define([<__MF_VA_START_USED__>],m4___file__:m4___line__)m4_dnl
696unroll_stack(env, __bi_argcnt + 1)>],
697[<m4_errprint(m4___file__:m4___line__: [<MF_VA_START>] used but `__MF_FUNCTION__' does not take variable number of arguments
698)m4_dnl
699m4_define([<__mf_error_code>],1)>])>])
700
701/* MF_VA_END()
702 * -----------
703 * End the section started with MF_VA_START
704 */
705m4_define([<MF_VA_END>],[<m4_dnl
706m4_ifdef([<__MF_VA_START_USED__>],[<m4_dnl
707m4_undefine([<__MF_VA_START_USED__>])m4_dnl
708adjust_stack(env, __bi_argcnt + 1)>],m4_dnl
709[<m4_errprint(m4___file__:m4___line__: [<MF_VA_END>] without previous [<MF_VA_START>]
710)
711m4_define([<__mf_error_code>],1)>])>])
712
713/* __mf_va_count()
714 * ---------------
715 * Return number of variable arguments passed to the current vararg function
716 */
717m4_define([<__mf_va_count>],[<m4_dnl
718(__bi_argcnt - mf_argcount(__MF_ARGLIST__))>])
719
720/* MF_VA_COUNT()
721 * -------------
722 * Return actual number of variable arguments passed to the
723 * function.  Bail out if the function is not a vararg one.
724 */
725m4_define([<MF_VA_COUNT>],[<m4_dnl
726m4_ifelse(__MF_VARARGS__,1,[<__mf_va_count>],
727[<m4_errprint(m4___file__:m4___line__: [<MF_VA_COUNT>] used but `__MF_FUNCTION__' does not take variable number of arguments
728)m4_dnl
729m4_define([<__mf_error_code>],1)>])>])
730
731/* MF_VA_ARG(N, TYPE, VAR)
732 * -----------------------
733 * Produce a code for assigning to VAR the Nth
734 * argument of the given TYPE in a vararg section.
735 */
736m4_define([<MF_VA_ARG>],[<m4_dnl
737m4_ifdef([<__MF_VA_START_USED__>],m4_dnl
738[<m4_pushdef([<__ARGN__>],[<($1+mf_argcount(__MF_ARGLIST__))>])
739 ((__bi_argcnt > __ARGN__) ?m4_dnl
740   __mf_c_getarg($2)(env, __ARGN__ + 1, &$3) :m4_dnl
741   (MF_THROW(mfe_range, "Argument %u is not supplied", (unsigned) __ARGN__),m4_dnl
742(__mf_c_type($2)) 0))m4_dnl
743m4_popdef([<__ARGN__>])>],
744[<m4_errprint(m4___file__:m4___line__: [<MF_VA_ARG>] without previous [<MF_VA_START>]
745)
746m4_define([<__mf_error_code>],1)>])>])
747
748/* MF_VAR(NAME,TYPE[,FLAG])
749 * ------------------------
750 * Declare a global variable NAME of type TYPE.  FLAGS are additional flags
751 * (SYM_VOLATILE is always used).
752 */
753m4_define([<MF_VAR>],[<m4_dnl
754static size_t $1_loc
755m4_divert(1)m4_dnl
756	builtin_variable_install("$1", __mf_argtype($2), m4_dnl
757[<SYM_VOLATILE>]m4_ifelse($3,,,|$3), &$1_loc);
758m4_divert(2)m4_dnl
759>])
760
761/* MF_VAR_REF(NAME, TYPE[, VALUE])
762 * -------------------------------
763 * Reference the global variable NAME.
764 * In two-argument form, expand to its value.  In three-arguments form, assign
765 * the VALUE to it.
766 */
767m4_define([<MF_VAR_REF>],[<m4_dnl
768mf_c_val(*env_data_ref(env, $1_loc),$2) m4_ifelse($3,,,= ($3))>])
769
770m4_define([<MF_VAR_STRING>],[<m4_dnl
771(char*)env_data_ref(env, MF_VAR_REF($1, size))>])
772
773/* MF_VAR_SET_STRING(NAME, VALUE)
774 * ------------------------------
775 * Set variable NAME to the string VALUE
776 */
777m4_define([<MF_VAR_SET_STRING>],[<
778{ size_t __off;
779  const char *__s = $2;
780  if (__s)
781     MF_COPY_STRING(__off, __s);
782  else
783     __off = 0;
784  MF_VAR_REF($1, size, __off); }
785>])
786
787/* MF_VAR_INC(NAME)
788 * ----------------
789 * Increment the value of the global variable NAME
790 */
791m4_define([<MF_VAR_INC>],[<m4_dnl
792env_var_inc(env, $1_loc)>])
793
794/* MF_DECLARE_DATA(NAME, INIT [, DESTR, FREECAP])
795 * ----------------------------------------------
796 * Declare private data for the current module.
797 * The data can be accessed using MF_GET_DATA (see below).
798 * Arguments:
799 *  NAME  - data identifier.
800 *  INIT  - initialization function (void init(void))
801 *  DESTR - destructor function (void destr(void*))
802 *  FREECAP - free capture function (void freecap(void*))
803 */
804m4_define([<MF_DECLARE_DATA>],[<
805m4_define([<__MF_PRIV_ID__>],$1_id)
806static int __MF_PRIV_ID__;
807m4_divert(1)m4_dnl
808__MF_PRIV_ID__ = builtin_priv_register($2, m4_dnl
809m4_ifelse($3,,NULL,$3),
810m4_ifelse($4,,NULL,$4));
811m4_divert(2)m4_dnl
812>])
813
814/* MF_GET_DATA
815 * -----------
816 * Return pointer to the private data, declared with MF_DECLARE_DATA
817 */
818m4_define([<MF_GET_DATA>],[<m4_dnl
819m4_ifdef([<__MF_PRIV_ID__>],[<m4_dnl
820env_get_builtin_priv(m4_ifelse($1,,env,$1),__MF_PRIV_ID__)>],m4_dnl
821[<m4_errprint(m4___file__:m4___line__: private data not declared (call [<MF_DECLARE_DATA>] first)
822)
823m4_define([<__mf_error_code>],1)
824>])>])
825
826/* MF_VASTRING(OFF)
827 * ----------------
828 * Extract string from VAPTR array at offset OFF.
829 */
830m4_define([<MF_VASTRING>],[<env_vaptr(env, $1)>])
831
832/* MF_THROW(EXCODE, ...)
833 * ------------------------
834 * Throw exception.  First argument (EXCODE) is the exception code.
835 * Rest of arguments supply additional parameters for the env_throw_bi
836 * call.
837 */
838m4_define([<MF_THROW>],[<m4_dnl
839(
840m4_ifdef([<__MF_CAPTURE__>],[<
841	mu_stream_unref(__MF_CAPTURE__),
842>])m4_dnl
843	env_throw_bi(env, $1, m4_ifdef([<__MF_FUNCTION__>],m4_dnl
844"__MF_FUNCTION__", NULL), m4_shift($@))
845)>])
846
847/* MF_STREAM_TO_MESSAGE(STR)
848 * -------------------------
849 * Convert mailutils stream STR to a message.
850 */
851m4_define([<MF_STREAM_TO_MESSAGE>],[<m4_dnl
852_builtin_mu_stream_to_message($1, env, m4_ifdef([<__MF_FUNCTION__>],m4_dnl
853"__MF_FUNCTION__", NULL))>])
854
855/* MF_ASSERT(COND, EXCEPTION, ...)
856 * -------------------------------
857 * Throw EXCEPTION unless condition COND is true.  Additional arguments
858 * are passed to MF_THROW.
859 */
860m4_define([<MF_ASSERT>],[<m4_dnl
861	if (!($1))
862		MF_THROW(m4_shift($@))
863>])
864
865/* END -- Finish the built-in function declaration, created with MF_DEFUN
866 */
867m4_define([<END>],m4_dnl
868[<m4_ifdef([<__MF_ENDLAB__>],[<endlab:>])
869m4_ifdef([<__MF_CAPTURE__>],[<
870	mu_stream_unref(__MF_CAPTURE__);
871>])m4_dnl
872m4_undefine([<__MF_ENV_GET_STREAM_PROHIBIT>])m4_dnl
873m4_ifdef([<__MF_VA_START_USED__>],[<m4_dnl
874m4_errprint(m4___file__:m4___line__: Missing [<MF_VA_END>]
875)m4_dnl
876m4_errprint(>]__MF_VA_START_USED__[<: This is the location of [<MF_VA_START>]
877)m4_dnl
878m4_define([<__mf_error_code>],1)m4_dnl
879m4_undefine([<__MF_VA_START_USED__>])>])m4_dnl
880m4_popdef([<__MF_FUNCTION__>])m4_dnl
881m4_popdef([<__MF_RETTYPE__>])m4_dnl
882m4_popdef([<__MF_ARGLIST__>])m4_dnl
883m4_popdef([<__MF_VARARGS__>])m4_dnl
884m4_undefine([<__MF_CAPTURE__>])m4_dnl
885m4_undefine([<__MF_STATE__>])m4_dnl
886m4_undefine([<__MF_ENDLAB__>])m4_dnl
887m4_define([<__MF_DEFUN_FLAGS__>],0)m4_dnl
888m4_define([<__mf_dataseg>])m4_dnl
889        env_function_cleanup_flush(env, NULL);
890	return;
891}>])
892
893/* MF_DCL_CLEANUP(PTR[, FUNC])
894 * ---------------------------
895 * Register clean-up function FUNC for data pointer PTR.  FUNC(PTR) will
896 * be called if an exception is thrown or MF_CLEANUP(PTR) is explicitly
897 * used.  If neither of these occurs, it will be called upon destroying
898 * the evaluation environment.
899 * Registration can be undone using MF_CLR_CLEANUP.
900 */
901m4_define([<MF_DCL_CLEANUP>],[<env_function_cleanup_add(env, $1, m4_dnl
902m4_ifelse($2,,NULL,$2))>])
903
904/* MF_CLR_CLEANUP(PTR)
905 * -------------------
906 * Undo registration of the clean-up routine for PTR.
907 */
908m4_define([<MF_CLR_CLEANUP>],[<env_function_cleanup_del(env, $1)>])
909
910/* MF_CLEANUP(PTR)
911 * ---------------
912 * Invoke a previously registered clean-up routine for pointer PTR.
913 */
914m4_define([<MF_CLEANUP>],[<env_function_cleanup_flush(env, $1)>])
915
916m4_define([<MF_TRANS_PREFIX>],[<_MFL_>])
917/* MF_TRANS(NAME)
918 * --------------
919 * Expands to a struct builtin_const_trans for translating constant NAME
920 * between MFL and C.
921 * See syslog.bi for an example of its use.
922 */
923m4_define([<MF_TRANS>],[<{ MF_TRANS_PREFIX[<>]$1, $1 }>])
924
925/* MF_PRAGMA(NAME, MIN, MAX)
926 * -------------------------
927 * Register a pragma NAME.
928 * Arguments:
929 *  NAME   - name of the new pragma
930 *  MIN    - minimum number of arguments (including pragma name)
931 *  MAX    - maximum number of arguments (or 0, if unlimited).
932 *
933 * The macro must be followed by a C block with the code for handling
934 * the pragma. The code can access the following three parameters:
935 *  int argc    -  number of actual arguments in argv array;
936 *  char **argv -  NULL terminated array of actual arguments;
937 *  text        -  actual pragma text, with built-in constants expanded;
938 */
939m4_define([<MF_PRAGMA>],m4_dnl
940[<m4_divert(1)m4_dnl
941m4_pushdef([<pragma_handler>],[<_pragma_>]m4_translit($1,-,_))
942install_pragma("$1", $2, $3, pragma_handler);
943m4_divert(2)
944[<static void >]pragma_handler[< (int argc, char **argv, const char *text)>]
945m4_popdef([<pragma_handler>])m4_dnl
946>])
947
948/* MF_COND(SYM)
949 * ------------
950 * Protect the code below by the `#ifdef SYM' / `#endif'
951 */
952m4_define([<MF_COND>],[<m4_dnl
953m4_pushdef([<__MF_COND_SYMBOL>],$1)m4_dnl
954#ifdef __MF_COND_SYMBOL
955>])
956
957/* MF_DEBUG(LEV, (ARGS...))
958 * ------------------------
959 * Expand to a mu_debug call with the debug handle for this built-in
960 * module and LEV, (ARGS...) as arguments.
961 */
962m4_define([<MF_DEBUG>],[<
963m4_ifdef([<__MF_DEBUG>],,[<m4_dnl
964m4_define([<__MF_DEBUG>],1)m4_dnl
965m4_divert(3)m4_dnl
966static mu_debug_handle_t debug_handle;
967m4_divert(2)>])
968[<mu_debug>](debug_handle, $@)>])>])
969
970m4_pushdef([<__MF_INIT_SEQUENCE>])
971
972/* MF_INIT(CODE)
973 * -------------
974 * Insert CODE into the initialization function for the
975 * curent module (MODNAME_init_builtin).
976 */
977m4_define([<MF_INIT>],m4_dnl
978 [<m4_pushdef([<__MF_INIT_SEQUENCE>],[<$1>])>])
979
980/* Expand to the generated text upon the end of input.
981 */
982m4_m4wrap([<
983m4_ifelse(MF_MODULE_NAME,,[<m4_errprint([<MF_BUILTIN_MODULE is missing
984>])
985m4_m4exit(1)>])
986m4_undefine([<__MF_PRIV_ID__>])m4_dnl
987m4_ifdef([<__MF_COND_SYMBOL>],[<#endif /[<>]* __MF_COND_SYMBOL */
988>])
989void
990MF_MODULE_NAME()_init_builtin(void)
991{
992	m4_ifdef([<__MF_DEBUG>],[<m4_dnl
993	debug_handle = mu_debug_register_category("MF_MODULE_DEBUG_NAME");
994>])
995m4_ifdef([<__MF_COND_SYMBOL>],[<#ifdef __MF_COND_SYMBOL
996	pp_define("__MF_COND_SYMBOL");
997>])m4_dnl
998	m4_undivert(1)
999	__MF_INIT_SEQUENCE
1000m4_popdef([<__MF_INIT_SEQUENCE>])m4_dnl
1001m4_ifdef([<__MF_COND_SYMBOL>],[<#endif /[<>]* __MF_COND_SYMBOL */
1002m4_popdef([<__MF_COND_SYMBOL>])>])m4_dnl
1003}
1004m4_divert(0)m4_dnl
1005/* -*- buffer-read-only: t -*- vi: set ro:
1006   THIS FILE IS GENERATED AUTOMATICALLY.  PLEASE DO NOT EDIT.
1007*/
1008#ifdef HAVE_CONFIG_H
1009# include <config.h>
1010#endif
1011#include <sys/types.h>
1012
1013#include "mailfromd.h"
1014#include "prog.h"
1015#include "builtin.h"
1016
1017m4_undivert(3)
1018m4_undivert(2)
1019m4_popdef([<MF_MODULE_NAME>])m4_dnl
1020>])
1021
1022m4_divert(2)
1023/* End of snarf.m4 */
1024