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