kpargv.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. /** @file kpargv.c
  2. */
  3. #include <assert.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <faux/list.h>
  8. #include <faux/error.h>
  9. #include <klish/khelper.h>
  10. #include <klish/kentry.h>
  11. #include <klish/kpargv.h>
  12. struct kpargv_s {
  13. faux_list_t *pargs;
  14. faux_list_t *completions;
  15. kpargv_status_e status; // Parse status
  16. size_t level; // Number of path's level where command was found
  17. const kentry_t *command; // ENTRY that consider as command (has ACTIONs)
  18. bool_t continuable; // Last argument can be expanded
  19. kpargv_purpose_e purpose; // Exec/Completion/Help
  20. char *last_arg;
  21. kparg_t *candidate_parg; // Don't free
  22. };
  23. // Status
  24. KGET(pargv, kpargv_status_e, status);
  25. KSET(pargv, kpargv_status_e, status);
  26. // Level
  27. KGET(pargv, size_t, level);
  28. KSET(pargv, size_t, level);
  29. // Command
  30. KGET(pargv, const kentry_t *, command);
  31. KSET(pargv, const kentry_t *, command);
  32. // Continuable
  33. KGET_BOOL(pargv, continuable);
  34. KSET_BOOL(pargv, continuable);
  35. // Purpose
  36. KGET(pargv, kpargv_purpose_e, purpose);
  37. KSET(pargv, kpargv_purpose_e, purpose);
  38. // Last argument
  39. KSET_STR(pargv, last_arg);
  40. KGET_STR(pargv, last_arg);
  41. // Level
  42. KGET(pargv, kparg_t *, candidate_parg);
  43. KSET(pargv, kparg_t *, candidate_parg);
  44. // Pargs
  45. KGET(pargv, faux_list_t *, pargs);
  46. KADD_NESTED(pargv, kparg_t *, pargs);
  47. KNESTED_LEN(pargv, pargs);
  48. KNESTED_IS_EMPTY(pargv, pargs);
  49. KNESTED_ITER(pargv, pargs);
  50. KNESTED_ITERR(pargv, pargs);
  51. KNESTED_EACH(pargv, kparg_t *, pargs);
  52. KNESTED_EACHR(pargv, kparg_t *, pargs);
  53. // Completions
  54. KGET(pargv, faux_list_t *, completions);
  55. KADD_NESTED(pargv, const kentry_t *, completions);
  56. KNESTED_LEN(pargv, completions);
  57. KNESTED_IS_EMPTY(pargv, completions);
  58. KNESTED_ITER(pargv, completions);
  59. KNESTED_EACH(pargv, const kentry_t *, completions);
  60. static int kpargv_completions_compare(const void *first, const void *second)
  61. {
  62. const kentry_t *f = (const kentry_t *)first;
  63. const kentry_t *s = (const kentry_t *)second;
  64. return strcmp(kentry_name(f), kentry_name(s));
  65. }
  66. static int kpargv_pargs_kcompare(const void *key, const void *list_item)
  67. {
  68. const kentry_t *f = (const kentry_t *)key;
  69. const kparg_t *s = (const kparg_t *)list_item;
  70. if (f == kparg_entry(s))
  71. return 0;
  72. return 1;
  73. }
  74. kpargv_t *kpargv_new()
  75. {
  76. kpargv_t *pargv = NULL;
  77. pargv = faux_zmalloc(sizeof(*pargv));
  78. assert(pargv);
  79. if (!pargv)
  80. return NULL;
  81. // Initialization
  82. pargv->status = KPARSE_NONE;
  83. pargv->level = 0;
  84. pargv->command = NULL;
  85. pargv->continuable = BOOL_FALSE;
  86. pargv->purpose = KPURPOSE_EXEC;
  87. pargv->last_arg = NULL;
  88. pargv->candidate_parg = NULL;
  89. // Parsed arguments list
  90. pargv->pargs = faux_list_new(FAUX_LIST_UNSORTED, FAUX_LIST_NONUNIQUE,
  91. NULL, kpargv_pargs_kcompare, (void (*)(void *))kparg_free);
  92. assert(pargv->pargs);
  93. // Completions
  94. pargv->completions = faux_list_new(FAUX_LIST_UNSORTED, FAUX_LIST_UNIQUE,
  95. kpargv_completions_compare, NULL, NULL);
  96. assert(pargv->completions);
  97. return pargv;
  98. }
  99. void kpargv_free(kpargv_t *pargv)
  100. {
  101. if (!pargv)
  102. return;
  103. faux_str_free(pargv->last_arg);
  104. faux_list_free(pargv->pargs);
  105. faux_list_free(pargv->completions);
  106. free(pargv);
  107. }
  108. kparg_t *kpargv_pargs_last(const kpargv_t *pargv)
  109. {
  110. assert(pargv);
  111. if (!pargv)
  112. return NULL;
  113. if (kpargv_pargs_is_empty(pargv))
  114. return NULL;
  115. return (kparg_t *)faux_list_data(faux_list_tail(pargv->pargs));
  116. }
  117. kparg_t *kpargv_entry_exists(const kpargv_t *pargv, const void *entry)
  118. {
  119. assert(pargv);
  120. if (!pargv)
  121. return NULL;
  122. assert(entry);
  123. if (!entry)
  124. return NULL;
  125. return (kparg_t *)faux_list_kfind(pargv->pargs, entry);
  126. }
  127. const char *kpargv_status_decode(kpargv_status_e status)
  128. {
  129. const char *s = "Unknown";
  130. switch (status) {
  131. case KPARSE_OK:
  132. s = "Ok";
  133. break;
  134. case KPARSE_INPROGRESS:
  135. s = "In progress";
  136. break;
  137. case KPARSE_NOTFOUND:
  138. s = "Not found";
  139. break;
  140. case KPARSE_INCOMPLETED:
  141. s = "Incompleted";
  142. break;
  143. case KPARSE_ILLEGAL:
  144. s = "Illegal";
  145. break;
  146. case KPARSE_NOACTION:
  147. s = "Has no action";
  148. break;
  149. default: // ERROR/MAX/NONE
  150. s = "Error";
  151. break;
  152. }
  153. return s;
  154. }
  155. const char *kpargv_status_str(const kpargv_t *pargv)
  156. {
  157. assert(pargv);
  158. if (!pargv)
  159. return NULL;
  160. return kpargv_status_decode(kpargv_status(pargv));
  161. }
  162. bool_t kpargv_accept_candidate_parg(kpargv_t *pargv)
  163. {
  164. kparg_t *candidate = NULL;
  165. assert(pargv);
  166. if (!pargv)
  167. return BOOL_FALSE;
  168. if (!(candidate = pargv->candidate_parg))
  169. return BOOL_FALSE;
  170. pargv->candidate_parg = NULL;
  171. return kpargv_add_pargs(pargv, candidate);
  172. }
  173. bool_t kpargv_decline_candidate_parg(kpargv_t *pargv)
  174. {
  175. assert(pargv);
  176. if (!pargv)
  177. return BOOL_FALSE;
  178. pargv->candidate_parg = NULL;
  179. return BOOL_TRUE;
  180. }
  181. bool_t kpargv_debug(const kpargv_t *pargv)
  182. {
  183. #ifdef PARGV_DEBUG
  184. kpargv_pargs_node_t *p_iter = NULL;
  185. assert(pargv);
  186. if (!pargv)
  187. return BOOL_FALSE;
  188. printf("Level: %lu, Command: %s, Status: %s\n",
  189. kpargv_level(pargv),
  190. kpargv_command(pargv) ? kentry_name(kpargv_command(pargv)) : "<none>",
  191. kpargv_status_str(pargv));
  192. // Parsed parameters
  193. p_iter = kpargv_pargs_iter(pargv);
  194. if (kpargv_pargs_len(pargv) > 0) {
  195. kparg_t *parg = NULL;
  196. while ((parg = kpargv_pargs_each(&p_iter))) {
  197. printf("%s(%s) ", kparg_value(parg), kentry_name(kparg_entry(parg)));
  198. }
  199. printf("\n");
  200. }
  201. // Completions
  202. if (!kpargv_completions_is_empty(pargv)) {
  203. const kentry_t *completion = NULL;
  204. kpargv_completions_node_t *citer = kpargv_completions_iter(pargv);
  205. printf("Completions (%s):\n", kpargv_last_arg(pargv));
  206. while ((completion = kpargv_completions_each(&citer)))
  207. printf("* %s\n", kentry_name(completion));
  208. }
  209. return BOOL_TRUE;
  210. #else
  211. pargv = pargv; // Happy compiler
  212. return BOOL_TRUE;
  213. #endif
  214. }