1/*---------------------------------------------------------------------------* 2 | PDFlib - A library for generating PDF on the fly | 3 +---------------------------------------------------------------------------+ 4 | Copyright (c) 1997-2004 Thomas Merz and PDFlib GmbH. All rights reserved. | 5 +---------------------------------------------------------------------------+ 6 | | 7 | This software is subject to the PDFlib license. It is NOT in the | 8 | public domain. Extended versions and commercial licenses are | 9 | available, please check http://www.pdflib.com. | 10 | | 11 *---------------------------------------------------------------------------*/ 12 13/* $Id: pc_core.c 14574 2005-10-29 16:27:43Z bonefish $ 14 * 15 * PDFlib core services 16 * 17 */ 18 19#ifndef WINCE 20#include <time.h> 21#else 22#include <winbase.h> 23#endif 24 25#include "pc_util.h" 26 27#define PDF_NonfatalError 11 28#define PDF_UnknownError 12 29 30 31/* TODO: how to make this dynamic? 32** exception during pdc_core_init(): 33** - out of memory in pdc_sb_new() 34** exception during exception: 35** - out of memory in pdc_sb_vprintf() 36** - format error in pdc_sb_vprintf() 37*/ 38#define PDC_ERRPARM_SIZE 2048 39#define PDC_ERRBUF_SIZE (5 * PDC_ERRPARM_SIZE) 40#define PDC_XSTACK_INISIZE 10 41 42#define N_ERRTABS (PDC_ET_LAST / 1000) 43 44/* exception handling frame. 45*/ 46typedef struct 47{ 48 pdc_jmpbuf jbuf; 49 /* we could anchor a destructor list here. */ 50} pdc_xframe; 51 52typedef struct 53{ 54 pdc_error_info * ei; 55 int n_entries; 56} error_table; 57 58 59/* ------------------------ the core core structure ---------------------- */ 60 61struct pdc_core_s { 62 /* ------------ try/catch ------------ */ 63 pdc_xframe * x_stack; 64 int x_ssize; 65 int x_sp; /* exception stack pointer */ 66 67 /* ------------ error handling ------------ */ 68 pdc_bool warnings_enabled; 69 pdc_bool in_error; 70 char errbuf[PDC_ERRBUF_SIZE]; 71 char errparms[4][PDC_ERRPARM_SIZE]; 72 int epcount; 73 int errnum; 74 pdc_bool x_thrown; /* exception thrown and not caught */ 75 const char * apiname; 76 pdc_error_fp errorhandler; /* client error handler */ 77 void * opaque; /* client specific, opaque data */ 78 79 error_table err_tables[N_ERRTABS]; 80 81 /* ------------------ tracing ---------------- */ 82 pdc_bool trace; /* trace feature enabled? */ 83 char * tracefilename; /* name of the trace file */ 84 int floatdigits; /* floating point output precision */ 85 86 /* ------------ memory management ------------ */ 87 pdc_alloc_fp allocproc; 88 pdc_realloc_fp reallocproc; 89 pdc_free_fp freeproc; 90}; 91 92 93 94/* ----------- default memory management & error handling ----------- */ 95 96static void * 97default_malloc(void *opaque, size_t size, const char *caller) 98{ 99 (void) opaque; 100 (void) caller; 101 102 return malloc(size); 103} 104 105static void * 106default_realloc(void *opaque, void *mem, size_t size, const char *caller) 107{ 108 (void) opaque; 109 (void) caller; 110 111 return realloc(mem, size); 112} 113 114static void 115default_free(void *opaque, void *mem) 116{ 117 (void) opaque; 118 119 free(mem); 120} 121 122static void 123default_errorhandler(void *opaque, int errnum, const char *msg) 124{ 125 (void) opaque; 126 127 if (errnum == PDF_NonfatalError) 128 { 129 fprintf(stderr, "PDFlib warning (ignored): %s\n", msg); 130 } 131 else 132 { 133 fprintf(stderr, "PDFlib exception (fatal): %s\n", msg); 134 exit(99); 135 } 136} 137 138pdc_bool 139pdc_enter_api(pdc_core *pdc, const char *apiname) 140{ 141 if (pdc->in_error) 142 return pdc_false; 143 144 pdc->errnum = 0; 145 pdc->apiname = apiname; 146 return pdc_true; 147} 148 149void 150pdc_set_warnings(pdc_core *pdc, pdc_bool on) 151{ 152 pdc->warnings_enabled = on; 153} 154 155pdc_bool 156pdc_in_error(pdc_core *pdc) 157{ 158 return pdc->in_error; 159} 160 161 162/* --------------------- error table management --------------------- */ 163 164static pdc_error_info core_errors[] = 165{ 166#define pdc_genInfo 1 167#include "pc_generr.h" 168}; 169 170#define N_CORE_ERRORS (sizeof core_errors / sizeof (pdc_error_info)) 171 172 173static void 174pdc_panic(pdc_core *pdc, const char *fmt, ...) 175{ 176 va_list ap; 177 178 va_start(ap, fmt); 179 vsprintf(pdc->errbuf, fmt, ap); 180 va_end(ap); 181 182 pdc->errnum = PDF_UnknownError; 183 (*pdc->errorhandler)(pdc->opaque, pdc->errnum, pdc->errbuf); 184} /* pdc_panic */ 185 186 187static void 188check_parms(pdc_core *pdc, pdc_error_info *ei) 189{ 190 const char *msg = ei->errmsg; 191 const char *dollar; 192 193 while ((dollar = strchr(msg, '$')) != (char *) 0) 194 { 195 if (isdigit(dollar[1])) 196 { 197 int n = dollar[1] - '0'; 198 199 if (ei->nparms < n || n < 1) 200 pdc_panic(pdc, "illegal parameter '$%d' in error message %d", 201 n, ei->errnum); 202 } 203 else if (dollar[1] != '$') 204 { 205 pdc_panic(pdc, 206 "illegal '$' in error message %d", ei->errnum); 207 } 208 209 msg = dollar + 1; 210 } 211} /* check_parms */ 212 213 214void 215pdc_register_errtab(pdc_core *pdc, int et, pdc_error_info *ei, int n_entries) 216{ 217 int i; 218 int n = (et / 1000) - 1; 219 220 if (n < 0 || N_ERRTABS <= n || et % 1000 != 0) 221 pdc_panic(pdc, "tried to register unknown error table %d", et); 222 223 /* ignore multiple registrations of the same table. 224 */ 225 if (pdc->err_tables[n].ei != (pdc_error_info *) 0) 226 return; 227 228 check_parms(pdc, &ei[0]); 229 230 for (i = 1; i < n_entries; ++i) 231 { 232 if (ei[i].errnum <= ei[i-1].errnum) 233 { 234 pdc_panic(pdc, 235 "duplicate or misplaced error number %d", ei[i].errnum); 236 } 237 238 check_parms(pdc, &ei[i]); 239 } 240 241 pdc->err_tables[n].ei = ei; 242 pdc->err_tables[n].n_entries = n_entries; 243} /* pdc_register_errtab */ 244 245 246/* pdc_init_core() never throws exceptions. 247** it returns NULL if there's not enough memory. 248*/ 249pdc_core * 250pdc_init_core( 251 pdc_error_fp errorhandler, 252 pdc_alloc_fp allocproc, 253 pdc_realloc_fp reallocproc, 254 pdc_free_fp freeproc, 255 void *opaque) 256{ 257 static const char fn[] = "pdc_init_core"; 258 259 pdc_core *pdc; 260 int i; 261 262 /* if allocproc is NULL, we use pdc's default memory handling. 263 */ 264 if (allocproc == (pdc_alloc_fp) 0) 265 { 266 allocproc = default_malloc; 267 reallocproc = default_realloc; 268 freeproc = default_free; 269 } 270 271 if (errorhandler == (pdc_error_fp) 0) 272 errorhandler = default_errorhandler; 273 274 pdc = (pdc_core *) (*allocproc)(opaque, sizeof (pdc_core), fn); 275 276 if (pdc == (pdc_core *) 0) 277 return (pdc_core *) 0; 278 279 pdc->errorhandler = errorhandler; 280 pdc->allocproc = allocproc; 281 pdc->reallocproc = reallocproc; 282 pdc->freeproc = freeproc; 283 pdc->opaque = opaque; 284 285 pdc->trace = pdc_false; 286 pdc->tracefilename = NULL; 287 pdc->floatdigits = 4; 288 289 /* initialize error & exception handling. 290 */ 291 pdc->warnings_enabled = pdc_true; 292 pdc->in_error = pdc_false; 293 pdc->x_thrown = pdc_false; 294 pdc->epcount = 0; 295 pdc->errnum = 0; 296 pdc->apiname = ""; 297 pdc->x_sp = -1; 298 pdc->x_ssize = PDC_XSTACK_INISIZE; 299 pdc->x_stack = (pdc_xframe *) 300 (*allocproc)(opaque, pdc->x_ssize * sizeof (pdc_xframe), fn); 301 302 if (pdc->x_stack == (pdc_xframe *) 0) 303 { 304 (*freeproc)(opaque, pdc); 305 return (pdc_core *) 0; 306 } 307 308 /* initialize error tables. 309 */ 310 for (i = 0; i < N_ERRTABS; ++i) 311 pdc->err_tables[i].ei = (pdc_error_info *) 0; 312 313 pdc_register_errtab(pdc, PDC_ET_CORE, core_errors, N_CORE_ERRORS); 314 315 return pdc; 316} 317 318void 319pdc_delete_core(pdc_core *pdc) 320{ 321 int i; 322 323 if (pdc->tracefilename) 324 pdc_free(pdc, pdc->tracefilename); 325 326 pdc_free(pdc, pdc->x_stack); 327 328 329 pdc_free(pdc, pdc); 330} 331 332/* --------------------------- memory management --------------------------- */ 333 334void * 335pdc_malloc(pdc_core *pdc, size_t size, const char *caller) 336{ 337 void *ret; 338 339 /* the behavior of malloc(0) is undefined in ANSI C, and may 340 * result in a NULL pointer return value which makes PDFlib bail out. 341 */ 342 if (size == (size_t) 0 || (long) size < 0L) { 343 size = (size_t) 1; 344 pdc_warning(pdc, PDC_E_INT_ALLOC0, caller, 0, 0, 0); 345 } 346 347 if ((ret = (*pdc->allocproc)(pdc->opaque, size, caller)) == (void *) 0) 348 { 349 pdc_error(pdc, PDC_E_MEM_OUT, caller, 0, 0, 0); 350 } 351 352 return ret; 353} 354 355/* We cook up our own calloc routine, using the caller-supplied 356 * malloc and memset. 357 */ 358void * 359pdc_calloc(pdc_core *pdc, size_t size, const char *caller) 360{ 361 void *ret; 362 363 if (size == (size_t) 0 || (long) size < 0L) { 364 size = (size_t) 1; 365 pdc_warning(pdc, PDC_E_INT_ALLOC0, caller, 0, 0, 0); 366 } 367 368 if ((ret = (*pdc->allocproc)(pdc->opaque, size, caller)) == (void *) 0) 369 { 370 pdc_error(pdc, PDC_E_MEM_OUT, caller, 0, 0, 0); 371 } 372 373 memset(ret, 0, size); 374 return ret; 375} 376 377void * 378pdc_realloc(pdc_core *pdc, void *mem, size_t size, const char *caller) 379{ 380 void *ret; 381 382 if (size == (size_t) 0 || (long) size < 0L) { 383 size = (size_t) 1; 384 pdc_warning(pdc, PDC_E_INT_ALLOC0, caller, 0, 0, 0); 385 } 386 387 if ((ret = (*pdc->reallocproc)(pdc->opaque, mem, size, caller)) 388 == (void *) 0) 389 pdc_error(pdc, PDC_E_MEM_OUT, caller, 0, 0, 0); 390 391 return ret; 392} 393 394void 395pdc_free(pdc_core *pdc, void *mem) 396{ 397 /* just in case the freeproc() isn't that ANSI compatible... 398 */ 399 if (mem != NULL) 400 (*pdc->freeproc)(pdc->opaque, mem); 401} 402 403 404/* --------------------------- exception handling --------------------------- */ 405 406const char *pdc_errprintf(pdc_core *pdc, const char *fmt, ...) 407{ 408 va_list ap; 409 410 if (pdc->epcount < 0 || pdc->epcount > 3) 411 pdc->epcount = 0; 412 413 va_start(ap, fmt); 414 vsprintf(pdc->errparms[pdc->epcount], fmt, ap); 415 va_end(ap); 416 417 return pdc->errparms[pdc->epcount++]; 418} 419 420static pdc_error_info * 421get_error_info(pdc_core *pdc, int errnum) 422{ 423 int n = (errnum / 1000) - 1; 424 425 if (0 <= n && n < N_ERRTABS && pdc->err_tables[n].ei != 0) 426 { 427 error_table *etab = &pdc->err_tables[n]; 428 int i; 429 430 /* LATER: binary search. */ 431 for (i = 0; i < etab->n_entries; ++i) 432 { 433 if (etab->ei[i].errnum == errnum) 434 return &etab->ei[i]; 435 } 436 } 437 438 pdc_panic(pdc, "Internal error: unknown error number %d", errnum); 439 440 return (pdc_error_info *) 0; /* for the compiler */ 441} /* get_error_info */ 442 443 444static void 445make_errmsg( 446 pdc_core * pdc, 447 pdc_error_info * ei, 448 const char * parm1, 449 const char * parm2, 450 const char * parm3, 451 const char * parm4) 452{ 453 const char *src = ei->ce_msg ? ei->ce_msg : ei->errmsg; 454 char * dst = pdc->errbuf; 455 const char *dollar; 456 457 pdc->epcount = 0; 458 459 /* copy *src to *dst, replacing "$N" with *parmN. 460 */ 461 while ((dollar = strchr(src, '$')) != (char *) 0) 462 { 463 const char *parm = (const char *) 0; 464 465 memcpy(dst, src, (size_t) (dollar - src)); 466 dst += dollar - src; 467 src = dollar + 1; 468 469 switch (*src) 470 { 471 case '1': parm = (parm1 ? parm1 : "?"); break; 472 case '2': parm = (parm2 ? parm2 : "?"); break; 473 case '3': parm = (parm3 ? parm3 : "?"); break; 474 case '4': parm = (parm4 ? parm4 : "?"); break; 475 476 case 0: break; 477 478 default: *(dst++) = *(src++); 479 break; 480 } 481 482 if (parm != (const char *) 0) 483 { 484 ++src; 485 strcpy(dst, parm); 486 dst += strlen(parm); 487 } 488 } 489 490 strcpy(dst, src); 491} /* make_errmsg */ 492 493 494void 495pdc_set_errmsg( 496 pdc_core * pdc, 497 int errnum, 498 const char *parm1, 499 const char *parm2, 500 const char *parm3, 501 const char *parm4) 502{ 503 pdc_error_info *ei = get_error_info(pdc, errnum); 504 505 make_errmsg(pdc, ei, parm1, parm2, parm3, parm4); 506 pdc->errnum = errnum; 507} /* pdc_set_errmsg */ 508 509 510void 511pdc_error( 512 pdc_core * pdc, 513 int errnum, 514 const char *parm1, 515 const char *parm2, 516 const char *parm3, 517 const char *parm4) 518{ 519 if (pdc->in_error) /* avoid recursive errors. */ 520 return; 521 else 522 { 523 pdc->in_error = pdc_true; 524 pdc->x_thrown = pdc_true; 525 } 526 527 if (errnum != -1) 528 { 529 pdc_error_info *ei = get_error_info(pdc, errnum); 530 531 make_errmsg(pdc, ei, parm1, parm2, parm3, parm4); 532 pdc->errnum = errnum; 533 } 534 535 pdc_trace(pdc, "\n[+++ exception %d in %s, %s +++]\n", 536 pdc->errnum, (pdc->errnum == 0) ? "" : pdc->apiname, 537 (pdc->x_sp == -1 ? "error handler active" : "try/catch active")); 538 pdc_trace(pdc, "[\"%s\"]\n\n", pdc->errbuf); 539 540 if (pdc->x_sp == -1) { 541 char errbuf[PDC_ERRBUF_SIZE]; 542 543 sprintf(errbuf, "[%d] %s: %s", 544 pdc->errnum, pdc_get_apiname(pdc), pdc->errbuf); 545 (*pdc->errorhandler)(pdc->opaque, PDF_UnknownError, errbuf); 546 547 /* 548 * The error handler must never return. If it does, it is severely 549 * broken. We cannot remedy this, so we exit. 550 */ 551 exit(99); 552 553 } else { 554 555 longjmp(pdc->x_stack[pdc->x_sp].jbuf.jbuf, 1); 556 } 557 558} /* pdc_error */ 559 560 561void 562pdc_warning( 563 pdc_core * pdc, 564 int errnum, 565 const char *parm1, 566 const char *parm2, 567 const char *parm3, 568 const char *parm4) 569{ 570 if (pdc->in_error || pdc->warnings_enabled == pdc_false) 571 return; 572 else 573 { 574 pdc->in_error = pdc_true; 575 pdc->x_thrown = pdc_true; 576 } 577 578 if (errnum != -1) 579 { 580 pdc_error_info *ei = get_error_info(pdc, errnum); 581 582 make_errmsg(pdc, ei, parm1, parm2, parm3, parm4); 583 pdc->errnum = errnum; 584 } 585 586 pdc_trace(pdc, "\n[+++ warning %d in %s, %s +++]\n", 587 pdc->errnum, (pdc->errnum == 0) ? "" : pdc->apiname, 588 (pdc->x_sp == -1 ? "error handler active" : "try/catch active")); 589 pdc_trace(pdc, "[\"%s\"]\n\n", pdc->errbuf); 590 591 if (pdc->x_sp == -1) { 592 char errbuf[PDC_ERRBUF_SIZE]; 593 594 sprintf(errbuf, "[%d] %s: %s", 595 pdc->errnum, pdc_get_apiname(pdc), pdc->errbuf); 596 (*pdc->errorhandler)(pdc->opaque, PDF_NonfatalError, errbuf); 597 598 } else { 599 600 longjmp(pdc->x_stack[pdc->x_sp].jbuf.jbuf, 1); 601 } 602 603 /* a client-supplied error handler may return after a warning */ 604 pdc->in_error = pdc_false; 605 606} /* pdc_warning */ 607 608 609pdc_jmpbuf * 610pdc_jbuf(pdc_core *pdc) 611{ 612 static const char fn[] = "pdc_jbuf"; 613 614 if (++pdc->x_sp == pdc->x_ssize) 615 { 616 /* TODO: test */ 617 pdc_xframe *aux = (pdc_xframe *) (*pdc->reallocproc)( 618 pdc->opaque, pdc->x_stack, 619 2 * pdc->x_ssize * sizeof (pdc_xframe), fn); 620 621 if (aux == (pdc_xframe *) 0) 622 { 623 --pdc->x_sp; 624 pdc->errnum = PDC_E_MEM_OUT; 625 pdc->x_thrown = pdc_true; 626 pdc->in_error = pdc_true; 627 strcpy(pdc->errbuf, "out of memory"); 628 longjmp(pdc->x_stack[pdc->x_sp].jbuf.jbuf, 1); 629 } 630 631 pdc->x_stack = aux; 632 pdc->x_ssize *= 2; 633 } 634 635 pdc->x_thrown = pdc_false; 636 return &pdc->x_stack[pdc->x_sp].jbuf; 637} /* pdc_jbuf */ 638 639void 640pdc_exit_try(pdc_core *pdc) 641{ 642 if (pdc->x_sp == -1) 643 { 644 strcpy(pdc->errbuf, "exception stack underflow"); 645 pdc->errnum = PDC_E_INT_XSTACK; 646 (*pdc->errorhandler)(pdc->opaque, PDF_UnknownError, pdc->errbuf); 647 } 648 else 649 --pdc->x_sp; 650} /* pdc_exit_try */ 651 652int 653pdc_catch_intern(pdc_core *pdc) 654{ 655 pdc_bool result; 656 657 if (pdc->x_sp == -1) 658 { 659 strcpy(pdc->errbuf, "exception stack underflow"); 660 pdc->errnum = PDC_E_INT_XSTACK; 661 (*pdc->errorhandler)(pdc->opaque, PDF_UnknownError, pdc->errbuf); 662 } 663 else 664 --pdc->x_sp; 665 666 result = pdc->x_thrown; 667 pdc->in_error = pdc_false; 668 pdc->x_thrown = pdc_false; 669 670 return result; 671} /* pdc_catch_intern */ 672 673int 674pdc_catch_extern(pdc_core *pdc) 675{ 676 pdc_bool result; 677 678 if (pdc->x_sp == -1) 679 { 680 strcpy(pdc->errbuf, "exception stack underflow"); 681 pdc->errnum = PDC_E_INT_XSTACK; 682 (*pdc->errorhandler)(pdc->opaque, PDF_UnknownError, pdc->errbuf); 683 } 684 else 685 --pdc->x_sp; 686 687 result = pdc->x_thrown; 688 pdc->x_thrown = pdc_false; 689 690 return result; 691} /* pdc_catch_extern */ 692 693void 694pdc_rethrow(pdc_core *pdc) 695{ 696 pdc_error(pdc, -1, 0, 0, 0, 0); 697} /* pdc_rethrow */ 698 699 700int 701pdc_get_errnum(pdc_core *pdc) 702{ 703 return pdc->errnum; 704} 705 706const char * 707pdc_get_errmsg(pdc_core *pdc) 708{ 709 return (pdc->errnum == 0) ? "" : pdc->errbuf; 710} 711 712const char * 713pdc_get_apiname(pdc_core *pdc) 714{ 715 return (pdc->errnum == 0) ? "" : pdc->apiname; 716} 717 718 719/* --------------------------- debug trace --------------------------- */ 720 721static const char digits[] = "0123456789ABCDEF"; 722 723static char * 724pdc_ltoa(char *buf, long n, int width, char pad, int base) 725{ 726 char aux[20]; 727 int k, i = sizeof aux; 728 char * dest = buf; 729 unsigned long ul = (unsigned long) n; 730 731 if (n == 0) 732 { 733 if (width == 0) 734 width = 1; 735 736 for (k = 0; k < width; ++k) 737 *(dest++) = '0'; 738 739 return dest; 740 } 741 742 if (n < 0 && base == 10) 743 { 744 ul = (unsigned long) -ul; /* safe against overflow, 745 while "n = -n" isn't! */ 746 *(dest++) = '-'; 747 } 748 749 aux[--i] = digits[ul % base]; 750 n = (long) (ul / base); 751 752 while (0 < n) 753 { 754 aux[--i] = digits[n % base]; 755 n = n / base; 756 } 757 758 width -= (int) (sizeof aux) - i; 759 for (k = 0; k < width; ++k) 760 *(dest++) = pad; 761 762 memcpy(dest, &aux[i], sizeof aux - i); 763 return dest + sizeof aux - i; 764} /* pdc_ltoa */ 765 766/* Acrobat viewers have an upper limit on real and integer numbers */ 767#define PDF_BIGREAL (32768.0) 768#define PDF_BIGINT (2147483647.0) 769 770static char * 771pdc_ftoa(pdc_core *pdc, char *buf, double x) 772{ 773 static const long pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000 }; 774 775 char * dest = buf; 776 double integ, fract; 777 long f; 778 779 if (fabs(x) < PDF_SMALLREAL) 780 { 781 *dest = '0'; 782 return dest + 1; 783 } 784 785 if (x < 0) 786 { 787 x = -x; 788 *(dest++) = '-'; 789 } 790 791 if (x >= PDF_BIGREAL) 792 { 793 if (x > PDF_BIGINT) 794 pdc_error(pdc, PDC_E_INT_FLOATTOOLARGE, 0, 0, 0, 0); 795 796 return pdc_ltoa(dest, (long) floor(x + 0.5), 0, ' ', 10); 797 } 798 799 fract = modf(x, &integ); 800 f = (long) floor(fract * pow10[pdc->floatdigits] + 0.5); 801 802 if (f == pow10[pdc->floatdigits]) 803 { 804 integ += 1.0; 805 f = 0; 806 } 807 808 if (integ == 0 && f == 0) /* avoid "-0" */ 809 dest = buf; 810 811 dest = pdc_ltoa(dest, (long) integ, 0, ' ', 10); 812 813 if (f != 0) 814 { 815 char * aux; 816 int i = pdc->floatdigits; 817 long rem; 818 819 *(dest++) = '.'; 820 821 do /* avoid trailing zeros */ 822 { 823 rem = f % 10; 824 f = f / 10; 825 --i; 826 } while (rem == 0); 827 828 aux = dest + i + 1; 829 dest[i--] = digits[rem]; 830 831 for (; 0 <= i; --i) 832 { 833 dest[i] = digits[f % 10]; 834 f = f / 10; 835 } 836 837 return aux; 838 } 839 840 return dest; 841} /* pdc_ftoa */ 842 843int 844pdc_vsprintf(pdc_core *pdc, char *buf, const char *format, va_list args) 845{ 846 char *dest = buf; 847 848 for (/* */ ; /* */ ; /* */) 849 { 850 int width = 0; 851 char pad = ' '; 852 853 /* as long as there is no '%', just print. 854 */ 855 while (*format != 0 && *format != '%') 856 *(dest++) = *(format++); 857 858 if (*format == 0) 859 { 860 *dest = 0; 861 return dest - buf; 862 } 863 864 if (*(++format) == '0') 865 { 866 pad = '0'; 867 ++format; 868 } 869 870 while (isdigit(*format)) 871 width = 10*width + *(format++) - '0'; 872 873 switch (*format) 874 { 875 case 'X': 876 dest = pdc_ltoa(dest, va_arg(args, int), width, pad, 16); 877 break; 878 879 case 'c': 880 *(dest++) = (char) va_arg(args, int); 881 break; 882 883 case 'd': 884 dest = pdc_ltoa(dest, va_arg(args, int), width, pad, 10); 885 break; 886 887 case 'g': /* for use in pdc_trace_api() */ 888 case 'f': 889 dest = pdc_ftoa(pdc, dest, va_arg(args, double)); 890 break; 891 892 case 'l': 893 { 894 long n = va_arg(args, long); 895 896 switch (*(++format)) 897 { 898 case 'X': 899 dest = pdc_ltoa(dest, n, width, pad, 16); 900 break; 901 902 case 'd': 903 dest = pdc_ltoa(dest, n, width, pad, 10); 904 break; 905 906 default: 907 pdc_error(pdc, PDC_E_INT_BADFORMAT, 908 pdc_errprintf(pdc, "l%c", 909 isprint(*format) ? *format : '?'), 910 pdc_errprintf(pdc, "0x%02X", *format), 911 0, 0); 912 } 913 914 break; 915 } 916 917 case 'p': 918 { 919 void *ptr = va_arg(args, void *); 920 dest += sprintf(dest, "%p", ptr); 921 break; 922 } 923 924 case 's': 925 { 926 char * str = va_arg(args, char *); 927 size_t len; 928 929 if (str == 0) 930 str = "(NULL)"; 931 932 if ((len = strlen(str)) != 0) 933 { 934 memcpy(dest, str, len); 935 dest += len; 936 } 937 break; 938 } 939 940 case '%': 941 *(dest++) = '%'; 942 break; 943 944 default: 945 pdc_error(pdc, PDC_E_INT_BADFORMAT, 946 pdc_errprintf(pdc, "%c", isprint(*format) ? *format : '?'), 947 pdc_errprintf(pdc, "0x%02X", *format), 948 0, 0); 949 } /* switch */ 950 951 ++format; 952 } /* loop */ 953} /* pdc_vsprintf */ 954 955void 956pdc_set_floatdigits(pdc_core *pdc, int val) 957{ 958 pdc->floatdigits = val; 959} 960 961void 962pdc_set_tracefile(pdc_core *pdc, const char *filename) 963{ 964 if (!filename || !*filename) 965 return; 966 967 if (pdc->tracefilename) 968 pdc_free(pdc, pdc->tracefilename); 969 970 pdc->tracefilename = pdc_strdup(pdc, filename); 971} 972 973/* Include informational stuff in [] brackets, and use 974 %s/\[[^]]*\]//g and 975 %s/)$/);/ 976 * to make it compilable :-) 977 */ 978 979/* start or stop (client == NULL) a trace for the supplied client program */ 980void 981pdc_set_trace(pdc_core *pdc, const char *client) 982{ 983#ifndef WINCE 984 time_t timer; 985 struct tm ltime; 986 987 time(&timer); 988 ltime = *localtime(&timer); 989#else 990 SYSTEMTIME st; 991 992 GetLocalTime (&st); 993#endif 994 995 pdc->trace = client ? pdc_true : pdc_false; 996 997 if (pdc->trace) { 998 pdc_trace(pdc, 999 "[ ------------------------------------------------------ ]\n"); 1000 pdc_trace(pdc, "[ %s on %s ] ", client, PDF_PLATFORM); 1001 pdc_trace(pdc, "[%04d-%02d-%02d]\n", 1002#ifndef WINCE 1003 ltime.tm_year + 1900, ltime.tm_mon + 1, ltime.tm_mday); 1004#else 1005 st.wYear, st.wMonth, st.wDay); 1006#endif /* !WINCE */ 1007 1008 pdc_trace(pdc, 1009 "[ ------------------------------------------------------ ]\n"); 1010 } 1011} 1012 1013/* trace function: version for pdf_enter_api() with 1014 * time stamp and function name output. 1015 */ 1016void 1017pdc_trace_api(pdc_core *pdc, const char *funame, const char *fmt, va_list args) 1018{ 1019 FILE * fp; 1020 const char *filename; 1021 char buf[2000]; 1022#ifndef WINCE 1023 time_t timer; 1024 struct tm ltime; 1025#else 1026 SYSTEMTIME st; 1027#endif 1028 1029 if (!pdc || !pdc->trace) 1030 return; 1031 1032 filename = pdc->tracefilename ? pdc->tracefilename : DEBUG_TRACE_FILE; 1033 1034 if ((fp = fopen(filename, APPENDMODE)) == NULL) 1035 return; 1036 1037#ifndef WINCE 1038 time(&timer); 1039 ltime = *localtime(&timer); 1040 fprintf(fp, "[%02d:%02d:%02d] ", ltime.tm_hour, ltime.tm_min, ltime.tm_sec); 1041 1042#else 1043 1044 GetLocalTime (&st); 1045 fprintf(fp, "[%02d:%02d:%02d] ", st.wHour, st.wMinute, st.wSecond); 1046#endif /* WINCE */ 1047 1048 fprintf(fp, "%s\t", funame); 1049 pdc_vsprintf(pdc, buf, fmt, args); 1050 fprintf(fp, "%s", buf); 1051 1052 fclose(fp); 1053} 1054 1055/* trace function: version without any decoration for return values etc.*/ 1056void 1057pdc_trace(pdc_core *pdc, const char *fmt, ...) 1058{ 1059 FILE *fp; 1060 const char *filename; 1061 va_list ap; 1062 1063 if (!pdc || !pdc->trace) 1064 return; 1065 1066 filename = pdc->tracefilename ? pdc->tracefilename : DEBUG_TRACE_FILE; 1067 1068 if ((fp = fopen(filename, APPENDMODE)) == NULL) 1069 return; 1070 1071 va_start(ap, fmt); 1072 vfprintf(fp, fmt, ap); 1073 va_end(ap); 1074 1075 fclose(fp); 1076} 1077 1078