tree.c 9.7 KB

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