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, <v); 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 }