campo-sirio/pdf/pdcore/pc_util.c
guy 3bf951f42c Patch level : 10.0
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
2009-03-23 08:55:58 +00:00

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, &ltime);
#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, &ltime);
gtimer = mktime(&ltime);
pdc_localtime_r(&timer, &ltime);
ltime.tm_isdst = 0;
diffminutes = difftime(mktime(&ltime), 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, &ltime);
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 */