UNIXworkcode

1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright 2013 Olaf Wintermann. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include "conf.h" 30 31 #include <string.h> 32 33 int cfg_parse_basic_file(ConfigParser *parser, FILE *in) { 34 parser->lines = NULL; 35 UcxMempool *mp = ucx_mempool_new(512); 36 parser->mp = mp->allocator; 37 38 // one logical line over many lines 39 sstr_t mline; 40 mline.ptr = NULL; 41 mline.length = 0; 42 ConfigLine *start_line; 43 ConfigLine *end_line; 44 45 // read file 46 sstr_t l; 47 while((l = cfg_readln(in)).ptr != NULL) { 48 void *org_ptr = l.ptr; 49 50 // put the line to the list 51 ConfigLine *line = OBJ_NEW(parser->mp, ConfigLine); 52 line->line = sstrdup_a(parser->mp, l); // TODO: check for 0-len str 53 line->object = NULL; 54 line->type = LINE_OTHER; 55 if(parser->lines) { 56 parser->lines = ucx_list_append_a(parser->mp, parser->lines, line); 57 } else { 58 parser->lines = ucx_list_append_a(parser->mp, parser->lines, line); 59 } 60 61 // check if the line contains something 62 l = cfg_trim_comment(l); 63 line->type = cfg_get_basic_type(l); 64 65 if(line->type == LINE_OTHER) { 66 // check for multi line 67 if(mline.ptr != NULL) { 68 // concate lines 69 char *ptr = ucx_mempool_malloc( 70 mp, 71 mline.length + l.length + 1); 72 73 memcpy(ptr, mline.ptr, mline.length); 74 memcpy(ptr + mline.length - 1, l.ptr, l.length); 75 mline.length += l.length; 76 free(mline.ptr); 77 mline.ptr = ptr; 78 mline.ptr[mline.length] = 0; 79 80 end_line = line; 81 82 line->type = LINE_MULTI; 83 } 84 if(l.ptr[l.length - 1] == '\\') { 85 if(mline.ptr == NULL) { 86 mline = sstrdup_a(parser->mp, l); 87 start_line = line; 88 } 89 } else { 90 // this line is complete so we can parse it 91 sstr_t ll; // we parse this line 92 93 if(mline.ptr == NULL) { 94 // single line 95 ll = l; 96 start_line = line; 97 end_line = line; 98 } else { 99 ll = mline; 100 } 101 102 // parse 103 int r = parser->parse(parser, start_line, end_line, ll); 104 105 // clean up 106 if(mline.ptr != NULL) { 107 free(mline.ptr); 108 mline.ptr = NULL; 109 mline.length = 0; 110 start_line = NULL; 111 end_line = NULL; 112 } 113 114 if(r != 0) { 115 free(org_ptr); 116 return -1; 117 } 118 } 119 } 120 121 free(org_ptr); 122 } 123 124 return 0; 125 } 126 127 sstr_t cfg_readln(FILE *file) { 128 sstr_t ns; 129 ns.ptr = NULL; 130 ns.length = 0; 131 132 if(!feof(file)) { 133 char buf[512]; 134 buf[0] = 0; 135 int len = 512; 136 137 if(fgets(buf, len, file) == NULL) { 138 return ns; 139 } 140 141 if(*buf == 0) { 142 printf("???\n"); 143 return ns; 144 } 145 146 char *ptr; 147 if((ptr = strrchr(buf, '\n'))) { 148 ptr[0] = 0; 149 } 150 151 sstr_t line = sstr(buf); 152 return sstrdup(line); 153 } 154 155 sstr_t s; 156 s.ptr = NULL; 157 s.length = 0; 158 return s; 159 } 160 161 162 /* 163 * removes a comment from the line 164 */ 165 sstr_t cfg_trim_comment(sstr_t line) { 166 sstr_t nl = line; 167 for(int i=0;i<line.length;i++) { 168 if(line.ptr[i] == '#') { 169 if(i > 0) { 170 nl.ptr = line.ptr + i - 1; 171 nl.length = i; 172 break; 173 } else { 174 nl.ptr = line.ptr; 175 nl.length = 0; 176 break; 177 } 178 } 179 } 180 return sstrtrim(nl); 181 } 182 183 /* 184 * gets the first parameter in the params string and returns a new string 185 * containing the other parameters or an empty string, if there are no more 186 * parameters 187 */ 188 sstr_t cfg_param(sstr_t params, sstr_t *name, sstr_t *value) { 189 name->ptr = NULL; 190 name->length = 0; 191 value->ptr = NULL; 192 value->length = 0; 193 194 // get name 195 int i; 196 for(i=0;i<params.length;i++) { 197 char c = params.ptr[i]; 198 if(c == '=') { 199 break; 200 } else if(c < 33) { 201 // no '=' means there is only a name, no value 202 name->ptr = params.ptr; 203 name->length = i; 204 205 params.ptr = params.ptr + i; 206 params.length -= i; 207 return sstrtrim(params); 208 } 209 } 210 211 name->ptr = params.ptr; 212 name->length = i; 213 i++; 214 215 // get value 216 if(i>=params.length) { 217 sstr_t ns; 218 ns.ptr = NULL; 219 ns.length = 0; 220 return ns; 221 } 222 223 int quote = 0; 224 value->ptr = params.ptr + i; 225 for(;i<params.length;i++) { 226 char c = params.ptr[i]; 227 if(c == '""') { 228 if(quote) { 229 break; // end of quoted value 230 } else { 231 quote = 1; 232 value->ptr++; 233 } 234 } else if(!quote && c < 33) { 235 break; // end of value 236 } 237 } 238 239 if(quote) { 240 // if the value is quoted, i points to the last quote char 241 value->length = i - name->length - 2; // subtract the quotes 242 i++; // set i behind the last quote 243 } else { 244 // i points to a white space char, which must be subtraced 245 value->length = i - name->length - 1; 246 } 247 248 if(value->length <= 0) { 249 value->length = 0; 250 value->ptr = NULL; 251 } 252 253 // create new params string 254 params.ptr += i; 255 params.length -= i; 256 return sstrtrim(params); 257 } 258 259 /* 260 * gets a value from a parameter 261 */ 262 sstr_t cfg_param_get(UcxList *list, sstr_t name) { 263 while(list != NULL) { 264 ConfigParam *param = list->data; 265 if(!sstrcmp(param->name, name)) { 266 return param->value; 267 } 268 list = list->next; 269 } 270 sstr_t ns; 271 ns.ptr = NULL; 272 ns.length = 0; 273 return ns; 274 } 275 276 /* 277 * parses a line containing a directive and returns a ConfigDirective object 278 * or NULL if an error occurs 279 */ 280 ConfigDirective* cfg_parse_directive(sstr_t line, UcxAllocator *mp) { 281 if(line.length < 6) { 282 log_ereport(LOG_FAILURE, "cfg_parse_directive: line too short"); 283 return NULL; // line too short 284 } 285 286 sstr_t name; 287 288 int i; 289 for(i=0;i<line.length;i++) { 290 if(line.ptr[i] < 33) { 291 break; 292 } 293 } 294 name.ptr = line.ptr; 295 name.length = i; 296 297 // create directive object 298 ConfigDirective *directive = OBJ_NEW(mp, ConfigDirective); 299 directive->directive_type = sstrdup_a(mp, name); 300 directive->type_num = cfg_get_directive_type_num(name); 301 directive->condition = NULL; // set later by main parsing function 302 //directive->param = NULL; 303 304 sstr_t param_str; 305 param_str.ptr = name.ptr + i; 306 param_str.length = line.length - i; 307 param_str = sstrtrim(param_str); 308 directive->value = sstrdup_a(mp, param_str); 309 310 /* 311 sstr_t pname; 312 sstr_t pvalue; 313 for(;;) { 314 param_str = cfg_param(param_str, &pname, &pvalue); 315 if(pname.length <= 0) { 316 break; 317 } 318 319 320 // create param object 321 ConfigParam *param = OBJ_NEW(mp, ConfigParam); 322 param->name = sstrdup_mp(mp, pname); 323 324 if(pvalue.length > 0) { 325 param->value = sstrdup_mp(mp, pvalue); 326 } else { 327 param->value.ptr = NULL; 328 param->value.length = 0; 329 } 330 331 // add param to list 332 333 //directive->param = ucx_list_append(directive->param, param); 334 } 335 */ 336 337 return directive; 338 } 339 340 UcxList* cfg_param_list(sstr_t param_str, UcxAllocator *mp) { 341 sstr_t pname; 342 sstr_t pvalue; 343 UcxList *plist = NULL; 344 for(;;) { 345 param_str = cfg_param(param_str, &pname, &pvalue); 346 if(pname.length <= 0) { 347 break; 348 } 349 350 // create param object 351 ConfigParam *param = OBJ_NEW(mp, ConfigParam); 352 param->name = sstrdup_a(mp, pname); 353 354 if(pvalue.length > 0) { 355 param->value = sstrdup_a(mp, pvalue); 356 } else { 357 param->value.ptr = NULL; 358 param->value.length = 0; 359 } 360 361 // add param to list 362 plist = ucx_list_append_a(mp, plist, param); 363 } 364 return plist; 365 } 366 367 368 369 /* 370 * gets the directive type number from a type string 371 * valid types are: 372 * AuthTrans 0 373 * NameTrans 1 374 * PathCheck 2 375 * ObjectType 3 376 * Service 4 377 * AddLog 5 378 * Init 6 379 */ 380 int cfg_get_directive_type_num(sstr_t type) { 381 /* get nsapi function type */ 382 383 // TODO: replace hard coded numbers 384 int dt = -1; 385 if(sstrcmp(type, sstr("AuthTrans")) == 0) { 386 dt = NSAPIAuthTrans; 387 } else if(sstrcmp(type, sstr("NameTrans")) == 0) { 388 dt = NSAPINameTrans; 389 } else if(sstrcmp(type, sstr("PathCheck")) == 0) { 390 dt = NSAPIPathCheck; 391 } else if(sstrcmp(type, sstr("ObjectType")) == 0) { 392 dt = NSAPIObjectType; 393 } else if(sstrcmp(type, sstr("Service")) == 0) { 394 dt = NSAPIService; 395 } else if(sstrcmp(type, sstr("Error")) == 0) { 396 dt = NSAPIError; 397 } else if(sstrcmp(type, sstr("AddLog")) == 0) { 398 dt = NSAPIAddLog; 399 } else if(sstrcmp(type, sstr("Init")) == 0) { 400 dt = INIT_DIRECTIVE; 401 } 402 return dt; 403 } 404 405 /* 406 * checks if the line contains only a comment or space 407 */ 408 int cfg_get_basic_type(sstr_t line) { 409 if(line.length == 0) { 410 return LINE_NOCONTENT; 411 } else if(line.ptr[0] == '#') { 412 return LINE_NOCONTENT; 413 } 414 return LINE_OTHER; 415 } 416 417 /* 418 * checks if the line contains a begin/end tag or a directive 419 */ 420 int cfg_get_line_type(sstr_t line) { 421 if(line.length < 3) { 422 // this line is to short to be correct 423 return LINE_ERROR; 424 } 425 426 if(line.ptr[0] == '<') { 427 // start or end tag 428 // TODO: check for space between '<' and '/' 429 if(line.ptr[1] == '/') { 430 return LINE_END_TAG; 431 } else { 432 return LINE_BEGIN_TAG; 433 } 434 } else { 435 return LINE_DIRECTIVE; 436 } 437 } 438 439 int cfg_get_tag_type(sstr_t tag) { 440 if(!sstrcmp(tag, sstr("Object"))) { 441 return TAG_OBJECT; 442 } else if(!sstrcmp(tag, sstr("If"))) { 443 return TAG_IF; 444 } else if(!sstrcmp(tag, sstr("ElseIf"))) { 445 return TAG_ELSEIF; 446 } else if(!sstrcmp(tag, sstr("Else"))) { 447 return TAG_ELSE; 448 } else if(!sstrcmp(tag, sstr("Client"))) { 449 return TAG_CLIENT; 450 } 451 return -1; 452 } 453 454 /* 455 * returns the name of the ending tag 456 * on error, this functions returns a zero length string 457 */ 458 sstr_t cfg_get_end_tag_name(sstr_t line) { 459 sstr_t ns; 460 ns.ptr = NULL; 461 ns.length = 0; 462 463 if(line.length < 4) { 464 // minimum of 4 chars: </a> 465 return ns; 466 } 467 468 sstr_t name; 469 name.ptr = line.ptr + 2; 470 name.length = line.length - 3; 471 472 // check for </ > frame 473 if(line.ptr[0] != '<' 474 || line.ptr[1] != '/' 475 || line.ptr[line.length - 1] != '>') 476 { 477 return ns; 478 } 479 480 return sstrtrim(name); 481 } 482 483 ConfigTag* cfg_parse_begin_tag(sstr_t line, UcxAllocator *mp) { 484 if(line.length < 4) { 485 return NULL; // this line can't contain a valid tag 486 } 487 488 if(line.ptr[0] != '<' || line.ptr[line.length - 1] != '>') { 489 return NULL; // syntax error 490 } 491 492 sstr_t name; 493 name.ptr = line.ptr + 1; 494 int i; 495 for(i=1;i<line.length - 1;i++) { 496 if(line.ptr[i] < 33) { // char is space 497 break; 498 } 499 } 500 name.length = i - 1; 501 if(name.length < 1) { 502 return NULL; // syntax error 503 } 504 505 // create tag object 506 ConfigTag *tag = OBJ_NEW(mp, ConfigTag); 507 tag->name = sstrdup_a(mp, name); 508 tag->param = NULL; 509 510 // parse parameters 511 sstr_t param_str; 512 param_str.ptr = line.ptr + i; 513 param_str.length = line.length - name.length - 2; 514 param_str = sstrtrim(param_str); 515 if(param_str.length == 0) { 516 return tag; // no parameters 517 } 518 tag->param_str = sstrdup_a(mp, param_str); 519 520 sstr_t pname; 521 sstr_t pvalue; 522 for(;;) { 523 param_str = cfg_param(param_str, &pname, &pvalue); 524 if(pname.length == 0) { 525 break; 526 } 527 528 // create param object 529 ConfigParam *param = OBJ_NEW(mp, ConfigParam); 530 param->name = sstrdup_a(mp, pname); 531 if(pvalue.length > 0) { 532 param->value = sstrdup_a(mp, pvalue); 533 } else { 534 param->value.ptr = NULL; 535 param->value.length = 0; 536 } 537 538 // add param to list 539 tag->param = ucx_list_append_a(mp, tag->param, param); 540 } 541 542 return tag; 543 } 544 545 546 /* directive functions */ 547 548 /* 549 * gets a ConfigDirective with a specific name from a List of directives 550 * returns a directive or NULL, if the directive cannot be found 551 */ 552 ConfigDirective* cfg_directivelist_get(UcxList *dirs, sstr_t name) { 553 while(dirs != NULL) { 554 ConfigDirective *d = dirs->data; 555 if(d != NULL) { 556 if(!sstrcmp(d->directive_type, name)) { 557 return d; 558 } 559 } 560 dirs = dirs->next; 561 } 562 return NULL; 563 } 564 565 sstr_t cfg_directivelist_get_str(UcxList *dirs, sstr_t name) { 566 ConfigDirective *d = cfg_directivelist_get(dirs, name); 567 if(d == NULL) { 568 sstr_t n; 569 n.ptr = NULL; 570 n.length = 0; 571 return n; 572 } 573 //return cfg_directive_pstr1(d); 574 return d->value; 575 } 576 577 /* 578 * returns the name of the first parameter of the directive 579 * useful for 'name value' directives 580 */ 581 /* 582 sstr_t cfg_directive_pstr1(ConfigDirective *dir) { 583 if(dir->param == NULL) { 584 fprintf(stderr, "%s", "Error: cfg_directive_pstr1: param is NULL\n"); 585 sstr_t n; 586 n.ptr = NULL; 587 n.length = 0; 588 return n; 589 } 590 591 ConfigParam *p = dir->param->data; 592 return p->name; 593 } 594 */ 595 596 static void cfg_list_free(void *list) { 597 ucx_list_free(list); 598 } 599 600 static void cfg_map_free(void *map) { 601 ucx_map_free(map); 602 } 603 604 605 606 void cfg_map_destr(UcxMempool *mp, UcxMap *map) { 607 if(map) { 608 ucx_mempool_reg_destr(mp, map, cfg_map_free); 609 } 610 } 611 612 613 614