Files correlati : pdflib Ricompilazione Demo : [ ] Commento : Aggiornata pdflib.dll alla versione 7.0.4 git-svn-id: svn://10.65.10.50/trunk@18580 c028cbd2-c16b-5b4b-a496-9718f37d4682
		
			
				
	
	
		
			3130 lines
		
	
	
		
			73 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			3130 lines
		
	
	
		
			73 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
/*---------------------------------------------------------------------------*
 | 
						|
 |              PDFlib - A library for generating PDF on the fly             |
 | 
						|
 +---------------------------------------------------------------------------+
 | 
						|
 | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. |
 | 
						|
 +---------------------------------------------------------------------------+
 | 
						|
 |                                                                           |
 | 
						|
 |    This software is subject to the PDFlib license. It is NOT in the       |
 | 
						|
 |    public domain. Extended versions and commercial licenses are           |
 | 
						|
 |    available, please check http://www.pdflib.com.                         |
 | 
						|
 |                                                                           |
 | 
						|
 *---------------------------------------------------------------------------*/
 | 
						|
 | 
						|
/* $Id: pc_util.c,v 1.4 2009-03-23 08:51:17 guy Exp $
 | 
						|
 *
 | 
						|
 * PDFlib various utility routines
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
#include <errno.h>
 | 
						|
 | 
						|
#include "pc_util.h"
 | 
						|
#include "pc_file.h"
 | 
						|
#include "pc_ctype.h"
 | 
						|
 | 
						|
#ifdef AS400
 | 
						|
#include <qp0z1170.h>   /* for getenv() emulation */
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef __sun
 | 
						|
#include <ieeefp.h>     /* for finite */
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined (isfinite)
 | 
						|
#define PDC_ISFINITE isfinite
 | 
						|
#else /* isfinite */
 | 
						|
 | 
						|
#ifdef _WIN32
 | 
						|
#include <windows.h>
 | 
						|
#include <float.h>
 | 
						|
#define PDC_ISFINITE _finite
 | 
						|
#else /* _WIN32 */
 | 
						|
 | 
						|
#ifdef OS_ZOS_SASC
 | 
						|
#define PDC_ISFINITE isfinite
 | 
						|
#else /* OS_ZOS_SASC */
 | 
						|
 | 
						|
#define PDC_ISFINITE finite
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
/* ---------------------- finite() workarounds -------------------------- */
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * pdc_check_number checks whether a floating-point number
 | 
						|
 * is valid and within the specified range. If not, an exception
 | 
						|
 * will be thrown.
 | 
						|
 */
 | 
						|
void
 | 
						|
pdc_check_number_limits(pdc_core *pdc, const char *paramname, double dz,
 | 
						|
                        double dmin, double dmax)
 | 
						|
{
 | 
						|
    if (!PDC_ISFINITE(dz))
 | 
						|
    {
 | 
						|
        pdc_error(pdc, PDC_E_ILLARG_FLOAT_NAN, paramname, 0, 0, 0);
 | 
						|
    }
 | 
						|
    else if (dz < dmin)
 | 
						|
    {
 | 
						|
        pdc_error(pdc, PDC_E_ILLARG_FLOAT_TOOSMALL, paramname,
 | 
						|
                  pdc_errprintf(pdc, "%f", dz),
 | 
						|
                  pdc_errprintf(pdc, "%f", dmin), 0);
 | 
						|
    }
 | 
						|
    else if (dz > dmax)
 | 
						|
    {
 | 
						|
        pdc_error(pdc, PDC_E_ILLARG_FLOAT_TOOLARGE, paramname,
 | 
						|
                  pdc_errprintf(pdc, "%f", dz),
 | 
						|
                  pdc_errprintf(pdc, "%f", dmax), 0);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
pdc_check_number(pdc_core *pdc, const char *paramname, double dz)
 | 
						|
{
 | 
						|
    pdc_check_number_limits(pdc, paramname, dz, PDC_FLOAT_MIN, PDC_FLOAT_MAX);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
pdc_check_number_zero(pdc_core *pdc, const char *paramname, double dz)
 | 
						|
{
 | 
						|
    pdc_check_number_limits(pdc, paramname, dz, PDC_FLOAT_MIN, PDC_FLOAT_MAX);
 | 
						|
 | 
						|
    if (PDC_FLOAT_ISNULL(dz))
 | 
						|
    {
 | 
						|
        pdc_error(pdc, PDC_E_ILLARG_FLOAT_ZERO, paramname,
 | 
						|
                  pdc_errprintf(pdc, "%f", dz), 0, 0);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
pdc_check_text_length(pdc_core *pdc, const char **text, int len, int maxlen)
 | 
						|
{
 | 
						|
    if (*text == NULL)
 | 
						|
    {
 | 
						|
        len = 0;
 | 
						|
        *text = "";
 | 
						|
    }
 | 
						|
    else if (len == 0)
 | 
						|
    {
 | 
						|
        len = (int) strlen(*text);
 | 
						|
    }
 | 
						|
 | 
						|
    if (len < 0 || len > maxlen)
 | 
						|
    {
 | 
						|
        pdc_error(pdc, PDC_E_ILLARG_STRINGLEN,
 | 
						|
                  pdc_errprintf(pdc, "%d", len),
 | 
						|
                  pdc_errprintf(pdc, "%d", maxlen), 0, 0);
 | 
						|
    }
 | 
						|
 | 
						|
    return len;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* ---------------- "unsupported feature" error message ------------------ */
 | 
						|
 | 
						|
void
 | 
						|
pdc_set_unsupp_error(pdc_core *pdc, int err_config, int err_lite,
 | 
						|
                     pdc_bool warning)
 | 
						|
{
 | 
						|
    (void) err_config;
 | 
						|
    (void) err_lite;
 | 
						|
 | 
						|
/* this feature is sufficient for non public version */
 | 
						|
    if (warning)
 | 
						|
        pdc_warning(pdc, err_lite, 0, 0, 0, 0);
 | 
						|
    else
 | 
						|
        pdc_error(pdc, err_lite, 0, 0, 0, 0);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* ---------------- error message with ASCII strings -------------------- */
 | 
						|
 | 
						|
void
 | 
						|
pdc_ascii_error(pdc_core *pdc, int errnum, int flags, const char *parm1,
 | 
						|
                const char *parm2, const char *parm3, const char *parm4)
 | 
						|
{
 | 
						|
    if (flags & (1<<0))
 | 
						|
    {
 | 
						|
        parm1 = pdc_errprintf(pdc, "%a", parm1);
 | 
						|
    }
 | 
						|
 | 
						|
    if (flags & (1<<1))
 | 
						|
    {
 | 
						|
        parm2 = pdc_errprintf(pdc, "%a", parm2);
 | 
						|
    }
 | 
						|
 | 
						|
    if (flags & (1<<2))
 | 
						|
    {
 | 
						|
        parm3 = pdc_errprintf(pdc, "%a", parm3);
 | 
						|
    }
 | 
						|
 | 
						|
    if (flags & (1<<3))
 | 
						|
    {
 | 
						|
        parm4 = pdc_errprintf(pdc, "%a", parm4);
 | 
						|
    }
 | 
						|
 | 
						|
    pdc_error(pdc, errnum, parm1, parm2, parm3, parm4);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* -------------------------- Time functions ------------------------------ */
 | 
						|
 | 
						|
#ifndef WINCE
 | 
						|
#ifndef __USE_POSIX
 | 
						|
#define __USE_POSIX
 | 
						|
#endif
 | 
						|
#include <time.h>
 | 
						|
#else
 | 
						|
#include <winbase.h>
 | 
						|
#endif
 | 
						|
 | 
						|
/* our private localtime() function. this one circumvents platform
 | 
						|
** quirks we found on WINCE and Solaris, and perhaps some more in
 | 
						|
** the future.
 | 
						|
*/
 | 
						|
void
 | 
						|
pdc_localtime(pdc_time *t)
 | 
						|
{
 | 
						|
#ifdef WINCE
 | 
						|
 | 
						|
    SYSTEMTIME  st;
 | 
						|
 | 
						|
    GetLocalTime (&st);
 | 
						|
 | 
						|
    t->second = st.wSecond;
 | 
						|
    t->minute = st.wMinute;
 | 
						|
    t->hour = st.wHour;
 | 
						|
    t->mday = st.wDay;
 | 
						|
    t->wday = st.wDayOfWeek;
 | 
						|
    t->month = st.wMonth;
 | 
						|
    t->year = st.wYear;
 | 
						|
 | 
						|
#else
 | 
						|
 | 
						|
    time_t      timer;
 | 
						|
    struct tm   ltime;
 | 
						|
 | 
						|
    time(&timer);
 | 
						|
 | 
						|
#if defined(PDC_NEEDS_R_FUNCTIONS)
 | 
						|
 | 
						|
    /* the localtime() function isn't thread safe on this platform.
 | 
						|
    ** a thread safe variant must be used instead.
 | 
						|
    */
 | 
						|
    (void) localtime_r(&timer, <ime);
 | 
						|
 | 
						|
#else
 | 
						|
 | 
						|
    ltime = *localtime(&timer);
 | 
						|
 | 
						|
#endif /* !PDC_NEEDS_R_FUNCTIONS */
 | 
						|
 | 
						|
    t->second = ltime.tm_sec;
 | 
						|
    t->minute = ltime.tm_min;
 | 
						|
    t->hour = ltime.tm_hour;
 | 
						|
    t->mday = ltime.tm_mday;
 | 
						|
    t->wday = ltime.tm_wday;
 | 
						|
    t->month = ltime.tm_mon;
 | 
						|
    t->year = ltime.tm_year;
 | 
						|
 | 
						|
#endif /* !WINCE */
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
pdc_localtime_r(const time_t *timer, struct tm *res)
 | 
						|
{
 | 
						|
#if defined(PDC_NEEDS_R_FUNCTIONS)
 | 
						|
    (void) localtime_r(timer, res);
 | 
						|
#else
 | 
						|
    *res = *localtime(timer);
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
pdc_gmtime_r(const time_t *timer, struct tm *res)
 | 
						|
{
 | 
						|
#if defined(PDC_NEEDS_R_FUNCTIONS)
 | 
						|
    (void) gmtime_r(timer, res);
 | 
						|
#else
 | 
						|
    *res = *gmtime(timer);
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
pdc_get_timestr(char *str, pdc_bool ktoascii)
 | 
						|
{
 | 
						|
#ifndef WINCE
 | 
						|
    time_t      timer, gtimer;
 | 
						|
    struct tm   ltime;
 | 
						|
    double      diffminutes;
 | 
						|
    int         utcoffset;
 | 
						|
#else
 | 
						|
    SYSTEMTIME  st;
 | 
						|
#endif
 | 
						|
 | 
						|
    (void) ktoascii;
 | 
						|
 | 
						|
#ifndef WINCE
 | 
						|
    time(&timer);
 | 
						|
 | 
						|
#if !defined(I370)
 | 
						|
    pdc_gmtime_r(&timer, <ime);
 | 
						|
    gtimer = mktime(<ime);
 | 
						|
    pdc_localtime_r(&timer, <ime);
 | 
						|
    ltime.tm_isdst = 0;
 | 
						|
    diffminutes = difftime(mktime(<ime), gtimer) / 60;
 | 
						|
    if (diffminutes >= 0)
 | 
						|
        utcoffset = (int)(diffminutes + 0.5);
 | 
						|
    else
 | 
						|
        utcoffset = (int)(diffminutes - 0.5);
 | 
						|
#else
 | 
						|
        utcoffset = 0;
 | 
						|
#endif
 | 
						|
 | 
						|
    /* Get local time again, previous data is damaged by mktime(). */
 | 
						|
    pdc_localtime_r(&timer, <ime);
 | 
						|
 | 
						|
    if (utcoffset > 0)
 | 
						|
        sprintf(str, "D:%04d%02d%02d%02d%02d%02d+%02d'%02d'",
 | 
						|
            ltime.tm_year + 1900, ltime.tm_mon + 1, ltime.tm_mday,
 | 
						|
            ltime.tm_hour, ltime.tm_min, ltime.tm_sec,
 | 
						|
            utcoffset / 60, utcoffset % 60);
 | 
						|
    else if (utcoffset < 0)
 | 
						|
        sprintf(str, "D:%04d%02d%02d%02d%02d%02d-%02d'%02d'",
 | 
						|
            ltime.tm_year + 1900, ltime.tm_mon + 1, ltime.tm_mday,
 | 
						|
            ltime.tm_hour, ltime.tm_min, ltime.tm_sec,
 | 
						|
            abs(utcoffset) / 60, abs(utcoffset) % 60);
 | 
						|
    else
 | 
						|
        sprintf(str, "D:%04d%02d%02d%02d%02d%02dZ",
 | 
						|
            ltime.tm_year + 1900, ltime.tm_mon + 1, ltime.tm_mday,
 | 
						|
            ltime.tm_hour, ltime.tm_min, ltime.tm_sec);
 | 
						|
 | 
						|
#else
 | 
						|
    GetLocalTime (&st);
 | 
						|
    sprintf(str, "D:%04d%02d%02d%02d%02d%02d",
 | 
						|
            st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
 | 
						|
#endif  /* !WINCE */
 | 
						|
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* -------------------------- Environment ------------------------------ */
 | 
						|
 | 
						|
char *
 | 
						|
pdc_getenv(const char *name)
 | 
						|
{
 | 
						|
#ifdef HAVE_ENVVARS
 | 
						|
    return getenv(name);
 | 
						|
#else
 | 
						|
    (void) name;
 | 
						|
 | 
						|
    return (char *) 0;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* ------------------------ Language Code ------------------------------ */
 | 
						|
 | 
						|
/* ISO 639 Windows and Mac Language codes */
 | 
						|
static const char lang_codes_ISO639[] =
 | 
						|
    "ab aa af sq am ar hy as ay az ba eu bn dz bh bi br bg my be km ca zh co"
 | 
						|
    "hr cs da nl en eo et fo fa fj fi fr fy gl gd gv ka de el kl gn gu ha he"
 | 
						|
    "hi hu is id ia ie iu ik ga it ja jv kn ks kk rw ky rn ko ku lo la lv li"
 | 
						|
    "ln lt mk mg ms ml mt mi mr mo mn na ne no oc or om ps pl pt pa qu rm ro"
 | 
						|
    "ru sm sg sa sr sh st tn sn sd si ss sk sl so es su sw sv tl tg ta tt te"
 | 
						|
    "th bo ti to ts tr tk tw ug uk ur uz vi vo cy wo xh yi yo zu"
 | 
						|
    "pt-br en-gb en-us de-de de-ch";
 | 
						|
 | 
						|
pdc_bool
 | 
						|
pdc_check_lang_code(pdc_core *pdc, const char* lang_code)
 | 
						|
{
 | 
						|
    pdc_bool valid = pdc_false;
 | 
						|
    int     i;
 | 
						|
    char*   country_code;
 | 
						|
    char*   language;
 | 
						|
 | 
						|
    if ((lang_code != NULL) && *lang_code)
 | 
						|
    {
 | 
						|
        /* do not check for IANA or private languages */
 | 
						|
        if (!(valid = ((lang_code[0] == 'i') || (lang_code[0] == 'x'))))
 | 
						|
        {
 | 
						|
            language = pdc_strdup(pdc, lang_code);
 | 
						|
            for (i = 0; i < (int)strlen(language); i++)
 | 
						|
            {
 | 
						|
                if (pdc_isupper(language[i]))
 | 
						|
                {
 | 
						|
                    language[i] = (char) pdc_tolower((int)language[i]);
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
 | 
						|
            country_code = (char *)strstr(lang_codes_ISO639, language);
 | 
						|
            valid = (country_code != NULL);
 | 
						|
 | 
						|
            if (!valid && (strlen(language) > 2))
 | 
						|
            {
 | 
						|
                country_code = strchr(language, '-');
 | 
						|
                if (country_code != NULL)
 | 
						|
                {
 | 
						|
                    country_code[0] = '\0';
 | 
						|
 | 
						|
                    country_code = (char *)strstr(lang_codes_ISO639, language);
 | 
						|
                    valid = (country_code != NULL);
 | 
						|
 | 
						|
                    if (!valid)
 | 
						|
                    {
 | 
						|
                        pdc_warning(pdc, PDC_E_ILLARG_LANG_CODE,
 | 
						|
                                    lang_code, 0, 0, 0);
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            pdc_free(pdc, language);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return valid;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* -------------------------- Bit arryas ------------------------------ */
 | 
						|
 | 
						|
/* set bit right to left within a byte */
 | 
						|
void
 | 
						|
pdc_setbit(char *bitarr, int bit)
 | 
						|
{
 | 
						|
    bitarr[bit/8] |= (char) (1<<(bit%8));
 | 
						|
}
 | 
						|
 | 
						|
/* set bit left to right within a byte */
 | 
						|
void
 | 
						|
pdc_setbit_l2r(char *bitarr, int bit)
 | 
						|
{
 | 
						|
    bitarr[bit/8] |= (char) (0x80>>(bit%8));
 | 
						|
}
 | 
						|
 | 
						|
pdc_bool
 | 
						|
pdc_getbit(const char *bitarr, int bit)
 | 
						|
{
 | 
						|
    return (pdc_bool) (bitarr[bit/8] & (1<<(bit%8)));
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
pdc_setbit_text(char *bitarr, const pdc_byte *text, int len,
 | 
						|
                int nbits, int size)
 | 
						|
{
 | 
						|
    int i, bit;
 | 
						|
    pdc_ushort *ustext = (pdc_ushort *) text;
 | 
						|
 | 
						|
    for (i = 0; i < len; i += size)
 | 
						|
    {
 | 
						|
        if (size == sizeof(pdc_byte))
 | 
						|
            bit = (int) text[i];
 | 
						|
        else
 | 
						|
            bit = ustext[i/size];
 | 
						|
        if (bit < nbits) pdc_setbit(bitarr, bit);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* ---------- Get functions of integer binary data types --------------- */
 | 
						|
 | 
						|
pdc_short
 | 
						|
pdc_get_le_short(const pdc_byte *data)
 | 
						|
{
 | 
						|
    return (pdc_short) ((pdc_short) (data[1] << 8) | data[0]);
 | 
						|
}
 | 
						|
 | 
						|
pdc_ushort
 | 
						|
pdc_get_le_ushort(const pdc_byte *data)
 | 
						|
{
 | 
						|
    return (pdc_ushort) ((data[1] << 8) | data[0]);
 | 
						|
}
 | 
						|
 | 
						|
pdc_uint32
 | 
						|
pdc_get_le_ulong3(const pdc_byte *data)
 | 
						|
{
 | 
						|
    return (pdc_uint32) (((((data[2]) << 8) | data[1]) << 8) | data[0]);
 | 
						|
}
 | 
						|
 | 
						|
pdc_sint32
 | 
						|
pdc_get_le_long(const pdc_byte *data)
 | 
						|
{
 | 
						|
    return ((pdc_sint32)
 | 
						|
         (((((data[3] << 8) | data[2]) << 8) | data[1]) << 8) | data[0]);
 | 
						|
}
 | 
						|
 | 
						|
pdc_uint32
 | 
						|
pdc_get_le_ulong(const pdc_byte *data)
 | 
						|
{
 | 
						|
    return (pdc_uint32)
 | 
						|
         ((((((data[3] << 8) | data[2]) << 8) | data[1]) << 8) | data[0]);
 | 
						|
}
 | 
						|
 | 
						|
pdc_short
 | 
						|
pdc_get_be_short(const pdc_byte *data)
 | 
						|
{
 | 
						|
    return (pdc_short) ((pdc_short) (data[0] << 8) | data[1]);
 | 
						|
}
 | 
						|
 | 
						|
pdc_ushort
 | 
						|
pdc_get_be_ushort(const pdc_byte *data)
 | 
						|
{
 | 
						|
    return (pdc_ushort) ((data[0] << 8) | data[1]);
 | 
						|
}
 | 
						|
 | 
						|
pdc_uint32
 | 
						|
pdc_get_be_ulong3(const pdc_byte *data)
 | 
						|
{
 | 
						|
    return (pdc_uint32) (((((data[0]) << 8) | data[1]) << 8) | data[2]);
 | 
						|
}
 | 
						|
 | 
						|
pdc_sint32
 | 
						|
pdc_get_be_long(const pdc_byte *data)
 | 
						|
{
 | 
						|
    return ((pdc_sint32)
 | 
						|
         (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3]);
 | 
						|
}
 | 
						|
 | 
						|
pdc_uint32
 | 
						|
pdc_get_be_ulong(const pdc_byte *data)
 | 
						|
{
 | 
						|
    return (pdc_uint32)
 | 
						|
        ((((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3]);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* ----------------- String handling for Unicode too ------------------- */
 | 
						|
 | 
						|
/* strlen() for wide character strings, which are double null terminated.
 | 
						|
 * pdc_wstrlen() returns the number of bytes in the Unicode string,
 | 
						|
 * NOT including the two terminating null bytes.
 | 
						|
 */
 | 
						|
size_t
 | 
						|
pdc_wstrlen(const char *str)
 | 
						|
{
 | 
						|
    size_t len = 0;
 | 
						|
 | 
						|
    while(str[len] != 0 || str[len+1] != 0)
 | 
						|
    {
 | 
						|
        len += 2;
 | 
						|
    }
 | 
						|
 | 
						|
    return len;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * This function returns the length in bytes for C and Unicode strings.
 | 
						|
 */
 | 
						|
size_t
 | 
						|
pdc_strlen(const char *str)
 | 
						|
{
 | 
						|
    if (pdc_is_utf16be_unicode(str) || pdc_is_utf16le_unicode(str))
 | 
						|
        return pdc_wstrlen(str);
 | 
						|
    else
 | 
						|
        return strlen(str);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Allocate a local buffer and copy the string including
 | 
						|
 * the terminating sentinel. If the string starts with the Unicode BOM
 | 
						|
 * it is considered a Unicode string, and must be terminated by
 | 
						|
 * two null bytes. Otherwise it is considered a plain C string and
 | 
						|
 * must be terminated by a single null byte.
 | 
						|
 * The caller is responsible for freeing the buffer.
 | 
						|
 *
 | 
						|
 * The special functions pdc_strdup, pdc_strdup_tmp and pdc_strdup_withbom
 | 
						|
 * should be replaced by the more sophisticated function pdc_strdup_ext.
 | 
						|
 * There: flags (see pc_unicode.h):
 | 
						|
 *
 | 
						|
 * PDC_CONV_TMPALLOC, PDC_CONV_EBCDIC, PDC_CONV_ASCII,
 | 
						|
 * PDC_CONV_WITHBOM, PDC_CONV_NOBOM, PDC_CONV_MAXSTRLEN
 | 
						|
 *
 | 
						|
 */
 | 
						|
char *
 | 
						|
pdc_strdup_ext(pdc_core *pdc, const char *text, int flags, const char *fn)
 | 
						|
{
 | 
						|
    char *buf = NULL;
 | 
						|
 | 
						|
    if (text != NULL)
 | 
						|
    {
 | 
						|
        size_t len = pdc_strlen(text) + 1;
 | 
						|
        size_t is = 0, it = 0;
 | 
						|
 | 
						|
        if ((flags & PDC_CONV_MAXSTRLEN) && len > PDC_ERR_MAXSTRLEN)
 | 
						|
            len = PDC_ERR_MAXSTRLEN;
 | 
						|
 | 
						|
        if ((flags & PDC_CONV_NOBOM) && pdc_is_utf8_bytecode(text))
 | 
						|
            is = 3;
 | 
						|
 | 
						|
        if ((flags & PDC_CONV_WITHBOM) && !pdc_is_utf8_bytecode(text))
 | 
						|
            it = 3;
 | 
						|
 | 
						|
        len += it - is;
 | 
						|
        if (flags & PDC_CONV_TMPALLOC)
 | 
						|
            buf = (char *) pdc_malloc_tmp(pdc, len + 1, fn, NULL, NULL);
 | 
						|
        else
 | 
						|
            buf = (char *) pdc_malloc(pdc, len + 1, fn);
 | 
						|
 | 
						|
        memcpy(&buf[it], &text[is], len - it);
 | 
						|
        buf[len] = 0;
 | 
						|
 | 
						|
 | 
						|
        if (it == 3)
 | 
						|
            pdc_copy_utf8_bom(buf);
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    return buf;
 | 
						|
}
 | 
						|
 | 
						|
/* Convenience functions
 | 
						|
*/
 | 
						|
char *
 | 
						|
pdc_strdup_tmp(pdc_core *pdc, const char *text)
 | 
						|
{
 | 
						|
    static const char fn[] = "pdc_strdup_tmp";
 | 
						|
 | 
						|
    return pdc_strdup_ext(pdc, text, PDC_CONV_TMPALLOC, fn);
 | 
						|
}
 | 
						|
 | 
						|
char *
 | 
						|
pdc_strdup_withbom(pdc_core *pdc, const char *text)
 | 
						|
{
 | 
						|
    static const char fn[] = "pdc_strdup_withbom";
 | 
						|
 | 
						|
    return pdc_strdup_ext(pdc, text, PDC_CONV_WITHBOM, fn);
 | 
						|
}
 | 
						|
 | 
						|
/* Rapid function
 | 
						|
*/
 | 
						|
char *
 | 
						|
pdc_strdup(pdc_core *pdc, const char *text)
 | 
						|
{
 | 
						|
    char *buf = NULL;
 | 
						|
    static const char fn[] = "pdc_strdup";
 | 
						|
 | 
						|
    if (text != NULL)
 | 
						|
    {
 | 
						|
        size_t len = pdc_strlen(text) + 1;
 | 
						|
 | 
						|
        buf = (char *) pdc_malloc(pdc, len + 1, fn);
 | 
						|
        memcpy(buf, text, len);
 | 
						|
        buf[len] = 0;
 | 
						|
    }
 | 
						|
 | 
						|
    return buf;
 | 
						|
}
 | 
						|
 | 
						|
char *
 | 
						|
pdc_strdup2(pdc_core *pdc, const char *text, size_t len)
 | 
						|
{
 | 
						|
    char *buf = NULL;
 | 
						|
    static const char fn[] = "pdc_strdup2";
 | 
						|
 | 
						|
    if (text != NULL)
 | 
						|
    {
 | 
						|
        buf = (char *) pdc_malloc(pdc, len + 1, fn);
 | 
						|
        memcpy(buf, text, len);
 | 
						|
        buf[len] = 0;
 | 
						|
    }
 | 
						|
 | 
						|
    return buf;
 | 
						|
}
 | 
						|
 | 
						|
/* Convert Pascal string to a null terminated C string.
 | 
						|
 * Size of C string: at least 256 bytes
 | 
						|
 */
 | 
						|
int
 | 
						|
pdc_convert_pascal_str(const char *pstr, char *cstr)
 | 
						|
{
 | 
						|
    int len = (int) *((pdc_byte *) pstr);
 | 
						|
 | 
						|
    memcpy(cstr, pstr + 1, (size_t) len);
 | 
						|
    cstr[len] = 0;
 | 
						|
 | 
						|
    return len;
 | 
						|
}
 | 
						|
 | 
						|
char *
 | 
						|
pdc_strdup_convert(pdc_core *pdc, pdc_encoding encto, pdc_encoding encfrom,
 | 
						|
                   const char *text, int flags, const char *fn)
 | 
						|
{
 | 
						|
    pdc_encodingvector *evfrom, *evto;
 | 
						|
    char *buf;
 | 
						|
    size_t len;
 | 
						|
    int i;
 | 
						|
 | 
						|
    evto = pdc_get_encoding_vector(pdc, encto);
 | 
						|
    evfrom = pdc_get_encoding_vector(pdc, encfrom);
 | 
						|
    buf = pdc_strdup_ext(pdc, text, flags, fn);
 | 
						|
    len = strlen(buf);
 | 
						|
 | 
						|
    for (i = 0; i < (int) len; i++)
 | 
						|
        buf[i] = (char) pdc_transform_bytecode(pdc, evto, evfrom,
 | 
						|
                                               (pdc_byte) text[i]);
 | 
						|
 | 
						|
    return buf;
 | 
						|
}
 | 
						|
 | 
						|
pdc_bool
 | 
						|
pdc_logg_isprint(int c)
 | 
						|
{
 | 
						|
    if (c < 0x20 || (c >= 0x7F && c < 0xA0))
 | 
						|
        return pdc_false;
 | 
						|
    return pdc_true;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * Put out an arbitrary string.
 | 
						|
 *
 | 
						|
 * strform = readable:  Direct byte output with replacing not
 | 
						|
 *                      printable bytes by their octal codes.
 | 
						|
 *         = readable0: Like readable, but byte 0 will be displayed as space.
 | 
						|
 *         = octal:     All bytes will be put out as octal.
 | 
						|
 *         = hexa:      All bytes will be put out as hexadecimal value.
 | 
						|
 *         = java:      Like readable, but Unicode strings and not printable
 | 
						|
 *                      bytes will be put out in Java notation \uxxxx,
 | 
						|
 *
 | 
						|
 * Output string is temporarily allocated.
 | 
						|
 *
 | 
						|
 */
 | 
						|
char *
 | 
						|
pdc_strprint(pdc_core *pdc, const char *str, int leni, int maxchar,
 | 
						|
             pdc_strform_kind strform)
 | 
						|
{
 | 
						|
    static const char fn[] = "pdc_strprint";
 | 
						|
 | 
						|
    if (str != NULL)
 | 
						|
    {
 | 
						|
        pdc_bool isunicode = pdc_false;
 | 
						|
        int len = leni;
 | 
						|
 | 
						|
        if (!leni)
 | 
						|
            len = (int) strlen(str);
 | 
						|
 | 
						|
        if (len)
 | 
						|
        {
 | 
						|
            pdc_strform_kind sf = strform;
 | 
						|
            char *ts, *tmpstr;
 | 
						|
            pdc_byte c = ' ', cp = '.';
 | 
						|
            pdc_ushort *ush = (pdc_ushort *) str;
 | 
						|
            int i, im;
 | 
						|
 | 
						|
            /* because of strform_java: \uxxxx: factor 6 */
 | 
						|
            tmpstr = (char *) pdc_calloc_tmp(pdc, (size_t) (6 * (len + 4)), fn,
 | 
						|
                                             NULL, NULL);
 | 
						|
            ts = tmpstr;
 | 
						|
 | 
						|
            if (strform == strform_java)
 | 
						|
            {
 | 
						|
                if (leni && !(leni % 2))
 | 
						|
                    isunicode = pdc_true;
 | 
						|
                else
 | 
						|
                    strform = strform_readable;
 | 
						|
            }
 | 
						|
 | 
						|
            if (maxchar <= 0)
 | 
						|
                maxchar = len;
 | 
						|
            im = (maxchar < len) ? maxchar : len;
 | 
						|
            if (isunicode)
 | 
						|
                im = im/2;
 | 
						|
            for (i = 0; i < im; i++)
 | 
						|
            {
 | 
						|
                if (isunicode)
 | 
						|
                {
 | 
						|
                    if (ush[i] > PDC_UNICODE_MAXLATIN1)
 | 
						|
                    {
 | 
						|
                        sf = strform_java;
 | 
						|
                    }
 | 
						|
                    else
 | 
						|
                    {
 | 
						|
                        c = (pdc_byte) ush[i];
 | 
						|
                        sf = strform;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    c = (pdc_byte) str[i];
 | 
						|
                    sf = strform;
 | 
						|
                }
 | 
						|
 | 
						|
                switch (sf)
 | 
						|
                {
 | 
						|
                    case strform_hexa:
 | 
						|
                    ts += sprintf(ts, "\\x%02X", c);
 | 
						|
                    break;
 | 
						|
 | 
						|
                    case strform_octal:
 | 
						|
                    ts += sprintf(ts, "\\%03o", c);
 | 
						|
                    break;
 | 
						|
 | 
						|
                    case strform_java:
 | 
						|
                    ts += sprintf(ts, "\\u%04X", ush[i]);
 | 
						|
                    break;
 | 
						|
 | 
						|
                    default:
 | 
						|
                    if (c == 0x00 && sf == strform_readable0)
 | 
						|
                    {
 | 
						|
                        c = 0x20;
 | 
						|
 | 
						|
                        *ts = (char) c;
 | 
						|
                        ts++;
 | 
						|
                    }
 | 
						|
                    else
 | 
						|
                    {
 | 
						|
                        if (!pdc_logg_isprint((int) c))
 | 
						|
                        {
 | 
						|
                            if (isunicode)
 | 
						|
                                ts += sprintf(ts, "\\u%04X", c);
 | 
						|
                            else
 | 
						|
                                ts += sprintf(ts, "\\%03o", c);
 | 
						|
                        }
 | 
						|
                        else
 | 
						|
                        {
 | 
						|
                            if (c == '"')
 | 
						|
                            {
 | 
						|
                                *ts = '\\';
 | 
						|
                                ts++;
 | 
						|
                            }
 | 
						|
 | 
						|
                            *ts = (char) c;
 | 
						|
                            ts++;
 | 
						|
                        }
 | 
						|
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            if (maxchar < len)
 | 
						|
            {
 | 
						|
                switch (strform)
 | 
						|
                {
 | 
						|
                    case strform_hexa:
 | 
						|
                    ts += sprintf(ts, "\\x%02X\\x%02X\\x%02X", cp, cp, cp);
 | 
						|
                    break;
 | 
						|
 | 
						|
                    case strform_octal:
 | 
						|
                    ts += sprintf(ts, "\\%03o\\%03o\\%03o", cp, cp, cp);
 | 
						|
                    break;
 | 
						|
 | 
						|
                    case strform_java:
 | 
						|
                    ts += sprintf(ts, "\\u%04X\\u%04X\\u%04X", cp, cp, cp);
 | 
						|
                    break;
 | 
						|
 | 
						|
                    default:
 | 
						|
                    ts += sprintf(ts, "%c%c%c", cp, cp, cp);
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            return tmpstr;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return (char *) pdc_calloc_tmp(pdc, 1, fn, NULL, NULL);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Returned string is temporary allocated.
 | 
						|
 */
 | 
						|
const char *
 | 
						|
pdc_utf8strprint(pdc_core *pdc, const char *str)
 | 
						|
{
 | 
						|
    static const char fn[] = "pdc_utf8strprint";
 | 
						|
 | 
						|
    return pdc_strdup_ext(pdc, str,
 | 
						|
                  PDC_CONV_TMPALLOC | PDC_CONV_NOBOM | PDC_CONV_MAXSTRLEN, fn);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Split a given text string into single strings which are separated by
 | 
						|
 * arbitrary characters. This characters must be specified in a string.
 | 
						|
 * If this string is NULL, " \f\n\r\t\v" (standard white spaces) is assumed.
 | 
						|
 *
 | 
						|
 * There is the convention that text inside braces {} will be taken verbatim.
 | 
						|
 * Inside brace expressions braces must exist only in pairs. Braces are
 | 
						|
 * masked by backslash.
 | 
						|
 *
 | 
						|
 * The caller is responsible for freeing the resultated string list
 | 
						|
 * by calling the function pdc_cleanup_stringlist.
 | 
						|
 *
 | 
						|
 * Not for unicode strings.
 | 
						|
 *
 | 
						|
 * Return value: Number of strings.
 | 
						|
 *               If braces aren't balanced the number is negative.
 | 
						|
 *
 | 
						|
 */
 | 
						|
int
 | 
						|
pdc_split_stringlist(pdc_core *pdc, const char *text, const char *i_separstr,
 | 
						|
                     int flags, char ***stringlist)
 | 
						|
{
 | 
						|
    static const char fn[] = "pdc_split_stringlist";
 | 
						|
    const char *separstr = " \f\n\r\t\v";
 | 
						|
    const char *oldtext;
 | 
						|
    char **strlist = NULL, *newtext = NULL;
 | 
						|
    int it, len, jt = 0, jtb = 0, maxk = 0, count = 0, inside = 0;
 | 
						|
    int ns, nbs = 0, nbss;
 | 
						|
 | 
						|
    if (stringlist)
 | 
						|
        *stringlist = NULL;
 | 
						|
    if (i_separstr)
 | 
						|
        separstr = i_separstr;
 | 
						|
 | 
						|
    if (text == NULL)
 | 
						|
        return 0;
 | 
						|
 | 
						|
    /* check for empty string */
 | 
						|
    ns = (int) strspn(text, separstr);
 | 
						|
    oldtext = &text[ns];
 | 
						|
    len = (int) strlen(oldtext);
 | 
						|
    if (!len)
 | 
						|
        return 0;
 | 
						|
 | 
						|
    /* check for UTF-8-BOM */
 | 
						|
    if (pdc_is_utf8_bytecode(oldtext))
 | 
						|
    {
 | 
						|
        oldtext = &text[ns + 3];
 | 
						|
        len -= 3;
 | 
						|
        ns = (int) strspn(oldtext, separstr);
 | 
						|
        oldtext = &oldtext[ns];
 | 
						|
        len -= ns;
 | 
						|
        if (!len)
 | 
						|
            return 0;
 | 
						|
    }
 | 
						|
 | 
						|
    /* new string */
 | 
						|
    if (stringlist != NULL)
 | 
						|
        newtext = (char *) pdc_malloc(pdc, (size_t) (len + 1), fn);
 | 
						|
    for (it = 0; it <= len; it++)
 | 
						|
    {
 | 
						|
        /* check for separators */
 | 
						|
        if (it == len)
 | 
						|
            ns = 1;
 | 
						|
        else if (inside <= 0)
 | 
						|
            ns = (int) strspn(&oldtext[it], separstr);
 | 
						|
        else
 | 
						|
            ns = 0;
 | 
						|
 | 
						|
        /* close text part */
 | 
						|
        if (ns)
 | 
						|
        {
 | 
						|
            if (stringlist != NULL)
 | 
						|
            {
 | 
						|
                newtext[jt] = 0;
 | 
						|
                if (count == maxk)
 | 
						|
                {
 | 
						|
                    maxk += 16;
 | 
						|
                    strlist = (char **) pdc_realloc(pdc, strlist,
 | 
						|
                                                    maxk * sizeof(char *), fn);
 | 
						|
                }
 | 
						|
                strlist[count] = &newtext[jtb];
 | 
						|
            }
 | 
						|
            count++;
 | 
						|
 | 
						|
            /* Exit */
 | 
						|
            it += ns;
 | 
						|
            if (it >= len ) break;
 | 
						|
 | 
						|
            /* new text part */
 | 
						|
            jt++;
 | 
						|
            jtb = jt;
 | 
						|
        }
 | 
						|
 | 
						|
        /* option list */
 | 
						|
        if (flags & PDC_SPLIT_ISOPTLIST)
 | 
						|
        {
 | 
						|
            /* save backslash counter */
 | 
						|
            nbss = nbs;
 | 
						|
 | 
						|
            /* backslash */
 | 
						|
            if (oldtext[it] == '\\')
 | 
						|
            {
 | 
						|
                nbs++;
 | 
						|
                if (!(nbs % 2) && inside <= 1)
 | 
						|
                    continue;
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                nbs = 0;
 | 
						|
            }
 | 
						|
 | 
						|
            /* open and close brace */
 | 
						|
            if (oldtext[it] == '{')
 | 
						|
            {
 | 
						|
                if (!(nbss % 2))
 | 
						|
                {
 | 
						|
                    inside++;
 | 
						|
                    if (inside == 1)
 | 
						|
                        continue;
 | 
						|
                }
 | 
						|
                else if (inside <= 1)
 | 
						|
                {
 | 
						|
                    jt--;
 | 
						|
                }
 | 
						|
            }
 | 
						|
            else if (oldtext[it] == '}')
 | 
						|
            {
 | 
						|
                if (!(nbss % 2))
 | 
						|
                {
 | 
						|
                    inside--;
 | 
						|
                    if (inside == 0)
 | 
						|
                        continue;
 | 
						|
                }
 | 
						|
                else if (inside <= 1)
 | 
						|
                {
 | 
						|
                    jt--;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        /* argument list */
 | 
						|
        else if (flags & PDC_SPLIT_ISARGLIST)
 | 
						|
        {
 | 
						|
            /* save backslash counter */
 | 
						|
            nbss = nbs;
 | 
						|
 | 
						|
            /* backslash */
 | 
						|
            if (oldtext[it] == '\\')
 | 
						|
            {
 | 
						|
                nbs++;
 | 
						|
                if (!(nbs % 2))
 | 
						|
                    continue;
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                nbs = 0;
 | 
						|
            }
 | 
						|
 | 
						|
            /* open and close quotation mark */
 | 
						|
            if (oldtext[it] == '"')
 | 
						|
            {
 | 
						|
                if (!(nbss % 2))
 | 
						|
                {
 | 
						|
                    inside = 1 - inside;
 | 
						|
                    continue;
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    jt--;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        /* save character */
 | 
						|
        if (stringlist != NULL)
 | 
						|
        {
 | 
						|
            newtext[jt] = oldtext[it];
 | 
						|
            jt++;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if (stringlist != NULL)
 | 
						|
        *stringlist = strlist;
 | 
						|
 | 
						|
    return inside ? -count : count;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
pdc_cleanup_stringlist(pdc_core *pdc, char **stringlist)
 | 
						|
{
 | 
						|
    if(stringlist != NULL)
 | 
						|
    {
 | 
						|
        if(stringlist[0] != NULL)
 | 
						|
            pdc_free(pdc, stringlist[0]);
 | 
						|
 | 
						|
        pdc_free(pdc, stringlist);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * Substitute a list of variables in a string by its values recursively.
 | 
						|
 * A variable begins with the character 'vchar' and ends at a character
 | 
						|
 * in 'delimiters' or at the end of string resp..
 | 
						|
 *
 | 
						|
 * The character 'vchar' must be masked by 'vchar'.
 | 
						|
 *
 | 
						|
 * If at least one of a variable was substituted, a new allocated null
 | 
						|
 * terminated string is returned. Otherwise the original pointer.
 | 
						|
 *
 | 
						|
 * The caller is responsible for freeing the new string.
 | 
						|
 *
 | 
						|
 *   string     null terminated string with variables
 | 
						|
 *   vchar      begin character for a variable
 | 
						|
 *   delimiters string with characters delimiting a variable name
 | 
						|
 *   varslist   list of variable names
 | 
						|
 *   valslist   list of variable values
 | 
						|
 *   nvars      number of variables
 | 
						|
 *   errind[2]  contains index and length of an unkown variable in string
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
static char *
 | 
						|
substitute_variables(pdc_core *pdc, char *string, int ibeg, int *level,
 | 
						|
    const char **varslist, const char **valslist, int nvars, char vchar,
 | 
						|
    const char *separstr, int *errind)
 | 
						|
{
 | 
						|
    static const char fn[] = "substitue_variables";
 | 
						|
    int i, j, l;
 | 
						|
 | 
						|
    j = ibeg;
 | 
						|
    for (i = ibeg; string[i] != 0; i++)
 | 
						|
    {
 | 
						|
        if (string[i] == vchar)
 | 
						|
        {
 | 
						|
            if (string[i + 1] == vchar)
 | 
						|
                i++;
 | 
						|
            else
 | 
						|
                break;
 | 
						|
        }
 | 
						|
 | 
						|
        string[j] = string[i];
 | 
						|
        j++;
 | 
						|
    }
 | 
						|
 | 
						|
    if (string[i] != 0)
 | 
						|
    {
 | 
						|
        char *s = &string[i + 1];
 | 
						|
        size_t n = strcspn(s, separstr);
 | 
						|
 | 
						|
        for (l = 0; l < nvars; l++)
 | 
						|
        {
 | 
						|
            if (n == strlen(varslist[l]) && !strncmp(s, varslist[l], n))
 | 
						|
            {
 | 
						|
                char *newstring;
 | 
						|
                int k = (int) (i + n + 1);
 | 
						|
                size_t nv = strlen(valslist[l]);
 | 
						|
                size_t nr = strlen(&string[k]);
 | 
						|
                size_t nb = (size_t) j +  nv + nr + 1;
 | 
						|
 | 
						|
                newstring = (char *) pdc_malloc(pdc, nb, fn);
 | 
						|
                strncpy(newstring, string, (size_t) j);
 | 
						|
                strncpy(&newstring[j], valslist[l], nv);
 | 
						|
                strcpy(&newstring[j + nv], &string[k]);
 | 
						|
 | 
						|
                pdc_free(pdc, string);
 | 
						|
                (*level)++;
 | 
						|
 | 
						|
                string = substitute_variables(pdc, newstring, j, level,
 | 
						|
                               varslist, valslist, nvars, vchar, separstr,
 | 
						|
                               errind);
 | 
						|
                break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if (l == nvars)
 | 
						|
        {
 | 
						|
            errind[0] = i;
 | 
						|
            errind[1] = (int) (n + 1);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        string[j] = 0;
 | 
						|
    }
 | 
						|
    return string;
 | 
						|
}
 | 
						|
 | 
						|
char *
 | 
						|
pdc_substitute_variables(pdc_core *pdc, const char *string, char vchar,
 | 
						|
    const char *delimiters, const char **varslist,
 | 
						|
    const char **valslist, int nvars, int *errind)
 | 
						|
{
 | 
						|
    static const char fn[] = "pdc_substitue_variables";
 | 
						|
    char *subststr, *newstring, separstr[64];
 | 
						|
    int level = 0;
 | 
						|
 | 
						|
    newstring = pdc_strdup_ext(pdc, string, 0, fn);
 | 
						|
 | 
						|
    separstr[0] = vchar;
 | 
						|
    separstr[1] = 0;
 | 
						|
    strcat(separstr, delimiters);
 | 
						|
 | 
						|
    errind[0] = -1;
 | 
						|
    errind[1] = 0;
 | 
						|
    subststr = substitute_variables(pdc, newstring, 0, &level,
 | 
						|
                         varslist, valslist, nvars, vchar, separstr, errind);
 | 
						|
 | 
						|
    return subststr;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Compares its arguments and returns an integer less than,
 | 
						|
 * equal to, or greater than zero, depending on whether s1
 | 
						|
 * is lexicographically less than, equal to, or greater than s2.
 | 
						|
 * Null pointer values for s1 and s2 are treated the same as pointers
 | 
						|
 * to empty strings.
 | 
						|
 *
 | 
						|
 * Presupposition: basic character set
 | 
						|
 *
 | 
						|
 * Return value:  < 0  s1 <  s2;
 | 
						|
 *                = 0  s1 == s2;
 | 
						|
 *                > 0  s1 >  s2;
 | 
						|
 *
 | 
						|
 */
 | 
						|
int
 | 
						|
pdc_strcmp(const char *s1, const char *s2)
 | 
						|
{
 | 
						|
    if (s1 == s2) return (0);
 | 
						|
    if (s1 == NULL) return (-1);
 | 
						|
    if (s2 == NULL) return (1);
 | 
						|
 | 
						|
    return strcmp(s1, s2);
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
pdc_stricmp(const char *s1, const char *s2)
 | 
						|
{
 | 
						|
    if (s1 == s2) return (0);
 | 
						|
    if (s1 == NULL) return (-1);
 | 
						|
    if (s2 == NULL) return (1);
 | 
						|
 | 
						|
    for (; *s1; ++s1, ++s2)
 | 
						|
    {
 | 
						|
        if (pdc_tolower(*s1) != pdc_tolower(*s2))
 | 
						|
            break;
 | 
						|
    }
 | 
						|
 | 
						|
    return (pdc_tolower(*s1) - pdc_tolower(*s2));
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
pdc_stricmp_a(const char *s1, const char *s2)
 | 
						|
{
 | 
						|
    if (s1 == s2) return (0);
 | 
						|
    if (s1 == NULL) return (-1);
 | 
						|
    if (s2 == NULL) return (1);
 | 
						|
 | 
						|
    for (; *s1; ++s1, ++s2)
 | 
						|
    {
 | 
						|
        if (pdc_tolower_a(*s1) != pdc_tolower_a(*s2))
 | 
						|
            break;
 | 
						|
    }
 | 
						|
 | 
						|
    return (pdc_tolower_a(*s1) - pdc_tolower_a(*s2));
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Same like pdc_strcmp, except that the strings can be
 | 
						|
 * wide character strings with nulls and double null terminated.
 | 
						|
 */
 | 
						|
int
 | 
						|
pdc_wstrcmp(const char *s1, const char *s2)
 | 
						|
{
 | 
						|
    size_t len1, len2, len;
 | 
						|
    int res;
 | 
						|
 | 
						|
    if (s1 == s2) return (0);
 | 
						|
    if (s1 == NULL) return (-1);
 | 
						|
    if (s2 == NULL) return (1);
 | 
						|
 | 
						|
    len1 = pdc_strlen(s1);
 | 
						|
    len2 = pdc_strlen(s2);
 | 
						|
    len = MIN(len1, len2);
 | 
						|
 | 
						|
    res = memcmp(s1, s2, len);
 | 
						|
 | 
						|
    if (!res && len1 != len2)
 | 
						|
        res = (len1 < len2) ? -1 : 1;
 | 
						|
 | 
						|
    return res;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Compares its arguments and returns an integer less than,
 | 
						|
 * equal to, or greater than zero, depending on whether s1
 | 
						|
 * is lexicographically less than, equal to, or greater than s2.
 | 
						|
 * But only up to n characters compared (n less than or equal
 | 
						|
 * to zero yields equality).Null pointer values for s1 and s2
 | 
						|
 * are treated the same as pointers to empty strings.
 | 
						|
 *
 | 
						|
 * Presupposition: basic character set
 | 
						|
 *
 | 
						|
 * Return value:  < 0  s1 <  s2;
 | 
						|
 *                = 0  s1 == s2;
 | 
						|
 *                > 0  s1 >  s2;
 | 
						|
 *
 | 
						|
 */
 | 
						|
int
 | 
						|
pdc_strincmp(const char *s1, const char *s2, int n)
 | 
						|
{
 | 
						|
    int i;
 | 
						|
 | 
						|
    if (s1 == s2)   return (0);
 | 
						|
    if (s1 == NULL) return (-1);
 | 
						|
    if (s2 == NULL) return (1);
 | 
						|
 | 
						|
    for (i = 0; i < n && *s1 && *s2; ++i, ++s1, ++s2)
 | 
						|
    {
 | 
						|
        if (pdc_tolower(*s1) != pdc_tolower(*s2))
 | 
						|
            break;
 | 
						|
    }
 | 
						|
 | 
						|
    return (i == n) ? 0 : (pdc_tolower(*s1) - pdc_tolower(*s2));
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * pdc_strtrim removes trailing white space characters from an input string.
 | 
						|
 * pdc_str2trim removes leading and trailing white space characters from an
 | 
						|
 * input string..
 | 
						|
 */
 | 
						|
char *
 | 
						|
pdc_strtrim(char *str)
 | 
						|
{
 | 
						|
    int i, n;
 | 
						|
 | 
						|
    n = (int) strlen(str);
 | 
						|
    for (i = n - 1; i >= 0; i--)
 | 
						|
        if (!pdc_isspace(str[i])) break;
 | 
						|
    str[i + 1] = '\0';
 | 
						|
 | 
						|
    return str;
 | 
						|
}
 | 
						|
 | 
						|
char *
 | 
						|
pdc_str2trim(char *str)
 | 
						|
{
 | 
						|
    int i, n;
 | 
						|
 | 
						|
    n = (int) strlen(str);
 | 
						|
    for (i = n - 1; i >= 0; i--)
 | 
						|
        if (!pdc_isspace(str[i])) break;
 | 
						|
    str[i + 1] = '\0';
 | 
						|
 | 
						|
    for (i = 0; ; i++)
 | 
						|
        if (!pdc_isspace(str[i])) break;
 | 
						|
    if (i > 0)
 | 
						|
        memmove(str, &str[i], strlen(&str[i]) + 1);
 | 
						|
 | 
						|
    return str;
 | 
						|
}
 | 
						|
 | 
						|
char *
 | 
						|
pdc_strtoupper(char *str)
 | 
						|
{
 | 
						|
    int i, n;
 | 
						|
 | 
						|
    n = (int) strlen(str);
 | 
						|
    for (i = 0; i < n; i++)
 | 
						|
        str[i] = (char) pdc_toupper(str[i]);
 | 
						|
 | 
						|
    return str;
 | 
						|
}
 | 
						|
 | 
						|
char *
 | 
						|
pdc_strtolower(char *str)
 | 
						|
{
 | 
						|
    int i, n;
 | 
						|
 | 
						|
    n = (int) strlen(str);
 | 
						|
    for (i = 0; i < n; i++)
 | 
						|
        str[i] = (char) pdc_tolower(str[i]);
 | 
						|
 | 
						|
    return str;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
pdc_swap_bytes2(const char *instring, int inlen, char *outstring)
 | 
						|
{
 | 
						|
    pdc_ushort *inp, *outp;
 | 
						|
    int i;
 | 
						|
 | 
						|
    if (instring == NULL)
 | 
						|
        return;
 | 
						|
 | 
						|
    if (outstring == NULL)
 | 
						|
        outstring = (char *) instring;
 | 
						|
 | 
						|
    inp = (pdc_ushort *) instring;
 | 
						|
    outp = (pdc_ushort *) outstring;
 | 
						|
 | 
						|
    inlen /= sizeof(pdc_ushort);
 | 
						|
    for (i = 0; i < inlen; i++)
 | 
						|
    {
 | 
						|
        outp[i] = (pdc_ushort) (((inp[i] & (pdc_ushort)0x00FFu) << 8) |
 | 
						|
                                ((inp[i] & (pdc_ushort)0xFF00u) >> 8));
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
pdc_swap_bytes4(const char *instring, int inlen, char *outstring)
 | 
						|
{
 | 
						|
    pdc_uint32 *inp, *outp;
 | 
						|
    int i;
 | 
						|
 | 
						|
    if (instring == NULL)
 | 
						|
        return;
 | 
						|
 | 
						|
    if (outstring == NULL)
 | 
						|
        outstring = (char *) instring;
 | 
						|
 | 
						|
    inp = (pdc_uint32 *) instring;
 | 
						|
    outp = (pdc_uint32 *) outstring;
 | 
						|
 | 
						|
    inlen /= sizeof(pdc_uint32);
 | 
						|
    for (i = 0; i < inlen; i++)
 | 
						|
    {
 | 
						|
        outp[i] = (pdc_uint32) (((inp[i] & (pdc_uint32)0x000000FFu) << 24) |
 | 
						|
                                ((inp[i] & (pdc_uint32)0x0000FF00u) <<  8) |
 | 
						|
                                ((inp[i] & (pdc_uint32)0x00FF0000u) >>  8) |
 | 
						|
                                ((inp[i] & (pdc_uint32)0xFF000000u) >> 24));
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
pdc_inflate_ascii(const char *instring, int inlen, char *outstring,
 | 
						|
                  pdc_text_format textformat)
 | 
						|
{
 | 
						|
    int i, j;
 | 
						|
    pdc_bool is_bigendian = (textformat == pdc_utf16be) ||
 | 
						|
                            (textformat == pdc_utf16 && PDC_ISBIGENDIAN);
 | 
						|
 | 
						|
    j = 0;
 | 
						|
    for (i = 0; i < inlen; i++)
 | 
						|
    {
 | 
						|
        if (is_bigendian)
 | 
						|
        {
 | 
						|
            outstring[j] = 0;
 | 
						|
            j++;
 | 
						|
            outstring[j] = instring[i];
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            outstring[j] = instring[i];
 | 
						|
            j++;
 | 
						|
            outstring[j] = 0;
 | 
						|
        }
 | 
						|
        j++;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 *  pdc_stresc --
 | 
						|
 *      Remove from a string containing escaped non-printable cha-
 | 
						|
 *      racters. The string must follows the C-standard escape
 | 
						|
 *      mechanism: an escaped character is preceeded by an escape
 | 
						|
 *      character which is a backslash '\' character and followed
 | 
						|
 *      by one or more characters to define the non-printable
 | 
						|
 *      character to be inserted here. The supported escapes are
 | 
						|
 *
 | 
						|
 *            \a              bell            (ASCII/EBCDIC-BEL)
 | 
						|
 *            \b              backspace       (ASCII/EBCDIC-BS)
 | 
						|
 *            \e              escape charater (ASCII/EBCDIC-ESC)
 | 
						|
 *            \f              formfeed        (ASCII/EBCDIC-FF)
 | 
						|
 *            \n              linefeed        (ASCII/EBCDIC-LF)
 | 
						|
 *            \r              return          (ASCII/EBCDIC-CR)
 | 
						|
 *            \t              tab character   (ASCII/EBCDIC-TAB)
 | 
						|
 *            \v              vertical tab    (ASCII/EBCDIC-VT)
 | 
						|
 *            \\              the slash itself
 | 
						|
 *            \xnn            two hex digits n to define a
 | 
						|
 *                            character numerically as ASCII/EBCDIC value.
 | 
						|
 *            \nnn            three octal digits n to define a
 | 
						|
 *                            character numerically as ASCII/EBCDIC value.
 | 
						|
 *
 | 
						|
 *      For example: \x0A, \x0a or \012 has the same effect in ASCII
 | 
						|
 *      as \n (i.e linefeed).
 | 
						|
 *      Note, if the last character in a string is the backslash
 | 
						|
 *      then the backslash is illegal.
 | 
						|
 *      The special characters a,b,e,f, and so on are recognized in
 | 
						|
 *      lower case only.
 | 
						|
 *
 | 
						|
 *      textformat:
 | 
						|
 *      pdc_bytes:      Latin1 or EBCDIC bytes on EBCDIC platforms
 | 
						|
 *      pdc_utf8:       Latin1
 | 
						|
 *      pdc_ebcdicutf8: EBCDIC - only on EBCDIC platforms
 | 
						|
 *      pdc_utf16:      2 bytes Latin1
 | 
						|
 *
 | 
						|
 *      If a illegal escaped sequence was detected an exception will
 | 
						|
 *      be thrown (verbose == pdc_true) or the sequence will be taken
 | 
						|
 *      as it (verbose == pdc_false).
 | 
						|
 *
 | 
						|
*/
 | 
						|
 | 
						|
static const pdc_keyconn pdc_ascii_escape_keylist[] =
 | 
						|
{
 | 
						|
    {"\\",   0x5C},
 | 
						|
    {"a",    0x07},
 | 
						|
    {"b",    0x08},
 | 
						|
    {"e",    0x1B},
 | 
						|
    {"f",    0x0C},
 | 
						|
    {"n",    0x0A},
 | 
						|
    {"r",    0x0D},
 | 
						|
    {"t",    0x09},
 | 
						|
    {"v",    0x0B},
 | 
						|
    {"x",    0x78},
 | 
						|
    {NULL, 0}
 | 
						|
};
 | 
						|
 | 
						|
pdc_ushort
 | 
						|
pdc_get_string_value(pdc_byte *str, int i, int charlen)
 | 
						|
{
 | 
						|
    pdc_ushort retval = 0;
 | 
						|
 | 
						|
    if (charlen == 1)
 | 
						|
    {
 | 
						|
        retval = (pdc_ushort) str[i];
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        pdc_ushort *ustr = (pdc_ushort *) str;
 | 
						|
 | 
						|
        retval = ustr[i];
 | 
						|
    }
 | 
						|
 | 
						|
    return retval;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
pdc_subst_backslash(pdc_core *pdc, pdc_byte *str, int len,
 | 
						|
                    pdc_encodingvector *ev, pdc_text_format textformat,
 | 
						|
                    pdc_bool verbose)
 | 
						|
{
 | 
						|
    pdc_ushort *ustr = (pdc_ushort *) str;
 | 
						|
    int charlen = (textformat == pdc_utf16) ? 2 : 1;
 | 
						|
    pdc_byte bschar = '\\';
 | 
						|
    pdc_ushort uv;
 | 
						|
    int i, j, k, code;
 | 
						|
 | 
						|
    if (ev != NULL)
 | 
						|
    {
 | 
						|
        code = pdc_get_encoding_bytecode(pdc, ev, PDC_UNICODE_BACKSLASH);
 | 
						|
        if (code != -1)
 | 
						|
            bschar = (pdc_byte) code;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    j = 0;
 | 
						|
    len /= charlen;
 | 
						|
    for (i = 0; i < len; i++)
 | 
						|
    {
 | 
						|
        uv = pdc_get_string_value(str, i, charlen);
 | 
						|
        if (uv > PDC_UNICODE_MAXLATIN1)
 | 
						|
        {
 | 
						|
            ustr[j] = uv;
 | 
						|
            j++;
 | 
						|
            continue;
 | 
						|
        }
 | 
						|
 | 
						|
        /* backslash found */
 | 
						|
        if (uv == bschar)
 | 
						|
        {
 | 
						|
            pdc_byte escseq[4], stemp[6];
 | 
						|
            pdc_bool kerror = pdc_false;
 | 
						|
 | 
						|
            i++;
 | 
						|
            if (i < len)
 | 
						|
            {
 | 
						|
                uv = pdc_get_string_value(str, i, charlen);
 | 
						|
                if (uv > PDC_UNICODE_MAXLATIN1)
 | 
						|
                    goto PDC_OVERFLOW_EXIT;
 | 
						|
 | 
						|
                escseq[0] = (pdc_byte) uv;
 | 
						|
                escseq[1] = 0;
 | 
						|
 | 
						|
                code = pdc_get_keycode((char *) escseq,
 | 
						|
                                       pdc_ascii_escape_keylist);
 | 
						|
                if (code != PDC_KEY_NOTFOUND)
 | 
						|
                {
 | 
						|
                    /* hex number */
 | 
						|
                    if (code == 0x78)
 | 
						|
                    {
 | 
						|
                        for (k = 0; k < 2; k++)
 | 
						|
                        {
 | 
						|
                            i++;
 | 
						|
                            if (i < len)
 | 
						|
                            {
 | 
						|
                                uv = pdc_get_string_value(str, i, charlen);
 | 
						|
                                if (uv > PDC_UNICODE_MAXLATIN1)
 | 
						|
                                    goto PDC_OVERFLOW_EXIT;
 | 
						|
                            }
 | 
						|
                            else
 | 
						|
                            {
 | 
						|
                                uv = 0;
 | 
						|
                            }
 | 
						|
                            escseq[k] = (pdc_byte) uv;
 | 
						|
                        }
 | 
						|
                        escseq[k] = 0;
 | 
						|
                        if (i >= len ||
 | 
						|
                            !pdc_str2integer((char *) escseq, PDC_INT_UNICODE,
 | 
						|
                                             &uv))
 | 
						|
                        {
 | 
						|
                            strcpy((char *) stemp, "\\x");
 | 
						|
                            strcat((char *) stemp, (char *) escseq);
 | 
						|
                            kerror = pdc_true;
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    else
 | 
						|
                    {
 | 
						|
                        pdc_char c = (pdc_char) code;
 | 
						|
                        uv = (pdc_ushort) (pdc_byte) c;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    /* octal number */
 | 
						|
                    for (k = 0; k < 3; k++)
 | 
						|
                    {
 | 
						|
                        if (k) i++;
 | 
						|
                        if (i < len)
 | 
						|
                        {
 | 
						|
                            uv = pdc_get_string_value(str, i, charlen);
 | 
						|
                            if (uv > PDC_UNICODE_MAXLATIN1)
 | 
						|
                                goto PDC_OVERFLOW_EXIT;
 | 
						|
                        }
 | 
						|
                        else
 | 
						|
                        {
 | 
						|
                            uv = 0;
 | 
						|
                        }
 | 
						|
                        escseq[k] = (pdc_byte) uv;
 | 
						|
                    }
 | 
						|
                    escseq[k] = 0;
 | 
						|
                    if (i >= len ||
 | 
						|
                        !pdc_str2integer((char *) escseq,
 | 
						|
                                        PDC_INT_SHORT |
 | 
						|
                                        PDC_INT_UNSIGNED |
 | 
						|
                                        PDC_INT_OCTAL,
 | 
						|
                                        &uv) ||
 | 
						|
                        (charlen == 1 && uv > 0xFF))
 | 
						|
                    {
 | 
						|
                        strcpy((char *) stemp, "\\");
 | 
						|
                        strcat((char *) stemp, (char *) escseq);
 | 
						|
                        kerror = pdc_true;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                strcpy((char *) stemp, "\\");
 | 
						|
                kerror = pdc_true;
 | 
						|
            }
 | 
						|
 | 
						|
            /* error message */
 | 
						|
            if (kerror)
 | 
						|
            {
 | 
						|
                pdc_set_errmsg(pdc, PDC_E_STR_ILL_ESCSEQ, (char *) stemp,
 | 
						|
                               0, 0, 0);
 | 
						|
 | 
						|
                if (verbose)
 | 
						|
                    pdc_error(pdc, -1, 0, 0, 0, 0);
 | 
						|
 | 
						|
                return 0;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if (charlen == 1)
 | 
						|
            str[j] = (pdc_byte) uv;
 | 
						|
        else
 | 
						|
            ustr[j] = uv;
 | 
						|
 | 
						|
        j++;
 | 
						|
    }
 | 
						|
 | 
						|
    if (charlen == 1)
 | 
						|
        str[j] = 0;
 | 
						|
    else
 | 
						|
        ustr[j] = 0;
 | 
						|
 | 
						|
    return charlen * j;
 | 
						|
 | 
						|
    PDC_OVERFLOW_EXIT:
 | 
						|
 | 
						|
    pdc_set_errmsg(pdc, PDC_E_STR_ILL_UNIESCSEQ,
 | 
						|
                   pdc_errprintf(pdc, "%04X", uv), 0, 0, 0);
 | 
						|
 | 
						|
    if (verbose)
 | 
						|
        pdc_error(pdc, -1, 0, 0, 0, 0);
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* ----------------------- number converting ----------------------- */
 | 
						|
 | 
						|
/*
 | 
						|
 * pdc_str2double converts a null terminated and trimmed string
 | 
						|
 * to a double precision number
 | 
						|
 */
 | 
						|
pdc_bool
 | 
						|
pdc_str2double(const char *string, double *o_dz)
 | 
						|
{
 | 
						|
    const char *s = string;
 | 
						|
    double dz = 0;
 | 
						|
    int is = 1, isd = 0;
 | 
						|
 | 
						|
    *o_dz = 0;
 | 
						|
 | 
						|
    /* sign */
 | 
						|
    if (*s == '-')
 | 
						|
    {
 | 
						|
        is = -1;
 | 
						|
        s++;
 | 
						|
    }
 | 
						|
    else if (*s == '+')
 | 
						|
        s++;
 | 
						|
 | 
						|
    if (!*s)
 | 
						|
        return pdc_false;
 | 
						|
 | 
						|
    /* places before decimal point */
 | 
						|
    isd = pdc_isdigit(*s);
 | 
						|
    if (isd)
 | 
						|
    {
 | 
						|
        do
 | 
						|
        {
 | 
						|
            dz = 10 * dz + *s - '0';
 | 
						|
            s++;
 | 
						|
        }
 | 
						|
        while (pdc_isdigit(*s));
 | 
						|
    }
 | 
						|
 | 
						|
    /* decimal point */
 | 
						|
    if (*s == '.' || *s == ',')
 | 
						|
    {
 | 
						|
        const char *sa;
 | 
						|
        double adz = 0;
 | 
						|
 | 
						|
        s++;
 | 
						|
        isd = pdc_isdigit(*s);
 | 
						|
        if (!isd)
 | 
						|
            return pdc_false;
 | 
						|
 | 
						|
        /* places after decimal point */
 | 
						|
        sa = s;
 | 
						|
        do
 | 
						|
        {
 | 
						|
            adz = 10 * adz + *s - '0';
 | 
						|
            s++;
 | 
						|
        }
 | 
						|
        while (pdc_isdigit(*s));
 | 
						|
        dz += adz / pow(10.0, (double)(s - sa));
 | 
						|
    }
 | 
						|
 | 
						|
    /* power sign */
 | 
						|
    if (*s == 'e' || *s == 'E')
 | 
						|
    {
 | 
						|
        s++;
 | 
						|
        if (!isd)
 | 
						|
            return pdc_false;
 | 
						|
 | 
						|
        /* sign */
 | 
						|
        if (!*s)
 | 
						|
        {
 | 
						|
            dz *= 10;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            int isp = 1;
 | 
						|
            double pdz = 0, pdl = log10(dz);
 | 
						|
 | 
						|
            if (*s == '-')
 | 
						|
            {
 | 
						|
                isp = -1;
 | 
						|
                s++;
 | 
						|
            }
 | 
						|
            else if (*s == '+')
 | 
						|
                s++;
 | 
						|
 | 
						|
            if (!pdc_isdigit(*s))
 | 
						|
                return pdc_false;
 | 
						|
            do
 | 
						|
            {
 | 
						|
                pdz = 10 * pdz + *s - '0';
 | 
						|
                s++;
 | 
						|
            }
 | 
						|
            while (pdc_isdigit(*s));
 | 
						|
 | 
						|
 | 
						|
            if (*s || fabs(pdl + pdz) > 300.0)
 | 
						|
                return pdc_false;
 | 
						|
 | 
						|
            dz *= pow(10.0, isp * pdz);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    else if(*s)
 | 
						|
    {
 | 
						|
        return pdc_false;
 | 
						|
    }
 | 
						|
 | 
						|
    *o_dz = is * dz;
 | 
						|
    return pdc_true;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * pdc_str2integer converts a null terminated and trimmed string
 | 
						|
 * to an hexadecimal or decimal integer number of arbitrary size
 | 
						|
 */
 | 
						|
pdc_bool
 | 
						|
pdc_str2integer(const char *string, int flags, void *o_iz)
 | 
						|
{
 | 
						|
    const char *s = string;
 | 
						|
    double dz = 0;
 | 
						|
    pdc_char cz = 0;
 | 
						|
    pdc_short sz = 0;
 | 
						|
    pdc_sint32 lz = 0;
 | 
						|
    pdc_byte ucz = 0;
 | 
						|
    pdc_ushort usz = 0;
 | 
						|
    pdc_uint32 ulz = 0;
 | 
						|
    int is = 1, lzd;
 | 
						|
 | 
						|
    if (flags & PDC_INT_CHAR)
 | 
						|
        memcpy(o_iz, &cz, sizeof(pdc_char));
 | 
						|
    else if (flags & PDC_INT_SHORT)
 | 
						|
        memcpy(o_iz, &sz, sizeof(pdc_short));
 | 
						|
    else
 | 
						|
        memcpy(o_iz, &lz, sizeof(pdc_sint32));
 | 
						|
 | 
						|
    /* sign */
 | 
						|
    if (*s == '-')
 | 
						|
    {
 | 
						|
        if (flags & PDC_INT_UNSIGNED)
 | 
						|
            return pdc_false;
 | 
						|
        is = -1;
 | 
						|
        s++;
 | 
						|
    }
 | 
						|
    else if (*s == '+')
 | 
						|
        s++;
 | 
						|
 | 
						|
    if (!*s)
 | 
						|
        return pdc_false;
 | 
						|
 | 
						|
    /* hexadecimal test */
 | 
						|
    if (!(flags & PDC_INT_DEC))
 | 
						|
    {
 | 
						|
        const char *ss = s;
 | 
						|
 | 
						|
        if (*s == '<')
 | 
						|
            s += 1;
 | 
						|
        else if (*s == 'x' || *s == 'X')
 | 
						|
            s += 1;
 | 
						|
        else if (!strncmp(s, "0x", 2) || !strncmp(s, "0X", 2))
 | 
						|
            s += 2;
 | 
						|
        if (s > ss)
 | 
						|
        {
 | 
						|
            if (!*s)
 | 
						|
                return pdc_false;
 | 
						|
            flags |= PDC_INT_HEXADEC;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /* hexadecimal */
 | 
						|
    if (flags & PDC_INT_HEXADEC)
 | 
						|
    {
 | 
						|
        while (pdc_isxdigit(*s))
 | 
						|
        {
 | 
						|
            if (pdc_isalpha(*s))
 | 
						|
                lzd = (pdc_isupper(*s) ? 'A' : 'a') - 10;
 | 
						|
            else
 | 
						|
                lzd = '0';
 | 
						|
            dz = 16 * dz + *s - lzd;
 | 
						|
            s++;
 | 
						|
        }
 | 
						|
        if (*string == '<')
 | 
						|
        {
 | 
						|
            if (*s == '>')
 | 
						|
                s += 1;
 | 
						|
            else
 | 
						|
                return pdc_false;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /* octal */
 | 
						|
    if (flags & PDC_INT_OCTAL)
 | 
						|
    {
 | 
						|
        while (pdc_isdigit(*s) && *s < '8')
 | 
						|
        {
 | 
						|
            dz = 8 * dz + *s - '0';
 | 
						|
            s++;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /* decimal */
 | 
						|
    else
 | 
						|
    {
 | 
						|
        while (pdc_isdigit(*s))
 | 
						|
        {
 | 
						|
            dz = 10 * dz + *s - '0';
 | 
						|
            s++;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if (*s)
 | 
						|
        return pdc_false;
 | 
						|
 | 
						|
    dz *= is;
 | 
						|
    if (flags & PDC_INT_CHAR)
 | 
						|
    {
 | 
						|
        if (flags & PDC_INT_UNSIGNED)
 | 
						|
        {
 | 
						|
            if (dz > PDC_UCHAR_MAX)
 | 
						|
                return pdc_false;
 | 
						|
            ucz = (pdc_byte) dz;
 | 
						|
            memcpy(o_iz, &ucz, sizeof(pdc_byte));
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            if (dz < PDC_SCHAR_MIN || dz > PDC_SCHAR_MAX)
 | 
						|
                return pdc_false;
 | 
						|
            cz = (pdc_char) dz;
 | 
						|
            memcpy(o_iz, &cz, sizeof(pdc_char));
 | 
						|
        }
 | 
						|
    }
 | 
						|
    else if (flags & PDC_INT_SHORT)
 | 
						|
    {
 | 
						|
        if (flags & PDC_INT_UNSIGNED)
 | 
						|
        {
 | 
						|
            if (dz > PDC_USHRT_MAX)
 | 
						|
                return pdc_false;
 | 
						|
            usz = (pdc_ushort) dz;
 | 
						|
            memcpy(o_iz, &usz, sizeof(pdc_ushort));
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            if (dz < PDC_SHRT_MIN || dz > PDC_SHRT_MAX)
 | 
						|
                return pdc_false;
 | 
						|
            sz = (pdc_short) dz;
 | 
						|
            memcpy(o_iz, &sz, sizeof(pdc_short));
 | 
						|
        }
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        if (flags & PDC_INT_UNSIGNED)
 | 
						|
        {
 | 
						|
            if (dz > PDC_UINT_MAX)
 | 
						|
                return pdc_false;
 | 
						|
            ulz = (pdc_uint32) dz;
 | 
						|
            memcpy(o_iz, &ulz, sizeof(pdc_uint32));
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            if (dz < PDC_INT_MIN || dz > PDC_INT_MAX)
 | 
						|
                return pdc_false;
 | 
						|
            lz = (pdc_sint32) dz;
 | 
						|
            memcpy(o_iz, &lz, sizeof(pdc_sint32));
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return pdc_true;
 | 
						|
}
 | 
						|
 | 
						|
static const char digits[] = "0123456789ABCDEF";
 | 
						|
 | 
						|
static char *
 | 
						|
pdc_ltoa(char *buf, long n, int width, char pad, int base)
 | 
						|
{
 | 
						|
    char        aux[100];
 | 
						|
    int         k, i = sizeof aux;
 | 
						|
    char *      dest = buf;
 | 
						|
    pdc_bool    sign;
 | 
						|
 | 
						|
    if (n == 0)
 | 
						|
    {
 | 
						|
        if (width == 0)
 | 
						|
            width = 1;
 | 
						|
 | 
						|
        for (k = 0; k < width; ++k)
 | 
						|
            *(dest++) = '0';
 | 
						|
 | 
						|
        return dest;
 | 
						|
    }
 | 
						|
 | 
						|
    if (n < 0 && base == 10)
 | 
						|
    {
 | 
						|
        --width;
 | 
						|
        sign = pdc_true;
 | 
						|
        aux[--i] = digits[- (n % base)];
 | 
						|
        n = n / -base;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        sign = pdc_false;
 | 
						|
        aux[--i] = digits[n % base];
 | 
						|
        n = n / base;
 | 
						|
    }
 | 
						|
 | 
						|
    while (0 < n)
 | 
						|
    {
 | 
						|
        aux[--i] = digits[n % base];
 | 
						|
        n = n / base;
 | 
						|
    }
 | 
						|
 | 
						|
    width -= (int) (sizeof aux) - i;
 | 
						|
    for (k = 0; k < width; ++k)
 | 
						|
        *(dest++) = pad;
 | 
						|
 | 
						|
    if (sign)
 | 
						|
        *(dest++) = '-';
 | 
						|
 | 
						|
    memcpy(dest, &aux[i], sizeof aux - i);
 | 
						|
    return dest + sizeof aux - i;
 | 
						|
} /* pdc_ltoa */
 | 
						|
 | 
						|
 | 
						|
static char *
 | 
						|
pdc_ulong2a(
 | 
						|
    char *	buf,
 | 
						|
    pdc_off_t	n,
 | 
						|
    int		width,
 | 
						|
    char	pad,
 | 
						|
    int		base,
 | 
						|
    pdc_bool	left_justify)
 | 
						|
{
 | 
						|
    char        aux[100];
 | 
						|
    int         k, i = sizeof aux;
 | 
						|
    char *      dest = buf;
 | 
						|
    pdc_bool    sign;
 | 
						|
 | 
						|
    if (n < 0)
 | 
						|
    {
 | 
						|
        --width;
 | 
						|
        sign = pdc_true;
 | 
						|
        aux[--i] = digits[- (n % base)];
 | 
						|
        n = n / -base;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        sign = pdc_false;
 | 
						|
        aux[--i] = digits[n % base];
 | 
						|
        n = n / base;
 | 
						|
    }
 | 
						|
 | 
						|
    while (0 < n)
 | 
						|
    {
 | 
						|
        aux[--i] = digits[n % base];
 | 
						|
        n = n / base;
 | 
						|
    }
 | 
						|
 | 
						|
    width -= (int) (sizeof aux) - i;
 | 
						|
 | 
						|
    if (!left_justify)
 | 
						|
    {
 | 
						|
	for (k = 0; k < width; ++k)
 | 
						|
	    *(dest++) = pad;
 | 
						|
    }
 | 
						|
 | 
						|
    if (sign)
 | 
						|
        *(dest++) = '-';
 | 
						|
 | 
						|
    memcpy(dest, &aux[i], sizeof aux - i);
 | 
						|
    dest += sizeof aux - i;
 | 
						|
 | 
						|
    if (left_justify)
 | 
						|
    {
 | 
						|
	for (k = 0; k < width; ++k)
 | 
						|
	    *(dest++) = pad;
 | 
						|
    }
 | 
						|
 | 
						|
    return dest;
 | 
						|
} /* pdc_ulong2a */
 | 
						|
 | 
						|
 | 
						|
static char *
 | 
						|
pdc_off_t2a(
 | 
						|
    char *	buf,
 | 
						|
    pdc_off_t	n,
 | 
						|
    int		width,
 | 
						|
    char	pad,
 | 
						|
    pdc_bool	left_justify,
 | 
						|
    pdc_bool	pos_sign)
 | 
						|
{
 | 
						|
    char        aux[100];
 | 
						|
    int         k, i = sizeof aux;
 | 
						|
    char *      dest = buf;
 | 
						|
    pdc_bool    sign;
 | 
						|
 | 
						|
    if (n < 0)
 | 
						|
    {
 | 
						|
        --width;
 | 
						|
        sign = pdc_true;
 | 
						|
        aux[--i] = digits[- (n % 10)];
 | 
						|
        n = n / -10;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
	if (pos_sign)
 | 
						|
	    --width;
 | 
						|
 | 
						|
        sign = pdc_false;
 | 
						|
        aux[--i] = digits[n % 10];
 | 
						|
        n = n / 10;
 | 
						|
    }
 | 
						|
 | 
						|
    while (0 < n)
 | 
						|
    {
 | 
						|
        aux[--i] = digits[n % 10];
 | 
						|
        n = n / 10;
 | 
						|
    }
 | 
						|
 | 
						|
    width -= (int) (sizeof aux) - i;
 | 
						|
 | 
						|
    if (!left_justify)
 | 
						|
    {
 | 
						|
	for (k = 0; k < width; ++k)
 | 
						|
	    *(dest++) = pad;
 | 
						|
    }
 | 
						|
 | 
						|
    if (sign)
 | 
						|
    {
 | 
						|
        *(dest++) = '-';
 | 
						|
    }
 | 
						|
    else if (pos_sign)
 | 
						|
    {
 | 
						|
        *(dest++) = '+';
 | 
						|
    }
 | 
						|
 | 
						|
    memcpy(dest, &aux[i], sizeof aux - i);
 | 
						|
    dest += sizeof aux - i;
 | 
						|
 | 
						|
    if (left_justify)
 | 
						|
    {
 | 
						|
	for (k = 0; k < width; ++k)
 | 
						|
	    *(dest++) = pad;
 | 
						|
    }
 | 
						|
 | 
						|
    return dest;
 | 
						|
} /* pdc_off_t2a */
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * pdc_ftoa converts a floating point number to string
 | 
						|
 *
 | 
						|
 * Because of historical reason "%f" = "%.12g".
 | 
						|
 *
 | 
						|
 * The function calls sprintf() and replaces
 | 
						|
 * decimal comma by decimal point.
 | 
						|
 *
 | 
						|
 * If the number is infinite or not a number
 | 
						|
 * "nan" will be set.
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
static char *
 | 
						|
pdc_ftoa(pdc_core *pdc, const char *format, char *buf, double x)
 | 
						|
{
 | 
						|
    char *dest = buf;
 | 
						|
    char *cd;
 | 
						|
    int n;
 | 
						|
 | 
						|
    (void) pdc;
 | 
						|
 | 
						|
    /* check whether the number is valid */
 | 
						|
    if (!PDC_ISFINITE(x))
 | 
						|
    {
 | 
						|
        strcpy(dest, "nan");
 | 
						|
        return dest + 3;
 | 
						|
    }
 | 
						|
 | 
						|
    /* standard C convert */
 | 
						|
    if (!strcmp(format, "%f"))
 | 
						|
        n = sprintf(dest, "%.12g", x);
 | 
						|
    else
 | 
						|
        n = sprintf(dest, format, x);
 | 
						|
 | 
						|
    /* normalized to decimal point */
 | 
						|
    cd = strchr(dest, ',');
 | 
						|
    if (cd != NULL)
 | 
						|
        *cd = '.';
 | 
						|
 | 
						|
    return dest + n;
 | 
						|
} /* pdc_ftoa */
 | 
						|
 | 
						|
/*
 | 
						|
 * pdc_ftoa_pdfconf converts a floating point number to string
 | 
						|
 * PDF conforming
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
static char *
 | 
						|
pdc_ftoa_pdfconf(pdc_core *pdc, char *buf, double x)
 | 
						|
{
 | 
						|
    static const long pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000 };
 | 
						|
    char *      dest = buf;
 | 
						|
    double      integ, fract, powd;
 | 
						|
    int         ifd;
 | 
						|
    long        f;
 | 
						|
 | 
						|
    /* check whether the number is valid */
 | 
						|
    if (!PDC_ISFINITE(x))
 | 
						|
        pdc_error(pdc, PDC_E_INT_ILLFLOAT, 0, 0, 0, 0);
 | 
						|
 | 
						|
    /* small number will be mapped to 0 */
 | 
						|
    if (x < PDF_SMALLREAL && x > -PDF_SMALLREAL)
 | 
						|
    {
 | 
						|
        *dest = '0';
 | 
						|
        return dest + 1;
 | 
						|
    }
 | 
						|
 | 
						|
    /* negative number */
 | 
						|
    if (x < 0)
 | 
						|
    {
 | 
						|
        x = -x;
 | 
						|
        *(dest++) = '-';
 | 
						|
    }
 | 
						|
 | 
						|
    /* large number is invalid or will be mapped to integer */
 | 
						|
    if (x >= PDF_BIGREAL)
 | 
						|
    {
 | 
						|
        if (x > PDF_BIGINT)
 | 
						|
            pdc_error(pdc, PDC_E_INT_FLOATTOOLARGE,
 | 
						|
                      pdc_errprintf(pdc, "%f", x), 0, 0, 0);
 | 
						|
 | 
						|
        return pdc_ltoa(dest, (long) (x + 0.5), 0, ' ', 10);
 | 
						|
    }
 | 
						|
 | 
						|
    ifd = pdc->floatdigits;
 | 
						|
    powd = pow10[ifd];
 | 
						|
 | 
						|
    /* number <= 1/powd will be mappepd to 1/powd */
 | 
						|
    if (x <= 1 / powd)
 | 
						|
    {
 | 
						|
        *(dest++) = '0';
 | 
						|
        *(dest++) = '.';
 | 
						|
        while (--ifd)
 | 
						|
            *(dest++) = '0';
 | 
						|
        *(dest++) = '1';
 | 
						|
        return dest;
 | 
						|
    }
 | 
						|
 | 
						|
    fract = modf(x, &integ);
 | 
						|
    f = (long) (fract * powd + 0.5);
 | 
						|
 | 
						|
    if (f == powd)
 | 
						|
    {
 | 
						|
        integ += 1.0;
 | 
						|
        f = 0;
 | 
						|
    }
 | 
						|
 | 
						|
    if (integ == 0 && f == 0)   /* avoid "-0" */
 | 
						|
        dest = buf;
 | 
						|
 | 
						|
    dest = pdc_ltoa(dest, (long) integ, 0, ' ', 10);
 | 
						|
 | 
						|
    if (f != 0)
 | 
						|
    {
 | 
						|
        char *  aux;
 | 
						|
        long    rem;
 | 
						|
 | 
						|
        *(dest++) = '.';
 | 
						|
 | 
						|
        do      /* avoid trailing zeros */
 | 
						|
        {
 | 
						|
            rem = f % 10;
 | 
						|
            f = f / 10;
 | 
						|
            --ifd;
 | 
						|
        } while (rem == 0);
 | 
						|
 | 
						|
        aux = dest + ifd + 1;
 | 
						|
        dest[ifd--] = digits[rem];
 | 
						|
 | 
						|
        for (; 0 <= ifd; --ifd)
 | 
						|
        {
 | 
						|
            dest[ifd] = digits[f % 10];
 | 
						|
            f = f / 10;
 | 
						|
        }
 | 
						|
 | 
						|
        return aux;
 | 
						|
    }
 | 
						|
 | 
						|
    return dest;
 | 
						|
} /* pdc_ftoa_pdfconf */
 | 
						|
 | 
						|
 | 
						|
/* flags for formatting function pdc_vxprintf()
 | 
						|
*/
 | 
						|
typedef enum
 | 
						|
{
 | 
						|
    pdc_form_nolimit,   /* no buffer limit supplied, no overflow check */
 | 
						|
    pdc_form_fixlimit,  /* fix buffer limit, buffer overflow causes exception */
 | 
						|
    pdc_form_varlimit   /* buffer overflow causes string truncation */
 | 
						|
}
 | 
						|
pdc_limitkind;
 | 
						|
 | 
						|
/* write to string or file
 | 
						|
*/
 | 
						|
static char *
 | 
						|
write_sf(
 | 
						|
    pdc_core *pdc,
 | 
						|
    FILE *fp,
 | 
						|
    pdc_limitkind ltd,
 | 
						|
    char *dst,
 | 
						|
    char *limit,
 | 
						|
    const char *src,
 | 
						|
    int n)
 | 
						|
{
 | 
						|
    if (fp != (FILE *) 0)
 | 
						|
    {
 | 
						|
	pdc_fwrite_ascii(pdc, src, (size_t) n, fp);
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        if (ltd != pdc_form_nolimit)
 | 
						|
        {
 | 
						|
            int avail = (int) (limit - dst);
 | 
						|
 | 
						|
            if (avail < n)
 | 
						|
            {
 | 
						|
                if (ltd == pdc_form_fixlimit)
 | 
						|
                {
 | 
						|
                    pdc_error(pdc, PDC_E_INT_FORMOVERFLOW, 0, 0, 0, 0);
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    n = MAX(avail, 0);
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if (n > 0)
 | 
						|
        {
 | 
						|
            memcpy(dst, src, (size_t) n);
 | 
						|
            dst += n;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return dst;
 | 
						|
} /* write2buf */
 | 
						|
 | 
						|
static int
 | 
						|
pdc_vxprintf(
 | 
						|
    pdc_core *pdc,
 | 
						|
    pdc_bool pdfconf,
 | 
						|
    pdc_limitkind ltd,
 | 
						|
    char *cp,
 | 
						|
    size_t size,
 | 
						|
    FILE *fp,
 | 
						|
    const char *format,
 | 
						|
    va_list args)
 | 
						|
{
 | 
						|
    static const char fn[] = "pdc_vxprintf";
 | 
						|
 | 
						|
    char buf[1024];
 | 
						|
    char *dest = buf;
 | 
						|
    int result = 0;
 | 
						|
    char *limit = (char *) 0;
 | 
						|
 | 
						|
    if (cp != (char *) 0 && ltd != pdc_form_nolimit)
 | 
						|
	limit = cp + (int) (size - 1);
 | 
						|
 | 
						|
    for (/* */ ; /* */ ; /* */)
 | 
						|
    {
 | 
						|
        int             width = 0;	/* = no width specified		*/
 | 
						|
        int             prec = -1;	/* = no precision specified	*/
 | 
						|
        char            pad = ' ';
 | 
						|
        pdc_bool        left_justify = pdc_false;
 | 
						|
        pdc_bool        pos_sign = pdc_false;
 | 
						|
 | 
						|
	char		fbuf[100];	/* format buffer for %f and %g	*/
 | 
						|
	char *		fscan = fbuf;
 | 
						|
 | 
						|
        /* as long as there is no '%', just print.
 | 
						|
        */
 | 
						|
        while (*format != 0 && *format != '%')
 | 
						|
            *(dest++) = *(format++);
 | 
						|
 | 
						|
	if (dest > buf)
 | 
						|
	{
 | 
						|
	    int inbuf = (int) (dest - buf);
 | 
						|
 | 
						|
	    cp = write_sf(pdc, fp, ltd, cp, limit, buf, inbuf);
 | 
						|
	    result += inbuf;
 | 
						|
	    dest = buf;
 | 
						|
	}
 | 
						|
 | 
						|
        if (*format == 0)
 | 
						|
        {
 | 
						|
            if (cp != (char *) 0)
 | 
						|
                *cp = 0;
 | 
						|
 | 
						|
            return result;
 | 
						|
        }
 | 
						|
 | 
						|
	*(fscan++) = *(format++);	/* '%' */
 | 
						|
 | 
						|
        /* get the "flags", if any.
 | 
						|
        */
 | 
						|
	while (*format && strchr("+- #0", *format))
 | 
						|
	{
 | 
						|
	    switch (*format)
 | 
						|
	    {
 | 
						|
		case '-':	left_justify = pdc_true;
 | 
						|
				break;
 | 
						|
 | 
						|
		case '+':	pos_sign = pdc_true;
 | 
						|
				break;
 | 
						|
 | 
						|
		case '0':	pad = '0';
 | 
						|
				break;
 | 
						|
 | 
						|
		default:	break;
 | 
						|
	    }
 | 
						|
 | 
						|
	    *(fscan++) = *(format++);
 | 
						|
	}
 | 
						|
 | 
						|
        /* get the "width", if present.
 | 
						|
        */
 | 
						|
        if (*format == '*')
 | 
						|
        {
 | 
						|
            width = va_arg(args, int);
 | 
						|
            ++format;
 | 
						|
 | 
						|
	    if (width < 0)
 | 
						|
	    {
 | 
						|
		width = -width;
 | 
						|
 | 
						|
		if (!left_justify)
 | 
						|
		{
 | 
						|
		    *(fscan++) = '-';
 | 
						|
		    left_justify = pdc_true;
 | 
						|
		}
 | 
						|
	    }
 | 
						|
 | 
						|
	    fscan += sprintf(fscan, "%d", width);
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            while (pdc_isdigit(*format))
 | 
						|
	    {
 | 
						|
                width = 10 * width + *format - '0';
 | 
						|
		*(fscan++) = *(format++);
 | 
						|
	    }
 | 
						|
        }
 | 
						|
 | 
						|
	if (left_justify)
 | 
						|
	    pad = ' ';
 | 
						|
 | 
						|
        /* get the "precision", if present.
 | 
						|
        */
 | 
						|
        if (*format == '.')
 | 
						|
        {
 | 
						|
            ++format;
 | 
						|
 | 
						|
            if (*format == '*')
 | 
						|
            {
 | 
						|
                prec = va_arg(args, int);
 | 
						|
                ++format;
 | 
						|
 | 
						|
		if (prec >= 0)		/* ignore negative precision */
 | 
						|
		{
 | 
						|
		    fscan += sprintf(fscan, ".%d", prec);
 | 
						|
		}
 | 
						|
            }
 | 
						|
            else if (pdc_isdigit(*format))
 | 
						|
            {
 | 
						|
		prec = 0;
 | 
						|
		*(fscan++) = '.';
 | 
						|
 | 
						|
		do
 | 
						|
		{
 | 
						|
                    prec = 10 * prec + *format - '0';
 | 
						|
		    *(fscan++) = *(format++);
 | 
						|
		} while (pdc_isdigit(*format));
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
	*(fscan++) = *format;
 | 
						|
	*fscan = 0;
 | 
						|
 | 
						|
        switch (*format)
 | 
						|
        {
 | 
						|
            case 'x':
 | 
						|
            case 'X':
 | 
						|
                dest = pdc_ulong2a(
 | 
						|
                        dest, (pdc_off_t) va_arg(args, pdc_uint),
 | 
						|
                        width, pad, 16, left_justify);
 | 
						|
                break;
 | 
						|
 | 
						|
            case 'c':
 | 
						|
                *(dest++) = (char) va_arg(args, int);
 | 
						|
                break;
 | 
						|
 | 
						|
            case 'd':
 | 
						|
                dest = pdc_off_t2a(dest, (pdc_off_t) va_arg(args, int),
 | 
						|
                                   width, pad, left_justify, pos_sign);
 | 
						|
                break;
 | 
						|
 | 
						|
            case 'u':
 | 
						|
                dest = pdc_ulong2a(
 | 
						|
                        dest, (pdc_off_t) va_arg(args, pdc_ulong),
 | 
						|
                        width, pad, 10, left_justify);
 | 
						|
                break;
 | 
						|
 | 
						|
            case 'g':
 | 
						|
            case 'f':
 | 
						|
                if (pdfconf)
 | 
						|
                {
 | 
						|
                    dest = pdc_ftoa_pdfconf(pdc, dest, va_arg(args, double));
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    dest = pdc_ftoa(pdc, fbuf, dest, va_arg(args, double));
 | 
						|
                }
 | 
						|
                break;
 | 
						|
 | 
						|
            case 'l':
 | 
						|
            {
 | 
						|
                pdc_off_t	n = 0;
 | 
						|
		pdc_bool	ll = pdc_false;
 | 
						|
 | 
						|
                if (*(++format) == 'l')
 | 
						|
                {
 | 
						|
		    ll = pdc_true;
 | 
						|
                    ++format;
 | 
						|
                }
 | 
						|
 | 
						|
		if (strchr("xXu", *format))
 | 
						|
		{
 | 
						|
		    if (ll)
 | 
						|
			n = va_arg(args, pdc_off_t);
 | 
						|
		    else
 | 
						|
			n = va_arg(args, pdc_ulong);
 | 
						|
		}
 | 
						|
		else if (*format == 'd')
 | 
						|
		{
 | 
						|
		    if (ll)
 | 
						|
			n = va_arg(args, pdc_off_t);
 | 
						|
		    else
 | 
						|
			n = va_arg(args, long);
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
		    pdc_error(pdc, PDC_E_INT_BADFORMAT,
 | 
						|
			pdc_errprintf(pdc, "l%c",
 | 
						|
			    pdc_isprint((int) *format) ? *format : '?'),
 | 
						|
			pdc_errprintf(pdc, "0x%02X", *format),
 | 
						|
			0, 0);
 | 
						|
		}
 | 
						|
 | 
						|
                switch (*format)
 | 
						|
                {
 | 
						|
                    case 'x':
 | 
						|
                    case 'X':
 | 
						|
                        dest = pdc_ulong2a(
 | 
						|
				    dest, n, width, pad, 16, left_justify);
 | 
						|
                        break;
 | 
						|
 | 
						|
                    case 'd':
 | 
						|
                        dest = pdc_off_t2a(dest, n, width, pad,
 | 
						|
					    left_justify, pos_sign);
 | 
						|
                        break;
 | 
						|
 | 
						|
                    case 'u':
 | 
						|
                        dest = pdc_ulong2a(
 | 
						|
				    dest, n, width, pad, 10, left_justify);
 | 
						|
                        break;
 | 
						|
 | 
						|
                    default:
 | 
						|
			break;
 | 
						|
                }
 | 
						|
 | 
						|
                break;
 | 
						|
            }
 | 
						|
 | 
						|
            case 'p':
 | 
						|
            {
 | 
						|
	        char tmp[64];
 | 
						|
                void *ptr = va_arg(args, void *);
 | 
						|
 | 
						|
		sprintf(tmp, "%p", ptr);
 | 
						|
#if defined(AIX)
 | 
						|
		if (strncmp(tmp, "0x", 2))
 | 
						|
		    dest += sprintf(dest, "0x");
 | 
						|
#endif
 | 
						|
                dest += sprintf(dest, "%s", tmp);
 | 
						|
                break;
 | 
						|
            }
 | 
						|
 | 
						|
            case 'a':
 | 
						|
            case 's':
 | 
						|
            case 'T':
 | 
						|
            {
 | 
						|
                char *str = va_arg(args, char *);
 | 
						|
                const char *cstr = str;
 | 
						|
                pdc_bool tobefree = pdc_false;
 | 
						|
                size_t len;
 | 
						|
                int llen;
 | 
						|
 | 
						|
                if (str != 0)
 | 
						|
                {
 | 
						|
                    if (*format == 'T')
 | 
						|
                    {
 | 
						|
                        llen = va_arg(args, int);
 | 
						|
                        cstr = pdc_print_loggstring(pdc, str, llen);
 | 
						|
                    }
 | 
						|
                    else if (*format == 'a')
 | 
						|
                    {
 | 
						|
                        cstr = pdc_strdup_ext(pdc, str, PDC_CONV_EBCDIC, fn);
 | 
						|
                        tobefree = pdc_true;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    cstr = "(NULL)";
 | 
						|
                    if (*format == 'T')
 | 
						|
                        llen = va_arg(args, int);
 | 
						|
                }
 | 
						|
 | 
						|
		len = strlen(cstr);
 | 
						|
 | 
						|
                if (prec != -1 && prec < len)
 | 
						|
		{
 | 
						|
		    len = prec;
 | 
						|
		}
 | 
						|
 | 
						|
                if (!left_justify && len < (size_t) width)
 | 
						|
                {
 | 
						|
		    int inbuf = (int) (width - len);
 | 
						|
 | 
						|
                    memset(buf, pad, (size_t) inbuf);
 | 
						|
                    cp = write_sf(pdc, fp, ltd, cp, limit, buf, inbuf);
 | 
						|
		    result += inbuf;
 | 
						|
                }
 | 
						|
 | 
						|
                if (len != 0)
 | 
						|
                {
 | 
						|
		    result += (int) len;
 | 
						|
 | 
						|
                    if (fp != (FILE *) 0)
 | 
						|
                    {
 | 
						|
                        pdc_fwrite_ascii(pdc, cstr, len, fp);
 | 
						|
                    }
 | 
						|
                    else if (ltd == pdc_form_nolimit || result < (int) size)
 | 
						|
                    {
 | 
						|
                        memcpy(cp, cstr, len);
 | 
						|
                        cp += (int) len;
 | 
						|
                    }
 | 
						|
                    else if (ltd == pdc_form_fixlimit)
 | 
						|
                    {
 | 
						|
                        pdc_error(pdc, PDC_E_INT_FORMOVERFLOW, 0, 0, 0, 0);
 | 
						|
                    }
 | 
						|
                    else if (cp < limit)
 | 
						|
                    {
 | 
						|
                        memcpy(cp, cstr, (size_t) (limit - cp));
 | 
						|
                        cp = limit;
 | 
						|
                    }
 | 
						|
 | 
						|
                    if (tobefree)
 | 
						|
                        pdc_free(pdc, (char *) cstr);
 | 
						|
                }
 | 
						|
 | 
						|
                if (left_justify && len < (size_t) width)
 | 
						|
                {
 | 
						|
		    int inbuf = (int) (width - len);
 | 
						|
 | 
						|
                    memset(buf, pad, (size_t) inbuf);
 | 
						|
                    cp = write_sf(pdc, fp, ltd, cp, limit, buf, inbuf);
 | 
						|
		    result += inbuf;
 | 
						|
                }
 | 
						|
 | 
						|
                break;
 | 
						|
            }
 | 
						|
 | 
						|
            case '%':
 | 
						|
                *(dest++) = '%';
 | 
						|
                break;
 | 
						|
 | 
						|
            default:
 | 
						|
                pdc_error(pdc, PDC_E_INT_BADFORMAT,
 | 
						|
                    pdc_errprintf(pdc, "%c", pdc_isprint((int) *format) ?
 | 
						|
                                  *format : '?'),
 | 
						|
                    pdc_errprintf(pdc, "0x%02X", *format),
 | 
						|
                    0, 0);
 | 
						|
        } /* switch */
 | 
						|
 | 
						|
        ++format;
 | 
						|
    } /* loop */
 | 
						|
} /* pdc_vxprintf */
 | 
						|
 | 
						|
 | 
						|
/* ----------------------- formatted output ----------------------- */
 | 
						|
 | 
						|
/*
 | 
						|
 * formatted output to file
 | 
						|
 */
 | 
						|
int
 | 
						|
pdc_vfprintf(pdc_core *pdc, pdc_bool pdfconf, FILE *fp,
 | 
						|
             const char *format, va_list args)
 | 
						|
{
 | 
						|
    return pdc_vxprintf(pdc, pdfconf, pdc_form_nolimit,
 | 
						|
                        NULL, 0, fp, format, args);
 | 
						|
} /* pdc_vfprintf */
 | 
						|
 | 
						|
int
 | 
						|
pdc_fprintf(pdc_core *pdc, pdc_bool pdfconf, FILE *fp,
 | 
						|
            const char *format, ...)
 | 
						|
{
 | 
						|
    int result;
 | 
						|
    va_list ap;
 | 
						|
 | 
						|
    va_start(ap, format);
 | 
						|
    result = pdc_vxprintf(pdc, pdfconf, pdc_form_nolimit,
 | 
						|
                          NULL, 0, fp, format, ap);
 | 
						|
    va_end(ap);
 | 
						|
 | 
						|
    return result;
 | 
						|
} /* pdc_fprintf */
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * formatted output to character string
 | 
						|
 */
 | 
						|
int
 | 
						|
pdc_vsprintf(pdc_core *pdc, pdc_bool pdfconf, char *buf,
 | 
						|
             const char *format, va_list args)
 | 
						|
{
 | 
						|
    return pdc_vxprintf(pdc, pdfconf, pdc_form_fixlimit,
 | 
						|
                        buf, PDC_GEN_BUFSIZE, NULL, format, args);
 | 
						|
} /* pdc_vsprintf */
 | 
						|
 | 
						|
int
 | 
						|
pdc_sprintf(pdc_core *pdc, pdc_bool pdfconf, char *buf,
 | 
						|
            const char *format, ...)
 | 
						|
{
 | 
						|
    int result;
 | 
						|
    va_list ap;
 | 
						|
 | 
						|
    va_start(ap, format);
 | 
						|
    result = pdc_vxprintf(pdc, pdfconf, pdc_form_nolimit,
 | 
						|
                          buf, 0, NULL, format, ap);
 | 
						|
    va_end(ap);
 | 
						|
 | 
						|
    return result;
 | 
						|
} /* pdc_sprintf */
 | 
						|
 | 
						|
int
 | 
						|
pdc_vsnprintf(pdc_core *pdc, char *buf, size_t size,
 | 
						|
              const char *format, va_list args)
 | 
						|
{
 | 
						|
    return pdc_vxprintf(pdc, pdc_false, pdc_form_varlimit,
 | 
						|
                        buf, size, NULL, format, args);
 | 
						|
} /* pdc_vsnprintf */
 | 
						|
 | 
						|
 | 
						|
/* --------------------- name tree handling ----------------------- */
 | 
						|
 | 
						|
struct pdc_branch_s
 | 
						|
{
 | 
						|
    char        *name;     /* name - must be allocated pointer */
 | 
						|
    void        *data;     /* private data - must be allocated pointer */
 | 
						|
    int          nalloc;   /* number of allocated kid structs */
 | 
						|
    int          nkids;    /* number of kids */
 | 
						|
    pdc_branch **kids;     /* kids */
 | 
						|
    pdc_branch  *parent;   /* parent branch */
 | 
						|
};
 | 
						|
 | 
						|
pdc_branch *
 | 
						|
pdc_init_tree(pdc_core *pdc)
 | 
						|
{
 | 
						|
    return pdc_create_treebranch(pdc, NULL, "__tree__root__",
 | 
						|
                                 NULL, 0, 0, NULL, NULL);
 | 
						|
}
 | 
						|
 | 
						|
pdc_branch *
 | 
						|
pdc_create_treebranch(pdc_core *pdc, pdc_branch *root, const char *pathname,
 | 
						|
                      void *data, int flags, int size,
 | 
						|
                      pdc_branch_error *errcode, const char **name_p)
 | 
						|
{
 | 
						|
    static const char fn[] = "pdc_create_branch";
 | 
						|
    char *name = NULL;
 | 
						|
    pdc_branch *branch = NULL;
 | 
						|
    pdc_branch *kid = NULL;
 | 
						|
    pdc_branch *parent = NULL;
 | 
						|
    char **namelist;
 | 
						|
    int i, j, k, nnames, nkids;
 | 
						|
 | 
						|
    if (errcode) *errcode = tree_ok;
 | 
						|
    if (name_p) *name_p = "";
 | 
						|
 | 
						|
    if (root)
 | 
						|
    {
 | 
						|
        /* search for parent branch */
 | 
						|
        parent = root;
 | 
						|
        nnames = pdc_split_stringlist(pdc, pathname, PDC_NAME_SEPARSTRG, 0,
 | 
						|
                                      &namelist);
 | 
						|
        for (i = 0; i < nnames; i++)
 | 
						|
        {
 | 
						|
            /* parent branch must not be a leaf branch */
 | 
						|
            if (!parent->nalloc)
 | 
						|
            {
 | 
						|
                if (errcode) *errcode = tree_isleaf;
 | 
						|
                pdc_cleanup_stringlist(pdc, namelist);
 | 
						|
                return NULL;
 | 
						|
            }
 | 
						|
            if (i == nnames - 1)
 | 
						|
                break;
 | 
						|
 | 
						|
            name = namelist[i];
 | 
						|
            if (name_p)
 | 
						|
            {
 | 
						|
                *name_p = pdc_utf8strprint(pdc, name);
 | 
						|
            }
 | 
						|
 | 
						|
            nkids = parent->nkids;
 | 
						|
            for (j = 0; j < nkids; j++)
 | 
						|
            {
 | 
						|
                kid = parent->kids[j];
 | 
						|
                k = pdc_is_utf8_bytecode(kid->name) ? 3 : 0;
 | 
						|
                if (!strcmp(&kid->name[k], name))
 | 
						|
                {
 | 
						|
                    parent = kid;
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
            }
 | 
						|
            if (j == nkids)
 | 
						|
            {
 | 
						|
                if (errcode) *errcode = tree_notfound;
 | 
						|
                pdc_cleanup_stringlist(pdc, namelist);
 | 
						|
                return NULL;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if (pdc_is_utf8_bytecode(pathname))
 | 
						|
            name = pdc_strdup_withbom(pdc, namelist[nnames - 1]);
 | 
						|
        else
 | 
						|
            name = pdc_strdup(pdc, namelist[nnames - 1]);
 | 
						|
        pdc_cleanup_stringlist(pdc, namelist);
 | 
						|
 | 
						|
        /* kids must have different names */
 | 
						|
        for (j = 0; j < parent->nkids; j++)
 | 
						|
        {
 | 
						|
            kid = parent->kids[j];
 | 
						|
            if (!strcmp(kid->name, name))
 | 
						|
            {
 | 
						|
                if (errcode) *errcode = tree_nameexists;
 | 
						|
                if (name_p) *name_p = pdc_utf8strprint(pdc, name);
 | 
						|
 | 
						|
                pdc_free(pdc, name);
 | 
						|
                return NULL;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        parent = NULL;
 | 
						|
        name = pdc_strdup(pdc, pathname);
 | 
						|
    }
 | 
						|
 | 
						|
    branch = (pdc_branch *) pdc_malloc(pdc, sizeof(pdc_branch), fn);
 | 
						|
    branch->name = name;
 | 
						|
    branch->data = data;
 | 
						|
    if (flags & PDC_TREE_ISLEAF)
 | 
						|
    {
 | 
						|
        branch->nalloc = 0;
 | 
						|
        branch->nkids = 0;
 | 
						|
        branch->kids = NULL;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        branch->nalloc = PDC_KIDS_CHUNKSIZE;
 | 
						|
        branch->nkids = 0;
 | 
						|
        branch->kids = (pdc_branch **) pdc_malloc(pdc,
 | 
						|
                            branch->nalloc * sizeof(pdc_branch *), fn);
 | 
						|
    }
 | 
						|
    branch->parent = parent;
 | 
						|
 | 
						|
    /* insert kid */
 | 
						|
    if (parent)
 | 
						|
    {
 | 
						|
        if (parent->nkids == parent->nalloc)
 | 
						|
        {
 | 
						|
            parent->nalloc *= 2;
 | 
						|
            parent->kids = (pdc_branch **) pdc_realloc(pdc, parent->kids,
 | 
						|
                                parent->nalloc * sizeof(pdc_branch *), fn);
 | 
						|
        }
 | 
						|
        parent->kids[parent->nkids] = branch;
 | 
						|
        (parent->nkids)++;
 | 
						|
 | 
						|
        if ((flags & PDC_TREE_INHERIT) && parent->data)
 | 
						|
            memcpy(branch->data, parent->data, (size_t) size);
 | 
						|
    }
 | 
						|
 | 
						|
    return branch;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
pdc_deactivate_name_treebranch(pdc_core *pdc, pdc_branch *branch)
 | 
						|
{
 | 
						|
    static const char fn[] = "pdc_deactivate_name_treebranch";
 | 
						|
    size_t len = strlen(branch->name);
 | 
						|
 | 
						|
    branch->name = (char *) pdc_realloc(pdc, branch->name, len + 2, fn);
 | 
						|
    branch->name[len] = PDC_NAME_SEPARSIGN;
 | 
						|
    branch->name[len+1] = 0;
 | 
						|
}
 | 
						|
 | 
						|
char *
 | 
						|
pdc_get_name_treebranch(pdc_branch *branch)
 | 
						|
{
 | 
						|
    return branch->name;
 | 
						|
}
 | 
						|
 | 
						|
pdc_branch *
 | 
						|
pdc_get_parent_treebranch(pdc_branch *branch)
 | 
						|
{
 | 
						|
    return branch->parent;
 | 
						|
}
 | 
						|
 | 
						|
void *
 | 
						|
pdc_get_data_treebranch(pdc_branch *branch)
 | 
						|
{
 | 
						|
    return branch->data;
 | 
						|
}
 | 
						|
 | 
						|
pdc_branch **
 | 
						|
pdc_get_kids_treebranch(pdc_branch *branch, int *nkids)
 | 
						|
{
 | 
						|
    *nkids = branch->nkids;
 | 
						|
    return branch->kids;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
pdc_cleanup_treebranch(pdc_core *pdc, pdc_branch *branch)
 | 
						|
{
 | 
						|
    int i;
 | 
						|
 | 
						|
    if (branch->name)
 | 
						|
        pdc_free(pdc, branch->name);
 | 
						|
 | 
						|
    if (branch->data)
 | 
						|
        pdc_free(pdc, branch->data);
 | 
						|
 | 
						|
    if (branch->kids)
 | 
						|
    {
 | 
						|
        for(i = 0; i < branch->nkids; i++)
 | 
						|
            pdc_cleanup_treebranch(pdc, branch->kids[i]);
 | 
						|
        pdc_free(pdc, branch->kids);
 | 
						|
    }
 | 
						|
 | 
						|
    pdc_free(pdc, branch);
 | 
						|
}
 | 
						|
 | 
						|
/***************************** memory pools *****************************/
 | 
						|
 | 
						|
/* the data structures and functions in this section are more than
 | 
						|
** confusing. the funny "mp_item" structure below makes them more
 | 
						|
** readable, believe it or not.
 | 
						|
*/
 | 
						|
typedef struct mp_item_s mp_item;
 | 
						|
 | 
						|
struct mp_item_s
 | 
						|
{
 | 
						|
    mp_item *   next;
 | 
						|
};
 | 
						|
 | 
						|
struct pdc_mempool_s
 | 
						|
{
 | 
						|
    pdc_core *  pdc;
 | 
						|
 | 
						|
    char **     pool_tab;
 | 
						|
    mp_item *   free_list;
 | 
						|
 | 
						|
    size_t      pool_incr;      /* pool growth chunk size (items)       */
 | 
						|
 | 
						|
    size_t      ptab_cap;       /* total # of slots in pool_tab         */
 | 
						|
    size_t      ptab_size;      /* used # of slots in pool_tab          */
 | 
						|
    size_t      ptab_incr;      /* pool_tab growth chunk size (slots)   */
 | 
						|
 | 
						|
    size_t      item_size;      /* size of a single item (bytes)        */
 | 
						|
};
 | 
						|
 | 
						|
#undef  COMMENT
 | 
						|
#ifdef  COMMENT
 | 
						|
 | 
						|
    pool_incr   = 5
 | 
						|
    ptab_incr   = 4
 | 
						|
    ptab_cap    = 4     (1 * ptab_incr)
 | 
						|
 | 
						|
 | 
						|
    +------+
 | 
						|
    | free |
 | 
						|
    +------+         +----------------------------------+
 | 
						|
    | free |    +--> |      |      |      | free | free |
 | 
						|
    +------+    |    +----------------------------------+
 | 
						|
    |      | ---+
 | 
						|
    +------+         +----------------------------------+
 | 
						|
    |      | ------> |      |      |      |      |      |
 | 
						|
    +------+         +----------------------------------+
 | 
						|
 | 
						|
    pool_tab
 | 
						|
 | 
						|
#endif  /* COMMENT */
 | 
						|
 | 
						|
 | 
						|
pdc_mempool *
 | 
						|
pdc_mp_new(pdc_core *pdc, size_t item_size)
 | 
						|
{
 | 
						|
    static const char fn[] = "pdc_mp_new";
 | 
						|
 | 
						|
    int m;
 | 
						|
    pdc_mempool *mp = (pdc_mempool *)
 | 
						|
        pdc_malloc(pdc, sizeof (pdc_mempool), fn);
 | 
						|
 | 
						|
    if (mp != (pdc_mempool *) 0)
 | 
						|
    {
 | 
						|
        /* round up 'item_size' to a multiple of 'sizeof (mp_item)'
 | 
						|
        ** to ensure proper alignment.
 | 
						|
        */
 | 
						|
        if ((m = (int) (item_size % sizeof (mp_item))) != 0)
 | 
						|
            item_size += sizeof (mp_item) - m;
 | 
						|
 | 
						|
        mp->pdc = pdc;
 | 
						|
 | 
						|
        mp->pool_tab = (char **) 0;
 | 
						|
        mp->free_list = (mp_item *) 0;
 | 
						|
        mp->pool_incr = 1000;
 | 
						|
 | 
						|
        mp->ptab_cap = 0;
 | 
						|
        mp->ptab_size = 0;
 | 
						|
        mp->ptab_incr = 100;
 | 
						|
 | 
						|
        mp->item_size = item_size;
 | 
						|
    }
 | 
						|
 | 
						|
    return mp;
 | 
						|
} /* pdc_mp_new */
 | 
						|
 | 
						|
 | 
						|
void
 | 
						|
pdc_mp_delete(pdc_mempool *mp)
 | 
						|
{
 | 
						|
    /* TODO: exception if there are still alloc'd items in the pool?    */
 | 
						|
    /* or, the other way round, call destructors?                       */
 | 
						|
 | 
						|
    pdc_core *  pdc = mp->pdc;
 | 
						|
    int         i;
 | 
						|
 | 
						|
    for (i = 0; i < (int) mp->ptab_size; ++i)
 | 
						|
        pdc_free(pdc, mp->pool_tab[i]);
 | 
						|
 | 
						|
    if (mp->pool_tab)
 | 
						|
        pdc_free(pdc, mp->pool_tab);
 | 
						|
 | 
						|
    pdc_free(pdc, mp);
 | 
						|
} /* pdc_mp_delete */
 | 
						|
 | 
						|
 | 
						|
void *
 | 
						|
pdc_mp_alloc(pdc_mempool *mp)
 | 
						|
{
 | 
						|
    static const char fn[] = "pdc_mp_alloc";
 | 
						|
 | 
						|
    pdc_core *  pdc = mp->pdc;
 | 
						|
    mp_item *   result;
 | 
						|
 | 
						|
    if (!mp->free_list)
 | 
						|
    {
 | 
						|
        char *  new_chunk;
 | 
						|
        int     i;
 | 
						|
 | 
						|
        if (mp->ptab_size == mp->ptab_cap)
 | 
						|
        {
 | 
						|
            mp->ptab_cap += mp->ptab_incr;
 | 
						|
 | 
						|
            mp->pool_tab = (char **) pdc_realloc(pdc,
 | 
						|
                mp->pool_tab, mp->ptab_cap * sizeof (char **), fn);
 | 
						|
        }
 | 
						|
 | 
						|
        new_chunk = mp->pool_tab[mp->ptab_size] = (char *)
 | 
						|
            pdc_malloc(pdc, mp->pool_incr * mp->item_size, fn);
 | 
						|
 | 
						|
        ++mp->ptab_size;
 | 
						|
        mp->free_list = (mp_item *) new_chunk;
 | 
						|
        mp->free_list->next = (mp_item *) 0;
 | 
						|
 | 
						|
        for (i = 1; i < (int) mp->pool_incr; ++i)
 | 
						|
        {
 | 
						|
            mp_item *scan = (mp_item *) (new_chunk + i * mp->item_size);
 | 
						|
 | 
						|
            scan->next = mp->free_list;
 | 
						|
            mp->free_list = scan;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    result = mp->free_list;
 | 
						|
    mp->free_list = result->next;
 | 
						|
 | 
						|
    return (void *) result;
 | 
						|
} /* pdc_mp_alloc */
 | 
						|
 | 
						|
 | 
						|
void
 | 
						|
pdc_mp_free(pdc_mempool *mp, void *item)
 | 
						|
{
 | 
						|
    mp_item *mpi = (mp_item *) item;
 | 
						|
 | 
						|
    mpi->next = mp->free_list;
 | 
						|
    mp->free_list = mpi;
 | 
						|
} /* pdc_mp_free */
 | 
						|
 | 
						|
 | 
						|
/***************************** miscellaneous ****************************/
 | 
						|
 | 
						|
/* search a sorted (strcmp order) array "names" of size "size"
 | 
						|
** for string "name". return the index if found, otherwise -1.
 | 
						|
*/
 | 
						|
int
 | 
						|
pdc_name2idx(const char **names, int size, const char *name)
 | 
						|
{
 | 
						|
    int lo = 0, hi = size;
 | 
						|
 | 
						|
    while (lo != hi)
 | 
						|
    {
 | 
						|
        int idx = (lo + hi) / 2;
 | 
						|
        int cmp = strcmp(name, names[idx]);
 | 
						|
 | 
						|
        if (cmp == 0)
 | 
						|
            return idx;
 | 
						|
 | 
						|
        if (cmp < 0)
 | 
						|
            hi = idx;
 | 
						|
        else
 | 
						|
            lo = idx + 1;
 | 
						|
    }
 | 
						|
 | 
						|
    return -1;
 | 
						|
} /* pdc_name2idx */
 | 
						|
 | 
						|
 | 
						|
/* linear search; see man page LSEARCH(3).
 | 
						|
*/
 | 
						|
void *
 | 
						|
pdc_lfind(
 | 
						|
    const void *key,
 | 
						|
    const void *base,
 | 
						|
    size_t *    nmemb,
 | 
						|
    size_t      size,
 | 
						|
    int       (*compar)(const void *, const void *))
 | 
						|
{
 | 
						|
    size_t i;
 | 
						|
 | 
						|
    for (i = 0; i < *nmemb; ++i)
 | 
						|
    {
 | 
						|
        const char *cp = (const char *) base + i * size;
 | 
						|
 | 
						|
        if (compar(key, (void *) cp) == 0)
 | 
						|
            return (void *) cp;
 | 
						|
    }
 | 
						|
 | 
						|
    return (void *) 0;
 | 
						|
} /* pdc_lfind */
 | 
						|
 | 
						|
 | 
						|
/********************* pseudo random numbers *********************/
 | 
						|
 | 
						|
int
 | 
						|
pdc_rand(pdc_core *pdc)
 | 
						|
{
 | 
						|
    pdc->last_rand = pdc->last_rand * 1103515245 + 12345;
 | 
						|
 | 
						|
    return (pdc_uint)(pdc->last_rand / 65536) % 32768;
 | 
						|
} /* pdc_rand */
 | 
						|
 | 
						|
void
 | 
						|
pdc_srand(pdc_core *pdc, pdc_uint seed)
 | 
						|
{
 | 
						|
    pdc->last_rand = seed;
 | 
						|
} /* pdc_srand */
 |