123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396 |
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <assert.h>
- #include <faux/str.h>
- #include <faux/list.h>
- #include <faux/conv.h>
- #include <klish/khelper.h>
- #include <klish/ientry.h>
- #include <klish/kentry.h>
- #define TAG "ENTRY"
- bool_t ientry_parse(const ientry_t *info, kentry_t *entry, faux_error_t *error)
- {
- bool_t retcode = BOOL_TRUE;
- if (!info)
- return BOOL_FALSE;
- if (!entry)
- return BOOL_FALSE;
- // Help
- if (!faux_str_is_empty(info->help)) {
- if (!kentry_set_help(entry, info->help)) {
- faux_error_add(error, TAG": Illegal 'help' attribute");
- retcode = BOOL_FALSE;
- }
- }
- // Container
- if (!faux_str_is_empty(info->container)) {
- bool_t b = BOOL_FALSE;
- if (!faux_conv_str2bool(info->container, &b) ||
- !kentry_set_container(entry, b)) {
- faux_error_add(error, TAG": Illegal 'container' attribute");
- retcode = BOOL_FALSE;
- }
- }
- // Mode
- if (!faux_str_is_empty(info->mode)) {
- kentry_mode_e mode = KENTRY_MODE_NONE;
- if (!faux_str_casecmp(info->mode, "sequence"))
- mode = KENTRY_MODE_SEQUENCE;
- else if (!faux_str_casecmp(info->mode, "switch"))
- mode = KENTRY_MODE_SWITCH;
- else if (!faux_str_casecmp(info->mode, "empty"))
- mode = KENTRY_MODE_EMPTY;
- if ((KENTRY_MODE_NONE == mode) || !kentry_set_mode(entry, mode)) {
- faux_error_add(error, TAG": Illegal 'mode' attribute");
- retcode = BOOL_FALSE;
- }
- }
- // Purpose
- if (!faux_str_is_empty(info->purpose)) {
- kentry_purpose_e purpose = KENTRY_PURPOSE_NONE;
- if (!faux_str_casecmp(info->purpose, "common"))
- purpose = KENTRY_PURPOSE_COMMON;
- else if (!faux_str_casecmp(info->purpose, "ptype"))
- purpose = KENTRY_PURPOSE_PTYPE;
- else if (!faux_str_casecmp(info->purpose, "prompt"))
- purpose = KENTRY_PURPOSE_PROMPT;
- else if (!faux_str_casecmp(info->purpose, "cond"))
- purpose = KENTRY_PURPOSE_COND;
- else if (!faux_str_casecmp(info->purpose, "completion"))
- purpose = KENTRY_PURPOSE_COMPLETION;
- if ((KENTRY_PURPOSE_NONE == purpose) || !kentry_set_purpose(entry, purpose)) {
- faux_error_add(error, TAG": Illegal 'purpose' attribute");
- retcode = BOOL_FALSE;
- }
- }
- // Min occurs
- if (!faux_str_is_empty(info->min)) {
- unsigned int i = 0;
- if (!faux_conv_atoui(info->min, &i, 0) ||
- !kentry_set_min(entry, (size_t)i)) {
- faux_error_add(error, TAG": Illegal 'min' attribute");
- retcode = BOOL_FALSE;
- }
- }
- // Max occurs
- if (!faux_str_is_empty(info->max)) {
- unsigned int i = 0;
- if (!faux_conv_atoui(info->max, &i, 0) ||
- !kentry_set_max(entry, (size_t)i)) {
- faux_error_add(error, TAG": Illegal 'max' attribute");
- retcode = BOOL_FALSE;
- }
- }
- // Ref string
- if (!faux_str_is_empty(info->ref)) {
- if (!kentry_set_ref_str(entry, info->ref)) {
- faux_error_add(error, TAG": Illegal 'ref' attribute");
- retcode = BOOL_FALSE;
- }
- }
- // Value
- if (!faux_str_is_empty(info->value)) {
- if (!kentry_set_value(entry, info->value)) {
- faux_error_add(error, TAG": Illegal 'value' attribute");
- retcode = BOOL_FALSE;
- }
- }
- // Restore
- if (!faux_str_is_empty(info->restore)) {
- bool_t b = BOOL_FALSE;
- if (!faux_conv_str2bool(info->restore, &b) ||
- !kentry_set_restore(entry, b)) {
- faux_error_add(error, TAG": Illegal 'restore' attribute");
- retcode = BOOL_FALSE;
- }
- }
- // Order
- if (!faux_str_is_empty(info->order)) {
- bool_t b = BOOL_FALSE;
- if (!faux_conv_str2bool(info->order, &b) ||
- !kentry_set_order(entry, b)) {
- faux_error_add(error, TAG": Illegal 'order' attribute");
- retcode = BOOL_FALSE;
- }
- }
- // Filter
- if (!faux_str_is_empty(info->filter)) {
- bool_t b = BOOL_FALSE;
- if (!faux_conv_str2bool(info->filter, &b) ||
- !kentry_set_filter(entry, b)) {
- faux_error_add(error, TAG": Illegal 'filter' attribute");
- retcode = BOOL_FALSE;
- }
- }
- return retcode;
- }
- bool_t ientry_parse_nested(const ientry_t *ientry, kentry_t *kentry,
- faux_error_t *error)
- {
- bool_t retval = BOOL_TRUE;
- if (!kentry || !ientry) {
- faux_error_add(error, TAG": Internal error");
- return BOOL_FALSE;
- }
- // ENTRY list
- // ENTRYs can be duplicate. Duplicated ENTRY will add nested
- // elements to existent ENTRY. Also it can overwrite ENTRY attributes.
- // So there is no special rule which attribute value will be "on top".
- // It's a random. Technically later ENTRYs will rewrite previous
- // values.
- if (ientry->entrys) {
- ientry_t **p_ientry = NULL;
- for (p_ientry = *ientry->entrys; *p_ientry; p_ientry++) {
- kentry_t *nkentry = NULL;
- ientry_t *nientry = *p_ientry;
- const char *entry_name = nientry->name;
- if (entry_name)
- nkentry = kentry_find_entry(kentry, entry_name);
- // ENTRY already exists
- if (nkentry) {
- if (!ientry_parse(nientry, nkentry, error)) {
- retval = BOOL_FALSE;
- continue;
- }
- if (!ientry_parse_nested(nientry, nkentry,
- error)) {
- retval = BOOL_FALSE;
- continue;
- }
- continue;
- }
- // New ENTRY
- nkentry = ientry_load(nientry, error);
- if (!nkentry) {
- retval = BOOL_FALSE;
- continue;
- }
- kentry_set_parent(nkentry, kentry); // Set parent entry
- if (!kentry_add_entrys(kentry, nkentry)) {
- faux_error_sprintf(error,
- TAG": Can't add ENTRY \"%s\"",
- kentry_name(nkentry));
- kentry_free(nkentry);
- retval = BOOL_FALSE;
- continue;
- }
- }
- }
- // ACTION list
- if (ientry->actions) {
- iaction_t **p_iaction = NULL;
- for (p_iaction = *ientry->actions; *p_iaction; p_iaction++) {
- kaction_t *kaction = NULL;
- iaction_t *iaction = *p_iaction;
- kaction = iaction_load(iaction, error);
- if (!kaction) {
- retval = BOOL_FALSE;
- continue;
- }
- if (!kentry_add_actions(kentry, kaction)) {
- faux_error_sprintf(error,
- TAG": Can't add ACTION #%d",
- kentry_actions_len(kentry) + 1);
- kaction_free(kaction);
- retval = BOOL_FALSE;
- continue;
- }
- }
- }
- if (!retval)
- faux_error_sprintf(error, TAG" \"%s\": Illegal nested elements",
- kentry_name(kentry));
- return retval;
- }
- kentry_t *ientry_load(const ientry_t *ientry, faux_error_t *error)
- {
- kentry_t *kentry = NULL;
- if (!ientry)
- return NULL;
- // Name [mandatory]
- if (faux_str_is_empty(ientry->name)) {
- faux_error_add(error, TAG": Empty 'name' attribute");
- return NULL;
- }
- kentry = kentry_new(ientry->name);
- if (!kentry) {
- faux_error_sprintf(error, TAG" \"%s\": Can't create object",
- ientry->name);
- return NULL;
- }
- if (!ientry_parse(ientry, kentry, error)) {
- kentry_free(kentry);
- return NULL;
- }
- // Parse nested elements
- if (!ientry_parse_nested(ientry, kentry, error)) {
- kentry_free(kentry);
- return NULL;
- }
- return kentry;
- }
- char *ientry_deploy(const kentry_t *kentry, int level)
- {
- char *str = NULL;
- char *tmp = NULL;
- char *mode = NULL;
- char *purpose = NULL;
- kentry_entrys_node_t *entrys_iter = NULL;
- kentry_actions_node_t *actions_iter = NULL;
- char *num = NULL;
- tmp = faux_str_sprintf("%*cENTRY {\n", level, ' ');
- faux_str_cat(&str, tmp);
- faux_str_free(tmp);
- attr2ctext(&str, "name", kentry_name(kentry), level + 1);
- attr2ctext(&str, "help", kentry_help(kentry), level + 1);
- attr2ctext(&str, "ref", kentry_ref_str(kentry), level + 1);
- // Links (ENTRY with 'ref' attribute) doesn't need the following filds
- // that will be replaced by content of referenced ENTRY
- if (faux_str_is_empty(kentry_ref_str(kentry))) {
- attr2ctext(&str, "container", faux_conv_bool2str(kentry_container(kentry)), level + 1);
- // Mode
- switch (kentry_mode(kentry)) {
- case KENTRY_MODE_SEQUENCE:
- mode = "sequence";
- break;
- case KENTRY_MODE_SWITCH:
- mode = "switch";
- break;
- case KENTRY_MODE_EMPTY:
- mode = "empty";
- break;
- default:
- mode = NULL;
- }
- attr2ctext(&str, "mode", mode, level + 1);
- // Purpose
- switch (kentry_purpose(kentry)) {
- case KENTRY_PURPOSE_COMMON:
- purpose = "common";
- break;
- case KENTRY_PURPOSE_PTYPE:
- purpose = "ptype";
- break;
- case KENTRY_PURPOSE_PROMPT:
- purpose = "prompt";
- break;
- case KENTRY_PURPOSE_COND:
- purpose = "cond";
- break;
- case KENTRY_PURPOSE_COMPLETION:
- purpose = "completion";
- break;
- default:
- purpose = NULL;
- }
- attr2ctext(&str, "purpose", purpose, level + 1);
- // Min occurs
- num = faux_str_sprintf("%u", kentry_min(kentry));
- attr2ctext(&str, "min", num, level + 1);
- faux_str_free(num);
- num = NULL;
- // Max occurs
- num = faux_str_sprintf("%u", kentry_max(kentry));
- attr2ctext(&str, "max", num, level + 1);
- faux_str_free(num);
- num = NULL;
- attr2ctext(&str, "value", kentry_value(kentry), level + 1);
- attr2ctext(&str, "restore", faux_conv_bool2str(kentry_restore(kentry)), level + 1);
- attr2ctext(&str, "order", faux_conv_bool2str(kentry_order(kentry)), level + 1);
- attr2ctext(&str, "filter", faux_conv_bool2str(kentry_filter(kentry)), level + 1);
- // ENTRY list
- entrys_iter = kentry_entrys_iter(kentry);
- if (entrys_iter) {
- kentry_t *nentry = NULL;
- tmp = faux_str_sprintf("\n%*cENTRY_LIST\n\n", level + 1, ' ');
- faux_str_cat(&str, tmp);
- faux_str_free(tmp);
- while ((nentry = kentry_entrys_each(&entrys_iter))) {
- tmp = ientry_deploy(nentry, level + 2);
- faux_str_cat(&str, tmp);
- faux_str_free(tmp);
- }
- tmp = faux_str_sprintf("%*cEND_ENTRY_LIST,\n", level + 1, ' ');
- faux_str_cat(&str, tmp);
- faux_str_free(tmp);
- }
- // ACTION list
- actions_iter = kentry_actions_iter(kentry);
- if (actions_iter) {
- kaction_t *action = NULL;
- tmp = faux_str_sprintf("\n%*cACTION_LIST\n\n", level + 1, ' ');
- faux_str_cat(&str, tmp);
- faux_str_free(tmp);
- while ((action = kentry_actions_each(&actions_iter))) {
- tmp = iaction_deploy(action, level + 2);
- faux_str_cat(&str, tmp);
- faux_str_free(tmp);
- }
- tmp = faux_str_sprintf("%*cEND_ACTION_LIST,\n", level + 1, ' ');
- faux_str_cat(&str, tmp);
- faux_str_free(tmp);
- }
- } // ref_str
- tmp = faux_str_sprintf("%*c},\n\n", level, ' ');
- faux_str_cat(&str, tmp);
- faux_str_free(tmp);
- return str;
- }
|