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