kpargv.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  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_EACH(pargv, kparg_t *, pargs);
  51. // Completions
  52. KGET(pargv, faux_list_t *, completions);
  53. KADD_NESTED(pargv, const kentry_t *, completions);
  54. KNESTED_LEN(pargv, completions);
  55. KNESTED_IS_EMPTY(pargv, completions);
  56. KNESTED_ITER(pargv, completions);
  57. KNESTED_EACH(pargv, const kentry_t *, completions);
  58. static int kpargv_completions_compare(const void *first, const void *second)
  59. {
  60. const kentry_t *f = (const kentry_t *)first;
  61. const kentry_t *s = (const kentry_t *)second;
  62. return strcmp(kentry_name(f), kentry_name(s));
  63. }
  64. static int kpargv_pargs_kcompare(const void *key, const void *list_item)
  65. {
  66. const kentry_t *f = (const kentry_t *)key;
  67. const kparg_t *s = (const kparg_t *)list_item;
  68. if (f == kparg_entry(s))
  69. return 0;
  70. return 1;
  71. }
  72. kpargv_t *kpargv_new()
  73. {
  74. kpargv_t *pargv = NULL;
  75. pargv = faux_zmalloc(sizeof(*pargv));
  76. assert(pargv);
  77. if (!pargv)
  78. return NULL;
  79. // Initialization
  80. pargv->status = KPARSE_NONE;
  81. pargv->level = 0;
  82. pargv->command = NULL;
  83. pargv->continuable = BOOL_FALSE;
  84. pargv->purpose = KPURPOSE_EXEC;
  85. pargv->last_arg = NULL;
  86. pargv->candidate_parg = NULL;
  87. // Parsed arguments list
  88. pargv->pargs = faux_list_new(FAUX_LIST_UNSORTED, FAUX_LIST_NONUNIQUE,
  89. NULL, kpargv_pargs_kcompare, (void (*)(void *))kparg_free);
  90. assert(pargv->pargs);
  91. // Completions
  92. pargv->completions = faux_list_new(FAUX_LIST_UNSORTED, FAUX_LIST_UNIQUE,
  93. kpargv_completions_compare, NULL, NULL);
  94. assert(pargv->completions);
  95. return pargv;
  96. }
  97. void kpargv_free(kpargv_t *pargv)
  98. {
  99. if (!pargv)
  100. return;
  101. faux_str_free(pargv->last_arg);
  102. faux_list_free(pargv->pargs);
  103. faux_list_free(pargv->completions);
  104. free(pargv);
  105. }
  106. kparg_t *kpargv_pargs_last(const kpargv_t *pargv)
  107. {
  108. assert(pargv);
  109. if (!pargv)
  110. return NULL;
  111. if (kpargv_pargs_is_empty(pargv))
  112. return NULL;
  113. return (kparg_t *)faux_list_data(faux_list_tail(pargv->pargs));
  114. }
  115. kparg_t *kpargv_entry_exists(const kpargv_t *pargv, const void *entry)
  116. {
  117. assert(pargv);
  118. if (!pargv)
  119. return NULL;
  120. assert(entry);
  121. if (!entry)
  122. return NULL;
  123. return (kparg_t *)faux_list_kfind(pargv->pargs, entry);
  124. }
  125. const char *kpargv_status_decode(kpargv_status_e status)
  126. {
  127. const char *s = "Unknown";
  128. switch (status) {
  129. case KPARSE_OK:
  130. s = "Ok";
  131. break;
  132. case KPARSE_INPROGRESS:
  133. s = "In progress";
  134. break;
  135. case KPARSE_NOTFOUND:
  136. s = "Not found";
  137. break;
  138. case KPARSE_INCOMPLETED:
  139. s = "Incompleted";
  140. break;
  141. case KPARSE_ILLEGAL:
  142. s = "Illegal";
  143. break;
  144. case KPARSE_NOACTION:
  145. s = "Has no action";
  146. break;
  147. default: // ERROR/MAX/NONE
  148. s = "Error";
  149. break;
  150. }
  151. return s;
  152. }
  153. const char *kpargv_status_str(const kpargv_t *pargv)
  154. {
  155. assert(pargv);
  156. if (!pargv)
  157. return NULL;
  158. return kpargv_status_decode(kpargv_status(pargv));
  159. }
  160. bool_t kpargv_accept_candidate_parg(kpargv_t *pargv)
  161. {
  162. kparg_t *candidate = NULL;
  163. assert(pargv);
  164. if (!pargv)
  165. return BOOL_FALSE;
  166. if (!(candidate = pargv->candidate_parg))
  167. return BOOL_FALSE;
  168. pargv->candidate_parg = NULL;
  169. return kpargv_add_pargs(pargv, candidate);
  170. }
  171. bool_t kpargv_decline_candidate_parg(kpargv_t *pargv)
  172. {
  173. assert(pargv);
  174. if (!pargv)
  175. return BOOL_FALSE;
  176. pargv->candidate_parg = NULL;
  177. return BOOL_TRUE;
  178. }
  179. bool_t kpargv_debug(const kpargv_t *pargv)
  180. {
  181. #ifdef PARGV_DEBUG
  182. kpargv_pargs_node_t *p_iter = NULL;
  183. assert(pargv);
  184. if (!pargv)
  185. return BOOL_FALSE;
  186. printf("Level: %lu, Command: %s, Status: %s\n",
  187. kpargv_level(pargv),
  188. kpargv_command(pargv) ? kentry_name(kpargv_command(pargv)) : "<none>",
  189. kpargv_status_str(pargv));
  190. // Parsed parameters
  191. p_iter = kpargv_pargs_iter(pargv);
  192. if (kpargv_pargs_len(pargv) > 0) {
  193. kparg_t *parg = NULL;
  194. while ((parg = kpargv_pargs_each(&p_iter))) {
  195. printf("%s(%s) ", kparg_value(parg), kentry_name(kparg_entry(parg)));
  196. }
  197. printf("\n");
  198. }
  199. // Completions
  200. if (!kpargv_completions_is_empty(pargv)) {
  201. const kentry_t *completion = NULL;
  202. kpargv_completions_node_t *citer = kpargv_completions_iter(pargv);
  203. printf("Completions (%s):\n", kpargv_last_arg(pargv));
  204. while ((completion = kpargv_completions_each(&citer)))
  205. printf("* %s\n", kentry_name(completion));
  206. }
  207. return BOOL_TRUE;
  208. #else
  209. pargv = pargv; // Happy compiler
  210. return BOOL_TRUE;
  211. #endif
  212. }