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