error.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. /** @file error.c
  2. * @brief Functions for working with errors.
  3. */
  4. #include <stdlib.h>
  5. #include <stdio.h>
  6. #include <string.h>
  7. #include <unistd.h>
  8. #include <assert.h>
  9. #include "private.h"
  10. #include "faux/faux.h"
  11. #include "faux/str.h"
  12. #include "faux/error.h"
  13. /** @brief Allocates new error object.
  14. *
  15. * Before working with error object it must be allocated and initialized.
  16. *
  17. * @return Allocated and initialized error object or NULL on error.
  18. */
  19. faux_error_t *faux_error_new(void)
  20. {
  21. faux_error_t *error = NULL;
  22. error = faux_zmalloc(sizeof(*error));
  23. if (!error)
  24. return NULL;
  25. // Init
  26. error->list = faux_list_new(FAUX_LIST_UNSORTED, FAUX_LIST_NONUNIQUE,
  27. NULL, NULL, (void (*)(void *))faux_str_free);
  28. return error;
  29. }
  30. /** @brief Frees the error object.
  31. *
  32. * After using the error object must be freed.
  33. *
  34. * @param [in] error Allocated and initialized error object.
  35. */
  36. void faux_error_free(faux_error_t *error)
  37. {
  38. if (!error)
  39. return;
  40. faux_list_free(error->list);
  41. faux_free(error);
  42. }
  43. /** @brief Reset error object to empty state.
  44. *
  45. * After using the error object must be freed.
  46. * @param [in] error Allocated and initialized error object.
  47. */
  48. void faux_error_reset(faux_error_t *error)
  49. {
  50. if (!error)
  51. return;
  52. faux_list_del_all(error->list);
  53. }
  54. /** @brief Gets current error stack length.
  55. *
  56. * @param [in] error Allocated and initialized error object.
  57. * @return BOOL_TRUE if object contains errors or BOOL_FALSE.
  58. */
  59. ssize_t faux_error_len(const faux_error_t *error)
  60. {
  61. if (!error)
  62. return -1;
  63. return faux_list_len(error->list);
  64. }
  65. /** @brief Current status of error object.
  66. *
  67. * If error list contains any entries then function returns BOOL_TRUE else
  68. * BOOL_FALSE.
  69. *
  70. * @param [in] error Allocated and initialized error object.
  71. * @return BOOL_TRUE if object contains errors or BOOL_FALSE.
  72. */
  73. bool_t faux_error(const faux_error_t *error)
  74. {
  75. if (faux_error_len(error) > 0)
  76. return BOOL_TRUE;
  77. return BOOL_FALSE;
  78. }
  79. /** @brief Adds error message to message stack.
  80. *
  81. * @param [in] error Allocated and initialized error object.
  82. * @return success - BOOL_TRUE, fail - BOOL_FALSE.
  83. */
  84. bool_t faux_error_add(faux_error_t *error, const char *str)
  85. {
  86. char *tmp = NULL;
  87. // If error == NULL it's not bug
  88. if (!error)
  89. return BOOL_FALSE;
  90. if (!str)
  91. return BOOL_FALSE;
  92. tmp = faux_str_dup(str);
  93. if (!tmp)
  94. return BOOL_FALSE;
  95. if (!faux_list_add(error->list, tmp)) {
  96. faux_str_free(tmp);
  97. return BOOL_FALSE;
  98. }
  99. return BOOL_TRUE;
  100. }
  101. /** @brief Add formatted error message to message stack.
  102. *
  103. * @param [in] error Allocated and initialized error object.
  104. * @param [in] fmt Format like printf() one.
  105. * @param [in] args Variable length args.
  106. * @return success - BOOL_TRUE, fail - BOOL_FALSE.
  107. */
  108. bool_t faux_error_sprintf(faux_error_t *error, const char *fmt, ...)
  109. {
  110. char *line = NULL;
  111. va_list ap;
  112. bool_t retval = BOOL_TRUE;
  113. if (!error)
  114. return BOOL_FALSE;
  115. if (!fmt)
  116. return BOOL_FALSE;
  117. va_start(ap, fmt);
  118. line = faux_str_vsprintf(fmt, ap);
  119. va_end(ap);
  120. if (!line)
  121. return BOOL_FALSE;
  122. retval = faux_error_add(error, line);
  123. faux_str_free(line);
  124. return retval;
  125. }
  126. /** @brief Initializes iterator to iterate through the entire error object.
  127. *
  128. * Before iterating with the faux_error_each() function the iterator must be
  129. * initialized. This function do it.
  130. *
  131. * @param [in] error Allocated and initialized error object.
  132. * @return Initialized iterator.
  133. * @sa faux_error_each()
  134. */
  135. faux_error_node_t *faux_error_iter(const faux_error_t *error)
  136. {
  137. assert(error);
  138. if (!error)
  139. return NULL;
  140. return (faux_error_node_t *)faux_list_head(error->list);
  141. }
  142. /** @brief Initializes iterator to iterate through error object in reverse order.
  143. *
  144. * Before iterating with the faux_error_eachr() function the iterator must be
  145. * initialized. This function do it.
  146. *
  147. * @param [in] error Allocated and initialized error object.
  148. * @return Initialized iterator.
  149. * @sa faux_error_each()
  150. */
  151. faux_error_node_t *faux_error_iterr(const faux_error_t *error)
  152. {
  153. assert(error);
  154. if (!error)
  155. return NULL;
  156. return (faux_error_node_t *)faux_list_tail(error->list);
  157. }
  158. /** @brief Iterate entire error object.
  159. *
  160. * Before iteration the iterator must be initialized by faux_error_iter()
  161. * function. Doesn't use faux_error_each() with uninitialized iterator.
  162. *
  163. * On each call function returns error string and modifies iterator.
  164. * Stop iteration when function returns NULL.
  165. *
  166. * @param [in,out] iter Iterator.
  167. * @return String with error description.
  168. * @sa faux_error_iter()
  169. */
  170. const char *faux_error_each(faux_error_node_t **iter)
  171. {
  172. return (const char *)faux_list_each((faux_list_node_t **)iter);
  173. }
  174. /** @brief Iterate entire error object in reverse order.
  175. *
  176. * Before iteration the iterator must be initialized by faux_error_iterr()
  177. * function. Doesn't use faux_error_each() with uninitialized iterator.
  178. *
  179. * On each call function returns error string and modifies iterator.
  180. * Stop iteration when function returns NULL.
  181. *
  182. * @param [in,out] iter Iterator.
  183. * @return String with error description.
  184. * @sa faux_error_iter()
  185. */
  186. const char *faux_error_eachr(faux_error_node_t **iter)
  187. {
  188. return (const char *)faux_list_eachr((faux_list_node_t **)iter);
  189. }
  190. /** @brief Print error stack.
  191. *
  192. * @param [in] error Allocated and initialized error object.
  193. * @param [in] handle File handler to write to.
  194. * @param [in] reverse Print errors in reverse order.
  195. * @param [in] hierarchy Print errors using hierarchy view (or peer view).
  196. * @return BOOL_TRUE - success, BOOL_FALSE - fail.
  197. */
  198. static bool_t faux_error_show_internal(const faux_error_t *error, FILE *handle,
  199. bool_t reverse, bool_t hierarchy)
  200. {
  201. faux_error_node_t *iter = NULL;
  202. const char *str = NULL;
  203. int level = 0;
  204. if (!error)
  205. return BOOL_FALSE;
  206. iter = reverse ? faux_error_iterr(error) : faux_error_iter(error);
  207. while ((str = (reverse ? faux_error_eachr(&iter) : faux_error_each(&iter)))) {
  208. if ((hierarchy) && (level > 0))
  209. fprintf(handle, "%*c", level, ' ');
  210. fprintf(handle, "%s\n", str);
  211. level ++;
  212. }
  213. return BOOL_TRUE;
  214. }
  215. /** @brief Print error stack.
  216. *
  217. * @param [in] error Allocated and initialized error object.
  218. * @param [in] handle File handler to write to.
  219. * @return BOOL_TRUE - success, BOOL_FALSE - fail.
  220. */
  221. bool_t faux_error_fshow(const faux_error_t *error, FILE *handle)
  222. {
  223. return faux_error_show_internal(error, handle, BOOL_FALSE, BOOL_FALSE);
  224. }
  225. /** @brief Print error stack.
  226. *
  227. * @param [in] error Allocated and initialized error object.
  228. * @return BOOL_TRUE - success, BOOL_FALSE - fail.
  229. */
  230. bool_t faux_error_show(const faux_error_t *error)
  231. {
  232. return faux_error_fshow(error, stderr);
  233. }
  234. /** @brief Print error stack to C-string.
  235. *
  236. * Result must be freed by faux_str_free() later.
  237. *
  238. * @param [in] error Allocated and initialized error object.
  239. * @return Allocated C-string or NULL on error.
  240. */
  241. char *faux_error_cstr(const faux_error_t *error)
  242. {
  243. faux_error_node_t *iter = NULL;
  244. const char *s = NULL;
  245. char *cstr = NULL;
  246. if (!error)
  247. return NULL;
  248. iter = faux_error_iter(error);
  249. while ((s = faux_error_each(&iter))) {
  250. faux_str_cat(&cstr, s);
  251. if (iter)
  252. faux_str_cat(&cstr, "\n");
  253. }
  254. return cstr;
  255. }