Asterisk - The Open Source Telephony Project GIT-master-3dae2cf
config_options.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2012, Digium, Inc.
5 *
6 * Mark Spencer <markster@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*! \file
20 * \brief Configuration Option-handling
21 * \author Terry Wilson <twilson@digium.com>
22 */
23
24/*** MODULEINFO
25 <support_level>core</support_level>
26 ***/
27
28#include "asterisk.h"
29
30#include <regex.h>
31
32#include "asterisk/_private.h"
33#include "asterisk/config.h"
36#include "asterisk/acl.h"
37#include "asterisk/app.h"
38#include "asterisk/frame.h"
39#include "asterisk/xmldoc.h"
40#include "asterisk/cli.h"
41#include "asterisk/term.h"
42#include "asterisk/format_cap.h"
43
44#ifdef LOW_MEMORY
45#define CONFIG_OPT_BUCKETS 5
46#else
47#define CONFIG_OPT_BUCKETS 53
48#endif /* LOW_MEMORY */
49
50/*! \brief Bits of aco_info that shouldn't be assigned outside this file
51 * \internal
52 */
54 void *pending; /*!< The user-defined config object awaiting application */
55};
56
58 regex_t *regex;
59 struct ao2_container *opts; /*!< The container of options registered to the aco_info */
60};
61
62struct aco_option {
63 const char *name;
64 const char *aliased_to;
65 const char *default_val;
67 regex_t *name_regex;
68 struct aco_type **obj;
71 unsigned int flags;
72 unsigned int no_doc:1;
73#ifdef AST_DEVMODE
74 unsigned int doc_unavailable:1;
75#endif
76 unsigned char deprecated:1;
77 size_t argc;
78 intptr_t args[0];
79};
80
81#ifdef AST_XML_DOCS
82static struct ao2_container *xmldocs;
83
84/*! \brief Value of the aco_option_type enum as strings */
85static char *aco_option_type_string[] = {
86 "ACL", /* OPT_ACL_T, */
87 "Boolean", /* OPT_BOOL_T, */
88 "Boolean", /* OPT_BOOLFLAG_T, */
89 "String", /* OPT_CHAR_ARRAY_T, */
90 "Codec", /* OPT_CODEC_T, */
91 "Custom", /* OPT_CUSTOM_T, */
92 "Double", /* OPT_DOUBLE_T, */
93 "Integer", /* OPT_INT_T, */
94 "None", /* OPT_NOOP_T, */
95 "IP Address", /* OPT_SOCKADDR_T, */
96 "String", /* OPT_STRINGFIELD_T, */
97 "Unsigned Integer", /* OPT_UINT_T, */
98 "Boolean", /* OPT_YESNO_T, */
99 "Time Length", /* OPT_TIMELEN_T, */
100};
101#endif /* AST_XML_DOCS */
102
104{
105 if (!(info && info->internal)) {
106 ast_log(LOG_ERROR, "This may not be called without an initialized aco_info!\n");
107 return NULL;
108 }
109 return info->internal->pending;
110}
111
112static void config_option_destroy(void *obj)
113{
114 struct aco_option *opt = obj;
115 if (opt->match_type == ACO_REGEX && opt->name_regex) {
116 regfree(opt->name_regex);
117 ast_free(opt->name_regex);
118 }
119}
120
121static int int_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
122static int uint_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
123static int timelen_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
124static int double_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
125static int sockaddr_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
126static int stringfield_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
127static int bool_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
128static int boolflag_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
129static int acl_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
130static int codec_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
131static int noop_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
132static int chararray_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
133
134#ifdef AST_XML_DOCS
135static int xmldoc_update_config_type(const char *module, const char *name, const char *category, const char *matchfield, const char *matchvalue, enum aco_category_op category_match);
136static int xmldoc_update_config_option(struct aco_type **types, const char *module, const char *name, const char *object_name, const char *default_value, unsigned int regex, enum aco_option_type type);
137#endif
138
140{
141 switch(type) {
142 case OPT_ACL_T: return acl_handler_fn;
143 case OPT_BOOL_T: return bool_handler_fn;
144 /* Reading from config files, BOOL and YESNO are handled exactly the
145 * same. Their difference is in how they are rendered to users
146 */
147 case OPT_YESNO_T: return bool_handler_fn;
150 case OPT_CODEC_T: return codec_handler_fn;
151 case OPT_DOUBLE_T: return double_handler_fn;
152 case OPT_INT_T: return int_handler_fn;
153 case OPT_NOOP_T: return noop_handler_fn;
156 case OPT_UINT_T: return uint_handler_fn;
158
159 case OPT_CUSTOM_T: return NULL;
160 }
161
162 return NULL;
163}
164
165static regex_t *build_regex(const char *text)
166{
167 int res;
168 regex_t *regex;
169
170 if (!(regex = ast_malloc(sizeof(*regex)))) {
171 return NULL;
172 }
173
174 if ((res = regcomp(regex, text, REG_EXTENDED | REG_ICASE | REG_NOSUB))) {
175 size_t len = regerror(res, regex, NULL, 0);
176 char buf[len];
177 regerror(res, regex, buf, len);
178 ast_log(LOG_ERROR, "Could not compile regex '%s': %s\n", text, buf);
180 return NULL;
181 }
182
183 return regex;
184}
185
186static int link_option_to_types(struct aco_info *info, struct aco_type **types, struct aco_option *opt)
187{
188 size_t idx = 0;
189 struct aco_type *type;
190
191 while ((type = types[idx++])) {
192 if (!type->internal) {
193 ast_log(LOG_ERROR, "Attempting to register option using uninitialized type\n");
194 return -1;
195 }
196 if (!ao2_link(type->internal->opts, opt)) {
197 do {
198 ao2_unlink(types[idx - 1]->internal->opts, opt);
199 } while (--idx);
200 return -1;
201 }
202#ifdef AST_XML_DOCS
203 if (!info->hidden && !opt->no_doc &&
204 xmldoc_update_config_option(types, info->module, opt->name, type->name, opt->default_val, opt->match_type == ACO_REGEX, opt->type)) {
205#ifdef AST_DEVMODE
206 opt->doc_unavailable = 1;
207#endif
208 }
209#endif
210 }
211 /* The container(s) should hold the only ref to opt */
212 ao2_ref(opt, -1);
213
214 return 0;
215}
216
217int aco_option_register_deprecated(struct aco_info *info, const char *name, struct aco_type **types, const char *aliased_to)
218{
219 struct aco_option *opt;
220
222 return -1;
223 }
224
226 if (!opt) {
227 return -1;
228 }
229
230 opt->name = name;
231 opt->aliased_to = aliased_to;
232 opt->deprecated = 1;
233 opt->match_type = ACO_EXACT;
234
235 if (link_option_to_types(info, types, opt)) {
236 ao2_ref(opt, -1);
237 return -1;
238 }
239
240 return 0;
241}
242
243unsigned int aco_option_get_flags(const struct aco_option *option)
244{
245 return option->flags;
246}
247
248intptr_t aco_option_get_argument(const struct aco_option *option, unsigned int position)
249{
250 return option->args[position];
251}
252
253#ifdef AST_XML_DOCS
254/*! \internal
255 * \brief Find a particular ast_xml_doc_item from it's parent config_info, types, and name
256 */
257static struct ast_xml_doc_item *find_xmldoc_option(struct ast_xml_doc_item *config_info, struct aco_type **types, const char *name)
258{
259 struct ast_xml_doc_item *iter = config_info;
260
261 if (!iter) {
262 return NULL;
263 }
264 /* First is just the configInfo, we can skip it */
265 while ((iter = AST_LIST_NEXT(iter, next))) {
266 size_t x;
267 if (strcasecmp(iter->name, name)) {
268 continue;
269 }
270 for (x = 0; types[x]; x++) {
271 /* All we care about is that at least one type has the option */
272 if (!strcasecmp(types[x]->name, iter->ref)) {
273 return iter;
274 }
275 }
276 }
277 return NULL;
278}
279
280/*! \internal
281 * \brief Find a particular ast_xml_doc_item from it's parent config_info and name
282 */
283static struct ast_xml_doc_item *find_xmldoc_type(struct ast_xml_doc_item *config_info, const char *name)
284{
285 struct ast_xml_doc_item *iter = config_info;
286 if (!iter) {
287 return NULL;
288 }
289 /* First is just the config Info, skip it */
290 while ((iter = AST_LIST_NEXT(iter, next))) {
291 if (!strcasecmp(iter->type, "configObject") && !strcasecmp(iter->name, name)) {
292 break;
293 }
294 }
295 return iter;
296}
297
298#endif /* AST_XML_DOCS */
299
300int __aco_option_register(struct aco_info *info, const char *name, enum aco_matchtype matchtype, struct aco_type **types,
301 const char *default_val, enum aco_option_type kind, aco_option_handler handler, unsigned int flags,
302 unsigned int no_doc, size_t argc, ...)
303{
304 struct aco_option *opt;
305 va_list ap;
306 int tmp;
307
308 /* Custom option types require a handler */
309 if (!handler && kind == OPT_CUSTOM_T) {
310 return -1;
311 }
312
313 if (!(types && types[0])) {
314 return -1;
315 }
316
317 opt = ao2_alloc_options(sizeof(*opt) + argc * sizeof(opt->args[0]),
319 if (!opt) {
320 return -1;
321 }
322
323 if (matchtype == ACO_REGEX && !(opt->name_regex = build_regex(name))) {
324 ao2_ref(opt, -1);
325 return -1;
326 }
327
328 va_start(ap, argc);
329 for (tmp = 0; tmp < argc; tmp++) {
330 opt->args[tmp] = va_arg(ap, size_t);
331 }
332 va_end(ap);
333
334 opt->name = name;
335 opt->match_type = matchtype;
337 opt->type = kind;
338 opt->handler = handler;
339 opt->flags = flags;
340 opt->argc = argc;
341 opt->no_doc = no_doc;
342
343 if (!opt->handler && !(opt->handler = ast_config_option_default_handler(opt->type))) {
344 /* This should never happen */
345 ast_log(LOG_ERROR, "No handler provided, and no default handler exists for type %u\n", opt->type);
346 ao2_ref(opt, -1);
347 return -1;
348 };
349
350 if (link_option_to_types(info, types, opt)) {
351 ao2_ref(opt, -1);
352 return -1;
353 }
354
355 return 0;
356}
357
358static int config_opt_hash(const void *obj, const int flags)
359{
360 const struct aco_option *opt = obj;
361 const char *name = (flags & OBJ_KEY) ? obj : opt->name;
362 return ast_str_case_hash(name);
363}
364
365static int config_opt_cmp(void *obj, void *arg, int flags)
366{
367 struct aco_option *opt1 = obj, *opt2 = arg;
368 const char *name = (flags & OBJ_KEY) ? arg : opt2->name;
369 return strcasecmp(opt1->name, name) ? 0 : CMP_MATCH | CMP_STOP;
370}
371
372static int find_option_cb(void *obj, void *arg, int flags)
373{
374 struct aco_option *match = obj;
375 const char *name = arg;
376
377 switch (match->match_type) {
378 case ACO_EXACT:
379 return strcasecmp(name, match->name) ? 0 : CMP_MATCH | CMP_STOP;
380 case ACO_PREFIX:
381 return strncasecmp(name, match->name, strlen(match->name)) ? 0 : CMP_MATCH | CMP_STOP;
382 case ACO_REGEX:
383 return regexec(match->name_regex, name, 0, NULL, 0) ? 0 : CMP_MATCH | CMP_STOP;
384 }
385 ast_log(LOG_ERROR, "Unknown match type. This should not be possible.\n");
386 return CMP_STOP;
387}
388
389static struct aco_option *aco_option_find(struct aco_type *type, const char *name)
390{
391 struct aco_option *opt;
392
393 if (!type || !type->internal || !type->internal->opts) {
394 ast_log(LOG_NOTICE, "Attempting to use NULL or unitialized config type\n");
395 return NULL;
396 }
397
398 /* Try an exact match with OBJ_KEY for the common/fast case, then iterate through
399 * all options for the regex cases */
400 if (!(opt = ao2_callback(type->internal->opts, OBJ_KEY, find_option_cb, (void *) name))) {
401 opt = ao2_callback(type->internal->opts, 0, find_option_cb, (void *) name);
402 }
403 return opt;
404}
405
407{
410}
411
412static int internal_aco_type_category_check(struct aco_type *match, const char *category)
413{
414 const char **categories = (const char **)match->category;
415
416 switch (match->category_match) {
417 case ACO_WHITELIST:
418 return regexec(match->internal->regex, category, 0, NULL, 0);
419
420 case ACO_BLACKLIST:
421 return !regexec(match->internal->regex, category, 0, NULL, 0);
422
424 return strcasecmp(match->category, category);
425
427 return !strcasecmp(match->category, category);
428
430 while (*categories) {
431 if (!strcasecmp(*categories, category)) {
432 return 0;
433 }
434 categories++;
435 }
436 return -1;
437
439 while (*categories) {
440 if (!strcasecmp(*categories, category)) {
441 return -1;
442 }
443 categories++;
444 }
445 return 0;
446 }
447
448 return -1;
449}
450
451static struct aco_type *internal_aco_type_find(struct aco_file *file, struct ast_config *cfg, const char *category)
452{
453 size_t x;
454 struct aco_type *match;
455 const char *val;
456
457 for (x = 0, match = file->types[x]; match; match = file->types[++x]) {
458 /* First make sure we are an object that can service this category */
460 continue;
461 }
462
463 /* Then, see if we need to match a particular field */
464 if (!ast_strlen_zero(match->matchfield) && (!ast_strlen_zero(match->matchvalue) || match->matchfunc)) {
465 if (!(val = ast_variable_retrieve(cfg, category, match->matchfield))) {
466 ast_log(LOG_ERROR, "Required match field '%s' not found\n", match->matchfield);
467 return NULL;
468 }
469 if (match->matchfunc) {
470 if (!match->matchfunc(val)) {
471 continue;
472 }
473 } else if (strcasecmp(val, match->matchvalue)) {
474 continue;
475 }
476 }
477 /* If we get this far, we're a match */
478 break;
479 }
480
481 return match;
482}
483
484static int is_preload(struct aco_file *file, const char *cat)
485{
486 int i;
487
488 if (!file->preload) {
489 return 0;
490 }
491
492 for (i = 0; !ast_strlen_zero(file->preload[i]); i++) {
493 if (!strcasecmp(cat, file->preload[i])) {
494 return 1;
495 }
496 }
497 return 0;
498}
499
500static int process_category(struct ast_config *cfg, struct aco_info *info, struct aco_file *file, const char *cat, int preload) {
501 RAII_VAR(void *, new_item, NULL, ao2_cleanup);
502 struct aco_type *type;
503 /* For global types, field is the global option struct. For non-global, it is the container for items.
504 * We do not grab a reference to these objects, as the info already holds references to them. This
505 * pointer is just a convenience. Do not actually store it somewhere. */
506 void **field;
507 regex_t *regex_skip;
508
509 /* Skip preloaded categories if we aren't preloading */
510 if (!preload && is_preload(file, cat)) {
511 return 0;
512 }
513
514 /* Skip the category if we've been told to ignore it */
515 if (!ast_strlen_zero(file->skip_category)) {
516 regex_skip = build_regex(file->skip_category);
517 if (!regexec(regex_skip, cat, 0, NULL, 0)) {
518 regfree(regex_skip);
519 ast_free(regex_skip);
520 return 0;
521 }
522 regfree(regex_skip);
523 ast_free(regex_skip);
524 }
525
526 /* Find aco_type by category, if not found it is an error */
527 if (!(type = internal_aco_type_find(file, cfg, cat))) {
528 ast_log(LOG_ERROR, "Could not find config type for category '%s' in '%s'\n", cat, file->filename);
529 return -1;
530 }
531
532 if (type->type == ACO_IGNORE) {
533 return 0;
534 }
535
536 field = info->internal->pending + type->item_offset;
537 if (!*field) {
538 ast_log(LOG_ERROR, "In %s: %s - No object to update!\n", file->filename, cat);
539 return -1;
540 }
541
542 if (type->type == ACO_GLOBAL && *field) {
543 if (aco_process_category_options(type, cfg, cat, *field)) {
544 ast_log(LOG_ERROR, "In %s: Processing options for %s failed\n", file->filename, cat);
545 return -1;
546 }
547 } else if (type->type == ACO_ITEM) {
548 int new = 0;
549 /* If we have multiple definitions of a category in a file, or can set the values from multiple
550 * files, look up the entry if we've already added it so we can merge the values together.
551 * Otherwise, alloc a new item. */
552 if (*field) {
553 if (!(new_item = type->item_find(*field, cat))) {
554 if (!(new_item = type->item_alloc(cat))) {
555 ast_log(LOG_ERROR, "In %s: Could not create item for %s\n", file->filename, cat);
556 return -1;
557 }
558 if (aco_set_defaults(type, cat, new_item)) {
559 ast_log(LOG_ERROR, "In %s: Setting defaults for %s failed\n", file->filename, cat);
560 return -1;
561 }
562 new = 1;
563 }
564 }
565
566 if (type->item_pre_process && type->item_pre_process(new_item)) {
567 ast_log(LOG_ERROR, "In %s: Preprocess callback for %s failed\n", file->filename, cat);
568 return -1;
569 }
570
571 if (aco_process_category_options(type, cfg, cat, new_item)) {
572 ast_log(LOG_ERROR, "In %s: Processing options for %s failed\n", file->filename, cat);
573 return -1;
574 }
575
576 if (type->item_prelink && type->item_prelink(new_item)) {
577 ast_log(LOG_ERROR, "In %s: Pre-link callback for %s failed\n", file->filename, cat);
578 return -1;
579 }
580
581 if (new && !ao2_link(*field, new_item)) {
582 ast_log(LOG_ERROR, "In %s: Linking config for %s failed\n", file->filename, cat);
583 return -1;
584 }
585 }
586 return 0;
587}
588
589static int apply_config(struct aco_info *info)
590{
591 ao2_global_obj_replace_unref(*info->global_obj, info->internal->pending);
592
593 return 0;
594}
595
597{
598 const char *cat = NULL;
599
600 if (file->preload) {
601 int i;
602 for (i = 0; !ast_strlen_zero(file->preload[i]); i++) {
603 if (process_category(cfg, info, file, file->preload[i], 1)) {
604 return ACO_PROCESS_ERROR;
605 }
606 }
607 }
608
609 while ((cat = ast_category_browse(cfg, cat))) {
610 if (process_category(cfg, info, file, cat, 0)) {
611 return ACO_PROCESS_ERROR;
612 }
613 }
614 return ACO_PROCESS_OK;
615}
616
618{
619 if (!info->internal) {
620 ast_log(LOG_ERROR, "Attempt to process %s with uninitialized aco_info\n", file->filename);
621 return ACO_PROCESS_ERROR;
622 }
623
624 if (!(info->internal->pending = info->snapshot_alloc())) {
625 ast_log(LOG_ERROR, "In %s: Could not allocate temporary objects\n", file->filename);
626 goto error;
627 }
628
630 goto error;
631 }
632
633 if (info->pre_apply_config && info->pre_apply_config()) {
634 goto error;
635 }
636
637 if (apply_config(info)) {
638 goto error;
639 };
640
641 ao2_cleanup(info->internal->pending);
642 info->internal->pending = NULL;
643 return ACO_PROCESS_OK;
644
645error:
646 ao2_cleanup(info->internal->pending);
647 info->internal->pending = NULL;
648
649 return ACO_PROCESS_ERROR;
650}
651
653{
654 struct ast_config *cfg;
655 struct ast_flags cfg_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0, };
656 int res = ACO_PROCESS_OK;
657 int file_count = 0;
658 struct aco_file *file;
659
660 if (!info->internal) {
661 ast_log(LOG_ERROR, "Attempting to process uninitialized aco_info\n");
662 return ACO_PROCESS_ERROR;
663 }
664
665 if (!(info->files[0])) {
666 ast_log(LOG_ERROR, "No filename given, cannot proceed!\n");
667 return ACO_PROCESS_ERROR;
668 }
669
670 if (!(info->internal->pending = info->snapshot_alloc())) {
671 ast_log(LOG_ERROR, "In %s: Could not allocate temporary objects\n", info->module);
672 return ACO_PROCESS_ERROR;
673 }
674
675 while (res != ACO_PROCESS_ERROR && (file = info->files[file_count++])) {
676 const char *filename = file->filename;
677 struct aco_type *match;
678 int i;
679
680 /* set defaults for global objects */
681 for (i = 0, match = file->types[i]; match; match = file->types[++i]) {
682 void **field = info->internal->pending + match->item_offset;
683
684 if (match->type == ACO_IGNORE) {
685 continue;
686 }
687
688 if (match->type != ACO_GLOBAL || !*field) {
689 continue;
690 }
691
692 if (aco_set_defaults(match, match->category, *field)) {
693 ast_log(LOG_ERROR, "In %s: Setting defaults for %s failed\n", file->filename, match->category);
694 res = ACO_PROCESS_ERROR;
695 break;
696 }
697 }
698
699 if (res == ACO_PROCESS_ERROR) {
700 break;
701 }
702
703try_alias:
704 cfg = ast_config_load(filename, cfg_flags);
705 if (!cfg || cfg == CONFIG_STATUS_FILEMISSING) {
706 if (file->alias && strcmp(file->alias, filename)) {
707 filename = file->alias;
708 goto try_alias;
709 }
710 ast_log(LOG_ERROR, "Unable to load config file '%s'\n", file->filename);
711 res = ACO_PROCESS_ERROR;
712 break;
713 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
714 ast_debug(1, "%s was unchanged\n", file->filename);
716 continue;
717 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
718 ast_log(LOG_ERROR, "Contents of %s are invalid and cannot be parsed\n",
719 file->filename);
720 res = ACO_PROCESS_ERROR;
721 break;
722 }
723
724 /* A file got loaded. */
725 if (reload) {
726 /* Must do any subsequent file loads unconditionally. */
727 reload = 0;
729
730 if (file_count != 1) {
731 /*
732 * Must restart loading to load all config files since a file
733 * after the first one changed.
734 */
735 file_count = 0;
736 } else {
738 }
739 } else {
741 }
743 }
744
745 if (res != ACO_PROCESS_OK) {
746 goto end;
747 }
748
749 if (info->pre_apply_config && info->pre_apply_config()) {
750 res = ACO_PROCESS_ERROR;
751 goto end;
752 }
753
754 if (apply_config(info)) {
755 res = ACO_PROCESS_ERROR;
756 goto end;
757 }
758
759 if (info->post_apply_config) {
760 info->post_apply_config();
761 }
762
763end:
764 ao2_cleanup(info->internal->pending);
765 info->internal->pending = NULL;
766
767 return res;
768}
769int aco_process_var(struct aco_type *type, const char *cat, struct ast_variable *var, void *obj)
770{
771 RAII_VAR(struct aco_option *, opt, aco_option_find(type, var->name), ao2_cleanup);
772 if (opt && opt->deprecated && !ast_strlen_zero(opt->aliased_to)) {
773 const char *alias = ast_strdupa(opt->aliased_to);
774 ast_log(LOG_WARNING, "At line %d of %s option '%s' is deprecated. Use '%s' instead\n", var->lineno, var->file, var->name, alias);
775 ao2_ref(opt, -1);
776 opt = aco_option_find(type, alias);
777 }
778
779 if (!opt) {
780 ast_log(LOG_ERROR, "Could not find option suitable for category '%s' named '%s' at line %d of %s\n", cat, var->name, var->lineno, var->file);
781 return -1;
782 }
783
784 if (!opt->handler) {
785 /* It should be impossible for an option to not have a handler */
786 ast_log(LOG_ERROR, "BUG! Somehow a config option for %s/%s was created with no handler!\n", cat, var->name);
787 return -1;
788 }
789
790#ifdef AST_DEVMODE
791 if (opt->doc_unavailable) {
792 ast_log(LOG_ERROR, "Config option '%s' of type '%s' is not completely documented and can not be set\n", var->name, type->name);
793 return -1;
794 }
795#endif
796
797 if (opt->handler(opt, var, obj)) {
798 ast_log(LOG_ERROR, "Error parsing %s=%s at line %d of %s\n", var->name, var->value, var->lineno, var->file);
799 return -1;
800 }
801
802 return 0;
803}
804
805int aco_process_category_options(struct aco_type *type, struct ast_config *cfg, const char *cat, void *obj)
806{
807 struct ast_variable *var;
808
809 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
810 if (aco_process_var(type, cat, var, obj)) {
811 return -1;
812 }
813 }
814
815 return 0;
816}
817
819{
820 /* If we've already had all our internal data cleared out,
821 * then there's no need to proceed further
822 */
823 if (!type->internal) {
824 return;
825 }
826
827 if (type->internal->regex) {
828 regfree(type->internal->regex);
829 ast_free(type->internal->regex);
830 }
831 ao2_cleanup(type->internal->opts);
832 type->internal->opts = NULL;
833 ast_free(type->internal);
834 type->internal = NULL;
835}
836
838{
839 size_t x;
840 struct aco_type *t;
841
842 for (x = 0, t = file->types[x]; t; t = file->types[++x]) {
844 t = NULL;
845 }
846}
847
849{
850 if (!(type->internal = ast_calloc(1, sizeof(*type->internal)))) {
851 return -1;
852 }
853
854 switch (type->category_match) {
855 case ACO_BLACKLIST:
856 case ACO_WHITELIST:
857 if (!(type->internal->regex = build_regex(type->category))) {
859 return -1;
860 }
861 break;
866 break;
867 }
868
869 if (!(type->internal->opts = aco_option_container_alloc())) {
871 return -1;
872 }
873
874 return 0;
875}
876
878{
879 size_t x = 0, y = 0;
880 struct aco_file *file;
881 struct aco_type *type;
882
883 if (!(info->internal = ast_calloc(1, sizeof(*info->internal)))) {
884 return -1;
885 }
886
887 while ((file = info->files[x++])) {
888 while ((type = file->types[y++])) {
890 goto error;
891 }
892#ifdef AST_XML_DOCS
893 if (!info->hidden &&
894 !type->hidden &&
895 type->type != ACO_IGNORE &&
896 xmldoc_update_config_type(info->module, type->name, type->category, type->matchfield, type->matchvalue, type->category_match)) {
897 goto error;
898 }
899#endif /* AST_XML_DOCS */
900 }
901 y = 0;
902 }
903
904 return 0;
905error:
907 return -1;
908}
909
911{
912 int x;
913 /* It shouldn't be possible for internal->pending to be in use when this is called because
914 * of the locks in loader.c around reloads and unloads and the fact that internal->pending
915 * only exists while those locks are held */
916 ast_free(info->internal);
917 info->internal = NULL;
918
919 for (x = 0; info->files[x]; x++) {
921 }
922}
923
924int aco_set_defaults(struct aco_type *type, const char *category, void *obj)
925{
926 struct aco_option *opt;
927 struct ao2_iterator iter;
928
929 if (!type->internal) {
930 return -1;
931 }
932
933 iter = ao2_iterator_init(type->internal->opts, 0);
934
935 while ((opt = ao2_iterator_next(&iter))) {
937
938 if (ast_strlen_zero(opt->default_val)) {
939 ao2_ref(opt, -1);
940 continue;
941 }
942 if (!(var = ast_variable_new(opt->name, opt->default_val, ""))) {
943 ao2_ref(opt, -1);
945 return -1;
946 }
947 if (opt->handler(opt, var, obj)) {
948 ast_log(LOG_ERROR, "Unable to set default for %s, %s=%s\n", category, var->name, var->value);
949 ao2_ref(opt, -1);
951 return -1;
952 }
953 ao2_ref(opt, -1);
954 }
956
957 return 0;
958}
959
960#ifdef AST_XML_DOCS
961
962/*! \internal
963 * \brief Complete the name of the module the user is looking for
964 */
965static char *complete_config_module(const char *word)
966{
967 size_t wordlen = strlen(word);
968 struct ao2_iterator i;
969 struct ast_xml_doc_item *cur;
970
972 while ((cur = ao2_iterator_next(&i))) {
973 if (!strncasecmp(word, cur->name, wordlen)) {
975 ao2_ref(cur, -1);
976 break;
977 }
978 }
979 ao2_ref(cur, -1);
980 }
982
983 return NULL;
984}
985
986/*! \internal
987 * \brief Complete the name of the configuration type the user is looking for
988 */
989static char *complete_config_type(const char *module, const char *word)
990{
991 size_t wordlen = strlen(word);
992 struct ast_xml_doc_item *info;
993 struct ast_xml_doc_item *cur;
994
995 info = ao2_find(xmldocs, module, OBJ_KEY);
996 if (!info) {
997 return NULL;
998 }
999
1000 cur = info;
1001 while ((cur = AST_LIST_NEXT(cur, next))) {
1002 if (!strcasecmp(cur->type, "configObject") && !strncasecmp(word, cur->name, wordlen)) {
1004 break;
1005 }
1006 }
1007 }
1008 ao2_ref(info, -1);
1009
1010 return NULL;
1011}
1012
1013/*! \internal
1014 * \brief Complete the name of the configuration option the user is looking for
1015 */
1016static char *complete_config_option(const char *module, const char *option, const char *word)
1017{
1018 size_t wordlen = strlen(word);
1019 struct ast_xml_doc_item *info;
1020 struct ast_xml_doc_item *cur;
1021
1022 info = ao2_find(xmldocs, module, OBJ_KEY);
1023 if (!info) {
1024 return NULL;
1025 }
1026
1027 cur = info;
1028 while ((cur = AST_LIST_NEXT(cur, next))) {
1029 if (!strcasecmp(cur->type, "configOption") && !strcasecmp(cur->ref, option) && !strncasecmp(word, cur->name, wordlen)) {
1031 break;
1032 }
1033 }
1034 }
1035 ao2_ref(info, -1);
1036
1037 return NULL;
1038}
1039
1040/*! \internal
1041 * \brief Generate a category match string suitable for display in 'config show help'
1042 */
1043static struct ast_str *derive_category_text(enum aco_category_op category_match, const char *category)
1044{
1045 struct ast_str *s = ast_str_create(128);
1046
1047 if (!s) {
1048 return NULL;
1049 }
1050
1051 switch (category_match) {
1053 case ACO_BLACKLIST_ARRAY: {
1054 size_t i;
1055 const char **matches = (const char **) category;
1056 ast_str_append(&s, 0, "^(");
1057 for (i = 0; matches[i]; i++) {
1058 ast_str_append(&s, 0, "%s%s",
1059 i ? "|" : "",
1060 matches[i]);
1061 }
1062 ast_str_append(&s, 0, ")$");
1063 break;
1064 }
1067 ast_str_set(&s, 0, "^%s$", category);
1068 break;
1069 case ACO_WHITELIST:
1070 case ACO_BLACKLIST:
1071 default:
1072 ast_str_set(&s, 0, "%s", category);
1073 break;
1074 }
1075
1076 return s;
1077}
1078
1079/* Define as 0 if we want to allow configurations to be registered without
1080 * documentation
1081 */
1082#define XMLDOC_STRICT 1
1083
1084/*! \internal
1085 * \brief Update the XML documentation for a config type based on its registration
1086 */
1087static int xmldoc_update_config_type(const char *module, const char *name, const char *category, const char *matchfield, const char *matchvalue, enum aco_category_op category_match)
1088{
1089 RAII_VAR(struct ast_xml_xpath_results *, results, NULL, ast_xml_xpath_results_free);
1090 RAII_VAR(struct ast_xml_doc_item *, config_info, ao2_find(xmldocs, module, OBJ_KEY), ao2_cleanup);
1091 struct ast_xml_doc_item *config_type;
1092 struct ast_xml_node *type, *syntax, *matchinfo, *tmp;
1093 struct ast_str *derived_category = NULL;
1094
1095 /* If we already have a syntax element, bail. This isn't an error, since we may unload a module which
1096 * has updated the docs and then load it again. */
1097 if ((results = ast_xmldoc_query("/docs/configInfo[@name='%s']/configFile/configObject[@name='%s']/syntax", module, name))) {
1098 return 0;
1099 }
1100
1101 if (!(results = ast_xmldoc_query("/docs/configInfo[@name='%s']/configFile/configObject[@name='%s']", module, name))) {
1102 ast_log(LOG_WARNING, "Cannot update type '%s' in module '%s' because it has no existing documentation!"
1103 " If this module was recently built, run 'xmldoc reload' to refresh documentation, then load the module again\n",
1104 name, module);
1105 return XMLDOC_STRICT ? -1 : 0;
1106 }
1107
1108 if (!(type = ast_xml_xpath_get_first_result(results))) {
1109 ast_log(LOG_WARNING, "Could not retrieve documentation for type '%s' in module '%s'\n", name, module);
1110 return XMLDOC_STRICT ? -1 : 0;
1111 }
1112
1113 if (!(syntax = ast_xml_new_child(type, "syntax"))) {
1114 ast_log(LOG_WARNING, "Could not create syntax node for type '%s' in module '%s'\n", name, module);
1115 return XMLDOC_STRICT ? -1 : 0;
1116 }
1117
1118 if (!(matchinfo = ast_xml_new_child(syntax, "matchInfo"))) {
1119 ast_log(LOG_WARNING, "Could not create matchInfo node for type '%s' in module '%s'\n", name, module);
1120 return XMLDOC_STRICT ? -1 : 0;
1121 }
1122
1123 if (!(tmp = ast_xml_new_child(matchinfo, "category"))) {
1124 ast_log(LOG_WARNING, "Could not create category node for type '%s' in module '%s'\n", name, module);
1125 return XMLDOC_STRICT ? -1 : 0;
1126 }
1127
1128 derived_category = derive_category_text(category_match, category);
1129 if (derived_category) {
1130 ast_xml_set_text(tmp, ast_str_buffer(derived_category));
1131 ast_free(derived_category);
1132 }
1133
1134 switch (category_match) {
1135 case ACO_WHITELIST:
1138 ast_xml_set_attribute(tmp, "match", "true");
1139 break;
1140 case ACO_BLACKLIST:
1143 ast_xml_set_attribute(tmp, "match", "false");
1144 break;
1145 }
1146
1147 if (!ast_strlen_zero(matchfield)) {
1148 if (!(tmp = ast_xml_new_child(matchinfo, "field"))) {
1149 ast_log(LOG_WARNING, "Could not add %s attribute for type '%s' in module '%s'\n", matchfield, name, module);
1150 return XMLDOC_STRICT ? -1 : 0;
1151 }
1152 ast_xml_set_attribute(tmp, "name", matchfield);
1153 ast_xml_set_text(tmp, matchvalue);
1154 }
1155
1156 if (!config_info || !(config_type = find_xmldoc_type(config_info, name))) {
1157 ast_log(LOG_WARNING, "Could not obtain XML documentation item for config type %s\n", name);
1158 return XMLDOC_STRICT ? -1 : 0;
1159 }
1160
1161 if (ast_xmldoc_regenerate_doc_item(config_type)) {
1162 ast_log(LOG_WARNING, "Could not update type '%s' with values from config type registration\n", name);
1163 return XMLDOC_STRICT ? -1 : 0;
1164 }
1165
1166 return 0;
1167}
1168
1169/*! \internal
1170 * \brief Update the XML documentation for a config option based on its registration
1171 */
1172static int xmldoc_update_config_option(struct aco_type **types, const char *module, const char *name, const char *object_name, const char *default_value, unsigned int regex, enum aco_option_type type)
1173{
1174 RAII_VAR(struct ast_xml_xpath_results *, results, NULL, ast_xml_xpath_results_free);
1175 RAII_VAR(struct ast_xml_doc_item *, config_info, ao2_find(xmldocs, module, OBJ_KEY), ao2_cleanup);
1176 struct ast_xml_doc_item * config_option;
1177 struct ast_xml_node *option;
1178
1180
1181 if (!config_info || !(config_option = find_xmldoc_option(config_info, types, name))) {
1182 ast_log(LOG_ERROR, "XML Documentation for option '%s' in modules '%s' not found!\n", name, module);
1183 return XMLDOC_STRICT ? -1 : 0;
1184 }
1185
1186 if (!(results = ast_xmldoc_query("/docs/configInfo[@name='%s']/configFile/configObject[@name='%s']/configOption[@name='%s']", module, object_name, name))) {
1187 ast_log(LOG_WARNING, "Could not find option '%s' with type '%s' in module '%s'\n", name, object_name, module);
1188 return XMLDOC_STRICT ? -1 : 0;
1189 }
1190
1191 if (!(option = ast_xml_xpath_get_first_result(results))) {
1192 ast_log(LOG_WARNING, "Could not obtain results for option '%s' with type '%s' in module '%s'\n", name, object_name, module);
1193 return XMLDOC_STRICT ? -1 : 0;
1194 }
1195 ast_xml_set_attribute(option, "regex", regex ? "true" : "false");
1196 ast_xml_set_attribute(option, "default", default_value);
1198
1199 if (ast_xmldoc_regenerate_doc_item(config_option)) {
1200 ast_log(LOG_WARNING, "Could not update option '%s' with values from config option registration\n", name);
1201 return XMLDOC_STRICT ? -1 : 0;
1202 }
1203
1204 return 0;
1205}
1206
1207/*! \internal
1208 * \brief Show the modules with configuration information
1209 */
1210static void cli_show_modules(struct ast_cli_args *a)
1211{
1212 struct ast_xml_doc_item *item;
1213 struct ao2_iterator it_items;
1214
1215 ast_assert(a->argc == 3);
1216
1217 if (ao2_container_count(xmldocs) == 0) {
1218 ast_cli(a->fd, "No modules found.\n");
1219 return;
1220 }
1221
1222 it_items = ao2_iterator_init(xmldocs, 0);
1223 ast_cli(a->fd, "The following modules have configuration information:\n");
1224 while ((item = ao2_iterator_next(&it_items))) {
1225 ast_cli(a->fd, "\t%s\n", item->name);
1226 ao2_ref(item, -1);
1227 }
1228 ao2_iterator_destroy(&it_items);
1229}
1230
1231/*! \internal
1232 * \brief Show the configuration types for a module
1233 */
1235{
1237 struct ast_xml_doc_item *tmp;
1238
1239 ast_assert(a->argc == 4);
1240
1241 if (!(item = ao2_find(xmldocs, a->argv[3], OBJ_KEY))) {
1242 ast_cli(a->fd, "Module %s not found.\n", a->argv[3]);
1243 return;
1244 }
1245
1246 if (ast_str_strlen(item->synopsis)) {
1247 ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(item->synopsis), 1));
1248 }
1249 if (ast_str_strlen(item->description)) {
1250 ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(item->description), 1));
1251 }
1252
1253 tmp = item;
1254 ast_cli(a->fd, "Configuration option types for %s:\n", tmp->name);
1255 while ((tmp = AST_LIST_NEXT(tmp, next))) {
1256 if (!strcasecmp(tmp->type, "configObject")) {
1257 ast_cli(a->fd, "%-25s -- %-65.65s\n", tmp->name,
1258 ast_str_buffer(tmp->synopsis));
1259 }
1260 }
1261}
1262
1263/*! \internal
1264 * \brief Show the information for a configuration type
1265 */
1267{
1269 struct ast_xml_doc_item *tmp;
1270 char option_type[64];
1271 int match = 0;
1272
1273 ast_assert(a->argc == 5);
1274
1275 if (!(item = ao2_find(xmldocs, a->argv[3], OBJ_KEY))) {
1276 ast_cli(a->fd, "Unknown module %s\n", a->argv[3]);
1277 return;
1278 }
1279
1280 tmp = item;
1281 while ((tmp = AST_LIST_NEXT(tmp, next))) {
1282 if (!strcasecmp(tmp->type, "configObject") && !strcasecmp(tmp->name, a->argv[4])) {
1283 match = 1;
1284 term_color(option_type, tmp->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(option_type));
1285 ast_cli(a->fd, "%s", option_type);
1286 if (ast_str_strlen(tmp->syntax)) {
1287 ast_cli(a->fd, ": [%s]\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->syntax), 1));
1288 } else {
1289 ast_cli(a->fd, "\n\n");
1290 }
1291 if (ast_str_strlen(tmp->synopsis)) {
1292 ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->synopsis), 1));
1293 }
1294 if (ast_str_strlen(tmp->description)) {
1295 ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->description), 1));
1296 }
1297 }
1298 }
1299
1300 if (!match) {
1301 ast_cli(a->fd, "Unknown configuration type %s\n", a->argv[4]);
1302 return;
1303 }
1304
1305 /* Now iterate over the options for the type */
1306 tmp = item;
1307 while ((tmp = AST_LIST_NEXT(tmp, next))) {
1308 if (!strcasecmp(tmp->type, "configOption") && !strcasecmp(tmp->ref, a->argv[4])) {
1309 ast_cli(a->fd, "%-25s -- %-120.120s\n", tmp->name,
1310 ast_str_buffer(tmp->synopsis));
1311 }
1312 }
1313}
1314
1315/*! \internal
1316 * \brief Show detailed information for an option
1317 */
1319{
1321 struct ast_xml_doc_item *tmp;
1322 char option_name[64];
1323 int match = 0;
1324
1325 ast_assert(a->argc == 6);
1326
1327 if (!(item = ao2_find(xmldocs, a->argv[3], OBJ_KEY))) {
1328 ast_cli(a->fd, "Unknown module %s\n", a->argv[3]);
1329 return;
1330 }
1331 tmp = item;
1332 while ((tmp = AST_LIST_NEXT(tmp, next))) {
1333 if (!strcasecmp(tmp->type, "configOption") && !strcasecmp(tmp->ref, a->argv[4]) && !strcasecmp(tmp->name, a->argv[5])) {
1334 if (match) {
1335 ast_cli(a->fd, "\n");
1336 }
1337 term_color(option_name, tmp->ref, COLOR_MAGENTA, COLOR_BLACK, sizeof(option_name));
1338 ast_cli(a->fd, "[%s%s]\n", option_name, ast_term_reset());
1339 if (ast_str_strlen(tmp->syntax)) {
1340 ast_cli(a->fd, "%s\n", ast_xmldoc_printable(ast_str_buffer(tmp->syntax), 1));
1341 }
1342 ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(AS_OR(tmp->synopsis, "No information available"), 1));
1343 if (ast_str_strlen(tmp->description)) {
1344 ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->description), 1));
1345 }
1346
1347 if (ast_str_strlen(tmp->seealso)) {
1348 ast_cli(a->fd, "See Also:\n");
1349 ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->seealso), 1));
1350 }
1351
1352 match = 1;
1353 }
1354 }
1355
1356 if (!match) {
1357 ast_cli(a->fd, "No option %s found for %s:%s\n", a->argv[5], a->argv[3], a->argv[4]);
1358 }
1359}
1360
1361static char *cli_show_help(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1362{
1363 switch (cmd) {
1364 case CLI_INIT:
1365 e->command = "config show help";
1366 e->usage =
1367 "Usage: config show help [<module> [<type> [<option>]]]\n"
1368 " Display detailed information about module configuration.\n"
1369 " * If nothing is specified, the modules that have\n"
1370 " configuration information are listed.\n"
1371 " * If <module> is specified, the configuration types\n"
1372 " for that module will be listed, along with brief\n"
1373 " information about that type.\n"
1374 " * If <module> and <type> are specified, detailed\n"
1375 " information about the type is displayed, as well\n"
1376 " as the available options.\n"
1377 " * If <module>, <type>, and <option> are specified,\n"
1378 " detailed information will be displayed about that\n"
1379 " option.\n"
1380 " NOTE: the help documentation is partially generated at run\n"
1381 " time when a module is loaded. If a module is not loaded,\n"
1382 " configuration help for that module may be incomplete.\n";
1383 return NULL;
1384 case CLI_GENERATE:
1385 switch(a->pos) {
1386 case 3:
1387 return complete_config_module(a->word);
1388 case 4:
1389 return complete_config_type(a->argv[3], a->word);
1390 case 5:
1391 return complete_config_option(a->argv[3], a->argv[4], a->word);
1392 default:
1393 return NULL;
1394 }
1395 }
1396
1397 switch (a->argc) {
1398 case 3:
1400 break;
1401 case 4:
1403 break;
1404 case 5:
1406 break;
1407 case 6:
1409 break;
1410 default:
1411 return CLI_SHOWUSAGE;
1412 }
1413
1414 return CLI_SUCCESS;
1415}
1416
1417static struct ast_cli_entry cli_aco[] = {
1418 AST_CLI_DEFINE(cli_show_help, "Show configuration help for a module"),
1419};
1420
1421static void aco_deinit(void)
1422{
1425}
1426#endif /* AST_XML_DOCS */
1427
1428int aco_init(void)
1429{
1430#ifdef AST_XML_DOCS
1432 if (!(xmldocs = ast_xmldoc_build_documentation("configInfo"))) {
1433 ast_log(LOG_ERROR, "Couldn't build config documentation\n");
1434 return -1;
1435 }
1437#endif /* AST_XML_DOCS */
1438 return 0;
1439}
1440
1441/* Default config option handlers */
1442
1443/*! \brief Default option handler for signed integers
1444 * \note For a description of the opt->flags and opt->args values, see the documentation for
1445 * enum aco_option_type in config_options.h
1446 */
1447static int int_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
1448 int *field = (int *)(obj + opt->args[0]);
1449 unsigned int flags = PARSE_INT32 | opt->flags;
1450 int res = 0;
1451 if (opt->flags & PARSE_IN_RANGE) {
1452 res = opt->flags & PARSE_DEFAULT ?
1453 ast_parse_arg(var->value, flags, field, (int) opt->args[1], (int) opt->args[2], opt->args[3]) :
1454 ast_parse_arg(var->value, flags, field, (int) opt->args[1], (int) opt->args[2]);
1455 if (res) {
1456 if (opt->flags & PARSE_RANGE_DEFAULTS) {
1457 ast_log(LOG_WARNING, "Failed to set %s=%s. Set to %d instead due to range limit (%d, %d)\n", var->name, var->value, *field, (int) opt->args[1], (int) opt->args[2]);
1458 res = 0;
1459 } else if (opt->flags & PARSE_DEFAULT) {
1460 ast_log(LOG_WARNING, "Failed to set %s=%s, Set to default value %d instead.\n", var->name, var->value, *field);
1461 res = 0;
1462 }
1463 }
1464 } else if ((opt->flags & PARSE_DEFAULT) && ast_parse_arg(var->value, flags, field, (int) opt->args[1])) {
1465 ast_log(LOG_WARNING, "Attempted to set %s=%s, but set it to %d instead due to default)\n", var->name, var->value, *field);
1466 } else {
1467 res = ast_parse_arg(var->value, flags, field);
1468 }
1469
1470 return res;
1471}
1472
1473/*! \brief Default option handler for unsigned integers
1474 * \note For a description of the opt->flags and opt->args values, see the documentation for
1475 * enum aco_option_type in config_options.h
1476 */
1477static int uint_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
1478 unsigned int *field = (unsigned int *)(obj + opt->args[0]);
1479 unsigned int flags = PARSE_UINT32 | opt->flags;
1480 int res = 0;
1481 if (opt->flags & PARSE_IN_RANGE) {
1482 res = opt->flags & PARSE_DEFAULT ?
1483 ast_parse_arg(var->value, flags, field, (unsigned int) opt->args[1], (unsigned int) opt->args[2], opt->args[3]) :
1484 ast_parse_arg(var->value, flags, field, (unsigned int) opt->args[1], (unsigned int) opt->args[2]);
1485 if (res) {
1486 if (opt->flags & PARSE_RANGE_DEFAULTS) {
1487 ast_log(LOG_WARNING, "Failed to set %s=%s. Set to %u instead due to range limit (%d, %d)\n", var->name, var->value, *field, (int) opt->args[1], (int) opt->args[2]);
1488 res = 0;
1489 } else if (opt->flags & PARSE_DEFAULT) {
1490 ast_log(LOG_WARNING, "Failed to set %s=%s, Set to default value %u instead.\n", var->name, var->value, *field);
1491 res = 0;
1492 }
1493 }
1494 } else if ((opt->flags & PARSE_DEFAULT) && ast_parse_arg(var->value, flags, field, (unsigned int) opt->args[1])) {
1495 ast_log(LOG_WARNING, "Attempted to set %s=%s, but set it to %u instead due to default)\n", var->name, var->value, *field);
1496 } else {
1497 res = ast_parse_arg(var->value, flags, field);
1498 }
1499
1500 return res;
1501}
1502
1503/*! \brief Default option handler for timelen signed integers
1504 * \note For a description of the opt->flags and opt->args values, see the documentation for
1505 * enum aco_option_type in config_options.h
1506 */
1507static int timelen_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1508{
1509 int *field = (int *)(obj + opt->args[0]);
1510 unsigned int flags = PARSE_TIMELEN | opt->flags;
1511 int res = 0;
1512 if (opt->flags & PARSE_IN_RANGE) {
1513 if (opt->flags & PARSE_DEFAULT) {
1514 res = ast_parse_arg(var->value, flags, field, (enum ast_timelen) opt->args[1], (int) opt->args[2], (int) opt->args[3], opt->args[4]);
1515 } else {
1516 res = ast_parse_arg(var->value, flags, field, (enum ast_timelen) opt->args[1], (int) opt->args[2], (int) opt->args[3]);
1517 }
1518 if (res) {
1519 if (opt->flags & PARSE_RANGE_DEFAULTS) {
1520 ast_log(LOG_WARNING, "Failed to set %s=%s. Set to %d instead due to range limit (%d, %d)\n", var->name, var->value, *field, (int) opt->args[2], (int) opt->args[3]);
1521 res = 0;
1522 } else if (opt->flags & PARSE_DEFAULT) {
1523 ast_log(LOG_WARNING, "Failed to set %s=%s, Set to default value %d instead.\n", var->name, var->value, *field);
1524 res = 0;
1525 }
1526 }
1527 } else if ((opt->flags & PARSE_DEFAULT) && ast_parse_arg(var->value, flags, field, (enum ast_timelen) opt->args[1], (int) opt->args[2])) {
1528 ast_log(LOG_WARNING, "Attempted to set %s=%s, but set it to %d instead due to default)\n", var->name, var->value, *field);
1529 } else {
1530 res = ast_parse_arg(var->value, flags, field, (enum ast_timelen) opt->args[1]);
1531 }
1532
1533 return res;
1534}
1535
1536/*! \brief Default option handler for doubles
1537 * \note For a description of the opt->flags and opt->args values, see the documentation for
1538 * enum aco_option_type in config_options.h
1539 */
1540static int double_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
1541 double *field = (double *)(obj + opt->args[0]);
1542 return ast_parse_arg(var->value, PARSE_DOUBLE | opt->flags, field);
1543}
1544
1545/*! \brief Default handler for ACLs
1546 * \note For a description of the opt->flags and opt->args values, see the documentation for
1547 * enum aco_option_type in config_options.h
1548 */
1549static int acl_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
1550 struct ast_ha **ha = (struct ast_ha **)(obj + opt->args[0]);
1551 int error = 0;
1552 *ha = ast_append_ha(opt->flags ? "permit" : "deny", var->value, *ha, &error);
1553 return error;
1554}
1555
1556/*! \brief Default option handler for codec preferences/capabilities
1557 * \note For a description of the opt->flags and opt->args values, see the documentation for
1558 * enum aco_option_type in config_options.h
1559 */
1560static int codec_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
1561 struct ast_format_cap **cap = (struct ast_format_cap **)(obj + opt->args[0]);
1562 return ast_format_cap_update_by_allow_disallow(*cap, var->value, opt->flags);
1563}
1564
1565/*! \brief Default option handler for stringfields
1566 * \note For a description of the opt->flags and opt->args values, see the documentation for
1567 * enum aco_option_type in config_options.h
1568 */
1569static int stringfield_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1570{
1571 ast_string_field *field = (const char **)(obj + opt->args[0]);
1572 struct ast_string_field_pool **pool = (struct ast_string_field_pool **)(obj + opt->args[1]);
1573 struct ast_string_field_mgr *mgr = (struct ast_string_field_mgr *)(obj + opt->args[2]);
1574
1575 if (opt->flags && ast_strlen_zero(var->value)) {
1576 return -1;
1577 }
1578 ast_string_field_ptr_set_by_fields(*pool, *mgr, field, var->value);
1579 return 0;
1580}
1581
1582/*! \brief Default option handler for bools (ast_true/ast_false)
1583 * \note For a description of the opt->flags and opt->args values, see the documentation for
1584 * enum aco_option_type in config_options.h
1585 */
1586static int bool_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1587{
1588 unsigned int *field = (unsigned int *)(obj + opt->args[0]);
1589 *field = opt->flags ? ast_true(var->value) : ast_false(var->value);
1590 return 0;
1591}
1592
1593/*! \brief Default option handler for bools (ast_true/ast_false) that are stored as flags
1594 * \note For a description of the opt->flags and opt->args values, see the documentation for
1595 * enum aco_option_type in config_options.h
1596 */
1597static int boolflag_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1598{
1599 unsigned int *flags_field = (unsigned int *)(obj + opt->args[0]);
1600 unsigned int val = opt->flags ? ast_true(var->value) : ast_false(var->value);
1601 unsigned int flag = opt->args[1];
1602 if (val) {
1603 *flags_field |= flag;
1604 } else {
1605 *flags_field &= ~flag;
1606 }
1607 return 0;
1608}
1609
1610/*! \brief Default handler for ast_sockaddrs
1611 * \note For a description of the opt->flags and opt->args values, see the documentation for
1612 * enum aco_option_type in config_options.h
1613 */
1614static int sockaddr_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1615{
1616 struct ast_sockaddr *field = (struct ast_sockaddr *)(obj + opt->args[0]);
1617 return ast_parse_arg(var->value, PARSE_ADDR | opt->flags, field);
1618}
1619
1620/*! \brief Default handler for doing nothing
1621 */
1622static int noop_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1623{
1624 return 0;
1625}
1626
1627/*! \brief Default handler for character arrays
1628 * \note For a description of the opt->flags and opt->args values, see the documentation for
1629 * enum aco_option_type in config_options.h
1630 */
1631static int chararray_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1632{
1633 char *field = (char *)(obj + opt->args[0]);
1634 size_t len = opt->args[1];
1635
1636 if (opt->flags && ast_strlen_zero(var->value)) {
1637 return -1;
1638 }
1639 ast_copy_string(field, var->value, len);
1640 return 0;
1641}
Prototypes for public functions only of internal interest,.
Access Control of various sorts.
struct ast_ha * ast_append_ha(const char *sense, const char *stuff, struct ast_ha *path, int *error)
Add a new rule to a list of HAs.
Definition: acl.c:712
char * text
Definition: app_queue.c:1639
#define var
Definition: ast_expr2f.c:605
Asterisk main include file. File version handling, generic pbx functions.
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition: clicompat.c:19
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
#define ast_log
Definition: astobj2.c:42
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
@ CMP_MATCH
Definition: astobj2.h:1027
@ CMP_STOP
Definition: astobj2.h:1028
#define OBJ_KEY
Definition: astobj2.h:1151
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
#define ao2_global_obj_replace_unref(holder, obj)
Replace an ao2 object in the global holder, throwing away any old object.
Definition: astobj2.h:901
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition: astobj2.h:1693
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:404
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition: astobj2.h:1303
static int tmp()
Definition: bt_open.c:389
static int match(struct ast_sockaddr *addr, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
Definition: chan_iax2.c:2362
static const char type[]
Definition: chan_ooh323.c:109
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition: cli.h:45
int ast_cli_unregister(struct ast_cli_entry *e)
Unregisters a command or an array of commands.
Definition: main/cli.c:2439
#define CLI_SUCCESS
Definition: cli.h:44
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
int ast_cli_completion_add(char *value)
Add a result to a request for completion options.
Definition: main/cli.c:2768
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
short word
struct ao2_container * aco_option_container_alloc(void)
Allocate a container to hold config options.
#define CONFIG_OPT_BUCKETS
static struct ao2_container * xmldocs
static char * aco_option_type_string[]
Value of the aco_option_type enum as strings.
static void internal_type_destroy(struct aco_type *type)
int __aco_option_register(struct aco_info *info, const char *name, enum aco_matchtype matchtype, struct aco_type **types, const char *default_val, enum aco_option_type kind, aco_option_handler handler, unsigned int flags, unsigned int no_doc, size_t argc,...)
register a config option
static struct ast_cli_entry cli_aco[]
int aco_option_register_deprecated(struct aco_info *info, const char *name, struct aco_type **types, const char *aliased_to)
Register a deprecated (and aliased) config option.
static int find_option_cb(void *obj, void *arg, int flags)
int aco_set_defaults(struct aco_type *type, const char *category, void *obj)
Set all default options of obj.
void aco_info_destroy(struct aco_info *info)
Destroy an initialized aco_info struct.
static int chararray_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
Default handler for character arrays.
int aco_init(void)
static int sockaddr_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
Default handler for ast_sockaddrs.
static int stringfield_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
Default option handler for stringfields.
static int process_category(struct ast_config *cfg, struct aco_info *info, struct aco_file *file, const char *cat, int preload)
static int xmldoc_update_config_option(struct aco_type **types, const char *module, const char *name, const char *object_name, const char *default_value, unsigned int regex, enum aco_option_type type)
static int codec_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
Default option handler for codec preferences/capabilities.
static int config_opt_hash(const void *obj, const int flags)
static int internal_type_init(struct aco_type *type)
int aco_info_init(struct aco_info *info)
Initialize an aco_info structure.
static int config_opt_cmp(void *obj, void *arg, int flags)
static int boolflag_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
Default option handler for bools (ast_true/ast_false) that are stored as flags.
static int timelen_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
Default option handler for timelen signed integers.
static void aco_deinit(void)
static void config_option_destroy(void *obj)
static int uint_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
Default option handler for unsigned integers.
static int apply_config(struct aco_info *info)
static int double_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
Default option handler for doubles.
static int bool_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
Default option handler for bools (ast_true/ast_false)
static int link_option_to_types(struct aco_info *info, struct aco_type **types, struct aco_option *opt)
unsigned int aco_option_get_flags(const struct aco_option *option)
Read the flags of a config option - useful when using a custom callback for a config option.
static struct ast_xml_doc_item * find_xmldoc_type(struct ast_xml_doc_item *config_info, const char *name)
static regex_t * build_regex(const char *text)
static void cli_show_modules(struct ast_cli_args *a)
static void internal_file_types_destroy(struct aco_file *file)
static struct ast_xml_doc_item * find_xmldoc_option(struct ast_xml_doc_item *config_info, struct aco_type **types, const char *name)
int aco_process_category_options(struct aco_type *type, struct ast_config *cfg, const char *cat, void *obj)
Parse each option defined in a config category.
static struct ast_str * derive_category_text(enum aco_category_op category_match, const char *category)
static char * complete_config_module(const char *word)
static int internal_aco_type_category_check(struct aco_type *match, const char *category)
static aco_option_handler ast_config_option_default_handler(enum aco_option_type type)
intptr_t aco_option_get_argument(const struct aco_option *option, unsigned int position)
Get the offset position for an argument within a config option.
static int acl_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
Default handler for ACLs.
static int noop_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
Default handler for doing nothing.
static void cli_show_module_types(struct ast_cli_args *a)
int aco_process_var(struct aco_type *type, const char *cat, struct ast_variable *var, void *obj)
Parse a single ast_variable and apply it to an object.
static int xmldoc_update_config_type(const char *module, const char *name, const char *category, const char *matchfield, const char *matchvalue, enum aco_category_op category_match)
static enum aco_process_status internal_process_ast_config(struct aco_info *info, struct aco_file *file, struct ast_config *cfg)
static char * complete_config_option(const char *module, const char *option, const char *word)
static void cli_show_module_options(struct ast_cli_args *a)
static int is_preload(struct aco_file *file, const char *cat)
static struct aco_type * internal_aco_type_find(struct aco_file *file, struct ast_config *cfg, const char *category)
static struct aco_option * aco_option_find(struct aco_type *type, const char *name)
void * aco_pending_config(struct aco_info *info)
Get pending config changes.
#define XMLDOC_STRICT
static char * complete_config_type(const char *module, const char *word)
static void cli_show_module_type(struct ast_cli_args *a)
static char * cli_show_help(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
enum aco_process_status aco_process_config(struct aco_info *info, int reload)
Process a config info via the options registered with an aco_info.
static int int_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
Default option handler for signed integers.
enum aco_process_status aco_process_ast_config(struct aco_info *info, struct aco_file *file, struct ast_config *cfg)
Process config info from an ast_config via options registered with an aco_info.
Configuration option-handling.
int(* aco_option_handler)(const struct aco_option *opt, struct ast_variable *var, void *obj)
A callback function for handling a particular option.
aco_matchtype
What kind of matching should be done on an option name.
@ ACO_PREFIX
@ ACO_EXACT
@ ACO_REGEX
aco_process_status
Return values for the aco_process functions.
@ ACO_PROCESS_UNCHANGED
The config had not been edited and no changes applied.
@ ACO_PROCESS_ERROR
Their was an error and no changes were applied.
@ ACO_PROCESS_OK
The config was processed and applied.
aco_option_type
The option types.
@ OPT_UINT_T
Type for default option handler for unsigned integers.
@ OPT_NOOP_T
Type for a default handler that should do nothing.
@ OPT_CODEC_T
Type for default option handler for format capabilities.
@ OPT_BOOL_T
Type for default option handler for bools (ast_true/ast_false)
@ OPT_BOOLFLAG_T
Type for default option handler for bools (ast_true/ast_false) that are stored in a flag.
@ OPT_CUSTOM_T
Type for a custom (user-defined) option handler.
@ OPT_CHAR_ARRAY_T
Type for default option handler for character array strings.
@ OPT_ACL_T
Type for default option handler for ACLs.
@ OPT_SOCKADDR_T
Type for default handler for ast_sockaddrs.
@ OPT_YESNO_T
Type for default option handler for bools (ast_true/ast_false)
@ OPT_INT_T
Type for default option handler for signed integers.
@ OPT_TIMELEN_T
Type for default option handler for time length signed integers.
@ OPT_DOUBLE_T
Type for default option handler for doubles.
@ OPT_STRINGFIELD_T
Type for default option handler for stringfields.
@ ACO_ITEM
@ ACO_GLOBAL
@ ACO_IGNORE
aco_category_op
@ ACO_WHITELIST_ARRAY
@ ACO_BLACKLIST
@ ACO_WHITELIST_EXACT
@ ACO_WHITELIST
@ ACO_BLACKLIST_ARRAY
@ ACO_BLACKLIST_EXACT
char * end
Definition: eagi_proxy.c:73
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
long int flag
Definition: f2c.h:83
Format Capabilities API.
int ast_format_cap_update_by_allow_disallow(struct ast_format_cap *cap, const char *list, int allowing)
Parse an "allow" or "deny" list and modify a format capabilities structure accordingly.
Definition: format_cap.c:320
static const char name[]
Definition: format_mp3.c:68
static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
Configuration File Parser.
#define ast_config_load(filename, flags)
Load a config file.
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3326
#define CONFIG_STATUS_FILEMISSING
#define ast_variable_new(name, value, filename)
#define CONFIG_STATUS_FILEUNCHANGED
#define CONFIG_STATUS_FILEINVALID
int ast_parse_arg(const char *arg, enum ast_parse_flags flags, void *p_result,...)
The argument parsing routine.
Definition: main/config.c:3834
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:784
@ PARSE_RANGE_DEFAULTS
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1215
@ CONFIG_FLAG_FILEUNCHANGED
Asterisk internal frame definitions.
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define LOG_NOTICE
#define LOG_WARNING
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:439
def info(msg)
static int reload(void)
#define NULL
Definition: resample.c:96
const char * ast_string_field
Definition: stringfields.h:190
#define ast_string_field_ptr_set_by_fields(field_mgr_pool, field_mgr, ptr, data)
Definition: stringfields.h:510
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: utils.c:2199
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"....
Definition: utils.c:2216
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:730
static force_inline int attribute_pure ast_str_case_hash(const char *str)
Compute a hash value on a case-insensitive string.
Definition: strings.h:1303
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
#define AS_OR(a, b)
Definition: strings.h:49
The representation of a single configuration file to be processed.
const char * filename
Bits of aco_info that shouldn't be assigned outside this file.
regex_t * name_regex
unsigned int no_doc
const char * name
unsigned char deprecated
const char * aliased_to
const char * default_val
unsigned int flags
intptr_t args[0]
struct aco_type ** obj
enum aco_matchtype match_type
aco_option_handler handler
enum aco_option_type type
struct ao2_container * opts
Type information about a category-level configurable object.
const char * category
const char * name
struct aco_type_internal * internal
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
descriptor for a cli entry.
Definition: cli.h:171
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
Structure used to handle boolean flags.
Definition: utils.h:199
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
internal representation of ACL entries In principle user applications would have no need for this,...
Definition: acl.h:51
Socket address structure.
Definition: netsock2.h:97
Support for dynamic strings.
Definition: strings.h:623
Structure for variables, used for configurations and for channel variables.
Struct that contains the XML documentation for a particular item. Note that this is an ao2 ref counte...
Definition: xmldoc.h:56
const ast_string_field ref
Definition: xmldoc.h:74
struct ast_xml_doc_item * next
Definition: xmldoc.h:80
const ast_string_field type
Definition: xmldoc.h:74
const ast_string_field name
Definition: xmldoc.h:74
Definition: ast_expr2.c:325
Handy terminal functions for vt* terms.
const char * ast_term_reset(void)
Returns the terminal reset code.
Definition: term.c:357
#define COLOR_MAGENTA
Definition: term.h:60
#define COLOR_BLACK
Definition: term.h:50
char * term_color(char *outbuf, const char *inbuf, int fgcolor, int bgcolor, int maxout)
Colorize a specified string by adding terminal color codes.
Definition: term.c:235
static void handler(const char *name, int response_code, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
Definition: test_ari.c:59
struct association categories[]
static struct aco_type item
Definition: test_config.c:1463
static struct test_val a
int error(const char *format,...)
Definition: utils/frame.c:999
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
#define ast_assert(a)
Definition: utils.h:739
#define ast_clear_flag(p, flag)
Definition: utils.h:77
#define ARRAY_LEN(a)
Definition: utils.h:666
struct ast_xml_node * ast_xml_new_child(struct ast_xml_node *parent, const char *child_name)
Add a child node inside a passed parent node.
Definition: xml.c:156
struct ast_xml_node * ast_xml_xpath_get_first_result(struct ast_xml_xpath_results *results)
Return the first result node of an XPath query.
Definition: xml.c:415
void ast_xml_xpath_results_free(struct ast_xml_xpath_results *results)
Free the XPath results.
Definition: xml.c:425
int ast_xml_set_attribute(struct ast_xml_node *node, const char *name, const char *value)
Set an attribute to a node.
Definition: xml.c:284
void ast_xml_set_text(struct ast_xml_node *node, const char *content)
Set an element content string.
Definition: xml.c:362
Asterisk XML Documentation API.
struct ast_xml_xpath_results * ast_xmldoc_query(const char *fmt,...)
Execute an XPath query on the loaded XML documentation.
Definition: xmldoc.c:2576
struct ao2_container * ast_xmldoc_build_documentation(const char *type)
Build the documentation for a particular source type.
Definition: xmldoc.c:2684
char * ast_xmldoc_printable(const char *bwinput, int withcolors)
Colorize and put delimiters (instead of tags) to the xmldoc output.
Definition: xmldoc.c:241
int ast_xmldoc_regenerate_doc_item(struct ast_xml_doc_item *item)
Regenerate the documentation for a particular item.
Definition: xmldoc.c:2635