Home | History | Annotate | Line # | Download | only in isccfg
      1 /*	$NetBSD: grammar.h,v 1.10 2025/01/26 16:25:45 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5  *
      6  * SPDX-License-Identifier: MPL-2.0
      7  *
      8  * This Source Code Form is subject to the terms of the Mozilla Public
      9  * License, v. 2.0. If a copy of the MPL was not distributed with this
     10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
     11  *
     12  * See the COPYRIGHT file distributed with this work for additional
     13  * information regarding copyright ownership.
     14  */
     15 
     16 #pragma once
     17 
     18 /*! \file isccfg/grammar.h */
     19 
     20 #include <inttypes.h>
     21 #include <stdbool.h>
     22 
     23 #include <isc/lex.h>
     24 #include <isc/netaddr.h>
     25 #include <isc/region.h>
     26 #include <isc/sockaddr.h>
     27 #include <isc/types.h>
     28 
     29 #include <isccfg/cfg.h>
     30 #include <isccfg/duration.h>
     31 
     32 /*
     33  * Definitions shared between the configuration parser
     34  * and the grammars; not visible to users of the parser.
     35  */
     36 
     37 /*% Clause may occur multiple times (e.g., "zone") */
     38 #define CFG_CLAUSEFLAG_MULTI 0x00000001
     39 /*% Clause is obsolete (logs a warning, but is not a fatal error) */
     40 #define CFG_CLAUSEFLAG_OBSOLETE 0x00000002
     41 /* obsolete: #define CFG_CLAUSEFLAG_NOTIMP 0x00000004 */
     42 /* obsolete: #define CFG_CLAUSEFLAG_NYI 0x00000008 */
     43 /* obsolete: #define CFG_CLAUSEFLAG_NEWDEFAULT 0x00000010 */
     44 /*%
     45  * Clause needs to be interpreted during parsing
     46  * by calling a callback function, like the
     47  * "directory" option.
     48  */
     49 #define CFG_CLAUSEFLAG_CALLBACK 0x00000020
     50 /*% An option that is only used in testing. */
     51 #define CFG_CLAUSEFLAG_TESTONLY 0x00000040
     52 /*% A configuration option that was not configured at compile time. */
     53 #define CFG_CLAUSEFLAG_NOTCONFIGURED 0x00000080
     54 /*% An option for an experimental feature. */
     55 #define CFG_CLAUSEFLAG_EXPERIMENTAL 0x00000100
     56 /*% An option that should be omited from the documentation */
     57 #define CFG_CLAUSEFLAG_NODOC 0x00000200
     58 /*% Clause will be obsolete in a future release (logs a warning) */
     59 #define CFG_CLAUSEFLAG_DEPRECATED 0x00000400
     60 /*% Clause has been obsolete so long that it's now a fatal error */
     61 #define CFG_CLAUSEFLAG_ANCIENT 0x00000800
     62 
     63 /*%
     64  * Zone types for which a clause is valid:
     65  * These share space with CFG_CLAUSEFLAG values, but count
     66  * down from the top.
     67  */
     68 #define CFG_ZONE_PRIMARY    0x80000000
     69 #define CFG_ZONE_SECONDARY  0x40000000
     70 #define CFG_ZONE_STUB	    0x20000000
     71 #define CFG_ZONE_HINT	    0x10000000
     72 #define CFG_ZONE_FORWARD    0x08000000
     73 #define CFG_ZONE_STATICSTUB 0x04000000
     74 #define CFG_ZONE_REDIRECT   0x02000000
     75 #define CFG_ZONE_DELEGATION 0x01000000
     76 #define CFG_ZONE_INVIEW	    0x00800000
     77 #define CFG_ZONE_MIRROR	    0x00400000
     78 
     79 typedef struct cfg_clausedef	 cfg_clausedef_t;
     80 typedef struct cfg_tuplefielddef cfg_tuplefielddef_t;
     81 typedef struct cfg_printer	 cfg_printer_t;
     82 typedef ISC_LIST(cfg_listelt_t) cfg_list_t;
     83 typedef struct cfg_map cfg_map_t;
     84 typedef struct cfg_rep cfg_rep_t;
     85 
     86 /*
     87  * Function types for configuration object methods
     88  */
     89 
     90 typedef isc_result_t (*cfg_parsefunc_t)(cfg_parser_t *, const cfg_type_t *type,
     91 					cfg_obj_t **);
     92 typedef void (*cfg_printfunc_t)(cfg_printer_t *, const cfg_obj_t *);
     93 typedef void (*cfg_docfunc_t)(cfg_printer_t *, const cfg_type_t *);
     94 typedef void (*cfg_freefunc_t)(cfg_parser_t *, cfg_obj_t *);
     95 
     96 /*
     97  * Structure definitions
     98  */
     99 
    100 /*%
    101  * A configuration printer object.  This is an abstract
    102  * interface to a destination to which text can be printed
    103  * by calling the function 'f'.
    104  */
    105 struct cfg_printer {
    106 	void (*f)(void *closure, const char *text, int textlen);
    107 	void *closure;
    108 	int   indent;
    109 	int   flags;
    110 };
    111 
    112 /*% A clause definition. */
    113 struct cfg_clausedef {
    114 	const char  *name;
    115 	cfg_type_t  *type;
    116 	unsigned int flags;
    117 };
    118 
    119 /*% A tuple field definition. */
    120 struct cfg_tuplefielddef {
    121 	const char  *name;
    122 	cfg_type_t  *type;
    123 	unsigned int flags;
    124 };
    125 
    126 /*% A configuration object type definition. */
    127 struct cfg_type {
    128 	const char     *name; /*%< For debugging purposes only */
    129 	cfg_parsefunc_t parse;
    130 	cfg_printfunc_t print;
    131 	cfg_docfunc_t	doc; /*%< Print grammar description */
    132 	cfg_rep_t      *rep; /*%< Data representation */
    133 	const void     *of;  /*%< Additional data for meta-types */
    134 };
    135 
    136 /*% A keyword-type definition, for things like "port <integer>". */
    137 typedef struct {
    138 	const char	 *name;
    139 	const cfg_type_t *type;
    140 } keyword_type_t;
    141 
    142 struct cfg_map {
    143 	cfg_obj_t *id; /*%< Used for 'named maps' like
    144 			* keys, zones, &c */
    145 	const cfg_clausedef_t *const *clausesets; /*%< The clauses that
    146 						   * can occur in this map;
    147 						   * used for printing */
    148 	isc_symtab_t *symtab;
    149 };
    150 
    151 typedef struct cfg_netprefix cfg_netprefix_t;
    152 
    153 struct cfg_netprefix {
    154 	isc_netaddr_t address; /* IP4/IP6 */
    155 	unsigned int  prefixlen;
    156 };
    157 
    158 /*%
    159  * A configuration data representation.
    160  */
    161 struct cfg_rep {
    162 	const char    *name; /*%< For debugging only */
    163 	cfg_freefunc_t free; /*%< How to free this kind of data. */
    164 };
    165 
    166 /*%
    167  * A configuration object.  This is the main building block
    168  * of the configuration parse tree.
    169  */
    170 
    171 struct cfg_obj {
    172 	const cfg_type_t *type;
    173 	union {
    174 		uint32_t	 uint32;
    175 		uint64_t	 uint64;
    176 		isc_textregion_t string; /*%< null terminated, too */
    177 		bool		 boolean;
    178 		cfg_map_t	 map;
    179 		cfg_list_t	 list;
    180 		cfg_obj_t      **tuple;
    181 		isc_sockaddr_t	 sockaddr;
    182 		struct {
    183 			isc_sockaddr_t	 sockaddr;
    184 			isc_textregion_t tls;
    185 		} sockaddrtls;
    186 		cfg_netprefix_t	  netprefix;
    187 		isccfg_duration_t duration;
    188 	} value;
    189 	isc_refcount_t references; /*%< reference counter */
    190 	const char    *file;
    191 	unsigned int   line;
    192 	cfg_parser_t  *pctx;
    193 };
    194 
    195 /*% A list element. */
    196 struct cfg_listelt {
    197 	cfg_obj_t *obj;
    198 	ISC_LINK(cfg_listelt_t) link;
    199 };
    200 
    201 /*% The parser object. */
    202 struct cfg_parser {
    203 	isc_mem_t   *mctx;
    204 	isc_log_t   *lctx;
    205 	isc_lex_t   *lexer;
    206 	unsigned int errors;
    207 	unsigned int warnings;
    208 	isc_token_t  token;
    209 
    210 	/*% We are at the end of all input. */
    211 	bool seen_eof;
    212 
    213 	/*% The current token has been pushed back. */
    214 	bool ungotten;
    215 
    216 	/*%
    217 	 * The stack of currently active files, represented
    218 	 * as a configuration list of configuration strings.
    219 	 * The head is the top-level file, subsequent elements
    220 	 * (if any) are the nested include files, and the
    221 	 * last element is the file currently being parsed.
    222 	 */
    223 	cfg_obj_t *open_files;
    224 
    225 	/*%
    226 	 * Names of files that we have parsed and closed
    227 	 * and were previously on the open_file list.
    228 	 * We keep these objects around after closing
    229 	 * the files because the file names may still be
    230 	 * referenced from other configuration objects
    231 	 * for use in reporting semantic errors after
    232 	 * parsing is complete.
    233 	 */
    234 	cfg_obj_t *closed_files;
    235 
    236 	/*%
    237 	 * Name of a buffer being parsed; used only for
    238 	 * logging.
    239 	 */
    240 	char const *buf_name;
    241 
    242 	/*%
    243 	 * Current line number.  We maintain our own
    244 	 * copy of this so that it is available even
    245 	 * when a file has just been closed.
    246 	 */
    247 	unsigned int line;
    248 
    249 	/*%
    250 	 * Parser context flags, used for maintaining state
    251 	 * from one token to the next.
    252 	 */
    253 	unsigned int flags;
    254 
    255 	/*%< Reference counter */
    256 	isc_refcount_t references;
    257 
    258 	cfg_parsecallback_t callback;
    259 	void		   *callbackarg;
    260 };
    261 
    262 /* Parser context flags */
    263 #define CFG_PCTX_SKIP		(1 << 0)
    264 #define CFG_PCTX_NODEPRECATED	(1 << 1)
    265 #define CFG_PCTX_NOOBSOLETE	(1 << 2)
    266 #define CFG_PCTX_NOEXPERIMENTAL (1 << 3)
    267 
    268 /*@{*/
    269 /*%
    270  * Flags defining whether to accept certain types of network addresses.
    271  */
    272 #define CFG_ADDR_V4OK	    0x00000001
    273 #define CFG_ADDR_V4PREFIXOK 0x00000002
    274 #define CFG_ADDR_V6OK	    0x00000004
    275 #define CFG_ADDR_WILDOK	    0x00000008
    276 #define CFG_ADDR_PORTOK	    0x00000010
    277 #define CFG_ADDR_TLSOK	    0x00000020
    278 #define CFG_ADDR_MASK	    (CFG_ADDR_V6OK | CFG_ADDR_V4OK)
    279 /*@}*/
    280 
    281 /*@{*/
    282 /*%
    283  * Predefined data representation types.
    284  */
    285 extern cfg_rep_t cfg_rep_uint32;
    286 extern cfg_rep_t cfg_rep_uint64;
    287 extern cfg_rep_t cfg_rep_string;
    288 extern cfg_rep_t cfg_rep_boolean;
    289 extern cfg_rep_t cfg_rep_map;
    290 extern cfg_rep_t cfg_rep_list;
    291 extern cfg_rep_t cfg_rep_tuple;
    292 extern cfg_rep_t cfg_rep_sockaddr;
    293 extern cfg_rep_t cfg_rep_sockaddrtls;
    294 extern cfg_rep_t cfg_rep_netprefix;
    295 extern cfg_rep_t cfg_rep_void;
    296 extern cfg_rep_t cfg_rep_fixedpoint;
    297 extern cfg_rep_t cfg_rep_percentage;
    298 extern cfg_rep_t cfg_rep_duration;
    299 /*@}*/
    300 
    301 /*@{*/
    302 /*%
    303  * Predefined configuration object types.
    304  */
    305 extern cfg_type_t cfg_type_boolean;
    306 extern cfg_type_t cfg_type_uint32;
    307 extern cfg_type_t cfg_type_uint64;
    308 extern cfg_type_t cfg_type_qstring;
    309 extern cfg_type_t cfg_type_astring;
    310 extern cfg_type_t cfg_type_ustring;
    311 extern cfg_type_t cfg_type_sstring;
    312 extern cfg_type_t cfg_type_bracketed_aml;
    313 extern cfg_type_t cfg_type_bracketed_text;
    314 extern cfg_type_t cfg_type_optional_bracketed_text;
    315 extern cfg_type_t cfg_type_keyref;
    316 extern cfg_type_t cfg_type_sockaddr;
    317 extern cfg_type_t cfg_type_sockaddrtls;
    318 extern cfg_type_t cfg_type_netaddr;
    319 extern cfg_type_t cfg_type_netaddr4;
    320 extern cfg_type_t cfg_type_netaddr4wild;
    321 extern cfg_type_t cfg_type_netaddr6;
    322 extern cfg_type_t cfg_type_netaddr6wild;
    323 extern cfg_type_t cfg_type_netprefix;
    324 extern cfg_type_t cfg_type_void;
    325 extern cfg_type_t cfg_type_token;
    326 extern cfg_type_t cfg_type_unsupported;
    327 extern cfg_type_t cfg_type_fixedpoint;
    328 extern cfg_type_t cfg_type_percentage;
    329 extern cfg_type_t cfg_type_duration;
    330 extern cfg_type_t cfg_type_duration_or_unlimited;
    331 /*@}*/
    332 
    333 isc_result_t
    334 cfg_gettoken(cfg_parser_t *pctx, int options);
    335 
    336 isc_result_t
    337 cfg_peektoken(cfg_parser_t *pctx, int options);
    338 
    339 void
    340 cfg_ungettoken(cfg_parser_t *pctx);
    341 
    342 #define CFG_LEXOPT_QSTRING (ISC_LEXOPT_QSTRING | ISC_LEXOPT_QSTRINGMULTILINE)
    343 
    344 isc_result_t
    345 cfg_create_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **objp);
    346 
    347 void
    348 cfg_print_rawuint(cfg_printer_t *pctx, unsigned int u);
    349 
    350 isc_result_t
    351 cfg_parse_uint32(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
    352 
    353 void
    354 cfg_print_uint32(cfg_printer_t *pctx, const cfg_obj_t *obj);
    355 
    356 void
    357 cfg_print_uint64(cfg_printer_t *pctx, const cfg_obj_t *obj);
    358 
    359 isc_result_t
    360 cfg_parse_qstring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
    361 
    362 void
    363 cfg_print_ustring(cfg_printer_t *pctx, const cfg_obj_t *obj);
    364 
    365 isc_result_t
    366 cfg_parse_astring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
    367 
    368 isc_result_t
    369 cfg_parse_sstring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
    370 
    371 isc_result_t
    372 cfg_parse_rawaddr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na);
    373 
    374 void
    375 cfg_print_rawaddr(cfg_printer_t *pctx, const isc_netaddr_t *na);
    376 
    377 bool
    378 cfg_lookingat_netaddr(cfg_parser_t *pctx, unsigned int flags);
    379 
    380 isc_result_t
    381 cfg_parse_rawport(cfg_parser_t *pctx, unsigned int flags, in_port_t *port);
    382 
    383 isc_result_t
    384 cfg_parse_sockaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
    385 
    386 isc_result_t
    387 cfg_parse_sockaddrtls(cfg_parser_t *pctx, const cfg_type_t *type,
    388 		      cfg_obj_t **ret);
    389 
    390 isc_result_t
    391 cfg_parse_boolean(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
    392 
    393 void
    394 cfg_print_sockaddr(cfg_printer_t *pctx, const cfg_obj_t *obj);
    395 
    396 void
    397 cfg_print_boolean(cfg_printer_t *pctx, const cfg_obj_t *obj);
    398 
    399 void
    400 cfg_doc_sockaddr(cfg_printer_t *pctx, const cfg_type_t *type);
    401 
    402 isc_result_t
    403 cfg_parse_netprefix(cfg_parser_t *pctx, const cfg_type_t *type,
    404 		    cfg_obj_t **ret);
    405 
    406 isc_result_t
    407 cfg_parse_special(cfg_parser_t *pctx, int special);
    408 /*%< Parse a required special character 'special'. */
    409 
    410 isc_result_t
    411 cfg_create_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **objp);
    412 
    413 isc_result_t
    414 cfg_parse_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
    415 
    416 void
    417 cfg_print_tuple(cfg_printer_t *pctx, const cfg_obj_t *obj);
    418 
    419 void
    420 cfg_doc_tuple(cfg_printer_t *pctx, const cfg_type_t *type);
    421 
    422 isc_result_t
    423 cfg_create_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **objp);
    424 
    425 isc_result_t
    426 cfg_parse_listelt(cfg_parser_t *pctx, const cfg_type_t *elttype,
    427 		  cfg_listelt_t **ret);
    428 
    429 isc_result_t
    430 cfg_parse_bracketed_list(cfg_parser_t *pctx, const cfg_type_t *type,
    431 			 cfg_obj_t **ret);
    432 
    433 void
    434 cfg_print_bracketed_list(cfg_printer_t *pctx, const cfg_obj_t *obj);
    435 
    436 void
    437 cfg_doc_bracketed_list(cfg_printer_t *pctx, const cfg_type_t *type);
    438 
    439 isc_result_t
    440 cfg_parse_spacelist(cfg_parser_t *pctx, const cfg_type_t *type,
    441 		    cfg_obj_t **ret);
    442 
    443 void
    444 cfg_print_spacelist(cfg_printer_t *pctx, const cfg_obj_t *obj);
    445 
    446 isc_result_t
    447 cfg_parse_enum(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
    448 
    449 void
    450 cfg_doc_enum(cfg_printer_t *pctx, const cfg_type_t *type);
    451 
    452 isc_result_t
    453 cfg_parse_enum_or_other(cfg_parser_t *pctx, const cfg_type_t *enumtype,
    454 			const cfg_type_t *othertype, cfg_obj_t **ret);
    455 
    456 void
    457 cfg_doc_enum_or_other(cfg_printer_t *pctx, const cfg_type_t *enumtype,
    458 		      const cfg_type_t *othertype);
    459 
    460 void
    461 cfg_print_chars(cfg_printer_t *pctx, const char *text, int len);
    462 /*%< Print 'len' characters at 'text' */
    463 
    464 void
    465 cfg_print_cstr(cfg_printer_t *pctx, const char *s);
    466 /*%< Print the null-terminated string 's' */
    467 
    468 isc_result_t
    469 cfg_parse_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
    470 
    471 isc_result_t
    472 cfg_parse_named_map(cfg_parser_t *pctx, const cfg_type_t *type,
    473 		    cfg_obj_t **ret);
    474 
    475 isc_result_t
    476 cfg_parse_addressed_map(cfg_parser_t *pctx, const cfg_type_t *type,
    477 			cfg_obj_t **ret);
    478 
    479 isc_result_t
    480 cfg_parse_netprefix_map(cfg_parser_t *pctx, const cfg_type_t *type,
    481 			cfg_obj_t **ret);
    482 
    483 void
    484 cfg_print_map(cfg_printer_t *pctx, const cfg_obj_t *obj);
    485 
    486 void
    487 cfg_doc_map(cfg_printer_t *pctx, const cfg_type_t *type);
    488 
    489 isc_result_t
    490 cfg_parse_mapbody(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
    491 
    492 void
    493 cfg_print_mapbody(cfg_printer_t *pctx, const cfg_obj_t *obj);
    494 
    495 void
    496 cfg_doc_mapbody(cfg_printer_t *pctx, const cfg_type_t *type);
    497 
    498 isc_result_t
    499 cfg_parse_void(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
    500 
    501 void
    502 cfg_print_void(cfg_printer_t *pctx, const cfg_obj_t *obj);
    503 
    504 void
    505 cfg_doc_void(cfg_printer_t *pctx, const cfg_type_t *type);
    506 
    507 isc_result_t
    508 cfg_parse_fixedpoint(cfg_parser_t *pctx, const cfg_type_t *type,
    509 		     cfg_obj_t **ret);
    510 
    511 void
    512 cfg_print_fixedpoint(cfg_printer_t *pctx, const cfg_obj_t *obj);
    513 
    514 isc_result_t
    515 cfg_parse_percentage(cfg_parser_t *pctx, const cfg_type_t *type,
    516 		     cfg_obj_t **ret);
    517 
    518 void
    519 cfg_print_percentage(cfg_printer_t *pctx, const cfg_obj_t *obj);
    520 
    521 isc_result_t
    522 cfg_parse_duration(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
    523 
    524 void
    525 cfg_print_duration(cfg_printer_t *pctx, const cfg_obj_t *obj);
    526 
    527 isc_result_t
    528 cfg_parse_duration_or_unlimited(cfg_parser_t *pctx, const cfg_type_t *type,
    529 				cfg_obj_t **ret);
    530 
    531 void
    532 cfg_print_duration_or_unlimited(cfg_printer_t *pctx, const cfg_obj_t *obj);
    533 
    534 isc_result_t
    535 cfg_parse_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
    536 
    537 void
    538 cfg_print_obj(cfg_printer_t *pctx, const cfg_obj_t *obj);
    539 
    540 void
    541 cfg_doc_obj(cfg_printer_t *pctx, const cfg_type_t *type);
    542 /*%<
    543  * Print a description of the grammar of an arbitrary configuration
    544  * type 'type'
    545  */
    546 
    547 void
    548 cfg_doc_terminal(cfg_printer_t *pctx, const cfg_type_t *type);
    549 /*%<
    550  * Document the type 'type' as a terminal by printing its
    551  * name in angle brackets, e.g., &lt;uint32>.
    552  */
    553 
    554 void
    555 cfg_parser_error(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...)
    556 	ISC_FORMAT_PRINTF(3, 4);
    557 /*!
    558  * Pass one of these flags to cfg_parser_error() to include the
    559  * token text in log message.
    560  */
    561 #define CFG_LOG_NEAR   0x00000001 /*%< Say "near <token>" */
    562 #define CFG_LOG_BEFORE 0x00000002 /*%< Say "before <token>" */
    563 #define CFG_LOG_NOPREP 0x00000004 /*%< Say just "<token>" */
    564 
    565 void
    566 cfg_parser_warning(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...)
    567 	ISC_FORMAT_PRINTF(3, 4);
    568 
    569 bool
    570 cfg_is_enum(const char *s, const char *const *enums);
    571 /*%< Return true iff the string 's' is one of the strings in 'enums' */
    572 
    573 bool
    574 cfg_clause_validforzone(const char *name, unsigned int ztype);
    575 /*%<
    576  * Check whether an option is legal for the specified zone type.
    577  */
    578 
    579 void
    580 cfg_print_zonegrammar(const unsigned int zonetype, unsigned int flags,
    581 		      void (*f)(void *closure, const char *text, int textlen),
    582 		      void *closure);
    583 /*%<
    584  * Print a summary of the grammar of the zone type represented by
    585  * 'zonetype'.
    586  */
    587 
    588 void
    589 cfg_print_clauseflags(cfg_printer_t *pctx, unsigned int flags);
    590 /*%<
    591  * Print clause flags (e.g. "obsolete", "not implemented", etc) in
    592  * human readable form
    593  */
    594 
    595 void
    596 cfg_print_indent(cfg_printer_t *pctx);
    597 /*%<
    598  * Print the necessary indent required by the current settings of 'pctx'.
    599  */
    600