openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

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, &currentFileName, &currentLineNum);
   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, &currentFileName, &currentLineNum);
   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 */