conf.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. /*
  2. * conf.c
  3. *
  4. * This file provides the implementation of a conf class
  5. */
  6. #include "private.h"
  7. #include "clish/variable.h"
  8. #include "lub/argv.h"
  9. #include "lub/string.h"
  10. #include "lub/ctype.h"
  11. #include <assert.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <stdio.h>
  15. /*---------------------------------------------------------
  16. * PRIVATE META FUNCTIONS
  17. *--------------------------------------------------------- */
  18. int clish_conf_bt_compare(const void *clientnode, const void *clientkey)
  19. {
  20. const clish_conf_t *this = clientnode;
  21. char *pri = (char *)clientkey;
  22. char *line = ((char *)clientkey + 1);
  23. if ((clish_conf__get_priority(this) == *pri) || (0 == *pri))
  24. return lub_string_nocasecmp(this->line, line);
  25. return (clish_conf__get_priority(this) - *pri);
  26. }
  27. /*-------------------------------------------------------- */
  28. static void clish_conf_key(lub_bintree_key_t * key, char priority, char *text)
  29. {
  30. char *pri = (char *)key;
  31. char *line = ((char *)key + 1);
  32. /* fill out the opaque key */
  33. *pri = priority;
  34. strcpy(line, text);
  35. }
  36. /*-------------------------------------------------------- */
  37. void clish_conf_bt_getkey(const void *clientnode, lub_bintree_key_t * key)
  38. {
  39. const clish_conf_t *this = clientnode;
  40. clish_conf_key(key, clish_conf__get_priority(this), this->line);
  41. }
  42. /*---------------------------------------------------------
  43. * PRIVATE METHODS
  44. *--------------------------------------------------------- */
  45. static void
  46. clish_conf_init(clish_conf_t * this, const char *line,
  47. const clish_command_t * cmd)
  48. {
  49. /* set up defaults */
  50. this->line = lub_string_dup(line);
  51. this->cmd = cmd;
  52. /* Be a good binary tree citizen */
  53. lub_bintree_node_init(&this->bt_node);
  54. /* initialise the tree of commands for this conf */
  55. lub_bintree_init(&this->tree,
  56. clish_conf_bt_offset(),
  57. clish_conf_bt_compare, clish_conf_bt_getkey);
  58. }
  59. /*--------------------------------------------------------- */
  60. static void clish_conf_fini(clish_conf_t * this)
  61. {
  62. clish_conf_t *conf;
  63. unsigned i;
  64. /* delete each conf held by this conf */
  65. while ((conf = lub_bintree_findfirst(&this->tree))) {
  66. /* remove the conf from the tree */
  67. lub_bintree_remove(&this->tree, conf);
  68. /* release the instance */
  69. clish_conf_delete(conf);
  70. }
  71. /* free our memory */
  72. lub_string_free(this->line);
  73. this->line = NULL;
  74. }
  75. /*---------------------------------------------------------
  76. * PUBLIC META FUNCTIONS
  77. *--------------------------------------------------------- */
  78. size_t clish_conf_bt_offset(void)
  79. {
  80. return offsetof(clish_conf_t, bt_node);
  81. }
  82. /*--------------------------------------------------------- */
  83. clish_conf_t *clish_conf_new(const char *line, const clish_command_t * cmd)
  84. {
  85. clish_conf_t *this = malloc(sizeof(clish_conf_t));
  86. if (this) {
  87. clish_conf_init(this, line, cmd);
  88. }
  89. return this;
  90. }
  91. /*---------------------------------------------------------
  92. * PUBLIC METHODS
  93. *--------------------------------------------------------- */
  94. void clish_conf_delete(clish_conf_t * this)
  95. {
  96. clish_conf_fini(this);
  97. free(this);
  98. }
  99. void clish_conf_fprintf(FILE * stream, clish_conf_t * this)
  100. {
  101. clish_conf_t *conf;
  102. lub_bintree_iterator_t iter;
  103. if (this->cmd && this->line) {
  104. char *space;
  105. int depth = clish_command__get_depth(this->cmd);
  106. space = malloc(depth + 1);
  107. memset(space, ' ', depth);
  108. space[depth] = '\0';
  109. fprintf(stream, "%s%s\n", space, this->line);
  110. free(space);
  111. }
  112. /* iterate child elements */
  113. if (conf = lub_bintree_findfirst(&this->tree)) {
  114. for (lub_bintree_iterator_init(&iter, &this->tree, conf);
  115. conf; conf = lub_bintree_iterator_next(&iter)) {
  116. if (clish_conf__get_depth(conf) == 0)
  117. fprintf(stream, "!\n");
  118. clish_conf_fprintf(stream, conf);
  119. }
  120. }
  121. }
  122. /*--------------------------------------------------------- */
  123. clish_conf_t *clish_conf_new_conf(clish_conf_t * this,
  124. const char *line, const clish_command_t * cmd)
  125. {
  126. /* allocate the memory for a new child element */
  127. clish_conf_t *conf = clish_conf_new(line, cmd);
  128. assert(conf);
  129. /* ...insert it into the binary tree for this conf */
  130. if (-1 == lub_bintree_insert(&this->tree, conf)) {
  131. /* inserting a duplicate command is bad */
  132. clish_conf_delete(conf);
  133. conf = NULL;
  134. }
  135. return conf;
  136. }
  137. /*--------------------------------------------------------- */
  138. clish_conf_t *clish_conf_find_conf(clish_conf_t * this,
  139. const char *line,
  140. const clish_command_t * cmd)
  141. {
  142. lub_bintree_key_t key;
  143. char priority = 0;
  144. if (cmd)
  145. priority = clish_command__get_priority(cmd);
  146. clish_conf_key(&key, priority, line);
  147. return lub_bintree_find(&this->tree, &key);
  148. }
  149. /*--------------------------------------------------------- */
  150. unsigned clish_conf__get_depth(const clish_conf_t * this)
  151. {
  152. if (!this->cmd)
  153. return 0;
  154. return clish_command__get_depth(this->cmd);
  155. }
  156. /*--------------------------------------------------------- */
  157. char clish_conf__get_priority(const clish_conf_t * this)
  158. {
  159. if (!this->cmd)
  160. return 0;
  161. return clish_command__get_priority(this->cmd);
  162. }