Home | History | Annotate | Download | only in libcutils
      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 
     17 #include <string.h>
     18 #include <ctype.h>
     19 #include <stdlib.h>
     20 #include <fcntl.h>
     21 #include <unistd.h>
     22 
     23 #include <cutils/config_utils.h>
     24 #include <cutils/misc.h>
     25 
     26 cnode* config_node(const char *name, const char *value)
     27 {
     28     cnode *node;
     29 
     30     node = calloc(sizeof(cnode), 1);
     31     if(node) {
     32         node->name = name ? name : "";
     33         node->value = value ? value : "";
     34     }
     35 
     36     return node;
     37 }
     38 
     39 cnode* config_find(cnode *root, const char *name)
     40 {
     41     cnode *node, *match = NULL;
     42 
     43     /* we walk the whole list, as we need to return the last (newest) entry */
     44     for(node = root->first_child; node; node = node->next)
     45         if(!strcmp(node->name, name))
     46             match = node;
     47 
     48     return match;
     49 }
     50 
     51 static cnode* _config_create(cnode *root, const char *name)
     52 {
     53     cnode *node;
     54 
     55     node = config_node(name, NULL);
     56 
     57     if(root->last_child)
     58         root->last_child->next = node;
     59     else
     60         root->first_child = node;
     61 
     62     root->last_child = node;
     63 
     64     return node;
     65 }
     66 
     67 int config_bool(cnode *root, const char *name, int _default)
     68 {
     69     cnode *node;
     70 
     71     node = config_find(root, name);
     72     if(!node)
     73         return _default;
     74 
     75     switch(node->value[0]) {
     76     case 'y':
     77     case 'Y':
     78     case '1':
     79         return 1;
     80     default:
     81         return 0;
     82     }
     83 }
     84 
     85 const char* config_str(cnode *root, const char *name, const char *_default)
     86 {
     87     cnode *node;
     88 
     89     node = config_find(root, name);
     90     if(!node)
     91         return _default;
     92     return node->value;
     93 }
     94 
     95 void config_set(cnode *root, const char *name, const char *value)
     96 {
     97     cnode *node;
     98 
     99     node = config_find(root, name);
    100     if(node)
    101         node->value = value;
    102     else {
    103         node = _config_create(root, name);
    104         node->value = value;
    105     }
    106 }
    107 
    108 #define T_EOF 0
    109 #define T_TEXT 1
    110 #define T_DOT 2
    111 #define T_OBRACE 3
    112 #define T_CBRACE 4
    113 
    114 typedef struct
    115 {
    116     char *data;
    117     char *text;
    118     int len;
    119     char next;
    120 } cstate;
    121 
    122 static int _lex(cstate *cs, int value)
    123 {
    124     char c;
    125     char *s;
    126     char *data;
    127 
    128     data = cs->data;
    129 
    130     if(cs->next != 0) {
    131         c = cs->next;
    132         cs->next = 0;
    133         goto got_c;
    134     }
    135 
    136 restart:
    137     for(;;) {
    138         c = *data++;
    139     got_c:
    140         if(isspace(c))
    141             continue;
    142 
    143         switch(c) {
    144         case 0:
    145             return T_EOF;
    146 
    147         case '#':
    148             for(;;) {
    149                 switch(*data) {
    150                 case 0:
    151                     cs->data = data;
    152                     return T_EOF;
    153                 case '\n':
    154                     cs->data = data + 1;
    155                     goto restart;
    156                 default:
    157                     data++;
    158                 }
    159             }
    160             break;
    161 
    162         case '.':
    163             cs->data = data;
    164             return T_DOT;
    165 
    166         case '{':
    167             cs->data = data;
    168             return T_OBRACE;
    169 
    170         case '}':
    171             cs->data = data;
    172             return T_CBRACE;
    173 
    174         default:
    175             s = data - 1;
    176 
    177             if(value) {
    178                 for(;;) {
    179                     if(*data == 0) {
    180                         cs->data = data;
    181                         break;
    182                     }
    183                     if(*data == '\n') {
    184                         cs->data = data + 1;
    185                         *data-- = 0;
    186                         break;
    187                     }
    188                     data++;
    189                 }
    190 
    191                     /* strip trailing whitespace */
    192                 while(data > s){
    193                     if(!isspace(*data)) break;
    194                     *data-- = 0;
    195                 }
    196 
    197                 goto got_text;
    198             } else {
    199                 for(;;) {
    200                     if(isspace(*data)) {
    201                         *data = 0;
    202                         cs->data = data + 1;
    203                         goto got_text;
    204                     }
    205                     switch(*data) {
    206                     case 0:
    207                         cs->data = data;
    208                         goto got_text;
    209                     case '.':
    210                     case '{':
    211                     case '}':
    212                         cs->next = *data;
    213                         *data = 0;
    214                         cs->data = data + 1;
    215                         goto got_text;
    216                     default:
    217                         data++;
    218                     }
    219                 }
    220             }
    221         }
    222     }
    223 
    224 got_text:
    225     cs->text = s;
    226     return T_TEXT;
    227 }
    228 
    229 #if 0
    230 char *TOKENNAMES[] = { "EOF", "TEXT", "DOT", "OBRACE", "CBRACE" };
    231 
    232 static int lex(cstate *cs, int value)
    233 {
    234     int tok = _lex(cs, value);
    235     printf("TOKEN(%d) %s %s\n", value, TOKENNAMES[tok],
    236            tok == T_TEXT ? cs->text : "");
    237     return tok;
    238 }
    239 #else
    240 #define lex(cs,v) _lex(cs,v)
    241 #endif
    242 
    243 static int parse_expr(cstate *cs, cnode *node);
    244 
    245 static int parse_block(cstate *cs, cnode *node)
    246 {
    247     for(;;){
    248         switch(lex(cs, 0)){
    249         case T_TEXT:
    250             if(parse_expr(cs, node)) return -1;
    251             continue;
    252 
    253         case T_CBRACE:
    254             return 0;
    255 
    256         default:
    257             return -1;
    258         }
    259     }
    260 }
    261 
    262 static int parse_expr(cstate *cs, cnode *root)
    263 {
    264     cnode *node;
    265 
    266         /* last token was T_TEXT */
    267     node = config_find(root, cs->text);
    268     if(!node || *node->value)
    269         node = _config_create(root, cs->text);
    270 
    271     for(;;) {
    272         switch(lex(cs, 1)) {
    273         case T_DOT:
    274             if(lex(cs, 0) != T_TEXT)
    275                 return -1;
    276             node = _config_create(node, cs->text);
    277             continue;
    278 
    279         case T_TEXT:
    280             node->value = cs->text;
    281             return 0;
    282 
    283         case T_OBRACE:
    284             return parse_block(cs, node);
    285 
    286         default:
    287             return -1;
    288         }
    289     }
    290 }
    291 
    292 void config_load(cnode *root, char *data)
    293 {
    294     if(data != 0) {
    295         cstate cs;
    296         cs.data = data;
    297         cs.next = 0;
    298 
    299         for(;;) {
    300             switch(lex(&cs, 0)) {
    301             case T_TEXT:
    302                 if(parse_expr(&cs, root))
    303                     return;
    304                 break;
    305             default:
    306                 return;
    307             }
    308         }
    309     }
    310 }
    311 
    312 void config_load_file(cnode *root, const char *fn)
    313 {
    314     char *data;
    315     data = load_file(fn, 0);
    316     config_load(root, data);
    317 }
    318 
    319 void config_free(cnode *root)
    320 {
    321     cnode *cur = root->first_child;
    322 
    323     while (cur) {
    324         cnode *prev = cur;
    325         config_free(cur);
    326         cur = cur->next;
    327         free(prev);
    328     }
    329 }
    330