• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Data Structures
  • Files
  • Directories
  • File List
  • Globals

cfg_parser.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  * Standalone Configuration File Parser
00004  *
00005  * Copyright (C) 2008 iptelorg GmbH
00006  * Written by Jan Janak <jan@iptel.org>
00007  *
00008  * This file is part of SER, a free SIP server.
00009  *
00010  * SER is free software; you can redistribute it and/or modify it under the
00011  * terms of the GNU General Public License as published by the Free Software
00012  * Foundation; either version 2 of the License, or (at your option) any later
00013  * version.
00014  *
00015  * SER is distributed in the hope that it will be useful, but WITHOUT ANY
00016  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00017  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
00018  * details.
00019  *
00020  * You should have received a copy of the GNU General Public License along
00021  * with this program; if not, write to the Free Software Foundation, Inc., 
00022  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00023  */
00154 #include "cfg_parser.h"
00155 
00156 #include "mem/mem.h"
00157 #include "mem/shm_mem.h"
00158 #include "dprint.h"
00159 #include "trim.h"
00160 #include "ut.h"
00161 
00162 #include <string.h>
00163 #include <stdlib.h>
00164 #include <stdio.h>
00165 #include <libgen.h>
00166 
00167 
00169 enum st {
00170         ST_S,  
00171         ST_A,  
00172         ST_AE, 
00173         ST_Q,  
00174         ST_QE, 
00175         ST_C,  
00176         ST_CE, 
00177         ST_E,  
00178 };
00179 
00180 
00182 #define IS_ALPHA(c) \
00183     (((c) >= 'a' && (c) <= 'z') || \
00184      ((c) >= 'A' && (c) <= 'Z') || \
00185      ((c) >= '0' && (c) <= '9') || \
00186      (c) == '_')
00187 
00188 
00190 #define IS_DELIM(c) \
00191     ((c) == '=' || \
00192      (c) == ':' || \
00193      (c) == ';' || \
00194      (c) == '.' || \
00195      (c) == ',' || \
00196      (c) == '?' || \
00197      (c) == '[' || \
00198      (c) == ']' || \
00199      (c) == '/' || \
00200      (c) == '@' || \
00201      (c) == '!' || \
00202      (c) == '$' || \
00203      (c) == '%' || \
00204      (c) == '&' || \
00205      (c) == '*' || \
00206      (c) == '(' || \
00207      (c) == ')' || \
00208      (c) == '-' || \
00209      (c) == '+' || \
00210      (c) == '|' || \
00211      (c) == '\'')
00212 
00213 
00215 #define IS_WHITESPACE(c) ((c) == ' ' || (c) == '\t' || (c) == '\r') 
00216 #define IS_QUOTE(c)      ((c) == '\"')  /* Quote characters */
00217 #define IS_COMMENT(c)    ((c) == '#')   /* Characters that start comments */
00218 #define IS_ESCAPE(c)     ((c) == '\\')  /* Escape characters */
00219 #define IS_EOL(c)        ((c) == '\n')  /* End of line */
00220 
00221 
00225 #define PUSH(c)                            \
00226     if (token->val.len >= MAX_TOKEN_LEN) { \
00227         ERR("%s:%d:%d: Token too long\n",  \
00228         st->file, st->line, st->col);      \
00229         return -1;                         \
00230     }                                      \
00231     if (token->val.len == 0) {             \
00232          token->start.line = st->line;     \
00233          token->start.col = st->col;       \
00234     }                                      \
00235     token->val.s[token->val.len++] = (c);
00236 
00237 
00241 #define RETURN(c)               \
00242     token->end.line = st->line; \
00243     token->end.col = st->col;   \
00244     token->type = (c);          \
00245     print_token(token);         \
00246     return 0;
00247 
00248 
00252 #define READ_CHAR      \
00253      c = fgetc(st->f); \
00254      if (IS_EOL(c)) {  \
00255          st->line++;   \
00256          st->col = 0;  \
00257      } else {          \
00258          st->col++;    \
00259      }
00260 
00261 
00262 cfg_option_t cfg_bool_values[] = {
00263         {"yes",      .val = 1},
00264         {"true",     .val = 1},
00265         {"enable",   .val = 1},
00266         {"enabled",  .val = 1},
00267         {"1",        .val = 1},
00268         {"on",       .val = 1},
00269         {"no",       .val = 0},
00270         {"false",    .val = 0},
00271         {"disable",  .val = 0},
00272         {"disabled", .val = 0},
00273         {"0",        .val = 0},
00274         {"off",      .val = 0},
00275         {0}
00276 };
00277 
00278 
00279 static void print_token(cfg_token_t* token)
00280 {
00281 #ifdef EXTRA_DEBUG
00282         int i, j;
00283         char* buf;
00284 
00285         if ((buf = pkg_malloc(token->val.len * 2)) == NULL) {
00286                 DBG("token(%d, '%.*s', <%d,%d>-<%d,%d>)\n", 
00287                         token->type, STR_FMT(&token->val),
00288                         token->start.line, token->start.col, 
00289                         token->end.line, token->end.col);
00290         } else {
00291                 for(i = 0, j = 0; i < token->val.len; i++) {
00292                         switch(token->val.s[i]) {
00293                         case '\n': buf[j++] = '\\'; buf[j++] = 'n'; break;
00294                         case '\r': buf[j++] = '\\'; buf[j++] = 'r'; break;
00295                         case '\t': buf[j++] = '\\'; buf[j++] = 't'; break;
00296                         case '\0': buf[j++] = '\\'; buf[j++] = '0'; break;
00297                         case '\\': buf[j++] = '\\'; buf[j++] = '\\'; break;
00298                         default: buf[j++] = token->val.s[i];
00299                         }
00300                 }
00301                 DBG("token(%d, '%.*s', <%d,%d>-<%d,%d>)\n", 
00302                         token->type, j, buf,
00303                         token->start.line, token->start.col, 
00304                         token->end.line, token->end.col);
00305                 pkg_free(buf);
00306         }
00307 #endif /* EXTRA_DEBUG */
00308 }
00309 
00310 
00311 int cfg_get_token(cfg_token_t* token, cfg_parser_t* st, unsigned int flags)
00312 {
00313         static int look_ahead = EOF;
00314         int c;
00315         enum st state;
00316 
00317         state = ST_S;
00318         
00319         token->val.s = token->buf;
00320         token->val.len = 0;
00321 
00322         if (look_ahead != EOF) {
00323                 c = look_ahead;
00324                 look_ahead = EOF;
00325         } else {
00326                 READ_CHAR;
00327         }
00328 
00329         while(c != EOF) {
00330                 switch(state) {
00331                 case ST_S:
00332                         if (flags & CFG_EXTENDED_ALPHA) {
00333                                 if (IS_WHITESPACE(c)) {
00334                                              /* Do nothing */
00335                                 } else if (IS_ALPHA(c) ||
00336                                            IS_ESCAPE(c) ||
00337                                            IS_DELIM(c)) {
00338                                         PUSH(c);
00339                                         state = ST_A;
00340                                 } else if (IS_QUOTE(c)) {
00341                                         state = ST_Q;
00342                                 } else if (IS_COMMENT(c)) {
00343                                         state = ST_C;
00344                                 } else if (IS_EOL(c)) {
00345                                         PUSH(c);
00346                                         RETURN(c);
00347                                 } else {
00348                                         ERR("%s:%d:%d: Invalid character 0x%x\n", 
00349                                             st->file, st->line, st->col, c);
00350                                         return -1;
00351                                 }
00352                         } else {
00353                                 if (IS_WHITESPACE(c)) {
00354                                              /* Do nothing */
00355                                 } else if (IS_ALPHA(c)) {
00356                                         PUSH(c);
00357                                         state = ST_A;
00358                                 } else if (IS_QUOTE(c)) {
00359                                         state = ST_Q;
00360                                 } else if (IS_COMMENT(c)) {
00361                                         state = ST_C;
00362                                 } else if (IS_ESCAPE(c)) {
00363                                         state = ST_E;
00364                                 } else if (IS_DELIM(c) || IS_EOL(c)) {
00365                                         PUSH(c);
00366                                         RETURN(c);
00367                                 } else {
00368                                         ERR("%s:%d:%d: Invalid character 0x%x\n", 
00369                                             st->file, st->line, st->col, c);
00370                                         return -1;
00371                                 }
00372                         }
00373                         break;
00374 
00375                 case ST_A:
00376                         if (flags & CFG_EXTENDED_ALPHA) {
00377                                 if (IS_ALPHA(c) ||
00378                                     IS_DELIM(c) ||
00379                                     IS_QUOTE(c)) {
00380                                         PUSH(c);
00381                                 } else if (IS_ESCAPE(c)) {
00382                                         state = ST_AE;
00383                                 } else if (IS_COMMENT(c) || IS_EOL(c) || IS_WHITESPACE(c)) {
00384                                         look_ahead = c;
00385                                         RETURN(CFG_TOKEN_ALPHA);
00386                                 } else {
00387                                         ERR("%s:%d:%d: Invalid character 0x%x\n", 
00388                                             st->file, st->line, st->col, c);
00389                                         return -1;
00390                                 }
00391                         } else {
00392                                 if (IS_ALPHA(c)) {
00393                                         PUSH(c);
00394                                 } else if (IS_ESCAPE(c)) {
00395                                         state = ST_AE;
00396                                 } else if (IS_WHITESPACE(c) ||
00397                                            IS_DELIM(c) ||
00398                                            IS_QUOTE(c) ||
00399                                            IS_COMMENT(c) ||
00400                                            IS_EOL(c)) {
00401                                         look_ahead = c;
00402                                         RETURN(CFG_TOKEN_ALPHA);
00403                                 } else {
00404                                         ERR("%s:%d:%d: Invalid character 0x%x\n", 
00405                                             st->file, st->line, st->col, c);
00406                                         return -1;
00407                                 }
00408                         }
00409                         break;
00410 
00411                 case ST_AE:
00412                         if (IS_COMMENT(c) ||
00413                             IS_QUOTE(c) ||
00414                             IS_ESCAPE(c)) {
00415                                 PUSH(c);
00416                         } else if (c == 'r') {
00417                                 PUSH('\r');
00418                         } else if (c == 'n') {
00419                                 PUSH('\n');
00420                         } else if (c == 't') {
00421                                 PUSH('\t');
00422                         } else if (c == ' ') {
00423                                 PUSH(' ');
00424                         } else if (IS_EOL(c)) {
00425                                      /* Do nothing */
00426                         } else {
00427                                 ERR("%s:%d:%d: Unsupported escape character 0x%x\n", 
00428                                     st->file, st->line, st->col, c);
00429                                 return -1;
00430                         }
00431                         state = ST_A;
00432                         break;
00433 
00434                 case ST_Q:
00435                         if (IS_QUOTE(c)) {
00436                                 RETURN(CFG_TOKEN_STRING);
00437                         } else if (IS_ESCAPE(c)) {
00438                                 state = ST_QE;
00439                                 break;
00440                         } else {
00441                                 PUSH(c);
00442                         }
00443                         break;
00444 
00445                 case ST_QE:
00446                         if (IS_ESCAPE(c) ||
00447                             IS_QUOTE(c)) {
00448                                 PUSH(c);
00449                         } else if (c == 'n') {
00450                                 PUSH('\n');
00451                         } else if (c == 'r') {
00452                                 PUSH('\r');
00453                         } else if (c == 't') {
00454                                 PUSH('\t');
00455                         } else if (IS_EOL(c)) {
00456                                      /* Do nothing */
00457                         } else {
00458                                 ERR("%s:%d:%d: Unsupported escape character 0x%x\n", 
00459                                     st->file, st->line, st->col, c);
00460                                 return -1;
00461                         }
00462                         state = ST_Q;
00463                         break;
00464 
00465                 case ST_C:
00466                         if (IS_ESCAPE(c)) {
00467                                 state = ST_CE;
00468                         } else if (IS_EOL(c)) {
00469                                 state = ST_S;
00470                                 continue; /* Do not read a new char, return EOL */
00471                         } else {
00472                                      /* Do nothing */
00473                         }
00474                         break;
00475 
00476                 case ST_CE:
00477                         state = ST_C;
00478                         break;
00479 
00480                 case ST_E:
00481                         if (IS_COMMENT(c) ||
00482                             IS_QUOTE(c) ||
00483                             IS_ESCAPE(c)) {
00484                                 PUSH(c);
00485                                 RETURN(c);
00486                         } else if (c == 'r') {
00487                                 PUSH('\r');
00488                                 RETURN('\r');
00489                         } else if (c == 'n') {
00490                                 PUSH('\n');
00491                                 RETURN('\n');
00492                         } else if (c == 't') {
00493                                 PUSH('\t');
00494                                 RETURN('\t');
00495                         } else if (c == ' ') {
00496                                 PUSH(' ');
00497                                 RETURN(' ');
00498                         } else if (IS_EOL(c)) {
00499                                      /* Escped eol means no eol */
00500                                 state = ST_S;
00501                         } else {
00502                                 ERR("%s:%d:%d: Unsupported escape character 0x%x\n", 
00503                                     st->file, st->line, st->col, c);
00504                                 return -1;
00505                         }
00506                         break;
00507                 }
00508 
00509                 READ_CHAR;
00510         };
00511 
00512         switch(state) {
00513         case ST_S: 
00514         case ST_C:
00515         case ST_CE:
00516                 return 1;
00517 
00518         case ST_A:
00519                 RETURN(CFG_TOKEN_ALPHA);
00520 
00521         case ST_Q:
00522                 ERR("%s:%d:%d: Premature end of file, missing closing quote in"
00523                         " string constant\n", st->file, st->line, st->col);
00524                 return -1;
00525 
00526         case ST_QE:
00527         case ST_E:
00528         case ST_AE:
00529                 ERR("%s:%d:%d: Premature end of file, missing escaped character\n", 
00530                     st->file, st->line, st->col);
00531                 return -1;
00532         }
00533         BUG("%s:%d:%d: Invalid state %d\n",
00534                 st->file, st->line, st->col, state);
00535         return -1;
00536 }
00537 
00538 
00539 int cfg_parse_section(void* param, cfg_parser_t* st, unsigned int flags)
00540 {
00541         cfg_token_t t;
00542         int ret;
00543 
00544         ret = cfg_parse_str(param, st, flags);
00545         if (ret < 0) return ret;
00546         if (ret > 0) {
00547                 ERR("%s:%d:%d: Section name missing.\n",
00548                         st->file, st->line, st->col);
00549                 return ret;
00550         }
00551 
00552         ret = cfg_get_token(&t, st, flags);
00553         if (ret < 0) goto error;
00554         if (ret > 0) {
00555                 ERR("%s:%d:%d: Closing ']' missing\n", st->file, st->line, st->col);
00556                 goto error;
00557         }
00558         if (t.type != ']') {
00559                 ERR("%s:%d:%d: Syntax error, ']' expected\n", 
00560                     st->file, t.start.line, t.start.col);
00561                 goto error;
00562         }
00563 
00564         if (cfg_eat_eol(st, flags)) goto error;
00565         return 0;
00566 
00567  error:
00568         if (param && ((str*)param)->s) {
00569                 if (flags & CFG_STR_PKGMEM) {
00570                         pkg_free(((str*)param)->s);
00571                         ((str*)param)->s = NULL;
00572                 } else if (flags & CFG_STR_SHMMEM) {
00573                         shm_free(((str*)param)->s);
00574                         ((str*)param)->s = NULL;
00575                 } else if (flags & CFG_STR_MALLOC) {
00576                         free(((str*)param)->s);
00577                         ((str*)param)->s = NULL;
00578                 }               
00579         }
00580         return -1;
00581 }
00582 
00583 
00584 static char* get_base_name(str* filename)
00585 {
00586         char* tmp1, *tmp2, *res;
00587         int len;
00588 
00589         res = NULL;
00590         if ((tmp1 = as_asciiz(filename)) == NULL) {
00591                 ERR("cfg_parser: No memory left\n");
00592                 goto error;
00593         }
00594         
00595         if ((tmp2 = basename(tmp1)) == NULL) {
00596                 ERR("cfg_parser: Error in basename\n");
00597                 goto error;
00598         }
00599         len = strlen(tmp2);
00600 
00601         if ((res = pkg_malloc(len + 1)) == NULL) {
00602                 ERR("cfg_parser: No memory left");
00603                 goto error;
00604         }
00605         memcpy(res, tmp2, len + 1);
00606         pkg_free(tmp1);
00607         return res;
00608 
00609  error:
00610         if (tmp1) pkg_free(tmp1);
00611         return NULL;
00612 }
00613 
00614 
00615 
00624 cfg_parser_t* cfg_parser_init(str* basedir, str* filename)
00625 {
00626         cfg_parser_t* st;
00627         char* pathname, *base, *abs_pathname;
00628 
00629         abs_pathname = NULL;
00630         pathname = filename->s;
00631         st = NULL;
00632         base = NULL;
00633         
00634         /* if basedir == 0 or != "" get_abs_pathname */
00635         if (basedir == 0  || basedir->len != 0) {
00636                 if ((abs_pathname = get_abs_pathname(basedir, filename)) == NULL) {
00637                         ERR("cfg_parser: Error while converting %.*s to absolute"
00638                                         " pathname\n", STR_FMT(filename));
00639                         goto error;
00640                 }
00641                 pathname = abs_pathname;
00642         }
00643 
00644         if ((base = get_base_name(filename)) == NULL) goto error;
00645 
00646         if ((st = (cfg_parser_t*)pkg_malloc(sizeof(*st))) == NULL) {
00647                 ERR("cfg_parser: No memory left\n");
00648                 goto error;
00649         }
00650         memset(st, '\0', sizeof(*st));
00651 
00652         if ((st->f = fopen(pathname, "r")) == NULL) {
00653                 ERR("cfg_parser: Unable to open file '%s'\n", pathname);
00654                 goto error;
00655         }
00656 
00657         if (abs_pathname) pkg_free(abs_pathname);
00658 
00659         st->file = base;
00660         st->line = 1;
00661         st->col = 0;
00662         return st;
00663 
00664  error:
00665         if (st) {
00666                 if (st->f) fclose(st->f);
00667                 pkg_free(st);
00668         }
00669         if (base) pkg_free(base);
00670         if (abs_pathname) pkg_free(abs_pathname);
00671         return NULL;
00672 }
00673 
00674 
00675 void cfg_parser_close(cfg_parser_t* st)
00676 {
00677         if (!st) return;
00678         if (st->f) fclose(st->f);
00679         if (st->file) pkg_free(st->file);
00680         pkg_free(st);
00681 }
00682 
00683 
00684 void cfg_section_parser(cfg_parser_t* st, cfg_func_f parser, void* param)
00685 {
00686         if (st == NULL) return;
00687         st->section.parser = parser;
00688         st->section.param = param;
00689 }
00690 
00691 
00692 void cfg_set_options(cfg_parser_t* st, cfg_option_t* options)
00693 {
00694         if (st) st->options = options;
00695 }
00696 
00697 
00698 static int process_option(cfg_parser_t* st, cfg_option_t* opt)
00699 {
00700         if (opt->f) {
00701                 /* We have a function so store it and pass opt->dst to it */
00702                 if (opt->f(opt->param, st, opt->flags) < 0) return -1;
00703         } else {
00704                 /* We have no function, so if we have a pointer to some
00705                  * variable in opt->param then store the value of opt->i
00706                  * there, the variable is assumed to be of type i
00707                  */
00708                 if (opt->param) *(int*)opt->param = opt->val;
00709         }
00710         return 0;
00711 }
00712 
00713 
00714 int sr_cfg_parse(cfg_parser_t* st)
00715 {
00716         int ret;
00717         cfg_token_t t;
00718         cfg_option_t* opt;
00719 
00720         while(1) {
00721                 ret = cfg_get_token(&t, st, 0);
00722                 if (ret < 0) return ret;
00723                 if (ret > 0) break;
00724 
00725                 switch(t.type) {
00726                 case CFG_TOKEN_ALPHA:
00727                         /* Lookup the option name */
00728                         if ((opt = cfg_lookup_token(st->options, &t.val)) == NULL) {
00729                                 ERR("%s:%d:%d: Unsupported option '%.*s'\n", 
00730                                     st->file, t.start.line, t.start.col, STR_FMT(&t.val));
00731                                 return -1;
00732                         }
00733 
00734                         st->cur_opt = &t;
00735                         if (process_option(st, opt) < 0) return -1;
00736                         break;
00737 
00738                 case '[': 
00739                         if (st->section.parser == NULL) {
00740                                 ERR("%s:%d:%d: Syntax error\n", st->file,
00741                                         t.start.line, t.start.col);
00742                                 return -1;
00743                         }
00744                         if (st->section.parser(st->section.param, st, 0) < 0) return -1;
00745                         break;
00746 
00747                              /* Empty line */
00748                 case '\n': continue;
00749 
00750                 default:
00751                         ERR("%s:%d:%d: Syntax error\n", 
00752                             st->file, t.start.line, t.start.col);
00753                         return -1;
00754                 }
00755         }
00756         return 0;
00757 }
00758 
00759 
00760 cfg_option_t* cfg_lookup_token(cfg_option_t* table, str* token)
00761 {
00762         int len, i;
00763         int (*cmp)(const char* s1, const char* s2, size_t n) = NULL;
00764 
00765 
00766         if (table == NULL) return NULL;
00767 
00768         for(i = 0; table[i].name; i++) {
00769                 len = strlen(table[i].name);
00770 
00771                 if (table[i].flags & CFG_PREFIX) {
00772                         if (token->len < len) continue;
00773                 } else {
00774                         if (token->len != len) continue;
00775                 }
00776 
00777                 if (table[i].flags & CFG_CASE_SENSITIVE) cmp = strncmp;
00778                 else cmp = strncasecmp;
00779 
00780                 if (cmp(token->s, table[i].name, len)) continue;
00781                 return table + i;
00782         }
00783         if (table[i].flags & CFG_DEFAULT) {
00784                 return table + i;
00785         }
00786         return NULL;
00787 }
00788 
00789 
00790 int cfg_eat_equal(cfg_parser_t* st, unsigned int flags)
00791 {
00792         cfg_token_t t;
00793         int ret;
00794 
00795         ret = cfg_get_token(&t, st, flags);
00796         if (ret < 0) return ret;
00797         if (ret > 0) {
00798                 ERR("%s:%d:%d: Delimiter '=' missing\n", 
00799                     st->file, st->line, st->col);
00800                 return ret;
00801         }
00802 
00803         if (t.type != '=') {
00804                 ERR("%s:%d:%d: Syntax error, '=' expected\n", 
00805                     st->file, t.start.line, t.start.col);
00806                 return -1;
00807         }
00808         return 0;
00809 }
00810 
00811 
00812 int cfg_eat_eol(cfg_parser_t* st, unsigned int flags)
00813 {
00814         cfg_token_t t;
00815         int ret;
00816 
00817         /* Skip EOL */
00818         ret = cfg_get_token(&t, st, 0);
00819         if (ret < 0) return ret;
00820         if (ret > 0) return 0;
00821         if (t.type != '\n') {
00822                 ERR("%s:%d:%d: End of line expected\n", 
00823                         st->file, t.start.line, t.start.col);
00824                 return -1;
00825         }
00826         return 0;
00827 }
00828 
00829 
00830 int cfg_parse_enum(void* param, cfg_parser_t* st, unsigned int flags)
00831 {
00832         int ret;
00833     cfg_token_t t;
00834         cfg_option_t* values, *val;
00835         
00836         values = (cfg_option_t*)param;
00837 
00838         ret = cfg_get_token(&t, st, flags);
00839         if (ret != 0) return ret;
00840 
00841         if (t.type != CFG_TOKEN_ALPHA && t.type != CFG_TOKEN_STRING) {
00842                 ERR("%s:%d:%d: Invalid enum value '%.*s'\n",
00843                     st->file, t.start.line, t.start.col, STR_FMT(&t.val));
00844                 return -1;
00845         }
00846 
00847         if (values) {
00848                 if ((val = cfg_lookup_token(values, &t.val)) == NULL) {
00849                         ERR("%s:%d:%d Unsupported enum value '%.*s'\n", 
00850                                 st->file, t.start.line, t.start.col, STR_FMT(&t.val));
00851                         return -1;
00852                 }
00853                 return process_option(st, val);
00854         } else {
00855                 return 0;
00856         }
00857 }
00858 
00859 
00860 int cfg_parse_enum_opt(void* param, cfg_parser_t* st, unsigned int flags)
00861 {
00862         int ret;
00863 
00864         if (cfg_eat_equal(st, flags)) return -1;
00865 
00866         ret = cfg_parse_enum(param, st, CFG_EXTENDED_ALPHA | flags);
00867         if (ret > 0) {
00868                 ERR("%s:%d:%d: Option value missing\n",
00869                     st->file, st->line, st->col);
00870                 return ret;
00871         } else if (ret < 0) return ret;
00872 
00873         if (cfg_eat_eol(st, flags)) return -1;
00874         return 0;
00875 }
00876 
00877 
00878 int cfg_parse_str(void* param, cfg_parser_t* st, unsigned int flags)
00879 {
00880         str* val;
00881         int ret;
00882         char* buf;
00883     cfg_token_t t;
00884         
00885         ret = cfg_get_token(&t, st, flags);
00886         if (ret != 0) return ret;
00887         
00888         if (t.type != CFG_TOKEN_ALPHA && t.type != CFG_TOKEN_STRING) {
00889                 ERR("%s:%d:%d: Invalid string value '%.*s', a string expected.\n",
00890                     st->file, t.start.line, t.start.col, STR_FMT(&t.val));
00891                 return -1;
00892         }
00893 
00894         if (!param) return 0;
00895         val = (str*)param;
00896 
00897         if (flags & CFG_STR_STATIC) {
00898                 if (!val->s || val->len <= t.val.len) {
00899                         ERR("%s:%d:%d: Destination string buffer too small\n",
00900                                 st->file, t.start.line, t.start.col);
00901                         return -1;
00902                 }
00903                 buf = val->s;
00904         } else if (flags & CFG_STR_SHMMEM) {
00905                 if ((buf = shm_malloc(t.val.len + 1)) == NULL) {
00906                         ERR("%s:%d:%d: Out of shared memory\n", st->file,
00907                                 t.start.line, t.start.col);
00908                         return -1;
00909                 }
00910                 if (val->s) shm_free(val->s);
00911         } else if (flags & CFG_STR_MALLOC) {
00912                 if ((buf = malloc(t.val.len + 1)) == NULL) {
00913                         ERR("%s:%d:%d: Out of malloc memory\n", st->file,
00914                                 t.start.line, t.start.col);
00915                         return -1;
00916                 }
00917                 if (val->s) free(val->s);
00918         } else if (flags & CFG_STR_PKGMEM) {
00919                 if ((buf = pkg_malloc(t.val.len + 1)) == NULL) {
00920                         ERR("%s:%d:%d: Out of private memory\n", st->file,
00921                                 t.start.line, t.start.col);
00922                         return -1;
00923                 }
00924                 if (val->s) pkg_free(val->s);
00925         } else {
00926                 *val = t.val;
00927                 return 0;
00928         }
00929         
00930         memcpy(buf, t.val.s, t.val.len);
00931         buf[t.val.len] = '\0';
00932         val->s = buf;
00933         val->len = t.val.len;
00934         return 0;
00935 }
00936 
00937 
00938 int cfg_parse_str_opt(void* param, cfg_parser_t* st, unsigned int flags)
00939 {
00940         int ret;
00941 
00942         if (cfg_eat_equal(st, flags)) return -1;
00943 
00944         ret = cfg_parse_str(param, st, flags | CFG_EXTENDED_ALPHA);
00945         if (ret > 0) {
00946                 ERR("%s:%d:%d: Option value missing\n",
00947                     st->file, st->line, st->col);
00948         } else if (ret < 0) return ret;
00949 
00950         if (cfg_eat_eol(st, flags)) return -1;
00951         return 0;
00952 }
00953 
00954 
00955 int cfg_parse_int(void* param, cfg_parser_t* st, unsigned int flags)
00956 {
00957         int* val;
00958         int ret, tmp;
00959         cfg_token_t t;
00960 
00961         val = (int*)param;
00962 
00963         ret = cfg_get_token(&t, st, flags);
00964         if (ret != 0) return ret;
00965 
00966         if (t.type != CFG_TOKEN_ALPHA && t.type != CFG_TOKEN_STRING) {
00967                 ERR("%s:%d:%d: Invalid integer value '%.*s'\n", 
00968                     st->file, t.start.line, t.start.col, STR_FMT(&t.val));
00969                 return -1;
00970         }
00971 
00972         if (str2sint(&t.val, &tmp) < 0) {
00973                 ERR("%s:%d:%d: Invalid integer value '%.*s'\n",
00974                         st->file, t.start.line, t.start.col, STR_FMT(&t.val));
00975                 return -1;
00976         }
00977 
00978         if (val) *val = tmp;
00979         return 0;
00980 }
00981 
00982 
00983 int cfg_parse_int_opt(void* param, cfg_parser_t* st, unsigned int flags)
00984 {
00985         int ret;
00986 
00987         if (cfg_eat_equal(st, flags)) return -1;
00988 
00989         ret = cfg_parse_int(param, st, flags);
00990         if (ret > 0) {
00991                 ERR("%s:%d:%d: Option value missing\n", 
00992                     st->file, st->line, st->col);
00993         } else if (ret < 0) return ret;
00994 
00995         if (cfg_eat_eol(st, flags)) return -1;
00996         return 0;
00997 }
00998 
00999 
01000 int cfg_parse_bool(void* param, cfg_parser_t* st, unsigned int flags)
01001 {
01002         int ret, *val;
01003         cfg_token_t t;
01004         cfg_option_t* map;
01005         
01006         val = (int*)param;
01007 
01008         ret = cfg_get_token(&t, st, flags);
01009         if (ret != 0) return ret;
01010 
01011         if (t.type != CFG_TOKEN_ALPHA && t.type != CFG_TOKEN_STRING) {
01012                 ERR("%s:%d:%d: Invalid option value '%.*s', boolean expected\n", 
01013                     st->file, t.start.line, t.start.col, STR_FMT(&t.val));
01014                 return -1;
01015         }
01016 
01017         if ((map = cfg_lookup_token(cfg_bool_values, &t.val)) == NULL) {
01018                 ERR("%s:%d:%d: Invalid option value '%.*s', boolean expected\n", 
01019                     st->file, t.start.line, t.start.col, STR_FMT(&t.val));
01020                 return -1;
01021         }
01022 
01023         if (val) *val = map->val;
01024         return 0;
01025 }
01026 
01027 
01028 int cfg_parse_bool_opt(void* param, cfg_parser_t* st, unsigned int flags)
01029 {
01030         int ret;
01031         if (cfg_eat_equal(st, flags)) return -1;
01032 
01033     ret = cfg_parse_bool(param, st, CFG_EXTENDED_ALPHA | flags);
01034         if (ret > 0) {
01035                 ERR("%s:%d:%d: Option value missing\n", 
01036                     st->file, st->line, st->col);
01037         } else if (ret < 0) return ret;
01038 
01039         if (cfg_eat_eol(st, flags)) return -1;
01040         return 0;
01041 }

Generated on Tue May 22 2012 13:10:04 for SIP Router by  doxygen 1.7.1