tree.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. /*
  2. * tree.c
  3. *
  4. * This file provides the implementation of a konf_tree class
  5. */
  6. #include "private.h"
  7. #include "lub/argv.h"
  8. #include "lub/string.h"
  9. #include "lub/ctype.h"
  10. #include <assert.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <stdio.h>
  14. #include <sys/types.h>
  15. #include <regex.h>
  16. /*--------------------------------------------------------- */
  17. static int konf_tree_compare(const void *first, const void *second)
  18. {
  19. const konf_tree_t *f = (const konf_tree_t *)first;
  20. const konf_tree_t *s = (const konf_tree_t *)second;
  21. /* Priority check */
  22. if (f->priority != s->priority)
  23. return (f->priority - s->priority);
  24. /* Sequence check */
  25. if (f->seq_num != s->seq_num)
  26. return (f->seq_num - s->seq_num);
  27. /* Sub-sequence check */
  28. if (f->sub_num != s->sub_num)
  29. return (f->sub_num - s->sub_num);
  30. /* Line check */
  31. return strcmp(f->line, s->line);
  32. }
  33. /*--------------------------------------------------------- */
  34. static void konf_tree_init(konf_tree_t * this, const char *line,
  35. unsigned short priority)
  36. {
  37. /* set up defaults */
  38. this->line = strdup(line);
  39. this->priority = priority;
  40. this->seq_num = 0;
  41. this->sub_num = KONF_ENTRY_OK;
  42. this->splitter = BOOL_TRUE;
  43. this->depth = -1;
  44. /* initialise the list of commands for this conf */
  45. this->list = lub_list_new(konf_tree_compare, konf_tree_delete);
  46. }
  47. /*--------------------------------------------------------- */
  48. static void konf_tree_fini(konf_tree_t * this)
  49. {
  50. lub_list_free_all(this->list);
  51. free(this->line);
  52. }
  53. /*--------------------------------------------------------- */
  54. konf_tree_t *konf_tree_new(const char *line, unsigned short priority)
  55. {
  56. konf_tree_t *this = malloc(sizeof(konf_tree_t));
  57. if (this)
  58. konf_tree_init(this, line, priority);
  59. return this;
  60. }
  61. /*--------------------------------------------------------- */
  62. void konf_tree_delete(void *data)
  63. {
  64. konf_tree_t *this = (konf_tree_t *)data;
  65. konf_tree_fini(this);
  66. free(this);
  67. }
  68. /*--------------------------------------------------------- */
  69. void konf_tree_fprintf(konf_tree_t *this, FILE *stream,
  70. const char *pattern, int top_depth, int depth,
  71. bool_t seq, bool_t splitter, unsigned char prev_pri_hi)
  72. {
  73. konf_tree_t *conf;
  74. lub_list_node_t *iter;
  75. unsigned char pri = 0;
  76. regex_t regexp;
  77. if (this->line && (*(this->line) != '\0') &&
  78. (this->depth > top_depth) &&
  79. ((depth < 0 ) || (this->depth <= (top_depth + depth)))) {
  80. char *space = NULL;
  81. unsigned int space_num = this->depth - top_depth - 1;
  82. if (space_num > 0) {
  83. space = malloc(space_num + 1);
  84. memset(space, ' ', space_num);
  85. space[space_num] = '\0';
  86. }
  87. if (splitter && (0 == this->depth) &&
  88. (this->splitter ||
  89. (konf_tree__get_priority_hi(this) != prev_pri_hi)))
  90. fprintf(stream, "!\n");
  91. fprintf(stream, "%s", space ? space : "");
  92. if (seq && (konf_tree__get_seq_num(this) != 0))
  93. fprintf(stream, "%u ", konf_tree__get_seq_num(this));
  94. fprintf(stream, "%s\n", this->line);
  95. free(space);
  96. }
  97. /* regexp compilation */
  98. if (pattern)
  99. if (regcomp(&regexp, pattern, REG_EXTENDED | REG_ICASE) != 0)
  100. return;
  101. /* iterate child elements */
  102. for(iter = lub_list__get_head(this->list);
  103. iter; iter = lub_list_node__get_next(iter)) {
  104. conf = (konf_tree_t *)lub_list_node__get_data(iter);
  105. if (pattern && (0 != regexec(&regexp, conf->line, 0, NULL, 0)))
  106. continue;
  107. /* Don't check pattern for child elements */
  108. konf_tree_fprintf(conf, stream, NULL, top_depth, depth,
  109. seq, splitter, pri);
  110. pri = konf_tree__get_priority_hi(conf);
  111. }
  112. if (pattern)
  113. regfree(&regexp);
  114. }
  115. /*-------------------------------------------------------- */
  116. static int normalize_seq(konf_tree_t * this, unsigned short priority,
  117. lub_list_node_t *start)
  118. {
  119. unsigned short cnt = 1;
  120. konf_tree_t *conf = NULL;
  121. lub_list_node_t *iter;
  122. unsigned short cur_pri;
  123. if (start) {
  124. lub_list_node_t *prev;
  125. iter = start;
  126. if ((prev = lub_list_node__get_prev(iter))) {
  127. conf = (konf_tree_t *)lub_list_node__get_data(prev);
  128. if (konf_tree__get_priority(conf) == priority)
  129. cnt = konf_tree__get_seq_num(conf) + 1;
  130. }
  131. } else {
  132. iter = lub_list__get_head(this->list);
  133. }
  134. /* If list is empty */
  135. if (!iter)
  136. return 0;
  137. /* Iterate and renum */
  138. do {
  139. conf = (konf_tree_t *)lub_list_node__get_data(iter);
  140. cur_pri = konf_tree__get_priority(conf);
  141. if (cur_pri > priority)
  142. break;
  143. if (cur_pri < priority)
  144. continue;
  145. if (konf_tree__get_seq_num(conf) == 0)
  146. continue;
  147. konf_tree__set_seq_num(conf, cnt++);
  148. } while ((iter = lub_list_node__get_next(iter)));
  149. return 0;
  150. }
  151. /*--------------------------------------------------------- */
  152. konf_tree_t *konf_tree_new_conf(konf_tree_t * this,
  153. const char *line, unsigned short priority,
  154. bool_t seq, unsigned short seq_num)
  155. {
  156. lub_list_node_t *node;
  157. /* Allocate the memory for a new child element */
  158. konf_tree_t *newconf = konf_tree_new(line, priority);
  159. assert(newconf);
  160. /* Sequence */
  161. if (seq) {
  162. konf_tree__set_seq_num(newconf,
  163. seq_num ? seq_num : 0xffff);
  164. konf_tree__set_sub_num(newconf, KONF_ENTRY_NEW);
  165. }
  166. /* Insert it into the list */
  167. node = lub_list_add(this->list, newconf);
  168. if (seq) {
  169. normalize_seq(this, priority, node);
  170. konf_tree__set_sub_num(newconf, KONF_ENTRY_OK);
  171. }
  172. return newconf;
  173. }
  174. /*--------------------------------------------------------- */
  175. konf_tree_t *konf_tree_find_conf(konf_tree_t * this,
  176. const char *line, unsigned short priority, unsigned short seq_num)
  177. {
  178. konf_tree_t *conf;
  179. lub_list_node_t *iter;
  180. int check_pri = 0;
  181. /* If list is empty */
  182. if (!(iter = lub_list__get_tail(this->list)))
  183. return NULL;
  184. if ((0 != priority) && (0 != seq_num))
  185. check_pri = 1;
  186. /* Iterate non-empty tree */
  187. do {
  188. conf = (konf_tree_t *)lub_list_node__get_data(iter);
  189. if (check_pri) {
  190. if (priority < conf->priority)
  191. continue;
  192. if (priority > conf->priority)
  193. break;
  194. if (seq_num < conf->seq_num)
  195. continue;
  196. if (seq_num > conf->seq_num)
  197. break;
  198. }
  199. if (!strcmp(conf->line, line))
  200. return conf;
  201. } while ((iter = lub_list_node__get_prev(iter)));
  202. return NULL;
  203. }
  204. /*--------------------------------------------------------- */
  205. int konf_tree_del_pattern(konf_tree_t *this,
  206. const char *line, bool_t unique,
  207. const char *pattern, unsigned short priority,
  208. bool_t seq, unsigned short seq_num)
  209. {
  210. int res = 0;
  211. konf_tree_t *conf;
  212. lub_list_node_t *iter;
  213. lub_list_node_t *tmp;
  214. regex_t regexp;
  215. int del_cnt = 0; /* how many strings were deleted */
  216. if (seq && (0 == priority))
  217. return -1;
  218. /* Is tree empty? */
  219. if (!(iter = lub_list__get_head(this->list)))
  220. return 0;
  221. /* Compile regular expression */
  222. if (regcomp(&regexp, pattern, REG_EXTENDED | REG_ICASE) != 0)
  223. return -1;
  224. /* Iterate configuration tree */
  225. tmp = lub_list_node_new(NULL);
  226. do {
  227. conf = (konf_tree_t *)lub_list_node__get_data(iter);
  228. if ((0 != priority) &&
  229. (priority != conf->priority))
  230. continue;
  231. if (seq && (seq_num != 0) &&
  232. (seq_num != conf->seq_num))
  233. continue;
  234. if (seq && (0 == seq_num) && (0 == conf->seq_num))
  235. continue;
  236. if (0 != regexec(&regexp, conf->line, 0, NULL, 0))
  237. continue;
  238. if (unique && line && !strcmp(conf->line, line)) {
  239. res++;
  240. continue;
  241. }
  242. lub_list_del(this->list, iter);
  243. konf_tree_delete(conf);
  244. lub_list_node_copy(tmp, iter);
  245. lub_list_node_free(iter);
  246. iter = tmp;
  247. del_cnt++;
  248. } while ((iter = lub_list_node__get_next(iter)));
  249. lub_list_node_free(tmp);
  250. regfree(&regexp);
  251. if (seq && (del_cnt != 0))
  252. normalize_seq(this, priority, NULL);
  253. return res;
  254. }
  255. /*--------------------------------------------------------- */
  256. unsigned short konf_tree__get_priority(const konf_tree_t * this)
  257. {
  258. return this->priority;
  259. }
  260. /*--------------------------------------------------------- */
  261. unsigned char konf_tree__get_priority_hi(const konf_tree_t * this)
  262. {
  263. return (unsigned char)(this->priority >> 8);
  264. }
  265. /*--------------------------------------------------------- */
  266. unsigned char konf_tree__get_priority_lo(const konf_tree_t * this)
  267. {
  268. return (unsigned char)(this->priority & 0xff);
  269. }
  270. /*--------------------------------------------------------- */
  271. bool_t konf_tree__get_splitter(const konf_tree_t * this)
  272. {
  273. return this->splitter;
  274. }
  275. /*--------------------------------------------------------- */
  276. void konf_tree__set_splitter(konf_tree_t *this, bool_t splitter)
  277. {
  278. this->splitter = splitter;
  279. }
  280. /*--------------------------------------------------------- */
  281. unsigned short konf_tree__get_seq_num(const konf_tree_t * this)
  282. {
  283. return this->seq_num;
  284. }
  285. /*--------------------------------------------------------- */
  286. void konf_tree__set_seq_num(konf_tree_t * this, unsigned short seq_num)
  287. {
  288. this->seq_num = seq_num;
  289. }
  290. /*--------------------------------------------------------- */
  291. unsigned short konf_tree__get_sub_num(const konf_tree_t * this)
  292. {
  293. return this->sub_num;
  294. }
  295. /*--------------------------------------------------------- */
  296. void konf_tree__set_sub_num(konf_tree_t * this, unsigned short sub_num)
  297. {
  298. this->sub_num = sub_num;
  299. }
  300. /*--------------------------------------------------------- */
  301. const char * konf_tree__get_line(const konf_tree_t * this)
  302. {
  303. return this->line;
  304. }
  305. /*--------------------------------------------------------- */
  306. void konf_tree__set_depth(konf_tree_t * this, int depth)
  307. {
  308. this->depth = depth;
  309. }
  310. /*--------------------------------------------------------- */
  311. int konf_tree__get_depth(const konf_tree_t * this)
  312. {
  313. return this->depth;
  314. }