123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511 |
- #include <stdlib.h>
- #include <string.h>
- #include <assert.h>
- #include <errno.h>
- #include <sys/types.h>
- #include <dirent.h>
- #include <faux/faux.h>
- #include <faux/str.h>
- #include <faux/error.h>
- #include <klish/kscheme.h>
- #include <klish/ischeme.h>
- #include <klish/kxml.h>
- #define TAG "XML"
- typedef bool_t (kxml_process_fn)(const kxml_node_t *element,
- void *parent, faux_error_t *error);
- static kxml_process_fn
- process_action,
- process_param,
- process_command,
- process_view,
- process_ptype,
- process_plugin,
- process_klish;
- typedef enum {
- KTAG_NONE,
- KTAG_ACTION,
- KTAG_PARAM,
- KTAG_COMMAND,
- KTAG_VIEW,
- KTAG_PTYPE,
- KTAG_PLUGIN,
- KTAG_KLISH,
- KTAG_MAX
- } ktags_e;
- static const char *kxml_tags[] = {
- NULL,
- "ACTION",
- "PARAM",
- "COMMAND",
- "VIEW",
- "PTYPE",
- "PLUGIN",
- "KLISH"
- };
- static kxml_process_fn *kxml_handlers[] = {
- NULL,
- process_action,
- process_param,
- process_command,
- process_view,
- process_ptype,
- process_plugin,
- process_klish
- };
- static ktags_e kxml_node_tag(const kxml_node_t *node)
- {
- ktags_e tag = KTAG_NONE;
- char *name = NULL;
- if (!node)
- return KTAG_NONE;
- if (kxml_node_type(node) != KXML_NODE_ELM)
- return KTAG_NONE;
- name = kxml_node_name(node);
- if (!name)
- return KTAG_NONE;
- for (tag = KTAG_NONE; tag < KTAG_MAX; tag++) {
- if (faux_str_casecmp(name, kxml_tags[tag]))
- break;
- }
- kxml_node_name_free(name);
- if (tag >= KTAG_MAX)
- return KTAG_NONE;
- return tag;
- }
- static kxml_process_fn *kxml_node_handler(const kxml_node_t *node)
- {
- return kxml_handlers[kxml_node_tag(node)];
- }
- static bool_t process_node(const kxml_node_t *node, void *parent, faux_error_t *error)
- {
- kxml_process_fn *handler = kxml_node_handler(node);
- if (!handler)
- return BOOL_TRUE;
- return handler(node, parent, error);
- }
- static bool_t kxml_load_file(kscheme_t *scheme, const char *filename,
- faux_error_t *error)
- {
- kxml_doc_t *doc = NULL;
- kxml_node_t *root = NULL;
- bool_t r = BOOL_FALSE;
- if (!scheme)
- return BOOL_FALSE;
- if (!filename)
- return BOOL_FALSE;
- doc = kxml_doc_read(filename);
- if (!kxml_doc_is_valid(doc)) {
- kxml_doc_release(doc);
- return BOOL_FALSE;
- }
- root = kxml_doc_root(doc);
- r = process_node(root, scheme, error);
- kxml_doc_release(doc);
- if (!r) {
- faux_error_sprintf(error, TAG": Illegal file %s", filename);
- return BOOL_FALSE;
- }
- return BOOL_TRUE;
- }
- static const char *default_path = "/etc/klish;~/.klish";
- static const char *path_separators = ":;";
- kscheme_t *kxml_load_scheme(const char *xml_path, faux_error_t *error)
- {
- kscheme_t *scheme = NULL;
- const char *path = xml_path;
- char *realpath = NULL;
- char *fn = NULL;
- char *saveptr = NULL;
- bool_t ret = BOOL_TRUE;
-
- scheme = kscheme_new();
- if (!scheme)
- return NULL;
-
- if (!path)
- path = default_path;
- realpath = faux_expand_tilde(path);
-
- for (fn = strtok_r(realpath, path_separators, &saveptr);
- fn; fn = strtok_r(NULL, path_separators, &saveptr)) {
- DIR *dir = NULL;
- struct dirent *entry = NULL;
-
- if (faux_isfile(fn)) {
- if (!kxml_load_file(scheme, fn, error)) {
- ret = BOOL_FALSE;
- continue;
- }
- }
-
- dir = opendir(fn);
- if (!dir)
- continue;
- for (entry = readdir(dir); entry; entry = readdir(dir)) {
- const char *extension = strrchr(entry->d_name, '.');
- char *filename = NULL;
-
- if (!extension || strcmp(".xml", extension))
- continue;
- filename = faux_str_sprintf("%s/%s", fn, entry->d_name);
- if (!kxml_load_file(scheme, filename, error)) {
- ret = BOOL_FALSE;
- continue;
- }
- faux_str_free(filename);
- }
- closedir(dir);
- }
- faux_str_free(realpath);
- if (!ret) {
- kscheme_free(scheme);
- return NULL;
- }
- return scheme;
- }
- static bool_t process_children(const kxml_node_t *element, void *parent,
- faux_error_t *error)
- {
- const kxml_node_t *node = NULL;
- while ((node = kxml_node_next_child(element, node)) != NULL) {
- bool_t res = BOOL_FALSE;
- res = process_node(node, parent, error);
- if (!res)
- return res;
- }
- return BOOL_TRUE;
- }
- static bool_t process_klish(const kxml_node_t *element, void *parent,
- faux_error_t *error)
- {
- return process_children(element, parent, error);
- }
- static bool_t process_view(const kxml_node_t *element, void *parent,
- faux_error_t *error)
- {
- iview_t iview = {};
- kview_t *view = NULL;
- bool_t res = BOOL_FALSE;
- ktags_e parent_tag = kxml_node_tag(kxml_node_parent(element));
- iview.name = kxml_node_attr(element, "name");
- view = iview_load(&iview, error);
- if (!view)
- goto err;
- if (parent_tag != KTAG_KLISH) {
- faux_error_add(error, TAG": Only KLISH tag can contain VIEW tag");
- return BOOL_FALSE;
- }
- if (!kscheme_add_view((kscheme_t *)parent, view)) {
- faux_error_sprintf(error, TAG": Can't add VIEW \"%s\"",
- kview_name(view));
- kview_free(view);
- goto err;
- }
- if (!process_children(element, view, error))
- goto err;
- res = BOOL_TRUE;
- err:
- kxml_node_attr_free(iview.name);
- return res;
- }
- static bool_t process_ptype(const kxml_node_t *element, void *parent,
- faux_error_t *error)
- {
- iptype_t iptype = {};
- kptype_t *ptype = NULL;
- bool_t res = BOOL_FALSE;
- ktags_e parent_tag = kxml_node_tag(kxml_node_parent(element));
- iptype.name = kxml_node_attr(element, "name");
- iptype.help = kxml_node_attr(element, "help");
- ptype = iptype_load(&iptype, error);
- if (!ptype)
- goto err;
- if (parent_tag != KTAG_KLISH) {
- faux_error_add(error, TAG": Only KLISH tag can contain PTYPE tag");
- return BOOL_FALSE;
- }
- if (!kscheme_add_ptype((kscheme_t *)parent, ptype)) {
- faux_error_sprintf(error, TAG": Can't add PTYPE \"%s\"",
- kptype_name(ptype));
- kptype_free(ptype);
- goto err;
- }
- if (!process_children(element, ptype, error))
- goto err;
- res = BOOL_TRUE;
- err:
- kxml_node_attr_free(iptype.name);
- kxml_node_attr_free(iptype.help);
- return res;
- }
- static bool_t process_plugin(const kxml_node_t *element, void *parent,
- faux_error_t *error)
- {
- iplugin_t iplugin = {};
- kplugin_t *plugin = NULL;
- bool_t res = BOOL_FALSE;
- ktags_e parent_tag = kxml_node_tag(kxml_node_parent(element));
- iplugin.name = kxml_node_attr(element, "name");
- iplugin.id = kxml_node_attr(element, "id");
- iplugin.file = kxml_node_attr(element, "file");
- iplugin.global = kxml_node_attr(element, "global");
- iplugin.conf = kxml_node_content(element);
- plugin = iplugin_load(&iplugin, error);
- if (!plugin)
- goto err;
- if (parent_tag != KTAG_KLISH) {
- faux_error_add(error, TAG": Only KLISH tag can contain PLUGIN tag");
- return BOOL_FALSE;
- }
- if (!kscheme_add_plugin((kscheme_t *)parent, plugin)) {
- faux_error_sprintf(error, TAG": Can't add PLUGIN \"%s\"",
- kplugin_name(plugin));
- kplugin_free(plugin);
- goto err;
- }
- if (!process_children(element, plugin, error))
- goto err;
- res = BOOL_TRUE;
- err:
- kxml_node_attr_free(iplugin.name);
- kxml_node_attr_free(iplugin.id);
- kxml_node_attr_free(iplugin.file);
- kxml_node_attr_free(iplugin.global);
- kxml_node_content_free(iplugin.conf);
- return res;
- }
- static bool_t process_param(const kxml_node_t *element, void *parent,
- faux_error_t *error)
- {
- iparam_t iparam = {};
- kparam_t *param = NULL;
- bool_t res = BOOL_FALSE;
- ktags_e parent_tag = kxml_node_tag(kxml_node_parent(element));
- iparam.name = kxml_node_attr(element, "name");
- iparam.help = kxml_node_attr(element, "help");
- iparam.ptype = kxml_node_attr(element, "ptype");
- param = iparam_load(&iparam, error);
- if (!param)
- goto err;
- if (parent_tag != KTAG_COMMAND) {
- faux_error_add(error, TAG": Only COMMAND tag can contain PARAM tag");
- return BOOL_FALSE;
- }
- if (!kcommand_add_param((kcommand_t *)parent, param)) {
- faux_error_sprintf(error, TAG": Can't add PARAM \"%s\"",
- kparam_name(param));
- kparam_free(param);
- goto err;
- }
- if (!process_children(element, param, error))
- goto err;
- res = BOOL_TRUE;
- err:
- kxml_node_attr_free(iparam.name);
- kxml_node_attr_free(iparam.help);
- kxml_node_attr_free(iparam.ptype);
- return res;
- }
- static bool_t process_command(const kxml_node_t *element, void *parent,
- faux_error_t *error)
- {
- icommand_t icommand = {};
- kcommand_t *command = NULL;
- bool_t res = BOOL_FALSE;
- ktags_e parent_tag = kxml_node_tag(kxml_node_parent(element));
- icommand.name = kxml_node_attr(element, "name");
- icommand.help = kxml_node_attr(element, "help");
- command = icommand_load(&icommand, error);
- if (!command)
- goto err;
- if (parent_tag != KTAG_VIEW) {
- faux_error_add(error, TAG": Only VIEW tag can contain COMMAND tag");
- return BOOL_FALSE;
- }
- if (!kview_add_command((kview_t *)parent, command)) {
- faux_error_sprintf(error, TAG": Can't add COMMAND \"%s\"",
- kcommand_name(command));
- kcommand_free(command);
- goto err;
- }
- if (!process_children(element, command, error))
- goto err;
- res = BOOL_TRUE;
- err:
- kxml_node_attr_free(icommand.name);
- kxml_node_attr_free(icommand.help);
- return res;
- }
- static bool_t process_action(const kxml_node_t *element, void *parent,
- faux_error_t *error)
- {
- iaction_t iaction = {};
- kaction_t *action = NULL;
- bool_t res = BOOL_FALSE;
- ktags_e parent_tag = kxml_node_tag(kxml_node_parent(element));
- iaction.sym = kxml_node_attr(element, "sym");
- iaction.lock = kxml_node_attr(element, "lock");
- iaction.interrupt = kxml_node_attr(element, "interrupt");
- iaction.interactive = kxml_node_attr(element, "interactive");
- iaction.exec_on = kxml_node_attr(element, "exec_on");
- iaction.update_retcode = kxml_node_attr(element, "update_retcode");
- iaction.script = kxml_node_content(element);
- action = iaction_load(&iaction, error);
- if (!action)
- goto err;
- if (KTAG_COMMAND == parent_tag) {
- kcommand_t *command = (kcommand_t *)parent;
- if (!kcommand_add_action(command, action)) {
- faux_error_sprintf(error,
- TAG": Can't add ACTION #%d to COMMAND \"%s\"",
- kcommand_actions_len(command) + 1,
- kcommand_name(command));
- kaction_free(action);
- goto err;
- }
- } else if (KTAG_PTYPE == parent_tag) {
- kptype_t *ptype = (kptype_t *)parent;
- if (!kptype_add_action(ptype, action)) {
- faux_error_sprintf(error,
- TAG": Can't add ACTION #%d to PTYPE \"%s\"",
- kptype_actions_len(ptype) + 1,
- kptype_name(ptype));
- kaction_free(action);
- goto err;
- }
- } else {
- faux_error_add(error,
- TAG": Only COMMAND, PTYPE tags can contain ACTION tag");
- return BOOL_FALSE;
- }
- if (!process_children(element, action, error))
- goto err;
- res = BOOL_TRUE;
- err:
- kxml_node_attr_free(iaction.sym);
- kxml_node_attr_free(iaction.lock);
- kxml_node_attr_free(iaction.interrupt);
- kxml_node_attr_free(iaction.interactive);
- kxml_node_attr_free(iaction.exec_on);
- kxml_node_attr_free(iaction.update_retcode);
- kxml_node_content_free(iaction.script);
- return res;
- }
|