tree.c 7.1 KB

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