ksession_parse.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. /** @file ksession_parse.c
  2. */
  3. #include <assert.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <faux/argv.h>
  8. #include <klish/khelper.h>
  9. #include <klish/kview.h>
  10. #include <klish/kscheme.h>
  11. #include <klish/kpath.h>
  12. #include <klish/kpargv.h>
  13. #include <klish/ksession.h>
  14. typedef enum {
  15. KPARSE_NONE,
  16. KPARSE_OK,
  17. KPARSE_INPROGRESS,
  18. KPARSE_NOTFOUND,
  19. KPARSE_INCOMPLETED,
  20. KPARSE_ILLEGAL,
  21. KPARSE_ERROR,
  22. } kparse_status_e;
  23. static bool_t ksession_validate_arg(kentry_t *entry, const char *arg)
  24. {
  25. const char *str = NULL;
  26. assert(entry);
  27. if (!entry)
  28. return BOOL_FALSE;
  29. assert(arg);
  30. if (!arg)
  31. return BOOL_FALSE;
  32. // Temporary test code that implements COMMAND i.e. it compares argument
  33. // to ENTRY's 'name' or 'value'. Later it will be removed by real code.
  34. str = kentry_value(entry);
  35. if (!str)
  36. str = kentry_name(entry);
  37. if (faux_str_casecmp(str, arg) == 0)
  38. return BOOL_TRUE;
  39. return BOOL_FALSE;
  40. }
  41. static kparse_status_e ksession_parse_arg(kentry_t *current_entry,
  42. faux_argv_node_t **argv_iter, kpargv_t *pargv)
  43. {
  44. kentry_t *entry = current_entry;
  45. kentry_mode_e mode = KENTRY_MODE_NONE;
  46. kparse_status_e retcode = KPARSE_NOTFOUND; // For ENTRY itself
  47. kparse_status_e rc = KPARSE_NOTFOUND; // For nested ENTRYs
  48. assert(current_entry);
  49. if (!current_entry)
  50. return KPARSE_ERROR;
  51. assert(argv_iter);
  52. if (!argv_iter)
  53. return KPARSE_ERROR;
  54. assert(pargv);
  55. if (!pargv)
  56. return KPARSE_ERROR;
  57. // If all arguments are resolved already then return INCOMPLETED
  58. assert(*argv_iter);
  59. if (!*argv_iter)
  60. return KPARSE_INCOMPLETED;
  61. // Is entry candidate to resolve current arg?
  62. // Container can't be a candidate.
  63. if (!kentry_container(entry)) {
  64. const char *current_arg = faux_argv_current(*argv_iter);
  65. if (ksession_validate_arg(entry, current_arg)) {
  66. kparg_t *parg = kparg_new(entry, current_arg);
  67. kpargv_add_parg(pargv, parg);
  68. faux_argv_each(argv_iter); // Next argument
  69. retcode = KPARSE_INPROGRESS;
  70. } else {
  71. // It's not a container and is not validated so
  72. // no chance to find anything here.
  73. return KPARSE_NOTFOUND;
  74. }
  75. }
  76. // ENTRY has no nested ENTRYs so return
  77. if (kentry_entrys_is_empty(entry))
  78. return retcode;
  79. // Walk through the nested entries
  80. mode = kentry_mode(entry);
  81. if (KENTRY_MODE_EMPTY == mode)
  82. return retcode;
  83. // SWITCH
  84. // Entries within SWITCH can't has 'min'/'max' else than 1.
  85. // So these attributes will be ignored. Note SWITCH itself can have
  86. // 'min'/'max'.
  87. if (KENTRY_MODE_SWITCH == mode) {
  88. kentry_entrys_node_t *iter = kentry_entrys_iter(entry);
  89. kentry_t *nested = NULL;
  90. while ((nested = kentry_entrys_each(&iter))) {
  91. rc = ksession_parse_arg(nested, argv_iter, pargv);
  92. // Any variant of error or INPROGRESS
  93. if (rc != KPARSE_NOTFOUND)
  94. break;
  95. }
  96. // SEQUENCE
  97. } else if (KENTRY_MODE_SEQUENCE == mode) {
  98. kentry_entrys_node_t *iter = kentry_entrys_iter(entry);
  99. kentry_entrys_node_t *saved_iter = iter;
  100. kentry_t *nested = NULL;
  101. while ((nested = kentry_entrys_each(&iter))) {
  102. kparse_status_e nrc = KPARSE_NOTFOUND;
  103. size_t num = 0;
  104. for (num = 0; num < kentry_max(nested); num++) {
  105. nrc = ksession_parse_arg(nested, argv_iter, pargv);
  106. if (nrc != KPARSE_INPROGRESS)
  107. break;
  108. }
  109. if ((nrc != KPARSE_INPROGRESS) && (nrc != KPARSE_NOTFOUND)) {
  110. rc = nrc;
  111. break;
  112. }
  113. // Not found all mandatory instances (NOTFOUND)
  114. if (num < kentry_min(nested)) {
  115. rc = KPARSE_NOTFOUND;
  116. break;
  117. }
  118. // It's not an error if optional parameter is absend
  119. rc = KPARSE_INPROGRESS;
  120. // Mandatory or ordered parameter
  121. if ((kentry_min(nested) > 0) ||
  122. kentry_order(nested))
  123. saved_iter = iter;
  124. iter = saved_iter;
  125. }
  126. }
  127. // When ENTRY (not container) is found but mandatory nested ENTRY is
  128. // not resolved. It's inconsistent. So NOTFOUND is not suitable in
  129. // this case.
  130. if ((KPARSE_NOTFOUND == rc) && (KPARSE_INPROGRESS == retcode))
  131. return KPARSE_ILLEGAL;
  132. return rc;
  133. }
  134. kpargv_t *ksession_parse_line(ksession_t *session, const char *line)
  135. {
  136. faux_argv_t *argv = NULL;
  137. faux_argv_node_t *argv_iter = NULL;
  138. kentry_t *current_entry = NULL;
  139. kpargv_t *pargv = NULL;
  140. assert(session);
  141. if (!session)
  142. return NULL;
  143. assert(line);
  144. if (!line)
  145. return NULL;
  146. // Split line to arguments
  147. argv = faux_argv_new();
  148. assert(argv);
  149. if (!argv)
  150. return NULL;
  151. if (faux_argv_parse(argv, line) <= 0) {
  152. faux_argv_free(argv);
  153. return NULL;
  154. }
  155. argv_iter = faux_argv_iter(argv);
  156. current_entry = klevel_entry(kpath_current(ksession_path(session)));
  157. pargv = kpargv_new();
  158. assert(pargv);
  159. ksession_parse_arg(current_entry, &argv_iter, pargv);
  160. if (kpargv_pargs_is_empty(pargv)) {
  161. kpargv_free(pargv);
  162. return NULL;
  163. }
  164. return pargv;
  165. }