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