cint_interpreter.c (30023B)
1 /* 2 * 3 * 4 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 5 * 6 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 7 * 8 * File: cint_interpreter.c 9 * Purpose: CINT interpreter 10 */ 11 12 #include "cint_config.h" 13 #include "cint_interpreter.h" 14 #include "cint_porting.h" 15 #include "cint_variables.h" 16 #include "cint_error.h" 17 #include "cint_eval_asts.h" 18 #include "cint_internal.h" 19 #include "cint_datatypes.h" 20 #include "cint_debug.h" 21 #include "cint_parser.h" 22 23 static cint_variable_t* __vinterp = NULL; 24 static cint_variable_t* __vargv = NULL; 25 static cint_variable_t* __vargc = NULL; 26 27 cint_ast_t* __eval_list = NULL; 28 29 typedef struct cint_iterator_list_s { 30 struct cint_iterator_list_s* next; 31 cint_custom_iterator_t* iterators; 32 } cint_iterator_list_t; 33 34 typedef struct cint_macro_list_s { 35 struct cint_macro_list_s* next; 36 cint_custom_macro_t* macros; 37 } cint_macro_list_t; 38 39 40 static cint_iterator_list_t* __iterator_list = NULL; 41 static cint_macro_list_t* __macro_list = NULL; 42 43 typedef struct cint_event_handler_list_s { 44 struct cint_event_handler_list_s* next; 45 cint_event_handler_cb handler; 46 void* user_data; 47 } cint_event_handler_list_t; 48 49 static cint_event_handler_list_t* __handler_list = NULL; 50 51 typedef struct cint_init_handler_list_s { 52 struct cint_init_handler_list_s* next; 53 cint_interpreter_init_cb_t handler; 54 void* user_data; 55 } cint_init_handler_list_t; 56 57 static cint_init_handler_list_t* __init_list = NULL; 58 59 60 int 61 cint_interpreter_event_register(cint_event_handler_cb handler, void* user_data) 62 { 63 cint_event_handler_list_t* nh = CINT_MALLOC(sizeof(*nh)); 64 65 if(nh == NULL) { 66 return CINT_E_MEMORY; 67 } 68 69 nh->next = __handler_list; 70 __handler_list = nh; 71 72 nh->handler = handler; 73 nh->user_data = user_data; 74 75 return CINT_E_NONE; 76 } 77 78 int 79 cint_interpreter_event_unregister(cint_event_handler_cb handler) 80 { 81 cint_event_handler_list_t *prev, *cur; 82 int rv = CINT_E_NOT_FOUND; 83 84 for (prev = NULL, cur = __handler_list; cur; cur = cur->next) { 85 if (cur->handler == handler) { 86 break; 87 } 88 prev = cur; 89 } 90 91 if (cur) { 92 if (prev) { 93 prev->next = cur->next; 94 } else { 95 __handler_list = cur->next; 96 } 97 CINT_FREE(cur); 98 99 rv = CINT_E_NONE; 100 } 101 return rv; 102 } 103 104 cint_error_t 105 cint_interpreter_event(cint_interpreter_event_t event) 106 { 107 cint_event_handler_list_t* hp; 108 109 /* only issue new events if requested */ 110 if (interp.extended_events == 0 && event > cintEventReset) { 111 return CINT_E_NONE; 112 } 113 114 for(hp = __handler_list; hp; hp = hp->next) { 115 if(hp->handler) { 116 hp->handler(hp->user_data, event); 117 } 118 } 119 return CINT_E_NONE; 120 } 121 122 123 int 124 cint_interpreter_initialize_register(cint_interpreter_init_cb_t handler, 125 void *user_data) 126 { 127 cint_init_handler_list_t* nh = CINT_MALLOC(sizeof(*nh)); 128 129 if(nh == NULL) { 130 return CINT_E_MEMORY; 131 } 132 133 nh->next = __init_list; 134 __init_list = nh; 135 136 nh->handler = handler; 137 nh->user_data = user_data; 138 139 return CINT_E_NONE; 140 } 141 142 int 143 cint_interpreter_initialize_unregister(cint_interpreter_init_cb_t handler, 144 void *user_data) 145 { 146 cint_init_handler_list_t *prev, *cur; 147 int rv = CINT_E_NOT_FOUND; 148 149 for (prev = NULL, cur = __init_list; cur; cur = cur->next) { 150 if (cur->handler == handler && cur->user_data == user_data) { 151 break; 152 } 153 prev = cur; 154 } 155 156 if (cur) { 157 if (prev) { 158 prev->next = cur->next; 159 } else { 160 __init_list = cur->next; 161 } 162 CINT_FREE(cur); 163 164 rv = CINT_E_NONE; 165 } 166 167 return rv; 168 } 169 170 static cint_error_t 171 cint_interpreter_user_init(void) 172 { 173 cint_init_handler_list_t* cur; 174 int rv = CINT_E_NONE; 175 176 for(cur = __init_list; cur; cur = cur->next) { 177 if(cur->handler) { 178 if ((rv=cur->handler(cur->user_data)) != CINT_E_NONE) { 179 break; 180 } 181 } 182 } 183 return rv; 184 } 185 186 187 188 int 189 cint_interpreter_init(void) 190 { 191 static char* _argv0 = NULL; 192 static char* _argc = NULL; 193 int rv; 194 extern cint_data_t cint_builtin_data; 195 cint_datatype_t dt; 196 197 CINT_MEMSET(&dt, 0, sizeof(dt)); 198 /* clear out any previous allocations */ 199 cint_variable_clear(); 200 201 /* 202 * Initialize Variable Management 203 */ 204 cint_variable_init(); 205 206 /* 207 * Add our builtins 208 */ 209 cint_datatype_clear(); 210 cint_interpreter_add_atomics(cint_builtin_data.atomics); 211 cint_interpreter_add_data(&cint_builtin_data, NULL); 212 213 /* 214 * Add a variable pointing to the interpreter state. 215 * This allows the state to be manipulated during interpretation. 216 * Use with care. 217 */ 218 if(cint_datatype_find("cint_interpreter_state_t", &dt) == CINT_E_NONE) { 219 cint_variable_create(&__vinterp, "interp", &dt.desc, 220 CINT_VARIABLE_F_SDATA|CINT_VARIABLE_F_NODESTROY, 221 &interp); 222 } 223 interp.debug.dtrace = 0; 224 interp.debug.atrace = 0; 225 interp.debug.ftrace = 0; 226 227 if ((rv = cint_interpreter_user_init()) != CINT_E_NONE) { 228 return rv; 229 } 230 231 cint_interpreter_create_pointer("void", "NULL", NULL); 232 233 234 /* 235 * Create the argc/argv global variables 236 */ 237 dt.desc.basetype = "int"; 238 dt.desc.pcount = 0; 239 dt.desc.num_dimensions = 0; 240 cint_variable_create(&__vargc, "ARGC", &dt.desc, 241 CINT_VARIABLE_F_SDATA|CINT_VARIABLE_F_NODESTROY, 242 &_argc); 243 244 dt.desc.basetype = "char"; 245 dt.desc.pcount = 2; 246 dt.desc.num_dimensions = 0; 247 cint_variable_create(&__vargv, "ARGV", &dt.desc, 248 CINT_VARIABLE_F_SDATA|CINT_VARIABLE_F_NODESTROY, 249 &_argv0); 250 251 __eval_list = NULL; 252 253 /* 254 * Initialize default include path 255 */ 256 #if CINT_CONFIG_INCLUDE_XINCLUDE == 1 257 cint_interpreter_include_set(NULL); 258 #endif 259 260 /* 261 * Changes to the default interpreter state go here 262 */ 263 264 return CINT_E_NONE; 265 } 266 267 int 268 cint_interpreter_add_atomics(cint_atomic_type_t* types) 269 { 270 return cint_datatype_add_atomics(types); 271 } 272 273 int 274 cint_interpreter_add_data(cint_data_t* data, void *dlhandle) 275 { 276 int rc = cint_datatype_add_data(data, dlhandle); 277 278 if(data->iterators) { 279 cint_iterator_list_t* n = CINT_MALLOC(sizeof(*n)); 280 if (n == NULL) { 281 return CINT_E_MEMORY; 282 } 283 n->next = __iterator_list; 284 n->iterators = data->iterators; 285 __iterator_list = n; 286 } 287 if(data->macros) { 288 cint_macro_list_t* n = CINT_MALLOC(sizeof(*n)); 289 if (n == NULL) { 290 return CINT_E_MEMORY; 291 } 292 n->next = __macro_list; 293 n->macros = data->macros; 294 __macro_list = n; 295 } 296 cint_interpreter_event(cintEventDatatypeAdded); 297 return rc; 298 } 299 300 int 301 cint_interpreter_add_function(cint_function_t* f) 302 { 303 int rc = cint_datatype_add_function(f); 304 cint_interpreter_event(cintEventDatatypeAdded); 305 return rc; 306 } 307 308 309 static int 310 __cint_is_exit(cint_ast_t* ast) 311 { 312 return (ast && 313 (ast->ntype == cintAstIdentifier) && 314 (ast->utype.identifier.s) && 315 !CINT_STRCMP(ast->utype.identifier.s, "exit")); 316 } 317 318 static void 319 cint_interpreter_enable_prompt(void) 320 { 321 extern int cint_scanner_prompt; 322 323 cint_scanner_prompt = 1; 324 } 325 326 cint_error_t 327 cint_interpreter_evaluate(cint_ast_t* ast) 328 { 329 cint_variable_t* rv = NULL; 330 /* 331 * Add to global translation unit evaluation list 332 */ 333 334 if(__eval_list == NULL) { 335 __eval_list = ast; 336 } 337 else { 338 cint_ast_append(__eval_list, ast); 339 } 340 341 if(interp.parse_only == 0) { 342 /* 343 * Evaluate new unit 344 */ 345 cint_errno = CINT_E_NONE; 346 rv = cint_eval_asts(ast); 347 if (rv && interp.print_expr) { 348 cint_variable_print(rv, 0, ""); 349 } 350 } 351 else { 352 /* 353 * Check for parsing exit condition 354 */ 355 if(__cint_is_exit(ast)) { 356 cint_errno = CINT_E_EXIT; 357 } 358 } 359 360 /* free all ASTs that were used */ 361 cint_ast_free_all(); 362 __eval_list = NULL; 363 364 /* Reprompt after translation unit is complete */ 365 cint_interpreter_enable_prompt(); 366 367 return cint_errno; 368 } 369 370 int 371 cint_interpreter_ctest_cmd(char *command) 372 { 373 cint_ast_t *ast; 374 cint_variable_t *cint_result; 375 int rv; 376 377 /* Parse */ 378 ast = cint_interpreter_parse_string(command); 379 if (ast == NULL) { 380 return CINT_E_BAD_VARIABLE; 381 } 382 else { 383 /* Evaluate */ 384 cint_result = cint_eval_asts(ast); 385 if (cint_result == NULL) { 386 rv = cint_errno; 387 } else { 388 rv = cint_long_value(cint_result); 389 } 390 } 391 cint_ast_free_all(); 392 393 return rv; 394 } 395 396 cint_ast_t* 397 cint_interpreter_tree(void) 398 { 399 return __eval_list; 400 } 401 402 volatile cint_error_t cint_errno; 403 404 405 int cint_interpreter_is_type(const char* str) 406 { 407 cint_datatype_t dt; 408 CINT_MEMSET(&dt, 0, sizeof(dt)); 409 if(cint_datatype_find(str, &dt) == CINT_E_NONE) { 410 return (dt.flags & CINT_DATATYPE_FLAGS_TYPE); 411 } 412 return 0; 413 } 414 415 static void 416 _indent(int count) 417 { 418 while(count--) { 419 CINT_PRINTF(" "); 420 } 421 } 422 423 static int 424 __pointer_print(void** p) 425 { 426 void* vp = *p; 427 if(vp == NULL) { 428 CINT_PRINTF("NULL"); 429 } 430 else { 431 CINT_PRINTF("%p", vp); 432 } 433 return 0; 434 } 435 436 437 static cint_enum_map_t* 438 _enum_find(void* p, cint_enum_map_t* maps) 439 { 440 int* e = (int *)p; 441 cint_enum_map_t* em; 442 443 for(em = maps; em->name; em++) { 444 if(em->value == *e) { 445 return em; 446 } 447 } 448 449 return NULL; 450 } 451 452 int 453 _str2enum(void* p, int pcount, const char* name, cint_enum_map_t* map) 454 { 455 int* e = (int *)p; 456 cint_enum_map_t* em; 457 458 while(pcount--) { 459 e = * (int**) e; 460 } 461 462 for(em = map; em->name; em++) { 463 if(!CINT_STRCMP(name, em->name)) { 464 *e = em->value; 465 return 0; 466 } 467 } 468 return CINT_E_NOT_FOUND; 469 } 470 471 472 /* 473 * Used when a variable is referenced from within the printf() function as "$var" 474 */ 475 int 476 cint_variable_printf(cint_variable_t* v) 477 { 478 char fbuffer[CINT_CONFIG_MAX_STACK_PRINT_BUFFER]; 479 480 if(v == NULL) { 481 return CINT_E_BAD_VARIABLE; 482 } 483 484 if(v->dt.desc.num_dimensions && v->dt.cap == NULL) { 485 CINT_PRINTF("<array variable>"); 486 } 487 else if(v->dt.desc.pcount || (v->dt.flags & CINT_DATATYPE_F_FUNC_POINTER)) { 488 /* 489 * This is a pointer 490 */ 491 __pointer_print((void**)v->data); 492 } 493 else if(v->dt.cap && v->dt.cap->format) { 494 v->dt.cap->format(v->data, fbuffer, sizeof(fbuffer), cintAtomicFormatCintPrintf); 495 CINT_PRINTF("%s", fbuffer); 496 } 497 else if(v->dt.flags & CINT_DATATYPE_F_ATOMIC) { 498 v->dt.basetype.ap->format(v->data, fbuffer, sizeof(fbuffer), cintAtomicFormatCintPrintf); 499 CINT_PRINTF("%s", fbuffer); 500 } 501 else if(v->dt.flags & CINT_DATATYPE_F_ENUM) { 502 cint_enum_map_t* em = _enum_find(v->data, v->dt.basetype.ep->enum_map); 503 CINT_PRINTF("%s", (em) ? em->name : "<invalid enum>"); 504 } 505 else if(v->dt.flags & CINT_DATATYPE_F_STRUCT) { 506 CINT_PRINTF("<structure variable>"); 507 } 508 else { 509 CINT_PRINTF("<unhandled variable print condition>"); 510 } 511 return 0; 512 } 513 514 /* 515 * Used for interactive interpreter "print" command 516 */ 517 static int 518 __cint_variable_print(cint_variable_t* v, int indent, const char* vname) 519 { 520 char fbuffer[CINT_CONFIG_MAX_STACK_PRINT_BUFFER]; 521 char _rstr[CINT_CONFIG_MAX_STACK_PRINT_BUFFER] = {0}; 522 523 const char* datatype; 524 525 if(v == NULL) { 526 return CINT_E_BAD_VARIABLE; 527 } 528 529 if(vname == NULL) { 530 vname = v->name; 531 } 532 533 if(vname[0] == '_' && 534 vname[1] == '_' && 535 vname[2] == 'a' && 536 vname[3] == 'u' && 537 vname[4] == 't' && 538 vname[5] == 'o') { 539 vname = "$$"; 540 } 541 542 datatype = cint_datatype_format(&v->dt, _rstr, 0); 543 544 if(v->dt.desc.pcount || (v->dt.flags & CINT_DATATYPE_F_FUNC_POINTER)) { 545 /* 546 * This is a pointer 547 */ 548 _indent(indent); 549 CINT_PRINTF("%s %s = ", datatype, vname); 550 __pointer_print((void**)v->data); 551 #if CINT_CONFIG_INCLUDE_CINT_LOGGER == 1 552 if (v->data && *(char**)v->data && 553 (v->dt.desc.pcount == 1) && !CINT_STRCMP(v->dt.desc.basetype, "char")) { 554 CINT_PRINTF(" \"%s\"", *(char**)v->data); 555 } 556 #endif 557 CINT_PRINTF("\n"); 558 return 0; 559 } 560 561 /* 562 * Atomic or structure types 563 */ 564 565 if(v->dt.cap && v->dt.cap->format) { 566 _indent(indent); 567 CINT_PRINTF("%s %s = ", datatype, vname); 568 v->dt.cap->format(v->data, fbuffer, sizeof(fbuffer), cintAtomicFormatCintPrintVariable); 569 CINT_PRINTF("%s\n", fbuffer); 570 } 571 else if(v->dt.flags & CINT_DATATYPE_F_ATOMIC) { 572 _indent(indent); 573 CINT_PRINTF("%s %s = ", datatype, vname); 574 v->dt.basetype.ap->format(v->data, fbuffer, sizeof(fbuffer), cintAtomicFormatCintPrintVariable); 575 CINT_PRINTF("%s\n", fbuffer); 576 } 577 else if(v->dt.flags & CINT_DATATYPE_F_ENUM) { 578 cint_enum_map_t* em = _enum_find(v->data, v->dt.basetype.ep->enum_map); 579 _indent(indent); 580 CINT_PRINTF("%s %s = %s (%d)\n", datatype, vname, 581 (em) ? em->name : "<invalid enum>", (em) ? em->value : *(int*)v->data); 582 } 583 else if(v->dt.flags & CINT_DATATYPE_F_STRUCT) { 584 const cint_parameter_desc_t* sm; 585 int i = 0; 586 _indent(indent); 587 588 CINT_PRINTF("%s %s = {\n", datatype, vname); 589 590 for(sm = v->dt.basetype.sp->struct_members; sm->basetype; sm++) { 591 /* 592 * Get the address of this member 593 */ 594 cint_variable_t* av = NULL; 595 void* maddr; 596 maddr = v->dt.basetype.sp->maddr(v->data, i, v->dt.basetype.sp); 597 /* 598 * Create an autovariable of the same type pointing to the address of this member 599 */ 600 { 601 cint_datatype_t sdt; 602 int rc; 603 sdt.desc = *sm; 604 cint_strlcpy(sdt.type, sm->basetype, sizeof(sdt.type)); 605 606 /* 607 * Add a variable by name of the structure member, so that we 608 * can print it. Do not push it to local scope so that non 609 * thread-safe list operations in CINT infrastructure which 610 * are not required here are avoided. 611 */ 612 if((rc = cint_variable_create_no_add(&av, NULL, &sdt.desc, 613 CINT_VARIABLE_F_SDATA, 614 maddr)) < 0) { 615 616 if(rc == CINT_E_TYPE_NOT_FOUND) { 617 /* 618 * A description for this datatype is missing. 619 */ 620 _indent(indent+4); 621 cint_warn(NULL, 0, "unknown type '%s'", cint_datatype_format(&sdt, _rstr, 0)); 622 623 /* Keep going */ 624 i++; 625 continue; 626 } 627 else { 628 return rc; 629 } 630 } 631 } 632 633 /* 634 * Print the autovar with this member's name 635 */ 636 cint_variable_print(av, indent+4, sm->name); 637 638 /* 639 * structure member is printed. Free the automatic variable created 640 * for that purpose. 641 */ 642 cint_variable_free(av); 643 i++; 644 } 645 _indent(indent); 646 CINT_PRINTF("}\n"); 647 } 648 else if(v->dt.flags & (CINT_DATATYPE_F_FUNC | CINT_DATATYPE_F_FUNC_DYNAMIC)) { 649 /* Function pointer variable */ 650 _indent(indent); 651 CINT_PRINTF("%s = %s function ", 652 vname, 653 (v->dt.flags & CINT_DATATYPE_F_FUNC) ? 654 "compiled" : "dynamic"); 655 if (v->dt.basetype.fp->params) { 656 CINT_PRINTF("'%s %s", 657 cint_datatype_format_pd(v->dt.basetype.fp->params, _rstr, 0), 658 v->dt.basetype.fp->name); 659 cint_fparams_print(v->dt.basetype.fp->params+1); 660 } else { 661 /* CINT vararg functions are special and always return int */ 662 CINT_PRINTF("'int %s(...)", 663 v->dt.basetype.fp->name); 664 } 665 CINT_PRINTF("'\n"); 666 } 667 668 return CINT_E_NONE; 669 } 670 671 static void __cint_variable_print_array( 672 cint_variable_t* v, 673 cint_variable_t* tempElement, 674 int currentDimension, 675 int elementSize, 676 const char* vname, 677 int indent) 678 { 679 char name[CINT_CONFIG_MAX_STACK_PRINT_BUFFER]; 680 char* p; 681 int i; 682 int sizeMultiplier = 1; 683 int hasCustomPrinter = 684 (v->dt.cap && 685 v->dt.cap->format && 686 (currentDimension + 1) == 687 (v->dt.desc.num_dimensions - v->dt.type_num_dimensions)) ? 1 : 0; 688 if(hasCustomPrinter) { 689 int dim_index; 690 for(dim_index = 0; 691 dim_index < v->dt.type_num_dimensions; 692 dim_index++) { 693 int index = dim_index + v->dt.desc.num_dimensions - 694 v->dt.type_num_dimensions; 695 sizeMultiplier *= v->dt.desc.dimensions[index]; 696 } 697 } 698 p = (char*)tempElement->data; 699 700 for(i = 0; i < v->dt.desc.dimensions[currentDimension]; i++) { 701 CINT_SPRINTF(name, "%s[%d]", vname, i); 702 if((currentDimension + 1) == v->dt.desc.num_dimensions || 703 hasCustomPrinter || 704 v->dt.desc.dimensions[currentDimension + 1] == 705 CINT_CONFIG_POINTER_INFINITE_DIMENSION) { 706 __cint_variable_print(tempElement, indent, name); 707 p += elementSize * sizeMultiplier; 708 tempElement->data = p; 709 } 710 else { 711 __cint_variable_print_array( 712 v, 713 tempElement, 714 currentDimension + 1, 715 elementSize, 716 name, 717 indent); 718 } 719 } 720 } 721 722 int 723 cint_variable_print(cint_variable_t* v, int indent, const char* vname) 724 { 725 char _rstr[256] = {0}; 726 if((v->dt.cap && 727 v->dt.cap->format && 728 v->dt.desc.num_dimensions == v->dt.type_num_dimensions) || 729 v->dt.desc.num_dimensions == 0) { 730 return __cint_variable_print(v, indent, vname); 731 } 732 else { 733 int elementSize; 734 cint_variable_t pv = *v; 735 736 _indent(indent); 737 738 CINT_PRINTF("%s %s = {\n", cint_datatype_format(&v->dt, _rstr, 0), vname); 739 740 pv.dt.desc.num_dimensions = 0; 741 elementSize = cint_datatype_size(&pv.dt); 742 743 __cint_variable_print_array( 744 v, 745 &pv, 746 0, 747 elementSize, 748 vname, 749 indent + 4); 750 751 _indent(indent); 752 CINT_PRINTF("}\n"); 753 } 754 return 0; 755 } 756 757 int 758 cint_constant_find(const char* name, int* c) 759 { 760 return cint_datatype_constant_find(name, c); 761 } 762 763 int 764 cint_interpreter_run(const char* fname) 765 { 766 cint_ast_t* ast; 767 768 if(fname == NULL) { 769 fname = "main"; 770 } 771 772 ast = cint_ast_function(NULL, NULL); 773 ast->utype.function.name = fname; 774 ast->utype.function.parameters = NULL; 775 cint_eval_ast(ast); 776 return cint_errno; 777 } 778 779 cint_error_t 780 cint_interpreter_create_pointer(const char* type, const char* name, void* ptr) 781 { 782 cint_datatype_t dt; 783 cint_variable_t* v; 784 cint_error_t rc; 785 786 CINT_MEMSET(&dt, 0, sizeof(dt)); 787 rc = cint_datatype_find((type) ? type : "void", &dt); 788 dt.desc.pcount=1; 789 if((rc = cint_variable_create(&v, name, &dt.desc, 790 CINT_VARIABLE_F_CONST| 791 CINT_VARIABLE_F_NODESTROY, 792 NULL)) == CINT_E_NONE) { 793 *(void**)v->data = ptr; 794 } 795 796 return rc; 797 } 798 799 800 #if CINT_CONFIG_INCLUDE_XINCLUDE == 1 801 802 typedef struct cint_directory_list_s { 803 struct cint_directory_list_s* next; 804 char* directory; 805 } cint_directory_list_t; 806 807 static cint_directory_list_t* __directory_list = NULL; 808 809 int 810 cint_interpreter_include_set(const char* path) 811 { 812 /* 813 * Free existing list 814 */ 815 cint_directory_list_t* list; 816 for(list = __directory_list; list;) { 817 cint_directory_list_t* next = list->next; 818 CINT_FREE(list->directory); 819 CINT_FREE(list); 820 list = next; 821 } 822 823 /* The head of the list is set to the local directory */ 824 __directory_list = CINT_MALLOC(sizeof(*__directory_list)); 825 __directory_list->next = NULL; 826 __directory_list->directory = CINT_MALLOC(1); 827 __directory_list->directory[0] = 0; 828 829 return cint_interpreter_include_add(path); 830 } 831 832 int 833 cint_interpreter_include_add(const char* path) 834 { 835 const char* s = path; 836 int count = 0; 837 /* 838 * Directory paths are semicolon or colon separated 839 */ 840 if(path && path[0]) { 841 842 int count = 0; 843 cint_directory_list_t* tail; 844 cint_directory_list_t* l = NULL; 845 846 int alloc_size = CINT_STRLEN(path)+1; 847 848 /* 849 * Get the tail of the current directory list 850 */ 851 for(tail = __directory_list; tail && tail->next; tail = tail->next); 852 853 854 /* 855 * Parse and append new paths to the tail of the current list 856 */ 857 do { 858 char* d; 859 860 /* Allocate new list entry */ 861 l = CINT_MALLOC(sizeof(*l)); 862 if(l == NULL) { 863 return CINT_E_MEMORY; 864 } 865 l->next = NULL; 866 867 l->directory = CINT_MALLOC(alloc_size); 868 if(l->directory == NULL) { 869 CINT_FREE(l); 870 return CINT_E_MEMORY; 871 } 872 873 /* Copy the current path */ 874 d = l->directory; 875 while(*s && ((*s != ';') && (*s != ':'))) { 876 *d++ = *s++; 877 } 878 *d = 0; 879 880 /* Skip semicolons */ 881 while(*s && ((*s == ';') || (*s == ':'))) { 882 s++; 883 } 884 885 /* Push this new path on the list */ 886 tail->next = l; 887 tail = l; 888 count++; 889 } while(*s); 890 } 891 return count; 892 } 893 894 /* 895 * Search include paths for requested name 896 */ 897 static int 898 _cint_interpreter_include_search(const char* name, char** path_rv) 899 { 900 cint_directory_list_t* l; 901 FILE* fp; 902 char* p; 903 int len_name = 0; 904 905 for (l = __directory_list; l ; l = l->next) { 906 907 if (!l->directory) { 908 continue; 909 } 910 911 len_name = CINT_STRLEN(name); 912 913 /* directory + '/' + name + \0 */ 914 p = CINT_MALLOC(CINT_STRLEN(l->directory)+1+len_name+1); 915 if(p == NULL) { 916 if(path_rv) { 917 *path_rv = NULL; 918 } 919 return CINT_E_MEMORY; 920 } 921 *p = 0; 922 923 if(l->directory[0]) { 924 CINT_SPRINTF(p, "%s/", l->directory); 925 } 926 CINT_STRNCAT(p, name, len_name); 927 /* Only (currently) portable way to check existence is to 928 open it with CINT_FOPEN() */ 929 if((fp = CINT_FOPEN(p, "r"))) { 930 CINT_FCLOSE(fp); 931 if(path_rv) { 932 *path_rv = p; 933 } 934 else { 935 CINT_FREE(p); 936 } 937 return CINT_E_NONE; 938 } 939 CINT_FREE(p); 940 } 941 if(path_rv) { 942 *path_rv = NULL; 943 } 944 return CINT_E_NOT_FOUND; 945 } 946 947 static int 948 _cint_interpreter_include_path(char** path_rv) 949 { 950 int size = 1; 951 cint_directory_list_t* l; 952 char* p, *s; 953 954 for(l = __directory_list; l ; l = l->next) { 955 size += CINT_STRLEN(l->directory)+1; 956 } 957 p = CINT_MALLOC(size); 958 959 if(p == NULL) { 960 return CINT_E_MEMORY; 961 } 962 963 for(l = __directory_list, s = p; l ; l = l->next) { 964 s += CINT_SPRINTF(s, "%s;", l->directory); 965 } 966 967 if(path_rv) { 968 *path_rv = p; 969 } 970 else { 971 CINT_FREE(p); 972 } 973 974 return CINT_E_NONE; 975 } 976 977 int 978 cint_interpreter_include_get(const char* name, char** path_rv) 979 { 980 int rv; 981 982 if (name) { 983 rv = _cint_interpreter_include_search(name, path_rv); 984 } else { 985 /* 986 * If name is NULL then return the entire current search path 987 */ 988 rv = _cint_interpreter_include_path(path_rv); 989 } 990 991 return rv; 992 } 993 994 #endif /* CINT_CONFIG_INCLUDE_XINCLUDE */ 995 996 #if CINT_CONFIG_INCLUDE_PARSER == 1 997 998 char *cint_current_line(void* yyscanner, char *const lineBuffer, const int lineLen, 999 int *column, int *tokLen, char **curFile, int *curLine); 1000 1001 static void* scanner = NULL; 1002 1003 #ifndef LONGEST_SOURCE_LINE 1004 #define LONGEST_SOURCE_LINE 256 1005 #endif 1006 1007 static const char* cint_get_file(void) { 1008 const int sourceLineLen = LONGEST_SOURCE_LINE; /* Truncate source lines longer than 256 characters. */ 1009 char sourceLine[LONGEST_SOURCE_LINE]; 1010 int col; 1011 int tokLen; 1012 char *currentFileName; 1013 int currentLineNum; 1014 1015 (void) cint_current_line(scanner, sourceLine, sourceLineLen, &col, 1016 &tokLen, ¤tFileName, ¤tLineNum); 1017 1018 return currentFileName; 1019 } 1020 1021 static int cint_get_line(void) { 1022 1023 const int sourceLineLen = LONGEST_SOURCE_LINE; /* Truncate source lines longer than 256 characters. */ 1024 char sourceLine[LONGEST_SOURCE_LINE]; 1025 int col; 1026 int tokLen; 1027 char *currentFileName; 1028 int currentLineNum; 1029 1030 (void) cint_current_line(scanner, sourceLine, sourceLineLen, &col, 1031 &tokLen, ¤tFileName, ¤tLineNum); 1032 1033 return currentLineNum; 1034 1035 } 1036 1037 int 1038 cint_interpreter_parse(void* handle, const char* prompt, int argc, char** argv) 1039 { 1040 cint_ast_t* ast; 1041 cint_cparser_t* cp = cint_cparser_create(); 1042 int parse_ok; 1043 1044 cint_errno = CINT_E_NONE; 1045 (void)cint_cparser_set_prompt(prompt); 1046 1047 cint_cparser_start_handle(cp, handle); 1048 1049 /* 1050 * Initialize ARGC/ARGV with passed arguments 1051 */ 1052 *((int*)__vargc->data) = argc; 1053 *((char***)__vargv->data) = argv; 1054 1055 cint_interpreter_enable_prompt(); 1056 1057 if(argc > 0 && !CINT_STRCMP(argv[0], "allow_file_info")) { 1058 scanner = cp->scanner; 1059 cint_ast_get_file_f = cint_get_file; 1060 cint_ast_get_line_f = cint_get_line; 1061 } else { 1062 scanner = NULL; 1063 cint_ast_get_file_f = NULL; 1064 cint_ast_get_line_f = NULL; 1065 } 1066 1067 parse_ok = 1; 1068 while ( cint_errno != CINT_E_EXIT ) { 1069 ast = cint_cparser_parse(cp); 1070 1071 if (handle != NULL && parse_ok && cint_cparser_error(cp)) { 1072 /* If parsing a file, once there's a parser error, 1073 continue to parse, but do not evaluate. 1074 1075 This is to avoid infinite loops from code like this: 1076 1077 f() 1078 { 1079 ^ syntax error, unexpected '{', expecting ',' or ';' 1080 while(1) { 1081 } 1082 } 1083 1084 which, if allowed to evaluate, would execute an 1085 infinite loop. 1086 */ 1087 parse_ok = !parse_ok; 1088 /* It is possible to break here to avoid a cascade of 1089 syntax errors, continuing on may display more 1090 legitimate syntax errors. */ 1091 } 1092 if (parse_ok && ast) { 1093 /* Evaluate AST */ 1094 cint_interpreter_evaluate(ast); 1095 } 1096 } 1097 1098 cint_cparser_destroy(cp); 1099 1100 return cint_errno; 1101 } 1102 1103 int 1104 cint_interpreter_is_iterator(const char* str, cint_ast_t** handle) 1105 { 1106 cint_iterator_list_t* list; 1107 cint_custom_iterator_t* iter; 1108 for(list = __iterator_list; list; list = list->next) { 1109 for(iter = list->iterators; iter && iter->name; iter++) { 1110 if(!CINT_STRCMP(iter->name, str)) { 1111 if(handle) { 1112 *handle = (cint_ast_t*)iter; 1113 } 1114 return 1; 1115 } 1116 } 1117 } 1118 return 0; 1119 } 1120 1121 int 1122 cint_interpreter_is_macro(const char* str, cint_ast_t** handle) 1123 { 1124 cint_macro_list_t* list; 1125 cint_custom_macro_t* macro; 1126 for(list = __macro_list; list; list = list->next) { 1127 for(macro = list->macros; macro && macro->name; macro++) { 1128 if(!CINT_STRCMP(macro->name, str)) { 1129 if(handle) { 1130 *handle = (cint_ast_t*)macro; 1131 } 1132 return 1; 1133 } 1134 } 1135 } 1136 return 0; 1137 } 1138 1139 cint_ast_t* 1140 cint_interpreter_iterator(cint_ast_t* handle, cint_ast_t* arguments, cint_ast_t* statements) 1141 { 1142 cint_ast_t* ast; 1143 cint_custom_iterator_t* iter = (cint_custom_iterator_t*)handle; 1144 ast = iter->handler(iter->name, arguments, statements); 1145 if(ast == NULL) { 1146 /* Error */ 1147 ast = cint_ast_empty(); 1148 } 1149 return ast; 1150 } 1151 1152 cint_ast_t* 1153 cint_interpreter_macro(cint_ast_t* handle, cint_ast_t* arguments) 1154 { 1155 cint_ast_t* ast; 1156 cint_custom_macro_t* macro = (cint_custom_macro_t*)handle; 1157 ast = macro->handler(macro->name, arguments); 1158 if(ast == NULL) { 1159 /* Error */ 1160 ast = cint_ast_empty(); 1161 } 1162 return ast; 1163 } 1164 1165 cint_ast_t* 1166 cint_interpreter_parse_string(const char* expr) 1167 { 1168 return cint_cparser_parse_string(expr); 1169 } 1170 1171 #endif /* CINT_CONFIG_INCLUDE_PARSER */