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_builtins.c (35463B)


      1 /*
      2  * 
      3  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      4  * 
      5  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      6  *
      7  * File:        cint_builtins.c
      8  * Purpose:     CINT building function handlers
      9  */
     10 
     11 /***********************************************************************
     12  *
     13  * Native C Atomic Datatypes and Builtin Interpreter Data Types
     14  */
     15 
     16 #include "cint_config.h"
     17 #include "cint_porting.h"
     18 #include "cint_interpreter.h"
     19 #include "cint_variables.h"
     20 #include "cint_ast.h"
     21 #include "cint_internal.h"
     22 #include "cint_eval_asts.h"
     23 
     24 static int 
     25 __cint_format_signed_char(void* p, char* dst, int size, cint_atomic_format_t format)
     26 {
     27     int i = *((signed char*)p); 
     28 
     29     switch(format) 
     30         {
     31         case cintAtomicFormatCintPrintVariable:
     32             {
     33                 cint_snprintf_ex(&dst, &size, "%d (0x%.2x) '%c'", i, i&0xff, (i < 127 && i > 31) ? i : '.'); 
     34                 break; 
     35             }
     36         case cintAtomicFormatCintPrintf:
     37         default:
     38             {
     39                 cint_snprintf_ex(&dst, &size, "%c", i); 
     40                 break; 
     41             }
     42         }       
     43                 
     44     return 0; 
     45 }       
     46 
     47 static int 
     48 __cint_format_unsigned_char(void* p, char* dst, int size, cint_atomic_format_t format)
     49 {
     50     unsigned int i = *((unsigned char*)p); 
     51     
     52     switch(format)
     53         {
     54         case cintAtomicFormatCintPrintVariable:
     55             {
     56                 cint_snprintf_ex(&dst, &size, "%u (0x%.2x)", i, i); 
     57                 break; 
     58             }
     59         case cintAtomicFormatCintPrintf:
     60         default:
     61             {
     62                 cint_snprintf_ex(&dst, &size, "0x%.2x", i); 
     63                 break; 
     64             }
     65         }
     66 
     67     return 0; 
     68 }       
     69 
     70 static int 
     71 __cint_format_signed_short(void* p, char* dst, int size, cint_atomic_format_t format)
     72 {
     73     signed short* u = (signed short*)p; 
     74     
     75     switch(format)
     76         {
     77         case cintAtomicFormatCintPrintVariable:
     78             {
     79                 cint_snprintf_ex(&dst, &size, "%hd (0x%.4hx)", *u, *u); 
     80                 break; 
     81             }
     82         case cintAtomicFormatCintPrintf:
     83         default:
     84             {
     85                 cint_snprintf_ex(&dst, &size, "%hd", *u); 
     86                 break;
     87             }
     88         }
     89 
     90     return 0; 
     91 }       
     92 
     93 static int 
     94 __cint_format_unsigned_short(void* p, char* dst, int size, cint_atomic_format_t format)
     95 {
     96     unsigned short* u = (unsigned short*)p; 
     97 
     98     switch(format)
     99         {
    100         case cintAtomicFormatCintPrintVariable:
    101             {   
    102                 cint_snprintf_ex(&dst, &size, "%hu (0x%.4hx)", *u, *u); 
    103                 break; 
    104             }
    105         case cintAtomicFormatCintPrintf:
    106         default:
    107             {
    108                 cint_snprintf_ex(&dst, &size, "%hu", *u); 
    109                 break; 
    110             }
    111         }
    112             
    113     return 0; 
    114 }       
    115 
    116 static int 
    117 __cint_format_signed_int(void* p, char* dst, int size, cint_atomic_format_t format)
    118 {
    119     signed int* i = (signed int*) p; 
    120 
    121     switch(format)
    122         {
    123         case cintAtomicFormatCintPrintVariable:
    124             {
    125                 cint_snprintf_ex(&dst, &size, "%d (0x%x)", *i, *i); 
    126                 break; 
    127             }
    128         case cintAtomicFormatCintPrintf:
    129         default:
    130             {
    131                 cint_snprintf_ex(&dst, &size, "%d", *i); 
    132                 break; 
    133             }
    134         }       
    135 
    136     return 0; 
    137 }       
    138 
    139 
    140 static int 
    141 __cint_format_unsigned_int(void* p, char* dst, int size, cint_atomic_format_t format)
    142 {
    143     unsigned int* i = (unsigned int*) p; 
    144 
    145     switch(format)
    146         {
    147         case cintAtomicFormatCintPrintVariable:
    148             {
    149                 cint_snprintf_ex(&dst, &size, "%u (0x%x)", *i, *i); 
    150                 break; 
    151             }
    152         case cintAtomicFormatCintPrintf:
    153         default:
    154             {
    155                 cint_snprintf_ex(&dst, &size, "%u", *i); 
    156                 break; 
    157             }
    158         }       
    159 
    160     return 0; 
    161 }       
    162 
    163 static int 
    164 __cint_format_signed_long(void* p, char* dst, int size, cint_atomic_format_t format)
    165 {
    166     signed long* u = (signed long*)p;     
    167     switch(format)
    168         {
    169         case cintAtomicFormatCintPrintVariable:
    170             {
    171                 cint_snprintf_ex(&dst, &size, "%ld (0x%.8lx)", *u, *u); 
    172                 break; 
    173             }
    174         case cintAtomicFormatCintPrintf:
    175         default:
    176             {
    177                 cint_snprintf_ex(&dst, &size, "%ld", *u); 
    178                 break; 
    179             }
    180         }       
    181 
    182     return 0; 
    183 }       
    184 
    185 
    186 static int 
    187 __cint_format_unsigned_long(void* p, char* dst, int size, cint_atomic_format_t format)
    188 {
    189     unsigned long* u = (unsigned long*)p;     
    190 
    191     switch(format)
    192         {
    193         case cintAtomicFormatCintPrintVariable:
    194             {
    195                 cint_snprintf_ex(&dst, &size, "%lu (0x%.8lx)", *u, *u);                 
    196                 break; 
    197             }
    198         case cintAtomicFormatCintPrintf:
    199         default:
    200             {
    201                 cint_snprintf_ex(&dst, &size, "%lu", *u); 
    202                 break; 
    203             }
    204         }       
    205 
    206     return 0; 
    207 }       
    208 
    209 #if CINT_CONFIG_INCLUDE_DOUBLES == 1
    210 
    211 static int
    212 __cint_format_double(void* p, char* dst, int size, cint_atomic_format_t format)
    213 {
    214     double* d = (double*)p; 
    215 
    216     switch(format)
    217         {
    218         case cintAtomicFormatCintPrintVariable:
    219             {
    220                 cint_snprintf_ex(&dst, &size, "%g", *d); 
    221                 break; 
    222             }
    223         case cintAtomicFormatCintPrintf:
    224         default:
    225             {
    226                 cint_snprintf_ex(&dst, &size, "%g", *d); 
    227                 break; 
    228             }
    229         }       
    230 
    231     return 0; 
    232 }
    233 
    234 #endif /* CINT_CONFIG_INCLUDE_DOUBLES */
    235 
    236 #if CINT_CONFIG_INCLUDE_LONGLONGS == 1
    237 
    238 static int
    239 __cint_format_signed_longlong(void* p, char* dst, int size, cint_atomic_format_t format)
    240 {
    241     signed long long* u = (signed long long*)p;
    242     char buf1[50], *s1;
    243     char buf2[50], *s2;
    244 
    245     s1 = cint_lltoa(buf1, sizeof(buf1), *u, 0, 16, 16);
    246     s2 = cint_lltoa(buf2, sizeof(buf2), *u, 1, 10, 0);
    247     
    248     switch(format)
    249         {
    250         case cintAtomicFormatCintPrintVariable:
    251             {
    252                 cint_snprintf_ex(&dst, &size, "%s (0x%s)", s2, s1); 
    253                 break; 
    254             }
    255         case cintAtomicFormatCintPrintf:
    256         default:
    257             {
    258                 cint_snprintf_ex(&dst, &size, "%s", s2); 
    259                 break; 
    260             }
    261         }       
    262 
    263     return 0; 
    264 }
    265 
    266 static int
    267 __cint_format_unsigned_longlong(void* p, char* dst, int size, cint_atomic_format_t format)
    268 {
    269     unsigned long long* u = (unsigned long long*)p; 
    270     char buf1[50], *s1;
    271     char buf2[50], *s2;
    272 
    273     s1 = cint_lltoa(buf1, sizeof(buf1), *u, 0, 16, 16);
    274     s2 = cint_lltoa(buf2, sizeof(buf2), *u, 0, 10, 0);
    275     
    276     switch(format)
    277         {
    278         case cintAtomicFormatCintPrintVariable:
    279             {
    280                 cint_snprintf_ex(&dst, &size, "%s (0x%s)", s2, s1); 
    281                 break; 
    282             }
    283         case cintAtomicFormatCintPrintf:
    284         default:
    285             {
    286                 cint_snprintf_ex(&dst, &size, "%s", s2); 
    287                 break; 
    288             }
    289         }      
    290 
    291     return 0; 
    292 }
    293 
    294 
    295 #endif /* CINT_CONFIG_INCLUDE_LONGLONGS */
    296 
    297 static cint_atomic_type_t __cint_builtin_atomics[] = 
    298     {
    299         
    300         /* Character types */
    301         {
    302             "char", 
    303             sizeof(signed char), 
    304             CINT_ATOMIC_TYPE_F_CHAR | CINT_ATOMIC_TYPE_F_SIGNED, 
    305             __cint_format_signed_char,
    306             NULL
    307         }, 
    308         {
    309             "signed char", 
    310             sizeof(char), 
    311             CINT_ATOMIC_TYPE_F_CHAR | CINT_ATOMIC_TYPE_F_SIGNED,
    312             __cint_format_signed_char,
    313             NULL
    314         }, 
    315         {
    316             "unsigned char", 
    317             sizeof(char), 
    318             CINT_ATOMIC_TYPE_F_CHAR | CINT_ATOMIC_TYPE_F_UNSIGNED,
    319             __cint_format_unsigned_char,
    320             NULL, 
    321         }, 
    322 
    323         /* Short types */
    324         {
    325             "short", 
    326             sizeof(short), 
    327             CINT_ATOMIC_TYPE_F_SHORT | CINT_ATOMIC_TYPE_F_SIGNED, 
    328             __cint_format_signed_short,
    329             NULL
    330         }, 
    331         {
    332             "signed short", 
    333             sizeof(short), 
    334             CINT_ATOMIC_TYPE_F_SHORT | CINT_ATOMIC_TYPE_F_SIGNED,
    335             __cint_format_signed_short,
    336             NULL
    337         }, 
    338 
    339         {
    340             "unsigned short", 
    341             sizeof(short), 
    342             CINT_ATOMIC_TYPE_F_SHORT | CINT_ATOMIC_TYPE_F_UNSIGNED, 
    343             __cint_format_unsigned_short,
    344             NULL
    345         }, 
    346 
    347 
    348         /* Int types */
    349         {
    350             "int", 
    351             sizeof(int), 
    352             CINT_ATOMIC_TYPE_F_INT | CINT_ATOMIC_TYPE_F_SIGNED, 
    353             __cint_format_signed_int,
    354             NULL
    355         }, 
    356         {
    357             "signed int", 
    358             sizeof(int), 
    359             CINT_ATOMIC_TYPE_F_INT | CINT_ATOMIC_TYPE_F_SIGNED, 
    360             __cint_format_signed_int, 
    361             NULL
    362         }, 
    363         {
    364             "unsigned int", 
    365             sizeof(int), 
    366             CINT_ATOMIC_TYPE_F_INT | CINT_ATOMIC_TYPE_F_UNSIGNED,
    367             __cint_format_unsigned_int, 
    368             NULL,
    369         }, 
    370 
    371         /* Long types */
    372         {
    373             "long", 
    374             sizeof(long), 
    375             CINT_ATOMIC_TYPE_F_LONG | CINT_ATOMIC_TYPE_F_SIGNED,
    376             __cint_format_signed_long,
    377             NULL
    378         }, 
    379         {
    380             "signed long", 
    381             sizeof(long), 
    382             CINT_ATOMIC_TYPE_F_LONG | CINT_ATOMIC_TYPE_F_SIGNED, 
    383             __cint_format_signed_long, 
    384             NULL
    385         }, 
    386         {
    387             "unsigned long", 
    388             sizeof(long), 
    389             CINT_ATOMIC_TYPE_F_LONG | CINT_ATOMIC_TYPE_F_UNSIGNED, 
    390             __cint_format_unsigned_long, 
    391             NULL
    392         }, 
    393 
    394 #if CINT_CONFIG_INCLUDE_LONGLONGS == 1
    395         {
    396             "long long", 
    397             sizeof(long long), 
    398             CINT_ATOMIC_TYPE_F_LONGLONG | CINT_ATOMIC_TYPE_F_SIGNED, 
    399             __cint_format_signed_longlong,
    400             NULL
    401         },
    402         {
    403             "signed long long", 
    404             sizeof(long long), 
    405             CINT_ATOMIC_TYPE_F_LONGLONG | CINT_ATOMIC_TYPE_F_SIGNED, 
    406             __cint_format_signed_longlong, 
    407             NULL
    408         },
    409         {
    410             "unsigned long long", 
    411             sizeof(long long), 
    412             CINT_ATOMIC_TYPE_F_LONGLONG | CINT_ATOMIC_TYPE_F_UNSIGNED, 
    413             __cint_format_unsigned_longlong,
    414             NULL
    415         },
    416 #endif /* CINT_CONFIG_INCLUDE_LONGLONGS */
    417 
    418 
    419 #if CINT_CONFIG_INCLUDE_DOUBLES == 1
    420         {
    421             "double", 
    422             sizeof(double), 
    423             CINT_ATOMIC_TYPE_F_DOUBLE,
    424             __cint_format_double, 
    425             NULL
    426         },
    427         {
    428             "float", 
    429             sizeof(double),
    430             CINT_ATOMIC_TYPE_F_DOUBLE, 
    431             __cint_format_double, 
    432             NULL
    433         },
    434 #endif
    435         {
    436             "void", 
    437             sizeof(void*),
    438             CINT_ATOMIC_TYPE_F_ABSTRACT,
    439             NULL, 
    440             NULL, 
    441         },
    442             
    443         { NULL }, 
    444     }; 
    445 
    446 
    447 /*
    448  * Global Interpreter State
    449  */
    450 cint_interpreter_state_t interp; 
    451 
    452 
    453 static cint_parameter_desc_t __cint_struct_members__cint_interpreter_debug_state_t[] = 
    454     {
    455         {
    456             "int", 
    457             "dtrace", 
    458             0,
    459             0
    460         },
    461         {
    462             "int", 
    463             "atrace", 
    464             0, 
    465             0,
    466         },
    467         {
    468             "int", 
    469             "ftrace", 
    470         },
    471         {       
    472             "int", 
    473             "aunique", 
    474         },
    475         { NULL }
    476     };
    477 
    478 static void*
    479 __cint_maddr__cint_interpreter_debug_state_t(void* p, int mnum, cint_struct_type_t* parent)
    480 {
    481     void* rv;
    482     cint_interpreter_debug_state_t* s = (cint_interpreter_debug_state_t*) p;
    483 
    484     switch(mnum)
    485         {
    486         case 0: rv = &(s->dtrace); break;
    487         case 1: rv = &(s->atrace); break;
    488         case 2: rv = &(s->ftrace); break;
    489         case 3: rv = &(s->aunique); break;
    490         default: rv = NULL; break;
    491         }
    492 
    493     return rv;
    494 }
    495 
    496 static void*
    497 __cint_maddr__cint_interpreter_state_t(void* p, int mnum, cint_struct_type_t* parent)
    498 {
    499     void* rv;
    500     cint_interpreter_state_t* s = (cint_interpreter_state_t*) p;
    501 
    502     switch(mnum)
    503         {
    504         case 0: rv = &(s->debug); break;
    505         case 1: rv = &(s->parse_only); break; 
    506         case 2: rv = &(s->print_expr); break; 
    507         default: rv = NULL; break;
    508     }
    509 
    510     return rv;
    511 }
    512 
    513 static cint_parameter_desc_t __cint_struct_members__cint_interpreter_state_t[] =     
    514     {   
    515         {
    516             "cint_interpreter_debug_state_t", 
    517             "debug", 
    518             0,0
    519         },
    520         {
    521             "int",
    522             "parse_only", 
    523             0, 0
    524         }, 
    525         {
    526             "int",
    527             "print_expr", 
    528             0, 0
    529         }, 
    530         { NULL }, 
    531     }; 
    532 
    533 static cint_struct_type_t __cint_builtin_structures[] = 
    534     {
    535         CINT_STRUCT_TYPE_DEFINE(cint_interpreter_state_t), 
    536         CINT_STRUCT_TYPE_DEFINE(cint_interpreter_debug_state_t),
    537         { NULL }
    538     };
    539   
    540 static cint_constants_t __cint_builtin_constants[] = 
    541     {
    542         /* Basic Constants */
    543 
    544 
    545         /*
    546          * Config option constants. 
    547          * Allows scripts to alter their behavior based on 
    548          * the config options for the interpreter
    549          */
    550 #define __CONFIG_OPTION(_x) { #_x, _x }
    551 #define CONFIG_OPTION(_x) __CONFIG_OPTION(CINT_CONFIG_##_x)
    552 
    553         CONFIG_OPTION(INCLUDE_DOUBLES), 
    554         CONFIG_OPTION(INCLUDE_LONGLONGS), 
    555         CONFIG_OPTION(INCLUDE_MAIN), 
    556         CONFIG_OPTION(MAX_VARIABLE_NAME),
    557         CONFIG_OPTION(INCLUDE_CINT_LOAD),
    558         CONFIG_OPTION(INCLUDE_CINT_SOURCE), 
    559         CONFIG_OPTION(INCLUDE_DTRACE), 
    560         CONFIG_OPTION(INCLUDE_DEBUG), 
    561         CONFIG_OPTION(INCLUDE_STDLIB), 
    562         CONFIG_OPTION(INCLUDE_SDK_SAL), 
    563         CONFIG_OPTION(INCLUDE_TEST_DATA),
    564 
    565         { NULL }
    566     }; 
    567 
    568 CINT_FWRAPPER_CREATE2_VP0(cint_variable_dump); 
    569 
    570 
    571 
    572 void
    573 cint_reset(void)
    574 {
    575     cint_interpreter_init(); 
    576     cint_interpreter_event(cintEventReset); 
    577 }
    578 
    579 int
    580 cint_defined(const char* id)
    581 {
    582     /* 
    583      * Returns 1 if the given name identifier exists. 
    584      * Exported to scripts to control their execution based
    585      * on identifier availability. 
    586      */
    587     int rv = 0; 
    588 
    589     if(id == NULL) {
    590         rv = 0; 
    591     }
    592     else if(cint_variable_find(id, 0)) {
    593         rv = 1; 
    594     }
    595     else if(cint_datatype_enum_find(id, NULL, NULL) == CINT_E_NONE) {
    596         rv = 1; 
    597     }   
    598     else if(cint_constant_find(id, NULL) == CINT_E_NONE) {
    599         rv = 1; 
    600     }
    601     else if(cint_datatype_find(id, NULL) == CINT_E_NONE) {
    602         rv = 1; 
    603     }
    604     else if(cint_interpreter_is_macro(id, NULL)) {
    605         rv = 1; 
    606     }
    607     else if(cint_interpreter_is_iterator(id, NULL)) {
    608         rv = 1; 
    609     }
    610     return rv; 
    611 }
    612            
    613 
    614 CINT_FWRAPPER_CREATE2_VP0(cint_reset); 
    615 CINT_FWRAPPER_CREATE_RP1(int, int, 0, 0, 
    616                          cint_defined, 
    617                          char*, char, identifier, 1, 0); 
    618 
    619 
    620 /*
    621  * Posix Timer routines. Mostly for profiling. 
    622  */
    623 
    624 #if CINT_CONFIG_INCLUDE_POSIX_TIMER == 1
    625 
    626 #include <time.h>
    627 #if (!defined(CLOCK_REALTIME) && !defined(CINT_TIMER_GET)) || \
    628     defined(CINT_USE_GETTIMEOFDAY)
    629 #include <sys/time.h>
    630 #endif /* !CLOCK_REALTIME && !CINT_TIMER_GET */
    631 
    632 unsigned long
    633 cint_timer_get(void)
    634 {
    635 #if defined(CINT_TIMER_GET)
    636     return (unsigned long)CINT_TIMER_GET;
    637 #elif defined(CLOCK_REALTIME) && !defined(CINT_USE_GETTIMEOFDAY)
    638     struct timespec    ltv;
    639     clock_gettime(CLOCK_REALTIME, &ltv);
    640     return (ltv.tv_sec * 1000000 + ltv.tv_nsec / 1000);
    641 #else
    642     struct timeval tv;
    643     gettimeofday(&tv, NULL);
    644     return (tv.tv_sec  * 1000000 + tv.tv_usec);
    645 #endif /* CLOCK_REALTIME */
    646 }
    647 
    648 long
    649 cint_timer_start(long t0)
    650 {
    651     return t0 - cint_timer_get(); 
    652 }
    653 
    654 long
    655 cint_timer_stop(long t0)
    656 {
    657     return t0 + cint_timer_get(); 
    658 }
    659     
    660 CINT_FWRAPPER_CREATE2_RP0(unsigned long, unsigned long, 0, 0, 
    661                          cint_timer_get); 
    662 
    663 CINT_FWRAPPER_CREATE2_RP1(long, long, 0, 0, 
    664                          cint_timer_start,
    665                           long, long, t0, 0, 0, CINT_PARAM_IN); 
    666 
    667 CINT_FWRAPPER_CREATE2_RP1(long, long, 0, 0, 
    668                          cint_timer_stop,
    669                          long, long, t0, 0, 0, CINT_PARAM_IN); 
    670 
    671 #endif /* CINT_CONFIG_INCLUDE_POSIX_TIMER */
    672 
    673 static cint_variable_t* cint_builtin_printf(cint_ast_t* ast); 
    674 static cint_variable_t* cint_builtin_sprintf(cint_ast_t* ast); 
    675 static cint_variable_t* cint_builtin_snprintf(cint_ast_t* ast); 
    676 
    677 static cint_function_t __cint_builtin_functions[] = 
    678         {
    679                 CINT_FWRAPPER_ENTRY(cint_variable_dump), 
    680 #if CINT_CONFIG_INCLUDE_POSIX_TIMER == 1
    681                 CINT_FWRAPPER_ENTRY(cint_timer_start), 
    682                 CINT_FWRAPPER_ENTRY(cint_timer_stop), 
    683                 CINT_FWRAPPER_ENTRY(cint_timer_get), 
    684 #endif 
    685                 CINT_FWRAPPER_ENTRY(cint_reset),
    686                 CINT_FWRAPPER_VARARG_ENTRY("printf", cint_builtin_printf),
    687                 CINT_FWRAPPER_VARARG_ENTRY("sprintf", cint_builtin_sprintf),
    688                 CINT_FWRAPPER_VARARG_ENTRY("snprintf", cint_builtin_snprintf),
    689                 CINT_FWRAPPER_ENTRY(cint_defined), 
    690                 CINT_ENTRY_LAST
    691         }; 
    692 
    693 
    694 cint_data_t cint_builtin_data = 
    695         {   
    696         __cint_builtin_atomics,         /* Atomics */
    697         __cint_builtin_functions,       /* Functions */
    698         __cint_builtin_structures,      /* Structures */
    699         NULL,                           /* Enums */
    700         NULL,                           /* Typedefs */
    701         __cint_builtin_constants,       /* Constants */
    702         NULL,                           /* Cb Functions */
    703     }; 
    704 
    705 typedef enum {
    706     cvt_integer_v,
    707     cvt_long_v,
    708     cvt_longlong_v,
    709     cvt_double_v,
    710     cvt_ptr_string,
    711     cvt_string,
    712     cvt_ptr_void,
    713     cvt_fmt,
    714     cvt_char
    715 } cint_print_driver_cvt_t;
    716 
    717 typedef struct {
    718     char *stg;  /* staging buffer for intermediate prints */
    719     char *out;  /* output buffer for final print */
    720     int len;    /* length of both fmt and out buffer */
    721     int cur;    /* Current length of output buffer */
    722 } cint_print_dest_t;
    723 
    724 typedef int (*cint_print_driver_f)(cint_print_dest_t *dst,
    725                                     const char *fmt,
    726                                     const void *src,
    727                                     cint_print_driver_cvt_t cvt);
    728 
    729 static int
    730 cint_builtin_printf_driver(cint_print_dest_t *dst,
    731                            const char *fmt,
    732                            const void *src,
    733                            cint_print_driver_cvt_t cvt)
    734 {
    735     int len = 0;
    736     switch (cvt) {
    737     case cvt_integer_v:
    738         len = CINT_PRINTF(fmt, cint_integer_value((cint_variable_t *)src)); 
    739         break;
    740     case cvt_long_v:
    741         len = CINT_PRINTF(fmt, cint_long_value((cint_variable_t *)src)); 
    742         break;
    743     case cvt_longlong_v:
    744         len = CINT_PRINTF(fmt, cint_longlong_value((cint_variable_t *)src)); 
    745         break;
    746     case cvt_double_v:
    747         len = CINT_PRINTF(fmt, cint_double_value((cint_variable_t *)src)); 
    748         break;
    749     case cvt_ptr_string:
    750         len = CINT_PRINTF(fmt, *(char**)src); 
    751         break;
    752     case cvt_string:
    753         len = CINT_PRINTF(fmt, (char*)src); 
    754         break;
    755     case cvt_ptr_void:
    756         len = CINT_PRINTF(fmt, *(void**)src); 
    757         break;
    758     case cvt_fmt:
    759         len = CINT_PRINTF(fmt, NULL); 
    760         break;
    761     case cvt_char:
    762         len = CINT_PRINTF(fmt, *(char *)src); 
    763         break;
    764     }
    765     return len;
    766 }
    767 
    768 static int
    769 cint_builtin_sprintf_driver(cint_print_dest_t *dst,
    770                             const char *fmt,
    771                             const void *src,
    772                             cint_print_driver_cvt_t cvt)
    773 {
    774     int n = 0;
    775 
    776     switch (cvt) {
    777     case cvt_integer_v:
    778         n = CINT_SNPRINTF(dst->stg, dst->len, fmt,
    779                           cint_integer_value((cint_variable_t *)src)); 
    780         break;
    781     case cvt_long_v:
    782         n = CINT_SNPRINTF(dst->stg, dst->len, fmt,
    783                           cint_long_value((cint_variable_t *)src)); 
    784         break;
    785     case cvt_longlong_v:
    786         n = CINT_SNPRINTF(dst->stg, dst->len, fmt,
    787                           cint_longlong_value((cint_variable_t *)src)); 
    788         break;
    789     case cvt_double_v:
    790         n = CINT_SNPRINTF(dst->stg, dst->len, fmt,
    791                           cint_double_value((cint_variable_t *)src)); 
    792         break;
    793     case cvt_ptr_string:
    794         n = CINT_SNPRINTF(dst->stg, dst->len, fmt, *(char**)src); 
    795         break;
    796     case cvt_string:
    797         n = CINT_SNPRINTF(dst->stg, dst->len, fmt, (char*)src); 
    798         break;
    799     case cvt_ptr_void:
    800         n = CINT_SNPRINTF(dst->stg, dst->len, fmt, *(void**)src); 
    801         break;
    802     case cvt_fmt:
    803         n = CINT_SNPRINTF(dst->stg, dst->len, fmt, NULL); 
    804         break;
    805     case cvt_char:
    806         n = CINT_SNPRINTF(dst->stg, dst->len, fmt, *(char *)src); 
    807         break;
    808     }
    809 
    810     if (n > 0) {
    811         /* overflow? */
    812         dst->cur += n;
    813         if (dst->cur <= dst->len) {
    814             /* good - cat staging to output. */
    815             CINT_STRNCAT(dst->out, dst->stg, dst->len);
    816         }
    817     }
    818     return n;
    819 }
    820 
    821 static cint_variable_t* 
    822 cint_builtin_print_kernel(char *name,
    823                           cint_print_driver_f print,
    824                           cint_ast_t* ast,
    825                           cint_print_dest_t *dst,
    826                           cint_ast_t* args)
    827 {
    828     char* pfmt; 
    829     const char* s; 
    830     char buffer[CINT_CONFIG_MAX_VARIABLE_NAME+1]; 
    831     char _rstr[256] = {0};
    832     cint_variable_t* ret = NULL;
    833     int len = 0;
    834     /*
    835      * Only constant strings are currently supported
    836      */
    837     if(args && args->ntype == cintAstString) {
    838         pfmt = cint_cstring_value(args->utype.string.s); 
    839     }
    840     else {
    841         cint_ast_error(ast, CINT_E_BAD_AST, "format argument to '%s' must be a string literal", name); 
    842         return NULL; 
    843     }   
    844 
    845     /* Foreach character in the format string */
    846     for(s = pfmt; s && *s;) {
    847 
    848 
    849         /* Embedded variable/perl style */
    850         
    851         if(*s == '$') {
    852             
    853             cint_variable_t* v; 
    854 
    855             s++; 
    856             if(*s == '{') {
    857                 int i = 0; 
    858                 s++; 
    859                 while(*s && *s != '}') {
    860                     buffer[i++] = *s++; 
    861                     buffer[i] = 0; 
    862                 }
    863                 if(*s != '}') {
    864                     cint_ast_error(ast, CINT_E_BAD_AST, "bad variable specifier in format string"); 
    865                     CINT_FREE(pfmt); 
    866                     return NULL; 
    867                 }
    868                 s++; 
    869             }
    870             else {
    871                 int i = 0; 
    872                 /* non-identifer characters */
    873                 while(*s && (*s != ' ' && *s != ':' && *s != '\n' && *s != '\t' && *s != '\r' && 
    874                              *s != '(' && *s != ')' && *s != '\'' && *s != '.')) {
    875                     buffer[i++] = *s++; 
    876                     buffer[i] = 0; 
    877                 }                
    878             }
    879             v = cint_variable_find(buffer, 0);             
    880             if(v == NULL) {
    881                 cint_ast_error(ast, CINT_E_BAD_VARIABLE, "variable '%s' is undefined\n", buffer); 
    882             }
    883             else {
    884                 cint_variable_printf(v); 
    885             }   
    886         }       
    887         /* Printf-style */
    888         else if(*s == '%') {
    889             /* Start of format specifier */
    890             int i = 0;            
    891             int larg = 0; 
    892             int _break = 0; 
    893             cint_variable_t* v; 
    894 
    895             args = args->next;         
    896             v = cint_eval_ast(args); 
    897 
    898             if(v == NULL && s[1] != '%') {
    899                 cint_ast_error(ast, CINT_E_BAD_AST, "error evaluating required argument to printf"); 
    900                 CINT_FREE(pfmt); 
    901                 return NULL; 
    902             }
    903 
    904             buffer[i++] = *s++; 
    905             buffer[i] = 0; 
    906 
    907             while(*s && !_break) {
    908                 buffer[i++] = *s; 
    909                 buffer[i] = 0; 
    910 
    911                 switch(*s)
    912                     {
    913                     case 'l': larg++; break; 
    914                     case 'd': 
    915                     case 'i':
    916                     case 'x':
    917                     case 'X':
    918                     case 'u':
    919                     case 'c':
    920                     case 'o':
    921                         {
    922                             /* Expects an integer type argument */
    923                             unsigned flags = cint_atomic_flags(v); 
    924                             if(flags & (CINT_ATOMIC_TYPE_FLAGS_INTEGRAL)) {
    925                                     
    926                                 if(larg == 0) {
    927                                     len += print(dst, buffer, v, cvt_integer_v); 
    928                                 }
    929                                 else if(larg == 1) {
    930                                     len += print(dst, buffer, v, cvt_long_v); 
    931                                 }
    932                                 else if(larg > 1){
    933                                     len += print(dst, buffer, v, cvt_longlong_v); 
    934                                 }
    935                                 _break = 1; 
    936                             }
    937                             else {
    938                                 cint_ast_error(ast, CINT_E_BAD_TYPE, "printf expected integer type but received %s\n", 
    939                                                (v) ? cint_datatype_format(&v->dt, _rstr, 0) : "none"); 
    940                                 CINT_FREE(pfmt); 
    941                                 return NULL; 
    942                             }  
    943                             break; 
    944                         }
    945                     case 'f':
    946                     case 'F':
    947                     case 'g':
    948                     case 'G':
    949                     case 'e':
    950                     case 'E':
    951                         {
    952                             /* Expects a double type argument */
    953                             unsigned flags = cint_atomic_flags(v); 
    954                             if(flags & CINT_ATOMIC_TYPE_FLAGS_ARITH) {
    955                                 len += print(dst, buffer, v, cvt_double_v); 
    956                                 _break = 1; 
    957                             }
    958                             else {
    959                                 cint_ast_error(ast, CINT_E_BAD_TYPE, "printf expected double type but received %s\n", 
    960                                                (v) ? cint_datatype_format(&v->dt, _rstr, 0) : "none"); 
    961                                 CINT_FREE(pfmt); 
    962                                 return NULL; 
    963                             }       
    964                             break;
    965                         }
    966                     case 's':
    967                         {
    968                             /* Expects a string or char* arguments */
    969                             if(v && 
    970                                 !CINT_STRCMP(v->dt.desc.basetype, "char")) {
    971                                 if(v->dt.desc.pcount == 1 &&
    972                                     v->dt.desc.num_dimensions == 0) {
    973                                     len += print(
    974                                         dst, 
    975                                         buffer,
    976                                         v->data,
    977                                         cvt_ptr_string); 
    978                                 }       
    979                                 else if(v->dt.desc.pcount == 0 && 
    980                                     v->dt.desc.num_dimensions != 0) {
    981                                     len += print(dst, buffer, v->data, cvt_string); 
    982                                 }       
    983                                 _break = 1; 
    984                                 break; 
    985                             }
    986                             cint_ast_error(ast, CINT_E_BAD_TYPE, "printf expected string type but received %s\n", 
    987                                            (v) ? cint_datatype_format(&v->dt, _rstr, 0) : "none"); 
    988                             CINT_FREE(pfmt); 
    989                             return NULL; 
    990                         }
    991                     case 'p':
    992                         {
    993                             if(!v || v->dt.desc.pcount == 0) {
    994                                 cint_ast_error(ast, CINT_E_BAD_TYPE, "printf expected pointer type but received %s\n", 
    995                                                (v) ? cint_datatype_format(&v->dt, _rstr, 0) : "none"); 
    996                                 CINT_FREE(pfmt); 
    997                                 return NULL; 
    998                             }   
    999                             else {
   1000                                 len += print(dst, buffer, v->data, cvt_ptr_void); 
   1001                                 _break = 1; 
   1002                             }
   1003                             break; 
   1004                         }
   1005                     case '%':
   1006                         {
   1007                             len += print(dst, buffer, NULL, cvt_fmt); 
   1008                             _break = 1; 
   1009                             break; 
   1010                         }                        
   1011                     }
   1012                 s++; 
   1013             }
   1014         }
   1015         else {
   1016             len += print(dst, "%c", s++, cvt_char); 
   1017         }
   1018     }
   1019     
   1020     CINT_FREE(pfmt); 
   1021     ret = cint_auto_integer(len);
   1022     return ret;
   1023 }
   1024 
   1025 
   1026 static cint_variable_t* 
   1027 cint_builtin_printf(cint_ast_t* ast)
   1028 {
   1029     return cint_builtin_print_kernel("printf",
   1030                                      cint_builtin_printf_driver,
   1031                                      ast,
   1032                                      NULL,
   1033                                      ast->utype.function.parameters);
   1034 }
   1035 
   1036 static cint_variable_t *
   1037 _cint_builtin_print_buffer(cint_ast_t* ast)
   1038 {
   1039     cint_variable_t *str;
   1040 
   1041     /* Evaluate the first argument and expect a character buffer */
   1042     str = cint_eval_ast(ast);
   1043     if (str == NULL) {
   1044         cint_ast_error(ast, CINT_E_BAD_VARIABLE,
   1045                        "could not evaluate the first argument (string)");
   1046         return NULL;
   1047     }
   1048 
   1049     if (!((CINT_STRCMP(str->dt.desc.basetype, "char")==0) &&
   1050           (((str->dt.desc.pcount == 1) && 
   1051             (str->dt.desc.num_dimensions == 0)) ||
   1052            ((str->dt.desc.pcount == 0) && 
   1053             (str->dt.desc.num_dimensions > 0))))) {
   1054         cint_ast_error(ast, CINT_E_BAD_VARIABLE, 
   1055                        "the first argument (str) must be a char* or char[]");
   1056         return NULL;
   1057     }
   1058 
   1059     return str;
   1060 }
   1061 
   1062 static cint_variable_t* 
   1063 cint_builtin_sprintf(cint_ast_t* ast)
   1064 {
   1065     cint_variable_t *str;
   1066     cint_variable_t* v;
   1067     cint_ast_t* arg;
   1068     cint_print_dest_t dst;
   1069 
   1070     arg = ast->utype.function.parameters;
   1071 
   1072     /* Evaluate the first argument and expect a character buffer */
   1073     str = _cint_builtin_print_buffer(arg);
   1074     if (str == NULL) {
   1075         return str;
   1076     }
   1077 
   1078     /* 
   1079      * The function needs to deal with two ways a string can be
   1080      * passed, that are quite different in CINT.
   1081      *
   1082      *  1) It can be a real char*. In that case, str->data points to
   1083      *  the place, where the pointer is stored, so additional
   1084      *  dereference is required. Also in that case the actual buffer
   1085      *  length is unknown, so we simply allocate a big buffer for the
   1086      *  staging area and pray that the result fits. If not, the
   1087      *  program will crash, just like any other C program that uses
   1088      *  sprintf() unsafely.
   1089      *
   1090      *  2) It can also be a char[]. In that case, str->data points to
   1091      *  the first character in the array. Moreover, we have the
   1092      *  information about the length of the array and we'll use it for
   1093      *  the staging buffer allocation
   1094  */
   1095     if (str->dt.desc.pcount == 1) { 
   1096         dst.out = *(char **)str->data;   /* char * was passed */
   1097         dst.len = CINT_CONFIG_SPRINTF_BUFFER_LENGTH;
   1098     } else {
   1099         dst.out = (char *)str->data;     /* char[] was passed */
   1100         dst.len = str->dt.desc.dimensions[0];
   1101     }
   1102 
   1103     dst.stg = CINT_MALLOC(dst.len);
   1104     if (!dst.stg) {
   1105         cint_ast_error(ast, CINT_E_MEMORY, "memory allocation failure");
   1106         return NULL;
   1107     }
   1108 
   1109     dst.out[0] = 0; /* start output buffer with a zero length string */
   1110     dst.cur = 1; /* account for terminating NUL */
   1111     /* go print */
   1112     v = cint_builtin_print_kernel("sprintf",
   1113                                   cint_builtin_sprintf_driver,
   1114                                   ast, &dst, arg->next);
   1115     CINT_FREE(dst.stg);
   1116     if (dst.cur > dst.len) {
   1117         cint_ast_error(ast, CINT_E_BAD_AST,
   1118                        "buffer length too small, "
   1119                        "allocated %d chars, needs %d chars",
   1120                        dst.len, dst.cur);
   1121     }
   1122 
   1123     return v;
   1124 }
   1125 static cint_variable_t* 
   1126 cint_builtin_snprintf(cint_ast_t* ast)
   1127 {
   1128     cint_variable_t* str;
   1129     cint_variable_t* size;
   1130     cint_variable_t* v;
   1131     cint_ast_t* arg;
   1132     cint_print_dest_t dst;
   1133 
   1134     arg = ast->utype.function.parameters;
   1135 
   1136     /* Evaluate the first argument and expect a character buffer */
   1137     str = _cint_builtin_print_buffer(arg);
   1138     if (str == NULL) {
   1139         return str;
   1140     }
   1141 
   1142     /* Evaluate the second argument and get an integer */
   1143     size = cint_eval_ast(arg->next);
   1144     if (size == NULL) {
   1145         cint_ast_error(ast, CINT_E_BAD_VARIABLE, 
   1146                        "could not evaluate the second argument (size)");
   1147         return NULL;
   1148     }
   1149         
   1150     if (!cint_is_integer(size)) {
   1151         cint_ast_error(ast, CINT_E_BAD_VARIABLE, 
   1152                        "the second argument (size) must be an integral type");
   1153         return NULL;
   1154     }
   1155 
   1156     /* Setup destination buffers. The staging buffer is the same size as the
   1157        output buffer for the worst case. */
   1158     dst.len = cint_integer_value(size);
   1159 
   1160     /* 
   1161      * The function needs to deal with two ways a string can be
   1162      * passed, that are quite different in CINT.
   1163      *
   1164      *  1) It can be a real char*. In that case, str->data points to
   1165      *  the place, where the pointer is stored, so additional
   1166      *  dereference is required
   1167      *
   1168      *  2) It can also be a char[]. In that case, str->data points to
   1169      *  the first character in the array. Moreover, we have the
   1170      *  information about the length of the array and thus we can
   1171      *  perform an additional check
   1172      */
   1173 
   1174     if (str->dt.desc.pcount == 1) { 
   1175         dst.out = *(char **)str->data;   /* char * was passed */
   1176     } else {
   1177         dst.out = (char *)str->data;     /* char[] was passed */
   1178         if (dst.len > str->dt.desc.dimensions[0]) { 
   1179             /* Most probably we'll be out of bounds */
   1180             cint_ast_error(ast, CINT_E_BAD_VARIABLE,
   1181                            "the first parameter is an array of length %d "
   1182                            "and the second parameter exceeds that length",
   1183                            str->dt.desc.dimensions[0]);
   1184             return NULL;
   1185         }  
   1186     }
   1187 
   1188     dst.stg = CINT_MALLOC(dst.len);
   1189     if (!dst.stg) {
   1190         cint_ast_error(ast, CINT_E_MEMORY, "memory allocation failure");
   1191         return NULL;
   1192     }
   1193 
   1194     dst.out[0] = 0; /* start output buffer with a zero length string */
   1195     dst.cur = 1; /* account for terminating NUL */
   1196     /* go print */
   1197     v = cint_builtin_print_kernel("snprintf",
   1198                                   cint_builtin_sprintf_driver,
   1199                                   ast, &dst, arg->next->next);
   1200     CINT_FREE(dst.stg);
   1201     if (dst.cur > dst.len) {
   1202         cint_ast_error(ast, CINT_E_BAD_AST,
   1203                        "buffer length too small, "
   1204                        "allocated %d chars, needs %d chars",
   1205                        dst.len, dst.cur);
   1206     }
   1207 
   1208     return v;
   1209 }