config_utils.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. /*
  2. * Copyright (C) 2007 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include <cutils/config_utils.h>
  17. #include <string.h>
  18. #include <ctype.h>
  19. #include <stdlib.h>
  20. #include <fcntl.h>
  21. #include <unistd.h>
  22. #include <cutils/misc.h>
  23. cnode* config_node(const char *name, const char *value)
  24. {
  25. cnode* node = static_cast<cnode*>(calloc(sizeof(cnode), 1));
  26. if(node) {
  27. node->name = name ? name : "";
  28. node->value = value ? value : "";
  29. }
  30. return node;
  31. }
  32. cnode* config_find(cnode *root, const char *name)
  33. {
  34. cnode *node, *match = NULL;
  35. /* we walk the whole list, as we need to return the last (newest) entry */
  36. for(node = root->first_child; node; node = node->next)
  37. if(!strcmp(node->name, name))
  38. match = node;
  39. return match;
  40. }
  41. static cnode* _config_create(cnode *root, const char *name)
  42. {
  43. cnode *node;
  44. node = config_node(name, NULL);
  45. if(root->last_child)
  46. root->last_child->next = node;
  47. else
  48. root->first_child = node;
  49. root->last_child = node;
  50. return node;
  51. }
  52. int config_bool(cnode *root, const char *name, int _default)
  53. {
  54. cnode *node;
  55. node = config_find(root, name);
  56. if(!node)
  57. return _default;
  58. switch(node->value[0]) {
  59. case 'y':
  60. case 'Y':
  61. case '1':
  62. return 1;
  63. default:
  64. return 0;
  65. }
  66. }
  67. const char* config_str(cnode *root, const char *name, const char *_default)
  68. {
  69. cnode *node;
  70. node = config_find(root, name);
  71. if(!node)
  72. return _default;
  73. return node->value;
  74. }
  75. void config_set(cnode *root, const char *name, const char *value)
  76. {
  77. cnode *node;
  78. node = config_find(root, name);
  79. if(node)
  80. node->value = value;
  81. else {
  82. node = _config_create(root, name);
  83. node->value = value;
  84. }
  85. }
  86. #define T_EOF 0
  87. #define T_TEXT 1
  88. #define T_DOT 2
  89. #define T_OBRACE 3
  90. #define T_CBRACE 4
  91. typedef struct
  92. {
  93. char *data;
  94. char *text;
  95. int len;
  96. char next;
  97. } cstate;
  98. static int _lex(cstate *cs, int value)
  99. {
  100. char c;
  101. char *s;
  102. char *data;
  103. data = cs->data;
  104. if(cs->next != 0) {
  105. c = cs->next;
  106. cs->next = 0;
  107. goto got_c;
  108. }
  109. restart:
  110. for(;;) {
  111. c = *data++;
  112. got_c:
  113. if(isspace(c))
  114. continue;
  115. switch(c) {
  116. case 0:
  117. return T_EOF;
  118. case '#':
  119. for(;;) {
  120. switch(*data) {
  121. case 0:
  122. cs->data = data;
  123. return T_EOF;
  124. case '\n':
  125. cs->data = data + 1;
  126. goto restart;
  127. default:
  128. data++;
  129. }
  130. }
  131. break;
  132. case '.':
  133. cs->data = data;
  134. return T_DOT;
  135. case '{':
  136. cs->data = data;
  137. return T_OBRACE;
  138. case '}':
  139. cs->data = data;
  140. return T_CBRACE;
  141. default:
  142. s = data - 1;
  143. if(value) {
  144. for(;;) {
  145. if(*data == 0) {
  146. cs->data = data;
  147. break;
  148. }
  149. if(*data == '\n') {
  150. cs->data = data + 1;
  151. *data-- = 0;
  152. break;
  153. }
  154. data++;
  155. }
  156. /* strip trailing whitespace */
  157. while(data > s){
  158. if(!isspace(*data)) break;
  159. *data-- = 0;
  160. }
  161. goto got_text;
  162. } else {
  163. for(;;) {
  164. if(isspace(*data)) {
  165. *data = 0;
  166. cs->data = data + 1;
  167. goto got_text;
  168. }
  169. switch(*data) {
  170. case 0:
  171. cs->data = data;
  172. goto got_text;
  173. case '.':
  174. case '{':
  175. case '}':
  176. cs->next = *data;
  177. *data = 0;
  178. cs->data = data + 1;
  179. goto got_text;
  180. default:
  181. data++;
  182. }
  183. }
  184. }
  185. }
  186. }
  187. got_text:
  188. cs->text = s;
  189. return T_TEXT;
  190. }
  191. #if 0
  192. char *TOKENNAMES[] = { "EOF", "TEXT", "DOT", "OBRACE", "CBRACE" };
  193. static int lex(cstate *cs, int value)
  194. {
  195. int tok = _lex(cs, value);
  196. printf("TOKEN(%d) %s %s\n", value, TOKENNAMES[tok],
  197. tok == T_TEXT ? cs->text : "");
  198. return tok;
  199. }
  200. #else
  201. #define lex(cs,v) _lex(cs,v)
  202. #endif
  203. static int parse_expr(cstate *cs, cnode *node);
  204. static int parse_block(cstate *cs, cnode *node)
  205. {
  206. for(;;){
  207. switch(lex(cs, 0)){
  208. case T_TEXT:
  209. if(parse_expr(cs, node)) return -1;
  210. continue;
  211. case T_CBRACE:
  212. return 0;
  213. default:
  214. return -1;
  215. }
  216. }
  217. }
  218. static int parse_expr(cstate *cs, cnode *root)
  219. {
  220. cnode *node;
  221. /* last token was T_TEXT */
  222. node = config_find(root, cs->text);
  223. if(!node || *node->value)
  224. node = _config_create(root, cs->text);
  225. for(;;) {
  226. switch(lex(cs, 1)) {
  227. case T_DOT:
  228. if(lex(cs, 0) != T_TEXT)
  229. return -1;
  230. node = _config_create(node, cs->text);
  231. continue;
  232. case T_TEXT:
  233. node->value = cs->text;
  234. return 0;
  235. case T_OBRACE:
  236. return parse_block(cs, node);
  237. default:
  238. return -1;
  239. }
  240. }
  241. }
  242. void config_load(cnode *root, char *data)
  243. {
  244. if(data != 0) {
  245. cstate cs;
  246. cs.data = data;
  247. cs.next = 0;
  248. for(;;) {
  249. switch(lex(&cs, 0)) {
  250. case T_TEXT:
  251. if(parse_expr(&cs, root))
  252. return;
  253. break;
  254. default:
  255. return;
  256. }
  257. }
  258. }
  259. }
  260. void config_load_file(cnode *root, const char *fn)
  261. {
  262. char* data = static_cast<char*>(load_file(fn, nullptr));
  263. config_load(root, data);
  264. // TODO: deliberate leak :-/
  265. }
  266. void config_free(cnode *root)
  267. {
  268. cnode *cur = root->first_child;
  269. while (cur) {
  270. cnode *prev = cur;
  271. config_free(cur);
  272. cur = cur->next;
  273. free(prev);
  274. }
  275. }