/* grecs - Gray's Extensible Configuration System Copyright (C) 2007-2022 Sergey Poznyakoff Grecs is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. Grecs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grecs. If not, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include "grecs.h" struct logging_setup { int use_syslog; int print_priority; char *tag; char *facility; }; struct logging_setup logging_setup; char *scalar_string; char *mailbox_pattern; char *mailbox_type; struct grecs_list *listvar; struct program { char *name; struct logging_setup logging_setup; char *scalar_string; grecs_locus_t locus; struct program *next; }; struct grecs_list *proglist; #if GRECS_TREE_API # define GRECS_CB_ARGS \ enum grecs_callback_command cmd,\ grecs_node_t *node,\ void *varptr,\ void *cb_data # define GRECS_CB_AUTO \ grecs_locus_t *locus = &node->locus;\ grecs_value_t *value = node->v.value; #else # define GRECS_CB_ARGS \ enum grecs_callback_command cmd,\ grecs_locus_t *locus,\ void *varptr,\ grecs_value_t *value,\ void *cb_data # define GRECS_CB_AUTO #endif static int cb_logging_facility(GRECS_CB_ARGS) { GRECS_CB_AUTO if (cmd != grecs_callback_set_value) { grecs_error(locus, 0, "Unexpected block statement"); return 1; } if (!value || value->type != GRECS_TYPE_STRING) { grecs_error(locus, 0, "expected string argument"); return 1; } *(char**)varptr = grecs_strdup(value->v.string); return 0; } static struct grecs_keyword logging_kwtab[] = { { "syslog", NULL, "Send to syslog", grecs_type_bool, GRECS_DFLT, NULL, offsetof(struct logging_setup, use_syslog) }, { "facility", "name", "Set logging facility", grecs_type_string, GRECS_AGGR, NULL, offsetof(struct logging_setup, facility), cb_logging_facility }, { "tag", "label", "Tag logging messages with this string", grecs_type_string, GRECS_DFLT, NULL, offsetof(struct logging_setup, tag) }, { "print-priority", NULL, "Prefix each message with its priority", grecs_type_bool, GRECS_DFLT, NULL, offsetof(struct logging_setup, print_priority) }, { NULL }, }; static struct grecs_keyword mailbox_kwtab[] = { { "mailbox-pattern", NULL, "Default mailbox pattern", grecs_type_string, GRECS_DFLT, &mailbox_pattern }, { "mailbox-type", NULL, "Default mailbox type", grecs_type_string, GRECS_DFLT, &mailbox_type }, { NULL }, }; static struct grecs_keyword program_kwtab[] = { { "scalar", "label", "Scalar string", grecs_type_string, GRECS_DFLT, NULL, offsetof(struct program,scalar_string) }, { "logging", NULL, "Configure logging logging", grecs_type_section, GRECS_DFLT, NULL, offsetof(struct program,logging_setup), NULL, NULL, logging_kwtab }, { NULL } }; static int cb_program(GRECS_CB_ARGS) { struct program *prog; void **pdata = cb_data; GRECS_CB_AUTO switch (cmd) { case grecs_callback_section_begin: if (!value || value->type != GRECS_TYPE_STRING) { grecs_error(locus, 0, "tag must be a string"); return 0; } prog = grecs_zalloc(sizeof(*prog)); prog->name = grecs_strdup(value->v.string); prog->locus = *locus; *pdata = prog; break; case grecs_callback_section_end: prog = *pdata; if (!proglist) proglist = grecs_list_create(); grecs_list_append(proglist, prog); break; case grecs_callback_set_value: grecs_error(locus, 0, "invalid use of block statement"); } return 0; } static struct grecs_keyword main_kwtab[] = { { "scalar", "label", "Scalar string", grecs_type_string, GRECS_DFLT, &scalar_string }, { "logging", NULL, "Configure logging logging", grecs_type_section, GRECS_DFLT, &logging_setup, 0, NULL, NULL, logging_kwtab }, { "mailbox", NULL, "Mailbox configuration", grecs_type_section, GRECS_DFLT, NULL, 0, NULL, NULL, mailbox_kwtab }, { "program", "name: string", "Subprogram configuration", grecs_type_section, GRECS_DFLT, NULL, 0, cb_program, NULL, program_kwtab }, { "listvar", NULL, "list variable", grecs_type_string, GRECS_LIST, &listvar }, { NULL } }; #define S(s) ((s) ? (s) : "(null)") static void print_logging_setup(struct logging_setup *p) { printf("logging: %d/%s/%s/%d\n", p->use_syslog, S(p->facility), S(p->tag), p->print_priority); } static void print_program(struct program *prog) { printf("Program %s:\n", prog->name); printf("scalar = %s\n", S(prog->scalar_string)); print_logging_setup(&prog->logging_setup); } static int node_ident_cmp(struct grecs_node const *a, struct grecs_node const *b) { return strcmp(a->ident, b->ident); } static void usage(const char *arg, FILE *fp, int code) { fprintf(fp, "usage: %s [-h] [-cfhelp] [-reduce] [-sort] [-print] [-locus] [-noset] file\n", arg); exit(code); } int main(int argc, char **argv) { char *progname = argv[0]; const char *file = NULL; struct grecs_node *tree; int cfhelp = 0; int reduce = 0; int print = 0; int sort = 0; int flags = GRECS_NODE_FLAG_DEFAULT; int dontset = 0; while (--argc) { char *arg = *++argv; if (strcmp(arg, "-cfhelp") == 0) cfhelp = 1; else if (strcmp(arg, "-h") == 0) usage(progname, stdout, 0); else if (strcmp(arg, "-reduce") == 0) reduce = 1; else if (strcmp(arg, "-print") == 0) print = 1; else if (strcmp(arg, "-locus") == 0) flags |= GRECS_NODE_FLAG_LOCUS; else if (strncmp(arg, "-delim=", 7) == 0) flags |= arg[7]; else if (strcmp(arg, "-sort") == 0) sort = 1; else if (strcmp(arg, "-noset") == 0) dontset = 1; else if (arg[0] == '-') usage(progname, stderr, 1); else if (file) usage(progname, stderr, 1); else file = arg; } if ((!file && !cfhelp) || argc) usage(progname, stderr, 1); if (cfhelp) { static char docstring[] = "Sample configuration file structure.\n"; grecs_print_docstring(docstring, 0, stdout); grecs_print_statement_array(main_kwtab, 1, 0, stdout); exit(0); } tree = grecs_parse(file); if (!tree) exit(2); if (reduce) grecs_tree_reduce(tree, main_kwtab, GRECS_AGGR); if (sort) grecs_tree_sort(tree, node_ident_cmp); if (print) { grecs_print_node(tree, flags, stdout); fputc('\n', stdout); } if (dontset) exit(0); if (grecs_tree_process(tree, main_kwtab)) exit(2); grecs_tree_free(tree); printf("Global settings:\n"); printf("scalar = %s\n", S(scalar_string)); if (listvar) { struct grecs_list_entry *ep; printf("listvar ="); for (ep = listvar->head; ep; ep = ep->next) printf(" \"%s\"", (char*)ep->data); putchar('\n'); } print_logging_setup(&logging_setup); if (proglist) { struct grecs_list_entry *ep; printf("Programs configured: %lu\n", (unsigned long) grecs_list_size(proglist)); for (ep = proglist->head; ep; ep = ep->next) print_program(ep->data); } exit(0); }