123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905 |
- /** @file load.c
- * @brief Common part for XML parsing.
- *
- * Different XML parsing engines can provide a functions in a form of
- * standardized API. This code uses this API and parses XML to kscheme.
- */
- #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,
- process_entry;
- // Different TAGs types
- typedef enum {
- KTAG_NONE,
- KTAG_ACTION,
- KTAG_PARAM,
- KTAG_SWITCH, // PARAM alias
- KTAG_SEQ, // PARAM alias
- KTAG_COMMAND,
- KTAG_FILTER,
- KTAG_VIEW,
- KTAG_PTYPE,
- KTAG_PLUGIN,
- KTAG_KLISH,
- KTAG_ENTRY,
- KTAG_COND,
- KTAG_COMPL,
- KTAG_HELP,
- KTAG_PROMPT,
- KTAG_MAX,
- } ktags_e;
- static const char * const kxml_tags[] = {
- NULL,
- "ACTION",
- "PARAM",
- "SWITCH",
- "SEQ",
- "COMMAND",
- "FILTER",
- "VIEW",
- "PTYPE",
- "PLUGIN",
- "KLISH",
- "ENTRY",
- "COND",
- "COMPL",
- "HELP",
- "PROMPT",
- };
- static kxml_process_fn *kxml_handlers[] = {
- NULL,
- process_action,
- process_param,
- process_param,
- process_param,
- process_command,
- process_command,
- process_view,
- process_ptype,
- process_plugin,
- process_klish,
- process_entry,
- process_command,
- process_command,
- process_command,
- process_command,
- };
- static const char *kxml_tag_name(ktags_e tag)
- {
- if ((KTAG_NONE == tag) || (tag >= KTAG_MAX))
- return "NONE";
- return kxml_tags[tag];
- }
- 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; // Strange case
- for (tag = (KTAG_NONE + 1); tag < KTAG_MAX; tag++) {
- if (faux_str_casecmp(name, kxml_tags[tag]) == 0)
- 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)];
- }
- /** @brief Reads an element from the XML stream and processes it.
- */
- static bool_t process_node(const kxml_node_t *node, void *parent, faux_error_t *error)
- {
- kxml_process_fn *handler = NULL;
- // Process only KXML_NODE_ELM. Don't process other types like:
- // KXML_NODE_DOC,
- // KXML_NODE_TEXT,
- // KXML_NODE_ATTR,
- // KXML_NODE_COMMENT,
- // KXML_NODE_PI,
- // KXML_NODE_DECL,
- // KXML_NODE_UNKNOWN,
- if (kxml_node_type(node) != KXML_NODE_ELM)
- return BOOL_TRUE;
- handler = kxml_node_handler(node);
- if (!handler) { // Unknown element
- faux_error_sprintf(error,
- TAG": Unknown tag \"%s\"", kxml_node_name(node));
- return BOOL_FALSE;
- }
- #ifdef KXML_DEBUG
- printf("kxml: Tag \"%s\"\n", kxml_node_name(node));
- #endif
- 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;
- #ifdef KXML_DEBUG
- printf("kxml: Processing XML file \"%s\"\n", filename);
- #endif
- doc = kxml_doc_read(filename);
- if (!kxml_doc_is_valid(doc)) {
- /* int errcaps = kxml_doc_error_caps(doc);
- printf("Unable to open file '%s'", filename);
- if ((errcaps & kxml_ERR_LINE) == kxml_ERR_LINE)
- printf(", at line %d", kxml_doc_err_line(doc));
- if ((errcaps & kxml_ERR_COL) == kxml_ERR_COL)
- printf(", at column %d", kxml_doc_err_col(doc));
- if ((errcaps & kxml_ERR_DESC) == kxml_ERR_DESC)
- printf(", message is %s", kxml_doc_err_msg(doc));
- printf("\n");
- */ 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;
- }
- /** @brief Default path to get XML files from.
- */
- static const char *default_path = "/etc/klish;~/.klish";
- static const char *path_separators = ":;";
- bool_t kxml_load_scheme(kscheme_t *scheme, const char *xml_path,
- faux_error_t *error)
- {
- char *path = NULL;
- char *fn = NULL;
- char *saveptr = NULL;
- bool_t ret = BOOL_TRUE;
- assert(scheme);
- if (!scheme)
- return BOOL_FALSE;
- // Use the default path if xml path is not specified.
- // Dup is needed because sring will be tokenized but
- // the xml_path is must be const.
- if (!xml_path)
- path = faux_str_dup(default_path);
- else
- path = faux_str_dup(xml_path);
- #ifdef KXML_DEBUG
- printf("kxml: Loading scheme \"%s\"\n", path);
- #endif
- // Loop through each directory
- for (fn = strtok_r(path, path_separators, &saveptr);
- fn; fn = strtok_r(NULL, path_separators, &saveptr)) {
- DIR *dir = NULL;
- struct dirent *entry = NULL;
- char *realpath = NULL;
- // Expand tilde. Tilde must be the first symbol.
- realpath = faux_expand_tilde(fn);
- // Regular file
- if (faux_isfile(realpath)) {
- if (!kxml_load_file(scheme, realpath, error))
- ret = BOOL_FALSE;
- faux_str_free(realpath);
- continue;
- }
- // Search this directory for any XML files
- #ifdef KXML_DEBUG
- printf("kxml: Processing XML dir \"%s\"\n", realpath);
- #endif
- dir = opendir(realpath);
- if (!dir) {
- faux_str_free(realpath);
- continue;
- }
- for (entry = readdir(dir); entry; entry = readdir(dir)) {
- const char *extension = strrchr(entry->d_name, '.');
- char *filename = NULL;
- // Check the filename
- if (!extension || strcmp(".xml", extension))
- continue;
- filename = faux_str_sprintf("%s/%s", realpath, entry->d_name);
- if (!kxml_load_file(scheme, filename, error))
- ret = BOOL_FALSE;
- faux_str_free(filename);
- }
- closedir(dir);
- faux_str_free(realpath);
- }
- faux_str_free(path);
- return ret;
- }
- /** @brief Iterate through element's children.
- */
- 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_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));
- if (parent_tag != KTAG_KLISH) {
- faux_error_sprintf(error,
- TAG": Tag \"%s\" can't contain PLUGIN tag",
- kxml_tag_name(parent_tag));
- return BOOL_FALSE;
- }
- iplugin.name = kxml_node_attr(element, "name");
- iplugin.id = kxml_node_attr(element, "id");
- iplugin.file = kxml_node_attr(element, "file");
- iplugin.conf = kxml_node_content(element);
- plugin = iplugin_load(&iplugin, error);
- if (!plugin)
- goto err;
- if (!kscheme_add_plugins((kscheme_t *)parent, plugin)) {
- faux_error_sprintf(error, TAG": Can't add PLUGIN \"%s\". "
- "Probably duplication",
- 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_content_free(iplugin.conf);
- 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));
- kentry_t *parent_entry = (kentry_t *)parent;
- 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.permanent = kxml_node_attr(element, "permanent");
- iaction.sync = kxml_node_attr(element, "sync");
- iaction.script = kxml_node_content(element);
- action = iaction_load(&iaction, error);
- if (!action)
- goto err;
- if ( (KTAG_ENTRY != parent_tag) &&
- (KTAG_COMMAND != parent_tag) &&
- (KTAG_FILTER != parent_tag) &&
- (KTAG_COND != parent_tag) &&
- (KTAG_COMPL != parent_tag) &&
- (KTAG_HELP != parent_tag) &&
- (KTAG_PROMPT != parent_tag) &&
- (KTAG_PTYPE != parent_tag)) {
- faux_error_sprintf(error,
- TAG": Tag \"%s\" can't contain ACTION tag",
- kxml_tag_name(parent_tag));
- kaction_free(action);
- goto err;
- }
- if (!kentry_add_actions(parent_entry, action)) {
- faux_error_sprintf(error,
- TAG": Can't add ACTION #%d to ENTRY \"%s\". "
- "Probably duplication",
- kentry_actions_len(parent_entry) + 1,
- kentry_name(parent_entry));
- kaction_free(action);
- goto err;
- }
- 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_attr_free(iaction.permanent);
- kxml_node_attr_free(iaction.sync);
- kxml_node_content_free(iaction.script);
- return res;
- }
- static kentry_t *add_entry_to_hierarchy(const kxml_node_t *element, void *parent,
- ientry_t *ientry, faux_error_t *error)
- {
- kentry_t *entry = NULL;
- ktags_e tag = kxml_node_tag(element);
- ktags_e parent_tag = kxml_node_tag(kxml_node_parent(element));
- assert(ientry);
- // Parent is mandatory field
- if (!parent) {
- faux_error_sprintf(error,
- TAG": Broken parent object for entry \"%s\"",
- ientry->name);
- return NULL;
- }
- if ((parent_tag == KTAG_ACTION) ||
- // (parent_tag == KTAG_HOTKEY) ||
- (parent_tag == KTAG_PLUGIN)) {
- faux_error_sprintf(error,
- TAG": Tag \"%s\" can't contain %s tag \"%s\"",
- kxml_tag_name(parent_tag),
- kxml_tag_name(tag), ientry->name);
- return NULL;
- }
- // High level ENTRY
- if (KTAG_KLISH == parent_tag) {
- kscheme_t *scheme = (kscheme_t *)parent;
- // Does such ENTRY already exist
- entry = kscheme_find_entry(scheme, ientry->name);
- if (entry) {
- if (!ientry_parse(ientry, entry, error))
- return NULL;
- } else { // New entry object
- entry = ientry_load(ientry, error);
- if (!entry)
- return NULL;
- if (!kscheme_add_entrys(scheme, entry)) {
- faux_error_sprintf(error, TAG": Can't add entry \"%s\". "
- "Probably duplication",
- kentry_name(entry));
- kentry_free(entry);
- return NULL;
- }
- }
- // ENTRY within ENTRY
- } else {
- kentry_t *parent_entry = (kentry_t *)parent;
- // Does such ENTRY already exist
- entry = kentry_find_entry(parent_entry, ientry->name);
- if (entry) {
- if (!ientry_parse(ientry, entry, error))
- return NULL;
- } else { // New entry object
- entry = ientry_load(ientry, error);
- if (!entry)
- return NULL;
- kentry_set_parent(entry, parent_entry);
- if (!kentry_add_entrys(parent_entry, entry)) {
- faux_error_sprintf(error, TAG": Can't add entry \"%s\". "
- "Probably duplication",
- kentry_name(entry));
- kentry_free(entry);
- return NULL;
- }
- }
- }
- return entry;
- }
- static bool_t process_entry(const kxml_node_t *element, void *parent,
- faux_error_t *error)
- {
- ientry_t ientry = {};
- kentry_t *entry = NULL;
- bool_t res = BOOL_FALSE;
- // Mandatory entry name
- ientry.name = kxml_node_attr(element, "name");
- if (!ientry.name) {
- faux_error_sprintf(error, TAG": entry without name");
- return BOOL_FALSE;
- }
- ientry.help = kxml_node_attr(element, "help");
- ientry.container = kxml_node_attr(element, "container");
- ientry.mode = kxml_node_attr(element, "mode");
- ientry.purpose = kxml_node_attr(element, "purpose");
- ientry.min = kxml_node_attr(element, "min");
- ientry.max = kxml_node_attr(element, "max");
- ientry.ref = kxml_node_attr(element, "ref");
- ientry.value = kxml_node_attr(element, "value");
- ientry.restore = kxml_node_attr(element, "restore");
- ientry.order = kxml_node_attr(element, "order");
- ientry.filter = kxml_node_attr(element, "filter");
- if (!(entry = add_entry_to_hierarchy(element, parent, &ientry, error)))
- goto err;
- if (!process_children(element, entry, error))
- goto err;
- res = BOOL_TRUE;
- err:
- kxml_node_attr_free(ientry.name);
- kxml_node_attr_free(ientry.help);
- kxml_node_attr_free(ientry.container);
- kxml_node_attr_free(ientry.mode);
- kxml_node_attr_free(ientry.purpose);
- kxml_node_attr_free(ientry.min);
- kxml_node_attr_free(ientry.max);
- kxml_node_attr_free(ientry.ref);
- kxml_node_attr_free(ientry.value);
- kxml_node_attr_free(ientry.restore);
- kxml_node_attr_free(ientry.order);
- kxml_node_attr_free(ientry.filter);
- return res;
- }
- static bool_t process_view(const kxml_node_t *element, void *parent,
- faux_error_t *error)
- {
- ientry_t ientry = {};
- kentry_t *entry = NULL;
- bool_t res = BOOL_FALSE;
- // Mandatory VIEW name
- ientry.name = kxml_node_attr(element, "name");
- if (!ientry.name) {
- faux_error_sprintf(error, TAG": VIEW without name");
- return BOOL_FALSE;
- }
- ientry.help = kxml_node_attr(element, "help");
- ientry.container = "true";
- ientry.mode = "switch";
- ientry.purpose = "common";
- ientry.min = "1";
- ientry.max = "1";
- ientry.ref = kxml_node_attr(element, "ref");
- ientry.value = NULL;
- ientry.restore = "false";
- ientry.order = "false";
- ientry.filter = "false";
- if (!(entry = add_entry_to_hierarchy(element, parent, &ientry, error)))
- goto err;
- if (!process_children(element, entry, error))
- goto err;
- res = BOOL_TRUE;
- err:
- kxml_node_attr_free(ientry.name);
- kxml_node_attr_free(ientry.help);
- kxml_node_attr_free(ientry.ref);
- return res;
- }
- static bool_t process_ptype(const kxml_node_t *element, void *parent,
- faux_error_t *error)
- {
- ientry_t ientry = {};
- kentry_t *entry = NULL;
- bool_t res = BOOL_FALSE;
- bool_t is_name = BOOL_FALSE;
- // Mandatory PTYPE name or reference
- ientry.name = kxml_node_attr(element, "name");
- ientry.ref = kxml_node_attr(element, "ref");
- if (ientry.name) {
- is_name = BOOL_TRUE;
- } else {
- if (!ientry.ref) {
- faux_error_sprintf(error,
- TAG": PTYPE without name or reference");
- return BOOL_FALSE;
- }
- ientry.name = "__ptype";
- }
- ientry.help = kxml_node_attr(element, "help");
- ientry.container = "true";
- ientry.mode = "sequence";
- ientry.purpose = "ptype";
- ientry.min = "1";
- ientry.max = "1";
- ientry.value = kxml_node_attr(element, "value");
- ientry.restore = "false";
- ientry.order = "true";
- ientry.filter = "false";
- if (!(entry = add_entry_to_hierarchy(element, parent, &ientry, error)))
- goto err;
- if (!process_children(element, entry, error))
- goto err;
- res = BOOL_TRUE;
- err:
- if (is_name)
- kxml_node_attr_free(ientry.name);
- kxml_node_attr_free(ientry.help);
- kxml_node_attr_free(ientry.ref);
- kxml_node_attr_free(ientry.value);
- return res;
- }
- static kentry_t *create_ptype(const char *ptype,
- const char *compl, const char *help, const char *ref)
- {
- kentry_t *ptype_entry = NULL;
- if (!ptype && !ref)
- return NULL;
- ptype_entry = kentry_new("__ptype");
- assert(ptype_entry);
- kentry_set_purpose(ptype_entry, KENTRY_PURPOSE_PTYPE);
- if (ref) {
- kentry_set_ref_str(ptype_entry, ref);
- // If ptype is reference then another actions is not needed.
- return ptype_entry;
- } else {
- kaction_t *ptype_action = kaction_new();
- assert(ptype_action);
- kaction_set_sym_ref(ptype_action, ptype);
- kaction_set_permanent(ptype_action, TRI_TRUE);
- kentry_add_actions(ptype_entry, ptype_action);
- }
- if (compl) {
- kentry_t *compl_entry = NULL;
- kaction_t *compl_action = NULL;
- compl_action = kaction_new();
- assert(compl_action);
- kaction_set_sym_ref(compl_action, compl);
- kaction_set_permanent(compl_action, TRI_TRUE);
- compl_entry = kentry_new("__compl");
- assert(compl_entry);
- kentry_set_purpose(compl_entry, KENTRY_PURPOSE_COMPLETION);
- kentry_add_actions(compl_entry, compl_action);
- kentry_add_entrys(ptype_entry, compl_entry);
- }
- if (help) {
- kentry_t *help_entry = NULL;
- kaction_t *help_action = NULL;
- help_action = kaction_new();
- assert(help_action);
- kaction_set_sym_ref(help_action, help);
- kaction_set_permanent(help_action, TRI_TRUE);
- help_entry = kentry_new("__help");
- assert(help_entry);
- kentry_set_purpose(help_entry, KENTRY_PURPOSE_HELP);
- kentry_add_actions(help_entry, help_action);
- kentry_add_entrys(ptype_entry, help_entry);
- }
- return ptype_entry;
- }
- // PARAM, SWITCH, SEQ
- static bool_t process_param(const kxml_node_t *element, void *parent,
- faux_error_t *error)
- {
- ientry_t ientry = {};
- kentry_t *entry = NULL;
- bool_t res = BOOL_FALSE;
- ktags_e tag = kxml_node_tag(element);
- bool_t is_mode = BOOL_FALSE;
- char *ptype_str = NULL;
- // Mandatory PARAM name
- ientry.name = kxml_node_attr(element, "name");
- if (!ientry.name) {
- faux_error_sprintf(error, TAG": PARAM without name");
- return BOOL_FALSE;
- }
- ientry.help = kxml_node_attr(element, "help");
- // Container
- if (KTAG_PARAM == tag)
- ientry.container = "false";
- else
- ientry.container = "true"; // SWITCH, SEQ
- // Mode
- switch (tag) {
- case KTAG_PARAM:
- ientry.mode = kxml_node_attr(element, "mode");
- is_mode = BOOL_TRUE;
- break;
- case KTAG_SWITCH:
- ientry.mode = "switch";
- break;
- case KTAG_SEQ:
- ientry.mode = "sequence";
- break;
- default:
- ientry.mode = "empty";
- break;
- }
- ientry.purpose = "common";
- ientry.min = kxml_node_attr(element, "min");
- ientry.max = kxml_node_attr(element, "max");
- ientry.ref = kxml_node_attr(element, "ref");
- ientry.value = kxml_node_attr(element, "value");
- ientry.restore = "false";
- ientry.order = kxml_node_attr(element, "order");
- ientry.filter = "false";
- if (!(entry = add_entry_to_hierarchy(element, parent, &ientry, error)))
- goto err;
- // Special attribute "ptype". It exists for more simple XML only. It
- // just links existing PTYPE. User can to don't specify nested tag PTYPE.
- ptype_str = kxml_node_attr(element, "ptype");
- if (ptype_str) {
- kentry_t *ptype_entry = create_ptype(NULL, NULL, NULL, ptype_str);
- assert(ptype_entry);
- kentry_add_entrys(entry, ptype_entry);
- }
- if (!process_children(element, entry, error))
- goto err;
- res = BOOL_TRUE;
- err:
- kxml_node_attr_free(ientry.name);
- kxml_node_attr_free(ientry.help);
- if (is_mode)
- kxml_node_attr_free(ientry.mode);
- kxml_node_attr_free(ientry.min);
- kxml_node_attr_free(ientry.max);
- kxml_node_attr_free(ientry.ref);
- kxml_node_attr_free(ientry.value);
- kxml_node_attr_free(ientry.order);
- kxml_node_attr_free(ptype_str);
- return res;
- }
- // COMMAND, FILTER, COND, COMPL, HELP, PROMPT
- static bool_t process_command(const kxml_node_t *element, void *parent,
- faux_error_t *error)
- {
- ientry_t ientry = {};
- kentry_t *entry = NULL;
- bool_t res = BOOL_FALSE;
- ktags_e tag = kxml_node_tag(element);
- bool_t is_name = BOOL_FALSE;
- kentry_entrys_node_t *iter = NULL;
- kentry_t *nested_entry = NULL;
- bool_t ptype_exists = BOOL_FALSE;
- // Mandatory COMMAND name
- ientry.name = kxml_node_attr(element, "name");
- if (ientry.name) {
- is_name = BOOL_TRUE;
- } else {
- switch (tag) {
- case KTAG_COMMAND:
- case KTAG_FILTER:
- faux_error_sprintf(error, TAG": COMMAND without name");
- return BOOL_FALSE;
- case KTAG_COND:
- ientry.name = "__cond";
- break;
- case KTAG_COMPL:
- ientry.name = "__compl";
- break;
- case KTAG_HELP:
- ientry.name = "__help";
- break;
- case KTAG_PROMPT:
- ientry.name = "__prompt";
- break;
- default:
- faux_error_sprintf(error, TAG": Unknown tag");
- return BOOL_FALSE;
- }
- }
- ientry.help = kxml_node_attr(element, "help");
- ientry.container = "false";
- ientry.mode = kxml_node_attr(element, "mode");
- // Purpose
- switch (tag) {
- case KTAG_COND:
- ientry.purpose = "cond";
- break;
- case KTAG_COMPL:
- ientry.purpose = "completion";
- break;
- case KTAG_HELP:
- ientry.purpose = "help";
- break;
- case KTAG_PROMPT:
- ientry.purpose = "prompt";
- break;
- default:
- ientry.purpose = "common";
- break;
- }
- ientry.min = "1";
- ientry.max = "1";
- ientry.ref = kxml_node_attr(element, "ref");
- if ((KTAG_FILTER == tag) || (KTAG_COMMAND == tag)) {
- ientry.value = kxml_node_attr(element, "value");
- ientry.restore = kxml_node_attr(element, "restore");
- } else {
- ientry.value = NULL;
- ientry.restore = "false";
- }
- ientry.order = "false";
- // Filter
- if (KTAG_FILTER == tag)
- ientry.filter = "true";
- else
- ientry.filter = "false";
- if (!(entry = add_entry_to_hierarchy(element, parent, &ientry, error)))
- goto err;
- if (!process_children(element, entry, error))
- goto err;
- // Add special PTYPE for command. It uses symbol from internal klish
- // plugin.
- // Iterate child entries to find out is there PTYPE entry already. We
- // can't use kentry_nested_by_purpose() because it's not calculated yet.
- iter = kentry_entrys_iter(entry);
- while ((nested_entry = kentry_entrys_each(&iter))) {
- if (kentry_purpose(nested_entry) == KENTRY_PURPOSE_PTYPE) {
- ptype_exists = BOOL_TRUE;
- break;
- }
- }
- if (!ptype_exists) {
- kentry_t *ptype_entry = create_ptype(
- "COMMAND@klish",
- "completion_COMMAND@klish",
- "help_COMMAND@klish",
- NULL);
- assert(ptype_entry);
- kentry_add_entrys(entry, ptype_entry);
- }
- res = BOOL_TRUE;
- err:
- if (is_name)
- kxml_node_attr_free(ientry.name);
- kxml_node_attr_free(ientry.help);
- kxml_node_attr_free(ientry.mode);
- kxml_node_attr_free(ientry.ref);
- if ((KTAG_FILTER == tag) || (KTAG_COMMAND == tag)) {
- kxml_node_attr_free(ientry.value);
- kxml_node_attr_free(ientry.restore);
- }
- return res;
- }
|