argv.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. /** @file argv.c
  2. * @brief Functions to parse string to arguments.
  3. */
  4. #include <stdlib.h>
  5. #include <stdio.h>
  6. #include <string.h>
  7. #include <assert.h>
  8. #include <ctype.h>
  9. #include "private.h"
  10. #include "faux/faux.h"
  11. #include "faux/str.h"
  12. #include "faux/list.h"
  13. #include "faux/argv.h"
  14. /** @brief Allocates new argv object.
  15. *
  16. * Before working with argument list it must be allocated and initialized.
  17. *
  18. * @return Allocated and initialized argument list or NULL on error.
  19. */
  20. faux_argv_t *faux_argv_new(void)
  21. {
  22. faux_argv_t *fargv = NULL;
  23. fargv = faux_zmalloc(sizeof(*fargv));
  24. assert(fargv);
  25. if (!fargv)
  26. return NULL;
  27. // Init
  28. fargv->list = faux_list_new(FAUX_LIST_UNSORTED, FAUX_LIST_NONUNIQUE,
  29. NULL, NULL, (void (*)(void *))faux_str_free);
  30. fargv->quotes = NULL;
  31. fargv->continuable = BOOL_FALSE;
  32. return fargv;
  33. }
  34. /** @brief Duplicate existing argv object.
  35. *
  36. * @param [in] fargv Allocated and initialized argv object.
  37. * @return Allocated and initialized duplicate or NULL on error.
  38. */
  39. faux_argv_t *faux_argv_dup(const faux_argv_t *origin)
  40. {
  41. faux_argv_t *fargv = NULL;
  42. faux_list_t *list = NULL;
  43. faux_argv_node_t *iter = NULL;
  44. const char *arg = NULL;
  45. assert(origin);
  46. if (!origin)
  47. return NULL;
  48. fargv = faux_argv_new();
  49. assert(fargv);
  50. if (!fargv)
  51. return NULL;
  52. // Copy all fields but list must be recreated
  53. list = fargv->list;
  54. *fargv = *origin;
  55. fargv->list = list;
  56. // Copy list
  57. iter = faux_argv_iter(origin);
  58. while ((arg = faux_argv_each(&iter)))
  59. faux_argv_add(fargv, arg);
  60. return fargv;
  61. }
  62. /** @brief Frees the argv object object.
  63. *
  64. * After using the argv object must be freed. Function frees argv object.
  65. */
  66. void faux_argv_free(faux_argv_t *fargv)
  67. {
  68. if (!fargv)
  69. return;
  70. faux_list_free(fargv->list);
  71. faux_str_free(fargv->quotes);
  72. faux_free(fargv);
  73. }
  74. /** @brief Initializes iterator to iterate through the entire argv object.
  75. *
  76. * Before iterating with the faux_argv_each() function the iterator must be
  77. * initialized. This function do it.
  78. *
  79. * @param [in] fargv Allocated and initialized argv object.
  80. * @return Initialized iterator.
  81. * @sa faux_argv_each()
  82. */
  83. faux_argv_node_t *faux_argv_iter(const faux_argv_t *fargv)
  84. {
  85. assert(fargv);
  86. if (!fargv)
  87. return NULL;
  88. return (faux_argv_node_t *)faux_list_head(fargv->list);
  89. }
  90. /** @brief Iterate entire argv object for arguments.
  91. *
  92. * Before iteration the iterator must be initialized by faux_argv_iter()
  93. * function. Doesn't use faux_argv_each() with uninitialized iterator.
  94. *
  95. * On each call function returns string (argument) and modifies iterator.
  96. * Stop iteration when function returns NULL.
  97. *
  98. * @param [in,out] iter Iterator.
  99. * @return String.
  100. * @sa faux_argv_iter()
  101. */
  102. const char *faux_argv_each(faux_argv_node_t **iter)
  103. {
  104. return (const char *)faux_list_each((faux_list_node_t **)iter);
  105. }
  106. /** @brief Get current argument by iterator.
  107. *
  108. * Before iteration the iterator must be initialized by faux_argv_iter()
  109. * function. Doesn't use faux_argv_current() with uninitialized iterator.
  110. *
  111. * Function doesn't modify iterator.
  112. *
  113. * @param [in] iter Iterator.
  114. * @return String.
  115. * @sa faux_argv_iter()
  116. */
  117. const char *faux_argv_current(faux_argv_node_t *iter)
  118. {
  119. return (const char *)faux_list_data((faux_list_node_t *)iter);
  120. }
  121. /** @brief Sets alternative quotes list.
  122. *
  123. * Any character from specified string becomes alternative quote.
  124. *
  125. * @param [in] fargv Allocated fargv object.
  126. * @param [in] quotes String with symbols to consider as a quote.
  127. */
  128. void faux_argv_set_quotes(faux_argv_t *fargv, const char *quotes)
  129. {
  130. assert(fargv);
  131. if (!fargv)
  132. return;
  133. faux_str_free(fargv->quotes);
  134. if (!quotes) {
  135. fargv->quotes = NULL; // No additional quotes
  136. return;
  137. }
  138. fargv->quotes = faux_str_dup(quotes);
  139. }
  140. /** @brief Parse string to words and quoted substrings.
  141. *
  142. * Parse string to words and quoted substrings. Additionally function sets
  143. * continuable flag. It shows if last word is reliable ended i.e. it can't be
  144. * continued.
  145. *
  146. * @param [in] fargv Allocated fargv object.
  147. * @param [in] str String to parse.
  148. * @return Number of resulting words and substrings or < 0 on error.
  149. */
  150. ssize_t faux_argv_parse(faux_argv_t *fargv, const char *str)
  151. {
  152. const char *saveptr = str;
  153. char *word = NULL;
  154. bool_t closed_quotes = BOOL_FALSE;
  155. assert(fargv);
  156. if (!fargv)
  157. return -1;
  158. if (!str)
  159. return -1;
  160. while ((word = faux_str_nextword(saveptr, &saveptr, fargv->quotes, &closed_quotes)))
  161. faux_list_add(fargv->list, word);
  162. // Check if last argument can be continued
  163. // It's true if last argument has unclosed quotes.
  164. // It's true if last argument doesn't terminated by space.
  165. fargv->continuable = !closed_quotes || ((saveptr != str) && (!isspace(*(saveptr - 1))));
  166. return faux_list_len(fargv->list);
  167. }
  168. /** @brief Get number of arguments.
  169. *
  170. * @param [in] fargv Allocated fargv object.
  171. * @return Number of words and substrings or < 0 on error.
  172. */
  173. ssize_t faux_argv_len(faux_argv_t *fargv)
  174. {
  175. assert(fargv);
  176. if (!fargv)
  177. return -1;
  178. return faux_list_len(fargv->list);
  179. }
  180. /** @brief Returns continuable flag.
  181. *
  182. * Can be used after faux_argv_parse() only.
  183. *
  184. * @sa faux_argv_parse()
  185. * @param [in] fargv Allocated fargv object.
  186. * @return Boolean continuable flag.
  187. */
  188. bool_t faux_argv_is_continuable(const faux_argv_t *fargv)
  189. {
  190. assert(fargv);
  191. if (!fargv)
  192. return BOOL_FALSE;
  193. return fargv->continuable;
  194. }
  195. /** @brief Sets continuable flag.
  196. *
  197. * @param [in] fargv Allocated fargv object.
  198. * @param [in] continuable Continuable flag to set.
  199. */
  200. void faux_argv_set_continuable(faux_argv_t *fargv, bool_t continuable)
  201. {
  202. assert(fargv);
  203. if (!fargv)
  204. return;
  205. fargv->continuable = continuable;
  206. }
  207. /** @brief Remove last uncompleted entry.
  208. *
  209. * If argv is continuable consider last entry as uncompleted and remove it.
  210. *
  211. * @param [in] fargv Allocated fargv object.
  212. */
  213. void faux_argv_del_continuable(faux_argv_t *fargv)
  214. {
  215. faux_list_node_t *tail = NULL;
  216. assert(fargv);
  217. if (!fargv)
  218. return;
  219. if (!fargv->continuable)
  220. return;
  221. tail = faux_list_tail(fargv->list);
  222. if (!tail)
  223. return;
  224. faux_list_del(fargv->list, tail);
  225. }
  226. /** @brief If given node is last one.
  227. *
  228. * @param [in] iter Iterator/Node.
  229. * @return BOOL_TRUE if last, BOOL_FALSE - not last or error.
  230. */
  231. bool_t faux_argv_is_last(faux_argv_node_t *iter)
  232. {
  233. faux_list_node_t *node = (faux_list_node_t *)iter;
  234. if (!node)
  235. return BOOL_FALSE;
  236. if (faux_list_next_node(node) == NULL)
  237. return BOOL_TRUE;
  238. return BOOL_FALSE;
  239. }
  240. /** @brief Adds argument to fargv object.
  241. *
  242. * @param [in] fargv Allocated argv object.
  243. * @param [in] arg Argument to add.
  244. * @return BOOL_TRUE - success, BOOL_FALSE - error.
  245. */
  246. bool_t faux_argv_add(faux_argv_t *fargv, const char *arg)
  247. {
  248. assert(fargv);
  249. if (!fargv)
  250. return BOOL_FALSE;
  251. assert(arg);
  252. if (!arg)
  253. return BOOL_FALSE;
  254. faux_list_add(fargv->list, faux_str_dup(arg));
  255. return BOOL_TRUE;
  256. }
  257. /** @brief Gets argument by index.
  258. *
  259. * @param [in] fargv Allocated argv object.
  260. * @return String or NULL on error.
  261. */
  262. const char *faux_argv_index(const faux_argv_t *fargv, size_t index)
  263. {
  264. const char *res = NULL;
  265. assert(fargv);
  266. if (!fargv)
  267. return NULL;
  268. res = (const char *)faux_list_index(fargv->list, index);
  269. return res;
  270. }
  271. /** @brief Gets whole text line (concatinated arguments).
  272. *
  273. * TODO: Now args with spaces is printed simply with quotes. It must be fixed
  274. * later because arg can contain quotes itself.
  275. *
  276. * @param [in] fargv Allocated argv object.
  277. * @return String or NULL on error.
  278. */
  279. char *faux_argv_line(const faux_argv_t *fargv)
  280. {
  281. bool_t is_first_arg = BOOL_TRUE;
  282. char *line = NULL;
  283. faux_argv_node_t *iter = NULL;
  284. const char *arg = NULL;
  285. iter = faux_argv_iter(fargv);
  286. while ((arg = faux_argv_each(&iter))) {
  287. bool_t space_found = BOOL_FALSE;
  288. if (is_first_arg)
  289. is_first_arg = BOOL_FALSE;
  290. else
  291. faux_str_cat(&line, " ");
  292. if (faux_str_chars(arg, " \t"))
  293. space_found = BOOL_TRUE;
  294. if (space_found)
  295. faux_str_cat(&line, "\"");
  296. faux_str_cat(&line, arg);
  297. if (space_found)
  298. faux_str_cat(&line, "\"");
  299. }
  300. return line;
  301. }