tree.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  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. int konf_tree_bt_compare(const void *clientnode, const void *clientkey)
  20. {
  21. const konf_tree_t *this = clientnode;
  22. unsigned short *pri = (unsigned short *)clientkey;
  23. unsigned short *seq = (unsigned short *)clientkey + 1;
  24. unsigned short *sub = (unsigned short *)clientkey + 2;
  25. char *line = ((char *)clientkey + (3 * sizeof(unsigned short)));
  26. /* Priority check */
  27. if (this->priority != *pri)
  28. return (this->priority - *pri);
  29. /* Sequence check */
  30. if (this->seq_num != *seq)
  31. return (this->seq_num - *seq);
  32. /* Sub-sequence check */
  33. if (this->sub_num != *sub)
  34. return (this->sub_num - *sub);
  35. /* Line check */
  36. return lub_string_nocasecmp(this->line, line);
  37. }
  38. /*-------------------------------------------------------- */
  39. static void konf_tree_key(lub_bintree_key_t * key,
  40. unsigned short priority, unsigned short sequence,
  41. unsigned short subseq, const char *text)
  42. {
  43. unsigned short *pri = (unsigned short *)key;
  44. unsigned short *seq = (unsigned short *)key + 1;
  45. unsigned short *sub = (unsigned short *)key + 2;
  46. char *line = ((char *)key + (3 * sizeof(unsigned short)));
  47. /* fill out the opaque key */
  48. *pri = priority;
  49. *seq = sequence;
  50. *sub = subseq;
  51. strcpy(line, text);
  52. }
  53. /*-------------------------------------------------------- */
  54. void konf_tree_bt_getkey(const void *clientnode, lub_bintree_key_t * key)
  55. {
  56. const konf_tree_t *this = clientnode;
  57. konf_tree_key(key, this->priority, this->seq_num,
  58. this->sub_num, this->line);
  59. }
  60. /*---------------------------------------------------------
  61. * PRIVATE METHODS
  62. *--------------------------------------------------------- */
  63. static void
  64. konf_tree_init(konf_tree_t * this, const char *line, unsigned short priority)
  65. {
  66. /* set up defaults */
  67. this->line = lub_string_dup(line);
  68. this->priority = priority;
  69. this->seq_num = 0;
  70. this->sub_num = KONF_ENTRY_OK;
  71. this->splitter = BOOL_TRUE;
  72. /* Be a good binary tree citizen */
  73. lub_bintree_node_init(&this->bt_node);
  74. /* initialise the tree of commands for this conf */
  75. lub_bintree_init(&this->tree,
  76. konf_tree_bt_offset(),
  77. konf_tree_bt_compare, konf_tree_bt_getkey);
  78. }
  79. /*--------------------------------------------------------- */
  80. static void konf_tree_fini(konf_tree_t * this)
  81. {
  82. konf_tree_t *conf;
  83. /* delete each conf held by this conf */
  84. while ((conf = lub_bintree_findfirst(&this->tree))) {
  85. /* remove the conf from the tree */
  86. lub_bintree_remove(&this->tree, conf);
  87. /* release the instance */
  88. konf_tree_delete(conf);
  89. }
  90. /* free our memory */
  91. lub_string_free(this->line);
  92. this->line = NULL;
  93. }
  94. /*---------------------------------------------------------
  95. * PUBLIC META FUNCTIONS
  96. *--------------------------------------------------------- */
  97. size_t konf_tree_bt_offset(void)
  98. {
  99. return offsetof(konf_tree_t, bt_node);
  100. }
  101. /*--------------------------------------------------------- */
  102. konf_tree_t *konf_tree_new(const char *line, unsigned short priority)
  103. {
  104. konf_tree_t *this = malloc(sizeof(konf_tree_t));
  105. if (this) {
  106. konf_tree_init(this, line, priority);
  107. }
  108. return this;
  109. }
  110. /*---------------------------------------------------------
  111. * PUBLIC METHODS
  112. *--------------------------------------------------------- */
  113. void konf_tree_delete(konf_tree_t * this)
  114. {
  115. konf_tree_fini(this);
  116. free(this);
  117. }
  118. /*--------------------------------------------------------- */
  119. void konf_tree_fprintf(konf_tree_t * this, FILE * stream,
  120. const char *pattern, int depth,
  121. bool_t seq, unsigned char prev_pri_hi)
  122. {
  123. konf_tree_t *conf;
  124. lub_bintree_iterator_t iter;
  125. unsigned char pri = 0;
  126. if (this->line && *(this->line) != '\0') {
  127. char *space = NULL;
  128. if (depth > 0) {
  129. space = malloc(depth + 1);
  130. memset(space, ' ', depth);
  131. space[depth] = '\0';
  132. }
  133. if ((0 == depth) &&
  134. (this->splitter ||
  135. (konf_tree__get_priority_hi(this) != prev_pri_hi)))
  136. fprintf(stream, "!\n");
  137. fprintf(stream, "%s", space ? space : "");
  138. if (seq && (konf_tree__get_seq_num(this) != 0))
  139. fprintf(stream, "%02u ", konf_tree__get_seq_num(this));
  140. fprintf(stream, "%s\n", this->line);
  141. free(space);
  142. }
  143. /* iterate child elements */
  144. if (!(conf = lub_bintree_findfirst(&this->tree)))
  145. return;
  146. for(lub_bintree_iterator_init(&iter, &this->tree, conf);
  147. conf; conf = lub_bintree_iterator_next(&iter)) {
  148. if (pattern &&
  149. (lub_string_nocasestr(conf->line, pattern) != conf->line))
  150. continue;
  151. konf_tree_fprintf(conf, stream, NULL, depth + 1, seq, pri);
  152. pri = konf_tree__get_priority_hi(conf);
  153. }
  154. }
  155. static int normalize_seq(konf_tree_t * this, unsigned short priority)
  156. {
  157. unsigned short seq_cnt = 1;
  158. konf_tree_t *conf = NULL;
  159. lub_bintree_iterator_t iter;
  160. /* If tree is empty */
  161. if (!(conf = lub_bintree_findfirst(&this->tree)))
  162. return 0;
  163. /* Iterate non-empty tree */
  164. lub_bintree_iterator_init(&iter, &this->tree, conf);
  165. do {
  166. unsigned short seq_cur = 0;
  167. unsigned short cur_pri = konf_tree__get_priority(conf);
  168. if (cur_pri < priority)
  169. continue;
  170. if (cur_pri > priority)
  171. break;
  172. seq_cur = konf_tree__get_seq_num(conf);
  173. if (0 == seq_cur)
  174. continue;
  175. konf_tree__set_seq_num(conf, seq_cnt++);
  176. konf_tree__set_sub_num(conf, KONF_ENTRY_OK);
  177. } while ((conf = lub_bintree_iterator_next(&iter)));
  178. return 0;
  179. }
  180. /*--------------------------------------------------------- */
  181. konf_tree_t *konf_tree_new_conf(konf_tree_t * this,
  182. const char *line, unsigned short priority,
  183. bool_t seq, unsigned short seq_num)
  184. {
  185. /* Allocate the memory for a new child element */
  186. konf_tree_t *newconf = konf_tree_new(line, priority);
  187. assert(newconf);
  188. /* Sequence */
  189. if (seq) {
  190. konf_tree__set_seq_num(newconf,
  191. seq_num ? seq_num : 0xffff);
  192. konf_tree__set_sub_num(newconf, KONF_ENTRY_DIRTY);
  193. }
  194. /* Insert it into the binary tree for this conf */
  195. if (-1 == lub_bintree_insert(&this->tree, newconf)) {
  196. /* inserting a duplicate command is bad */
  197. konf_tree_delete(newconf);
  198. newconf = NULL;
  199. }
  200. if (seq)
  201. normalize_seq(this, priority);
  202. return newconf;
  203. }
  204. /*--------------------------------------------------------- */
  205. konf_tree_t *konf_tree_find_conf(konf_tree_t * this,
  206. const char *line, unsigned short priority, unsigned short sequence)
  207. {
  208. konf_tree_t *conf;
  209. lub_bintree_key_t key;
  210. lub_bintree_iterator_t iter;
  211. if ((0 != priority) && (0 != sequence)) {
  212. konf_tree_key(&key, priority, sequence,
  213. KONF_ENTRY_OK, line);
  214. return lub_bintree_find(&this->tree, &key);
  215. }
  216. /* If tree is empty */
  217. if (!(conf = lub_bintree_findfirst(&this->tree)))
  218. return NULL;
  219. /* Iterate non-empty tree */
  220. lub_bintree_iterator_init(&iter, &this->tree, conf);
  221. do {
  222. if (0 == lub_string_nocasecmp(conf->line, line))
  223. return conf;
  224. } while ((conf = lub_bintree_iterator_next(&iter)));
  225. return NULL;
  226. }
  227. /*--------------------------------------------------------- */
  228. void konf_tree_del_pattern(konf_tree_t *this,
  229. const char *pattern)
  230. {
  231. konf_tree_t *conf;
  232. lub_bintree_iterator_t iter;
  233. regex_t regexp;
  234. /* Is tree empty? */
  235. if (!(conf = lub_bintree_findfirst(&this->tree)))
  236. return;
  237. /* Compile regular expression */
  238. regcomp(&regexp, pattern, REG_EXTENDED | REG_ICASE);
  239. /* Iterate configuration tree */
  240. lub_bintree_iterator_init(&iter, &this->tree, conf);
  241. do {
  242. if (0 == regexec(&regexp, conf->line, 0, NULL, 0)) {
  243. lub_bintree_remove(&this->tree, conf);
  244. konf_tree_delete(conf);
  245. }
  246. } while ((conf = lub_bintree_iterator_next(&iter)));
  247. regfree(&regexp);
  248. }
  249. /*--------------------------------------------------------- */
  250. unsigned short konf_tree__get_priority(const konf_tree_t * this)
  251. {
  252. return this->priority;
  253. }
  254. /*--------------------------------------------------------- */
  255. unsigned char konf_tree__get_priority_hi(const konf_tree_t * this)
  256. {
  257. return (unsigned char)(this->priority >> 8);
  258. }
  259. /*--------------------------------------------------------- */
  260. unsigned char konf_tree__get_priority_lo(const konf_tree_t * this)
  261. {
  262. return (unsigned char)(this->priority & 0xff);
  263. }
  264. /*--------------------------------------------------------- */
  265. bool_t konf_tree__get_splitter(const konf_tree_t * this)
  266. {
  267. return this->splitter;
  268. }
  269. /*--------------------------------------------------------- */
  270. void konf_tree__set_splitter(konf_tree_t *this, bool_t splitter)
  271. {
  272. this->splitter = splitter;
  273. }
  274. /*--------------------------------------------------------- */
  275. unsigned short konf_tree__get_seq_num(const konf_tree_t * this)
  276. {
  277. return this->seq_num;
  278. }
  279. /*--------------------------------------------------------- */
  280. void konf_tree__set_seq_num(konf_tree_t * this, unsigned short seq_num)
  281. {
  282. this->seq_num = seq_num;
  283. }
  284. /*--------------------------------------------------------- */
  285. unsigned short konf_tree__get_sub_num(const konf_tree_t * this)
  286. {
  287. return this->sub_num;
  288. }
  289. /*--------------------------------------------------------- */
  290. void konf_tree__set_sub_num(konf_tree_t * this, unsigned short sub_num)
  291. {
  292. this->sub_num = sub_num;
  293. }