Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals

config.c

Go to the documentation of this file.
00001 /* 00002 * Asterisk -- A telephony toolkit for Linux. 00003 * 00004 * Configuration File Parser 00005 * 00006 * Copyright (C) 1999, Mark Spencer 00007 * 00008 * Mark Spencer <markster@linux-support.net> 00009 * 00010 * This program is free software, distributed under the terms of 00011 * the GNU General Public License 00012 */ 00013 00014 #include <stdio.h> 00015 #include <unistd.h> 00016 #include <stdlib.h> 00017 #include <string.h> 00018 #include <errno.h> 00019 #include <time.h> 00020 #include <asterisk/config.h> 00021 #include <asterisk/options.h> 00022 #include <asterisk/logger.h> 00023 #include <asterisk/utils.h> 00024 #include "asterisk.h" 00025 #include "astconf.h" 00026 00027 #define MAX_INCLUDE_LEVEL 10 00028 00029 struct ast_category { 00030 char name[80]; 00031 struct ast_variable *root; 00032 struct ast_category *next; 00033 #ifdef PRESERVE_COMMENTS 00034 struct ast_comment *precomments; 00035 struct ast_comment *sameline; 00036 #endif 00037 }; 00038 00039 struct ast_config { 00040 /* Maybe this structure isn't necessary but we'll keep it 00041 for now */ 00042 struct ast_category *root; 00043 struct ast_category *prev; 00044 #ifdef PRESERVE_COMMENTS 00045 struct ast_comment *trailingcomments; 00046 #endif 00047 }; 00048 00049 #ifdef PRESERVE_COMMENTS 00050 struct ast_comment_struct 00051 { 00052 struct ast_comment *root; 00053 struct ast_comment *prev; 00054 }; 00055 #endif 00056 00057 static char *strip(char *buf) 00058 { 00059 char *start; 00060 /* Strip off trailing whitespace, returns, etc */ 00061 while(!ast_strlen_zero(buf) && (buf[strlen(buf)-1]<33)) 00062 buf[strlen(buf)-1] = '\0'; 00063 start = buf; 00064 /* Strip off leading whitespace, returns, etc */ 00065 while(*start && (*start < 33)) 00066 *start++ = '\0'; 00067 return start; 00068 } 00069 00070 #ifdef PRESERVE_COMMENTS 00071 static void free_comments(struct ast_comment *com) 00072 { 00073 struct ast_comment *l; 00074 while (com) { 00075 l = com; 00076 com = com->next; 00077 free(l); 00078 } 00079 } 00080 #endif 00081 00082 void ast_destroy(struct ast_config *ast) 00083 { 00084 struct ast_category *cat, *catn; 00085 struct ast_variable *v, *vn; 00086 00087 if (!ast) 00088 return; 00089 00090 cat = ast->root; 00091 while(cat) { 00092 v = cat->root; 00093 while(v) { 00094 vn = v; 00095 free(v->name); 00096 free(v->value); 00097 #ifdef PRESERVE_COMMENTS 00098 free_comments(v->precomments); 00099 free_comments(v->sameline); 00100 #endif 00101 v = v->next; 00102 free(vn); 00103 } 00104 catn = cat; 00105 #ifdef PRESERVE_COMMENTS 00106 free_comments(cat->precomments); 00107 free_comments(cat->sameline); 00108 #endif 00109 cat = cat->next; 00110 free(catn); 00111 } 00112 #ifdef PRESERVE_COMMENTS 00113 free_comments(ast->trailingcomments); 00114 #endif 00115 free(ast); 00116 } 00117 00118 int ast_true(char *s) 00119 { 00120 if (!s) 00121 return 0; 00122 /* Determine if this is a true value */ 00123 if (!strcasecmp(s, "yes") || 00124 !strcasecmp(s, "true") || 00125 !strcasecmp(s, "y") || 00126 !strcasecmp(s, "t") || 00127 !strcasecmp(s, "1")) 00128 return -1; 00129 return 0; 00130 } 00131 00132 int ast_false(char *s) 00133 { 00134 if (!s) 00135 return 0; 00136 /* Determine if this is a false value */ 00137 if (!strcasecmp(s, "no") || 00138 !strcasecmp(s, "false") || 00139 !strcasecmp(s, "n") || 00140 !strcasecmp(s, "f") || 00141 !strcasecmp(s, "0")) 00142 return -1; 00143 return 0; 00144 } 00145 00146 struct ast_variable *ast_variable_browse(struct ast_config *config, char *category) 00147 { 00148 struct ast_category *cat; 00149 cat = config->root; 00150 while(cat) { 00151 if (cat->name == category) 00152 return cat->root; 00153 cat = cat->next; 00154 } 00155 cat = config->root; 00156 while(cat) { 00157 if (!strcasecmp(cat->name, category)) 00158 return cat->root; 00159 cat = cat->next; 00160 } 00161 return NULL; 00162 } 00163 00164 char *ast_variable_retrieve(struct ast_config *config, char *category, char *value) 00165 { 00166 struct ast_variable *v; 00167 if (category) { 00168 v = ast_variable_browse(config, category); 00169 while (v) { 00170 if (value == v->name) 00171 return v->value; 00172 v=v->next; 00173 } 00174 v = ast_variable_browse(config, category); 00175 while (v) { 00176 if (!strcasecmp(value, v->name)) 00177 return v->value; 00178 v=v->next; 00179 } 00180 } else { 00181 struct ast_category *cat; 00182 cat = config->root; 00183 while(cat) { 00184 v = cat->root; 00185 while (v) { 00186 if (!strcasecmp(value, v->name)) 00187 return v->value; 00188 v=v->next; 00189 } 00190 cat = cat->next; 00191 } 00192 } 00193 return NULL; 00194 } 00195 00196 #ifdef PRESERVE_COMMENTS 00197 int ast_variable_delete(struct ast_config *cfg, char *category, char *variable, char *value) 00198 { 00199 struct ast_variable *v, *pv, *bv, *bpv; 00200 struct ast_category *cat; 00201 cat = cfg->root; 00202 while(cat) { 00203 if (cat->name == category) { 00204 break; 00205 } 00206 cat = cat->next; 00207 } 00208 if (!cat) { 00209 cat = cfg->root; 00210 while(cat) { 00211 if (!strcasecmp(cat->name, category)) { 00212 break; 00213 } 00214 cat = cat->next; 00215 } 00216 } 00217 if (!cat) 00218 return -1; 00219 v = cat->root; 00220 pv = NULL; 00221 while (v) { 00222 if ((variable == v->name) && (!value || !strcmp(v->value, value))) 00223 break; 00224 pv = v; 00225 v=v->next; 00226 } 00227 if (!v) { 00228 /* Get the last one that looks like it */ 00229 bv = NULL; 00230 bpv = NULL; 00231 v = cat->root; 00232 pv = NULL; 00233 while (v) { 00234 if (!strcasecmp(variable, v->name) && (!value || !strcmp(v->value, value))) { 00235 bv = v; 00236 bpv = pv; 00237 } 00238 pv = v; 00239 v=v->next; 00240 } 00241 v = bv; 00242 } 00243 00244 if (v) { 00245 /* Unlink from original position */ 00246 if (pv) 00247 pv->next = v->next; 00248 else 00249 cat->root = v->next; 00250 v->next = NULL; 00251 free(v->name); 00252 if (v->value) 00253 free(v->value); 00254 free_comments(v->sameline); 00255 free_comments(v->precomments); 00256 return 0; 00257 } 00258 return -1; 00259 } 00260 00261 int ast_category_delete(struct ast_config *cfg, char *category) 00262 { 00263 struct ast_variable *v, *pv; 00264 struct ast_category *cat, *cprev; 00265 cat = cfg->root; 00266 cprev = NULL; 00267 while(cat) { 00268 if (cat->name == category) { 00269 break; 00270 } 00271 cprev = cat; 00272 cat = cat->next; 00273 } 00274 if (!cat) { 00275 cat = cfg->root; 00276 cprev = NULL; 00277 while(cat) { 00278 if (!strcasecmp(cat->name, category)) { 00279 break; 00280 } 00281 cprev = cat; 00282 cat = cat->next; 00283 } 00284 } 00285 if (!cat) 00286 return -1; 00287 /* Unlink it */ 00288 if (cprev) 00289 cprev->next = cat->next; 00290 else 00291 cfg->root = cat->next; 00292 v = cat->root; 00293 while (v) { 00294 pv = v; 00295 v=v->next; 00296 if (pv->value) 00297 free(pv->value); 00298 if (pv->name) 00299 free(pv->name); 00300 free_comments(pv->sameline); 00301 free_comments(pv->precomments); 00302 free(pv); 00303 } 00304 free_comments(cat->sameline); 00305 free_comments(cat->precomments); 00306 free(cat); 00307 return 0; 00308 } 00309 00310 struct ast_variable *ast_variable_append_modify(struct ast_config *config, char *category, char *variable, char *value, int newcat, int newvar, int move) 00311 { 00312 struct ast_variable *v, *pv=NULL, *bv, *bpv; 00313 struct ast_category *cat, *pcat; 00314 cat = config->root; 00315 if (!newcat) { 00316 while(cat) { 00317 if (cat->name == category) { 00318 break; 00319 } 00320 cat = cat->next; 00321 } 00322 if (!cat) { 00323 cat = config->root; 00324 while(cat) { 00325 if (!strcasecmp(cat->name, category)) { 00326 break; 00327 } 00328 cat = cat->next; 00329 } 00330 } 00331 } 00332 if (!cat) { 00333 cat = malloc(sizeof(struct ast_category)); 00334 if (!cat) 00335 return NULL; 00336 memset(cat, 0, sizeof(struct ast_category)); 00337 strncpy(cat->name, category, sizeof(cat->name)); 00338 if (config->root) { 00339 /* Put us at the end */ 00340 pcat = config->root; 00341 while(pcat->next) 00342 pcat = pcat->next; 00343 pcat->next = cat; 00344 } else { 00345 /* We're the first one */ 00346 config->root = cat; 00347 } 00348 00349 } 00350 if (!newvar) { 00351 v = cat->root; 00352 pv = NULL; 00353 while (v) { 00354 if (variable == v->name) 00355 break; 00356 pv = v; 00357 v=v->next; 00358 } 00359 if (!v) { 00360 /* Get the last one that looks like it */ 00361 bv = NULL; 00362 bpv = NULL; 00363 v = cat->root; 00364 pv = NULL; 00365 while (v) { 00366 if (!strcasecmp(variable, v->name)) { 00367 bv = v; 00368 bpv = pv; 00369 } 00370 pv = v; 00371 v=v->next; 00372 } 00373 v = bv; 00374 } 00375 } else v = NULL; 00376 if (v && move) { 00377 /* Unlink from original position */ 00378 if (pv) 00379 pv->next = v->next; 00380 else 00381 cat->root = v->next; 00382 v->next = NULL; 00383 } 00384 if (!v) { 00385 v = malloc(sizeof(struct ast_variable)); 00386 if (!v) 00387 return NULL; 00388 memset(v, 0, sizeof(struct ast_variable)); 00389 v->name = strdup(variable); 00390 move = 1; 00391 } 00392 if (v->value) 00393 free(v->value); 00394 if (value) 00395 v->value = strdup(value); 00396 else 00397 v->value = strdup(""); 00398 if (move) { 00399 if (cat->root) { 00400 pv = cat->root; 00401 while (pv->next) 00402 pv = pv->next; 00403 pv->next = v; 00404 } else { 00405 cat->root = v; 00406 } 00407 } 00408 return v; 00409 } 00410 #endif 00411 00412 int ast_category_exist(struct ast_config *config, char *category_name) 00413 { 00414 struct ast_category *category = NULL; 00415 00416 category = config->root; 00417 00418 while(category) { 00419 if (!strcasecmp(category->name,category_name)) 00420 return 1; 00421 category = category->next; 00422 } 00423 00424 return 0; 00425 } 00426 00427 #ifdef PRESERVE_COMMENTS 00428 static struct ast_comment *build_comment(char *cmt) 00429 { 00430 struct ast_comment *c; 00431 int len = strlen(cmt) + 1; 00432 c = malloc(sizeof(struct ast_comment) + len); 00433 if (c) { 00434 /* Memset the header */ 00435 memset(c, 0, sizeof(struct ast_comment)); 00436 /* Copy the rest */ 00437 strcpy(c->cmt, cmt); 00438 } 00439 return c; 00440 } 00441 #endif 00442 00443 static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, int includelevel 00444 #ifdef PRESERVE_COMMENTS 00445 , struct ast_comment_struct *acs 00446 #endif 00447 ); 00448 00449 static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, char *buf, int lineno, char *configfile, int includelevel 00450 #ifdef PRESERVE_COMMENTS 00451 ,struct ast_comment_struct *acs 00452 #endif 00453 ) 00454 { 00455 char *c; 00456 char *cur; 00457 struct ast_variable *v; 00458 #ifdef PRESERVE_COMMENTS 00459 struct ast_comment *com = NULL; 00460 #endif 00461 int object; 00462 /* Strip off lines using ; as comment */ 00463 c = strchr(buf, ';'); 00464 if (c) { 00465 *c = '\0'; 00466 #ifdef PRESERVE_COMMENTS 00467 c++; 00468 if (*c != '!') 00469 com = build_comment(c); 00470 #endif 00471 } 00472 cur = strip(buf); 00473 if (!ast_strlen_zero(cur)) { 00474 /* Actually parse the entry */ 00475 if (cur[0] == '[') { 00476 /* A category header */ 00477 c = strchr(cur, ']'); 00478 if (c) { 00479 *c = 0; 00480 *_tmpc = malloc(sizeof(struct ast_category)); 00481 if (!*_tmpc) { 00482 ast_destroy(tmp); 00483 ast_log(LOG_WARNING, 00484 "Out of memory, line %d\n", lineno); 00485 return -1; 00486 } 00487 memset(*_tmpc, 0, sizeof(struct ast_category)); 00488 strncpy((*_tmpc)->name, cur+1, sizeof((*_tmpc)->name) - 1); 00489 (*_tmpc)->root = NULL; 00490 #ifdef PRESERVE_COMMENTS 00491 (*_tmpc)->precomments = acs->root; 00492 (*_tmpc)->sameline = com; 00493 #endif 00494 if (!tmp->prev) 00495 tmp->root = *_tmpc; 00496 else 00497 tmp->prev->next = *_tmpc; 00498 00499 tmp->prev = *_tmpc; 00500 #ifdef PRESERVE_COMMENTS 00501 acs->root = NULL; 00502 acs->prev = NULL; 00503 #endif 00504 *_last = NULL; 00505 } else { 00506 ast_log(LOG_WARNING, 00507 "parse error: no closing ']', line %d of %s\n", lineno, configfile); 00508 } 00509 } else if (cur[0] == '#') { 00510 /* A directive */ 00511 cur++; 00512 c = cur; 00513 while(*c && (*c > 32)) c++; 00514 if (*c) { 00515 *c = '\0'; 00516 c++; 00517 /* Find real argument */ 00518 while(*c && (*c < 33)) c++; 00519 if (!*c) 00520 c = NULL; 00521 } else 00522 c = NULL; 00523 if (!strcasecmp(cur, "include")) { 00524 /* A #include */ 00525 if (c) { 00526 while((*c == '<') || (*c == '>') || (*c == '\"')) c++; 00527 /* Get rid of leading mess */ 00528 cur = c; 00529 while(!ast_strlen_zero(cur)) { 00530 c = cur + strlen(cur) - 1; 00531 if ((*c == '>') || (*c == '<') || (*c == '\"')) 00532 *c = '\0'; 00533 else 00534 break; 00535 } 00536 if (includelevel < MAX_INCLUDE_LEVEL) { 00537 __ast_load(cur, tmp, _tmpc, _last, includelevel + 1 00538 #ifdef PRESERVE_COMMENTS 00539 ,acs 00540 #endif 00541 ); 00542 } else 00543 ast_log(LOG_WARNING, "Maximum Include level (%d) exceeded\n", includelevel); 00544 } else 00545 ast_log(LOG_WARNING, "Directive '#include' needs an argument (filename) at line %d of %s\n", lineno, configfile); 00546 /* Strip off leading and trailing "'s and <>'s */ 00547 } else 00548 ast_log(LOG_WARNING, "Unknown directive '%s' at line %d of %s\n", cur, lineno, configfile); 00549 } else { 00550 /* Just a line (variable = value) */ 00551 if (!*_tmpc) { 00552 ast_log(LOG_WARNING, 00553 "parse error: No category context for line %d of %s\n", lineno, configfile); 00554 ast_destroy(tmp); 00555 return -1; 00556 } 00557 c = strchr(cur, '='); 00558 if (c) { 00559 *c = 0; 00560 c++; 00561 /* Ignore > in => */ 00562 if (*c== '>') { 00563 object = 1; 00564 c++; 00565 } else 00566 object = 0; 00567 v = malloc(sizeof(struct ast_variable)); 00568 if (v) { 00569 memset(v, 0, sizeof(struct ast_variable)); 00570 v->next = NULL; 00571 v->name = strdup(strip(cur)); 00572 v->value = strdup(strip(c)); 00573 v->lineno = lineno; 00574 v->object = object; 00575 /* Put and reset comments */ 00576 #ifdef PRESERVE_COMMENTS 00577 v->precomments = acs->root; 00578 v->sameline = com; 00579 acs->prev = NULL; 00580 acs->root = NULL; 00581 #endif 00582 v->blanklines = 0; 00583 if (*_last) 00584 (*_last)->next = v; 00585 else 00586 (*_tmpc)->root = v; 00587 *_last = v; 00588 } else { 00589 ast_destroy(tmp); 00590 ast_log(LOG_WARNING, "Out of memory, line %d\n", lineno); 00591 return -1; 00592 } 00593 } else { 00594 ast_log(LOG_WARNING, "No '=' (equal sign) in line %d of %s\n", lineno, configfile); 00595 } 00596 00597 } 00598 } else { 00599 /* store any comments if there are any */ 00600 #ifdef PRESERVE_COMMENTS 00601 if (com) { 00602 if (acs->prev) 00603 acs->prev->next = com; 00604 else 00605 acs->root = com; 00606 acs->prev = com; 00607 } else { 00608 if (*_last) 00609 (*_last)->blanklines++; 00610 00611 } 00612 #endif 00613 } 00614 return 0; 00615 } 00616 00617 #ifdef PRESERVE_COMMENTS 00618 static void dump_comments(FILE *f, struct ast_comment *comment) 00619 { 00620 while (comment) { 00621 fprintf(f, ";%s", comment->cmt); 00622 comment = comment->next; 00623 } 00624 } 00625 #endif 00626 00627 int ast_save(char *configfile, struct ast_config *cfg, char *generator) 00628 { 00629 FILE *f; 00630 char fn[256]; 00631 char date[256]; 00632 time_t t; 00633 struct ast_variable *var; 00634 struct ast_category *cat; 00635 int blanklines = 0; 00636 if (configfile[0] == '/') { 00637 strncpy(fn, configfile, sizeof(fn)-1); 00638 } else { 00639 snprintf(fn, sizeof(fn), "%s/%s", AST_CONFIG_DIR, configfile); 00640 } 00641 time(&t); 00642 strncpy(date, ctime(&t), sizeof(date)); 00643 if ((f = fopen(fn, "w"))) { 00644 if ((option_verbose > 1) && !option_debug) 00645 ast_verbose( VERBOSE_PREFIX_2 "Saving '%s': ", fn); 00646 fprintf(f, ";!\n"); 00647 fprintf(f, ";! Automatically generated configuration file\n"); 00648 fprintf(f, ";! Filename: %s (%s)\n", configfile, fn); 00649 fprintf(f, ";! Generator: %s\n", generator); 00650 fprintf(f, ";! Creation Date: %s", date); 00651 fprintf(f, ";!\n"); 00652 cat = cfg->root; 00653 while(cat) { 00654 #ifdef PRESERVE_COMMENTS 00655 /* Dump any precomments */ 00656 dump_comments(f, cat->precomments); 00657 #endif 00658 /* Dump section with any appropriate comment */ 00659 #ifdef PRESERVE_COMMENTS 00660 if (cat->sameline) 00661 fprintf(f, "[%s] ; %s\n", cat->name, cat->sameline->cmt); 00662 else 00663 #endif 00664 fprintf(f, "[%s]\n", cat->name); 00665 var = cat->root; 00666 while(var) { 00667 #ifdef PRESERVE_COMMENTS 00668 dump_comments(f, var->precomments); 00669 #endif 00670 if (var->sameline) 00671 fprintf(f, "%s %s %s ; %s\n", var->name, (var->object ? "=>" : "="), var->value, var->sameline->cmt); 00672 else 00673 fprintf(f, "%s %s %s\n", var->name, (var->object ? "=>" : "="), var->value); 00674 if (var->blanklines) { 00675 blanklines = var->blanklines; 00676 while (blanklines) { 00677 fprintf(f, "\n"); 00678 blanklines--; 00679 } 00680 } 00681 00682 var = var->next; 00683 } 00684 #if 0 00685 /* Put an empty line */ 00686 fprintf(f, "\n"); 00687 #endif 00688 cat = cat->next; 00689 } 00690 #ifdef PRESERVE_COMMENTS 00691 dump_comments(f, cfg->trailingcomments); 00692 #endif 00693 } else { 00694 if (option_debug) 00695 printf("Unable to open for writing: %s\n", fn); 00696 else if (option_verbose > 1) 00697 printf( "Unable to write (%s)", strerror(errno)); 00698 return -1; 00699 } 00700 fclose(f); 00701 return 0; 00702 } 00703 00704 static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, int includelevel 00705 #ifdef PRESERVE_COMMENTS 00706 , struct ast_comment_struct *acs 00707 #endif 00708 ) 00709 { 00710 char fn[256]; 00711 char buf[512]; 00712 FILE *f; 00713 int lineno=0; 00714 int master=0; 00715 00716 if (configfile[0] == '/') { 00717 strncpy(fn, configfile, sizeof(fn)-1); 00718 } else { 00719 snprintf(fn, sizeof(fn), "%s/%s", (char *)ast_config_AST_CONFIG_DIR, configfile); 00720 } 00721 if ((option_verbose > 1) && !option_debug) { 00722 ast_verbose( VERBOSE_PREFIX_2 "Parsing '%s': ", fn); 00723 fflush(stdout); 00724 } 00725 if ((f = fopen(fn, "r"))) { 00726 if (option_debug) 00727 ast_log(LOG_DEBUG, "Parsing %s\n", fn); 00728 else if (option_verbose > 1) 00729 ast_verbose( "Found\n"); 00730 if (!tmp) { 00731 tmp = malloc(sizeof(struct ast_config)); 00732 if (tmp) 00733 memset(tmp, 0, sizeof(struct ast_config)); 00734 00735 master = 1; 00736 } 00737 if (!tmp) { 00738 ast_log(LOG_WARNING, "Out of memory\n"); 00739 fclose(f); 00740 return NULL; 00741 } 00742 while(!feof(f)) { 00743 lineno++; 00744 if (fgets(buf, sizeof(buf), f)) { 00745 if (cfg_process(tmp, _tmpc, _last, buf, lineno, configfile, includelevel 00746 #ifdef PRESERVE_COMMENTS 00747 , acs 00748 #endif 00749 )) { 00750 fclose(f); 00751 return NULL; 00752 } 00753 } 00754 } 00755 fclose(f); 00756 } else { 00757 if (option_debug) 00758 ast_log(LOG_DEBUG, "No file to parse: %s\n", fn); 00759 else if (option_verbose > 1) 00760 ast_verbose( "Not found (%s)\n", strerror(errno)); 00761 } 00762 #ifdef PRESERVE_COMMENTS 00763 if (master) { 00764 /* Keep trailing comments */ 00765 tmp->trailingcomments = acs->root; 00766 acs->root = NULL; 00767 acs->prev = NULL; 00768 } 00769 #endif 00770 return tmp; 00771 } 00772 00773 struct ast_config *ast_load(char *configfile) 00774 { 00775 struct ast_category *tmpc=NULL; 00776 struct ast_variable *last = NULL; 00777 #ifdef PRESERVE_COMMENTS 00778 struct ast_comment_struct acs = { NULL, NULL }; 00779 #endif 00780 return __ast_load(configfile, NULL, &tmpc, &last, 0 00781 #ifdef PRESERVE_COMMENTS 00782 ,&acs 00783 #endif 00784 ); 00785 } 00786 00787 char *ast_category_browse(struct ast_config *config, char *prev) 00788 { 00789 struct ast_category *cat; 00790 if (!prev) { 00791 if (config->root) 00792 return config->root->name; 00793 else 00794 return NULL; 00795 } 00796 cat = config->root; 00797 while(cat) { 00798 if (cat->name == prev) { 00799 if (cat->next) 00800 return cat->next->name; 00801 else 00802 return NULL; 00803 } 00804 cat = cat->next; 00805 } 00806 cat = config->root; 00807 while(cat) { 00808 if (!strcasecmp(cat->name, prev)) { 00809 if (cat->next) 00810 return cat->next->name; 00811 else 00812 return NULL; 00813 } 00814 cat = cat->next; 00815 } 00816 return NULL; 00817 }

Generated on Sat Jun 12 16:40:57 2004 for Asterisk by doxygen 1.3.7